OpenCore  1.0.4
OpenCore Bootloader
Loading...
Searching...
No Matches
EfiResTool.c
Go to the documentation of this file.
29#ifdef WIN32
30
31#include <stdlib.h>
32#include <stdio.h>
33
34int main(int argc, const char* argv[]) {
35 fprintf(stderr, "This utility is not yet supported on Windows\n");
36 return EXIT_FAILURE;
37}
38
39#else
40
41#include <sys/types.h>
42#include <unistd.h> // write
43#include <fcntl.h> // open, close
44#include <stdio.h> // fprintf
45#include <string.h> // strerror, strdup, strchr
46#include <stdlib.h> // abort, free, EXIT_*
47#include <sys/mman.h> // mmap, munmap
48#include <sys/stat.h> // fstat
49#include <errno.h> // errno
50#include <dirent.h> // DIR, dirent, opendir, readdir
51#include <stdint.h> // UINT32_MAX
52
53typedef struct {
54 char name[64];
57}
58__attribute__((packed, aligned(1)))
59efires_file_t;
60
61#define EFIRES_CURRENT_REVISION 2
62typedef struct {
63 uint16_t revision; // EFIRES_CURRENT_REVISION
64 uint16_t nentries; // count of entries
65 efires_file_t entries[/* nentries */];
66}
68efires_hdr_t;
69
70#if !defined(le16toh) && defined(__BYTE_ORDER__) && __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__
71#define le16toh(x) (x)
72#define le32toh(x) (x)
73#define htole16(x) (x)
74#define htole32(x) (x)
75#elif !defined(le16toh) && defined(__APPLE__)
76#include <libkern/OSByteOrder.h>
77#define le16toh(x) OSSwapLittleToHostInt16(x)
78#define le32toh(x) OSSwapLittleToHostInt32(x)
79#define htole16(x) OSSwapHostToLittleInt16(x)
80#define htole32(x) OSSwapHostToLittleInt32(x)
81#else
82#include <endian.h>
83#endif
84
85typedef enum {
86 ONLY_LIST = 1,
88
89int unpack_efires(const char* fname, const char* destination, unpack_flag flags, char** filelist[]);
90int pack_efires(const char* fname, const char* fromdir, const char* filelist[]);
91
92int write_filelist(const char** filelist, const char* fname);
93const char** parse_filelist(const char* fname);
94void free_filelist(char** filelist);
95
96#define ACTION_UNPACK "unpack"
97#define ACTION_PACK "pack"
98#define ACTION_LIST "list"
99
100void print_usage(const char* prog) {
101 fprintf(stderr,
102 "efirestool -- tool to work with APPL efires archives\n"
103 "\n"
104 "Usage:\n"
105 " %s " ACTION_UNPACK " efires destination [filelist]\n"
106 " %s " ACTION_PACK " efires from [filelist]\n"
107 " %s " ACTION_LIST " efires [-f filelist]\n"
108 , prog, prog, prog);
109}
110
111int main(int argc, const char* argv[]) {
112 if (argc < 3) {
113 print_usage(argv[0]);
114 return EXIT_FAILURE;
115 }
116
117 const char* action = argv[1];
118 const char* efires = argv[2];
119 const char* directory = NULL;
120 const char* filelist_fname = NULL;
121 const char** filelist = NULL;
122
123 int retval = 0;
124
125 if (argc > 3) {
126 directory = argv[3];
127 }
128
129 if (argc > 4) {
130 filelist_fname = argv[4];
131 }
132
133 if ((strcmp(action, ACTION_UNPACK) == 0) || (strcmp(action, ACTION_LIST) == 0)) {
134 unpack_flag flags = 0;
135
136 if (strcmp(action, ACTION_LIST) == 0) flags |= ONLY_LIST;
137
138 retval = unpack_efires(efires, directory, flags, (char***) ((filelist_fname) ? &filelist : NULL));
139
140 if (!retval && filelist_fname) {
141 if (filelist == NULL) {
142 fprintf(stderr, "Failed to build filelist\n");
143 retval = 1;
144 } else {
145 retval = write_filelist(filelist, filelist_fname);
146 }
147 }
148 } else if (strcmp(action, ACTION_PACK) == 0) {
149 filelist = parse_filelist(filelist_fname);
150
151 if (filelist == NULL) {
152 fprintf(stderr, "Failed to parse filelist\n");
153 retval = 1;
154 } else {
155 retval = pack_efires(efires, directory, filelist);
156 }
157 } else {
158 print_usage(argv[0]);
159 retval = EXIT_FAILURE;
160 }
161
162 if (filelist) {
163 free_filelist((char**)filelist);
164 }
165
166 return retval;
167}
168
169void free_filelist(char** filelist) {
170 for (char** p = filelist; *p != NULL; ++p) {
171 free((char*)*p);
172 }
173
174 free(filelist);
175}
176
177const char** parse_filelist(const char* fname) {
178 FILE *f = fopen(fname, "r");
179 if (f == NULL) {
180 fprintf(stderr, "Cant open filelist (%s): %s\n", fname, strerror(errno));
181 return NULL;
182 }
183
184 // XXX realloc and grow
185 size_t res_size = sizeof(char*) * UINT32_MAX / sizeof(efires_file_t);
186 char** res = malloc(res_size);
187
188 if (res == NULL) {
189 fprintf(stderr, "Cant allocate memory for filelist\n");
190 fclose(f);
191 return NULL;
192 }
193
194 ssize_t linelen = 0;
195 char** itm = res;
196 size_t n = 0;
197
198 for (*itm = NULL, n = 0;
199 (itm < (res + res_size - 1)) && ((linelen = getline(itm, &n, f)) != -1);
200 ++itm, *itm = NULL, n = 0, linelen = 0)
201 {
202 (*itm)[linelen - 1] = '\0';
203 }
204
205 if (linelen == 0) {
206 *itm = NULL;
207 } else if (*itm) {
208 free(*itm);
209 *itm = NULL;
210 }
211
212 fclose(f);
213
214 return (const char**)res;
215}
216
217int write_filelist(const char** filelist, const char* fname) {
218 if (filelist == NULL) {
219 fprintf(stderr, "Cant write NULL filelist\n");
220 return 1;
221 }
222 FILE *f = fopen(fname, "w");
223
224 if (f == NULL) {
225 fprintf(stderr, "Cant open filelist (%s): %s\n", fname, strerror(errno));
226 return 1;
227 }
228
229 for (const char** itm = filelist; *itm != NULL; ++itm) {
230 fprintf(f, "%s\n", *itm);
231 }
232
233 fclose(f);
234 return 0;
235}
236
237int unpack_efires(const char* fname, const char* destination, unpack_flag flags, char** filelist[]) {
238 int result = 1;
239 size_t file_size = 0;
240 const void *file_map = NULL;
241
242 if (filelist) *filelist = NULL;
243
244 if (((flags & ONLY_LIST) == 0) && (destination == NULL)) {
245 fprintf(stderr, "Cant determine destination\n");
246 goto out;
247 }
248
249 int fd = open(fname, O_RDONLY);
250 if (fd == -1) {
251 fprintf(stderr, "Cant open resource file (%s): %s\n", fname, strerror(errno));
252 goto out;
253 }
254
255 struct stat s;
256 if (fstat(fd, &s) != 0) {
257 fprintf(stderr, "fstat failed for (%s): %s\n", fname, strerror(errno));
258 goto out;
259 }
260
261 file_size = s.st_size;
262
263 if (file_size < sizeof(efires_hdr_t)) {
264 fprintf(stderr, "File is too short to be an efires file\n");
265 goto out;
266 }
267
268 file_map = mmap(NULL, s.st_size, PROT_READ, MAP_PRIVATE, fd, 0);
269 if (file_map == MAP_FAILED) {
270 fprintf(stderr, "Cant mmap file (%s): %s\n", fname, strerror(errno));
271 file_map = NULL;
272 goto out;
273 }
274
275 const efires_hdr_t *hdr = (const efires_hdr_t *) file_map;
276 if (le16toh(hdr->revision) != EFIRES_CURRENT_REVISION) {
277 fprintf(stderr, "Wrong efires revision: 0x%02x (expected 0x%02x)\n", le16toh(hdr->revision), EFIRES_CURRENT_REVISION);
278 goto out;
279 }
280
281 uint16_t nentries = le16toh(hdr->nentries);
282 fprintf(stderr, "File with 0x%x entries: %s\n", nentries, fname);
283
284 if (nentries * sizeof(efires_file_t) + sizeof(efires_hdr_t) > file_size) {
285 fprintf(stderr, "File is too small to have so many entries\n");
286 goto out;
287 }
288
289 char** filelist_iter = NULL;
290
291 if (filelist) {
292 *filelist = malloc((nentries + 1) * sizeof(char*));
293 filelist_iter = *filelist;
294 if (filelist_iter) {
295 *filelist_iter = NULL;
296 } else {
297 fprintf(stderr, "Cant allocate memory for filelist\n");
298 goto out;
299 }
300 }
301
302 if ((flags & ONLY_LIST) == 0) {
303 if (mkdir(destination, 0755) != 0) {
304 fprintf(stderr, "Cant create destination directory '%s': %s\n", destination, strerror(errno));
305 goto out;
306 }
307
308 if (chdir(destination) != 0) {
309 fprintf(stderr, "Cant chdir to destination directory '%s': %s\n", destination, strerror(errno));
310 goto out;
311 }
312 }
313
314 for (uint16_t i = 0; i != nentries; ++i) {
315 const efires_file_t *ent = &hdr->entries[i];
316 uint32_t off = le32toh(ent->offset);
317 uint32_t len = le32toh(ent->length);
318
319 printf("0x%04x (0x%08x - 0x%08x): %s\n", i, off, off + len, ent->name);
320
321 if (filelist_iter) *(filelist_iter++) = strdup(ent->name);
322
323 if (flags & ONLY_LIST) continue;
324
325 if (off + len > file_size) {
326 fprintf(stderr, "File 0x%04x: overflows efires file -- skipping\n", i);
327 continue;
328 }
329
330 int f = open(ent->name, O_WRONLY|O_CREAT|O_EXCL, 0755);
331
332 if (f == -1) {
333 fprintf(stderr, "File 0x%04x: Failed to create file: %s\n", i, strerror(errno));
334 continue;
335 }
336
337 int wrote = write(f, (void*) ((uintptr_t)file_map + off), len);
338 if ((uint32_t)wrote != len) {
339 fprintf(stderr, "File 0x%04x: Expected to write %d bytes, wrote %d: %s\n", i, len, wrote, strerror(errno));
340 }
341
342 close(f);
343 }
344
345 result = 0;
346
347out:;
348
349 if (result && filelist && *filelist) {
350 free_filelist(*filelist);
351 *filelist = NULL;
352 }
353
354 if (file_map) {
355 munmap((void*)file_map, file_size);
356 }
357 return result;
358}
359
360int pack_efires(const char* fname, const char* fromdir, const char* filelist[]) {
361 int result = 1;
362 DIR *dir = NULL;
363 int dfd = -1;
364 int outfd = -1;
365 size_t file_size = 0;
366 void *file_map = NULL;
367 uint32_t nentries = 0;
368
369 dir = opendir(fromdir);
370 dfd = dirfd(dir);
371 if (dir == NULL || dfd == -1) {
372 fprintf(stderr, "Cant open directory to pack (%s) : %s\n", fromdir, strerror(errno));
373 goto out;
374 }
375
376 outfd = open(fname, O_RDWR | O_CREAT | O_EXCL, 0644);
377 if (outfd == -1) {
378 fprintf(stderr, "Cant open output file (%s) : %s\n", fname, strerror(errno));
379 goto out;
380 }
381
382 {
383 // write space for header
384 efires_hdr_t tmp;
385 if (write(outfd, &tmp, sizeof(tmp)) == -1)
386 abort();
387 }
388
389 // header and one reserved zeroed entry
390 uint32_t full_file_len = sizeof(efires_hdr_t) + sizeof(efires_file_t);
391
392 efires_file_t cur_entr;
393 struct dirent *ep = NULL;
394 const char** itm = filelist;
395
396 while ((itm && *itm) || ((itm == NULL) && (ep = readdir(dir)) != NULL)) {
397 struct stat s;
398
399 const char* d_name = NULL;
400
401 if (itm) {
402 d_name = *(itm++);
403 } else {
404 d_name = ep->d_name;
405 }
406
407 if (fstatat(dfd, d_name, &s, 0) != 0) {
408 fprintf(stderr, "Cant stat file, skipping (%s/%s) : %s\n", fromdir, d_name, strerror(errno));
409 continue;
410 }
411
412 if ((s.st_mode & S_IFMT) != S_IFREG) {
413 fprintf(stderr, "Entry isn't regular file, skipping (%s/%s)\n", fromdir, d_name);
414 continue;
415 }
416
417 if (s.st_size > UINT32_MAX) {
418 fprintf(stderr, "File too big for efires, skipping (%s/%s)\n", fromdir, d_name);
419 continue;
420 }
421
422 cur_entr.length = (uint32_t) s.st_size;
423
424 if (full_file_len + cur_entr.length > UINT32_MAX) {
425 fprintf(stderr, "File too big to fit in current state, skipping (%u bytes left, %u bytes needed) (%s/%s)\n", UINT32_MAX - full_file_len, cur_entr.length, fromdir, d_name);
426 continue;
427 }
428
429 size_t e_name_len = strlen(d_name);
430 if (e_name_len > sizeof(cur_entr.name)) {
431 fprintf(stderr, "Filename too long, skipping (%s/%s)\n", fromdir, d_name);
432 continue;
433 }
434
435 ++nentries;
436 memcpy(cur_entr.name, d_name, e_name_len);
437
438 if (e_name_len < sizeof(cur_entr.name)) {
439 memset(cur_entr.name + e_name_len, 0, sizeof(cur_entr.name) - e_name_len);
440 }
441
442 if (write(outfd, &cur_entr, sizeof(cur_entr)) != sizeof(cur_entr)) {
443 fprintf(stderr, "Write to result file failed: %s\n", strerror(errno));
444 goto out;
445 }
446
447 full_file_len += sizeof(cur_entr) + cur_entr.length;
448
449 if (nentries + 1 == UINT32_MAX) {
450 fprintf(stderr, "Too many entries, only packing 0x%08x\n", nentries);
451 break;
452 }
453 }
454
455 // reserved zeroed entry
456 memset(&cur_entr, 0, sizeof(cur_entr));
457 if (write(outfd, &cur_entr, sizeof(cur_entr)) != sizeof(cur_entr)) {
458 fprintf(stderr, "Write to result file failed: %s\n", strerror(errno));
459 goto out;
460 }
461
462 if (ftruncate(outfd, full_file_len) != 0) {
463 fprintf(stderr, "Failed to expand result file to needed size: %s\n", strerror(errno));
464 goto out;
465 }
466
467 file_map = mmap(NULL, full_file_len, PROT_READ | PROT_WRITE, MAP_SHARED, outfd, 0);
468
469 if (file_map == MAP_FAILED) {
470 fprintf(stderr, "Cant mmap result file: %s\n", strerror(errno));
471 file_map = NULL;
472 goto out;
473 }
474
475 efires_hdr_t *hdr = (efires_hdr_t *) file_map;
476 hdr->revision = htole16(EFIRES_CURRENT_REVISION);
477 hdr->nentries = htole16(nentries);
478
479 // header + nentries entries + reserved zeroed entry
480 uint32_t current_offset = sizeof(efires_hdr_t) + (nentries + 1) * sizeof(efires_file_t);
481 for (uint16_t i = 0; i != nentries; ++i) {
482 efires_file_t *ent = &hdr->entries[i];
483
484 uint32_t length = ent->length;
485 uint32_t offset = current_offset;
486 current_offset += length;
487
488 ent->length = htole32(length);
489 ent->offset = htole32(offset);
490
491 printf("0x%04x (0x%08x - 0x%08x): %s\n", i, offset, offset + length, ent->name);
492
493 int entfd = openat(dfd, ent->name, O_RDONLY);
494
495 if (entfd == -1) {
496 fprintf(stderr, "Cant open file, leaving zeroed (%s/%s): %s\n", fromdir, ent->name, strerror(errno));
497 continue;
498 }
499
500 if (read(entfd, (void*) ((uintptr_t)file_map + offset), length) != length) {
501 fprintf(stderr, "Cant read %u bytes from file, contents in efires undefined (%s/%s): %s\n", length, fromdir, ent->name, strerror(errno));
502 }
503
504 close(entfd);
505 }
506
507 result = 0;
508
509out:;
510 if (dir != NULL) {
511 closedir(dir);
512 }
513
514 if (file_map != NULL) {
515 munmap(file_map, file_size);
516 }
517
518 if (outfd != -1) {
519 close(outfd);
520
521 // delete file if error occured
522 if (result) {
523 unlink(fname);
524 }
525 }
526
527 return result;
528}
529
530#endif // WIN32
#define EFIRES_CURRENT_REVISION
__attribute__((packed, aligned(1)))
Definition EfiResTool.c:67
const char ** parse_filelist(const char *fname)
Definition EfiResTool.c:177
void print_usage(const char *prog)
Definition EfiResTool.c:100
#define ACTION_LIST
Definition EfiResTool.c:98
aligned(1)
Definition EfiResTool.c:58
int pack_efires(const char *fname, const char *fromdir, const char *filelist[])
Definition EfiResTool.c:360
unpack_flag
Definition EfiResTool.c:87
int unpack_efires(const char *fname, const char *destination, unpack_flag flags, char **filelist[])
Definition EfiResTool.c:237
#define ACTION_UNPACK
Definition EfiResTool.c:96
int write_filelist(const char **filelist, const char *fname)
Definition EfiResTool.c:217
void free_filelist(char **filelist)
Definition EfiResTool.c:169
#define ACTION_PACK
Definition EfiResTool.c:97
#define ssize_t
Definition Ubsan.h:86
#define UINT32_MAX
Definition Ubsan.h:115
#define uint32_t
Definition Ubsan.h:59
#define uintptr_t
Definition Ubsan.h:63
int main()
Definition acdtinfo.c:181
#define S_IFREG
Definition fsw_core.h:512
#define S_IFMT
Definition fsw_core.h:507
#define memset(ptr, c, len)
UINT16 uint16_t
UINT32 uint32_t
#define malloc(Size)
Definition lzss.h:49
#define free(Ptr)
Definition lzss.h:50
#define memcpy(Dst, Src, Size)
Definition lzvn.h:57
uint32_t length
Definition EfiResTool.c:56
uint32_t offset
Definition EfiResTool.c:55