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 }