OSDN Git Service

fdbd16da0482721d36b9ec257283f89589c29669
[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 (h *FileHeader) FileInfo() os.FileInfo {
61         return headerFileInfo{h}
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 func (fi headerFileInfo) Sys() interface{}   { return fi.fh }
75
76 // FileInfoHeader creates a partially-populated FileHeader from an
77 // os.FileInfo.
78 func FileInfoHeader(fi os.FileInfo) (*FileHeader, error) {
79         size := fi.Size()
80         if size > (1<<32 - 1) {
81                 return nil, errors.New("zip: file over 4GB")
82         }
83         fh := &FileHeader{
84                 Name:             fi.Name(),
85                 UncompressedSize: uint32(size),
86         }
87         fh.SetModTime(fi.ModTime())
88         fh.SetMode(fi.Mode())
89         return fh, nil
90 }
91
92 type directoryEnd struct {
93         diskNbr            uint16 // unused
94         dirDiskNbr         uint16 // unused
95         dirRecordsThisDisk uint16 // unused
96         directoryRecords   uint16
97         directorySize      uint32
98         directoryOffset    uint32 // relative to file
99         commentLen         uint16
100         comment            string
101 }
102
103 // msDosTimeToTime converts an MS-DOS date and time into a time.Time.
104 // The resolution is 2s.
105 // See: http://msdn.microsoft.com/en-us/library/ms724247(v=VS.85).aspx
106 func msDosTimeToTime(dosDate, dosTime uint16) time.Time {
107         return time.Date(
108                 // date bits 0-4: day of month; 5-8: month; 9-15: years since 1980
109                 int(dosDate>>9+1980),
110                 time.Month(dosDate>>5&0xf),
111                 int(dosDate&0x1f),
112
113                 // time bits 0-4: second/2; 5-10: minute; 11-15: hour
114                 int(dosTime>>11),
115                 int(dosTime>>5&0x3f),
116                 int(dosTime&0x1f*2),
117                 0, // nanoseconds
118
119                 time.UTC,
120         )
121 }
122
123 // timeToMsDosTime converts a time.Time to an MS-DOS date and time.
124 // The resolution is 2s.
125 // See: http://msdn.microsoft.com/en-us/library/ms724274(v=VS.85).aspx
126 func timeToMsDosTime(t time.Time) (fDate uint16, fTime uint16) {
127         t = t.In(time.UTC)
128         fDate = uint16(t.Day() + int(t.Month())<<5 + (t.Year()-1980)<<9)
129         fTime = uint16(t.Second()/2 + t.Minute()<<5 + t.Hour()<<11)
130         return
131 }
132
133 // ModTime returns the modification time.
134 // The resolution is 2s.
135 func (h *FileHeader) ModTime() time.Time {
136         return msDosTimeToTime(h.ModifiedDate, h.ModifiedTime)
137 }
138
139 // SetModTime sets the ModifiedTime and ModifiedDate fields to the given time.
140 // The resolution is 2s.
141 func (h *FileHeader) SetModTime(t time.Time) {
142         h.ModifiedDate, h.ModifiedTime = timeToMsDosTime(t)
143 }
144
145 const (
146         // Unix constants. The specification doesn't mention them,
147         // but these seem to be the values agreed on by tools.
148         s_IFMT   = 0xf000
149         s_IFSOCK = 0xc000
150         s_IFLNK  = 0xa000
151         s_IFREG  = 0x8000
152         s_IFBLK  = 0x6000
153         s_IFDIR  = 0x4000
154         s_IFCHR  = 0x2000
155         s_IFIFO  = 0x1000
156         s_ISUID  = 0x800
157         s_ISGID  = 0x400
158         s_ISVTX  = 0x200
159
160         msdosDir      = 0x10
161         msdosReadOnly = 0x01
162 )
163
164 // Mode returns the permission and mode bits for the FileHeader.
165 func (h *FileHeader) Mode() (mode os.FileMode) {
166         switch h.CreatorVersion >> 8 {
167         case creatorUnix, creatorMacOSX:
168                 mode = unixModeToFileMode(h.ExternalAttrs >> 16)
169         case creatorNTFS, creatorVFAT, creatorFAT:
170                 mode = msdosModeToFileMode(h.ExternalAttrs)
171         }
172         if len(h.Name) > 0 && h.Name[len(h.Name)-1] == '/' {
173                 mode |= os.ModeDir
174         }
175         return mode
176 }
177
178 // SetMode changes the permission and mode bits for the FileHeader.
179 func (h *FileHeader) SetMode(mode os.FileMode) {
180         h.CreatorVersion = h.CreatorVersion&0xff | creatorUnix<<8
181         h.ExternalAttrs = fileModeToUnixMode(mode) << 16
182
183         // set MSDOS attributes too, as the original zip does.
184         if mode&os.ModeDir != 0 {
185                 h.ExternalAttrs |= msdosDir
186         }
187         if mode&0200 == 0 {
188                 h.ExternalAttrs |= msdosReadOnly
189         }
190 }
191
192 func msdosModeToFileMode(m uint32) (mode os.FileMode) {
193         if m&msdosDir != 0 {
194                 mode = os.ModeDir | 0777
195         } else {
196                 mode = 0666
197         }
198         if m&msdosReadOnly != 0 {
199                 mode &^= 0222
200         }
201         return mode
202 }
203
204 func fileModeToUnixMode(mode os.FileMode) uint32 {
205         var m uint32
206         switch mode & os.ModeType {
207         default:
208                 m = s_IFREG
209         case os.ModeDir:
210                 m = s_IFDIR
211         case os.ModeSymlink:
212                 m = s_IFLNK
213         case os.ModeNamedPipe:
214                 m = s_IFIFO
215         case os.ModeSocket:
216                 m = s_IFSOCK
217         case os.ModeDevice:
218                 if mode&os.ModeCharDevice != 0 {
219                         m = s_IFCHR
220                 } else {
221                         m = s_IFBLK
222                 }
223         }
224         if mode&os.ModeSetuid != 0 {
225                 m |= s_ISUID
226         }
227         if mode&os.ModeSetgid != 0 {
228                 m |= s_ISGID
229         }
230         if mode&os.ModeSticky != 0 {
231                 m |= s_ISVTX
232         }
233         return m | uint32(mode&0777)
234 }
235
236 func unixModeToFileMode(m uint32) os.FileMode {
237         mode := os.FileMode(m & 0777)
238         switch m & s_IFMT {
239         case s_IFBLK:
240                 mode |= os.ModeDevice
241         case s_IFCHR:
242                 mode |= os.ModeDevice | os.ModeCharDevice
243         case s_IFDIR:
244                 mode |= os.ModeDir
245         case s_IFIFO:
246                 mode |= os.ModeNamedPipe
247         case s_IFLNK:
248                 mode |= os.ModeSymlink
249         case s_IFREG:
250                 // nothing to do
251         case s_IFSOCK:
252                 mode |= os.ModeSocket
253         }
254         if m&s_ISGID != 0 {
255                 mode |= os.ModeSetgid
256         }
257         if m&s_ISUID != 0 {
258                 mode |= os.ModeSetuid
259         }
260         if m&s_ISVTX != 0 {
261                 mode |= os.ModeSticky
262         }
263         return mode
264 }