diff --git a/internal/fs/file.go b/internal/fs/file.go index fdd9a4a..c7bc714 100644 --- a/internal/fs/file.go +++ b/internal/fs/file.go @@ -1,18 +1,25 @@ package fs import ( + "bytes" + "io" + "io/fs" "log" "os" + "sync" models "github.com/pojntfx/stfs/internal/db/sqlite/models/metadata" "github.com/pojntfx/stfs/pkg/config" "github.com/pojntfx/stfs/pkg/inventory" + "github.com/pojntfx/stfs/pkg/operations" "github.com/spf13/afero" ) type File struct { afero.File + ops *operations.Operations + metadata config.MetadataConfig path string @@ -20,10 +27,15 @@ type File struct { name string info os.FileInfo + reader *io.PipeReader + readerLock sync.Mutex + onHeader func(hdr *models.Header) } func NewFile( + ops *operations.Operations, + metadata config.MetadataConfig, path string, @@ -34,6 +46,8 @@ func NewFile( onHeader func(hdr *models.Header), ) *File { return &File{ + ops: ops, + metadata: metadata, path: path, @@ -45,19 +59,19 @@ func NewFile( } } -func (f File) Name() string { +func (f *File) Name() string { log.Println("File.Name", f.name) return f.name } -func (f File) Stat() (os.FileInfo, error) { +func (f *File) Stat() (os.FileInfo, error) { log.Println("File.Stat", f.name) return f.info, nil } -func (f File) Readdir(count int) ([]os.FileInfo, error) { +func (f *File) Readdir(count int) ([]os.FileInfo, error) { log.Println("File.Readdir", f.name, count) hdrs, err := inventory.List( @@ -80,61 +94,94 @@ func (f File) Readdir(count int) ([]os.FileInfo, error) { return fileInfos, nil } -func (f File) Readdirnames(n int) ([]string, error) { +func (f *File) Readdirnames(n int) ([]string, error) { log.Println("File.Readdirnames", f.name, n) return nil, ErrNotImplemented } -func (f File) Sync() error { +func (f *File) Sync() error { log.Println("File.Sync", f.name) return ErrNotImplemented } -func (f File) Truncate(size int64) error { +func (f *File) Truncate(size int64) error { log.Println("File.Truncate", f.name, size) return ErrNotImplemented } -func (f File) WriteString(s string) (ret int, err error) { +func (f *File) WriteString(s string) (ret int, err error) { log.Println("File.WriteString", f.name, s) return -1, ErrNotImplemented } -func (f File) Close() error { +func (f *File) Close() error { log.Println("File.Close", f.name) return ErrNotImplemented } -func (f File) Read(p []byte) (n int, err error) { - log.Println("File.Read", f.name, p) +func (f *File) Read(p []byte) (n int, err error) { + log.Println("File.Read", f.name, len(p)) - return -1, ErrNotImplemented + f.readerLock.Lock() + defer f.readerLock.Unlock() + + if f.reader == nil { + reader, writer := io.Pipe() + + go func() { + if err := f.ops.Restore( + func(path string, mode fs.FileMode) (io.WriteCloser, error) { + return writer, nil + }, + func(path string, mode fs.FileMode) error { + // Not necessary; can't read on a directory + return nil + }, + + f.path, + "", + true, + ); err != nil { + // TODO: Handle error + panic(err) + } + }() + + f.reader = reader + } + + w := &bytes.Buffer{} + if _, err := io.CopyN(w, f.reader, int64(len(p))); err != nil { + return -1, err + } + + return copy(p, w.Bytes()), nil } -func (f File) ReadAt(p []byte, off int64) (n int, err error) { +func (f *File) ReadAt(p []byte, off int64) (n int, err error) { log.Println("File.ReadAt", f.name, p, off) return -1, ErrNotImplemented } -func (f File) Seek(offset int64, whence int) (int64, error) { +func (f *File) Seek(offset int64, whence int) (int64, error) { log.Println("File.Seek", f.name, offset, whence) return -1, ErrNotImplemented } -func (f File) Write(p []byte) (n int, err error) { +func (f *File) Write(p []byte) (n int, err error) { log.Println("File.Write", f.name, p) return -1, ErrNotImplemented } -func (f File) WriteAt(p []byte, off int64) (n int, err error) { +func (f *File) WriteAt(p []byte, off int64) (n int, err error) { log.Println("File.WriteAt", f.name, p, off) return -1, ErrNotImplemented diff --git a/internal/fs/fileinfo.go b/internal/fs/fileinfo.go index 29b6149..c73268e 100644 --- a/internal/fs/fileinfo.go +++ b/internal/fs/fileinfo.go @@ -28,37 +28,37 @@ func NewFileInfo(hdr *tar.Header) *FileInfo { } } -func (f FileInfo) Name() string { +func (f *FileInfo) Name() string { log.Println("FileInfo.Name", f.name) return f.name } -func (f FileInfo) Size() int64 { +func (f *FileInfo) Size() int64 { log.Println("FileInfo.Size", f.name) return f.size } -func (f FileInfo) Mode() os.FileMode { +func (f *FileInfo) Mode() os.FileMode { log.Println("FileInfo.Mode", f.name) return os.FileMode(f.mode) } -func (f FileInfo) ModTime() time.Time { +func (f *FileInfo) ModTime() time.Time { log.Println("FileInfo.ModTime", f.name) return f.modTime } -func (f FileInfo) IsDir() bool { +func (f *FileInfo) IsDir() bool { log.Println("FileInfo.IsDir", f.name) return f.isDir } -func (f FileInfo) Sys() interface{} { +func (f *FileInfo) Sys() interface{} { log.Println("FileInfo.Sys", f.name) return nil diff --git a/internal/fs/filesystem.go b/internal/fs/filesystem.go index 5cf71c2..e78d702 100644 --- a/internal/fs/filesystem.go +++ b/internal/fs/filesystem.go @@ -86,6 +86,8 @@ func (f *FileSystem) Open(name string) (afero.File, error) { } return NewFile( + f.ops, + f.metadata, hdr.Name,