[PATCH] Retain timestamp with gunzip

Ian Wienand ianw at vmware.com
Wed Oct 29 23:43:44 UTC 2008


Hi,

It would be nice to keep the timestamp from gunzipped files.

The proposed patch adds an 'mtime' argument for unpackers to fill out,
which gets stamped in via utime.  I imagine the other unpackers can
use it if they care, and it could be expanded to a struct of other
useful information if it was ever required.

Where the gzip unpacker is used in a streaming manner for other tools,
there is a _simple() function which ignores the mtime argument.

Testing:
 - passes all of the compression related testsuite tests

 $ ls -l foo
 -rw-r--r-- 1 ianw ianw 0 2008-10-28 12:23 foo
 $ gzip foo
 $ ./busybox gunzip foo.gz
 $ ls -l foo
 -rw-r--r-- 1 ianw ianw 0 2008-10-28 12:23 foo

-i

 archival/bbunzip.c                        |   32 ++++++++++++++++++++++--------
 archival/libunarchive/decompress_unzip.c  |   29 ++++++++++++++++++++-------
 archival/libunarchive/get_header_tar_gz.c |    2 -
 archival/rpm.c                            |    2 -
 archival/rpm2cpio.c                       |    2 -
 include/libbb.h                           |    2 -
 include/unarchive.h                       |    3 +-
 libbb/read.c                              |    2 -
 8 files changed, 53 insertions(+), 21 deletions(-)

Index: archival/rpm.c
===================================================================
--- archival/rpm.c	(revision 23853)
+++ archival/rpm.c	(working copy)
@@ -215,7 +215,7 @@
 
 	xread(archive_handle->src_fd, &magic, 2);
 #if BB_MMU
-	xformer = unpack_gz_stream;
+	xformer = unpack_gz_stream_simple;
 #else
 	xformer_prog = "gunzip";
 #endif
Index: archival/bbunzip.c
===================================================================
--- archival/bbunzip.c	(revision 23853)
+++ archival/bbunzip.c	(working copy)
@@ -30,13 +30,14 @@
 
 int FAST_FUNC bbunpack(char **argv,
 	char* (*make_new_name)(char *filename),
-	USE_DESKTOP(long long) int (*unpacker)(void)
+	USE_DESKTOP(long long) int (*unpacker)(time_t *mtime)
 )
 {
 	struct stat stat_buf;
 	USE_DESKTOP(long long) int status;
 	char *filename, *new_name;
 	smallint exitcode = 0;
+	time_t mtime;
 
 	do {
 		/* NB: new_name is *maybe* malloc'ed! */
@@ -92,14 +93,25 @@
 					"use -f to force it");
 		}
 
-		status = unpacker();
+		status = unpacker(&mtime);
 		if (status < 0)
 			exitcode = 1;
 
 		if (filename) {
 			char *del = new_name;
 			if (status >= 0) {
-				/* TODO: restore user/group/times here? */
+				/* TODO: restore other things? */
+				if (mtime > 0) {
+					struct utimbuf times;
+					/* Done with this.  On some
+					systems calling utime then
+					closing resets the mtime. */
+					close(STDOUT_FILENO);
+					times.actime = mtime;
+					times.modtime = mtime;
+					utime(new_name, &times); // don't worry about errors
+				}
+
 				/* Delete _compressed_ file */
 				del = filename;
 				/* restore extension (unless tgz -> tar case) */
@@ -159,8 +171,9 @@
 }
 
 static
-USE_DESKTOP(long long) int unpack_bunzip2(void)
+USE_DESKTOP(long long) int unpack_bunzip2(time_t *mtime)
 {
+	*mtime = 0; // not handled yet
 	return unpack_bz2_stream_prime(STDIN_FILENO, STDOUT_FILENO);
 }
 
@@ -235,7 +248,7 @@
 }
 
 static
-USE_DESKTOP(long long) int unpack_gunzip(void)
+USE_DESKTOP(long long) int unpack_gunzip(time_t *mtime)
 {
 	USE_DESKTOP(long long) int status = -1;
 
@@ -245,9 +258,10 @@
 
 		magic2 = xread_char(STDIN_FILENO);
 		if (ENABLE_FEATURE_SEAMLESS_Z && magic2 == 0x9d) {
+			mtime = NULL;
 			status = unpack_Z_stream(STDIN_FILENO, STDOUT_FILENO);
 		} else if (magic2 == 0x8b) {
-			status = unpack_gz_stream(STDIN_FILENO, STDOUT_FILENO);
+			status = unpack_gz_stream(STDIN_FILENO, STDOUT_FILENO, mtime);
 		} else {
 			goto bad_magic;
 		}
@@ -309,8 +323,9 @@
 }
 
 static
-USE_DESKTOP(long long) int unpack_unlzma(void)
+USE_DESKTOP(long long) int unpack_unlzma(time_t *mtime)
 {
+	*mtime = 0;
 	return unpack_lzma_stream(STDIN_FILENO, STDOUT_FILENO);
 }
 
@@ -344,10 +359,11 @@
 }
 
 static
