common.go 8.7 KB

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