github.com/varialus/godfly@v0.0.0-20130904042352-1934f9f095ab/src/pkg/archive/tar/common.go (about) 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 ) 42 43 // A Header represents a single header in a tar archive. 44 // Some fields may not be populated. 45 type Header struct { 46 Name string // name of header file entry 47 Mode int64 // permission and mode bits 48 Uid int // user id of owner 49 Gid int // group id of owner 50 Size int64 // length in bytes 51 ModTime time.Time // modified time 52 Typeflag byte // type of header entry 53 Linkname string // target name of link 54 Uname string // user name of owner 55 Gname string // group name of owner 56 Devmajor int64 // major number of character or block device 57 Devminor int64 // minor number of character or block device 58 AccessTime time.Time // access time 59 ChangeTime time.Time // status change time 60 } 61 62 // File name constants from the tar spec. 63 const ( 64 fileNameSize = 100 // Maximum number of bytes in a standard tar name. 65 fileNamePrefixSize = 155 // Maximum number of ustar extension bytes. 66 ) 67 68 // FileInfo returns an os.FileInfo for the Header. 69 func (h *Header) FileInfo() os.FileInfo { 70 return headerFileInfo{h} 71 } 72 73 // headerFileInfo implements os.FileInfo. 74 type headerFileInfo struct { 75 h *Header 76 } 77 78 func (fi headerFileInfo) Size() int64 { return fi.h.Size } 79 func (fi headerFileInfo) IsDir() bool { return fi.Mode().IsDir() } 80 func (fi headerFileInfo) ModTime() time.Time { return fi.h.ModTime } 81 func (fi headerFileInfo) Sys() interface{} { return fi.h } 82 83 // Name returns the base name of the file. 84 func (fi headerFileInfo) Name() string { 85 if fi.IsDir() { 86 return path.Base(path.Clean(fi.h.Name)) 87 } 88 return path.Base(fi.h.Name) 89 } 90 91 // Mode returns the permission and mode bits for the headerFileInfo. 92 func (fi headerFileInfo) Mode() (mode os.FileMode) { 93 // Set file permission bits. 94 mode = os.FileMode(fi.h.Mode).Perm() 95 96 // Set setuid, setgid and sticky bits. 97 if fi.h.Mode&c_ISUID != 0 { 98 // setuid 99 mode |= os.ModeSetuid 100 } 101 if fi.h.Mode&c_ISGID != 0 { 102 // setgid 103 mode |= os.ModeSetgid 104 } 105 if fi.h.Mode&c_ISVTX != 0 { 106 // sticky 107 mode |= os.ModeSticky 108 } 109 110 // Set file mode bits. 111 // clear perm, setuid, setgid and sticky bits. 112 m := os.FileMode(fi.h.Mode) &^ 07777 113 if m == c_ISDIR { 114 // directory 115 mode |= os.ModeDir 116 } 117 if m == c_ISFIFO { 118 // named pipe (FIFO) 119 mode |= os.ModeNamedPipe 120 } 121 if m == c_ISLNK { 122 // symbolic link 123 mode |= os.ModeSymlink 124 } 125 if m == c_ISBLK { 126 // device file 127 mode |= os.ModeDevice 128 } 129 if m == c_ISCHR { 130 // Unix character device 131 mode |= os.ModeDevice 132 mode |= os.ModeCharDevice 133 } 134 if m == c_ISSOCK { 135 // Unix domain socket 136 mode |= os.ModeSocket 137 } 138 139 switch fi.h.Typeflag { 140 case TypeLink, TypeSymlink: 141 // hard link, symbolic link 142 mode |= os.ModeSymlink 143 case TypeChar: 144 // character device node 145 mode |= os.ModeDevice 146 mode |= os.ModeCharDevice 147 case TypeBlock: 148 // block device node 149 mode |= os.ModeDevice 150 case TypeDir: 151 // directory 152 mode |= os.ModeDir 153 case TypeFifo: 154 // fifo node 155 mode |= os.ModeNamedPipe 156 } 157 158 return mode 159 } 160 161 // sysStat, if non-nil, populates h from system-dependent fields of fi. 162 var sysStat func(fi os.FileInfo, h *Header) error 163 164 // Mode constants from the tar spec. 165 const ( 166 c_ISUID = 04000 // Set uid 167 c_ISGID = 02000 // Set gid 168 c_ISVTX = 01000 // Save text (sticky bit) 169 c_ISDIR = 040000 // Directory 170 c_ISFIFO = 010000 // FIFO 171 c_ISREG = 0100000 // Regular file 172 c_ISLNK = 0120000 // Symbolic link 173 c_ISBLK = 060000 // Block special file 174 c_ISCHR = 020000 // Character special file 175 c_ISSOCK = 0140000 // Socket 176 ) 177 178 // Keywords for the PAX Extended Header 179 const ( 180 paxAtime = "atime" 181 paxCharset = "charset" 182 paxComment = "comment" 183 paxCtime = "ctime" // please note that ctime is not a valid pax header. 184 paxGid = "gid" 185 paxGname = "gname" 186 paxLinkpath = "linkpath" 187 paxMtime = "mtime" 188 paxPath = "path" 189 paxSize = "size" 190 paxUid = "uid" 191 paxUname = "uname" 192 paxNone = "" 193 ) 194 195 // FileInfoHeader creates a partially-populated Header from fi. 196 // If fi describes a symlink, FileInfoHeader records link as the link target. 197 // If fi describes a directory, a slash is appended to the name. 198 // Because os.FileInfo's Name method returns only the base name of 199 // the file it describes, it may be necessary to modify the Name field 200 // of the returned header to provide the full path name of the file. 201 func FileInfoHeader(fi os.FileInfo, link string) (*Header, error) { 202 if fi == nil { 203 return nil, errors.New("tar: FileInfo is nil") 204 } 205 fm := fi.Mode() 206 h := &Header{ 207 Name: fi.Name(), 208 ModTime: fi.ModTime(), 209 Mode: int64(fm.Perm()), // or'd with c_IS* constants later 210 } 211 switch { 212 case fm.IsRegular(): 213 h.Mode |= c_ISREG 214 h.Typeflag = TypeReg 215 h.Size = fi.Size() 216 case fi.IsDir(): 217 h.Typeflag = TypeDir 218 h.Mode |= c_ISDIR 219 h.Name += "/" 220 case fm&os.ModeSymlink != 0: 221 h.Typeflag = TypeSymlink 222 h.Mode |= c_ISLNK 223 h.Linkname = link 224 case fm&os.ModeDevice != 0: 225 if fm&os.ModeCharDevice != 0 { 226 h.Mode |= c_ISCHR 227 h.Typeflag = TypeChar 228 } else { 229 h.Mode |= c_ISBLK 230 h.Typeflag = TypeBlock 231 } 232 case fm&os.ModeNamedPipe != 0: 233 h.Typeflag = TypeFifo 234 h.Mode |= c_ISFIFO 235 case fm&os.ModeSocket != 0: 236 h.Mode |= c_ISSOCK 237 default: 238 return nil, fmt.Errorf("archive/tar: unknown file mode %v", fm) 239 } 240 if fm&os.ModeSetuid != 0 { 241 h.Mode |= c_ISUID 242 } 243 if fm&os.ModeSetgid != 0 { 244 h.Mode |= c_ISGID 245 } 246 if fm&os.ModeSticky != 0 { 247 h.Mode |= c_ISVTX 248 } 249 if sysStat != nil { 250 return h, sysStat(fi, h) 251 } 252 return h, nil 253 } 254 255 var zeroBlock = make([]byte, blockSize) 256 257 // POSIX specifies a sum of the unsigned byte values, but the Sun tar uses signed byte values. 258 // We compute and return both. 259 func checksum(header []byte) (unsigned int64, signed int64) { 260 for i := 0; i < len(header); i++ { 261 if i == 148 { 262 // The chksum field (header[148:156]) is special: it should be treated as space bytes. 263 unsigned += ' ' * 8 264 signed += ' ' * 8 265 i += 7 266 continue 267 } 268 unsigned += int64(header[i]) 269 signed += int64(int8(header[i])) 270 } 271 return 272 } 273 274 type slicer []byte 275 276 func (sp *slicer) next(n int) (b []byte) { 277 s := *sp 278 b, *sp = s[0:n], s[n:] 279 return 280 } 281 282 func isASCII(s string) bool { 283 for _, c := range s { 284 if c >= 0x80 { 285 return false 286 } 287 } 288 return true 289 } 290 291 func toASCII(s string) string { 292 if isASCII(s) { 293 return s 294 } 295 var buf bytes.Buffer 296 for _, c := range s { 297 if c < 0x80 { 298 buf.WriteByte(byte(c)) 299 } 300 } 301 return buf.String() 302 }