Make sure the utilities don't lose appended junk on FatELF files.
authorRyan C. Gordon <icculus@icculus.org>
Sat, 24 Oct 2009 03:16:31 -0400
changeset 102 f59e3ae223b1
parent 101 0087a1620fbe
child 103 7528b40af909
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
utils/fatelf-info.c
utils/fatelf-remove.c
utils/fatelf-replace.c
utils/fatelf-split.c
utils/fatelf-utils.c
utils/fatelf-utils.h
--- a/utils/fatelf-extract.c	Sat Oct 24 03:14:27 2009 -0400
+++ b/utils/fatelf-extract.c	Sat Oct 24 03:16:31 2009 -0400
@@ -21,6 +21,7 @@
     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);
--- a/utils/fatelf-info.c	Sat Oct 24 03:14:27 2009 -0400
+++ b/utils/fatelf-info.c	Sat Oct 24 03:16:31 2009 -0400
@@ -14,10 +14,17 @@
     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];
--- a/utils/fatelf-remove.c	Sat Oct 24 03:14:27 2009 -0400
+++ b/utils/fatelf-remove.c	Sat Oct 24 03:16:31 2009 -0400
@@ -50,6 +50,8 @@
         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);
 
--- a/utils/fatelf-replace.c	Sat Oct 24 03:14:27 2009 -0400
+++ b/utils/fatelf-replace.c	Sat Oct 24 03:16:31 2009 -0400
@@ -61,6 +61,8 @@
         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);
 
--- a/utils/fatelf-split.c	Sat Oct 24 03:14:27 2009 -0400
+++ b/utils/fatelf-split.c	Sat Oct 24 03:16:31 2009 -0400
@@ -116,6 +116,7 @@
         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);
--- a/utils/fatelf-utils.c	Sat Oct 24 03:14:27 2009 -0400
+++ b/utils/fatelf-utils.c	Sat Oct 24 03:16:31 2009 -0400
@@ -169,6 +169,15 @@
 } // 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 @@
 } // 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 @@
 } // 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.
--- a/utils/fatelf-utils.h	Sat Oct 24 03:14:27 2009 -0400
+++ b/utils/fatelf-utils.h	Sat Oct 24 03:16:31 2009 -0400
@@ -17,6 +17,8 @@
 #include <fcntl.h>
 #include <stdint.h>
 #include <assert.h>
+#include <sys/types.h>
+#include <sys/stat.h>
 
 #include "fatelf.h"
 
@@ -89,6 +91,9 @@
                      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 @@
 // 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);