[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]

Re: grokking libgsf



On Mon, 4 May 2009, Morten Welinder wrote:

> You want something like this...

Now that I have a somewhat better understanding of how libgsf
works, here's a suggestion for a patch (attached).  It adds the
ability to read the timestamp from files inside a zip archive, and
to set the time stamp on files created via stdio.  So you can
emulate 'unzip' by doing something like:

gint mtime;

/* 'input' is a GsfInput from zip */
g_object_get(G_OBJECT(input), "modification-time", &mtime, NULL);

...

/* 'out' is obtained via gsf_outfile_stdio_new */
output = gsf_outfile_new_child_full(out, name, is_dir,
                                    "modification-time", mtime,
                                    NULL);

The use of gint for mtime expires in 2038; if there's a better way
of handling time_t via g_object that would be good.

--
Allin Cottrell
Department of Economics
Wake Forest University
diff -ub libgsf-1.14.12.orig/gsf/gsf-infile-zip.c libgsf-1.14.12/gsf/gsf-infile-zip.c
--- libgsf-1.14.12.orig/gsf/gsf-infile-zip.c	2009-04-17 18:27:14.000000000 -0400
+++ libgsf-1.14.12/gsf/gsf-infile-zip.c	2009-05-05 14:13:19.000000000 -0400
@@ -38,6 +38,7 @@
 	PROP_0,
 	PROP_SOURCE,
 	PROP_COMPRESSION_LEVEL,
+       PROP_MODTIME,
 	PROP_INTERNAL_PARENT,
 };
 
@@ -192,7 +193,7 @@
 	GsfZipDirent *dirent;
 	guint8 const *data;
 	guint16 name_len, extras_len, comment_len, compr_method;
-	guint32 crc32, csize, usize, off;
+	guint32 dostime, crc32, csize, usize, off;
 	gchar *name;
 
 	/* Read data and check the header */
@@ -207,6 +208,8 @@
 	comment_len =   GSF_LE_GET_GUINT16 (data + ZIP_DIRENT_COMMENT_SIZE);
 
 	compr_method =  GSF_LE_GET_GUINT16 (data + ZIP_DIRENT_COMPR_METHOD);
+
+       dostime =       GSF_LE_GET_GUINT32 (data + ZIP_DIRENT_DOSTIME);
 	crc32 =         GSF_LE_GET_GUINT32 (data + ZIP_DIRENT_CRC32);
 	csize =         GSF_LE_GET_GUINT32 (data + ZIP_DIRENT_CSIZE);
 	usize =         GSF_LE_GET_GUINT32 (data + ZIP_DIRENT_USIZE);
@@ -223,6 +226,7 @@
 	dirent->name = name;
 
 	dirent->compr_method =  compr_method;
+       dirent->dostime =       dostime;
 	dirent->crc32 =         crc32;
 	dirent->csize =         csize;
 	dirent->usize =         usize;
@@ -589,6 +593,28 @@
 	return FALSE;
 }
 
+static gint32
+zip_time_translate (guint32 dostime)
+{
+	struct tm ltime;
+	time_t now = time (NULL);
+
+	ltime = *localtime (&now);
+
+	ltime.tm_year = (dostime >> 25) + 80;
+	ltime.tm_mon =  ((dostime >> 21) & 0x0f) - 1;
+	ltime.tm_mday = (dostime >> 16) & 0x1f;
+	ltime.tm_hour = (dostime >> 11) & 0x0f;
+	ltime.tm_min =  (dostime >> 5) & 0x3f;
+	ltime.tm_sec =  (dostime & 0x1f) << 1;
+
+	ltime.tm_wday = -1;
+	ltime.tm_yday = -1;
+	ltime.tm_isdst = -1;
+
+	return (gint32) mktime (&ltime);
+}
+
 /* GsfInfile class functions */
 
 /*****************************************************************************/
@@ -752,6 +778,12 @@
 				 ? zip->vdir->dirent->compr_method
 				 : 0);
 		break;
