OSDN Git Service

67e9658629419a06bdbf064254735012fdd71372
[pf3gnuchains/gcc-fork.git] / libgo / go / archive / zip / struct.go
1 // Copyright 2010 The Go Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style
3 // license that can be found in the LICENSE file.
4
5 /*
6 Package zip provides support for reading and writing ZIP archives.
7
8 See: http://www.pkware.com/documents/casestudies/APPNOTE.TXT
9
10 This package does not support ZIP64 or disk spanning.
11 */
12 package zip
13
14 import (
15         "errors"
16         "os"
17         "time"
18 )
19
20 // Compression methods.
21 const (
22         Store   uint16 = 0
23         Deflate uint16 = 8
24 )
25
26 const (
27         fileHeaderSignature      = 0x04034b50
28         directoryHeaderSignature = 0x02014b50
29         directoryEndSignature    = 0x06054b50
30         fileHeaderLen            = 30 // + filename + extra
31         directoryHeaderLen       = 46 // + filename + extra + comment
32         directoryEndLen          = 22 // + comment
33         dataDescriptorLen        = 12
34
35         // Constants for the first byte in CreatorVersion
36         creatorFAT    = 0
37         creatorUnix   = 3
38         creatorNTFS   = 11
39         creatorVFAT   = 14
40         creatorMacOSX = 19
41 )
42
43 type FileHeader struct {
44         Name             string
45         CreatorVersion   uint16
46         ReaderVersion    uint16
47         Flags            uint16
48         Method           uint16
49         ModifiedTime     uint16 // MS-DOS time
50         ModifiedDate     uint16 // MS-DOS date
51         CRC32            uint32
52         CompressedSize   uint32
53         UncompressedSize uint32
54         Extra            []byte
55         ExternalAttrs    uint32 // Meaning depends on CreatorVersion
56         Comment          string
57 }
58
59 // FileInfo returns an os.FileInfo for the FileHeader.
60 func (fh *FileHeader) FileInfo() os.FileInfo {
61         return headerFileInfo{fh}
62 }
63
64 // headerFileInfo implements os.FileInfo.
65 type headerFileInfo struct {
66         fh *FileHeader
67 }
68
69 func (fi headerFileInfo) Name() string       { return fi.fh.Name }
70 func (fi headerFileInfo) Size() int64        { return int64(fi.fh.UncompressedSize) }
71 func (fi headerFileInfo) IsDir() bool        { return fi.Mode().IsDir() }
72 func (fi headerFileInfo) ModTime() time.Time { return fi.fh.ModTime() }
73 func (fi headerFileInfo) Mode() os.FileMode  { return fi.fh.Mode() }
74
75 // FileInfoHeader creates a partially-populated FileHeader from an
76 // os.FileInfo.
77 func FileInfoHeader(fi os.FileInfo) (*FileHeader, error) {
78         size := fi.Size()
79         if size > (1<<32 - 1) {
80                 return nil, errors.New("zip: file over 4GB")
81         }
82         fh := &FileHeader{
83                 Name:             fi.Name(),
84                 UncompressedSize: uint32(size),
85         }
86         fh.SetModTime(fi.ModTime())
87         fh.SetMode(fi.Mode())
88         return fh, nil
89 }
90
91 type directoryEnd struct {
92         diskNbr            uint16 // unused
93         dirDiskNbr         uint16 // unused
94         dirRecordsThisDisk uint16 // unused
95         directoryRecords   uint16
96         directorySize      uint32
97         directoryOffset    uint32 // relative to file
98         commentLen         uint16
99         comment            string
100 }
101
102 func recoverError(errp *error) {
103         if e := recover(); e != nil {
104                 if err, ok := e.(error); ok {
105                         *errp = err
106                         return
107                 }
108                 panic(e)
109         }
110 }
111
112 // msDosTimeToTime converts an MS-DOS date and time into a time.Time.
113 // The resolution is 2s.
114 // See: http://msdn.microsoft.com/en-us/library/ms724247(v=VS.85).aspx
115 func msDosTimeToTime(dosDate, dosTime uint16) time.Time {
116         return time.Date(
117                 // date bits 0-4: day of month; 5-8: month; 9-15: years since 1980
118                 int(dosDate>>9+1980),
119                 time.Month(dosDate>>5&0xf),
120                 int(dosDate&0x1f),
121
122                 // time bits 0-4: second/2; 5-10: minute; 11-15: hour
123                 int(dosTime>>11),
124                 int(dosTime>>5&0x3f),
125                 int(dosTime&0x1f*2),
126                 0, // nanoseconds
127
128                 time.UTC,
129         )
130 }
131
132 // timeToMsDosTime converts a time.Time to an MS-DOS date and time.
133 // The resolution is 2s.
134 // See: http://msdn.microsoft.com/en-us/library/ms724274(v=VS.85).aspx
135 func timeToMsDosTime(t time.Time) (fDate uint16, fTime uint16) {
136         t = t.In(time.UTC)
137         fDate = uint16(t.Day() + int(t.Month())<<5 + (t.Year()-1980)<<9)
138         fTime = uint16(t.Second()/2 + t.Minute()<<5 + t.Hour()<<11)
139         return
140 }
141
142 // ModTime returns the modification time.
143 // The resolution is 2s.
144 func (h *FileHeader) ModTime() time.Time {
145         return msDosTimeToTime(h.ModifiedDate, h.ModifiedTime)
146 }
147
148 // SetModTime sets the ModifiedTime and ModifiedDate fields to the given time.
149 // The resolution is 2s.
150 func (h *FileHeader) SetModTime(t time.Time) {
151         h.ModifiedDate, h.ModifiedTime = timeToMsDosTime(t)
152 }
153
154 // traditional names for Unix constants
155 const (
156         s_IFMT  = 0xf000
157         s_IFDIR = 0x4000
158         s_IFREG = 0x8000
159         s_ISUID = 0x800
160         s_ISGID = 0x400
161
162         msdosDir      = 0x10
163         msdosReadOnly = 0x01
164 )
165
166 // Mode returns the permission and mode bits for the FileHeader.
167 func (h *FileHeader) Mode() (mode os.FileMode) {
168         switch h.CreatorVersion >> 8 {
169         case creatorUnix, creatorMacOSX:
170                 mode = unixModeToFileMode(h.ExternalAttrs >> 16)
171         case creatorNTFS, creatorVFAT, creatorFAT:
172                 mode = msdosModeToFileMode(h.ExternalAttrs)
173         }
174         if len(h.Name) > 0 && h.Name[len(h.Name)-1] == '/' {
175                 mode |= os.ModeDir
176         }
177         return mode
178 }
179
180 // SetMode changes the permission and mode bits for the FileHeader.
181 func (h *FileHeader) SetMode(mode os.FileMode) {
182         h.CreatorVersion = h.CreatorVersion&0xff | creatorUnix<<8
183         h.ExternalAttrs = fileModeToUnixMode(mode) << 16
184
185         // set MSDOS attributes too, as the original zip does.
186         if mode&os.ModeDir != 0 {
187                 h.ExternalAttrs |= msdosDir
188         }
189         if mode&0200 == 0 {
190                 h.ExternalAttrs |= msdosReadOnly
191         }
192 }
193
194 func msdosModeToFileMode(m uint32) (mode os.FileMode) {
195         if m&msdosDir != 0 {
196                 mode = os.ModeDir | 0777
197         } else {
198                 mode = 0666
199         }
200         if m&msdosReadOnly != 0 {
201                 mode &^= 0222
202         }
203         return mode
204 }
205
206 func fileModeToUnixMode(mode os.FileMode) uint32 {
207         var m uint32
208         if mode&os.ModeDir != 0 {
209                 m = s_IFDIR
210         } else {
211                 m = s_IFREG
212         }
213         if mode&os.ModeSetuid != 0 {
214                 m |= s_ISUID
215         }
216         if mode&os.ModeSetgid != 0 {
217                 m |= s_ISGID
218         }
219         return m | uint32(mode&0777)
220 }
221
222 func unixModeToFileMode(m uint32) os.FileMode {
223         var mode os.FileMode
224         if m&s_IFMT == s_IFDIR {
225                 mode |= os.ModeDir
226         }
227         if m&s_ISGID != 0 {
228                 mode |= os.ModeSetgid
229         }
230         if m&s_ISUID != 0 {
231                 mode |= os.ModeSetuid
232         }
233         return mode | os.FileMode(m&0777)
234 }