All of lore.kernel.org
 help / color / mirror / Atom feed
From: Hamish Moffatt <hamish@cloud.net.au>
To: linux-mtd@lists.infradead.org
Subject: [PATCH] support zlib decompression in flashcp
Date: Mon, 21 May 2007 17:48:26 +1000	[thread overview]
Message-ID: <20070521074826.GA31844@cloud.net.au> (raw)

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@debian.org> <hamish@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);
 }

             reply	other threads:[~2007-05-21  7:48 UTC|newest]

Thread overview: 2+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2007-05-21  7:48 Hamish Moffatt [this message]
2007-06-28 19:39 ` [PATCH] support zlib decompression in flashcp David Woodhouse

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20070521074826.GA31844@cloud.net.au \
    --to=hamish@cloud.net.au \
    --cc=linux-mtd@lists.infradead.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.