docstore/pkg/fs/fs.go
2019-05-05 19:06:51 +02:00

143 lines
2.8 KiB
Go

// Copyright (C) 2019 Marius Schellenberger
package fs
import (
"errors"
"git.giftfish.de/ston1th/docstore/pkg/core"
"git.giftfish.de/ston1th/docstore/pkg/log"
"os"
"path/filepath"
"sort"
"strings"
"sync"
)
const (
DirMode = 0750
FileMode = 0640
)
// Directory represents a directory and its contents
type Directory struct {
Dirs core.Paths
Files core.Paths
}
type Filesystem struct {
Base string
// protects scan
m sync.RWMutex
scan map[string]struct{}
}
func NewFilesystem(base string) (fs *Filesystem, err error) {
if !filepath.IsAbs(base) {
err = errors.New("base dir '" + base + "' is not an absolute path")
return
}
fi, err := os.Stat(base)
if err != nil {
err = os.Mkdir(base, DirMode)
if err != nil {
return
}
log.Printf("fs: created data directory '%s'", base)
fi, err = os.Stat(base)
if err != nil {
return
}
}
if !fi.IsDir() {
err = errors.New("base dir '" + base + "' is not a directory")
return
}
fs = &Filesystem{Base: base, scan: make(map[string]struct{})}
return
}
func (fs *Filesystem) ReadDir(path string) (d *Directory) {
path = Clean(path)
combined := filepath.Join(fs.Base, path)
f, err := os.Open(combined)
if err != nil {
return
}
names, err := f.Readdirnames(0)
if err != nil {
return
}
d = new(Directory)
for _, n := range names {
fi, err := os.Stat(filepath.Join(combined, n))
if err != nil {
continue
}
m := fi.Mode()
if m.IsDir() {
d.Dirs = append(d.Dirs, core.Path{Name: n, Abs: filepath.Join(path, n)})
continue
}
if m.IsRegular() {
abs := filepath.Join(path, n)
d.Files = append(d.Files, core.Path{Name: n, Abs: abs, Scan: fs.CheckScan(abs)})
}
}
sort.Sort(d.Dirs)
sort.Sort(d.Files)
return
}
func (fs *Filesystem) Recursive(p string) (paths core.Paths) {
p, _ = filepath.Split(Clean(p))
if len(p) >= 2 {
p = p[:len(p)-1]
}
filepath.Walk(fs.Base, func(path string, info os.FileInfo, err error) error {
if err != nil {
return nil
}
if info.IsDir() {
a := strings.TrimPrefix(path, fs.Base)
if a == "" {
a = "/"
}
paths = append(paths, core.Path{Abs: a, Flag: a == p})
}
return nil
})
sort.Sort(paths)
return
}
func (fs *Filesystem) RecursiveFiles(p string) (files []string) {
filepath.Walk(filepath.Join(fs.Base, Clean(p)), func(path string, info os.FileInfo, err error) error {
if err != nil {
return nil
}
if info.Mode().IsRegular() {
files = append(files, strings.TrimPrefix(path, fs.Base))
}
return nil
})
return
}
func Paths(path string) (p core.Paths) {
s := strings.Split(Clean(path), string(filepath.Separator))
for i, v := range s[1:] {
if v == "" {
continue
}
if i == 0 {
p = append(p, core.Path{Name: v, Abs: "/" + v})
continue
}
p = append(p, core.Path{Name: v, Abs: filepath.Join(p[i-1].Abs, v)})
}
if len(p) != 0 {
p[len(p)-1].Flag = true
}
return
}