[libgsf] zip: improve timestamps in zip.



commit 08574918704ad7a7fb6b44c2825bee6ac1bc736d
Author: Morten Welinder <terra gnome org>
Date:   Fri Nov 28 18:32:43 2014 -0500

    zip: improve timestamps in zip.

 ChangeLog             |    5 ++++
 NEWS                  |    1 +
 gsf/gsf-outfile-zip.c |   54 +++++++++++++++++++++++++++++++++++++++----------
 gsf/gsf-zip-impl.h    |    1 +
 4 files changed, 50 insertions(+), 11 deletions(-)
---
diff --git a/ChangeLog b/ChangeLog
index 6507bd4..cb3c3d9 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,8 @@
+2014-11-28  Morten Welinder  <terra gnome org>
+
+       * gsf/gsf-outfile-zip.c (zip_dirent_new_out): Store mtime in zip
+       files, as long as they fit.
+
 2014-11-27  Morten Welinder  <terra gnome org>
 
        * gsf/gsf-input.c (gsf_input_copy): Minor cleanups.
diff --git a/NEWS b/NEWS
index 01f577d..5dff056 100644
--- a/NEWS
+++ b/NEWS
@@ -14,6 +14,7 @@ Morten:
        * Fix various issues with files larger than 4G.
        * Fix minor zip file issues.
        * Write zip archives with more than 64k+ members.
+       * Store unix modtime in zip.  (Until that overflows.)
 
 --------------------------------------------------------------------------
 libgsf 1.14.30
diff --git a/gsf/gsf-outfile-zip.c b/gsf/gsf-outfile-zip.c
index 345fecd..6e843b8 100644
--- a/gsf/gsf-outfile-zip.c
+++ b/gsf/gsf-outfile-zip.c
@@ -187,6 +187,18 @@ zip_dirent_write (GsfOutput *sink, GsfZipDirent *dirent)
                }
        }
 
+       if (dirent->mtime && dirent->mtime <= G_MAXUINT32) {
+               /* Clearly a year 2038 problem here.  */
+               char tmp[4];
+               GSF_LE_SET_GUINT16 (tmp, ZIP_DIRENT_EXTRA_FIELD_UNIXTIME);
+               GSF_LE_SET_GUINT16 (tmp + 2, 5);
+               g_string_append_len (extras, tmp, 4);
+               tmp[0] = 1;
+               g_string_append_len (extras, tmp, 1);
+               GSF_LE_SET_GUINT32 (tmp, dirent->mtime);
+               g_string_append_len (extras, tmp, 4);
+       }
+
        memset (buf, 0, sizeof buf);
        GSF_LE_SET_GUINT32 (buf, ZIP_DIRENT_SIGNATURE);
        GSF_LE_SET_GUINT16 (buf + ZIP_DIRENT_ENCODER,
@@ -371,11 +383,6 @@ zip_time_make (GDateTime *modtime)
        gint year, month, day, hour, minute, second;
        guint32 ztime;
 
-       if (!modtime)
-               modtime = g_date_time_new_now_utc ();
-       else
-               g_date_time_ref (modtime);
-
        g_date_time_get_ymd (modtime, &year, &month, &day);
        hour = g_date_time_get_hour (modtime);
        minute = g_date_time_get_minute (modtime);
@@ -392,8 +399,6 @@ zip_time_make (GDateTime *modtime)
                ztime = (ztime << 5) | ((second / 2) & 0x1f);
        }
 
-       g_date_time_unref (modtime);
-
        return ztime;
 }
 
@@ -414,11 +419,26 @@ zip_dirent_new_out (GsfOutfileZip *zip)
         */
        if (strlen (name) < G_MAXUINT16) {
                GsfZipDirent *dirent = gsf_zip_dirent_new ();
+               GDateTime *modtime = gsf_output_get_modtime (GSF_OUTPUT (zip));
+               gint64 mtime64;
+
                dirent->name = name;
                dirent->compr_method = zip->compression_method;
-               dirent->dostime = zip_time_make (gsf_output_get_modtime (GSF_OUTPUT (zip)));
+
+               if (!modtime)
+                       modtime = g_date_time_new_now_utc ();
+               else
+                       g_date_time_ref (modtime);
+               dirent->dostime = zip_time_make (modtime);
+               mtime64 = g_date_time_to_unix (modtime);
+               if (mtime64 == (gint64)(time_t)mtime64)
+                   dirent->mtime = (time_t)mtime64;
+
                dirent->zip64 = zip->zip64;
                zip_dirent_update_flags (dirent);
+
+               g_date_time_unref (modtime);
+
                return dirent;
        } else
                return NULL;
@@ -437,13 +457,13 @@ zip_header_write (GsfOutfileZip *zip)
        gsf_off_t csize = has_ddesc ? 0 : dirent->csize;
        gsf_off_t usize = has_ddesc ? 0 : dirent->usize;
        GString *extras = g_string_sized_new (ZIP_HEADER_SIZE + nlen + 100);
-       gboolean real_extra_field =
+       gboolean real_zip64 =
                (dirent->zip64 == TRUE ||
                 (dirent->zip64 == -1 &&
                  (dirent->usize >= G_MAXUINT32 ||
                   dirent->csize >= G_MAXUINT32 ||
                   dirent->offset >= G_MAXUINT32)));
-       const guint8 extract = real_extra_field ? 45 : 23;
+       const guint8 extract = real_zip64 ? 45 : 23;
 
        /*
         * In the has_ddesc case, we write crc32/size/usize as zero and store
@@ -457,7 +477,7 @@ zip_header_write (GsfOutfileZip *zip)
 
        if (dirent->zip64) {
                char tmp[8];
-               guint16 typ = real_extra_field
+               guint16 typ = real_zip64
                        ? ZIP_DIRENT_EXTRA_FIELD_ZIP64
                        : ZIP_DIRENT_EXTRA_FIELD_IGNORE;
 
@@ -470,6 +490,18 @@ zip_header_write (GsfOutfileZip *zip)
                g_string_append_len (extras, tmp, 8);
        }
 
+       if (dirent->mtime && dirent->mtime <= G_MAXUINT32) {
+               /* Clearly a year 2038 problem here.  */
+               char tmp[4];
+               GSF_LE_SET_GUINT16 (tmp, ZIP_DIRENT_EXTRA_FIELD_UNIXTIME);
+               GSF_LE_SET_GUINT16 (tmp + 2, 5);
+               g_string_append_len (extras, tmp, 4);
+               tmp[0] = 1;
+               g_string_append_len (extras, tmp, 1);
+               GSF_LE_SET_GUINT32 (tmp, dirent->mtime);
+               g_string_append_len (extras, tmp, 4);
+       }
+
        memset (hbuf, 0, sizeof hbuf);
        GSF_LE_SET_GUINT32 (hbuf, ZIP_HEADER_SIGNATURE);
        GSF_LE_SET_GUINT16 (hbuf + ZIP_HEADER_EXTRACT,
diff --git a/gsf/gsf-zip-impl.h b/gsf/gsf-zip-impl.h
index 8202086..2f371d4 100644
--- a/gsf/gsf-zip-impl.h
+++ b/gsf/gsf-zip-impl.h
@@ -144,6 +144,7 @@ typedef struct {
        gsf_off_t                offset;
        gsf_off_t                data_offset;
        guint32                  dostime;
+       time_t                   mtime;
        guint8                   zip64;  /* -1 = auto, FALSE, TRUE. */
 } GsfZipDirent;
 


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