diff options
-rw-r--r-- | misc-utils/flashcp.c | 93 |
1 files changed, 92 insertions, 1 deletions
diff --git a/misc-utils/flashcp.c b/misc-utils/flashcp.c index d7b0a59..341c210 100644 --- a/misc-utils/flashcp.c +++ b/misc-utils/flashcp.c @@ -67,6 +67,7 @@ #define FLAG_FILENAME 0x04 #define FLAG_DEVICE 0x08 #define FLAG_ERASE_ALL 0x10 +#define FLAG_PARTITION 0x20 /* error levels */ #define LOG_NORMAL 1 @@ -96,6 +97,7 @@ static NORETURN void showusage(bool error) "\n" " -h | --help Show this help message\n" " -v | --verbose Show progress reports\n" + " -p | --partition Only copy different block from file to device\n" " -A | --erase-all Erases the whole device regardless of the image size\n" " -V | --version Show version information and exit\n" " <filename> File which you want to copy to flash\n" @@ -181,10 +183,11 @@ int main (int argc,char *argv[]) for (;;) { int option_index = 0; - static const char *short_options = "hvAV"; + static const char *short_options = "hvpAV"; static const struct option long_options[] = { {"help", no_argument, 0, 'h'}, {"verbose", no_argument, 0, 'v'}, + {"partition", no_argument, 0, 'p'}, {"erase-all", no_argument, 0, 'A'}, {"version", no_argument, 0, 'V'}, {0, 0, 0, 0}, @@ -205,6 +208,10 @@ int main (int argc,char *argv[]) flags |= FLAG_VERBOSE; DEBUG("Got FLAG_VERBOSE\n"); break; + case 'p': + flags |= FLAG_PARTITION; + DEBUG("Got FLAG_PARTITION"); + break; case 'A': flags |= FLAG_ERASE_ALL; DEBUG("Got FLAG_ERASE_ALL\n"); @@ -257,6 +264,12 @@ int main (int argc,char *argv[]) exit (EXIT_FAILURE); } + /* diff block flashcp */ + if (flags & FLAG_PARTITION) + { + goto DIFF_BLOCKS; + } + /***************************************************** * erase enough blocks so that we can write the file * *****************************************************/ @@ -403,4 +416,82 @@ int main (int argc,char *argv[]) DEBUG("Verified %d / %lluk bytes\n",written,(unsigned long long)filestat.st_size); exit (EXIT_SUCCESS); + + /********************************************* + * Copy different blocks from file to device * + ********************************************/ +DIFF_BLOCKS: + safe_rewind (fil_fd,filename); + safe_rewind (dev_fd,device); + size = filestat.st_size; + i = mtd.erasesize; + erase.start = 0; + erase.length = (filestat.st_size + mtd.erasesize - 1) / mtd.erasesize; + erase.length *= mtd.erasesize; + written = 0; + unsigned long current_dev_block = 0; + int diffBlock = 0; + int blocks = erase.length / mtd.erasesize; + erase.length = mtd.erasesize; + + if (flags & FLAG_VERBOSE) + log_printf (LOG_NORMAL, + "\rProcessing blocks: 0/%d (%d%%)", blocks, PERCENTAGE (0,blocks)); + for (int s = 1; s <= blocks; s++) + { + if (size < mtd.erasesize) i = size; + if (flags & FLAG_VERBOSE) + log_printf (LOG_NORMAL, + "\rProcessing blocks: %d/%d (%d%%)", s, blocks, PERCENTAGE (s,blocks)); + + /* read from filename */ + safe_read (fil_fd,filename,src,i,flags & FLAG_VERBOSE); + + /* read from device */ + current_dev_block = lseek(dev_fd, 0, SEEK_CUR); + safe_read (dev_fd,device,dest,i,flags & FLAG_VERBOSE); + + /* compare buffers, if not the same, erase and write the block */ + if (memcmp (src,dest,i)) + { + diffBlock++; + /* erase block */ + lseek(dev_fd, current_dev_block, SEEK_SET); + if (ioctl (dev_fd,MEMERASE,&erase) < 0) + { + log_printf (LOG_NORMAL,"\n"); + log_printf (LOG_ERROR, + "While erasing blocks 0x%.8x-0x%.8x on %s: %m\n", + (unsigned int) erase.start,(unsigned int) (erase.start + erase.length),device); + exit (EXIT_FAILURE); + } + + /* write to device */ + lseek(dev_fd, current_dev_block, SEEK_SET); + result = write (dev_fd,src,i); + if (i != result) + { + if (flags & FLAG_VERBOSE) log_printf (LOG_NORMAL,"\n"); + if (result < 0) + { + log_printf (LOG_ERROR, + "While writing data to 0x%.8lx-0x%.8lx on %s: %m\n", + written,written + i,device); + exit (EXIT_FAILURE); + } + log_printf (LOG_ERROR, + "Short write count returned while writing to x%.8zx-0x%.8zx on %s: %zu/%llu bytes written to flash\n", + written,written + i,device,written + result,(unsigned long long)filestat.st_size); + exit (EXIT_FAILURE); + } + } + + erase.start += i; + written += i; + size -= i; + } + + if (flags & FLAG_VERBOSE) log_printf (LOG_NORMAL, "\ndiff blocks: %d\n", diffBlock); + + exit (EXIT_SUCCESS); } |