writer.go 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653
  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
  5. import (
  6. "fmt"
  7. "io"
  8. "path"
  9. "sort"
  10. "strings"
  11. "time"
  12. )
  13. // Writer provides sequential writing of a tar archive.
  14. // Write.WriteHeader begins a new file with the provided Header,
  15. // and then Writer can be treated as an io.Writer to supply that file's data.
  16. type Writer struct {
  17. w io.Writer
  18. pad int64 // Amount of padding to write after current file entry
  19. curr fileWriter // Writer for current file entry
  20. hdr Header // Shallow copy of Header that is safe for mutations
  21. blk block // Buffer to use as temporary local storage
  22. // err is a persistent error.
  23. // It is only the responsibility of every exported method of Writer to
  24. // ensure that this error is sticky.
  25. err error
  26. }
  27. // NewWriter creates a new Writer writing to w.
  28. func NewWriter(w io.Writer) *Writer {
  29. return &Writer{w: w, curr: &regFileWriter{w, 0}}
  30. }
  31. type fileWriter interface {
  32. io.Writer
  33. fileState
  34. ReadFrom(io.Reader) (int64, error)
  35. }
  36. // Flush finishes writing the current file's block padding.
  37. // The current file must be fully written before Flush can be called.
  38. //
  39. // This is unnecessary as the next call to WriteHeader or Close
  40. // will implicitly flush out the file's padding.
  41. func (tw *Writer) Flush() error {
  42. if tw.err != nil {
  43. return tw.err
  44. }
  45. if nb := tw.curr.LogicalRemaining(); nb > 0 {
  46. return fmt.Errorf("archive/tar: missed writing %d bytes", nb)
  47. }
  48. if _, tw.err = tw.w.Write(zeroBlock[:tw.pad]); tw.err != nil {
  49. return tw.err
  50. }
  51. tw.pad = 0
  52. return nil
  53. }
  54. // WriteHeader writes hdr and prepares to accept the file's contents.
  55. // The Header.Size determines how many bytes can be written for the next file.
  56. // If the current file is not fully written, then this returns an error.
  57. // This implicitly flushes any padding necessary before writing the header.
  58. func (tw *Writer) WriteHeader(hdr *Header) error {
  59. if err := tw.Flush(); err != nil {
  60. return err
  61. }
  62. tw.hdr = *hdr // Shallow copy of Header
  63. // Avoid usage of the legacy TypeRegA flag, and automatically promote
  64. // it to use TypeReg or TypeDir.
  65. if tw.hdr.Typeflag == TypeRegA {
  66. if strings.HasSuffix(tw.hdr.Name, "/") {
  67. tw.hdr.Typeflag = TypeDir
  68. } else {
  69. tw.hdr.Typeflag = TypeReg
  70. }
  71. }
  72. // Round ModTime and ignore AccessTime and ChangeTime unless
  73. // the format is explicitly chosen.
  74. // This ensures nominal usage of WriteHeader (without specifying the format)
  75. // does not always result in the PAX format being chosen, which
  76. // causes a 1KiB increase to every header.
  77. if tw.hdr.Format == FormatUnknown {
  78. tw.hdr.ModTime = tw.hdr.ModTime.Round(time.Second)
  79. tw.hdr.AccessTime = time.Time{}
  80. tw.hdr.ChangeTime = time.Time{}
  81. }
  82. allowedFormats, paxHdrs, err := tw.hdr.allowedFormats()
  83. switch {
  84. case allowedFormats.has(FormatUSTAR):
  85. tw.err = tw.writeUSTARHeader(&tw.hdr)
  86. return tw.err
  87. case allowedFormats.has(FormatPAX):
  88. tw.err = tw.writePAXHeader(&tw.hdr, paxHdrs)
  89. return tw.err
  90. case allowedFormats.has(FormatGNU):
  91. tw.err = tw.writeGNUHeader(&tw.hdr)
  92. return tw.err
  93. default:
  94. return err // Non-fatal error
  95. }
  96. }
  97. func (tw *Writer) writeUSTARHeader(hdr *Header) error {
  98. // Check if we can use USTAR prefix/suffix splitting.
  99. var namePrefix string
  100. if prefix, suffix, ok := splitUSTARPath(hdr.Name); ok {
  101. namePrefix, hdr.Name = prefix, suffix
  102. }
  103. // Pack the main header.
  104. var f formatter
  105. blk := tw.templateV7Plus(hdr, f.formatString, f.formatOctal)
  106. f.formatString(blk.USTAR().Prefix(), namePrefix)
  107. blk.SetFormat(FormatUSTAR)
  108. if f.err != nil {
  109. return f.err // Should never happen since header is validated
  110. }
  111. return tw.writeRawHeader(blk, hdr.Size, hdr.Typeflag)
  112. }
  113. func (tw *Writer) writePAXHeader(hdr *Header, paxHdrs map[string]string) error {
  114. realName, realSize := hdr.Name, hdr.Size
  115. // TODO(dsnet): Re-enable this when adding sparse support.
  116. // See https://golang.org/issue/22735
  117. /*
  118. // Handle sparse files.
  119. var spd sparseDatas
  120. var spb []byte
  121. if len(hdr.SparseHoles) > 0 {
  122. sph := append([]sparseEntry{}, hdr.SparseHoles...) // Copy sparse map
  123. sph = alignSparseEntries(sph, hdr.Size)
  124. spd = invertSparseEntries(sph, hdr.Size)
  125. // Format the sparse map.
  126. hdr.Size = 0 // Replace with encoded size
  127. spb = append(strconv.AppendInt(spb, int64(len(spd)), 10), '\n')
  128. for _, s := range spd {
  129. hdr.Size += s.Length
  130. spb = append(strconv.AppendInt(spb, s.Offset, 10), '\n')
  131. spb = append(strconv.AppendInt(spb, s.Length, 10), '\n')
  132. }
  133. pad := blockPadding(int64(len(spb)))
  134. spb = append(spb, zeroBlock[:pad]...)
  135. hdr.Size += int64(len(spb)) // Accounts for encoded sparse map
  136. // Add and modify appropriate PAX records.
  137. dir, file := path.Split(realName)
  138. hdr.Name = path.Join(dir, "GNUSparseFile.0", file)
  139. paxHdrs[paxGNUSparseMajor] = "1"
  140. paxHdrs[paxGNUSparseMinor] = "0"
  141. paxHdrs[paxGNUSparseName] = realName
  142. paxHdrs[paxGNUSparseRealSize] = strconv.FormatInt(realSize, 10)
  143. paxHdrs[paxSize] = strconv.FormatInt(hdr.Size, 10)
  144. delete(paxHdrs, paxPath) // Recorded by paxGNUSparseName
  145. }
  146. */
  147. _ = realSize
  148. // Write PAX records to the output.
  149. isGlobal := hdr.Typeflag == TypeXGlobalHeader
  150. if len(paxHdrs) > 0 || isGlobal {
  151. // Sort keys for deterministic ordering.
  152. var keys []string
  153. for k := range paxHdrs {
  154. keys = append(keys, k)
  155. }
  156. sort.Strings(keys)
  157. // Write each record to a buffer.
  158. var buf strings.Builder
  159. for _, k := range keys {
  160. rec, err := formatPAXRecord(k, paxHdrs[k])
  161. if err != nil {
  162. return err
  163. }
  164. buf.WriteString(rec)
  165. }
  166. // Write the extended header file.
  167. var name string
  168. var flag byte
  169. if isGlobal {
  170. name = realName
  171. if name == "" {
  172. name = "GlobalHead.0.0"
  173. }
  174. flag = TypeXGlobalHeader
  175. } else {
  176. dir, file := path.Split(realName)
  177. name = path.Join(dir, "PaxHeaders.0", file)
  178. flag = TypeXHeader
  179. }
  180. data := buf.String()
  181. if err := tw.writeRawFile(name, data, flag, FormatPAX); err != nil || isGlobal {
  182. return err // Global headers return here
  183. }
  184. }
  185. // Pack the main header.
  186. var f formatter // Ignore errors since they are expected
  187. fmtStr := func(b []byte, s string) { f.formatString(b, toASCII(s)) }
  188. blk := tw.templateV7Plus(hdr, fmtStr, f.formatOctal)
  189. blk.SetFormat(FormatPAX)
  190. if err := tw.writeRawHeader(blk, hdr.Size, hdr.Typeflag); err != nil {
  191. return err
  192. }
  193. // TODO(dsnet): Re-enable this when adding sparse support.
  194. // See https://golang.org/issue/22735
  195. /*
  196. // Write the sparse map and setup the sparse writer if necessary.
  197. if len(spd) > 0 {
  198. // Use tw.curr since the sparse map is accounted for in hdr.Size.
  199. if _, err := tw.curr.Write(spb); err != nil {
  200. return err
  201. }
  202. tw.curr = &sparseFileWriter{tw.curr, spd, 0}
  203. }
  204. */
  205. return nil
  206. }
  207. func (tw *Writer) writeGNUHeader(hdr *Header) error {
  208. // Use long-link files if Name or Linkname exceeds the field size.
  209. const longName = "././@LongLink"
  210. if len(hdr.Name) > nameSize {
  211. data := hdr.Name + "\x00"
  212. if err := tw.writeRawFile(longName, data, TypeGNULongName, FormatGNU); err != nil {
  213. return err
  214. }
  215. }
  216. if len(hdr.Linkname) > nameSize {
  217. data := hdr.Linkname + "\x00"
  218. if err := tw.writeRawFile(longName, data, TypeGNULongLink, FormatGNU); err != nil {
  219. return err
  220. }
  221. }
  222. // Pack the main header.
  223. var f formatter // Ignore errors since they are expected
  224. var spd sparseDatas
  225. var spb []byte
  226. blk := tw.templateV7Plus(hdr, f.formatString, f.formatNumeric)
  227. if !hdr.AccessTime.IsZero() {
  228. f.formatNumeric(blk.GNU().AccessTime(), hdr.AccessTime.Unix())
  229. }
  230. if !hdr.ChangeTime.IsZero() {
  231. f.formatNumeric(blk.GNU().ChangeTime(), hdr.ChangeTime.Unix())
  232. }
  233. // TODO(dsnet): Re-enable this when adding sparse support.
  234. // See https://golang.org/issue/22735
  235. /*
  236. if hdr.Typeflag == TypeGNUSparse {
  237. sph := append([]sparseEntry{}, hdr.SparseHoles...) // Copy sparse map
  238. sph = alignSparseEntries(sph, hdr.Size)
  239. spd = invertSparseEntries(sph, hdr.Size)
  240. // Format the sparse map.
  241. formatSPD := func(sp sparseDatas, sa sparseArray) sparseDatas {
  242. for i := 0; len(sp) > 0 && i < sa.MaxEntries(); i++ {
  243. f.formatNumeric(sa.Entry(i).Offset(), sp[0].Offset)
  244. f.formatNumeric(sa.Entry(i).Length(), sp[0].Length)
  245. sp = sp[1:]
  246. }
  247. if len(sp) > 0 {
  248. sa.IsExtended()[0] = 1
  249. }
  250. return sp
  251. }
  252. sp2 := formatSPD(spd, blk.GNU().Sparse())
  253. for len(sp2) > 0 {
  254. var spHdr block
  255. sp2 = formatSPD(sp2, spHdr.Sparse())
  256. spb = append(spb, spHdr[:]...)
  257. }
  258. // Update size fields in the header block.
  259. realSize := hdr.Size
  260. hdr.Size = 0 // Encoded size; does not account for encoded sparse map
  261. for _, s := range spd {
  262. hdr.Size += s.Length
  263. }
  264. copy(blk.V7().Size(), zeroBlock[:]) // Reset field
  265. f.formatNumeric(blk.V7().Size(), hdr.Size)
  266. f.formatNumeric(blk.GNU().RealSize(), realSize)
  267. }
  268. */
  269. blk.SetFormat(FormatGNU)
  270. if err := tw.writeRawHeader(blk, hdr.Size, hdr.Typeflag); err != nil {
  271. return err
  272. }
  273. // Write the extended sparse map and setup the sparse writer if necessary.
  274. if len(spd) > 0 {
  275. // Use tw.w since the sparse map is not accounted for in hdr.Size.
  276. if _, err := tw.w.Write(spb); err != nil {
  277. return err
  278. }
  279. tw.curr = &sparseFileWriter{tw.curr, spd, 0}
  280. }
  281. return nil
  282. }
  283. type (
  284. stringFormatter func([]byte, string)
  285. numberFormatter func([]byte, int64)
  286. )
  287. // templateV7Plus fills out the V7 fields of a block using values from hdr.
  288. // It also fills out fields (uname, gname, devmajor, devminor) that are
  289. // shared in the USTAR, PAX, and GNU formats using the provided formatters.
  290. //
  291. // The block returned is only valid until the next call to
  292. // templateV7Plus or writeRawFile.
  293. func (tw *Writer) templateV7Plus(hdr *Header, fmtStr stringFormatter, fmtNum numberFormatter) *block {
  294. tw.blk.Reset()
  295. modTime := hdr.ModTime
  296. if modTime.IsZero() {
  297. modTime = time.Unix(0, 0)
  298. }
  299. v7 := tw.blk.V7()
  300. v7.TypeFlag()[0] = hdr.Typeflag
  301. fmtStr(v7.Name(), hdr.Name)
  302. fmtStr(v7.LinkName(), hdr.Linkname)
  303. fmtNum(v7.Mode(), hdr.Mode)
  304. fmtNum(v7.UID(), int64(hdr.Uid))
  305. fmtNum(v7.GID(), int64(hdr.Gid))
  306. fmtNum(v7.Size(), hdr.Size)
  307. fmtNum(v7.ModTime(), modTime.Unix())
  308. ustar := tw.blk.USTAR()
  309. fmtStr(ustar.UserName(), hdr.Uname)
  310. fmtStr(ustar.GroupName(), hdr.Gname)
  311. fmtNum(ustar.DevMajor(), hdr.Devmajor)
  312. fmtNum(ustar.DevMinor(), hdr.Devminor)
  313. return &tw.blk
  314. }
  315. // writeRawFile writes a minimal file with the given name and flag type.
  316. // It uses format to encode the header format and will write data as the body.
  317. // It uses default values for all of the other fields (as BSD and GNU tar does).
  318. func (tw *Writer) writeRawFile(name, data string, flag byte, format Format) error {
  319. tw.blk.Reset()
  320. // Best effort for the filename.
  321. name = toASCII(name)
  322. if len(name) > nameSize {
  323. name = name[:nameSize]
  324. }
  325. name = strings.TrimRight(name, "/")
  326. var f formatter
  327. v7 := tw.blk.V7()
  328. v7.TypeFlag()[0] = flag
  329. f.formatString(v7.Name(), name)
  330. f.formatOctal(v7.Mode(), 0)
  331. f.formatOctal(v7.UID(), 0)
  332. f.formatOctal(v7.GID(), 0)
  333. f.formatOctal(v7.Size(), int64(len(data))) // Must be < 8GiB
  334. f.formatOctal(v7.ModTime(), 0)
  335. tw.blk.SetFormat(format)
  336. if f.err != nil {
  337. return f.err // Only occurs if size condition is violated
  338. }
  339. // Write the header and data.
  340. if err := tw.writeRawHeader(&tw.blk, int64(len(data)), flag); err != nil {
  341. return err
  342. }
  343. _, err := io.WriteString(tw, data)
  344. return err
  345. }
  346. // writeRawHeader writes the value of blk, regardless of its value.
  347. // It sets up the Writer such that it can accept a file of the given size.
  348. // If the flag is a special header-only flag, then the size is treated as zero.
  349. func (tw *Writer) writeRawHeader(blk *block, size int64, flag byte) error {
  350. if err := tw.Flush(); err != nil {
  351. return err
  352. }
  353. if _, err := tw.w.Write(blk[:]); err != nil {
  354. return err
  355. }
  356. if isHeaderOnlyType(flag) {
  357. size = 0
  358. }
  359. tw.curr = &regFileWriter{tw.w, size}
  360. tw.pad = blockPadding(size)
  361. return nil
  362. }
  363. // splitUSTARPath splits a path according to USTAR prefix and suffix rules.
  364. // If the path is not splittable, then it will return ("", "", false).
  365. func splitUSTARPath(name string) (prefix, suffix string, ok bool) {
  366. length := len(name)
  367. if length <= nameSize || !isASCII(name) {
  368. return "", "", false
  369. } else if length > prefixSize+1 {
  370. length = prefixSize + 1
  371. } else if name[length-1] == '/' {
  372. length--
  373. }
  374. i := strings.LastIndex(name[:length], "/")
  375. nlen := len(name) - i - 1 // nlen is length of suffix
  376. plen := i // plen is length of prefix
  377. if i <= 0 || nlen > nameSize || nlen == 0 || plen > prefixSize {
  378. return "", "", false
  379. }
  380. return name[:i], name[i+1:], true
  381. }
  382. // Write writes to the current file in the tar archive.
  383. // Write returns the error ErrWriteTooLong if more than
  384. // Header.Size bytes are written after WriteHeader.
  385. //
  386. // Calling Write on special types like TypeLink, TypeSymlink, TypeChar,
  387. // TypeBlock, TypeDir, and TypeFifo returns (0, ErrWriteTooLong) regardless
  388. // of what the Header.Size claims.
  389. func (tw *Writer) Write(b []byte) (int, error) {
  390. if tw.err != nil {
  391. return 0, tw.err
  392. }
  393. n, err := tw.curr.Write(b)
  394. if err != nil && err != ErrWriteTooLong {
  395. tw.err = err
  396. }
  397. return n, err
  398. }
  399. // readFrom populates the content of the current file by reading from r.
  400. // The bytes read must match the number of remaining bytes in the current file.
  401. //
  402. // If the current file is sparse and r is an io.ReadSeeker,
  403. // then readFrom uses Seek to skip past holes defined in Header.SparseHoles,
  404. // assuming that skipped regions are all NULs.
  405. // This always reads the last byte to ensure r is the right size.
  406. //
  407. // TODO(dsnet): Re-export this when adding sparse file support.
  408. // See https://golang.org/issue/22735
  409. func (tw *Writer) readFrom(r io.Reader) (int64, error) {
  410. if tw.err != nil {
  411. return 0, tw.err
  412. }
  413. n, err := tw.curr.ReadFrom(r)
  414. if err != nil && err != ErrWriteTooLong {
  415. tw.err = err
  416. }
  417. return n, err
  418. }
  419. // Close closes the tar archive by flushing the padding, and writing the footer.
  420. // If the current file (from a prior call to WriteHeader) is not fully written,
  421. // then this returns an error.
  422. func (tw *Writer) Close() error {
  423. if tw.err == ErrWriteAfterClose {
  424. return nil
  425. }
  426. if tw.err != nil {
  427. return tw.err
  428. }
  429. // Trailer: two zero blocks.
  430. err := tw.Flush()
  431. for i := 0; i < 2 && err == nil; i++ {
  432. _, err = tw.w.Write(zeroBlock[:])
  433. }
  434. // Ensure all future actions are invalid.
  435. tw.err = ErrWriteAfterClose
  436. return err // Report IO errors
  437. }
  438. // regFileWriter is a fileWriter for writing data to a regular file entry.
  439. type regFileWriter struct {
  440. w io.Writer // Underlying Writer
  441. nb int64 // Number of remaining bytes to write
  442. }
  443. func (fw *regFileWriter) Write(b []byte) (n int, err error) {
  444. overwrite := int64(len(b)) > fw.nb
  445. if overwrite {
  446. b = b[:fw.nb]
  447. }
  448. if len(b) > 0 {
  449. n, err = fw.w.Write(b)
  450. fw.nb -= int64(n)
  451. }
  452. switch {
  453. case err != nil:
  454. return n, err
  455. case overwrite:
  456. return n, ErrWriteTooLong
  457. default:
  458. return n, nil
  459. }
  460. }
  461. func (fw *regFileWriter) ReadFrom(r io.Reader) (int64, error) {
  462. return io.Copy(struct{ io.Writer }{fw}, r)
  463. }
  464. func (fw regFileWriter) LogicalRemaining() int64 {
  465. return fw.nb
  466. }
  467. func (fw regFileWriter) PhysicalRemaining() int64 {
  468. return fw.nb
  469. }
  470. // sparseFileWriter is a fileWriter for writing data to a sparse file entry.
  471. type sparseFileWriter struct {
  472. fw fileWriter // Underlying fileWriter
  473. sp sparseDatas // Normalized list of data fragments
  474. pos int64 // Current position in sparse file
  475. }
  476. func (sw *sparseFileWriter) Write(b []byte) (n int, err error) {
  477. overwrite := int64(len(b)) > sw.LogicalRemaining()
  478. if overwrite {
  479. b = b[:sw.LogicalRemaining()]
  480. }
  481. b0 := b
  482. endPos := sw.pos + int64(len(b))
  483. for endPos > sw.pos && err == nil {
  484. var nf int // Bytes written in fragment
  485. dataStart, dataEnd := sw.sp[0].Offset, sw.sp[0].endOffset()
  486. if sw.pos < dataStart { // In a hole fragment
  487. bf := b[:min(int64(len(b)), dataStart-sw.pos)]
  488. nf, err = zeroWriter{}.Write(bf)
  489. } else { // In a data fragment
  490. bf := b[:min(int64(len(b)), dataEnd-sw.pos)]
  491. nf, err = sw.fw.Write(bf)
  492. }
  493. b = b[nf:]
  494. sw.pos += int64(nf)
  495. if sw.pos >= dataEnd && len(sw.sp) > 1 {
  496. sw.sp = sw.sp[1:] // Ensure last fragment always remains
  497. }
  498. }
  499. n = len(b0) - len(b)
  500. switch {
  501. case err == ErrWriteTooLong:
  502. return n, errMissData // Not possible; implies bug in validation logic
  503. case err != nil:
  504. return n, err
  505. case sw.LogicalRemaining() == 0 && sw.PhysicalRemaining() > 0:
  506. return n, errUnrefData // Not possible; implies bug in validation logic
  507. case overwrite:
  508. return n, ErrWriteTooLong
  509. default:
  510. return n, nil
  511. }
  512. }
  513. func (sw *sparseFileWriter) ReadFrom(r io.Reader) (n int64, err error) {
  514. rs, ok := r.(io.ReadSeeker)
  515. if ok {
  516. if _, err := rs.Seek(0, io.SeekCurrent); err != nil {
  517. ok = false // Not all io.Seeker can really seek
  518. }
  519. }
  520. if !ok {
  521. return io.Copy(struct{ io.Writer }{sw}, r)
  522. }
  523. var readLastByte bool
  524. pos0 := sw.pos
  525. for sw.LogicalRemaining() > 0 && !readLastByte && err == nil {
  526. var nf int64 // Size of fragment
  527. dataStart, dataEnd := sw.sp[0].Offset, sw.sp[0].endOffset()
  528. if sw.pos < dataStart { // In a hole fragment
  529. nf = dataStart - sw.pos
  530. if sw.PhysicalRemaining() == 0 {
  531. readLastByte = true
  532. nf--
  533. }
  534. _, err = rs.Seek(nf, io.SeekCurrent)
  535. } else { // In a data fragment
  536. nf = dataEnd - sw.pos
  537. nf, err = io.CopyN(sw.fw, rs, nf)
  538. }
  539. sw.pos += nf
  540. if sw.pos >= dataEnd && len(sw.sp) > 1 {
  541. sw.sp = sw.sp[1:] // Ensure last fragment always remains
  542. }
  543. }
  544. // If the last fragment is a hole, then seek to 1-byte before EOF, and
  545. // read a single byte to ensure the file is the right size.
  546. if readLastByte && err == nil {
  547. _, err = mustReadFull(rs, []byte{0})
  548. sw.pos++
  549. }
  550. n = sw.pos - pos0
  551. switch {
  552. case err == io.EOF:
  553. return n, io.ErrUnexpectedEOF
  554. case err == ErrWriteTooLong:
  555. return n, errMissData // Not possible; implies bug in validation logic
  556. case err != nil:
  557. return n, err
  558. case sw.LogicalRemaining() == 0 && sw.PhysicalRemaining() > 0:
  559. return n, errUnrefData // Not possible; implies bug in validation logic
  560. default:
  561. return n, ensureEOF(rs)
  562. }
  563. }
  564. func (sw sparseFileWriter) LogicalRemaining() int64 {
  565. return sw.sp[len(sw.sp)-1].endOffset() - sw.pos
  566. }
  567. func (sw sparseFileWriter) PhysicalRemaining() int64 {
  568. return sw.fw.PhysicalRemaining()
  569. }
  570. // zeroWriter may only be written with NULs, otherwise it returns errWriteHole.
  571. type zeroWriter struct{}
  572. func (zeroWriter) Write(b []byte) (int, error) {
  573. for i, c := range b {
  574. if c != 0 {
  575. return i, errWriteHole
  576. }
  577. }
  578. return len(b), nil
  579. }
  580. // ensureEOF checks whether r is at EOF, reporting ErrWriteTooLong if not so.
  581. func ensureEOF(r io.Reader) error {
  582. n, err := tryReadFull(r, []byte{0})
  583. switch {
  584. case n > 0:
  585. return ErrWriteTooLong
  586. case err == io.EOF:
  587. return nil
  588. default:
  589. return err
  590. }
  591. }