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 }