[PATCH STABLE] archival: add "extended-timestamp" extra block for zip archives (issue3600)

FUJIWARA Katsunori foozy at lares.dti.ne.jp
Tue Sep 18 05:55:01 CDT 2012


# HG changeset patch
# User FUJIWARA Katsunori <foozy at lares.dti.ne.jp>
# Date 1347965175 -32400
# Branch stable
# Node ID 0e9b339a01836e21d5d3fdf369406a12839b83a3
# Parent  495d3c671a8b01f19d5bfdafbbba908331d98879
archival: add "extended-timestamp" extra block for zip archives (issue3600)

Before this patch, zip archives created by "hg archive" are extracted
with unexpected timestamp, if TZ is not configured as GMT.

This patch adds "extended-timestamp" extra block to zip archives, and
unzip will extract such archives with timestamp specified in added
extra block, even though TZ is not configured as GMT.

Please see documents below for detail about specification of zip file
format and "extended-timestamp" extra block:

  http://www.pkware.com/documents/casestudies/APPNOTE.TXT
  http://www.opensource.apple.com/source/zip/zip-6/unzip/unzip/proginfo/extra.fld

Original implementation of this patch was suggested by "Jun Omae
<jun66j5 at gmail.com>".

diff -r 495d3c671a8b -r 0e9b339a0183 mercurial/archival.py
--- a/mercurial/archival.py	Mon Sep 17 15:13:03 2012 -0500
+++ b/mercurial/archival.py	Tue Sep 18 19:46:15 2012 +0900
@@ -12,6 +12,7 @@
 import scmutil, util, encoding
 import cStringIO, os, tarfile, time, zipfile
 import zlib, gzip
+import struct
 
 def tidyprefix(dest, kind, prefix):
     '''choose prefix to use for names in archive.  make sure prefix is
@@ -165,6 +166,7 @@
         if mtime < epoch:
             mtime = epoch
 
+        self.mtime = mtime
         self.date_time = time.gmtime(mtime)[:6]
 
     def addfile(self, name, mode, islink, data):
@@ -178,6 +180,14 @@
             mode = 0777
             ftype = 0xa000 # UNX_IFLNK in unzip source code
         i.external_attr = (mode | ftype) << 16L
+        # add "extended-timestamp" extra block, because zip archives
+        # without this will be extracted with unexpected timestamp,
+        # if TZ is not configured as GMT
+        i.extra += struct.pack('<hhBl',
+                               0x5455,     # block type: "extended-timestamp"
+                               1 + 4,      # size of this block
+                               1,          # "modification time is present"
+                               self.mtime) # time of last modification (UTC)
         self.z.writestr(i, data)
 
     def done(self):
diff -r 495d3c671a8b -r 0e9b339a0183 tests/test-archive.t
--- a/tests/test-archive.t	Mon Sep 17 15:13:03 2012 -0500
+++ b/tests/test-archive.t	Tue Sep 18 19:46:15 2012 +0900
@@ -270,3 +270,31 @@
   \s*147\s+2 files (re)
 
   $ cd ..
+
+issue3600: check whether "hg archive" can create archive files which
+are extracted with expected timestamp, even though TZ is not
+configured as GMT.
+
+  $ mkdir issue3600
+  $ cd issue3600
+
+  $ hg init repo
+  $ echo a > repo/a
+  $ hg -R repo add repo/a
+  $ hg -R repo commit -m '#0' -d '456789012 21600'
+  $ cat > show_mtime.py <<EOF
+  > import sys, os
+  > print int(os.stat(sys.argv[1]).st_mtime)
+  > EOF
+
+  $ hg -R repo archive --prefix tar-extracted archive.tar
+  $ (TZ=UTC-3; export TZ; tar xf archive.tar)
+  $ python show_mtime.py tar-extracted/a
+  456789012
+
+  $ hg -R repo archive --prefix zip-extracted archive.zip
+  $ (TZ=UTC-3; export TZ; unzip -q archive.zip)
+  $ python show_mtime.py zip-extracted/a
+  456789012
+
+  $ cd ..


More information about the Mercurial-devel mailing list