github.com/anacrolix/torrent@v1.61.0/storage/file-misc.go (about)

     1  package storage
     2  
     3  import (
     4  	"io"
     5  	"os"
     6  	"path/filepath"
     7  
     8  	"github.com/anacrolix/sync"
     9  	"github.com/anacrolix/torrent/metainfo"
    10  	"github.com/anacrolix/torrent/segments"
    11  )
    12  
    13  // Returns the minimum file lengths required for the given extent to exist on disk. Returns false if
    14  // the extent is not covered by the files in the index.
    15  func minFileLengthsForTorrentExtent(
    16  	fileSegmentsIndex segments.Index,
    17  	off, n int64,
    18  	each func(fileIndex int, length int64) bool,
    19  ) {
    20  	for fileIndex, segmentBounds := range fileSegmentsIndex.LocateIter(segments.Extent{
    21  		Start:  off,
    22  		Length: n,
    23  	}) {
    24  		if !each(fileIndex, segmentBounds.Start+segmentBounds.Length) {
    25  			return
    26  		}
    27  	}
    28  }
    29  
    30  func fsync(filePath string) (err error) {
    31  	f, err := os.OpenFile(filePath, os.O_WRONLY, filePerm)
    32  	if err != nil {
    33  		return
    34  	}
    35  	defer f.Close()
    36  	if err = f.Sync(); err != nil {
    37  		return err
    38  	}
    39  	return f.Close()
    40  }
    41  
    42  // A helper to create zero-length files which won't appear for file-orientated storage since no
    43  // writes will ever occur to them (no torrent data is associated with a zero-length file). The
    44  // caller should make sure the file name provided is safe/sanitized.
    45  func CreateNativeZeroLengthFile(name string) error {
    46  	os.MkdirAll(filepath.Dir(name), dirPerm)
    47  	var f io.Closer
    48  	// Must request write perms to create and trunc. But we don't need those for a zero-length file.
    49  	f, err := os.OpenFile(name, os.O_RDWR|os.O_CREATE|os.O_TRUNC, filePerm)
    50  	if err != nil {
    51  		stat, statErr := os.Stat(name)
    52  		if statErr == nil && stat.Mode().IsRegular() && stat.Size() == 0 {
    53  			return nil
    54  		}
    55  		return err
    56  	}
    57  	return f.Close()
    58  }
    59  
    60  // Combines data from different locations required to handle files in file storage.
    61  type file struct {
    62  	// Required for piece length.
    63  	*metainfo.Info
    64  	// Enumerated when info is provided.
    65  	*metainfo.FileInfo
    66  	*fileExtra
    67  }
    68  
    69  func (f *file) beginPieceIndex() int {
    70  	return f.FileInfo.BeginPieceIndex(f.Info.PieceLength)
    71  }
    72  
    73  func (f *file) endPieceIndex() int {
    74  	return f.FileInfo.EndPieceIndex(f.Info.PieceLength)
    75  }
    76  
    77  func (f *file) length() int64 {
    78  	return f.FileInfo.Length
    79  }
    80  
    81  func (f *file) torrentOffset() int64 {
    82  	return f.FileInfo.TorrentOffset
    83  }
    84  
    85  // Extra state in the file storage for each file.
    86  type fileExtra struct {
    87  	// This protects high level OS file state like partial file name, permission mod, renaming etc.
    88  	mu sync.RWMutex
    89  	// The safe, OS-local file path.
    90  	safeOsPath string
    91  	// Utility value to help the race detector find issues for us.
    92  	race byte
    93  }
    94  
    95  func (f *fileExtra) partFilePath() string {
    96  	return f.safeOsPath + ".part"
    97  }