diff --git a/pkg/filemanager/fs/dbfs/dbfs.go b/pkg/filemanager/fs/dbfs/dbfs.go index 7d7f7a4..5289547 100644 --- a/pkg/filemanager/fs/dbfs/dbfs.go +++ b/pkg/filemanager/fs/dbfs/dbfs.go @@ -448,6 +448,10 @@ func (f *DBFS) Get(ctx context.Context, path *fs.URI, opts ...fs.Option) (fs.Fil return nil, fmt.Errorf("failed to get target file: %w", err) } + if o.notRoot && target.IsRootFolder() { + return nil, fs.ErrNotSupportedAction.WithError(fmt.Errorf("cannot operate root file")) + } + if o.extendedInfo && target != nil { extendedInfo := &fs.FileExtendedInfo{ StorageUsed: target.SizeUsed(), diff --git a/pkg/filemanager/fs/dbfs/options.go b/pkg/filemanager/fs/dbfs/options.go index e2b8ce7..b4e0122 100644 --- a/pkg/filemanager/fs/dbfs/options.go +++ b/pkg/filemanager/fs/dbfs/options.go @@ -25,6 +25,7 @@ type dbfsOption struct { noChainedCreation bool streamListResponseCallback func(parent fs.File, file []fs.File) ancestor *File + notRoot bool } func newDbfsOption() *dbfsOption { @@ -56,6 +57,13 @@ func WithFilePublicMetadata() fs.Option { }) } +// WithNotRoot force the get result cannot be a root folder +func WithNotRoot() fs.Option { + return optionFunc(func(o *dbfsOption) { + o.notRoot = true + }) +} + // WithContextHint enables generating context hint for the list operation. func WithContextHint() fs.Option { return optionFunc(func(o *dbfsOption) { diff --git a/pkg/filemanager/fs/dbfs/share_navigator.go b/pkg/filemanager/fs/dbfs/share_navigator.go index 61bfc3b..6c3f664 100644 --- a/pkg/filemanager/fs/dbfs/share_navigator.go +++ b/pkg/filemanager/fs/dbfs/share_navigator.go @@ -183,7 +183,7 @@ func (n *shareNavigator) To(ctx context.Context, path *fs.URI) (*File, error) { elements := path.Elements() // If target is root of single file share, the root itself is the target. - if len(elements) <= 1 && n.singleFileShare { + if len(elements) == 1 && n.singleFileShare { file, err := n.latestSharedSingleFile(ctx) if err != nil { return nil, err diff --git a/pkg/filemanager/fs/dbfs/upload.go b/pkg/filemanager/fs/dbfs/upload.go index 8fcbd93..4e047d3 100644 --- a/pkg/filemanager/fs/dbfs/upload.go +++ b/pkg/filemanager/fs/dbfs/upload.go @@ -176,7 +176,7 @@ func (f *DBFS) PrepareUpload(ctx context.Context, req *fs.UploadRequest, opts .. func (f *DBFS) CompleteUpload(ctx context.Context, session *fs.UploadSession) (fs.File, error) { // Get placeholder file - file, err := f.Get(ctx, session.Props.Uri, WithFileEntities()) + file, err := f.Get(ctx, session.Props.Uri, WithFileEntities(), WithNotRoot()) if err != nil { return nil, fmt.Errorf("failed to get placeholder file: %w", err) } @@ -270,7 +270,7 @@ func (f *DBFS) CompleteUpload(ctx context.Context, session *fs.UploadSession) (f } } - file, err = f.Get(ctx, session.Props.Uri, WithFileEntities()) + file, err = f.Get(ctx, session.Props.Uri, WithFileEntities(), WithNotRoot()) if err != nil { return nil, fmt.Errorf("failed to get updated file: %w", err) } @@ -284,7 +284,7 @@ func (f *DBFS) CompleteUpload(ctx context.Context, session *fs.UploadSession) (f // - File unlocked, upload session not valid func (f *DBFS) CancelUploadSession(ctx context.Context, path *fs.URI, sessionID string, session *fs.UploadSession) ([]fs.Entity, error) { // Get placeholder file - file, err := f.Get(ctx, path, WithFileEntities()) + file, err := f.Get(ctx, path, WithFileEntities(), WithNotRoot()) if err != nil { return nil, fmt.Errorf("failed to get placeholder file: %w", err) } diff --git a/pkg/filemanager/fs/fs.go b/pkg/filemanager/fs/fs.go index 12f505a..314354a 100644 --- a/pkg/filemanager/fs/fs.go +++ b/pkg/filemanager/fs/fs.go @@ -158,6 +158,7 @@ type ( ExtendedInfo() *FileExtendedInfo FolderSummary() *FolderSummary Capabilities() *boolset.BooleanSet + IsRootFolder() bool } Entities []Entity diff --git a/pkg/filemanager/manager/archive.go b/pkg/filemanager/manager/archive.go index acd1efd..fa2440a 100644 --- a/pkg/filemanager/manager/archive.go +++ b/pkg/filemanager/manager/archive.go @@ -27,7 +27,7 @@ func (m *manager) CreateArchive(ctx context.Context, uris []*fs.URI, writer io.W // List all top level files files := make([]fs.File, 0, len(uris)) for _, uri := range uris { - file, err := m.Get(ctx, uri, dbfs.WithFileEntities(), dbfs.WithRequiredCapabilities(dbfs.NavigatorCapabilityDownloadFile)) + file, err := m.Get(ctx, uri, dbfs.WithFileEntities(), dbfs.WithRequiredCapabilities(dbfs.NavigatorCapabilityDownloadFile), dbfs.WithNotRoot()) if err != nil { return 0, fmt.Errorf("failed to get file %s: %w", uri, err) } diff --git a/pkg/filemanager/manager/operation.go b/pkg/filemanager/manager/operation.go index ffadfdc..1b70c9a 100644 --- a/pkg/filemanager/manager/operation.go +++ b/pkg/filemanager/manager/operation.go @@ -227,7 +227,7 @@ func (l *manager) Restore(ctx context.Context, path ...*fs.URI) error { } func (l *manager) CreateOrUpdateShare(ctx context.Context, path *fs.URI, args *CreateShareArgs) (*ent.Share, error) { - file, err := l.fs.Get(ctx, path, dbfs.WithRequiredCapabilities(dbfs.NavigatorCapabilityShare)) + file, err := l.fs.Get(ctx, path, dbfs.WithRequiredCapabilities(dbfs.NavigatorCapabilityShare), dbfs.WithNotRoot()) if err != nil { return nil, serializer.NewError(serializer.CodeNotFound, "src file not found", err) } diff --git a/pkg/filemanager/manager/viewer.go b/pkg/filemanager/manager/viewer.go index 0b85f8c..819ef31 100644 --- a/pkg/filemanager/manager/viewer.go +++ b/pkg/filemanager/manager/viewer.go @@ -45,7 +45,7 @@ func init() { } func (m *manager) CreateViewerSession(ctx context.Context, uri *fs.URI, version string, viewer *setting.Viewer) (*ViewerSession, error) { - file, err := m.fs.Get(ctx, uri, dbfs.WithFileEntities()) + file, err := m.fs.Get(ctx, uri, dbfs.WithFileEntities(), dbfs.WithNotRoot()) if err != nil { return nil, err } diff --git a/pkg/filemanager/workflows/extract.go b/pkg/filemanager/workflows/extract.go index 14d907e..9f7d865 100644 --- a/pkg/filemanager/workflows/extract.go +++ b/pkg/filemanager/workflows/extract.go @@ -171,7 +171,7 @@ func (m *ExtractArchiveTask) createSlaveExtractTask(ctx context.Context, dep dep fm := manager.NewFileManager(dep, user) // Get entity source to extract - archiveFile, err := fm.Get(ctx, uri, dbfs.WithFileEntities(), dbfs.WithRequiredCapabilities(dbfs.NavigatorCapabilityDownloadFile)) + archiveFile, err := fm.Get(ctx, uri, dbfs.WithFileEntities(), dbfs.WithRequiredCapabilities(dbfs.NavigatorCapabilityDownloadFile), dbfs.WithNotRoot()) if err != nil { return task.StatusError, fmt.Errorf("failed to get archive file: %s (%w)", err, queue.CriticalErr) } @@ -256,7 +256,7 @@ func (m *ExtractArchiveTask) masterExtractArchive(ctx context.Context, dep depen fm := manager.NewFileManager(dep, user) // Get entity source to extract - archiveFile, err := fm.Get(ctx, uri, dbfs.WithFileEntities(), dbfs.WithRequiredCapabilities(dbfs.NavigatorCapabilityDownloadFile)) + archiveFile, err := fm.Get(ctx, uri, dbfs.WithFileEntities(), dbfs.WithRequiredCapabilities(dbfs.NavigatorCapabilityDownloadFile), dbfs.WithNotRoot()) if err != nil { return task.StatusError, fmt.Errorf("failed to get archive file: %s (%w)", err, queue.CriticalErr) } @@ -413,7 +413,7 @@ func (m *ExtractArchiveTask) masterDownloadZip(ctx context.Context, dep dependen fm := manager.NewFileManager(dep, user) // Get entity source to extract - archiveFile, err := fm.Get(ctx, uri, dbfs.WithFileEntities(), dbfs.WithRequiredCapabilities(dbfs.NavigatorCapabilityDownloadFile)) + archiveFile, err := fm.Get(ctx, uri, dbfs.WithFileEntities(), dbfs.WithRequiredCapabilities(dbfs.NavigatorCapabilityDownloadFile), dbfs.WithNotRoot()) if err != nil { return task.StatusError, fmt.Errorf("failed to get archive file: %s (%w)", err, queue.CriticalErr) } diff --git a/service/explorer/file.go b/service/explorer/file.go index c17f549..ca49db5 100644 --- a/service/explorer/file.go +++ b/service/explorer/file.go @@ -621,7 +621,7 @@ func (s *GetFileInfoService) Get(c *gin.Context) (*FileResponse, error) { return nil, serializer.NewError(serializer.CodeParamErr, "unknown uri", err) } - opts := []fs.Option{dbfs.WithFilePublicMetadata()} + opts := []fs.Option{dbfs.WithFilePublicMetadata(), dbfs.WithNotRoot()} if s.ExtendedInfo { opts = append(opts, dbfs.WithExtendedInfo(), dbfs.WithEntityUser(), dbfs.WithFileShareIfOwned()) } diff --git a/service/explorer/viewer.go b/service/explorer/viewer.go index f7ede90..63f54b6 100644 --- a/service/explorer/viewer.go +++ b/service/explorer/viewer.go @@ -3,6 +3,9 @@ package explorer import ( "errors" "fmt" + "net/http" + "time" + "github.com/cloudreve/Cloudreve/v4/application/dependency" "github.com/cloudreve/Cloudreve/v4/ent" "github.com/cloudreve/Cloudreve/v4/inventory" @@ -18,8 +21,6 @@ import ( "github.com/cloudreve/Cloudreve/v4/pkg/setting" "github.com/cloudreve/Cloudreve/v4/pkg/wopi" "github.com/gin-gonic/gin" - "net/http" - "time" ) type WopiService struct { @@ -68,7 +69,7 @@ func (service *WopiService) RefreshLock(c *gin.Context) error { l := dep.Logger() // Make sure file exists and readable - file, err := m.Get(c, uri, dbfs.WithRequiredCapabilities(dbfs.NavigatorCapabilityLockFile)) + file, err := m.Get(c, uri, dbfs.WithRequiredCapabilities(dbfs.NavigatorCapabilityLockFile), dbfs.WithNotRoot()) if err != nil { return fmt.Errorf("failed to get file: %w", err) } @@ -105,7 +106,7 @@ func (service *WopiService) Lock(c *gin.Context) error { l := dep.Logger() // Make sure file exists and readable - file, err := m.Get(c, uri, dbfs.WithRequiredCapabilities(dbfs.NavigatorCapabilityLockFile)) + file, err := m.Get(c, uri, dbfs.WithRequiredCapabilities(dbfs.NavigatorCapabilityLockFile), dbfs.WithNotRoot()) if err != nil { return fmt.Errorf("failed to get file: %w", err) } @@ -159,7 +160,7 @@ func (service *WopiService) PutContent(c *gin.Context) error { } // Make sure file exists and readable - file, err := m.Get(c, uri, dbfs.WithRequiredCapabilities(dbfs.NavigatorCapabilityUploadFile)) + file, err := m.Get(c, uri, dbfs.WithRequiredCapabilities(dbfs.NavigatorCapabilityUploadFile), dbfs.WithNotRoot()) if err != nil { return fmt.Errorf("failed to get file: %w", err) } @@ -244,7 +245,7 @@ func (service *WopiService) GetFile(c *gin.Context) error { } // Make sure file exists and readable - file, err := m.Get(c, uri, dbfs.WithExtendedInfo(), dbfs.WithRequiredCapabilities(dbfs.NavigatorCapabilityDownloadFile)) + file, err := m.Get(c, uri, dbfs.WithExtendedInfo(), dbfs.WithRequiredCapabilities(dbfs.NavigatorCapabilityDownloadFile), dbfs.WithNotRoot()) if err != nil { return fmt.Errorf("failed to get file: %w", err) } @@ -285,6 +286,7 @@ func (service *WopiService) FileInfo(c *gin.Context) (*WopiFileInfo, error) { opts := []fs.Option{ dbfs.WithFilePublicMetadata(), dbfs.WithExtendedInfo(), + dbfs.WithNotRoot(), dbfs.WithRequiredCapabilities(dbfs.NavigatorCapabilityDownloadFile, dbfs.NavigatorCapabilityInfo, dbfs.NavigatorCapabilityUploadFile), } file, err := m.Get(c, uri, opts...)