package ftpserver import ( "Scanyonero/document" "io" "os" "time" "github.com/spf13/afero" "github.com/spf13/afero/mem" ) const filePathSeparator = os.PathSeparator type virtualFile struct { mem.File Callback func(file document.File) error } // Override close behavior. // When the file handle is closed, we will forward the file content via callback. func (v *virtualFile) Close() error { if v.Callback != nil { file := document.File{ Name: v.Name(), } var err error if file.Data, err = io.ReadAll(mem.NewReadOnlyFileHandle(v.Data())); err != nil { v.File.Close() return err } if err := v.Callback(file); err != nil { v.File.Close() return err } } return v.File.Close() } var _ afero.File = &virtualFile{} type virtualFS struct { Callback func(file document.File) error } var _ afero.Fs = &virtualFS{} // Create creates a file in the filesystem, returning the file and an error, if any happens. func (v *virtualFS) Create(name string) (afero.File, error) { name = normalizePath(name) //log.Printf("VirtualFS: Create: %v", name) file := mem.CreateFile(name) fileHandle := *mem.NewFileHandle(file) return &virtualFile{File: fileHandle, Callback: v.Callback}, nil } // Mkdir creates a directory in the filesystem, return an error if any happens. func (v *virtualFS) Mkdir(name string, perm os.FileMode) error { //name = normalizePath(name) //log.Printf("VirtualFS: Mkdir: %v, %v", name, perm) return nil } // MkdirAll creates a directory path and all parents that does not exist yet. func (v *virtualFS) MkdirAll(path string, perm os.FileMode) error { //path = normalizePath(path) //log.Printf("VirtualFS: MkdirAll: %v, %v", path, perm) return nil } // Open opens a file, returning it or an error, if any happens. func (v *virtualFS) Open(name string) (afero.File, error) { name = normalizePath(name) //log.Printf("VirtualFS: Open: %v", name) dir := mem.CreateDir(name) mem.SetMode(dir, os.ModeDir|0o755) return mem.NewReadOnlyFileHandle(dir), nil } // OpenFile opens a file using the given flags and the given mode. func (v *virtualFS) OpenFile(name string, flag int, perm os.FileMode) (afero.File, error) { name = normalizePath(name) //log.Printf("VirtualFS: OpenFile: %v, %v, %v", name, flag, perm) return v.Create(name) } // Remove removes a file identified by name, returning an error, if any happens. func (v *virtualFS) Remove(name string) error { name = normalizePath(name) //log.Printf("VirtualFS: Remove: %v", name) return &os.PathError{Op: "remove", Path: name, Err: os.ErrNotExist} } // RemoveAll removes a directory path and any children it contains. It does not fail if the path does not exist (return nil). func (v *virtualFS) RemoveAll(path string) error { //path = normalizePath(path) //log.Printf("VirtualFS: RemoveAll: %v", path) return nil } // Rename renames a file. func (v *virtualFS) Rename(oldName, newName string) error { oldName = normalizePath(oldName) //newName = normalizePath(newName) //log.Printf("VirtualFS: Rename: %v -> %v", oldName, newName) return &os.PathError{Op: "rename", Path: oldName, Err: os.ErrNotExist} } // Stat returns a FileInfo describing the named file, or an error, if any happens. func (v *virtualFS) Stat(name string) (os.FileInfo, error) { name = normalizePath(name) //log.Printf("VirtualFS: Stat: %v", name) dir := mem.CreateDir(name) mem.SetMode(dir, os.ModeDir|0o755) return mem.GetFileInfo(dir), nil } // The name of this FileSystem. func (v *virtualFS) Name() string { return "ScanyoneroVirtualFS" } // Chmod changes the mode of the named file to mode. func (v *virtualFS) Chmod(name string, mode os.FileMode) error { name = normalizePath(name) //log.Printf("VirtualFS: Chmod: %v, %v", name, mode) return &os.PathError{Op: "chmod", Path: name, Err: os.ErrNotExist} } // Chown changes the uid and gid of the named file. func (v *virtualFS) Chown(name string, uid, gid int) error { name = normalizePath(name) //log.Printf("VirtualFS: Chown: %v, %v, %v", name, uid, gid) return &os.PathError{Op: "chown", Path: name, Err: os.ErrNotExist} } // Chtimes changes the access and modification times of the named file. func (v *virtualFS) Chtimes(name string, atime time.Time, mtime time.Time) error { name = normalizePath(name) //log.Printf("VirtualFS: Chtimes: %v, %v, %v", name, atime, mtime) return &os.PathError{Op: "chtimes", Path: name, Err: os.ErrNotExist} }