[uClinux-dev] [PATCH] Remove system dependencies from flthdr [-z]

Julian Brown julian at codesourcery.com
Tue Oct 30 13:32:56 EST 2007


Hi,

This patch allows flthdr's compression options to work in a wider 
variety of environments (e.g. under MinGW/Win32), by linking with zlib 
rather than by using external gzip/gunzip executables. The cp binary 
isn't used any more either, and libiberty's make_temp_file() is used 
instead of mkstemp() as a more portable way of creating a temporary file.

Also the compression logic is made somewhat clearer, IMO.

(I hope this is the right place for this patch to go!).

Does this look reasonable? Please apply if so (I have no uclinux commit 
rights).

Cheers,

Julian

ChangeLog

     * Makefile.in (INCLUDES): Add @zlib_include_dir at .
     * configure.in (zlib): Add --with-zlib-prefix option. Probe for
     library if option not given.
     (zlib_include_dir): Set if zlib found. Substitute into Makefile.in.
     * configure: Regenerated.
     * flthdr.c (assert.h, zlib.h, libiberty.h): Include.
     (compress): Rename to docompress to avoid name clash with zlib
     (throughout file).
     (stream_type): New enum.
     (stream): New tagged union.
     (fopen_stream_u, fread_stream, fwrite_stream, fclose_stream)
     (ferror_stream, reopen_stream_compressed): New functions to handle
     either compressed or uncompressed file I/O.
     (transferr): Rename to...
     (transfer): This. Use fread_stream and fwrite_stream.
     (process_file): Use stream functions instead of gzip/gunzip
     executables for compression and decompression. Use libiberty to make
     temporary file name. Don't call external cp executable.
     (main): Rename compress to docompress.
-------------- next part --------------
diff -urp ../elf2flt-2006q1-orig/Makefile.in ./Makefile.in
--- ../elf2flt-2006q1-orig/Makefile.in	2007-10-30 11:19:55.000000000 -0700
+++ ./Makefile.in	2007-10-22 07:34:58.000000000 -0700
@@ -11,7 +11,7 @@ CC = @CC@
 CPU = @target_cpu@
 TARGET = @target_alias@
 CFLAGS = @CFLAGS@
-INCLUDES = @bfd_include_dir@ @binutils_include_dir@
+INCLUDES = @bfd_include_dir@ @binutils_include_dir@ @zlib_include_dir@
 CPPFLAGS = @CPPFLAGS@
 LDFLAGS = @LDFLAGS@
 LIBS = @LIBS@
diff -urp ../elf2flt-2006q1-orig/configure.in ./configure.in
--- ../elf2flt-2006q1-orig/configure.in	2007-10-30 11:19:55.000000000 -0700
+++ ./configure.in	2007-10-22 08:37:57.000000000 -0700
@@ -1,6 +1,12 @@
 dnl Process this file with autoconf to produce a configure script.
 AC_INIT(elf2flt.c)
 
