package filestorage import ( "context" "errors" "io" "os" "path/filepath" ) type LocalStorage struct { root string } func NewLocal(root string) *LocalStorage { return &LocalStorage{root: root} } func (l *LocalStorage) Provider() string { return "local" } func (l *LocalStorage) Probe(_ context.Context) error { if err := os.MkdirAll(l.root, 0o755); err != nil { return err } probePath := filepath.Join(l.root, ".healthcheck") file, err := os.OpenFile(probePath, os.O_CREATE|os.O_WRONLY|os.O_TRUNC, 0o644) if err != nil { return err } if err := file.Close(); err != nil { return err } _ = os.Remove(probePath) return nil } func (l *LocalStorage) Put(_ context.Context, key string, reader io.Reader, _ string, _ int64) error { path := filepath.Join(l.root, filepath.Clean(key)) if err := os.MkdirAll(filepath.Dir(path), 0o755); err != nil { return err } file, err := os.Create(path) if err != nil { return err } if _, err := io.Copy(file, reader); err != nil { _ = file.Close() _ = os.Remove(path) return err } return file.Close() } func (l *LocalStorage) Get(_ context.Context, key string) (Object, error) { path := filepath.Join(l.root, filepath.Clean(key)) file, err := os.Open(path) if err != nil { if errors.Is(err, os.ErrNotExist) { return Object{}, ErrNotFound } return Object{}, err } info, err := file.Stat() if err != nil { _ = file.Close() return Object{}, err } if info.IsDir() { _ = file.Close() return Object{}, ErrNotFound } return Object{ Body: file, Size: info.Size(), }, nil } func (l *LocalStorage) Delete(_ context.Context, key string) error { path := filepath.Join(l.root, filepath.Clean(key)) if err := os.Remove(path); err != nil && !errors.Is(err, os.ErrNotExist) { return err } return nil }