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