github.com/Schaudge/grailbase@v0.0.0-20240223061707-44c758a471c0/ioctx/spliceio/spliceio.go (about) 1 package spliceio 2 3 import ( 4 "context" 5 "os" 6 7 "github.com/Schaudge/grailbase/ioctx/fsctx" 8 ) 9 10 // ReaderAt reads data by giving the caller an OS file descriptor plus coordinates so the 11 // caller can directly splice (or just read) the file descriptor. Concurrent calls are allowed. 12 // 13 // It's possible for gotSize to be less than wantSize with nil error. This is different from 14 // io.ReaderAt. Callers should simply continue their read at off + gotSize. 15 type ReaderAt interface { 16 // SpliceReadAt returns a file descriptor and coordinates, or error. 17 // 18 // Note that fdOff is totally unrelated to off; fdOff must only be used for operations on fd. 19 // No guarantees are made about fd from different calls (no consistency, no uniqueness). 20 // No guarantees are made about fdOff from different calls (no ordering, no uniqueness). 21 SpliceReadAt(_ context.Context, wantSize int, off int64) (fd uintptr, gotSize int, fdOff int64, _ error) 22 } 23 24 // OSFile is a ReaderAt wrapping os.File. It's also a fsctx.File and a 25 // fsnodefuse.Writable. 26 type OSFile os.File 27 28 var ( 29 _ fsctx.File = (*OSFile)(nil) 30 _ ReaderAt = (*OSFile)(nil) 31 ) 32 33 func (f *OSFile) SpliceReadAt( 34 _ context.Context, wantSize int, off int64, 35 ) ( 36 fd uintptr, gotSize int, fdOff int64, _ error, 37 ) { 38 // TODO: Validation? Probably don't need to check file size. Maybe wantSize, off >= 0? 39 return (*os.File)(f).Fd(), wantSize, off, nil 40 } 41 42 func (f *OSFile) Stat(context.Context) (os.FileInfo, error) { return (*os.File)(f).Stat() } 43 func (f *OSFile) Read(_ context.Context, b []byte) (int, error) { return (*os.File)(f).Read(b) } 44 func (f *OSFile) Close(context.Context) error { return (*os.File)(f).Close() } 45 46 func (f *OSFile) WriteAt(_ context.Context, b []byte, offset int64) (int, error) { 47 return (*os.File)(f).WriteAt(b, offset) 48 } 49 func (f *OSFile) Truncate(_ context.Context, size int64) error { return (*os.File)(f).Truncate(size) } 50 func (f *OSFile) Flush(_ context.Context) error { return nil } 51 func (f *OSFile) Fsync(_ context.Context) error { return (*os.File)(f).Sync() }