}
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)
}
package zip
import (
+ "errors"
"os"
"time"
)
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
)
// 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)
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.
"bytes"
"fmt"
"io"
+ "reflect"
"testing"
"time"
)
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)
+ }
+}