common.go 8.2 KB

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