-USE_DESKTOP(long long) int unpack_uncompress(void)
+USE_DESKTOP(long long) int unpack_uncompress(time_t *mtime)
 {
 	USE_DESKTOP(long long) int status = -1;
 
+	*mtime = 0;
 	if ((xread_char(STDIN_FILENO) != 0x1f) || (xread_char(STDIN_FILENO) != 0x9d)) {
 		bb_error_msg("invalid magic");
 	} else {
Index: archival/libunarchive/decompress_unzip.c
===================================================================
--- archival/libunarchive/decompress_unzip.c	(revision 23853)
+++ archival/libunarchive/decompress_unzip.c	(working copy)
@@ -1108,17 +1108,17 @@
 	return res;
 }
 
-static int check_header_gzip(STATE_PARAM_ONLY)
+static int check_header_gzip(STATE_PARAM time_t *mtime)
 {
 	union {
 		unsigned char raw[8];
 		struct {
 			uint8_t gz_method;
 			uint8_t flags;
-			//uint32_t mtime; - unused fields
-			//uint8_t xtra_flags;
-			//uint8_t os_flags;
-		} formatted; /* packed */
+			uint32_t mtime;
+			uint8_t xtra_flags;
+			uint8_t os_flags;
+		} __attribute__((packed)) formatted;
 	} header;
 
 	/*
@@ -1167,6 +1167,15 @@
 		}
 	}
 
+	if (mtime) {
+#if BB_LITTLE_ENDIAN
+		/* gzip data always in le */
+		header.formatted.mtime =
+			SWAP_LE32(header.formatted.mtime);
+#endif
+		*mtime = header.formatted.mtime;
+	}
+
 	/* Read the header checksum */
 	if (header.formatted.flags & 0x02) {
 		if (!top_up(PASS_STATE 2))
@@ -1177,7 +1186,7 @@
 }
 
 USE_DESKTOP(long long) int FAST_FUNC
-unpack_gz_stream(int in, int out)
+unpack_gz_stream(int in, int out, time_t *mtime)
 {
 	uint32_t v32;
 	USE_DESKTOP(long long) int n;
@@ -1192,7 +1201,7 @@
 	gunzip_src_fd = in;
 
  again:
-	if (!check_header_gzip(PASS_STATE_ONLY)) {
+	if (!check_header_gzip(PASS_STATE mtime)) {
 		bb_error_msg("corrupted data");
 		n = -1;
 		goto ret;
@@ -1239,3 +1248,9 @@
 	DEALLOC_STATE;
 	return n;
 }
+
+USE_DESKTOP(long long) int FAST_FUNC
+unpack_gz_stream_simple(int in, int out)
+{
+	return unpack_gz_stream(in, out, NULL);
+}
Index: archival/libunarchive/get_header_tar_gz.c
===================================================================
--- archival/libunarchive/get_header_tar_gz.c	(revision 23853)
+++ archival/libunarchive/get_header_tar_gz.c	(working copy)
@@ -26,7 +26,7 @@
 	}
 #endif
 
-	open_transformer(archive_handle->src_fd, unpack_gz_stream, "gunzip");
+	open_transformer(archive_handle->src_fd, unpack_gz_stream_simple, "gunzip");
 	archive_handle->offset = 0;
 	while (get_header_tar(archive_handle) == EXIT_SUCCESS)
 		continue;
Index: archival/rpm2cpio.c
===================================================================
--- archival/rpm2cpio.c	(revision 23853)
+++ archival/rpm2cpio.c	(working copy)
@@ -79,7 +79,7 @@
 		bb_error_msg_and_die("invalid gzip magic");
 	}
 
-	if (unpack_gz_stream(rpm_fd, STDOUT_FILENO) < 0) {
+	if (unpack_gz_stream(rpm_fd, STDOUT_FILENO, NULL) < 0) {
 		bb_error_msg("error inflating");
 	}
 
Index: libbb/read.c
===================================================================
--- libbb/read.c	(revision 23853)
+++ libbb/read.c	(working copy)
@@ -340,7 +340,7 @@
 			xread(fd, &magic, 2);
 #if ENABLE_FEATURE_SEAMLESS_GZ
 #if BB_MMU
-			xformer = unpack_gz_stream;
+			xformer = unpack_gz_stream_simple;
 #else
 			xformer_prog = "gunzip";
 #endif
Index: include/libbb.h
===================================================================
--- include/libbb.h	(revision 23853)
+++ include/libbb.h	(working copy)
@@ -914,7 +914,7 @@
 int bunzip2_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
 int bbunpack(char **argv,
 	char* (*make_new_name)(char *filename),
-	USE_DESKTOP(long long) int (*unpacker)(void)
+	USE_DESKTOP(long long) int (*unpacker)(time_t *mtime)
 ) FAST_FUNC;
 #if ENABLE_ROUTE
 void bb_displayroutes(int noresolve, int netstatfmt) FAST_FUNC;
Index: include/unarchive.h
===================================================================
--- include/unarchive.h	(revision 23853)
+++ include/unarchive.h	(working copy)
@@ -125,7 +125,8 @@
 USE_DESKTOP(long long) int unpack_lzma_stream(int src_fd, int dst_fd) FAST_FUNC;
 /* the rest wants 2 first bytes already skipped by the caller */
 USE_DESKTOP(long long) int unpack_bz2_stream(int src_fd, int dst_fd) FAST_FUNC;
-USE_DESKTOP(long long) int unpack_gz_stream(int src_fd, int dst_fd) FAST_FUNC;
+USE_DESKTOP(long long) int unpack_gz_stream(int src_fd, int dst_fd, time_t *mtime) FAST_FUNC;
+USE_DESKTOP(long long) int unpack_gz_stream_simple(int src_fd, int dst_fd) FAST_FUNC;
 USE_DESKTOP(long long) int unpack_Z_stream(int fd_in, int fd_out) FAST_FUNC;
 /* wrapper which checks first two bytes to be "BZ" */
 USE_DESKTOP(long long) int unpack_bz2_stream_prime(int src_fd, int dst_fd) FAST_FUNC;




More information about the busybox mailing list