]> Cypherpunks repositories - gostls13.git/commitdiff
archive/zip: support functions to get modified time in ns from MS-DOS time
authorRobert Griesemer <gri@golang.org>
Tue, 19 Jul 2011 03:30:44 +0000 (20:30 -0700)
committerRobert Griesemer <gri@golang.org>
Tue, 19 Jul 2011 03:30:44 +0000 (20:30 -0700)
R=rsc, r, bradfitz, r, adg
CC=golang-dev
https://golang.org/cl/4748056

src/pkg/archive/zip/reader_test.go
src/pkg/archive/zip/struct.go

index c72cd9a2347b48162795d8535077c27640145cc5..14603ce672509b3f2ecddbb0ce27721e009c9b54 100644 (file)
@@ -11,6 +11,7 @@ import (
        "io/ioutil"
        "os"
        "testing"
+       "time"
 )
 
 type ZipTest struct {
@@ -24,8 +25,19 @@ type ZipTestFile struct {
        Name    string
        Content []byte // if blank, will attempt to compare against File
        File    string // name of file to compare to (relative to testdata/)
+       Mtime   string // modified time in format "mm-dd-yy hh:mm:ss"
 }
 
+// Caution: The Mtime values found for the test files should correspond to
+//          the values listed with unzip -l <zipfile>. However, the values
+//          listed by unzip appear to be off by some hours. When creating
+//          fresh test files and testing them, this issue is not present.
+//          The test files were created in Sydney, so there might be a time
+//          zone issue. The time zone information does have to be encoded
+//          somewhere, because otherwise unzip -l could not provide a different
+//          time from what the archive/zip package provides, but there appears
+//          to be no documentation about this.
+
 var tests = []ZipTest{
        {
                Name:    "test.zip",
@@ -34,10 +46,12 @@ var tests = []ZipTest{
                        {
                                Name:    "test.txt",
                                Content: []byte("This is a test text file.\n"),
+                               Mtime:   "09-05-10 12:12:02",
                        },
                        {
-                               Name: "gophercolor16x16.png",
-                               File: "gophercolor16x16.png",
+                               Name:  "gophercolor16x16.png",
+                               File:  "gophercolor16x16.png",
+                               Mtime: "09-05-10 15:52:58",
                        },
                },
        },
@@ -45,8 +59,9 @@ var tests = []ZipTest{
                Name: "r.zip",
                File: []ZipTestFile{
                        {
-                               Name: "r/r.zip",
-                               File: "r.zip",
+                               Name:  "r/r.zip",
+                               File:  "r.zip",
+                               Mtime: "03-04-10 00:24:16",
                        },
                },
        },
@@ -58,6 +73,7 @@ var tests = []ZipTest{
                        {
                                Name:    "filename",
                                Content: []byte("This is a test textfile.\n"),
+                               Mtime:   "02-02-11 13:06:20",
                        },
                },
        },
@@ -136,18 +152,30 @@ func readTestFile(t *testing.T, ft ZipTestFile, f *File) {
        if f.Name != ft.Name {
                t.Errorf("name=%q, want %q", f.Name, ft.Name)
        }
+
+       mtime, err := time.Parse("01-02-06 15:04:05", ft.Mtime)
+       if err != nil {
+               t.Error(err)
+               return
+       }
+       if got, want := f.Mtime_ns()/1e9, mtime.Seconds(); got != want {
+               t.Errorf("%s: mtime=%s (%d); want %s (%d)", f.Name, time.SecondsToUTC(got), got, mtime, want)
+       }
+
        var b bytes.Buffer
        r, err := f.Open()
        if err != nil {
                t.Error(err)
                return
        }
+
        _, err = io.Copy(&b, r)
        if err != nil {
                t.Error(err)
                return
        }
        r.Close()
+
        var c []byte
        if len(ft.Content) != 0 {
                c = ft.Content
@@ -155,10 +183,12 @@ func readTestFile(t *testing.T, ft ZipTestFile, f *File) {
                t.Error(err)
                return
        }
+
        if b.Len() != len(c) {
                t.Errorf("%s: len=%d, want %d", f.Name, b.Len(), len(c))
                return
        }
+
        for i, b := range b.Bytes() {
                if b != c[i] {
                        t.Errorf("%s: content[%d]=%q want %q", f.Name, i, b, c[i])
index 3092314c9c1e8eee64922e89dfab4fd1b1a9f15c..8bcd6a5814d28a803125f00fdb69edab89e925bc 100644 (file)
@@ -12,6 +12,7 @@ This package does not support ZIP64 or disk spanning.
 package zip
 
 import "os"
+import "time"
 
 // Compression methods.
 const (
@@ -32,8 +33,8 @@ type FileHeader struct {
        ReaderVersion    uint16
        Flags            uint16
        Method           uint16
-       ModifiedTime     uint16
-       ModifiedDate     uint16
+       ModifiedTime     uint16 // MS-DOS time
+       ModifiedDate     uint16 // MS-DOS date
        CRC32            uint32
        CompressedSize   uint32
        UncompressedSize uint32
@@ -61,3 +62,27 @@ func recoverError(err *os.Error) {
                panic(e)
        }
 }
+
+// msDosTimeToTime converts an MS-DOS date and time into a time.Time.
+// The resolution is 2s.
+// See: http://msdn.microsoft.com/en-us/library/ms724247(v=VS.85).aspx
+func msDosTimeToTime(dosDate, dosTime uint16) time.Time {
+       return time.Time{
+               // date bits 0-4: day of month; 5-8: month; 9-15: years since 1980
+               Year:  int64(dosDate>>9 + 1980),
+               Month: int(dosDate >> 5 & 0xf),
+               Day:   int(dosDate & 0x1f),
+
+               // time bits 0-4: second/2; 5-10: minute; 11-15: hour
+               Hour:   int(dosTime >> 11),
+               Minute: int(dosTime >> 5 & 0x3f),
+               Second: int(dosTime & 0x1f * 2),
+       }
+}
+
+// Mtime_ns returns the modified time in ns since epoch.
+// The resolution is 2s.
+func (h *FileHeader) Mtime_ns() int64 {
+       t := msDosTimeToTime(h.ModifiedDate, h.ModifiedTime)
+       return t.Seconds() * 1e9
+}