+	case PROP_MODTIME:
+		g_value_set_int (value,
+				 zip->vdir->dirent
+				 ? zip_time_translate(zip->vdir->dirent->dostime)
+				 : 0);
+		break;
 	default:
 		G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
 		break;
@@ -833,6 +865,16 @@
 				   G_PARAM_READABLE));
 	g_object_class_install_property
 		(gobject_class,
+		 PROP_MODTIME,
+		 g_param_spec_int ("modification-time",
+				   "Last modification time",
+				   "The last modification time of the file.",
+				   G_MININT, G_MAXINT,
+                                   0,
+				   GSF_PARAM_STATIC |
+				   G_PARAM_READABLE));
+	g_object_class_install_property
+		(gobject_class,
 		 PROP_INTERNAL_PARENT,
 		 g_param_spec_object ("internal-parent",
 				      "",
diff -ub libgsf-1.14.12.orig/gsf/gsf-outfile-zip.c libgsf-1.14.12/gsf/gsf-outfile-zip.c
--- libgsf-1.14.12.orig/gsf/gsf-outfile-zip.c	2009-04-17 18:27:14.000000000 -0400
+++ libgsf-1.14.12/gsf/gsf-outfile-zip.c	2009-05-05 14:56:09.000000000 -0400
@@ -37,7 +37,8 @@
 	PROP_0,
 	PROP_SINK,
 	PROP_ENTRY_NAME,
-	PROP_COMPRESSION_LEVEL
+	PROP_COMPRESSION_LEVEL,
+	PROP_MODTIME,
 };
 
 static GObjectClass *parent_class;
@@ -56,6 +57,8 @@
 	z_stream  *stream;
 	GsfZipCompressionMethod compression_method;
 
+	time_t modtime;
+
 	gboolean   writing;
 
 	guint8   *buf;
@@ -281,7 +284,7 @@
 	GsfZipDirent *dirent = gsf_zip_dirent_new ();
 	dirent->name = stream_name_build (zip);
 	dirent->compr_method = zip->compression_method;
-	dirent->dostime = zip_time_make (time (NULL));
+	dirent->dostime = zip_time_make (zip->modtime);
 	return dirent;
 }
 
@@ -611,6 +614,7 @@
 	zip->root_order = NULL;
 	zip->stream = NULL;
 	zip->compression_method = GSF_ZIP_DEFLATED;
+	zip->modtime = time (NULL);
 	zip->writing = FALSE;
 	zip->buf = NULL;
 	zip->buf_size = 0;
@@ -658,6 +662,9 @@
 	case PROP_ENTRY_NAME:
 		zip->entry_name = g_strdup (g_value_get_string (value));
 		break;
+	case PROP_MODTIME: 
+		zip->modtime = (time_t) g_value_get_int (value);
+		break;
 	case PROP_COMPRESSION_LEVEL: {
 		int level = g_value_get_int (value);
 		switch (level) {
@@ -668,7 +675,6 @@
 		default:
 			g_warning ("Unsupported compression level %d", level);
 		}
-		break;
 	}
 	default:
 		G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
@@ -723,6 +729,17 @@
 				   GSF_PARAM_STATIC |
 				   G_PARAM_READWRITE |
 				   G_PARAM_CONSTRUCT_ONLY));
