Remove the FS thing and use normal paths
This commit is contained in:
parent
b87f3445e4
commit
a5f7feb5eb
198
path.go
198
path.go
@ -1,190 +1,32 @@
|
|||||||
package nasin
|
package nasin
|
||||||
|
|
||||||
import "io"
|
|
||||||
import "os"
|
import "os"
|
||||||
import "io/fs"
|
|
||||||
import "strings"
|
|
||||||
import "path/filepath"
|
import "path/filepath"
|
||||||
|
|
||||||
// FS is Tomo's implementation of fs.FS. It provides access to a specific part
|
// ApplicationUserDataDir returns the directory path where an application can
|
||||||
// of the filesystem.
|
// store its user data files. If the directory does not exist, it will be
|
||||||
type FS struct {
|
// created.
|
||||||
path string
|
func ApplicationUserDataDir (app ApplicationDescription) (string, error) {
|
||||||
|
return userMkdirAll(app.ID, userDataDir)
|
||||||
}
|
}
|
||||||
|
|
||||||
// FileWriter is a writable version of fs.File.
|
// ApplicationUserConfigDir returns the directory path where an application can
|
||||||
type FileWriter interface {
|
// store its user configuration files.
|
||||||
fs.File
|
func ApplicationUserConfigDir (app ApplicationDescription) (string, error) {
|
||||||
io.Writer
|
return userMkdirAll(app.ID, userConfigDir)
|
||||||
}
|
}
|
||||||
|
|
||||||
// ApplicationUserDataFS returns an FS that an application can use to store user
|
// ApplicationUserCacheDir returns the directory path where an application can
|
||||||
// data files.
|
// store its user cache files.
|
||||||
func ApplicationUserDataFS (app ApplicationDescription) (*FS, error) {
|
func ApplicationUserCacheDir (app ApplicationDescription) (string, error) {
|
||||||
dataDir, err := userDataDir()
|
return userMkdirAll(app.ID, userCacheDir)
|
||||||
if err != nil { return nil, err }
|
|
||||||
return appFs(dataDir, app)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// ApplicationUserConfigFS returns an FS that an application can use to store
|
func userMkdirAll (sub string, getter func () (string, error)) (string, error) {
|
||||||
// user configuration files.
|
path, err := getter()
|
||||||
func ApplicationUserConfigFS (app ApplicationDescription) (*FS, error) {
|
if err != nil { return "", err }
|
||||||
configDir, err := userConfigDir()
|
path = filepath.Join(path, sub)
|
||||||
if err != nil { return nil, err }
|
err = os.MkdirAll(path, 0700)
|
||||||
return appFs(configDir, app)
|
if err != nil { return "", err }
|
||||||
}
|
return path, nil
|
||||||
|
|
||||||
// ApplicationUserCacheFS returns an FS that an application can use to store
|
|
||||||
// user cache files.
|
|
||||||
func ApplicationUserCacheFS (app ApplicationDescription) (*FS, error) {
|
|
||||||
cacheDir, err := userCacheDir()
|
|
||||||
if err != nil { return nil, err }
|
|
||||||
return appFs(cacheDir, app)
|
|
||||||
}
|
|
||||||
|
|
||||||
func pathErr (op, path string, err error) error {
|
|
||||||
return &fs.PathError {
|
|
||||||
Op: op,
|
|
||||||
Path: path,
|
|
||||||
Err: err,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func appFs (root string, app ApplicationDescription) (*FS, error) {
|
|
||||||
// remove slashes
|
|
||||||
appid := app.ID
|
|
||||||
appid = strings.ReplaceAll(appid, "/", "-")
|
|
||||||
appid = strings.ReplaceAll(appid, "\\", "-")
|
|
||||||
|
|
||||||
path := filepath.Join(root, appid)
|
|
||||||
|
|
||||||
// ensure the directory actually exists
|
|
||||||
err := os.MkdirAll(path, 700)
|
|
||||||
if err != nil { return nil, err }
|
|
||||||
|
|
||||||
return &FS { path: path }, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (this FS) subPath (name string) (string, error) {
|
|
||||||
if !fs.ValidPath(name) { return "", fs.ErrInvalid }
|
|
||||||
if strings.Contains(name, "/") { return "", fs.ErrInvalid }
|
|
||||||
return filepath.Join(this.path, name), nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// Open opens the named file.
|
|
||||||
func (this FS) Open (name string) (fs.File, error) {
|
|
||||||
path, err := this.subPath(name)
|
|
||||||
if err != nil {
|
|
||||||
return nil, pathErr("open", name, err)
|
|
||||||
}
|
|
||||||
|
|
||||||
return os.Open(path)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Create creates or truncates the named file.
|
|
||||||
func (this FS) Create (name string) (FileWriter, error) {
|
|
||||||
path, err := this.subPath(name)
|
|
||||||
if err != nil {
|
|
||||||
return nil, pathErr("create", name, err)
|
|
||||||
}
|
|
||||||
|
|
||||||
return os.Create(path)
|
|
||||||
}
|
|
||||||
|
|
||||||
// OpenFile is the generalized open call; most users will use Open or Create
|
|
||||||
// instead.
|
|
||||||
func (this FS) OpenFile (
|
|
||||||
name string,
|
|
||||||
flag int,
|
|
||||||
perm os.FileMode,
|
|
||||||
) (
|
|
||||||
FileWriter,
|
|
||||||
error,
|
|
||||||
) {
|
|
||||||
path, err := this.subPath(name)
|
|
||||||
if err != nil {
|
|
||||||
return nil, pathErr("open", name, err)
|
|
||||||
}
|
|
||||||
|
|
||||||
return os.OpenFile(path, flag, perm)
|
|
||||||
}
|
|
||||||
|
|
||||||
// ReadDir reads the named directory and returns a list of directory entries
|
|
||||||
// sorted by filename.
|
|
||||||
func (this FS) ReadDir (name string) ([]fs.DirEntry, error) {
|
|
||||||
path, err := this.subPath(name)
|
|
||||||
if err != nil {
|
|
||||||
return nil, pathErr("readdir", name, err)
|
|
||||||
}
|
|
||||||
|
|
||||||
return os.ReadDir(path)
|
|
||||||
}
|
|
||||||
|
|
||||||
// ReadFile reads the named file and returns its contents.
|
|
||||||
// A successful call returns a nil error, not io.EOF.
|
|
||||||
// (Because ReadFile reads the whole file, the expected EOF
|
|
||||||
// from the final Read is not treated as an error to be reported.)
|
|
||||||
//
|
|
||||||
// The caller is permitted to modify the returned byte slice.
|
|
||||||
func (this FS) ReadFile (name string) ([]byte, error) {
|
|
||||||
path, err := this.subPath(name)
|
|
||||||
if err != nil {
|
|
||||||
return nil, pathErr("readfile", name, err)
|
|
||||||
}
|
|
||||||
|
|
||||||
return os.ReadFile(path)
|
|
||||||
}
|
|
||||||
|
|
||||||
// WriteFile writes data to the named file, creating it if necessary.
|
|
||||||
func (this FS) WriteFile (name string, data []byte, perm os.FileMode) error {
|
|
||||||
path, err := this.subPath(name)
|
|
||||||
if err != nil {
|
|
||||||
return pathErr("writefile", name, err)
|
|
||||||
}
|
|
||||||
|
|
||||||
return os.WriteFile(path, data, perm)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Stat returns a FileInfo describing the file.
|
|
||||||
func (this FS) Stat (name string) (fs.FileInfo, error) {
|
|
||||||
path, err := this.subPath(name)
|
|
||||||
if err != nil {
|
|
||||||
return nil, pathErr("stat", name, err)
|
|
||||||
}
|
|
||||||
|
|
||||||
return os.Stat(path)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Remove removes the named file or (empty) directory.
|
|
||||||
func (this FS) Remove (name string) error {
|
|
||||||
path, err := this.subPath(name)
|
|
||||||
if err != nil {
|
|
||||||
return pathErr("remove", name, err)
|
|
||||||
}
|
|
||||||
|
|
||||||
return os.Remove(path)
|
|
||||||
}
|
|
||||||
|
|
||||||
// RemoveAll removes name and any children it contains.
|
|
||||||
func (this FS) RemoveAll (name string) error {
|
|
||||||
path, err := this.subPath(name)
|
|
||||||
if err != nil {
|
|
||||||
return pathErr("removeall", name, err)
|
|
||||||
}
|
|
||||||
|
|
||||||
return os.RemoveAll(path)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Rename renames (moves) oldname to newname.
|
|
||||||
func (this FS) Rename (oldname, newname string) error {
|
|
||||||
oldpath, err := this.subPath(oldname)
|
|
||||||
if err != nil {
|
|
||||||
return pathErr("rename", oldname, err)
|
|
||||||
}
|
|
||||||
newpath, err := this.subPath(newname)
|
|
||||||
if err != nil {
|
|
||||||
return pathErr("rename", newname, err)
|
|
||||||
}
|
|
||||||
|
|
||||||
return os.Rename(oldpath, newpath)
|
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user