<div dir="ltr"><div>Dear John Crispin and Felix Fietkau,<br><br><b>Description:</b> During the first boot following a sysupgrade, if the rootfs_data<br>partition has not been formatted, the intended behavior is to mount a <br>temporary ram overlay filesystem, deferring the cleaning and formatting <br>of the rootfs_data partition and the switch to the jffs2 overlay until</div><div>later in the init sequence. If a sysupgrade call preserves a config across</div><div>the update (via sysupgrade.tgz), the jffs2 overlay is always immediately <br>mounted, regardless of whether or not the rootfs_data partition has <br>been formatted.<br><br>Launching the jffs2 overlay when the rootfs_data partition has not been <br>formatted blocks preinit_main for the duration of the formatting. This can <br>be fatal, especially on systems with large rootfs_data partitions. <br>Even on machines that can survive the preinit hang, the intermediate ram <br>overlay should be launched for consistency across boots.<br><br>This bug also causes the jffs2 driver to not clean up the first blocks <br>of rootfs_data used to store sysupgrade.tgz, leaving those blocks </div><div>to be cleaned before use during userspace run time. </div><div><br><b>package name:</b> package/system/fstools<br><br>--- a/libfstools/volume.c<br>+++ b/libfstools/volume.c<br>@@ -12,11 +12,17 @@<br>  */<br> <br> #include <sys/mount.h><br>+#include <sys/types.h><br>+#include <sys/stat.h><br>+#include <fcntl.h><br> #include <stdio.h><br> #include <stdlib.h><br> <br> #include “libfstools.h”<br> #include “volume.h”<br>+#include “crc32.h”<br>+<br>+#define CRC_BUF_LEN 4096<br> <br> static LIST_HEAD(drivers);<br> <br>@@ -41,3 +47,96 @@ struct volume* volume_find(char *name)<br> <br>    return NULL;<br> }<br>+<br>+/*<br>+ * if we are using a jffs2 rootfs_data partition,<br>+ * parse sysupgrade.tgz from rootfs_data, and move it<br>+ * to the newly mounted RAM read-write root<br>+ */<br>+int volume_read_tar_rootfs_data(const char* tar_destination)<br>+{<br>+   int destination_fd;<br>+   char *read_buf;<br>+   char *crc_buf;<br>+   unsigned int bytes_crc = 0;<br>+   unsigned int bytes_read = 0;<br>+   unsigned int bytes_written = 0;<br>+   unsigned int total_bytes_read = 0;<br>+   unsigned int rootfs_data_ofs = 0;<br>+   __u32 tar_page_marker;<br>+   __u32 calculated_crc;<br>+   struct tar_file_header header;<br>+   struct volume *rootfs_data = volume_find(“rootfs_data”);<br>+<br>+   volume_init(rootfs_data);<br>+   volume_read(rootfs_data, &header, 0, sizeof(header));<br>+<br>+   rootfs_data_ofs = sizeof(header);<br>+   if(header.tar_file_marker == 0xadddf111){<br>+       read_buf = malloc(rootfs_data->block_size);<br>+       if(read_buf){<br>+           destination_fd = open(tar_destination, O_RDWR | O_CREAT, S_IRWXG);<br>+           if(destination_fd >= 0){<br>+               if(header.tar_file_size >= rootfs_data->block_size - sizeof(header)){<br>+                   volume_read(rootfs_data, read_buf, rootfs_data_ofs, rootfs_data->block_size - sizeof(header));<br>+                   bytes_read = rootfs_data->block_size - sizeof(header);<br>+               }<br>+               else{<br>+                   volume_read(rootfs_data, read_buf, rootfs_data_ofs, header.tar_file_size);<br>+                   bytes_read = header.tar_file_size;<br>+               }<br>+               total_bytes_read += bytes_read;<br>+               rootfs_data_ofs += bytes_read;<br>+               bytes_written = write(destination_fd, read_buf, bytes_read);<br>+               while(bytes_written != header.tar_file_size && rootfs_data_ofs < rootfs_data->size){<br>+                   volume_read(rootfs_data, &tar_page_marker, rootfs_data_ofs, sizeof(tar_page_marker));<br>+                   rootfs_data_ofs += sizeof(tar_page_marker);<br>+                   if(tar_page_marker == 0xadddf111){<br>+                       if(header.tar_file_size >= total_bytes_read + rootfs_data->block_size - sizeof(tar_page_marker)){<br>+                           volume_read(rootfs_data, read_buf, rootfs_data_ofs, rootfs_data->block_size - sizeof(header));<br>+                           bytes_read = rootfs_data->block_size - sizeof(header);<br>+                       }<br>+                       else{<br>+                           volume_read(rootfs_data, read_buf, rootfs_data_ofs, header.tar_file_size - total_bytes_read - sizeof(tar_page_marker));<br>+                           bytes_read = header.tar_file_size - total_bytes_read - sizeof(tar_page_marker);<br>+                       }<br>+                       total_bytes_read += bytes_read;<br>+                       rootfs_data_ofs += bytes_read;<br>+                       bytes_written += write(destination_fd, read_buf, bytes_read);<br>+                   }<br>+                   else{<br>+                       /* bad block, skip it */<br>+                       rootfs_data_ofs += rootfs_data->block_size - sizeof(tar_page_marker);<br>+                   }<br>+               }<br>+               free(read_buf);<br>+               read_buf = NULL;<br>+<br>+               /* crc check */<br>+               if(bytes_written){<br>+                   lseek(destination_fd, 0, SEEK_SET);<br>+                   crc_buf = malloc(CRC_BUF_LEN);<br>+                   if(crc_buf){<br>+                       bytes_crc = read(destination_fd, crc_buf, CRC_BUF_LEN);<br>+                       calculated_crc = crc32(0, crc_buf, bytes_crc);<br>+                       while(bytes_crc){<br>+                           bytes_crc = read(destination_fd, crc_buf, CRC_BUF_LEN);<br>+                           calculated_crc = crc32(calculated_crc, crc_buf, bytes_crc);<br>+                       }<br>+                       free(crc_buf);<br>+                       if(calculated_crc == header.tar_file_crc){<br>+                           close(destination_fd);<br>+                           return 0;<br>+                       }<br>+                   }<br>+               }<br>+               /* uh oh... something went wrong */<br>+               close(destination_fd);<br>+               remove(tar_destination);<br>+           }<br>+           if(read_buf)<br>+               free(read_buf);<br>+       }<br>+   }<br>+   return -1;<br>+}<br>--- a/libfstools/volume.h<br>+++ b/libfstools/volume.h<br>@@ -42,6 +42,13 @@ struct driver {<br>    volume_erase_all_t  erase_all;<br> };<br> <br>+struct tar_file_header {<br>+   __u32 deadcode;<br>+   __u32 tar_file_marker;<br>+   __u32 tar_file_crc;<br>+   __u32 tar_file_size;<br>+};<br>+<br> enum {<br>    UNKNOWN_TYPE,<br>    NANDFLASH,<br>@@ -62,6 +69,7 @@ struct volume {<br> <br> extern struct volume* volume_find(char *name);<br> extern void volume_register_driver(struct driver *drv);<br>+extern int volume_read_tar_rootfs_data(const char* tar_destination);<br> <br> static inline int volume_init(struct volume *v)<br> {<br>--- a/libfstools/mount.c<br>+++ b/libfstools/mount.c<br>@@ -21,6 +21,7 @@<br> #include <string.h><br> <br> #include “libfstools.h”<br>+#include “volume.h”<br> <br> /* this is a raw syscall - man 2 pivot_root */<br> extern int pivot_root(const char *new_root, const char *put_old);<br>@@ -152,8 +153,17 @@ fopivot(char *rw_root, char *ro_root)<br> int<br> ramoverlay(void)<br> {<br>-   mkdir(“/tmp/root”, 0755);<br>-   mount(“tmpfs”, “/tmp/root”, “tmpfs”, MS_NOATIME, “mode=0755”);<br>+   char rw_root[64] = “/tmp/root”;<br>+   char sysupgrade_dest[64];<br> <br>-   return fopivot(“/tmp/root”, “/rom”);<br>+   mkdir(rw_root, 0755);<br>+   mount(“tmpfs”, rw_root, “tmpfs”, MS_NOATIME, “mode=0755”);<br>+<br>+   snprintf(sysupgrade_dest, sizeof(sysupgrade_dest), “%s/sysupgrade.tgz”, rw_root);<br>+   if(!volume_read_tar_rootfs_data(sysupgrade_dest))<br>+       ULOG_NOTE(“config retreived from rootfs_data\n”);<br>+   else<br>+       ULOG_NOTE(“no config retrieved from rootfs_data\n”);<br>+<br>+   return fopivot(rw_root, “/rom”);<br> }<br>--- /dev/null<br>+++ b/libfstools/crc32.h<br>@@ -0,0 +1,26 @@<br>+#ifndef CRC32_H<br>+#define CRC32_H<br>+<br>+#include <stdint.h><br>+<br>+extern const uint32_t crc32_table[256];<br>+<br>+/* Return a 32-bit CRC of the contents of the buffer. */<br>+<br>+static inline uint32_t<br>+crc32(uint32_t val, const void *ss, int len)<br>+{<br>+   const unsigned char *s = ss;<br>+   while (--len >= 0)<br>+       val = crc32_table[(val ^ *s++) & 0xff] ^ (val >> 8);<br>+   return val;<br>+}<br>+<br>+static inline unsigned int crc32buf(char *buf, size_t len)<br>+{<br>+   return crc32(0xFFFFFFFF, buf, len);<br>+}<br>+<br>+<br>+<br>+#endif<br>--- /dev/null<br>+++ b/libfstools/crc32.c<br>@@ -0,0 +1,95 @@<br>+/*<br>+ *  COPYRIGHT (C) 1986 Gary S. Brown.  You may use this program, or<br>+ *  code or tables extracted from it, as desired without restriction.<br>+ *<br>+ *  First, the polynomial itself and its table of feedback terms.  The<br>+ *  polynomial is<br>+ *  X^32+X^26+X^23+X^22+X^16+X^12+X^11+X^10+X^8+X^7+X^5+X^4+X^2+X^1+X^0<br>+ *<br>+ *  Note that we take it “backwards” and put the highest-order term in<br>+ *  the lowest-order bit.  The X^32 term is “implied”; the LSB is the<br>+ *  X^31 term, etc.  The X^0 term (usually shown as “+1") results in<br>+ *  the MSB being 1<br>+ *<br>+ *  Note that the usual hardware shift register implementation, which<br>+ *  is what we’re using (we’re merely optimizing it by doing eight-bit<br>+ *  chunks at a time) shifts bits into the lowest-order term.  In our<br>+ *  implementation, that means shifting towards the right.  Why do we<br>+ *  do it this way?  Because the calculated CRC must be transmitted in<br>+ *  order from highest-order term to lowest-order term.  UARTs transmit<br>+ *  characters in order from LSB to MSB.  By storing the CRC this way<br>+ *  we hand it to the UART in the order low-byte to high-byte; the UART<br>+ *  sends each low-bit to hight-bit; and the result is transmission bit<br>+ *  by bit from highest- to lowest-order term without requiring any bit<br>+ *  shuffling on our part.  Reception works similarly<br>+ *<br>+ *  The feedback terms table consists of 256, 32-bit entries.  Notes<br>+ *<br>+ *      The table can be generated at runtime if desired; code to do so<br>+ *      is shown later.  It might not be obvious, but the feedback<br>+ *      terms simply represent the results of eight shift/xor opera<br>+ *      tions for all combinations of data and CRC register values<br>+ *<br>+ *      The values must be right-shifted by eight bits by the “updcrc<br>+ *      logic; the shift must be unsigned (bring in zeroes).  On some<br>+ *      hardware you could probably optimize the shift in assembler by<br>+ *      using byte-swap instructions<br>+ *      polynomial $edb88320<br>+ */<br>+<br>+#include <stdint.h><br>+<br>+const uint32_t crc32_table[256] = {<br>+   0x00000000L, 0x77073096L, 0xee0e612cL, 0x990951baL, 0x076dc419L,<br>+   0x706af48fL, 0xe963a535L, 0x9e6495a3L, 0x0edb8832L, 0x79dcb8a4L,<br>+   0xe0d5e91eL, 0x97d2d988L, 0x09b64c2bL, 0x7eb17cbdL, 0xe7b82d07L,<br>+   0x90bf1d91L, 0x1db71064L, 0x6ab020f2L, 0xf3b97148L, 0x84be41deL,<br>+   0x1adad47dL, 0x6ddde4ebL, 0xf4d4b551L, 0x83d385c7L, 0x136c9856L,<br>+   0x646ba8c0L, 0xfd62f97aL, 0x8a65c9ecL, 0x14015c4fL, 0x63066cd9L,<br>+   0xfa0f3d63L, 0x8d080df5L, 0x3b6e20c8L, 0x4c69105eL, 0xd56041e4L,<br>+   0xa2677172L, 0x3c03e4d1L, 0x4b04d447L, 0xd20d85fdL, 0xa50ab56bL,<br>+   0x35b5a8faL, 0x42b2986cL, 0xdbbbc9d6L, 0xacbcf940L, 0x32d86ce3L,<br>+   0x45df5c75L, 0xdcd60dcfL, 0xabd13d59L, 0x26d930acL, 0x51de003aL,<br>+   0xc8d75180L, 0xbfd06116L, 0x21b4f4b5L, 0x56b3c423L, 0xcfba9599L,<br>+   0xb8bda50fL, 0x2802b89eL, 0x5f058808L, 0xc60cd9b2L, 0xb10be924L,<br>+   0x2f6f7c87L, 0x58684c11L, 0xc1611dabL, 0xb6662d3dL, 0x76dc4190L,<br>+   0x01db7106L, 0x98d220bcL, 0xefd5102aL, 0x71b18589L, 0x06b6b51fL,<br>+   0x9fbfe4a5L, 0xe8b8d433L, 0x7807c9a2L, 0x0f00f934L, 0x9609a88eL,<br>+   0xe10e9818L, 0x7f6a0dbbL, 0x086d3d2dL, 0x91646c97L, 0xe6635c01L,<br>+   0x6b6b51f4L, 0x1c6c6162L, 0x856530d8L, 0xf262004eL, 0x6c0695edL,<br>+   0x1b01a57bL, 0x8208f4c1L, 0xf50fc457L, 0x65b0d9c6L, 0x12b7e950L,<br>+   0x8bbeb8eaL, 0xfcb9887cL, 0x62dd1ddfL, 0x15da2d49L, 0x8cd37cf3L,<br>+   0xfbd44c65L, 0x4db26158L, 0x3ab551ceL, 0xa3bc0074L, 0xd4bb30e2L,<br>+   0x4adfa541L, 0x3dd895d7L, 0xa4d1c46dL, 0xd3d6f4fbL, 0x4369e96aL,<br>+   0x346ed9fcL, 0xad678846L, 0xda60b8d0L, 0x44042d73L, 0x33031de5L,<br>+   0xaa0a4c5fL, 0xdd0d7cc9L, 0x5005713cL, 0x270241aaL, 0xbe0b1010L,<br>+   0xc90c2086L, 0x5768b525L, 0x206f85b3L, 0xb966d409L, 0xce61e49fL,<br>+   0x5edef90eL, 0x29d9c998L, 0xb0d09822L, 0xc7d7a8b4L, 0x59b33d17L,<br>+   0x2eb40d81L, 0xb7bd5c3bL, 0xc0ba6cadL, 0xedb88320L, 0x9abfb3b6L,<br>+   0x03b6e20cL, 0x74b1d29aL, 0xead54739L, 0x9dd277afL, 0x04db2615L,<br>+   0x73dc1683L, 0xe3630b12L, 0x94643b84L, 0x0d6d6a3eL, 0x7a6a5aa8L,<br>+   0xe40ecf0bL, 0x9309ff9dL, 0x0a00ae27L, 0x7d079eb1L, 0xf00f9344L,<br>+   0x8708a3d2L, 0x1e01f268L, 0x6906c2feL, 0xf762575dL, 0x806567cbL,<br>+   0x196c3671L, 0x6e6b06e7L, 0xfed41b76L, 0x89d32be0L, 0x10da7a5aL,<br>+   0x67dd4accL, 0xf9b9df6fL, 0x8ebeeff9L, 0x17b7be43L, 0x60b08ed5L,<br>+   0xd6d6a3e8L, 0xa1d1937eL, 0x38d8c2c4L, 0x4fdff252L, 0xd1bb67f1L,<br>+   0xa6bc5767L, 0x3fb506ddL, 0x48b2364bL, 0xd80d2bdaL, 0xaf0a1b4cL,<br>+   0x36034af6L, 0x41047a60L, 0xdf60efc3L, 0xa867df55L, 0x316e8eefL,<br>+   0x4669be79L, 0xcb61b38cL, 0xbc66831aL, 0x256fd2a0L, 0x5268e236L,<br>+   0xcc0c7795L, 0xbb0b4703L, 0x220216b9L, 0x5505262fL, 0xc5ba3bbeL,<br>+   0xb2bd0b28L, 0x2bb45a92L, 0x5cb36a04L, 0xc2d7ffa7L, 0xb5d0cf31L,<br>+   0x2cd99e8bL, 0x5bdeae1dL, 0x9b64c2b0L, 0xec63f226L, 0x756aa39cL,<br>+   0x026d930aL, 0x9c0906a9L, 0xeb0e363fL, 0x72076785L, 0x05005713L,<br>+   0x95bf4a82L, 0xe2b87a14L, 0x7bb12baeL, 0x0cb61b38L, 0x92d28e9bL,<br>+   0xe5d5be0dL, 0x7cdcefb7L, 0x0bdbdf21L, 0x86d3d2d4L, 0xf1d4e242L,<br>+   0x68ddb3f8L, 0x1fda836eL, 0x81be16cdL, 0xf6b9265bL, 0x6fb077e1L,<br>+   0x18b74777L, 0x88085ae6L, 0xff0f6a70L, 0x66063bcaL, 0x11010b5cL,<br>+   0x8f659effL, 0xf862ae69L, 0x616bffd3L, 0x166ccf45L, 0xa00ae278L,<br>+   0xd70dd2eeL, 0x4e048354L, 0x3903b3c2L, 0xa7672661L, 0xd06016f7L,<br>+   0x4969474dL, 0x3e6e77dbL, 0xaed16a4aL, 0xd9d65adcL, 0x40df0b66L,<br>+   0x37d83bf0L, 0xa9bcae53L, 0xdebb9ec5L, 0x47b2cf7fL, 0x30b5ffe9L,<br>+   0xbdbdf21cL, 0xcabac28aL, 0x53b39330L, 0x24b4a3a6L, 0xbad03605L,<br>+   0xcdd70693L, 0x54de5729L, 0x23d967bfL, 0xb3667a2eL, 0xc4614ab8L,<br>+   0x5d681b02L, 0x2a6f2b94L, 0xb40bbe37L, 0xc30c8ea1L, 0x5a05df1bL,<br>+   0x2d02ef8dL<br>+};<br>--- a/CMakeLists.txt<br>+++ b/CMakeLists.txt<br>@@ -14,7 +14,8 @@ ADD_LIBRARY(fstools SHARED<br>        libfstools/mount.c<br>        libfstools/ubi.c<br>        libfstools/rootdisk.c<br>-       libfstools/find.c)<br>+       libfstools/find.c<br>+       libfstools/crc32.c)<br> TARGET_LINK_LIBRARIES(fstools ubox)<br> INSTALL(TARGETS fstools LIBRARY DESTINATION lib)<br> <br><br><b>package name:</b> package/system/mtd<br><br>--- a/jffs2.c<br>+++ b/jffs2.c<br>@@ -26,6 +26,7 @@<br> #include <dirent.h><br> #include <unistd.h><br> #include <endian.h><br>+#include <limits.h><br> #include “jffs2.h”<br> #include “crc32.h”<br> #include “mtd.h”<br>@@ -34,10 +35,14 @@<br> <br> #if BYTE_ORDER == BIG_ENDIAN<br> # define CLEANMARKER “\x19\x85\x20\x03\x00\x00\x00\x0c\xf0\x60\xdc\x98"<br>+# define TARFILEMARKER “\xad\xdd\xf1\x11”<br> #else<br> # define CLEANMARKER “\x85\x19\x03\x20\x0c\x00\x00\x00\xb1\xb0\x1e\xe4"<br>+# define TARFILEMARKER “\x11\xf1\xdd\xad”<br> #endif<br> <br>+#define CRC_BUF_LEN 4096<br>+<br> static int last_ino = 0;<br> static int last_version = 0;<br> static char *buf = NULL;<br>@@ -236,24 +241,120 @@ static void add_file(const char *name, i<br>    close(fd);<br> }<br> <br>-int mtd_replace_jffs2(const char *mtd, int fd, int ofs, const char *filename)<br>+void add_tar_cleanup(int fd, int in_mtdofs)<br> {<br>-   outfd = fd;<br>-   mtdofs = ofs;<br>-<br>-   buf = malloc(erasesize);<br>-   target_ino = 1;<br>-   if (!last_ino)<br>-       last_ino = 1;<br>-   add_file(filename, target_ino);<br>-   pad(erasesize);<br>+   ofs = 0;<br>+   mtdofs = in_mtdofs;<br> <br>-   /* add eof marker, pad to eraseblock size and write the data */<br>+   /* If at any point we fail, erase the first block<br>+    * and replace the JFFS2_EOF. In mtd_add_tar_file_jffs2(),<br>+    * return a ‘skip’ of 1 erase block so that we jump over 0xdeadc0de. */<br>+   mtd_erase_block(fd, mtdofs);<br>    add_data(JFFS2_EOF, sizeof(JFFS2_EOF) - 1);<br>    pad(erasesize);<br>-   free(buf);<br>+}<br>+<br>+int mtd_add_tar_file_jffs2(const char *mtd, int fd, int in_mtdofs, const char *filename)<br>+{<br>+   outfd = fd;<br>+   mtdofs = in_mtdofs;<br>+   struct stat tar_file_st;<br>+   int tar_fd;<br>+   int bytes_crc = 0;<br>+   int bytes_read = 0;<br>+   int total_bytes_read = 0;<br>+   char* crc_buf;<br>+   uint32_t temp_file_size = 0;<br>+   uint32_t tar_crc = 0;<br>+   uint32_t mask = 0xffffffff;<br>+<br>+   /* If sysupgrade.tgz passed in,<br>+    * write 16-byte header followed by file contents.<br>+    * TARFILEMARKER will head each subsequent block<br>+    * needed to write the rest of the file. */<br>+   if (!stat(filename, &tar_file_st)){<br>+       tar_fd = open(filename, 0);<br>+       if (tar_fd < 0) {<br>+           fprintf(stderr, “File %s does not exist\n”, filename);<br>+           add_tar_cleanup(outfd, in_mtdofs);<br>+           return erasesize;<br>+       }<br>+<br>+       /* Calculate crc */<br>+       crc_buf = malloc(CRC_BUF_LEN);<br>+       if(!crc_buf){<br>+           fprintf(stderr, “Out of memory\n”);<br>+           add_tar_cleanup(outfd, in_mtdofs);<br>+           return erasesize;<br>+       }<br>+       bytes_crc = read(tar_fd, crc_buf, CRC_BUF_LEN);<br>+       tar_crc = crc32(0, crc_buf, bytes_crc);<br>+       while(bytes_crc)<br>+       {<br>+           bytes_crc = read(tar_fd, crc_buf, CRC_BUF_LEN);<br>+           tar_crc = crc32(tar_crc, crc_buf, bytes_crc);<br>+       }<br>+       free(crc_buf);<br>+       lseek(tar_fd, 0, SEEK_SET);<br>+       buf = malloc(erasesize);<br>+       if(!buf){<br>+           fprintf(stderr, “Out of memory\n”);<br>+           add_tar_cleanup(outfd, in_mtdofs);<br>+           return erasesize;<br>+       }<br>+       ofs = 0;<br>+<br>+       add_data(JFFS2_EOF, sizeof(JFFS2_EOF) - 1);<br>+       add_data(TARFILEMARKER, sizeof(TARFILEMARKER) - 1);<br>+<br>+       /* sizeof(off_t) can be 16 to 64 bytes.<br>+        * Set the cut off at 4 bytes unsigned */<br>+       if(tar_file_st.st_size >= 0 && tar_file_st.st_size <= UINT_MAX){<br>+           temp_file_size = tar_file_st.st_size & mask;<br>+       }<br>+       else{<br>+           fprintf(stderr, “Incoming tar file too large. Tar file size is %lld, max size is %u”<br>+               , tar_file_st.st_size<br>+               , UINT_MAX<br>+               );<br>+           add_tar_cleanup(outfd, in_mtdofs);<br>+           free(buf);<br>+           close(tar_fd);<br>+           return erasesize;<br>+       }<br>+<br>+       add_data((char*)&tar_crc, sizeof(tar_crc));<br>+       add_data((char*)&temp_file_size, sizeof(mask));<br>+<br>+       total_bytes_read = read(tar_fd, buf + ofs,<br>+           erasesize - (sizeof(JFFS2_EOF) - 1 + sizeof(TARFILEMARKER) - 1 + sizeof(erasesize) + 4));<br>+       ofs += total_bytes_read;<br>+       pad(erasesize);<br>+<br>+       while(total_bytes_read != temp_file_size && mtdofs < mtdsize)<br>+       {<br>+           ofs = 0;<br>+           add_data(TARFILEMARKER, sizeof(TARFILEMARKER) - 1);<br>+           bytes_read = read(tar_fd, buf + ofs, erasesize - sizeof(TARFILEMARKER) - 1);<br>+           ofs += bytes_read;<br>+           pad(erasesize);<br>+           total_bytes_read += bytes_read;<br>+       }<br>+       if(total_bytes_read != tar_file_st.st_size){<br>+           fprintf(stderr, “Error reading from file %s\n”, filename);<br>+           add_tar_cleanup(outfd, in_mtdofs);<br>+           free(buf);<br>+           close(tar_fd);<br>+           return erasesize;<br>+       }<br>+       free(buf);<br>+       close(tar_fd);<br>+       ofs = 0;<br>+       return (mtdofs - in_mtdofs);<br>+   }<br> <br>-   return (mtdofs - ofs);<br>+   add_tar_cleanup(outfd, in_mtdofs);<br>+   return mtdofs - in_mtdofs;<br> }<br> <br> void mtd_parse_jffs2data(const char *buf, const char *dir)<br>--- a/mtd.c<br>+++ b/mtd.c<br>@@ -468,7 +468,7 @@ mtd_write(int imagefd, const char *mtd, <br>    ssize_t r, w, e;<br>    ssize_t skip = 0;<br>    uint32_t offset = 0;<br>-   int jffs2_replaced = 0;<br>+   int jffs2_tar_file_added = 0;<br>    int skip_bad_blocks = 0;<br> <br> #ifdef FIS_SUPPORT<br>@@ -597,8 +597,8 @@ resume:<br>                if (quiet < 2)<br>                    fprintf(stderr, “\nAppending jffs2 data from %s to %s..\n.“, jffs2file, mtd);<br>                /* got an EOF marker - this is the place to add some jffs2 data */<br>-               skip = mtd_replace_jffs2(mtd, fd, e, jffs2file);<br>-               jffs2_replaced = 1;<br>+               skip = mtd_add_tar_file_jffs2(mtd, fd, e, jffs2file);<br>+               jffs2_tar_file_added = 1;<br> <br>                /* don’t add it again */<br>                jffs2file = NULL;<br>@@ -675,7 +675,7 @@ resume:<br>        offset = 0;<br>    }<br> <br>-   if (jffs2_replaced) {<br>+   if (jffs2_tar_file_added) {<br>        switch (imageformat) {<br>        case MTD_IMAGE_FORMAT_TRX:<br>            if (trx_fixup)<br>--- a/mtd.h<br>+++ b/mtd.h<br>@@ -19,7 +19,7 @@ extern int mtd_block_is_bad(int fd, int <br> extern int mtd_erase_block(int fd, int offset);<br> extern int mtd_write_buffer(int fd, const char *buf, int offset, int length);<br> extern int mtd_write_jffs2(const char *mtd, const char *filename, const char *dir);<br>-extern int mtd_replace_jffs2(const char *mtd, int fd, int ofs, const char *filename);<br>+extern int mtd_add_tar_file_jffs2(const char *mtd, int fd, int ofs, const char *filename);<br> extern void mtd_parse_jffs2data(const char *buf, const char *dir);<br> <br> /* target specific functions */<br><br>Signed-off-by: Sean Miller <<a href="mailto:seanmichaelmiller2014@gmail.com">seanmichaelmiller2014@gmail.com</a>><br><br>These two patches (both must be applied) fix this bug. </div><div>If always mounting the jffs2 overlay and skipping the ram overlay when </div><div>sysupgrade.tgz is saved across an upgrade is the desired behavior, </div><div>I will instead submit changes to the documentation.</div><div><br>Thanks for your time</div></div>