package s3 import ( "context" "io" "os" "path" "github.com/minio/minio-go/v7" ) type File struct { fs *Fs key string r io.ReadSeekCloser w io.WriteCloser werrc <-chan error cancel context.CancelFunc } // implements io.Closer func (f *File) Close() error { defer f.cancel() if f.r != nil { return f.r.Close() } if f.w != nil { f.w.Close() return <-f.werrc } return nil } // implements io.Reader func (f *File) Read(b []byte) (int, error) { if f.r == nil { return 0, ErrUnsupported } n, err := f.r.Read(b) if err != nil { return n, transformError(err) } return n, nil } // implements io.ReaderAt func (f *File) ReadAt(p []byte, off int64) (int, error) { panic("not implemented") } // implements io.Writer func (f *File) Write(p []byte) (int, error) { if f.w == nil { return 0, ErrUnsupported } n, err := f.w.Write(p) if err != nil { return n, transformError(err) } return n, nil } // implements io.WriterAt func (f *File) WriteAt(p []byte, off int64) (int, error) { panic("not implemented") } func (f *File) Name() string { return path.Base(f.key) } func (f *File) readdir(count int, onlyDir bool) ([]os.FileInfo, error) { if !isDirPath(f.key) { return nil, ErrNotDirectory } if count == 0 { return []os.FileInfo{}, nil } ctx, cancel := f.fs.contextWithTimeout() defer cancel() objectsCh := f.fs.client.ListObjects(ctx, f.fs.bucket, minio.ListObjectsOptions{Prefix: f.key}) n := 0 lastDir := f.key results := make([]os.FileInfo, 0) for objectInfo := range objectsCh { base := path.Base(objectInfo.Key) dir := path.Dir(objectInfo.Key) + "/" if lastDir != dir { lastDir = dir results = append(results, &FileInfo{ name: base, isDir: true, }) if onlyDir { n += 1 } } if !onlyDir { results = append(results, transformObjectInfo(objectInfo)) n += 1 } if n > count { break } } return results, nil } func (f *File) Readdir(count int) ([]os.FileInfo, error) { return f.readdir(count, false) } func (f *File) Readdirnames(n int) ([]string, error) { results, err := f.readdir(n, true) if err != nil { return nil, err } list := make([]string, 0, len(results)) for _, info := range results { list = append(list, info.Name()) } return list, nil } func (f *File) Seek(offset int64, whence int) (int64, error) { if f.r == nil { return 0, ErrUnsupported } return f.r.Seek(offset, whence) } func (f *File) Stat() (os.FileInfo, error) { return f.fs.Stat(f.key) } func (f *File) Sync() error { panic("not implemented") } func (f *File) Truncate(size int64) error { panic("not implemented") } func (f *File) WriteString(s string) (ret int, err error) { return f.Write([]byte(s)) }