local.go

 1package storage
 2
 3import (
 4	"errors"
 5	"io"
 6	"io/fs"
 7	"os"
 8	"path/filepath"
 9	"strings"
10)
11
12// LocalStorage is a storage implementation that stores objects on the local
13// filesystem.
14type LocalStorage struct {
15	root string
16}
17
18var _ Storage = (*LocalStorage)(nil)
19
20// NewLocalStorage creates a new LocalStorage.
21func NewLocalStorage(root string) *LocalStorage {
22	return &LocalStorage{root: root}
23}
24
25// Delete implements Storage.
26func (l *LocalStorage) Delete(name string) error {
27	name = l.fixPath(name)
28	return os.Remove(name)
29}
30
31// Open implements Storage.
32func (l *LocalStorage) Open(name string) (Object, error) {
33	name = l.fixPath(name)
34	return os.Open(name)
35}
36
37// Stat implements Storage.
38func (l *LocalStorage) Stat(name string) (fs.FileInfo, error) {
39	name = l.fixPath(name)
40	return os.Stat(name)
41}
42
43// Put implements Storage.
44func (l *LocalStorage) Put(name string, r io.Reader) (int64, error) {
45	name = l.fixPath(name)
46	if err := os.MkdirAll(filepath.Dir(name), os.ModePerm); err != nil {
47		return 0, err
48	}
49
50	f, err := os.Create(name)
51	if err != nil {
52		return 0, err
53	}
54	defer f.Close()
55	return io.Copy(f, r)
56}
57
58// Exists implements Storage.
59func (l *LocalStorage) Exists(name string) (bool, error) {
60	name = l.fixPath(name)
61	_, err := os.Stat(name)
62	if err == nil {
63		return true, nil
64	}
65	if errors.Is(err, fs.ErrNotExist) {
66		return false, nil
67	}
68	return false, err
69}
70
71// Rename implements Storage.
72func (l *LocalStorage) Rename(oldName, newName string) error {
73	oldName = l.fixPath(oldName)
74	newName = l.fixPath(newName)
75	if err := os.MkdirAll(filepath.Dir(newName), os.ModePerm); err != nil {
76		return err
77	}
78
79	return os.Rename(oldName, newName)
80}
81
82// Replace all slashes with the OS-specific separator.
83func (l LocalStorage) fixPath(path string) string {
84	path = strings.ReplaceAll(path, "/", string(os.PathSeparator))
85	if !filepath.IsAbs(path) {
86		return filepath.Join(l.root, path)
87	}
88
89	return path
90}