From: Matt Joiner Date: Sat, 19 Jul 2025 11:41:18 +0000 (+1000) Subject: Implement io.WriterTo for file storage pieces X-Git-Tag: v1.59.0~8 X-Git-Url: http://www.git.stargrave.org/?a=commitdiff_plain;h=7e994d5ef3191428b130b7ad8f881e8e871d1dbb;p=btrtrc.git Implement io.WriterTo for file storage pieces --- diff --git a/storage/file-piece.go b/storage/file-piece.go index f6c9de96..654ea155 100644 --- a/storage/file-piece.go +++ b/storage/file-piece.go @@ -27,6 +27,7 @@ type filePieceImpl struct { var _ interface { PieceImpl //PieceReaderer + io.WriterTo } = (*filePieceImpl)(nil) func (me *filePieceImpl) logger() *slog.Logger { @@ -85,7 +86,7 @@ func (me *filePieceImpl) iterFileSegments() iter.Seq2[int, segments.Extent] { } } -// If a piece is complete, check consituent files have the minimum required sizes. +// If a piece is complete, check constituent files have the minimum required sizes. func (me *filePieceImpl) checkCompleteFileSizes() (c Completion) { c.Complete = true c.Ok = true @@ -315,6 +316,26 @@ func (me *filePieceImpl) partFiles() bool { return me.t.partFiles() } +func (me *filePieceImpl) WriteTo(w io.Writer) (n int64, err error) { + for fileIndex, extent := range me.iterFileSegments() { + file := me.t.file(fileIndex) + var f *os.File + f, err = me.t.openFile(file) + if err != nil { + return + } + f.Seek(extent.Start, io.SeekStart) + var n1 int64 + n1, err = io.CopyN(w, f, extent.Length) + n += n1 + f.Close() + if err != nil { + return + } + } + return +} + // //// TODO: Just implement StorageReader already. //func (me *filePieceImpl) NewReader() (PieceReader, error) { diff --git a/storage/file-torrent-io.go b/storage/file-torrent-io.go index 107f28e9..c2080b05 100644 --- a/storage/file-torrent-io.go +++ b/storage/file-torrent-io.go @@ -18,17 +18,7 @@ type fileTorrentImplIO struct { // Returns EOF on short or missing file. func (fst fileTorrentImplIO) readFileAt(file file, b []byte, off int64) (n int, err error) { fst.fts.logger().Debug("readFileAt", "file.safeOsPath", file.safeOsPath) - var f sharedFileIf - file.mu.RLock() - // Fine to open once under each name on a unix system. We could make the shared file keys more - // constrained but it shouldn't matter. TODO: Ensure at most one of the names exist. - if fst.fts.partFiles() { - f, err = sharedFiles.Open(file.partFilePath()) - } - if err == nil && f == nil || errors.Is(err, fs.ErrNotExist) { - f, err = sharedFiles.Open(file.safeOsPath) - } - file.mu.RUnlock() + f, err := fst.fts.openSharedFile(file) if errors.Is(err, fs.ErrNotExist) { // File missing is treated the same as a short file. Should we propagate this through the // interface now that fs.ErrNotExist is a thing? diff --git a/storage/file-torrent.go b/storage/file-torrent.go index d3e458ab..55200d4f 100644 --- a/storage/file-torrent.go +++ b/storage/file-torrent.go @@ -125,3 +125,33 @@ func (fts *fileTorrentImpl) file(index int) file { fileExtra: &fts.files[index], } } + +// Open file for reading. +func (me *fileTorrentImpl) openSharedFile(file file) (f sharedFileIf, err error) { + file.mu.RLock() + // Fine to open once under each name on a unix system. We could make the shared file keys more + // constrained, but it shouldn't matter. TODO: Ensure at most one of the names exist. + if me.partFiles() { + f, err = sharedFiles.Open(file.partFilePath()) + } + if err == nil && f == nil || errors.Is(err, fs.ErrNotExist) { + f, err = sharedFiles.Open(file.safeOsPath) + } + file.mu.RUnlock() + return +} + +// Open file for reading. +func (me *fileTorrentImpl) openFile(file file) (f *os.File, err error) { + file.mu.RLock() + // Fine to open once under each name on a unix system. We could make the shared file keys more + // constrained, but it shouldn't matter. TODO: Ensure at most one of the names exist. + if me.partFiles() { + f, err = os.Open(file.partFilePath()) + } + if err == nil && f == nil || errors.Is(err, fs.ErrNotExist) { + f, err = os.Open(file.safeOsPath) + } + file.mu.RUnlock() + return +} diff --git a/storage/iter.go b/storage/iter.go index 9fe49c5e..b889dec1 100644 --- a/storage/iter.go +++ b/storage/iter.go @@ -1,17 +1,2 @@ package storage -import ( - "iter" -) - -func enumIter[T any](i iter.Seq[T]) iter.Seq2[int, T] { - return func(yield func(int, T) bool) { - j := 0 - for t := range i { - if !yield(j, t) { - return - } - j++ - } - } -}