+	g_object_class_install_property
+		(gobject_class,
+		 PROP_MODTIME,
+		 g_param_spec_int ("modification-time",
+				   "Last modification time",
+				   "The last modification time of the file.",
+				   G_MININT, G_MAXINT,
+                                   0,
+				   GSF_PARAM_STATIC |
+				   G_PARAM_READWRITE |
+				   G_PARAM_CONSTRUCT_ONLY));
 }
 
 GSF_CLASS (GsfOutfileZip, gsf_outfile_zip,
diff -ub libgsf-1.14.12.orig/gsf/gsf-output-stdio.c libgsf-1.14.12/gsf/gsf-output-stdio.c
--- libgsf-1.14.12.orig/gsf/gsf-output-stdio.c	2009-04-17 18:27:14.000000000 -0400
+++ libgsf-1.14.12/gsf/gsf-output-stdio.c	2009-05-05 15:56:12.000000000 -0400
@@ -34,6 +34,7 @@
 #endif
 #include <sys/types.h>
 #include <sys/stat.h>
+#include <utime.h>
 #ifdef HAVE_SYS_STATFS_H
 #include <sys/statfs.h>
 #endif
@@ -51,6 +52,11 @@
 #define W_OK 2
 #endif
 
+enum {
+	PROP_0,
+	PROP_MODTIME,
+};
+
 static GObjectClass *parent_class;
 
 struct _GsfOutputStdio {
@@ -60,6 +66,7 @@
 	char	 *real_filename, *temp_filename;
 	gboolean  create_backup_copy, keep_open;
 	struct stat st;
+        time_t modtime;
 };
 
 typedef struct {
@@ -121,6 +128,17 @@
 #endif
 }
 
+static void 
+set_filetime (char const *filename, time_t modtime)
+{
+	struct utimbuf ut;
+
+	ut.actime =  time (NULL);
+	ut.modtime = modtime;
+
+	utime (filename, &ut);
+}
+
 #define GSF_MAX_LINK_LEVEL 256
 
 /* Calls g_file_read_link() until we find a real filename. */
@@ -279,6 +297,10 @@
 		}
 		chmod_wrapper (stdio->real_filename, stdio->st.st_mode);
 #endif
+
+		/* Set the file modification time, if wanted */
+                if (stdio->modtime) 
+			set_filetime(stdio->real_filename, stdio->modtime);
 	}
 
 	g_free (backup_filename);
@@ -387,6 +409,43 @@
 	stdio->file = NULL;
 	stdio->create_backup_copy = FALSE;
 	stdio->keep_open	  = FALSE;
+	stdio->modtime	          = (time_t) 0;
+}
+
+static void
+gsf_output_stdio_get_property (GObject     *object,
+			       guint        property_id,
+			       GValue      *value,
+			       GParamSpec  *pspec)
+{
+	GsfOutputStdio *stdio = (GsfOutputStdio *)object;
+
+	switch (property_id) {
+	case PROP_MODTIME: 
+		g_value_set_int (value, stdio->modtime);
+		break;
+	default:
+		G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
+		break;
+	}
+}
+
+static void
+gsf_output_stdio_set_property (GObject      *object,
+			       guint         property_id,
+			       GValue const *value,
+			       GParamSpec   *pspec)
+{
+	GsfOutputStdio *stdio = (GsfOutputStdio *)object;
+
+	switch (property_id) {
+	case PROP_MODTIME: 
+		stdio->modtime = (time_t) g_value_get_int (value);
+		break;
+	default:
+		G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
+		break;
+	}
 }
 
 static void
@@ -395,11 +454,24 @@
 	GsfOutputClass *output_class = GSF_OUTPUT_CLASS (gobject_class);
 
 	gobject_class->finalize = gsf_output_stdio_finalize;
+       gobject_class->get_property = gsf_output_stdio_get_property;
+	gobject_class->set_property = gsf_output_stdio_set_property;
 	output_class->Close	= gsf_output_stdio_close;
 	output_class->Seek	= gsf_output_stdio_seek;
 	output_class->Write	= gsf_output_stdio_write;
 	output_class->Vprintf	= gsf_output_stdio_vprintf;
 
+	g_object_class_install_property
+		(gobject_class,
+		 PROP_MODTIME,
+		 g_param_spec_int ("modification-time",
+				   "Last modification time",
+				   "The last modification time of the file.",
+				   G_MININT, G_MAXINT,
+                                   0,
+				   GSF_PARAM_STATIC |
+				   G_PARAM_READWRITE));
+
 	parent_class = g_type_class_peek_parent (gobject_class);
 }


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]