From 2345ab218d0bfe2d53c39e918bb98688ad5aacf5 Mon Sep 17 00:00:00 2001 From: "Ryan C. Gordon" Date: Sat, 24 Oct 2009 03:16:31 -0400 Subject: [PATCH] Make sure the utilities don't lose appended junk on FatELF files. Otherwise, if you split a self-extracting .zip file, you lose the .zip data. --- utils/fatelf-extract.c | 1 + utils/fatelf-info.c | 7 +++++ utils/fatelf-remove.c | 2 ++ utils/fatelf-replace.c | 2 ++ utils/fatelf-split.c | 1 + utils/fatelf-utils.c | 65 ++++++++++++++++++++++++++++++++++++++++++ utils/fatelf-utils.h | 20 +++++++++++++ 7 files changed, 98 insertions(+) diff --git a/utils/fatelf-extract.c b/utils/fatelf-extract.c index 8de654d..01427b2 100644 --- a/utils/fatelf-extract.c +++ b/utils/fatelf-extract.c @@ -21,6 +21,7 @@ static int fatelf_extract(const char *out, const char *fname, unlink_on_xfail = out; xcopyfile_range(fname, fd, out, outfd, rec->offset, rec->size); + xappend_junk(fname, fd, out, outfd, header); xclose(out, outfd); xclose(fname, fd); free(header); diff --git a/utils/fatelf-info.c b/utils/fatelf-info.c index d9b02b7..838b5ff 100644 --- a/utils/fatelf-info.c +++ b/utils/fatelf-info.c @@ -14,10 +14,17 @@ static int fatelf_info(const char *fname) const int fd = xopen(fname, O_RDONLY, 0755); FATELF_header *header = xread_fatelf_header(fname, fd); unsigned int i = 0; + uint64_t junkoffset, junksize; printf("%s: FatELF format version %d\n", fname, (int) header->version); printf("%d records.\n", (int) header->num_records); + if (xfind_junk(fname, fd, header, &junkoffset, &junksize)) + { + printf("%llu bytes of junk appended, starting at offset %llu.\n", + (unsigned long long) junksize, (unsigned long long) junkoffset); + } // if + for (i = 0; i < header->num_records; i++) { const FATELF_record *rec = &header->records[i]; diff --git a/utils/fatelf-remove.c b/utils/fatelf-remove.c index 772fc47..fa88d4a 100644 --- a/utils/fatelf-remove.c +++ b/utils/fatelf-remove.c @@ -50,6 +50,8 @@ static int fatelf_remove(const char *out, const char *fname, memmove(dst, src, sizeof (FATELF_record) * count); } // if + xappend_junk(fname, fd, out, outfd, header); + // Write the actual FatELF header now... xwrite_fatelf_header(out, outfd, header); diff --git a/utils/fatelf-replace.c b/utils/fatelf-replace.c index c24e0d2..fe6942f 100644 --- a/utils/fatelf-replace.c +++ b/utils/fatelf-replace.c @@ -61,6 +61,8 @@ static int fatelf_replace(const char *out, const char *fname, offset = binary_offset + rec->size; } // for + xappend_junk(fname, fd, out, outfd, header); + // Write the actual FatELF header now... xwrite_fatelf_header(out, outfd, header); diff --git a/utils/fatelf-split.c b/utils/fatelf-split.c index cbb3d04..c233219 100644 --- a/utils/fatelf-split.c +++ b/utils/fatelf-split.c @@ -116,6 +116,7 @@ static int fatelf_split(const char *fname) outfd = xopen(out, O_WRONLY | O_CREAT | O_TRUNC, 0755); unlink_on_xfail = out; xcopyfile_range(fname, fd, out, outfd, rec->offset, rec->size); + xappend_junk(fname, fd, out, outfd, header); xclose(out, outfd); unlink_on_xfail = NULL; free(out); diff --git a/utils/fatelf-utils.c b/utils/fatelf-utils.c index a83ecea..f56bdba 100644 --- a/utils/fatelf-utils.c +++ b/utils/fatelf-utils.c @@ -169,6 +169,15 @@ void xlseek(const char *fname, const int fd, } // xlseek +uint64_t xget_file_size(const char *fname, const int fd) +{ + struct stat statbuf; + if (fstat(fd, &statbuf) == -1) + xfail("Failed to fstat '%s': %s", fname, strerror(errno)); + return (uint64_t) statbuf.st_size; +} // xget_file_size + + static uint8_t copybuf[256 * 1024]; // xfail() on error. @@ -771,6 +780,30 @@ int fatelf_record_matches(const FATELF_record *a, const FATELF_record *b) } // fatelf_record_matches +int find_furthest_record(const FATELF_header *header) +{ + // there's nothing that says the records have to be in order, although + // we probably _should_. Just in case, check them all. + const int total = (int) header->num_records; + uint64_t furthest = 0; + int retval = -1; + int i; + + for (i = 0; i < total; i++) + { + const FATELF_record *rec = &header->records[i]; + const uint64_t edge = rec->offset + rec->size; + if (edge > furthest) + { + retval = i; + furthest = edge; + } // if + } // for + + return retval; +} // find_furthest_record + + const char *fatelf_get_wordsize_string(const uint8_t wordsize) { if (wordsize == FATELF_32BITS) @@ -864,6 +897,38 @@ const char *fatelf_get_target_name(const FATELF_record *rec, const int wants) } // fatelf_get_target_name +int xfind_junk(const char *fname, const int fd, const FATELF_header *header, + uint64_t *offset, uint64_t *size) +{ + const int furthest = find_furthest_record(header); + + if (furthest >= 0) // presumably, we failed elsewhere, but oh well. + { + const uint64_t fsize = xget_file_size(fname, fd); + const FATELF_record *rec = &header->records[furthest]; + const uint64_t edge = rec->offset + rec->size; + if (fsize > edge) + { + *offset = edge; + *size = fsize - edge; + return 1; + } // if + } // if + + return 0; +} // xfind_junk + + +void xappend_junk(const char *fname, const int fd, + const char *out, const int outfd, + const FATELF_header *header) +{ + uint64_t offset, size; + if (xfind_junk(fname, fd, header, &offset, &size)) + xcopyfile_range(fname, fd, out, outfd, offset, size); +} // xappend_junk + + void xfatelf_init(int argc, const char **argv) { memset(zerobuf, '\0', sizeof (zerobuf)); // just in case. diff --git a/utils/fatelf-utils.h b/utils/fatelf-utils.h index a1ac661..a71bf57 100644 --- a/utils/fatelf-utils.h +++ b/utils/fatelf-utils.h @@ -17,6 +17,8 @@ #include #include #include +#include +#include #include "fatelf.h" @@ -89,6 +91,9 @@ void xcopyfile_range(const char *in, const int infd, const char *out, const int outfd, const uint64_t offset, const uint64_t size); +// get the length of an open file in bytes. +uint64_t xget_file_size(const char *fname, const int fd); + // read the parts of an ELF header we care about. void xread_elf_header(const char *fname, const int fd, const uint64_t offset, FATELF_record *rec); @@ -104,9 +109,24 @@ void xwrite_fatelf_header(const char *fname, const int fd, // don't forget to free() the returned pointer! FATELF_header *xread_fatelf_header(const char *fname, const int fd); +// Locate non-FatELF data at the end of a FatELF file fd, based on +// header header. Returns non-zero if junk found, and fills in offset and +// size. +int xfind_junk(const char *fname, const int fd, const FATELF_header *header, + uint64_t *offset, uint64_t *size); + +// Write non-FatELF data at the end of FatELF file fd to current position in +// outfd, based on header header. +void xappend_junk(const char *fname, const int fd, + const char *out, const int outfd, + const FATELF_header *header); + // Align a value to the page size. uint64_t align_to_page(const uint64_t offset); +// find the record closest to the end of the file. -1 on error! +int find_furthest_record(const FATELF_header *header); + const fatelf_machine_info *get_machine_by_id(const uint16_t id); const fatelf_machine_info *get_machine_by_name(const char *name); const fatelf_osabi_info *get_osabi_by_id(const uint8_t id);