mirror of
https://github.com/golang/go
synced 2024-10-04 03:11:22 -06:00
archive/zip: support functions to get modified time in ns from MS-DOS time
R=rsc, r, bradfitz, r, adg CC=golang-dev https://golang.org/cl/4748056
This commit is contained in:
parent
208e6e6dfc
commit
98f5fc5e86
@ -11,6 +11,7 @@ import (
|
|||||||
"io/ioutil"
|
"io/ioutil"
|
||||||
"os"
|
"os"
|
||||||
"testing"
|
"testing"
|
||||||
|
"time"
|
||||||
)
|
)
|
||||||
|
|
||||||
type ZipTest struct {
|
type ZipTest struct {
|
||||||
@ -24,8 +25,19 @@ type ZipTestFile struct {
|
|||||||
Name string
|
Name string
|
||||||
Content []byte // if blank, will attempt to compare against File
|
Content []byte // if blank, will attempt to compare against File
|
||||||
File string // name of file to compare to (relative to testdata/)
|
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{
|
var tests = []ZipTest{
|
||||||
{
|
{
|
||||||
Name: "test.zip",
|
Name: "test.zip",
|
||||||
@ -34,10 +46,12 @@ var tests = []ZipTest{
|
|||||||
{
|
{
|
||||||
Name: "test.txt",
|
Name: "test.txt",
|
||||||
Content: []byte("This is a test text file.\n"),
|
Content: []byte("This is a test text file.\n"),
|
||||||
|
Mtime: "09-05-10 12:12:02",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
Name: "gophercolor16x16.png",
|
Name: "gophercolor16x16.png",
|
||||||
File: "gophercolor16x16.png",
|
File: "gophercolor16x16.png",
|
||||||
|
Mtime: "09-05-10 15:52:58",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
@ -45,8 +59,9 @@ var tests = []ZipTest{
|
|||||||
Name: "r.zip",
|
Name: "r.zip",
|
||||||
File: []ZipTestFile{
|
File: []ZipTestFile{
|
||||||
{
|
{
|
||||||
Name: "r/r.zip",
|
Name: "r/r.zip",
|
||||||
File: "r.zip",
|
File: "r.zip",
|
||||||
|
Mtime: "03-04-10 00:24:16",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
@ -58,6 +73,7 @@ var tests = []ZipTest{
|
|||||||
{
|
{
|
||||||
Name: "filename",
|
Name: "filename",
|
||||||
Content: []byte("This is a test textfile.\n"),
|
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 {
|
if f.Name != ft.Name {
|
||||||
t.Errorf("name=%q, want %q", 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
|
var b bytes.Buffer
|
||||||
r, err := f.Open()
|
r, err := f.Open()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Error(err)
|
t.Error(err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
_, err = io.Copy(&b, r)
|
_, err = io.Copy(&b, r)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Error(err)
|
t.Error(err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
r.Close()
|
r.Close()
|
||||||
|
|
||||||
var c []byte
|
var c []byte
|
||||||
if len(ft.Content) != 0 {
|
if len(ft.Content) != 0 {
|
||||||
c = ft.Content
|
c = ft.Content
|
||||||
@ -155,10 +183,12 @@ func readTestFile(t *testing.T, ft ZipTestFile, f *File) {
|
|||||||
t.Error(err)
|
t.Error(err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
if b.Len() != len(c) {
|
if b.Len() != len(c) {
|
||||||
t.Errorf("%s: len=%d, want %d", f.Name, b.Len(), len(c))
|
t.Errorf("%s: len=%d, want %d", f.Name, b.Len(), len(c))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
for i, b := range b.Bytes() {
|
for i, b := range b.Bytes() {
|
||||||
if b != c[i] {
|
if b != c[i] {
|
||||||
t.Errorf("%s: content[%d]=%q want %q", f.Name, i, b, c[i])
|
t.Errorf("%s: content[%d]=%q want %q", f.Name, i, b, c[i])
|
||||||
|
@ -12,6 +12,7 @@ This package does not support ZIP64 or disk spanning.
|
|||||||
package zip
|
package zip
|
||||||
|
|
||||||
import "os"
|
import "os"
|
||||||
|
import "time"
|
||||||
|
|
||||||
// Compression methods.
|
// Compression methods.
|
||||||
const (
|
const (
|
||||||
@ -32,8 +33,8 @@ type FileHeader struct {
|
|||||||
ReaderVersion uint16
|
ReaderVersion uint16
|
||||||
Flags uint16
|
Flags uint16
|
||||||
Method uint16
|
Method uint16
|
||||||
ModifiedTime uint16
|
ModifiedTime uint16 // MS-DOS time
|
||||||
ModifiedDate uint16
|
ModifiedDate uint16 // MS-DOS date
|
||||||
CRC32 uint32
|
CRC32 uint32
|
||||||
CompressedSize uint32
|
CompressedSize uint32
|
||||||
UncompressedSize uint32
|
UncompressedSize uint32
|
||||||
@ -61,3 +62,27 @@ func recoverError(err *os.Error) {
|
|||||||
panic(e)
|
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
|
||||||
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user