common.go 24 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723
  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. //
  6. // Tape archives (tar) are a file format for storing a sequence of files that
  7. // can be read and written in a streaming manner.
  8. // This package aims to cover most variations of the format,
  9. // including those produced by GNU and BSD tar tools.
  10. package tar
  11. import (
  12. "errors"
  13. "fmt"
  14. "math"
  15. "os"
  16. "path"
  17. "reflect"
  18. "strconv"
  19. "strings"
  20. "time"
  21. )
  22. // BUG: Use of the Uid and Gid fields in Header could overflow on 32-bit
  23. // architectures. If a large value is encountered when decoding, the result
  24. // stored in Header will be the truncated version.
  25. var (
  26. ErrHeader = errors.New("archive/tar: invalid tar header")
  27. ErrWriteTooLong = errors.New("archive/tar: write too long")
  28. ErrFieldTooLong = errors.New("archive/tar: header field too long")
  29. ErrWriteAfterClose = errors.New("archive/tar: write after close")
  30. errMissData = errors.New("archive/tar: sparse file references non-existent data")
  31. errUnrefData = errors.New("archive/tar: sparse file contains unreferenced data")
  32. errWriteHole = errors.New("archive/tar: write non-NUL byte in sparse hole")
  33. )
  34. type headerError []string
  35. func (he headerError) Error() string {
  36. const prefix = "archive/tar: cannot encode header"
  37. var ss []string
  38. for _, s := range he {
  39. if s != "" {
  40. ss = append(ss, s)
  41. }
  42. }
  43. if len(ss) == 0 {
  44. return prefix
  45. }
  46. return fmt.Sprintf("%s: %v", prefix, strings.Join(ss, "; and "))
  47. }
  48. // Type flags for Header.Typeflag.
  49. const (
  50. // Type '0' indicates a regular file.
  51. TypeReg = '0'
  52. TypeRegA = '\x00' // Deprecated: Use TypeReg instead.
  53. // Type '1' to '6' are header-only flags and may not have a data body.
  54. TypeLink = '1' // Hard link
  55. TypeSymlink = '2' // Symbolic link
  56. TypeChar = '3' // Character device node
  57. TypeBlock = '4' // Block device node
  58. TypeDir = '5' // Directory
  59. TypeFifo = '6' // FIFO node
  60. // Type '7' is reserved.
  61. TypeCont = '7'
  62. // Type 'x' is used by the PAX format to store key-value records that
  63. // are only relevant to the next file.
  64. // This package transparently handles these types.
  65. TypeXHeader = 'x'
  66. // Type 'g' is used by the PAX format to store key-value records that
  67. // are relevant to all subsequent files.
  68. // This package only supports parsing and composing such headers,
  69. // but does not currently support persisting the global state across files.
  70. TypeXGlobalHeader = 'g'
  71. // Type 'S' indicates a sparse file in the GNU format.
  72. TypeGNUSparse = 'S'
  73. // Types 'L' and 'K' are used by the GNU format for a meta file
  74. // used to store the path or link name for the next file.
  75. // This package transparently handles these types.
  76. TypeGNULongName = 'L'
  77. TypeGNULongLink = 'K'
  78. )
  79. // Keywords for PAX extended header records.
  80. const (
  81. paxNone = "" // Indicates that no PAX key is suitable
  82. paxPath = "path"
  83. paxLinkpath = "linkpath"
  84. paxSize = "size"
  85. paxUid = "uid"
  86. paxGid = "gid"
  87. paxUname = "uname"
  88. paxGname = "gname"
  89. paxMtime = "mtime"
  90. paxAtime = "atime"
  91. paxCtime = "ctime" // Removed from later revision of PAX spec, but was valid
  92. paxCharset = "charset" // Currently unused
  93. paxComment = "comment" // Currently unused
  94. paxSchilyXattr = "SCHILY.xattr."
  95. // Keywords for GNU sparse files in a PAX extended header.
  96. paxGNUSparse = "GNU.sparse."
  97. paxGNUSparseNumBlocks = "GNU.sparse.numblocks"
  98. paxGNUSparseOffset = "GNU.sparse.offset"
  99. paxGNUSparseNumBytes = "GNU.sparse.numbytes"
  100. paxGNUSparseMap = "GNU.sparse.map"
  101. paxGNUSparseName = "GNU.sparse.name"
  102. paxGNUSparseMajor = "GNU.sparse.major"
  103. paxGNUSparseMinor = "GNU.sparse.minor"
  104. paxGNUSparseSize = "GNU.sparse.size"
  105. paxGNUSparseRealSize = "GNU.sparse.realsize"
  106. )
  107. // basicKeys is a set of the PAX keys for which we have built-in support.
  108. // This does not contain "charset" or "comment", which are both PAX-specific,
  109. // so adding them as first-class features of Header is unlikely.
  110. // Users can use the PAXRecords field to set it themselves.
  111. var basicKeys = map[string]bool{
  112. paxPath: true, paxLinkpath: true, paxSize: true, paxUid: true, paxGid: true,
  113. paxUname: true, paxGname: true, paxMtime: true, paxAtime: true, paxCtime: true,
  114. }
  115. // A Header represents a single header in a tar archive.
  116. // Some fields may not be populated.
  117. //
  118. // For forward compatibility, users that retrieve a Header from Reader.Next,
  119. // mutate it in some ways, and then pass it back to Writer.WriteHeader
  120. // should do so by creating a new Header and copying the fields
  121. // that they are interested in preserving.
  122. type Header struct {
  123. // Typeflag is the type of header entry.
  124. // The zero value is automatically promoted to either TypeReg or TypeDir
  125. // depending on the presence of a trailing slash in Name.
  126. Typeflag byte
  127. Name string // Name of file entry
  128. Linkname string // Target name of link (valid for TypeLink or TypeSymlink)
  129. Size int64 // Logical file size in bytes
  130. Mode int64 // Permission and mode bits
  131. Uid int // User ID of owner
  132. Gid int // Group ID of owner
  133. Uname string // User name of owner
  134. Gname string // Group name of owner
  135. // If the Format is unspecified, then Writer.WriteHeader rounds ModTime
  136. // to the nearest second and ignores the AccessTime and ChangeTime fields.
  137. //
  138. // To use AccessTime or ChangeTime, specify the Format as PAX or GNU.
  139. // To use sub-second resolution, specify the Format as PAX.
  140. ModTime time.Time // Modification time
  141. AccessTime time.Time // Access time (requires either PAX or GNU support)
  142. ChangeTime time.Time // Change time (requires either PAX or GNU support)
  143. Devmajor int64 // Major device number (valid for TypeChar or TypeBlock)
  144. Devminor int64 // Minor device number (valid for TypeChar or TypeBlock)
  145. // Xattrs stores extended attributes as PAX records under the
  146. // "SCHILY.xattr." namespace.
  147. //
  148. // The following are semantically equivalent:
  149. // h.Xattrs[key] = value
  150. // h.PAXRecords["SCHILY.xattr."+key] = value
  151. //
  152. // When Writer.WriteHeader is called, the contents of Xattrs will take
  153. // precedence over those in PAXRecords.
  154. //
  155. // Deprecated: Use PAXRecords instead.
  156. Xattrs map[string]string
  157. // PAXRecords is a map of PAX extended header records.
  158. //
  159. // User-defined records should have keys of the following form:
  160. // VENDOR.keyword
  161. // Where VENDOR is some namespace in all uppercase, and keyword may
  162. // not contain the '=' character (e.g., "GOLANG.pkg.version").
  163. // The key and value should be non-empty UTF-8 strings.
  164. //
  165. // When Writer.WriteHeader is called, PAX records derived from the
  166. // other fields in Header take precedence over PAXRecords.
  167. PAXRecords map[string]string
  168. // Format specifies the format of the tar header.
  169. //
  170. // This is set by Reader.Next as a best-effort guess at the format.
  171. // Since the Reader liberally reads some non-compliant files,
  172. // it is possible for this to be FormatUnknown.
  173. //
  174. // If the format is unspecified when Writer.WriteHeader is called,
  175. // then it uses the first format (in the order of USTAR, PAX, GNU)
  176. // capable of encoding this Header (see Format).
  177. Format Format
  178. }
  179. // sparseEntry represents a Length-sized fragment at Offset in the file.
  180. type sparseEntry struct{ Offset, Length int64 }
  181. func (s sparseEntry) endOffset() int64 { return s.Offset + s.Length }
  182. // A sparse file can be represented as either a sparseDatas or a sparseHoles.
  183. // As long as the total size is known, they are equivalent and one can be
  184. // converted to the other form and back. The various tar formats with sparse
  185. // file support represent sparse files in the sparseDatas form. That is, they
  186. // specify the fragments in the file that has data, and treat everything else as
  187. // having zero bytes. As such, the encoding and decoding logic in this package
  188. // deals with sparseDatas.
  189. //
  190. // However, the external API uses sparseHoles instead of sparseDatas because the
  191. // zero value of sparseHoles logically represents a normal file (i.e., there are
  192. // no holes in it). On the other hand, the zero value of sparseDatas implies
  193. // that the file has no data in it, which is rather odd.
  194. //
  195. // As an example, if the underlying raw file contains the 10-byte data:
  196. // var compactFile = "abcdefgh"
  197. //
  198. // And the sparse map has the following entries:
  199. // var spd sparseDatas = []sparseEntry{
  200. // {Offset: 2, Length: 5}, // Data fragment for 2..6
  201. // {Offset: 18, Length: 3}, // Data fragment for 18..20
  202. // }
  203. // var sph sparseHoles = []sparseEntry{
  204. // {Offset: 0, Length: 2}, // Hole fragment for 0..1
  205. // {Offset: 7, Length: 11}, // Hole fragment for 7..17
  206. // {Offset: 21, Length: 4}, // Hole fragment for 21..24
  207. // }
  208. //
  209. // Then the content of the resulting sparse file with a Header.Size of 25 is:
  210. // var sparseFile = "\x00"*2 + "abcde" + "\x00"*11 + "fgh" + "\x00"*4
  211. type (
  212. sparseDatas []sparseEntry
  213. sparseHoles []sparseEntry
  214. )
  215. // validateSparseEntries reports whether sp is a valid sparse map.
  216. // It does not matter whether sp represents data fragments or hole fragments.
  217. func validateSparseEntries(sp []sparseEntry, size int64) bool {
  218. // Validate all sparse entries. These are the same checks as performed by
  219. // the BSD tar utility.
  220. if size < 0 {
  221. return false
  222. }
  223. var pre sparseEntry
  224. for _, cur := range sp {
  225. switch {
  226. case cur.Offset < 0 || cur.Length < 0:
  227. return false // Negative values are never okay
  228. case cur.Offset > math.MaxInt64-cur.Length:
  229. return false // Integer overflow with large length
  230. case cur.endOffset() > size:
  231. return false // Region extends beyond the actual size
  232. case pre.endOffset() > cur.Offset:
  233. return false // Regions cannot overlap and must be in order
  234. }
  235. pre = cur
  236. }
  237. return true
  238. }
  239. // alignSparseEntries mutates src and returns dst where each fragment's
  240. // starting offset is aligned up to the nearest block edge, and each
  241. // ending offset is aligned down to the nearest block edge.
  242. //
  243. // Even though the Go tar Reader and the BSD tar utility can handle entries
  244. // with arbitrary offsets and lengths, the GNU tar utility can only handle
  245. // offsets and lengths that are multiples of blockSize.
  246. func alignSparseEntries(src []sparseEntry, size int64) []sparseEntry {
  247. dst := src[:0]
  248. for _, s := range src {
  249. pos, end := s.Offset, s.endOffset()
  250. pos += blockPadding(+pos) // Round-up to nearest blockSize
  251. if end != size {
  252. end -= blockPadding(-end) // Round-down to nearest blockSize
  253. }
  254. if pos < end {
  255. dst = append(dst, sparseEntry{Offset: pos, Length: end - pos})
  256. }
  257. }
  258. return dst
  259. }
  260. // invertSparseEntries converts a sparse map from one form to the other.
  261. // If the input is sparseHoles, then it will output sparseDatas and vice-versa.
  262. // The input must have been already validated.
  263. //
  264. // This function mutates src and returns a normalized map where:
  265. // * adjacent fragments are coalesced together
  266. // * only the last fragment may be empty
  267. // * the endOffset of the last fragment is the total size
  268. func invertSparseEntries(src []sparseEntry, size int64) []sparseEntry {
  269. dst := src[:0]
  270. var pre sparseEntry
  271. for _, cur := range src {
  272. if cur.Length == 0 {
  273. continue // Skip empty fragments
  274. }
  275. pre.Length = cur.Offset - pre.Offset
  276. if pre.Length > 0 {
  277. dst = append(dst, pre) // Only add non-empty fragments
  278. }
  279. pre.Offset = cur.endOffset()
  280. }
  281. pre.Length = size - pre.Offset // Possibly the only empty fragment
  282. return append(dst, pre)
  283. }
  284. // fileState tracks the number of logical (includes sparse holes) and physical
  285. // (actual in tar archive) bytes remaining for the current file.
  286. //
  287. // Invariant: LogicalRemaining >= PhysicalRemaining
  288. type fileState interface {
  289. LogicalRemaining() int64
  290. PhysicalRemaining() int64
  291. }
  292. // allowedFormats determines which formats can be used.
  293. // The value returned is the logical OR of multiple possible formats.
  294. // If the value is FormatUnknown, then the input Header cannot be encoded
  295. // and an error is returned explaining why.
  296. //
  297. // As a by-product of checking the fields, this function returns paxHdrs, which
  298. // contain all fields that could not be directly encoded.
  299. // A value receiver ensures that this method does not mutate the source Header.
  300. func (h Header) allowedFormats() (format Format, paxHdrs map[string]string, err error) {
  301. format = FormatUSTAR | FormatPAX | FormatGNU
  302. paxHdrs = make(map[string]string)
  303. var whyNoUSTAR, whyNoPAX, whyNoGNU string
  304. var preferPAX bool // Prefer PAX over USTAR
  305. verifyString := func(s string, size int, name, paxKey string) {
  306. // NUL-terminator is optional for path and linkpath.
  307. // Technically, it is required for uname and gname,
  308. // but neither GNU nor BSD tar checks for it.
  309. tooLong := len(s) > size
  310. allowLongGNU := paxKey == paxPath || paxKey == paxLinkpath
  311. if hasNUL(s) || (tooLong && !allowLongGNU) {
  312. whyNoGNU = fmt.Sprintf("GNU cannot encode %s=%q", name, s)
  313. format.mustNotBe(FormatGNU)
  314. }
  315. if !isASCII(s) || tooLong {
  316. canSplitUSTAR := paxKey == paxPath
  317. if _, _, ok := splitUSTARPath(s); !canSplitUSTAR || !ok {
  318. whyNoUSTAR = fmt.Sprintf("USTAR cannot encode %s=%q", name, s)
  319. format.mustNotBe(FormatUSTAR)
  320. }
  321. if paxKey == paxNone {
  322. whyNoPAX = fmt.Sprintf("PAX cannot encode %s=%q", name, s)
  323. format.mustNotBe(FormatPAX)
  324. } else {
  325. paxHdrs[paxKey] = s
  326. }
  327. }
  328. if v, ok := h.PAXRecords[paxKey]; ok && v == s {
  329. paxHdrs[paxKey] = v
  330. }
  331. }
  332. verifyNumeric := func(n int64, size int, name, paxKey string) {
  333. if !fitsInBase256(size, n) {
  334. whyNoGNU = fmt.Sprintf("GNU cannot encode %s=%d", name, n)
  335. format.mustNotBe(FormatGNU)
  336. }
  337. if !fitsInOctal(size, n) {
  338. whyNoUSTAR = fmt.Sprintf("USTAR cannot encode %s=%d", name, n)
  339. format.mustNotBe(FormatUSTAR)
  340. if paxKey == paxNone {
  341. whyNoPAX = fmt.Sprintf("PAX cannot encode %s=%d", name, n)
  342. format.mustNotBe(FormatPAX)
  343. } else {
  344. paxHdrs[paxKey] = strconv.FormatInt(n, 10)
  345. }
  346. }
  347. if v, ok := h.PAXRecords[paxKey]; ok && v == strconv.FormatInt(n, 10) {
  348. paxHdrs[paxKey] = v
  349. }
  350. }
  351. verifyTime := func(ts time.Time, size int, name, paxKey string) {
  352. if ts.IsZero() {
  353. return // Always okay
  354. }
  355. if !fitsInBase256(size, ts.Unix()) {
  356. whyNoGNU = fmt.Sprintf("GNU cannot encode %s=%v", name, ts)
  357. format.mustNotBe(FormatGNU)
  358. }
  359. isMtime := paxKey == paxMtime
  360. fitsOctal := fitsInOctal(size, ts.Unix())
  361. if (isMtime && !fitsOctal) || !isMtime {
  362. whyNoUSTAR = fmt.Sprintf("USTAR cannot encode %s=%v", name, ts)
  363. format.mustNotBe(FormatUSTAR)
  364. }
  365. needsNano := ts.Nanosecond() != 0
  366. if !isMtime || !fitsOctal || needsNano {
  367. preferPAX = true // USTAR may truncate sub-second measurements
  368. if paxKey == paxNone {
  369. whyNoPAX = fmt.Sprintf("PAX cannot encode %s=%v", name, ts)
  370. format.mustNotBe(FormatPAX)
  371. } else {
  372. paxHdrs[paxKey] = formatPAXTime(ts)
  373. }
  374. }
  375. if v, ok := h.PAXRecords[paxKey]; ok && v == formatPAXTime(ts) {
  376. paxHdrs[paxKey] = v
  377. }
  378. }
  379. // Check basic fields.
  380. var blk block
  381. v7 := blk.V7()
  382. ustar := blk.USTAR()
  383. gnu := blk.GNU()
  384. verifyString(h.Name, len(v7.Name()), "Name", paxPath)
  385. verifyString(h.Linkname, len(v7.LinkName()), "Linkname", paxLinkpath)
  386. verifyString(h.Uname, len(ustar.UserName()), "Uname", paxUname)
  387. verifyString(h.Gname, len(ustar.GroupName()), "Gname", paxGname)
  388. verifyNumeric(h.Mode, len(v7.Mode()), "Mode", paxNone)
  389. verifyNumeric(int64(h.Uid), len(v7.UID()), "Uid", paxUid)
  390. verifyNumeric(int64(h.Gid), len(v7.GID()), "Gid", paxGid)
  391. verifyNumeric(h.Size, len(v7.Size()), "Size", paxSize)
  392. verifyNumeric(h.Devmajor, len(ustar.DevMajor()), "Devmajor", paxNone)
  393. verifyNumeric(h.Devminor, len(ustar.DevMinor()), "Devminor", paxNone)
  394. verifyTime(h.ModTime, len(v7.ModTime()), "ModTime", paxMtime)
  395. verifyTime(h.AccessTime, len(gnu.AccessTime()), "AccessTime", paxAtime)
  396. verifyTime(h.ChangeTime, len(gnu.ChangeTime()), "ChangeTime", paxCtime)
  397. // Check for header-only types.
  398. var whyOnlyPAX, whyOnlyGNU string
  399. switch h.Typeflag {
  400. case TypeReg, TypeChar, TypeBlock, TypeFifo, TypeGNUSparse:
  401. // Exclude TypeLink and TypeSymlink, since they may reference directories.
  402. if strings.HasSuffix(h.Name, "/") {
  403. return FormatUnknown, nil, headerError{"filename may not have trailing slash"}
  404. }
  405. case TypeXHeader, TypeGNULongName, TypeGNULongLink:
  406. return FormatUnknown, nil, headerError{"cannot manually encode TypeXHeader, TypeGNULongName, or TypeGNULongLink headers"}
  407. case TypeXGlobalHeader:
  408. h2 := Header{Name: h.Name, Typeflag: h.Typeflag, Xattrs: h.Xattrs, PAXRecords: h.PAXRecords, Format: h.Format}
  409. if !reflect.DeepEqual(h, h2) {
  410. return FormatUnknown, nil, headerError{"only PAXRecords should be set for TypeXGlobalHeader"}
  411. }
  412. whyOnlyPAX = "only PAX supports TypeXGlobalHeader"
  413. format.mayOnlyBe(FormatPAX)
  414. }
  415. if !isHeaderOnlyType(h.Typeflag) && h.Size < 0 {
  416. return FormatUnknown, nil, headerError{"negative size on header-only type"}
  417. }
  418. // Check PAX records.
  419. if len(h.Xattrs) > 0 {
  420. for k, v := range h.Xattrs {
  421. paxHdrs[paxSchilyXattr+k] = v
  422. }
  423. whyOnlyPAX = "only PAX supports Xattrs"
  424. format.mayOnlyBe(FormatPAX)
  425. }
  426. if len(h.PAXRecords) > 0 {
  427. for k, v := range h.PAXRecords {
  428. switch _, exists := paxHdrs[k]; {
  429. case exists:
  430. continue // Do not overwrite existing records
  431. case h.Typeflag == TypeXGlobalHeader:
  432. paxHdrs[k] = v // Copy all records
  433. case !basicKeys[k] && !strings.HasPrefix(k, paxGNUSparse):
  434. paxHdrs[k] = v // Ignore local records that may conflict
  435. }
  436. }
  437. whyOnlyPAX = "only PAX supports PAXRecords"
  438. format.mayOnlyBe(FormatPAX)
  439. }
  440. for k, v := range paxHdrs {
  441. if !validPAXRecord(k, v) {
  442. return FormatUnknown, nil, headerError{fmt.Sprintf("invalid PAX record: %q", k+" = "+v)}
  443. }
  444. }
  445. // TODO(dsnet): Re-enable this when adding sparse support.
  446. // See https://golang.org/issue/22735
  447. /*
  448. // Check sparse files.
  449. if len(h.SparseHoles) > 0 || h.Typeflag == TypeGNUSparse {
  450. if isHeaderOnlyType(h.Typeflag) {
  451. return FormatUnknown, nil, headerError{"header-only type cannot be sparse"}
  452. }
  453. if !validateSparseEntries(h.SparseHoles, h.Size) {
  454. return FormatUnknown, nil, headerError{"invalid sparse holes"}
  455. }
  456. if h.Typeflag == TypeGNUSparse {
  457. whyOnlyGNU = "only GNU supports TypeGNUSparse"
  458. format.mayOnlyBe(FormatGNU)
  459. } else {
  460. whyNoGNU = "GNU supports sparse files only with TypeGNUSparse"
  461. format.mustNotBe(FormatGNU)
  462. }
  463. whyNoUSTAR = "USTAR does not support sparse files"
  464. format.mustNotBe(FormatUSTAR)
  465. }
  466. */
  467. // Check desired format.
  468. if wantFormat := h.Format; wantFormat != FormatUnknown {
  469. if wantFormat.has(FormatPAX) && !preferPAX {
  470. wantFormat.mayBe(FormatUSTAR) // PAX implies USTAR allowed too
  471. }
  472. format.mayOnlyBe(wantFormat) // Set union of formats allowed and format wanted
  473. }
  474. if format == FormatUnknown {
  475. switch h.Format {
  476. case FormatUSTAR:
  477. err = headerError{"Format specifies USTAR", whyNoUSTAR, whyOnlyPAX, whyOnlyGNU}
  478. case FormatPAX:
  479. err = headerError{"Format specifies PAX", whyNoPAX, whyOnlyGNU}
  480. case FormatGNU:
  481. err = headerError{"Format specifies GNU", whyNoGNU, whyOnlyPAX}
  482. default:
  483. err = headerError{whyNoUSTAR, whyNoPAX, whyNoGNU, whyOnlyPAX, whyOnlyGNU}
  484. }
  485. }
  486. return format, paxHdrs, err
  487. }
  488. // FileInfo returns an os.FileInfo for the Header.
  489. func (h *Header) FileInfo() os.FileInfo {
  490. return headerFileInfo{h}
  491. }
  492. // headerFileInfo implements os.FileInfo.
  493. type headerFileInfo struct {
  494. h *Header
  495. }
  496. func (fi headerFileInfo) Size() int64 { return fi.h.Size }
  497. func (fi headerFileInfo) IsDir() bool { return fi.Mode().IsDir() }
  498. func (fi headerFileInfo) ModTime() time.Time { return fi.h.ModTime }
  499. func (fi headerFileInfo) Sys() interface{} { return fi.h }
  500. // Name returns the base name of the file.
  501. func (fi headerFileInfo) Name() string {
  502. if fi.IsDir() {
  503. return path.Base(path.Clean(fi.h.Name))
  504. }
  505. return path.Base(fi.h.Name)
  506. }
  507. // Mode returns the permission and mode bits for the headerFileInfo.
  508. func (fi headerFileInfo) Mode() (mode os.FileMode) {
  509. // Set file permission bits.
  510. mode = os.FileMode(fi.h.Mode).Perm()
  511. // Set setuid, setgid and sticky bits.
  512. if fi.h.Mode&c_ISUID != 0 {
  513. mode |= os.ModeSetuid
  514. }
  515. if fi.h.Mode&c_ISGID != 0 {
  516. mode |= os.ModeSetgid
  517. }
  518. if fi.h.Mode&c_ISVTX != 0 {
  519. mode |= os.ModeSticky
  520. }
  521. // Set file mode bits; clear perm, setuid, setgid, and sticky bits.
  522. switch m := os.FileMode(fi.h.Mode) &^ 07777; m {
  523. case c_ISDIR:
  524. mode |= os.ModeDir
  525. case c_ISFIFO:
  526. mode |= os.ModeNamedPipe
  527. case c_ISLNK:
  528. mode |= os.ModeSymlink
  529. case c_ISBLK:
  530. mode |= os.ModeDevice
  531. case c_ISCHR:
  532. mode |= os.ModeDevice
  533. mode |= os.ModeCharDevice
  534. case c_ISSOCK:
  535. mode |= os.ModeSocket
  536. }
  537. switch fi.h.Typeflag {
  538. case TypeSymlink:
  539. mode |= os.ModeSymlink
  540. case TypeChar:
  541. mode |= os.ModeDevice
  542. mode |= os.ModeCharDevice
  543. case TypeBlock:
  544. mode |= os.ModeDevice
  545. case TypeDir:
  546. mode |= os.ModeDir
  547. case TypeFifo:
  548. mode |= os.ModeNamedPipe
  549. }
  550. return mode
  551. }
  552. // sysStat, if non-nil, populates h from system-dependent fields of fi.
  553. var sysStat func(fi os.FileInfo, h *Header) error
  554. const (
  555. // Mode constants from the USTAR spec:
  556. // See http://pubs.opengroup.org/onlinepubs/9699919799/utilities/pax.html#tag_20_92_13_06
  557. c_ISUID = 04000 // Set uid
  558. c_ISGID = 02000 // Set gid
  559. c_ISVTX = 01000 // Save text (sticky bit)
  560. // Common Unix mode constants; these are not defined in any common tar standard.
  561. // Header.FileInfo understands these, but FileInfoHeader will never produce these.
  562. c_ISDIR = 040000 // Directory
  563. c_ISFIFO = 010000 // FIFO
  564. c_ISREG = 0100000 // Regular file
  565. c_ISLNK = 0120000 // Symbolic link
  566. c_ISBLK = 060000 // Block special file
  567. c_ISCHR = 020000 // Character special file
  568. c_ISSOCK = 0140000 // Socket
  569. )
  570. // FileInfoHeader creates a partially-populated Header from fi.
  571. // If fi describes a symlink, FileInfoHeader records link as the link target.
  572. // If fi describes a directory, a slash is appended to the name.
  573. //
  574. // Since os.FileInfo's Name method only returns the base name of
  575. // the file it describes, it may be necessary to modify Header.Name
  576. // to provide the full path name of the file.
  577. func FileInfoHeader(fi os.FileInfo, link string) (*Header, error) {
  578. if fi == nil {
  579. return nil, errors.New("archive/tar: FileInfo is nil")
  580. }
  581. fm := fi.Mode()
  582. h := &Header{
  583. Name: fi.Name(),
  584. ModTime: fi.ModTime(),
  585. Mode: int64(fm.Perm()), // or'd with c_IS* constants later
  586. }
  587. switch {
  588. case fm.IsRegular():
  589. h.Typeflag = TypeReg
  590. h.Size = fi.Size()
  591. case fi.IsDir():
  592. h.Typeflag = TypeDir
  593. h.Name += "/"
  594. case fm&os.ModeSymlink != 0:
  595. h.Typeflag = TypeSymlink
  596. h.Linkname = link
  597. case fm&os.ModeDevice != 0:
  598. if fm&os.ModeCharDevice != 0 {
  599. h.Typeflag = TypeChar
  600. } else {
  601. h.Typeflag = TypeBlock
  602. }
  603. case fm&os.ModeNamedPipe != 0:
  604. h.Typeflag = TypeFifo
  605. case fm&os.ModeSocket != 0:
  606. return nil, fmt.Errorf("archive/tar: sockets not supported")
  607. default:
  608. return nil, fmt.Errorf("archive/tar: unknown file mode %v", fm)
  609. }
  610. if fm&os.ModeSetuid != 0 {
  611. h.Mode |= c_ISUID
  612. }
  613. if fm&os.ModeSetgid != 0 {
  614. h.Mode |= c_ISGID
  615. }
  616. if fm&os.ModeSticky != 0 {
  617. h.Mode |= c_ISVTX
  618. }
  619. // If possible, populate additional fields from OS-specific
  620. // FileInfo fields.
  621. if sys, ok := fi.Sys().(*Header); ok {
  622. // This FileInfo came from a Header (not the OS). Use the
  623. // original Header to populate all remaining fields.
  624. h.Uid = sys.Uid
  625. h.Gid = sys.Gid
  626. h.Uname = sys.Uname
  627. h.Gname = sys.Gname
  628. h.AccessTime = sys.AccessTime
  629. h.ChangeTime = sys.ChangeTime
  630. if sys.Xattrs != nil {
  631. h.Xattrs = make(map[string]string)
  632. for k, v := range sys.Xattrs {
  633. h.Xattrs[k] = v
  634. }
  635. }
  636. if sys.Typeflag == TypeLink {
  637. // hard link
  638. h.Typeflag = TypeLink
  639. h.Size = 0
  640. h.Linkname = sys.Linkname
  641. }
  642. if sys.PAXRecords != nil {
  643. h.PAXRecords = make(map[string]string)
  644. for k, v := range sys.PAXRecords {
  645. h.PAXRecords[k] = v
  646. }
  647. }
  648. }
  649. if sysStat != nil {
  650. return h, sysStat(fi, h)
  651. }
  652. return h, nil
  653. }
  654. // isHeaderOnlyType checks if the given type flag is of the type that has no
  655. // data section even if a size is specified.
  656. func isHeaderOnlyType(flag byte) bool {
  657. switch flag {
  658. case TypeLink, TypeSymlink, TypeChar, TypeBlock, TypeDir, TypeFifo:
  659. return true
  660. default:
  661. return false
  662. }
  663. }
  664. func min(a, b int64) int64 {
  665. if a < b {
  666. return a
  667. }
  668. return b
  669. }