package archive import ( "context" "io/fs" "strings" "time" "git.kmsign.ru/royalcat/tstor/server/src/vfs" ) type archiveLoader func(ctx context.Context, archivePath string, r vfs.File, size int64) (map[string]fileEntry, error) var _ vfs.Filesystem = &ArchiveFS{} type fileEntry struct { fs.FileInfo open func(ctx context.Context) (vfs.File, error) } type ArchiveFS struct { name string size int64 files map[string]fileEntry modTime time.Time } // Rename implements Filesystem. func (a *ArchiveFS) Rename(ctx context.Context, oldpath string, newpath string) error { return vfs.ErrNotImplemented } // ModTime implements Filesystem. func (a *ArchiveFS) ModTime() time.Time { return a.modTime } // Mode implements Filesystem. func (a *ArchiveFS) Mode() fs.FileMode { return fs.ModeDir } // Size implements Filesystem. func (a *ArchiveFS) Size() int64 { return int64(a.size) } // Sys implements Filesystem. func (a *ArchiveFS) Sys() any { return nil } // FsName implements Filesystem. func (a *ArchiveFS) FsName() string { return "archivefs" } func (d *Daemon) NewArchiveFS(ctx context.Context, archivePath, name string, f vfs.File, size int64, loader archiveLoader) (*ArchiveFS, error) { archiveFiles, err := loader(ctx, archivePath, f, size) if err != nil { return nil, err } // TODO make optional singleDir := true for k := range archiveFiles { if !strings.HasPrefix(k, "/"+name+"/") { singleDir = false break } } files := make(map[string]fileEntry, len(archiveFiles)) for k, v := range archiveFiles { // TODO make optional if strings.Contains(k, "/__MACOSX/") { continue } if singleDir { k, _ = strings.CutPrefix(k, "/"+name) } files[k] = v } // FIXME configurable files["/.forcegallery"] = fileEntry{ FileInfo: vfs.NewFileInfo("/.forcegallery", 0, time.Time{}), open: func(ctx context.Context) (vfs.File, error) { return vfs.NewMemoryFile(".forcegallery", []byte{}), nil }, } return &ArchiveFS{ name: name, size: size, files: files, }, nil }