aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBrad Fitzpatrick <bradfitz@golang.org>2012-01-26 15:31:09 -0800
committerBrad Fitzpatrick <bradfitz@golang.org>2012-01-26 15:31:09 -0800
commitb62a5099e4bf2e87525792dd562c20894fff878c (patch)
treee1614fe5b4fadde58d111e5367d3c66451297de2
parent2a22f35598bba353f13d4808b4c4d710fa125f43 (diff)
downloadgo-b62a5099e4bf2e87525792dd562c20894fff878c.tar.gz
go-b62a5099e4bf2e87525792dd562c20894fff878c.zip
archive/zip: add functions to convert between os.FileInfo & FileHeader
Fixes #2186 R=golang-dev, gri, adg CC=golang-dev https://golang.org/cl/5579044
-rw-r--r--src/pkg/archive/zip/reader_test.go8
-rw-r--r--src/pkg/archive/zip/struct.go38
-rw-r--r--src/pkg/archive/zip/zip_test.go20
3 files changed, 57 insertions, 9 deletions
diff --git a/src/pkg/archive/zip/reader_test.go b/src/pkg/archive/zip/reader_test.go
index b34f5bf1ef..9407e35d5c 100644
--- a/src/pkg/archive/zip/reader_test.go
+++ b/src/pkg/archive/zip/reader_test.go
@@ -250,13 +250,9 @@ func readTestFile(t *testing.T, ft ZipTestFile, f *File) {
}
func testFileMode(t *testing.T, f *File, want os.FileMode) {
- mode, err := f.Mode()
+ mode := f.Mode()
if want == 0 {
- if err == nil {
- t.Errorf("%s mode: got %v, want none", f.Name, mode)
- }
- } else if err != nil {
- t.Errorf("%s mode: %s", f.Name, err)
+ t.Errorf("%s mode: got %v, want none", f.Name, mode)
} else if mode != want {
t.Errorf("%s mode: want %v, got %v", f.Name, want, mode)
}
diff --git a/src/pkg/archive/zip/struct.go b/src/pkg/archive/zip/struct.go
index 34a87fae5b..67e9658629 100644
--- a/src/pkg/archive/zip/struct.go
+++ b/src/pkg/archive/zip/struct.go
@@ -12,6 +12,7 @@ This package does not support ZIP64 or disk spanning.
package zip
import (
+ "errors"
"os"
"time"
)
@@ -55,6 +56,38 @@ type FileHeader struct {
Comment string
}
+// FileInfo returns an os.FileInfo for the FileHeader.
+func (fh *FileHeader) FileInfo() os.FileInfo {
+ return headerFileInfo{fh}
+}
+
+// headerFileInfo implements os.FileInfo.
+type headerFileInfo struct {
+ fh *FileHeader
+}
+
+func (fi headerFileInfo) Name() string { return fi.fh.Name }
+func (fi headerFileInfo) Size() int64 { return int64(fi.fh.UncompressedSize) }
+func (fi headerFileInfo) IsDir() bool { return fi.Mode().IsDir() }
+func (fi headerFileInfo) ModTime() time.Time { return fi.fh.ModTime() }
+func (fi headerFileInfo) Mode() os.FileMode { return fi.fh.Mode() }
+
+// FileInfoHeader creates a partially-populated FileHeader from an
+// os.FileInfo.
+func FileInfoHeader(fi os.FileInfo) (*FileHeader, error) {
+ size := fi.Size()
+ if size > (1<<32 - 1) {
+ return nil, errors.New("zip: file over 4GB")
+ }
+ fh := &FileHeader{
+ Name: fi.Name(),
+ UncompressedSize: uint32(size),
+ }
+ fh.SetModTime(fi.ModTime())
+ fh.SetMode(fi.Mode())
+ return fh, nil
+}
+
type directoryEnd struct {
diskNbr uint16 // unused
dirDiskNbr uint16 // unused
@@ -131,8 +164,7 @@ const (
)
// Mode returns the permission and mode bits for the FileHeader.
-// An error is returned in case the information is not available.
-func (h *FileHeader) Mode() (mode os.FileMode, err error) {
+func (h *FileHeader) Mode() (mode os.FileMode) {
switch h.CreatorVersion >> 8 {
case creatorUnix, creatorMacOSX:
mode = unixModeToFileMode(h.ExternalAttrs >> 16)
@@ -142,7 +174,7 @@ func (h *FileHeader) Mode() (mode os.FileMode, err error) {
if len(h.Name) > 0 && h.Name[len(h.Name)-1] == '/' {
mode |= os.ModeDir
}
- return mode, nil
+ return mode
}
// SetMode changes the permission and mode bits for the FileHeader.
diff --git a/src/pkg/archive/zip/zip_test.go b/src/pkg/archive/zip/zip_test.go
index 8aab2b6812..acd3d93821 100644
--- a/src/pkg/archive/zip/zip_test.go
+++ b/src/pkg/archive/zip/zip_test.go
@@ -10,6 +10,7 @@ import (
"bytes"
"fmt"
"io"
+ "reflect"
"testing"
"time"
)
@@ -66,3 +67,22 @@ func TestModTime(t *testing.T) {
t.Errorf("times don't match: got %s, want %s", outTime, testTime)
}
}
+
+func TestFileHeaderRoundTrip(t *testing.T) {
+ fh := &FileHeader{
+ Name: "foo.txt",
+ UncompressedSize: 987654321,
+ ModifiedTime: 1234,
+ ModifiedDate: 5678,
+ }
+ fi := fh.FileInfo()
+ fh2, err := FileInfoHeader(fi)
+
+ // Ignore these fields:
+ fh2.CreatorVersion = 0
+ fh2.ExternalAttrs = 0
+
+ if !reflect.DeepEqual(fh, fh2) {
+ t.Errorf("mismatch\n input=%#v\noutput=%#v\nerr=%v", fh, fh2, err)
+ }
+}