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 13package tar 14 15import ( 16 "errors" 17 "fmt" 18 "os" 19 "path" 20 "time" 21) 22 23const ( 24 blockSize = 512 25 26 // Types 27 TypeReg = '0' // regular file 28 TypeRegA = '\x00' // regular file 29 TypeLink = '1' // hard link 30 TypeSymlink = '2' // symbolic link 31 TypeChar = '3' // character device node 32 TypeBlock = '4' // block device node 33 TypeDir = '5' // directory 34 TypeFifo = '6' // fifo node 35 TypeCont = '7' // reserved 36 TypeXHeader = 'x' // 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 name 40) 41 42// A Header represents a single header in a tar archive. 43// Some fields may not be populated. 44type 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} 60 61// File name constants from the tar spec. 62const ( 63 fileNameSize = 100 // Maximum number of bytes in a standard tar name. 64 fileNamePrefixSize = 155 // Maximum number of ustar extension bytes. 65) 66 67// FileInfo returns an os.FileInfo for the Header. 68func (h *Header) FileInfo() os.FileInfo { 69 return headerFileInfo{h} 70} 71 72// headerFileInfo implements os.FileInfo. 73type headerFileInfo struct { 74 h *Header 75} 76 77func (fi headerFileInfo) Size() int64 { return fi.h.Size } 78func (fi headerFileInfo) IsDir() bool { return fi.Mode().IsDir() } 79func (fi headerFileInfo) ModTime() time.Time { return fi.h.ModTime } 80func (fi headerFileInfo) Sys() interface{} { return fi.h } 81 82// Name returns the base name of the file. 83func (fi headerFileInfo) Name() string { 84 if fi.IsDir() { 85 return path.Clean(fi.h.Name) 86 } 87 return fi.h.Name 88} 89 90// Mode returns the permission and mode bits for the headerFileInfo. 91func (fi headerFileInfo) Mode() (mode os.FileMode) { 92 // Set file permission bits. 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 } 108 109 // Set file mode bits. 110 // clear perm, setuid, setgid and sticky bits. 111 m := os.FileMode(fi.h.Mode) &^ 07777 112 if m == c_ISDIR { 113 // directory 114 mode |= os.ModeDir 115 } 116 if m == c_ISFIFO { 117 // named pipe (FIFO) 118 mode |= os.ModeNamedPipe 119 } 120 if m == c_ISLNK { 121 // symbolic link 122 mode |= os.ModeSymlink 123 } 124 if m == c_ISBLK { 125 // device file 126 mode |= os.ModeDevice 127 } 128 if m == c_ISCHR { 129 // Unix character device 130 mode |= os.ModeDevice 131 mode |= os.ModeCharDevice 132 } 133 if m == c_ISSOCK { 134 // Unix domain socket 135 mode |= os.ModeSocket 136 } 137 138 switch fi.h.Typeflag { 139 case TypeLink, TypeSymlink: 140 // hard link, symbolic link 141 mode |= os.ModeSymlink 142 case TypeChar: 143 // character device node 144 mode |= os.ModeDevice 145 mode |= os.ModeCharDevice 146 case TypeBlock: 147 // block device node 148 mode |= os.ModeDevice 149 case TypeDir: 150 // directory 151 mode |= os.ModeDir 152 case TypeFifo: 153 // fifo node 154 mode |= os.ModeNamedPipe 155 } 156 157 return mode 158} 159 160// sysStat, if non-nil, populates h from system-dependent fields of fi. 161var sysStat func(fi os.FileInfo, h *Header) error 162 163// Mode constants from the tar spec. 164const ( 165 c_ISUID = 04000 // Set uid 166 c_ISGID = 02000 // Set gid 167 c_ISVTX = 01000 // Save text (sticky bit) 168 c_ISDIR = 040000 // Directory 169 c_ISFIFO = 010000 // FIFO 170 c_ISREG = 0100000 // Regular file 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 175) 176 177// FileInfoHeader creates a partially-populated Header from fi. 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. 180func FileInfoHeader(fi os.FileInfo, link string) (*Header, error) { 181 if fi == nil { 182 return nil, errors.New("tar: FileInfo is nil") 183 } 184 fm := fi.Mode() 185 h := &Header{ 186 Name: fi.Name(), 187 ModTime: fi.ModTime(), 188 Mode: int64(fm.Perm()), // or'd with c_IS* constants later 189 } 190 switch { 191 case fm.IsRegular(): 192 h.Mode |= c_ISREG 193 h.Typeflag = TypeReg 194 h.Size = fi.Size() 195 case fi.IsDir(): 196 h.Typeflag = TypeDir 197 h.Mode |= c_ISDIR 198 h.Name += "/" 199 case fm&os.ModeSymlink != 0: 200 h.Typeflag = TypeSymlink 201 h.Mode |= c_ISLNK 202 h.Linkname = link 203 case fm&os.ModeDevice != 0: 204 if fm&os.ModeCharDevice != 0 { 205 h.Mode |= c_ISCHR 206 h.Typeflag = TypeChar 207 } else { 208 h.Mode |= c_ISBLK 209 h.Typeflag = TypeBlock 210 } 211 case fm&os.ModeNamedPipe != 0: 212 h.Typeflag = TypeFifo 213 h.Mode |= c_ISFIFO 214 case fm&os.ModeSocket != 0: 215 h.Mode |= c_ISSOCK 216 default: 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 227 } 228 if sysStat != nil { 229 return h, sysStat(fi, h) 230 } 231 return h, nil 232} 233 234var zeroBlock = make([]byte, blockSize) 235 236// POSIX specifies a sum of the unsigned byte values, but the Sun tar uses signed byte values. 237// We compute and return both. 238func checksum(header []byte) (unsigned int64, signed int64) { 239 for i := 0; i < len(header); i++ { 240 if i == 148 { 241 // The chksum field (header[148:156]) is special: it should be treated as space bytes. 242 unsigned += ' ' * 8 243 signed += ' ' * 8 244 i += 7 245 continue 246 } 247 unsigned += int64(header[i]) 248 signed += int64(int8(header[i])) 249 } 250 return 251} 252 253type slicer []byte 254 255func (sp *slicer) next(n int) (b []byte) { 256 s := *sp 257 b, *sp = s[0:n], s[n:] 258 return 259} 260