github.com/corona10/go@v0.0.0-20180224231303-7a218942be57/src/archive/tar/writer.go (about)

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