[PATCH] support zlib decompression in flashcp
Hamish Moffatt
hamish at cloud.net.au
Mon May 21 03:48:26 EDT 2007
Hi,
Here's a patch which allows flashcp to decompress .gz files on the fly
using zlib. It's against the git tree from a week or two ago.
It adds a new command line switch -z (or --gzip).
The zlib functions allow transparent access to uncompressed files.
However rather than using this I force the user to request
decompression; this is so that you can still write .gz files
directly to flash without decompression if that is what you want (eg
a gzip-compressed ramdisk image).
I shouldn't really use <asm/byteorder.h>, but I need __le32_to_cpu
or an equivalent. Is there a better approach?
Comments welcome?
Hamish
--
Hamish Moffatt VK3SB <hamish at debian.org> <hamish at cloud.net.au>
Index: Makefile
===================================================================
--- Makefile (revision 1097)
+++ Makefile (working copy)
@@ -96,6 +96,9 @@
$(BUILDDIR)/sumtool: $(BUILDDIR)/sumtool.o $(BUILDDIR)/crc32.o
$(CC) $(LDFLAGS) -o $@ $^
+$(BUILDDIR)/flashcp: $(BUILDDIR)/flashcp.o
+ $(CC) $(LDFLAGS) -o $@ $^ -lz
+
install: ${TARGETS}
mkdir -p ${DESTDIR}/${SBINDIR}
install -m0755 ${TARGETS} ${DESTDIR}/${SBINDIR}/
Index: flashcp.c
===================================================================
--- flashcp.c (revision 1097)
+++ flashcp.c (working copy)
@@ -42,6 +42,9 @@
#include <unistd.h>
#include <mtd/mtd-user.h>
#include <getopt.h>
+#include <errno.h>
+#include <zlib.h>
+#include <asm/byteorder.h>
typedef int bool;
#define true 1
@@ -71,6 +74,7 @@
#define FLAG_HELP 0x02
#define FLAG_FILENAME 0x04
#define FLAG_DEVICE 0x08
+#define FLAG_GZIP 0x10
/* error levels */
#define LOG_NORMAL 1
@@ -99,6 +103,7 @@
"\n"
" -h | --help Show this help message\n"
" -v | --verbose Show progress reports\n"
+ " -z | --gzip Decompress gzip file on the fly\n"
" <filename> File which you want to copy to flash\n"
" <device> Flash device to write to (e.g. /dev/mtd0, /dev/mtd1, etc.)\n"
"\n",
@@ -146,6 +151,24 @@
}
}
+static void safe_gzread (gzFile gz,const char *filename,void *buf,size_t count,bool verbose)
+{
+ ssize_t result;
+
+ result = gzread (gz,buf,count);
+ if (count != result)
+ {
+ if (verbose) log_printf (LOG_NORMAL,"\n");
+ if (result < 0)
+ {
+ log_printf (LOG_ERROR,"While reading data from %s: %m\n",filename);
+ exit (EXIT_FAILURE);
+ }
+ log_printf (LOG_ERROR,"Short read count returned while reading from %s\n",filename);
+ exit (EXIT_FAILURE);
+ }
+}
+
static void safe_rewind (int fd,const char *filename)
{
if (lseek (fd,0L,SEEK_SET) < 0)
@@ -155,9 +178,18 @@
}
}
+static void safe_gzrewind (gzFile gz,const char *filename)
+{
+ if (gzrewind(gz))
+ {
+ log_printf (LOG_ERROR,"While seeking to start of %s: %m\n",filename);
+ exit (EXIT_FAILURE);
+ }
+}
/******************************************************************************/
static int dev_fd = -1,fil_fd = -1;
+static gzFile fil_gz = NULL;
static void cleanup (void)
{
@@ -170,7 +202,7 @@
const char *progname,*filename = NULL,*device = NULL;
int i,flags = FLAG_NONE;
ssize_t result;
- size_t size,written;
+ size_t size, written, total_size = 0;
struct mtd_info_user mtd;
struct erase_info_user erase;
struct stat filestat;
@@ -184,10 +216,11 @@
for (;;) {
int option_index = 0;
- static const char *short_options = "hv";
+ static const char *short_options = "hvz";
static const struct option long_options[] = {
{"help", no_argument, 0, 'h'},
{"verbose", no_argument, 0, 'v'},
+ {"gzip", no_argument, 0, 'z'},
{0, 0, 0, 0},
};
@@ -206,6 +239,10 @@
flags |= FLAG_VERBOSE;
DEBUG("Got FLAG_VERBOSE\n");
break;
+ case 'z':
+ flags |= FLAG_GZIP;
+ DEBUG("Got FLAG_GZIP\n");
+ break;
default:
DEBUG("Unknown parameter: %s\n",argv[option_index]);
showusage (progname,true);
@@ -221,7 +258,7 @@
DEBUG("Got device: %s\n",device);
}
- if (flags & FLAG_HELP || progname == NULL || device == NULL)
+ if (flags & FLAG_HELP || filename == NULL || device == NULL)
showusage (progname,flags != FLAG_HELP);
atexit (cleanup);
@@ -237,14 +274,47 @@
/* get some info about the file we want to copy */
fil_fd = safe_open (filename,O_RDONLY);
- if (fstat (fil_fd,&filestat) < 0)
- {
- log_printf (LOG_ERROR,"While trying to get the file status of %s: %m\n",filename);
- exit (EXIT_FAILURE);
+
+ if (flags & FLAG_GZIP) {
+ /* Check the header */
+ safe_read(fil_fd, filename, src, 2, false);
+ if (memcmp(src, "\037\213", 2) != 0) {
+ log_printf (LOG_ERROR,"This doesn't seem to be a valid gzip file\n");
+ exit (EXIT_FAILURE);
+ }
+
+ /* Get the file size from the trailer */
+ if (lseek(fil_fd, -4, SEEK_END) == -1L) {
+ log_printf (LOG_ERROR, "Could not seek to end of file: %s\n", sys_errlist[errno]);
+ exit (EXIT_FAILURE);
+ }
+
+ safe_read(fil_fd, filename, src, 4, false);
+ memcpy(&total_size, src, 4);
+ total_size = __le32_to_cpu(total_size);
+ safe_rewind(fil_fd, filename);
+
+ log_printf(LOG_NORMAL, "File size is %d\n", total_size);
+
+ if ((fil_gz = gzdopen(fil_fd, "r")) == NULL)
+ {
+ log_printf (LOG_ERROR,"While trying to initialize gzip\n");
+ exit (EXIT_FAILURE);
+ }
+
+ } else {
+
+ if (fstat (fil_fd,&filestat) < 0)
+ {
+ log_printf (LOG_ERROR,"While trying to get the file status of %s: %m\n",filename);
+ exit (EXIT_FAILURE);
+ }
+ total_size = filestat.st_size;
+
}
/* does it fit into the device/partition? */
- if (filestat.st_size > mtd.size)
+ if (total_size > mtd.size)
{
log_printf (LOG_ERROR,"%s won't fit into %s!\n",filename,device);
exit (EXIT_FAILURE);
@@ -257,8 +327,8 @@
#warning "Check for smaller erase regions"
erase.start = 0;
- erase.length = filestat.st_size & ~(mtd.erasesize - 1);
- if (filestat.st_size % mtd.erasesize) erase.length += mtd.erasesize;
+ erase.length = total_size & ~(mtd.erasesize - 1);
+ if (total_size % mtd.erasesize) erase.length += mtd.erasesize;
if (flags & FLAG_VERBOSE)
{
/* if the user wants verbose output, erase 1 block at a time and show him/her what's going on */
@@ -291,14 +361,14 @@
exit (EXIT_FAILURE);
}
}
- DEBUG("Erased %u / %luk bytes\n",erase.length,filestat.st_size);
+ DEBUG("Erased %u / %luk bytes\n",erase.length,total_size);
/**********************************
* write the entire file to flash *
**********************************/
- if (flags & FLAG_VERBOSE) log_printf (LOG_NORMAL,"Writing data: 0k/%luk (0%%)",KB (filestat.st_size));
- size = filestat.st_size;
+ if (flags & FLAG_VERBOSE) log_printf (LOG_NORMAL,"Writing data: 0k/%luk (0%%)",KB (total_size));
+ size = total_size;
i = BUFSIZE;
written = 0;
while (size)
@@ -307,11 +377,14 @@
if (flags & FLAG_VERBOSE)
log_printf (LOG_NORMAL,"\rWriting data: %dk/%luk (%lu%%)",
KB (written + i),
- KB (filestat.st_size),
- PERCENTAGE (written + i,filestat.st_size));
+ KB (total_size),
+ PERCENTAGE (written + i,total_size));
/* read from filename */
- safe_read (fil_fd,filename,src,i,flags & FLAG_VERBOSE);
+ if (flags & FLAG_GZIP)
+ safe_gzread (fil_gz,filename,src,i,flags & FLAG_VERBOSE);
+ else
+ safe_read (fil_fd,filename,src,i,flags & FLAG_VERBOSE);
/* write to device */
result = write (dev_fd,src,i);
@@ -327,7 +400,7 @@
}
log_printf (LOG_ERROR,
"Short write count returned while writing to x%.8x-0x%.8x on %s: %d/%lu bytes written to flash\n",
- written,written + i,device,written + result,filestat.st_size);
+ written,written + i,device,written + result,total_size);
exit (EXIT_FAILURE);
}
@@ -337,20 +410,24 @@
if (flags & FLAG_VERBOSE)
log_printf (LOG_NORMAL,
"\rWriting data: %luk/%luk (100%%)\n",
- KB (filestat.st_size),
- KB (filestat.st_size));
- DEBUG("Wrote %d / %luk bytes\n",written,filestat.st_size);
+ KB (total_size),
+ KB (total_size));
+ DEBUG("Wrote %d / %luk bytes\n",written,total_size);
/**********************************
* verify that flash == file data *
**********************************/
- safe_rewind (fil_fd,filename);
+ if (flags & FLAG_GZIP)
+ safe_gzrewind (fil_gz,filename);
+ else
+ safe_rewind (fil_fd,filename);
+
safe_rewind (dev_fd,device);
- size = filestat.st_size;
+ size = total_size;
i = BUFSIZE;
written = 0;
- if (flags & FLAG_VERBOSE) log_printf (LOG_NORMAL,"Verifying data: 0k/%luk (0%%)",KB (filestat.st_size));
+ if (flags & FLAG_VERBOSE) log_printf (LOG_NORMAL,"Verifying data: 0k/%luk (0%%)",KB (total_size));
while (size)
{
if (size < BUFSIZE) i = size;
@@ -358,11 +435,14 @@
log_printf (LOG_NORMAL,
"\rVerifying data: %dk/%luk (%lu%%)",
KB (written + i),
- KB (filestat.st_size),
- PERCENTAGE (written + i,filestat.st_size));
+ KB (total_size),
+ PERCENTAGE (written + i,total_size));
/* read from filename */
- safe_read (fil_fd,filename,src,i,flags & FLAG_VERBOSE);
+ if (flags & FLAG_GZIP)
+ safe_gzread (fil_gz,filename,src,i,flags & FLAG_VERBOSE);
+ else
+ safe_read (fil_fd,filename,src,i,flags & FLAG_VERBOSE);
/* read from device */
safe_read (dev_fd,device,dest,i,flags & FLAG_VERBOSE);
@@ -382,9 +462,9 @@
if (flags & FLAG_VERBOSE)
log_printf (LOG_NORMAL,
"\rVerifying data: %luk/%luk (100%%)\n",
- KB (filestat.st_size),
- KB (filestat.st_size));
- DEBUG("Verified %d / %luk bytes\n",written,filestat.st_size);
+ KB (total_size),
+ KB (total_size));
+ DEBUG("Verified %d / %luk bytes\n",written,total_size);
exit (EXIT_SUCCESS);
}
More information about the linux-mtd
mailing list