summaryrefslogtreecommitdiff
path: root/libgo/go/archive/zip
diff options
context:
space:
mode:
Diffstat (limited to 'libgo/go/archive/zip')
-rw-r--r--libgo/go/archive/zip/reader.go2
-rw-r--r--libgo/go/archive/zip/reader_test.go18
-rw-r--r--libgo/go/archive/zip/struct.go19
-rw-r--r--libgo/go/archive/zip/writer.go4
-rw-r--r--libgo/go/archive/zip/writer_test.go58
5 files changed, 86 insertions, 15 deletions
diff --git a/libgo/go/archive/zip/reader.go b/libgo/go/archive/zip/reader.go
index f92f9297ada..b0a559936bd 100644
--- a/libgo/go/archive/zip/reader.go
+++ b/libgo/go/archive/zip/reader.go
@@ -238,7 +238,7 @@ func readDirectoryHeader(f *File, r io.Reader) os.Error {
commentLen := int(c.Uint16(b[32:34]))
// startDiskNumber := c.Uint16(b[34:36]) // Unused
// internalAttributes := c.Uint16(b[36:38]) // Unused
- // externalAttributes := c.Uint32(b[38:42]) // Unused
+ f.ExternalAttrs = c.Uint32(b[38:42])
f.headerOffset = int64(c.Uint32(b[42:46]))
d := make([]byte, filenameLen+extraLen+commentLen)
if _, err := io.ReadFull(r, d); err != nil {
diff --git a/libgo/go/archive/zip/reader_test.go b/libgo/go/archive/zip/reader_test.go
index fd5fed2af05..3b7b0dc1304 100644
--- a/libgo/go/archive/zip/reader_test.go
+++ b/libgo/go/archive/zip/reader_test.go
@@ -26,6 +26,7 @@ type ZipTestFile struct {
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"
+ Mode uint32
}
// Caution: The Mtime values found for the test files should correspond to
@@ -47,11 +48,13 @@ var tests = []ZipTest{
Name: "test.txt",
Content: []byte("This is a test text file.\n"),
Mtime: "09-05-10 12:12:02",
+ Mode: 0x81a4,
},
{
Name: "gophercolor16x16.png",
File: "gophercolor16x16.png",
Mtime: "09-05-10 15:52:58",
+ Mode: 0x81a4,
},
},
},
@@ -162,6 +165,8 @@ func readTestFile(t *testing.T, ft ZipTestFile, f *File) {
t.Errorf("%s: mtime=%s (%d); want %s (%d)", f.Name, time.SecondsToUTC(got), got, mtime, want)
}
+ testFileMode(t, f, ft.Mode)
+
size0 := f.UncompressedSize
var b bytes.Buffer
@@ -203,6 +208,19 @@ func readTestFile(t *testing.T, ft ZipTestFile, f *File) {
}
}
+func testFileMode(t *testing.T, f *File, want uint32) {
+ mode, err := 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)
+ } else if mode != want {
+ t.Errorf("%s mode: want 0x%x, got 0x%x", f.Name, want, mode)
+ }
+}
+
func TestInvalidFiles(t *testing.T) {
const size = 1024 * 70 // 70kb
b := make([]byte, size)
diff --git a/libgo/go/archive/zip/struct.go b/libgo/go/archive/zip/struct.go
index 1d6e70f105a..a32de5a9e0d 100644
--- a/libgo/go/archive/zip/struct.go
+++ b/libgo/go/archive/zip/struct.go
@@ -28,6 +28,9 @@ const (
directoryHeaderLen = 46 // + filename + extra + comment
directoryEndLen = 22 // + comment
dataDescriptorLen = 12
+
+ // Constants for the first byte in CreatorVersion
+ creatorUnix = 3
)
type FileHeader struct {
@@ -42,6 +45,7 @@ type FileHeader struct {
CompressedSize uint32
UncompressedSize uint32
Extra []byte
+ ExternalAttrs uint32 // Meaning depends on CreatorVersion
Comment string
}
@@ -89,3 +93,18 @@ func (h *FileHeader) Mtime_ns() int64 {
t := msDosTimeToTime(h.ModifiedDate, h.ModifiedTime)
return t.Seconds() * 1e9
}
+
+// 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 uint32, err os.Error) {
+ if h.CreatorVersion>>8 == creatorUnix {
+ return h.ExternalAttrs >> 16, nil
+ }
+ return 0, os.NewError("file mode not available")
+}
+
+// SetMode changes the permission and mode bits for the FileHeader.
+func (h *FileHeader) SetMode(mode uint32) {
+ h.CreatorVersion = h.CreatorVersion&0xff | creatorUnix<<8
+ h.ExternalAttrs = mode << 16
+}
diff --git a/libgo/go/archive/zip/writer.go b/libgo/go/archive/zip/writer.go
index 2065b06daac..3a6dc38e20f 100644
--- a/libgo/go/archive/zip/writer.go
+++ b/libgo/go/archive/zip/writer.go
@@ -69,7 +69,7 @@ func (w *Writer) Close() (err os.Error) {
write(w, uint16(len(h.Comment)))
write(w, uint16(0)) // disk number start
write(w, uint16(0)) // internal file attributes
- write(w, uint32(0)) // external file attributes
+ write(w, h.ExternalAttrs)
write(w, h.offset)
writeBytes(w, []byte(h.Name))
writeBytes(w, h.Extra)
@@ -115,7 +115,7 @@ func (w *Writer) CreateHeader(fh *FileHeader) (io.Writer, os.Error) {
}
fh.Flags |= 0x8 // we will write a data descriptor
- fh.CreatorVersion = 0x14
+ fh.CreatorVersion = fh.CreatorVersion&0xff00 | 0x14
fh.ReaderVersion = 0x14
fw := &fileWriter{
diff --git a/libgo/go/archive/zip/writer_test.go b/libgo/go/archive/zip/writer_test.go
index eb2a80c3f70..b562f843053 100644
--- a/libgo/go/archive/zip/writer_test.go
+++ b/libgo/go/archive/zip/writer_test.go
@@ -13,19 +13,45 @@ import (
// TODO(adg): a more sophisticated test suite
-const testString = "Rabbits, guinea pigs, gophers, marsupial rats, and quolls."
+type WriteTest struct {
+ Name string
+ Data []byte
+ Method uint16
+ Mode uint32
+}
+
+var writeTests = []WriteTest{
+ WriteTest{
+ Name: "foo",
+ Data: []byte("Rabbits, guinea pigs, gophers, marsupial rats, and quolls."),
+ Method: Store,
+ },
+ WriteTest{
+ Name: "bar",
+ Data: nil, // large data set in the test
+ Method: Deflate,
+ Mode: 0x81ed,
+ },
+}
func TestWriter(t *testing.T) {
largeData := make([]byte, 1<<17)
for i := range largeData {
largeData[i] = byte(rand.Int())
}
+ writeTests[1].Data = largeData
+ defer func() {
+ writeTests[1].Data = nil
+ }()
// write a zip file
buf := new(bytes.Buffer)
w := NewWriter(buf)
- testCreate(t, w, "foo", []byte(testString), Store)
- testCreate(t, w, "bar", largeData, Deflate)
+
+ for _, wt := range writeTests {
+ testCreate(t, w, &wt)
+ }
+
if err := w.Close(); err != nil {
t.Fatal(err)
}
@@ -35,26 +61,34 @@ func TestWriter(t *testing.T) {
if err != nil {
t.Fatal(err)
}
- testReadFile(t, r.File[0], []byte(testString))
- testReadFile(t, r.File[1], largeData)
+ for i, wt := range writeTests {
+ testReadFile(t, r.File[i], &wt)
+ }
}
-func testCreate(t *testing.T, w *Writer, name string, data []byte, method uint16) {
+func testCreate(t *testing.T, w *Writer, wt *WriteTest) {
header := &FileHeader{
- Name: name,
- Method: method,
+ Name: wt.Name,
+ Method: wt.Method,
+ }
+ if wt.Mode != 0 {
+ header.SetMode(wt.Mode)
}
f, err := w.CreateHeader(header)
if err != nil {
t.Fatal(err)
}
- _, err = f.Write(data)
+ _, err = f.Write(wt.Data)
if err != nil {
t.Fatal(err)
}
}
-func testReadFile(t *testing.T, f *File, data []byte) {
+func testReadFile(t *testing.T, f *File, wt *WriteTest) {
+ if f.Name != wt.Name {
+ t.Fatalf("File name: got %q, want %q", f.Name, wt.Name)
+ }
+ testFileMode(t, f, wt.Mode)
rc, err := f.Open()
if err != nil {
t.Fatal("opening:", err)
@@ -67,7 +101,7 @@ func testReadFile(t *testing.T, f *File, data []byte) {
if err != nil {
t.Fatal("closing:", err)
}
- if !bytes.Equal(b, data) {
- t.Errorf("File contents %q, want %q", b, data)
+ if !bytes.Equal(b, wt.Data) {
+ t.Errorf("File contents %q, want %q", b, wt.Data)
}
}