Left: | ||
Right: |
LEFT | RIGHT |
---|---|
1 // Copyright 2009 The Go Authors. All rights reserved. | 1 // Copyright 2009 The Go Authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style | 2 // Use of this source code is governed by a BSD-style |
3 // license that can be found in the LICENSE file. | 3 // license that can be found in the LICENSE file. |
4 | 4 |
5 // Package tar implements access to tar archives. | 5 // Package tar implements access to tar archives. |
6 // It aims to cover most of the variations, including those produced | 6 // It aims to cover most of the variations, including those produced |
7 // by GNU and BSD tars. | 7 // by GNU and BSD tars. |
8 // | 8 // |
9 // References: | 9 // References: |
10 // http://www.freebsd.org/cgi/man.cgi?query=tar&sektion=5 | 10 // http://www.freebsd.org/cgi/man.cgi?query=tar&sektion=5 |
11 // http://www.gnu.org/software/tar/manual/html_node/Standard.html | 11 // http://www.gnu.org/software/tar/manual/html_node/Standard.html |
12 // http://pubs.opengroup.org/onlinepubs/9699919799/utilities/pax.html | |
12 package tar | 13 package tar |
13 | 14 |
14 import ( | 15 import ( |
15 "errors" | 16 "errors" |
16 "fmt" | 17 "fmt" |
17 "os" | 18 "os" |
19 "path" | |
18 "time" | 20 "time" |
19 ) | 21 ) |
20 | 22 |
21 const ( | 23 const ( |
22 blockSize = 512 | 24 blockSize = 512 |
23 | 25 |
24 // Types | 26 // Types |
25 TypeReg = '0' // regular file | 27 TypeReg = '0' // regular file |
26 TypeRegA = '\x00' // regular file | 28 TypeRegA = '\x00' // regular file |
27 TypeLink = '1' // hard link | 29 TypeLink = '1' // hard link |
28 TypeSymlink = '2' // symbolic link | 30 TypeSymlink = '2' // symbolic link |
29 TypeChar = '3' // character device node | 31 TypeChar = '3' // character device node |
30 TypeBlock = '4' // block device node | 32 TypeBlock = '4' // block device node |
31 TypeDir = '5' // directory | 33 TypeDir = '5' // directory |
32 TypeFifo = '6' // fifo node | 34 TypeFifo = '6' // fifo node |
33 TypeCont = '7' // reserved | 35 TypeCont = '7' // reserved |
34 TypeXHeader = 'x' // extended header | 36 TypeXHeader = 'x' // extended header |
35 TypeXGlobalHeader = 'g' // global extended header | 37 TypeXGlobalHeader = 'g' // global extended header |
38 TypeGNULongName = 'L' // Next file has a long name | |
39 TypeGNULongLink = 'K' // Next file symlinks to a file w/ a long nam e | |
36 ) | 40 ) |
37 | 41 |
38 // A Header represents a single header in a tar archive. | 42 // A Header represents a single header in a tar archive. |
39 // Some fields may not be populated. | 43 // Some fields may not be populated. |
40 type Header struct { | 44 type Header struct { |
41 Name string // name of header file entry | 45 Name string // name of header file entry |
42 Mode int64 // permission and mode bits | 46 Mode int64 // permission and mode bits |
43 Uid int // user id of owner | 47 Uid int // user id of owner |
44 Gid int // group id of owner | 48 Gid int // group id of owner |
45 Size int64 // length in bytes | 49 Size int64 // length in bytes |
46 ModTime time.Time // modified time | 50 ModTime time.Time // modified time |
47 Typeflag byte // type of header entry | 51 Typeflag byte // type of header entry |
48 Linkname string // target name of link | 52 Linkname string // target name of link |
49 Uname string // user name of owner | 53 Uname string // user name of owner |
50 Gname string // group name of owner | 54 Gname string // group name of owner |
51 Devmajor int64 // major number of character or block device | 55 Devmajor int64 // major number of character or block device |
52 Devminor int64 // minor number of character or block device | 56 Devminor int64 // minor number of character or block device |
53 AccessTime time.Time // access time | 57 AccessTime time.Time // access time |
54 ChangeTime time.Time // status change time | 58 ChangeTime time.Time // status change time |
55 } | 59 } |
56 | 60 |
61 // File name constants from the tar spec. | |
62 const ( | |
63 fileNameSize = 100 // Maximum number of bytes in a standard tar na me. | |
64 fileNamePrefixSize = 155 // Maximum number of ustar extension bytes. | |
65 ) | |
66 | |
57 // FileInfo returns an os.FileInfo for the Header. | 67 // FileInfo returns an os.FileInfo for the Header. |
58 func (h *Header) FileInfo() os.FileInfo { | 68 func (h *Header) FileInfo() os.FileInfo { |
59 return headerFileInfo{h} | 69 return headerFileInfo{h} |
60 } | 70 } |
61 | 71 |
62 // headerFileInfo implements os.FileInfo. | 72 // headerFileInfo implements os.FileInfo. |
63 type headerFileInfo struct { | 73 type headerFileInfo struct { |
64 h *Header | 74 h *Header |
65 } | 75 } |
66 | 76 |
67 func (fi headerFileInfo) Name() string { return fi.h.Name } | |
68 func (fi headerFileInfo) Size() int64 { return fi.h.Size } | 77 func (fi headerFileInfo) Size() int64 { return fi.h.Size } |
69 func (fi headerFileInfo) IsDir() bool { return fi.Mode().IsDir() } | 78 func (fi headerFileInfo) IsDir() bool { return fi.Mode().IsDir() } |
70 func (fi headerFileInfo) ModTime() time.Time { return fi.h.ModTime } | 79 func (fi headerFileInfo) ModTime() time.Time { return fi.h.ModTime } |
80 func (fi headerFileInfo) Sys() interface{} { return fi.h } | |
81 | |
82 // Name returns the base name of the file. | |
83 func (fi headerFileInfo) Name() string { | |
84 if fi.IsDir() { | |
85 return path.Clean(fi.h.Name) | |
86 } | |
87 return fi.h.Name | |
88 } | |
71 | 89 |
72 // Mode returns the permission and mode bits for the headerFileInfo. | 90 // Mode returns the permission and mode bits for the headerFileInfo. |
73 func (fi headerFileInfo) Mode() (mode os.FileMode) { | 91 func (fi headerFileInfo) Mode() (mode os.FileMode) { |
74 // Set file permission bits. | 92 // Set file permission bits. |
75 » mode = os.FileMode(fi.h.Mode) & os.ModePerm | 93 » mode = os.FileMode(fi.h.Mode).Perm() |
94 | |
95 » // Set setuid, setgid and sticky bits. | |
96 » if fi.h.Mode&c_ISUID != 0 { | |
97 » » // setuid | |
98 » » mode |= os.ModeSetuid | |
99 » } | |
100 » if fi.h.Mode&c_ISGID != 0 { | |
101 » » // setgid | |
102 » » mode |= os.ModeSetgid | |
103 » } | |
104 » if fi.h.Mode&c_ISVTX != 0 { | |
105 » » // sticky | |
106 » » mode |= os.ModeSticky | |
107 » } | |
76 | 108 |
77 // Set file mode bits. | 109 // Set file mode bits. |
78 » m := os.FileMode(fi.h.Mode) &^ os.ModePerm | 110 » // clear perm, setuid, setgid and sticky bits. |
79 » switch { | 111 » m := os.FileMode(fi.h.Mode) &^ 07777 |
80 » case m&c_ISDIR != 0: | 112 » if m == c_ISDIR { |
113 » » // directory | |
81 mode |= os.ModeDir | 114 mode |= os.ModeDir |
82 » case m&c_ISFIFO != 0: | 115 » } |
116 » if m == c_ISFIFO { | |
117 » » // named pipe (FIFO) | |
83 mode |= os.ModeNamedPipe | 118 mode |= os.ModeNamedPipe |
u
2013/02/09 20:21:11
Could someone please verify that os.ModeNamedPipe
| |
84 » case m&c_ISREG != 0: | 119 » } |
85 » » // regular file | 120 » if m == c_ISLNK { |
u
2013/02/09 20:21:11
Should we remove this nop case?
| |
86 » case m&c_ISLNK != 0: | 121 » » // symbolic link |
87 mode |= os.ModeSymlink | 122 mode |= os.ModeSymlink |
88 » case m&c_ISBLK != 0: | 123 » } |
89 » » mode |= os.ModeDevice | 124 » if m == c_ISBLK { |
90 » case m&c_ISCHR != 0: | 125 » » // device file |
126 » » mode |= os.ModeDevice | |
127 » } | |
128 » if m == c_ISCHR { | |
129 » » // Unix character device | |
91 mode |= os.ModeDevice | 130 mode |= os.ModeDevice |
92 mode |= os.ModeCharDevice | 131 mode |= os.ModeCharDevice |
93 » case m&c_ISSOCK != 0: | 132 » } |
133 » if m == c_ISSOCK { | |
134 » » // Unix domain socket | |
94 mode |= os.ModeSocket | 135 mode |= os.ModeSocket |
95 } | 136 } |
96 | 137 |
97 switch fi.h.Typeflag { | 138 switch fi.h.Typeflag { |
98 » case '0', '\x00': | 139 » case TypeLink, TypeSymlink: |
99 » » // regular file | |
u
2013/02/09 20:21:11
Should we remove nop cases ('0', '\x00', '7', 'x',
| |
100 » case '1', '2': | |
101 // hard link, symbolic link | 140 // hard link, symbolic link |
102 mode |= os.ModeSymlink | 141 mode |= os.ModeSymlink |
u
2013/02/09 20:21:11
Is there a way to differentiate a hard link from a
| |
103 » case '3': | 142 » case TypeChar: |
104 // character device node | 143 // character device node |
105 mode |= os.ModeDevice | 144 mode |= os.ModeDevice |
106 mode |= os.ModeCharDevice | 145 mode |= os.ModeCharDevice |
107 » case '4': | 146 » case TypeBlock: |
108 // block device node | 147 // block device node |
109 mode |= os.ModeDevice | 148 mode |= os.ModeDevice |
110 » case '5': | 149 » case TypeDir: |
111 // directory | 150 // directory |
112 mode |= os.ModeDir | 151 mode |= os.ModeDir |
113 » case '6': | 152 » case TypeFifo: |
114 // fifo node | 153 // fifo node |
115 mode |= os.ModeNamedPipe | 154 mode |= os.ModeNamedPipe |
u
2013/02/09 20:21:11
Could someone please verify that os.ModeNamedPipe
| |
116 case '7': | |
117 // reserved | |
118 case 'x': | |
119 // extended header | |
120 case 'g': | |
121 // global extended header | |
122 } | 155 } |
123 | 156 |
124 return mode | 157 return mode |
125 } | 158 } |
126 | |
127 func (fi headerFileInfo) Sys() interface{} { return fi.h } | |
128 | 159 |
129 // sysStat, if non-nil, populates h from system-dependent fields of fi. | 160 // sysStat, if non-nil, populates h from system-dependent fields of fi. |
130 var sysStat func(fi os.FileInfo, h *Header) error | 161 var sysStat func(fi os.FileInfo, h *Header) error |
131 | 162 |
132 // Mode constants from the tar spec. | 163 // Mode constants from the tar spec. |
133 const ( | 164 const ( |
134 » c_ISDIR = 040000 | 165 » c_ISUID = 04000 // Set uid |
135 » c_ISFIFO = 010000 | 166 » c_ISGID = 02000 // Set gid |
136 » c_ISREG = 0100000 | 167 » c_ISVTX = 01000 // Save text (sticky bit) |
137 » c_ISLNK = 0120000 | 168 » c_ISDIR = 040000 // Directory |
138 » c_ISBLK = 060000 | 169 » c_ISFIFO = 010000 // FIFO |
139 » c_ISCHR = 020000 | 170 » c_ISREG = 0100000 // Regular file |
140 » c_ISSOCK = 0140000 | 171 » c_ISLNK = 0120000 // Symbolic link |
172 » c_ISBLK = 060000 // Block special file | |
173 » c_ISCHR = 020000 // Character special file | |
174 » c_ISSOCK = 0140000 // Socket | |
141 ) | 175 ) |
142 | 176 |
143 // FileInfoHeader creates a partially-populated Header from fi. | 177 // FileInfoHeader creates a partially-populated Header from fi. |
144 // If fi describes a symlink, FileInfoHeader records link as the link target. | 178 // If fi describes a symlink, FileInfoHeader records link as the link target. |
179 // If fi describes a directory, a slash is appended to the name. | |
145 func FileInfoHeader(fi os.FileInfo, link string) (*Header, error) { | 180 func FileInfoHeader(fi os.FileInfo, link string) (*Header, error) { |
146 if fi == nil { | 181 if fi == nil { |
147 return nil, errors.New("tar: FileInfo is nil") | 182 return nil, errors.New("tar: FileInfo is nil") |
148 } | 183 } |
184 fm := fi.Mode() | |
149 h := &Header{ | 185 h := &Header{ |
150 Name: fi.Name(), | 186 Name: fi.Name(), |
151 ModTime: fi.ModTime(), | 187 ModTime: fi.ModTime(), |
152 » » Mode: int64(fi.Mode().Perm()), // or'd with c_IS* constants l ater | 188 » » Mode: int64(fm.Perm()), // or'd with c_IS* constants later |
153 } | 189 } |
154 switch { | 190 switch { |
155 » case fi.Mode().IsRegular(): | 191 » case fm.IsRegular(): |
156 h.Mode |= c_ISREG | 192 h.Mode |= c_ISREG |
157 h.Typeflag = TypeReg | 193 h.Typeflag = TypeReg |
158 h.Size = fi.Size() | 194 h.Size = fi.Size() |
159 case fi.IsDir(): | 195 case fi.IsDir(): |
160 h.Typeflag = TypeDir | 196 h.Typeflag = TypeDir |
161 h.Mode |= c_ISDIR | 197 h.Mode |= c_ISDIR |
162 » case fi.Mode()&os.ModeSymlink != 0: | 198 » » h.Name += "/" |
199 » case fm&os.ModeSymlink != 0: | |
163 h.Typeflag = TypeSymlink | 200 h.Typeflag = TypeSymlink |
164 h.Mode |= c_ISLNK | 201 h.Mode |= c_ISLNK |
165 h.Linkname = link | 202 h.Linkname = link |
166 » case fi.Mode()&os.ModeDevice != 0: | 203 » case fm&os.ModeDevice != 0: |
167 » » if fi.Mode()&os.ModeCharDevice != 0 { | 204 » » if fm&os.ModeCharDevice != 0 { |
168 h.Mode |= c_ISCHR | 205 h.Mode |= c_ISCHR |
169 h.Typeflag = TypeChar | 206 h.Typeflag = TypeChar |
170 } else { | 207 } else { |
171 h.Mode |= c_ISBLK | 208 h.Mode |= c_ISBLK |
172 h.Typeflag = TypeBlock | 209 h.Typeflag = TypeBlock |
173 } | 210 } |
174 » case fi.Mode()&os.ModeSocket != 0: | 211 » case fm&os.ModeNamedPipe != 0: |
212 » » h.Typeflag = TypeFifo | |
213 » » h.Mode |= c_ISFIFO | |
214 » case fm&os.ModeSocket != 0: | |
175 h.Mode |= c_ISSOCK | 215 h.Mode |= c_ISSOCK |
176 default: | 216 default: |
177 » » return nil, fmt.Errorf("archive/tar: unknown file mode %v", fi.M ode()) | 217 » » return nil, fmt.Errorf("archive/tar: unknown file mode %v", fm) |
218 » } | |
219 » if fm&os.ModeSetuid != 0 { | |
220 » » h.Mode |= c_ISUID | |
221 » } | |
222 » if fm&os.ModeSetgid != 0 { | |
223 » » h.Mode |= c_ISGID | |
224 » } | |
225 » if fm&os.ModeSticky != 0 { | |
226 » » h.Mode |= c_ISVTX | |
178 } | 227 } |
179 if sysStat != nil { | 228 if sysStat != nil { |
180 return h, sysStat(fi, h) | 229 return h, sysStat(fi, h) |
181 } | 230 } |
182 return h, nil | 231 return h, nil |
183 } | 232 } |
184 | 233 |
185 var zeroBlock = make([]byte, blockSize) | 234 var zeroBlock = make([]byte, blockSize) |
186 | 235 |
187 // POSIX specifies a sum of the unsigned byte values, but the Sun tar uses signe d byte values. | 236 // POSIX specifies a sum of the unsigned byte values, but the Sun tar uses signe d byte values. |
(...skipping 13 matching lines...) Expand all Loading... | |
201 return | 250 return |
202 } | 251 } |
203 | 252 |
204 type slicer []byte | 253 type slicer []byte |
205 | 254 |
206 func (sp *slicer) next(n int) (b []byte) { | 255 func (sp *slicer) next(n int) (b []byte) { |
207 s := *sp | 256 s := *sp |
208 b, *sp = s[0:n], s[n:] | 257 b, *sp = s[0:n], s[n:] |
209 return | 258 return |
210 } | 259 } |
LEFT | RIGHT |