+AC_ARG_WITH(zlib-prefix,
+	[ --with-zlib-prefix=<dir>  path to installed zlib ],
+	[ ac_zlib_prefix=$withval ],
+	[ ac_zlib_prefix=NONE ]
+)
+
 AC_ARG_WITH(libbfd,
 	[ --with-libbfd=<file>  path to libbfd.a library to use ],
 	[ ac_libbfd=$withval ],
@@ -89,6 +95,11 @@ if test "$ac_libbfd" = "NONE"; then
 else
   LIBS="$ac_libbfd $LIBS"
 fi
+if test "$ac_zlib_prefix" = "NONE"; then
+  AC_CHECK_LIB(z, deflate)
+else
+  LIBS="-L$ac_zlib_prefix/lib -lz $LIBS"
+fi
 
 bfd_include_dir=
 if test "$ac_bfd_include_dir" != "NONE"; then
@@ -100,6 +111,11 @@ if test "$ac_binutils_include_dir" != "N
   binutils_include_dir="-I$ac_binutils_include_dir"
 fi
 
+zlib_include_dir=
+if test "$ac_zlib_prefix" != "NONE"; then
+  zlib_include_dir="-I$ac_zlib_prefix/include"
+fi
+
 binutils_ldscript_dir=
 if test "$ac_binutils_ldscript_dir" = "NONE"; then
   ac_binutils_ldscript_dir="\${TOOLDIR}/../${target_alias}/lib"
@@ -164,6 +180,7 @@ AC_SUBST(target_os)
 AC_SUBST(target_vendor)
 AC_SUBST(bfd_include_dir)
 AC_SUBST(binutils_include_dir)
+AC_SUBST(zlib_include_dir)
 AC_SUBST(binutils_ldscript_dir)
 AC_SUBST(got_check)
 AC_SUBST(emit_relocs)
diff -urp ../elf2flt-2006q1-orig/flthdr.c ./flthdr.c
--- ../elf2flt-2006q1-orig/flthdr.c	2007-10-30 11:19:55.000000000 -0700
+++ ./flthdr.c	2007-10-22 08:51:42.000000000 -0700
@@ -15,6 +15,7 @@
 #include <time.h>
 #include <stdlib.h>   /* exit() */
 #include <string.h>   /* strcat(), strcpy() */
+#include <assert.h>
 
 /* macros for conversion between host and (internet) network byte order */
 #ifndef WIN32
@@ -23,6 +24,9 @@
 #include <winsock2.h>
 #endif
 
+#include <zlib.h>
+#include <libiberty.h>
+
 /* from uClinux-x.x.x/include/linux */
 #include "flat.h"     /* Binary flat header description                      */
 
@@ -38,13 +42,178 @@
 char *program_name;
 
 static char cmd[1024];
-static int print = 0, compress = 0, ramload = 0, stacksize = 0, ktrace = 0;
+static int print = 0, docompress = 0, ramload = 0, stacksize = 0, ktrace = 0;
 static int short_format = 0;
 
 /****************************************************************************/
 
+typedef enum
+{
+  INVALID,
+  UNCOMPRESSED,
+  COMPRESSED
+} stream_type;
+
+/* Tagged union holding either a regular FILE* handle or a zlib gzFile
+   handle.  */
+
+typedef struct
+{
+  stream_type type;
+  const char *mode;
+  union
+    {
+      FILE *filep;
+      gzFile gzfilep;
+    } u;
+} stream;
+
+/* Open an (uncompressed) file as a stream.  Return 0 on success, 1 on
+   error.
+   NOTE: The MODE argument must remain valid for the lifetime of the stream,
+   because it is referred to by reopen_stream_compressed() if it is called.
+   String constants work fine.  */
+
+static int
+fopen_stream_u (stream *fp, const char *path, const char *mode)
+{
+	fp->u.filep = fopen (path, mode);
+	fp->type = (fp->u.filep) ? UNCOMPRESSED : INVALID;
+	fp->mode = mode;
+	return (fp->u.filep) ? 0 : 1;
+}
+
+/* Read from stream.  Return number of elements read.  */
+
+static size_t
+fread_stream (void *ptr, size_t size, size_t nmemb, stream *str)
+{
+	size_t read;
+
+	switch (str->type) {
+		case UNCOMPRESSED:
+		read = fread(ptr, size, nmemb, str->u.filep);
+		break;
+
+		case COMPRESSED:
+		read = gzread(str->u.gzfilep, ptr, size * nmemb) / size;
+		break;
+
+		default:
+		abort ();
+	}
+
+	return read;
+}
+
+/* Write to stream.  Return number of elements written.  */
+
+static size_t
+fwrite_stream (const void *ptr, size_t size, size_t nmemb, stream *str)
+{
+	size_t written;
+
+	switch (str->type) {
+		case UNCOMPRESSED:
+		written = fwrite(ptr, size, nmemb, str->u.filep);
+		break;
+
+		case COMPRESSED:
+		written = gzwrite(str->u.gzfilep, ptr, size * nmemb) / size;
+		break;
+
+		default:
+		abort ();
+	}
+
+	return written;
+}
+
+/* Close stream.  */
+
+static int
+fclose_stream (stream *str)
+{
+	switch (str->type) {
+		case UNCOMPRESSED:
+		return fclose (str->u.filep);
+
+		case COMPRESSED:
+		return gzclose (str->u.gzfilep);
+
+		default:
+		abort ();
+	}
+	
+	return 0;
+}
+
+static int
+ferror_stream (stream *str)
+{
+	switch (str->type) {
+		case UNCOMPRESSED:
+		return ferror (str->u.filep);
+		
+		case COMPRESSED:
+		{
+			const char *err;
+			int errno;
+			
+			err = gzerror (str->u.gzfilep, &errno);
+			if (errno == Z_OK || errno == Z_STREAM_END)
+				return 0;
+			else if (errno == Z_ERRNO)
+				return 1;
+			else {
+				fprintf (stderr, "%s\n", err);
+				return 1;
+			}
+		}
+		break;
+		
+		default:
+		abort ();
+	}
+
+	return 0;
+}
+
+/* Reopen a stream at the current file position.  */
+
+static void
+reopen_stream_compressed (stream *str)
+{
+	int fd;
+	long offset, roffset;
+
+	/* Already a compressed stream, return immediately  */
+	if (str->type == COMPRESSED)
+		return;
+  
+	if (str->type == INVALID)
+		abort ();
+  
+	fd = fileno (str->u.filep);
+	/* Get current (buffered) file position.  */
+	offset = ftell (str->u.filep);
+	
+	/* Make sure there's nothing left in buffers.  */
+	fflush (str->u.filep);
+  
+	/* Reposition underlying FD.  (Might be unnecessary?)  */
+	roffset = lseek (fd, offset, SEEK_SET);
+  
+	assert (roffset == offset);
+  
+	/* Reopen as compressed stream.  */
+	str->u.gzfilep = gzdopen (fd, str->mode);
+	gzsetparams (str->u.gzfilep, 9, Z_DEFAULT_STRATEGY);
+	str->type = COMPRESSED;
+}
+
 void
-transferr(FILE *ifp, FILE *ofp, int count)
+transfer (stream *ifp, stream *ofp, int count)
 {
 	int n, num;
 
@@ -53,10 +222,10 @@ transferr(FILE *ifp, FILE *ofp, int coun
 			num = sizeof(cmd);
 		else
 			num = count;
-		n = fread(cmd, 1, num, ifp);
+		n = fread_stream (cmd, 1, num, ifp);
 		if (n == 0)
 			break;
-		if (fwrite(cmd, n, 1, ofp) != 1) {
+		if (fwrite_stream (cmd, n, 1, ofp) != 1) {
 			fprintf(stderr, "Write failed :-(\n");
 			exit(1);
 		}
@@ -64,31 +233,31 @@ transferr(FILE *ifp, FILE *ofp, int coun
 			count -= n;
 	}
 	if (count > 0) {
-		fprintf(stderr, "Failed to transferr %d bytes\n", count);
+		fprintf(stderr, "Failed to transfer %d bytes\n", count);
 		exit(1);
 	}
 }
-	
+
 /****************************************************************************/
 
 void
 process_file(char *ifile, char *ofile)
 {
 	int old_flags, old_stack, new_flags, new_stack;
-	FILE *ifp, *ofp;
-	int ofp_is_pipe = 0;
+	stream ifp, ofp;
 	struct flat_hdr old_hdr, new_hdr;
-	char tfile[256];
-	char tfile2[256];
+	char *tfile, tmpbuf[256];
+	int input_error, output_error;
+	FILE *tifp, *tofp;
 
-	*tfile = *tfile2 = '\0';
+	*tmpbuf = '\0';
 
-	if ((ifp = fopen(ifile, "rb")) == NULL) {
+	if (fopen_stream_u (&ifp, ifile, "rb")) {
 		fprintf(stderr, "Cannot open %s\n", ifile);
 		return;
 	}
 
-	if (fread(&old_hdr, sizeof(old_hdr), 1, ifp) != 1) {
+	if (fread_stream (&old_hdr, sizeof(old_hdr), 1, &ifp) != 1) {
 		fprintf(stderr, "Cannot read header of %s\n", ifile);
 		return;
 	}
@@ -102,13 +271,13 @@ process_file(char *ifile, char *ofile)
 	new_stack = old_stack = ntohl(old_hdr.stack_size);
 	new_hdr = old_hdr;
 
-	if (compress == 1) {
+	if (docompress == 1) {
 		new_flags |= FLAT_FLAG_GZIP;
 		new_flags &= ~FLAT_FLAG_GZDATA;
-	} else if (compress == 2) {
+	} else if (docompress == 2) {
 		new_flags |= FLAT_FLAG_GZDATA;
 		new_flags &= ~FLAT_FLAG_GZIP;
-	} else if (compress < 0)
+	} else if (docompress < 0)
 		new_flags &= ~(FLAT_FLAG_GZIP|FLAT_FLAG_GZDATA);
 	
 	if (ramload > 0)
@@ -162,13 +331,13 @@ process_file(char *ifile, char *ofile)
 			printf("-----------------------------------------------------------\n");
 			first = 0;
 		}
-		*tfile = '\0';
-		strcat(tfile, (old_flags & FLAT_FLAG_KTRACE) ? "k" : "");
-		strcat(tfile, (old_flags & FLAT_FLAG_RAM) ? "r" : "");
-		strcat(tfile, (old_flags & FLAT_FLAG_GOTPIC) ? "p" : "");
-		strcat(tfile, (old_flags & FLAT_FLAG_GZIP) ? "z" :
+		*tmpbuf = '\0';
+		strcat(tmpbuf, (old_flags & FLAT_FLAG_KTRACE) ? "k" : "");
+		strcat(tmpbuf, (old_flags & FLAT_FLAG_RAM) ? "r" : "");
+		strcat(tmpbuf, (old_flags & FLAT_FLAG_GOTPIC) ? "p" : "");
+		strcat(tmpbuf, (old_flags & FLAT_FLAG_GZIP) ? "z" :
 					((old_flags & FLAT_FLAG_GZDATA) ? "d" : ""));
-		printf("-%-3.3s ", tfile);
+		printf("-%-3.3s ", tmpbuf);
 		printf("%3d ", ntohl(old_hdr.rev));
 		printf("%6d ", text=ntohl(old_hdr.data_start)-sizeof(struct flat_hdr));
 		printf("%6d ", data=ntohl(old_hdr.data_end)-ntohl(old_hdr.data_start));
@@ -204,106 +373,74 @@ process_file(char *ifile, char *ofile)
 	new_hdr.flags = htonl(new_flags);
 	new_hdr.stack_size = htonl(new_stack);
 
-	strcpy(tfile, "/tmp/flatXXXXXX");
-	mkstemp(tfile);
-	if ((ofp = fopen(tfile, "wb")) == NULL) {
+	tfile = make_temp_file ("flthdr");
+
+	if (fopen_stream_u (&ofp, tfile, "wb")) {
 		fprintf(stderr, "Failed to open %s for writing\n", tfile);
 		unlink(tfile);
-		unlink(tfile2);
 		exit(1);
 	}
 
-	if (fwrite(&new_hdr, sizeof(new_hdr), 1, ofp) != 1) {
+	/* Copy header (always uncompressed).  */
+	if (fwrite_stream (&new_hdr, sizeof(new_hdr), 1, &ofp) != 1) {
 		fprintf(stderr, "Failed to write to  %s\n", tfile);
 		unlink(tfile);
-		unlink(tfile2);
 		exit(1);
 	}
 
-	/*
-	 * get ourselves a fully uncompressed copy of the text/data/relocs
-	 * so that we can manipulate it more easily
-	 */
-	if (old_flags & (FLAT_FLAG_GZIP|FLAT_FLAG_GZDATA)) {
-		FILE *tfp;
-
-		strcpy(tfile2, "/tmp/flat2XXXXXX");
-		mkstemp(tfile2);
-		
-		if (old_flags & FLAT_FLAG_GZDATA) {
-			tfp = fopen(tfile2, "wb");
-			if (!tfp) {
-				fprintf(stderr, "Failed to open %s for writing\n", tfile2);
-				exit(1);
-			}
-			transferr(ifp, tfp, ntohl(old_hdr.data_start) -
-					sizeof(struct flat_hdr));
-			fclose(tfp);
-		}
-
-		sprintf(cmd, "gunzip >> %s", tfile2);
-		tfp = popen(cmd, "wb");
-		if(!tfp) {
-			perror("popen");
-			exit(1);
-		}
-		transferr(ifp, tfp, -1);
-		pclose(tfp);
-
-		fclose(ifp);
-		ifp = fopen(tfile2, "rb");
-		if (!ifp) {
-			fprintf(stderr, "Failed to open %s for reading\n", tfile2);
-			unlink(tfile);
-			unlink(tfile2);
-			exit(1);
-		}
-	}
+	/* Whole input file (including text) is compressed: start decompressing
+	   now.  */
+	if (old_flags & FLAT_FLAG_GZIP)
+		reopen_stream_compressed (&ifp);
 
+	/* Likewise, output file is compressed. Start compressing now.  */
 	if (new_flags & FLAT_FLAG_GZIP) {
 		printf("zflat %s --> %s\n", ifile, ofile);
-		fclose(ofp);
-		sprintf(cmd, "gzip -9 -f >> %s", tfile);
-		ofp = popen(cmd, "wb");
-		ofp_is_pipe = 1;
-	} else if (new_flags & FLAT_FLAG_GZDATA) {
-		printf("zflat-data %s --> %s\n", ifile, ofile);
-		transferr(ifp, ofp, ntohl(new_hdr.data_start) -
-				sizeof(struct flat_hdr));
-		fclose(ofp);
-		sprintf(cmd, "gzip -9 -f >> %s", tfile);
-		ofp = popen(cmd, "wb");
-		ofp_is_pipe = 1;
+		reopen_stream_compressed (&ofp);
 	}
+	
+	transfer (&ifp, &ofp,
+		  ntohl (old_hdr.data_start) - sizeof (struct flat_hdr));
 
-	if (!ofp) { /* can only happen if using gzip/gunzip */
-		fprintf(stderr, "Can't run cmd %s\n", cmd);
-		unlink(tfile);
-		unlink(tfile2);
-		exit(1);
+	/* Only data and relocs were compressed in input.  Start decompressing
+	   from here.  */
+	if (old_flags & FLAT_FLAG_GZDATA)
+		reopen_stream_compressed (&ifp);
+	
+	/* Only data/relocs to be compressed in output.  Start compressing
+	   from here.  */
+	if (new_flags & FLAT_FLAG_GZDATA) {
+		printf("zflat-data %s --> %s\n", ifile, ofile);
+		reopen_stream_compressed (&ofp);
 	}
 
-	transferr(ifp, ofp, -1);
+	transfer (&ifp, &ofp, -1);
+
+	input_error = ferror_stream (&ifp);
+	output_error = ferror_stream (&ofp);
 	
-	if (ferror(ifp) || ferror(ofp)) {
+	if (input_error || output_error) {
 		fprintf(stderr, "Error on file pointer%s%s\n",
-				ferror(ifp) ? " input" : "", ferror(ofp) ? " output" : "");
+				input_error ? " input" : "",
+				output_error ? " output" : "");
 		unlink(tfile);
-		unlink(tfile2);
 		exit(1);
 	}
 
-	fclose(ifp);
-	if (ofp_is_pipe)
-		pclose(ofp);
-	else
-		fclose(ofp);
-
-	/* cheat a little here to preserve file permissions */
-	sprintf(cmd, "cp %s %s", tfile, ofile);
-	system(cmd);
-	unlink(tfile);
-	unlink(tfile2);
+	fclose_stream (&ifp);
+	fclose_stream (&ofp);
+
+	/* Copy temporary file to output location.  */
+	fopen_stream_u (&ifp, tfile, "rb");
+	fopen_stream_u (&ofp, ofile, "wb");
+	
+	transfer (&ifp, &ofp, -1);
+	
+	fclose_stream (&ifp);
+	fclose_stream (&ofp);
+
+	unlink (tfile);
+	free (tfile);
 }
 
 /****************************************************************************/
@@ -373,9 +510,9 @@ main(int argc, char *argv[])
 		  
 		  
 		case 'p': print = 1;                break;
-		case 'z': compress = 1;             break;
-		case 'd': compress = 2;             break;
-		case 'Z': compress = -1;            break;
+		case 'z': docompress = 1;           break;
+		case 'd': docompress = 2;           break;
+		case 'Z': docompress = -1;          break;
 		case 'r': ramload = 1;              break;
 		case 'R': ramload = -1;             break;
 		case 'k': ktrace = 1;               break;
@@ -394,7 +531,7 @@ main(int argc, char *argv[])
 	if (ofile && argc - optind > 1)
 		usage("-o can only be used with a single file");
 	
-	if (!print && !compress && !ramload && !stacksize) /* no args == print */
+	if (!print && !docompress && !ramload && !stacksize) /* no args == print */
 		print = argc - optind; /* greater than 1 is short format */
 	
 	for (c = optind; c < argc; c++) {


More information about the uClinux-dev mailing list