github.com/NVIDIA/aistore@v1.3.23-0.20240517131212-7df6609be51d/cmn/archive/fast.go (about)

     1  // Package archive: write, read, copy, append, list primitives
     2  // across all supported formats
     3  /*
     4   * Copyright (c) 2018-2023, NVIDIA CORPORATION. All rights reserved.
     5   */
     6  package archive
     7  
     8  import (
     9  	"archive/tar"
    10  	"fmt"
    11  	"io"
    12  	"os"
    13  
    14  	"github.com/NVIDIA/aistore/cmn/cos"
    15  	"github.com/NVIDIA/aistore/cmn/debug"
    16  )
    17  
    18  // fast.go provides "fast append"
    19  
    20  // Opens TAR and uses its reader's Next() to skip to the position
    21  // right _after_ the last file in the TAR (padding bytes including).
    22  //
    23  // Background:
    24  // TAR file is padded with one or more 512-byte blocks of zero bytes.
    25  // The blocks must be overwritten, otherwise newly added files won't be
    26  // accessible. Different TAR formats (such as `ustar`, `pax` and `GNU`)
    27  // write different number of zero blocks.
    28  func OpenTarSeekEnd(cname, workFQN string) (rwfh *os.File, tarFormat tar.Format, err error) {
    29  	if rwfh, err = os.OpenFile(workFQN, os.O_RDWR, cos.PermRWR); err != nil {
    30  		return
    31  	}
    32  	if tarFormat, err = _seekTarEnd(cname, rwfh); err != nil {
    33  		rwfh.Close() // always close on err
    34  	}
    35  	return
    36  }
    37  
    38  func _seekTarEnd(cname string, fh *os.File) (tarFormat tar.Format, _ error) {
    39  	var (
    40  		twr     = tar.NewReader(fh)
    41  		size    int64
    42  		pos     = int64(-1)
    43  		unknown bool
    44  	)
    45  	for {
    46  		hdr, err := twr.Next()
    47  		if err != nil {
    48  			if err != io.EOF {
    49  				return tarFormat, err // invalid TAR format
    50  			}
    51  			// EOF
    52  			if pos < 0 {
    53  				return tarFormat, ErrTarIsEmpty
    54  			}
    55  			break
    56  		}
    57  		if pos < 0 {
    58  			tarFormat = hdr.Format
    59  		} else if !unknown { // once unknown remains unknown
    60  			if tarFormat != hdr.Format {
    61  				tarFormat = tar.FormatUnknown
    62  				unknown = true
    63  			}
    64  		}
    65  		pos, err = fh.Seek(0, io.SeekCurrent)
    66  		if err != nil {
    67  			debug.AssertNoErr(err) // unlikely
    68  			return tarFormat, err
    69  		}
    70  		size = hdr.Size
    71  	}
    72  	if pos == 0 {
    73  		return tarFormat, fmt.Errorf("failed to seek end of the TAR %s", cname)
    74  	}
    75  	padded := cos.CeilAlignInt64(size, TarBlockSize)
    76  	_, err := fh.Seek(pos+padded, io.SeekStart)
    77  	return tarFormat, err
    78  }