Tizen_4.0 base
[platform/upstream/docker-engine.git] / vendor / github.com / vbatts / tar-split / archive / tar / common.go
1 // Copyright 2009 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 // Package tar implements access to tar archives.
6 // It aims to cover most of the variations, including those produced
7 // by GNU and BSD tars.
8 //
9 // References:
10 //   http://www.freebsd.org/cgi/man.cgi?query=tar&sektion=5
11 //   http://www.gnu.org/software/tar/manual/html_node/Standard.html
12 //   http://pubs.opengroup.org/onlinepubs/9699919799/utilities/pax.html
13 package tar
14
15 import (
16         "bytes"
17         "errors"
18         "fmt"
19         "os"
20         "path"
21         "time"
22 )
23
24 const (
25         blockSize = 512
26
27         // Types
28         TypeReg           = '0'    // regular file
29         TypeRegA          = '\x00' // regular file
30         TypeLink          = '1'    // hard link
31         TypeSymlink       = '2'    // symbolic link
32         TypeChar          = '3'    // character device node
33         TypeBlock         = '4'    // block device node
34         TypeDir           = '5'    // directory
35         TypeFifo          = '6'    // fifo node
36         TypeCont          = '7'    // reserved
37         TypeXHeader       = 'x'    // extended header
38         TypeXGlobalHeader = 'g'    // global extended header
39         TypeGNULongName   = 'L'    // Next file has a long name
40         TypeGNULongLink   = 'K'    // Next file symlinks to a file w/ a long name
41         TypeGNUSparse     = 'S'    // sparse file
42 )
43
44 // A Header represents a single header in a tar archive.
45 // Some fields may not be populated.
46 type Header struct {
47         Name       string    // name of header file entry
48         Mode       int64     // permission and mode bits
49         Uid        int       // user id of owner
50         Gid        int       // group id of owner
51         Size       int64     // length in bytes
52         ModTime    time.Time // modified time
53         Typeflag   byte      // type of header entry
54         Linkname   string    // target name of link
55         Uname      string    // user name of owner
56         Gname      string    // group name of owner
57         Devmajor   int64     // major number of character or block device
58         Devminor   int64     // minor number of character or block device
59         AccessTime time.Time // access time
60         ChangeTime time.Time // status change time
61         Xattrs     map[string]string
62 }
63
64 // File name constants from the tar spec.
65 const (
66         fileNameSize       = 100 // Maximum number of bytes in a standard tar name.
67         fileNamePrefixSize = 155 // Maximum number of ustar extension bytes.
68 )
69
70 // FileInfo returns an os.FileInfo for the Header.
71 func (h *Header) FileInfo() os.FileInfo {
72         return headerFileInfo{h}
73 }
74
75 // headerFileInfo implements os.FileInfo.
76 type headerFileInfo struct {
77         h *Header
78 }
79
80 func (fi headerFileInfo) Size() int64        { return fi.h.Size }
81 func (fi headerFileInfo) IsDir() bool        { return fi.Mode().IsDir() }
82 func (fi headerFileInfo) ModTime() time.Time { return fi.h.ModTime }
83 func (fi headerFileInfo) Sys() interface{}   { return fi.h }
84
85 // Name returns the base name of the file.
86 func (fi headerFileInfo) Name() string {
87         if fi.IsDir() {
88                 return path.Base(path.Clean(fi.h.Name))
89         }
90         return path.Base(fi.h.Name)
91 }
92
93 // Mode returns the permission and mode bits for the headerFileInfo.
94 func (fi headerFileInfo) Mode() (mode os.FileMode) {
95         // Set file permission bits.
96         mode = os.FileMode(fi.h.Mode).Perm()
97
98         // Set setuid, setgid and sticky bits.
99         if fi.h.Mode&c_ISUID != 0 {
100                 // setuid
101                 mode |= os.ModeSetuid
102         }
103         if fi.h.Mode&c_ISGID != 0 {
104                 // setgid
105                 mode |= os.ModeSetgid
106         }
107         if fi.h.Mode&c_ISVTX != 0 {
108                 // sticky
109                 mode |= os.ModeSticky
110         }
111
112         // Set file mode bits.
113         // clear perm, setuid, setgid and sticky bits.
114         m := os.FileMode(fi.h.Mode) &^ 07777
115         if m == c_ISDIR {
116                 // directory
117                 mode |= os.ModeDir
118         }
119         if m == c_ISFIFO {
120                 // named pipe (FIFO)
121                 mode |= os.ModeNamedPipe
122         }
123         if m == c_ISLNK {
124                 // symbolic link
125                 mode |= os.ModeSymlink
126         }
127         if m == c_ISBLK {
128                 // device file
129                 mode |= os.ModeDevice
130         }
131         if m == c_ISCHR {
132                 // Unix character device
133                 mode |= os.ModeDevice
134                 mode |= os.ModeCharDevice
135         }
136         if m == c_ISSOCK {
137                 // Unix domain socket
138                 mode |= os.ModeSocket
139         }
140
141         switch fi.h.Typeflag {
142         case TypeSymlink:
143                 // symbolic link
144                 mode |= os.ModeSymlink
145         case TypeChar:
146                 // character device node
147                 mode |= os.ModeDevice
148                 mode |= os.ModeCharDevice
149         case TypeBlock:
150                 // block device node
151                 mode |= os.ModeDevice
152         case TypeDir:
153                 // directory
154                 mode |= os.ModeDir
155         case TypeFifo:
156                 // fifo node
157                 mode |= os.ModeNamedPipe
158         }
159
160         return mode
161 }
162
163 // sysStat, if non-nil, populates h from system-dependent fields of fi.
164 var sysStat func(fi os.FileInfo, h *Header) error
165
166 // Mode constants from the tar spec.
167 const (
168         c_ISUID  = 04000   // Set uid
169         c_ISGID  = 02000   // Set gid
170         c_ISVTX  = 01000   // Save text (sticky bit)
171         c_ISDIR  = 040000  // Directory
172         c_ISFIFO = 010000  // FIFO
173         c_ISREG  = 0100000 // Regular file
174         c_ISLNK  = 0120000 // Symbolic link
175         c_ISBLK  = 060000  // Block special file
176         c_ISCHR  = 020000  // Character special file
177         c_ISSOCK = 0140000 // Socket
178 )
179
180 // Keywords for the PAX Extended Header
181 const (
182         paxAtime    = "atime"
183         paxCharset  = "charset"
184         paxComment  = "comment"
185         paxCtime    = "ctime" // please note that ctime is not a valid pax header.
186         paxGid      = "gid"
187         paxGname    = "gname"
188         paxLinkpath = "linkpath"
189         paxMtime    = "mtime"
190         paxPath     = "path"
191         paxSize     = "size"
192         paxUid      = "uid"
193         paxUname    = "uname"
194         paxXattr    = "SCHILY.xattr."
195         paxNone     = ""
196 )
197
198 // FileInfoHeader creates a partially-populated Header from fi.
199 // If fi describes a symlink, FileInfoHeader records link as the link target.
200 // If fi describes a directory, a slash is appended to the name.
201 // Because os.FileInfo's Name method returns only the base name of
202 // the file it describes, it may be necessary to modify the Name field
203 // of the returned header to provide the full path name of the file.
204 func FileInfoHeader(fi os.FileInfo, link string) (*Header, error) {
205         if fi == nil {
206                 return nil, errors.New("tar: FileInfo is nil")
207         }
208         fm := fi.Mode()
209         h := &Header{
210                 Name:    fi.Name(),
211                 ModTime: fi.ModTime(),
212                 Mode:    int64(fm.Perm()), // or'd with c_IS* constants later
213         }
214         switch {
215         case fm.IsRegular():
216                 h.Mode |= c_ISREG
217                 h.Typeflag = TypeReg
218                 h.Size = fi.Size()
219         case fi.IsDir():
220                 h.Typeflag = TypeDir
221                 h.Mode |= c_ISDIR
222                 h.Name += "/"
223         case fm&os.ModeSymlink != 0:
224                 h.Typeflag = TypeSymlink
225                 h.Mode |= c_ISLNK
226                 h.Linkname = link
227         case fm&os.ModeDevice != 0:
228                 if fm&os.ModeCharDevice != 0 {
229                         h.Mode |= c_ISCHR
230                         h.Typeflag = TypeChar
231                 } else {
232                         h.Mode |= c_ISBLK
233                         h.Typeflag = TypeBlock
234                 }
235         case fm&os.ModeNamedPipe != 0:
236                 h.Typeflag = TypeFifo
237                 h.Mode |= c_ISFIFO
238         case fm&os.ModeSocket != 0:
239                 h.Mode |= c_ISSOCK
240         default:
241                 return nil, fmt.Errorf("archive/tar: unknown file mode %v", fm)
242         }
243         if fm&os.ModeSetuid != 0 {
244                 h.Mode |= c_ISUID
245         }
246         if fm&os.ModeSetgid != 0 {
247                 h.Mode |= c_ISGID
248         }
249         if fm&os.ModeSticky != 0 {
250                 h.Mode |= c_ISVTX
251         }
252         // If possible, populate additional fields from OS-specific
253         // FileInfo fields.
254         if sys, ok := fi.Sys().(*Header); ok {
255                 // This FileInfo came from a Header (not the OS). Use the
256                 // original Header to populate all remaining fields.
257                 h.Uid = sys.Uid
258                 h.Gid = sys.Gid
259                 h.Uname = sys.Uname
260                 h.Gname = sys.Gname
261                 h.AccessTime = sys.AccessTime
262                 h.ChangeTime = sys.ChangeTime
263                 if sys.Xattrs != nil {
264                         h.Xattrs = make(map[string]string)
265                         for k, v := range sys.Xattrs {
266                                 h.Xattrs[k] = v
267                         }
268                 }
269                 if sys.Typeflag == TypeLink {
270                         // hard link
271                         h.Typeflag = TypeLink
272                         h.Size = 0
273                         h.Linkname = sys.Linkname
274                 }
275         }
276         if sysStat != nil {
277                 return h, sysStat(fi, h)
278         }
279         return h, nil
280 }
281
282 var zeroBlock = make([]byte, blockSize)
283
284 // POSIX specifies a sum of the unsigned byte values, but the Sun tar uses signed byte values.
285 // We compute and return both.
286 func checksum(header []byte) (unsigned int64, signed int64) {
287         for i := 0; i < len(header); i++ {
288                 if i == 148 {
289                         // The chksum field (header[148:156]) is special: it should be treated as space bytes.
290                         unsigned += ' ' * 8
291                         signed += ' ' * 8
292                         i += 7
293                         continue
294                 }
295                 unsigned += int64(header[i])
296                 signed += int64(int8(header[i]))
297         }
298         return
299 }
300
301 type slicer []byte
302
303 func (sp *slicer) next(n int) (b []byte) {
304         s := *sp
305         b, *sp = s[0:n], s[n:]
306         return
307 }
308
309 func isASCII(s string) bool {
310         for _, c := range s {
311                 if c >= 0x80 {
312                         return false
313                 }
314         }
315         return true
316 }
317
318 func toASCII(s string) string {
319         if isASCII(s) {
320                 return s
321         }
322         var buf bytes.Buffer
323         for _, c := range s {
324                 if c < 0x80 {
325                         buf.WriteByte(byte(c))
326                 }
327         }
328         return buf.String()
329 }
330
331 // isHeaderOnlyType checks if the given type flag is of the type that has no
332 // data section even if a size is specified.
333 func isHeaderOnlyType(flag byte) bool {
334         switch flag {
335         case TypeLink, TypeSymlink, TypeChar, TypeBlock, TypeDir, TypeFifo:
336                 return true
337         default:
338                 return false
339         }
340 }