|
|
|
package swampfile
|
|
|
|
|
|
|
|
import (
|
|
|
|
"caj-larsson/bog/dataswamp/swampfile"
|
|
|
|
"errors"
|
|
|
|
"io/fs"
|
|
|
|
"os"
|
|
|
|
"path"
|
|
|
|
"path/filepath"
|
|
|
|
"time"
|
|
|
|
)
|
|
|
|
|
|
|
|
var ErrDirtyRepo = errors.New("Dirty repository without flag")
|
|
|
|
|
|
|
|
type FileSystemSwampFileData struct {
|
|
|
|
path string
|
|
|
|
size int64
|
|
|
|
mod_time time.Time
|
|
|
|
file *os.File
|
|
|
|
}
|
|
|
|
|
|
|
|
func (f FileSystemSwampFileData) Read(p []byte) (int, error) {
|
|
|
|
return f.file.Read(p)
|
|
|
|
}
|
|
|
|
|
|
|
|
func (f FileSystemSwampFileData) Write(p []byte) (int, error) {
|
|
|
|
return f.file.Write(p)
|
|
|
|
}
|
|
|
|
|
|
|
|
func (f FileSystemSwampFileData) Close() error {
|
|
|
|
return f.file.Close()
|
|
|
|
}
|
|
|
|
|
|
|
|
func (f FileSystemSwampFileData) Seek(offset int64, whence int) (int64, error) {
|
|
|
|
return f.file.Seek(offset, whence)
|
|
|
|
}
|
|
|
|
|
|
|
|
func (f FileSystemSwampFileData) Path() string {
|
|
|
|
return f.path
|
|
|
|
}
|
|
|
|
|
|
|
|
func (f FileSystemSwampFileData) Size() int64 {
|
|
|
|
return f.size
|
|
|
|
}
|
|
|
|
|
|
|
|
func (f FileSystemSwampFileData) Modified() time.Time {
|
|
|
|
stat, _ := f.file.Stat()
|
|
|
|
return stat.ModTime()
|
|
|
|
}
|
|
|
|
|
|
|
|
type Repository struct {
|
|
|
|
Root string
|
|
|
|
}
|
|
|
|
|
|
|
|
func NewRepository(root string) (*Repository, error) {
|
|
|
|
fi, err := os.ReadDir(root)
|
|
|
|
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
|
|
|
flagpath := path.Join(root, ".bogrepo")
|
|
|
|
|
|
|
|
if len(fi) == 0 {
|
|
|
|
// New Repository, write flagfile
|
|
|
|
f, err := os.OpenFile(flagpath, os.O_CREATE, 0644)
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
f.Close()
|
|
|
|
}
|
|
|
|
|
|
|
|
flagfile, err := os.OpenFile(flagpath, os.O_RDONLY, 0)
|
|
|
|
|
|
|
|
if err != nil {
|
|
|
|
return nil, ErrDirtyRepo
|
|
|
|
}
|
|
|
|
flagfile.Close()
|
|
|
|
return &Repository{root}, nil
|
|
|
|
}
|
|
|
|
|
|
|
|
func (f Repository) absPath(filename string, namespace_ns string) string {
|
|
|
|
return path.Join(f.Root, namespace_ns, filename)
|
|
|
|
}
|
|
|
|
|
|
|
|
func (f Repository) Create(filename string, namespace_ns string) (swampfile.SwampInFile, error) {
|
|
|
|
abs_path := f.absPath(filename, namespace_ns)
|
|
|
|
|
|
|
|
dir := path.Dir(abs_path)
|
|
|
|
os.MkdirAll(dir, 0750)
|
|
|
|
file, err := os.OpenFile(abs_path, os.O_RDWR|os.O_CREATE, 0644)
|
|
|
|
|
|
|
|
if err != nil {
|
|
|
|
panic(err)
|
|
|
|
}
|
|
|
|
|
|
|
|
stat_info, err := file.Stat()
|
|
|
|
if err != nil {
|
|
|
|
panic(err)
|
|
|
|
}
|
|
|
|
file.Truncate(0)
|
|
|
|
|
|
|
|
bfd := FileSystemSwampFileData{filename, stat_info.Size(), stat_info.ModTime(), file}
|
|
|
|
|
|
|
|
return bfd, nil
|
|
|
|
}
|
|
|
|
|
|
|
|
func (f Repository) Open(filename string, namespace_ns string) (swampfile.SwampOutFile, error) {
|
|
|
|
abs_path := f.absPath(filename, namespace_ns)
|
|
|
|
|
|
|
|
dir := path.Dir(abs_path)
|
|
|
|
os.MkdirAll(dir, 0750)
|
|
|
|
file, err := os.OpenFile(abs_path, os.O_RDONLY, 0644)
|
|
|
|
|
|
|
|
if err != nil {
|
|
|
|
return nil, swampfile.ErrNotExists
|
|
|
|
}
|
|
|
|
|
|
|
|
stat, err := file.Stat()
|
|
|
|
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
|
|
|
bfd := FileSystemSwampFileData{filename, stat.Size(), time.Now(), file}
|
|
|
|
|
|
|
|
return bfd, nil
|
|
|
|
}
|
|
|
|
|
|
|
|
func (f Repository) Delete(filename string, namespace_ns string) {
|
|
|
|
abs_path := f.absPath(filename, namespace_ns)
|
|
|
|
os.Remove(abs_path)
|
|
|
|
}
|
|
|
|
|
|
|
|
func (r Repository) DeleteOlderThan(namespace_stub string, ts time.Time) ([]swampfile.DeletedSwampFile, error) {
|
|
|
|
df := []swampfile.DeletedSwampFile{}
|
|
|
|
|
|
|
|
dr := path.Join(r.Root, namespace_stub)
|
|
|
|
err := filepath.Walk(dr, func(path string, info fs.FileInfo, err error) error {
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
mode := info.Mode()
|
|
|
|
|
|
|
|
if mode.IsRegular() {
|
|
|
|
if info.ModTime().Before(ts) {
|
|
|
|
df = append(df, swampfile.DeletedSwampFile{path, info.Size()})
|
|
|
|
err = os.Remove(path)
|
|
|
|
if err != nil {
|
|
|
|
panic(err)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
if !mode.IsDir() {
|
|
|
|
return swampfile.ErrCorrupted
|
|
|
|
}
|
|
|
|
|
|
|
|
return nil
|
|
|
|
})
|
|
|
|
return df, err
|
|
|
|
}
|