144 lines
2.9 KiB
Go
144 lines
2.9 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
|
|
Log *log.ScanLog
|
|
|
|
// 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, Log: log.NewScanLog(0), 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
|
|
}
|