diff --git a/internal/grpc/services/gateway/storageprovider.go b/internal/grpc/services/gateway/storageprovider.go index 5a14fca07cf..d603e6f7d7a 100644 --- a/internal/grpc/services/gateway/storageprovider.go +++ b/internal/grpc/services/gateway/storageprovider.go @@ -1861,7 +1861,6 @@ func (s *svc) RestoreRecycleItem(ctx context.Context, req *provider.RestoreRecyc } func (s *svc) PurgeRecycle(ctx context.Context, req *gateway.PurgeRecycleRequest) (*provider.PurgeRecycleResponse, error) { - // lookup storage by treating the key as a path. It has been prefixed with the storage path in ListRecycle c, err := s.find(ctx, req.Ref) if err != nil { return &provider.PurgeRecycleResponse{ diff --git a/internal/grpc/services/storageprovider/storageprovider.go b/internal/grpc/services/storageprovider/storageprovider.go index 44f2f3fee11..d64833893ac 100644 --- a/internal/grpc/services/storageprovider/storageprovider.go +++ b/internal/grpc/services/storageprovider/storageprovider.go @@ -754,7 +754,12 @@ func (s *service) ListRecycleStream(req *provider.ListRecycleStreamRequest, ss p ctx := ss.Context() log := appctx.GetLogger(ctx) - items, err := s.storage.ListRecycle(ctx, nil) + ref, err := s.unwrap(ctx, req.Ref) + if err != nil { + return err + } + + items, err := s.storage.ListRecycle(ctx, ref.ResourceId.OpaqueId, ref.Path) if err != nil { var st *rpc.Status switch err.(type) { @@ -794,7 +799,7 @@ func (s *service) ListRecycle(ctx context.Context, req *provider.ListRecycleRequ if err != nil { return nil, err } - items, err := s.storage.ListRecycle(ctx, ref) + items, err := s.storage.ListRecycle(ctx, ref.ResourceId.OpaqueId, ref.Path) // TODO(labkode): CRITICAL: fill recycle info with storage provider. if err != nil { var st *rpc.Status @@ -824,10 +829,7 @@ func (s *service) RestoreRecycleItem(ctx context.Context, req *provider.RestoreR if err != nil { return nil, err } - ref.ResourceId = &provider.ResourceId{ - OpaqueId: req.Key, - } - if err := s.storage.RestoreRecycleItem(ctx, ref, req.RestoreRef); err != nil { + if err := s.storage.RestoreRecycleItem(ctx, req.Key, ref.Path, req.RestoreRef); err != nil { var st *rpc.Status switch err.(type) { case errtypes.IsNotFound: @@ -851,7 +853,7 @@ func (s *service) RestoreRecycleItem(ctx context.Context, req *provider.RestoreR func (s *service) PurgeRecycle(ctx context.Context, req *provider.PurgeRecycleRequest) (*provider.PurgeRecycleResponse, error) { // if a key was sent as opaque id purge only that item if req.GetRef().GetResourceId() != nil && req.GetRef().GetResourceId().OpaqueId != "" { - if err := s.storage.PurgeRecycleItem(ctx, req.GetRef()); err != nil { + if err := s.storage.PurgeRecycleItem(ctx, req.GetRef().GetResourceId().OpaqueId, req.GetRef().Path); err != nil { var st *rpc.Status switch err.(type) { case errtypes.IsNotFound: diff --git a/internal/http/services/owncloud/ocdav/trashbin.go b/internal/http/services/owncloud/ocdav/trashbin.go index 3a32ccc6b0d..a06a37d9c0f 100644 --- a/internal/http/services/owncloud/ocdav/trashbin.go +++ b/internal/http/services/owncloud/ocdav/trashbin.go @@ -24,7 +24,6 @@ import ( "fmt" "net/http" "path" - "path/filepath" "strconv" "strings" "time" @@ -108,7 +107,7 @@ func (h *TrashbinHandler) Handler(s *svc) http.Handler { //} if r.Method == "PROPFIND" { - h.listTrashbin(w, r, s, u, path.Join(key, r.URL.Path)) + h.listTrashbin(w, r, s, u, key, r.URL.Path) return } if key != "" && r.Method == "MOVE" { @@ -142,7 +141,7 @@ func (h *TrashbinHandler) Handler(s *svc) http.Handler { }) } -func (h *TrashbinHandler) listTrashbin(w http.ResponseWriter, r *http.Request, s *svc, u *userpb.User, key string) { +func (h *TrashbinHandler) listTrashbin(w http.ResponseWriter, r *http.Request, s *svc, u *userpb.User, key, itemPath string) { ctx := r.Context() ctx, span := trace.StartSpan(ctx, "listTrashbin") defer span.End() @@ -190,8 +189,7 @@ func (h *TrashbinHandler) listTrashbin(w http.ResponseWriter, r *http.Request, s } // ask gateway for recycle items - // TODO(labkode): add Reference to ListRecycleRequest - getRecycleRes, err := gc.ListRecycle(ctx, &gateway.ListRecycleRequest{Ref: &provider.Reference{Path: filepath.Join(getHomeRes.Path, key)}}) + getRecycleRes, err := gc.ListRecycle(ctx, &gateway.ListRecycleRequest{Ref: &provider.Reference{Path: path.Join(getHomeRes.Path, key, itemPath)}}) if err != nil { sublog.Error().Err(err).Msg("error calling ListRecycle") @@ -331,7 +329,7 @@ func (h *TrashbinHandler) itemToPropResponse(ctx context.Context, s *svc, u *use Prop: []*propertyXML{}, }) // yes this is redundant, can be derived from oc:trashbin-original-location which contains the full path, clients should not fetch it - response.Propstat[0].Prop = append(response.Propstat[0].Prop, s.newProp("oc:trashbin-original-filename", filepath.Base(item.Ref.Path))) + response.Propstat[0].Prop = append(response.Propstat[0].Prop, s.newProp("oc:trashbin-original-filename", path.Base(item.Ref.Path))) response.Propstat[0].Prop = append(response.Propstat[0].Prop, s.newProp("oc:trashbin-original-location", strings.TrimPrefix(item.Ref.Path, "/"))) response.Propstat[0].Prop = append(response.Propstat[0].Prop, s.newProp("oc:trashbin-delete-timestamp", strconv.FormatUint(item.DeletionTime.Seconds, 10))) response.Propstat[0].Prop = append(response.Propstat[0].Prop, s.newProp("oc:trashbin-delete-datetime", dTime)) @@ -368,7 +366,7 @@ func (h *TrashbinHandler) itemToPropResponse(ctx context.Context, s *svc, u *use } case "trashbin-original-filename": // yes this is redundant, can be derived from oc:trashbin-original-location which contains the full path, clients should not fetch it - propstatOK.Prop = append(propstatOK.Prop, s.newProp("oc:trashbin-original-filename", filepath.Base(item.Ref.Path))) + propstatOK.Prop = append(propstatOK.Prop, s.newProp("oc:trashbin-original-filename", path.Base(item.Ref.Path))) case "trashbin-original-location": // TODO (jfd) double check and clarify the cs3 spec what the Key is about and if Path is only the folder that contains the file or if it includes the filename propstatOK.Prop = append(propstatOK.Prop, s.newProp("oc:trashbin-original-location", strings.TrimPrefix(item.Ref.Path, "/"))) @@ -415,7 +413,7 @@ func (h *TrashbinHandler) itemToPropResponse(ctx context.Context, s *svc, u *use } // restore has a destination and a key -func (h *TrashbinHandler) restore(w http.ResponseWriter, r *http.Request, s *svc, u *userpb.User, dst, key, resourcePath string) { +func (h *TrashbinHandler) restore(w http.ResponseWriter, r *http.Request, s *svc, u *userpb.User, dst, key, itemPath string) { ctx := r.Context() ctx, span := trace.StartSpan(ctx, "restore") defer span.End() @@ -453,7 +451,7 @@ func (h *TrashbinHandler) restore(w http.ResponseWriter, r *http.Request, s *svc } dstRef := &provider.Reference{ - Path: filepath.Join(getHomeRes.Path, dst), + Path: path.Join(getHomeRes.Path, dst), } dstStatReq := &provider.StatRequest{ @@ -516,7 +514,7 @@ func (h *TrashbinHandler) restore(w http.ResponseWriter, r *http.Request, s *svc // use the key which is prefixed with the StoragePath to lookup the correct storage ... // TODO currently limited to the home storage Ref: &provider.Reference{ - Path: path.Join(getHomeRes.Path, resourcePath), + Path: path.Join(getHomeRes.Path, itemPath), }, Key: key, RestoreRef: &provider.Reference{Path: dst}, @@ -555,7 +553,7 @@ func (h *TrashbinHandler) restore(w http.ResponseWriter, r *http.Request, s *svc } // delete has only a key -func (h *TrashbinHandler) delete(w http.ResponseWriter, r *http.Request, s *svc, u *userpb.User, key, path string) { +func (h *TrashbinHandler) delete(w http.ResponseWriter, r *http.Request, s *svc, u *userpb.User, key, itemPath string) { ctx := r.Context() ctx, span := trace.StartSpan(ctx, "erase") defer span.End() @@ -599,7 +597,7 @@ func (h *TrashbinHandler) delete(w http.ResponseWriter, r *http.Request, s *svc, StorageId: sRes.Info.Id.StorageId, OpaqueId: key, }, - Path: utils.MakeRelativePath(path), + Path: utils.MakeRelativePath(itemPath), }, } diff --git a/pkg/storage/fs/owncloud/owncloud.go b/pkg/storage/fs/owncloud/owncloud.go index a98154dc57d..51668275da2 100644 --- a/pkg/storage/fs/owncloud/owncloud.go +++ b/pkg/storage/fs/owncloud/owncloud.go @@ -2060,12 +2060,12 @@ func (fs *ocfs) RestoreRevision(ctx context.Context, ref *provider.Reference, re return fs.propagate(ctx, ip) } -func (fs *ocfs) PurgeRecycleItem(ctx context.Context, ref *provider.Reference) error { +func (fs *ocfs) PurgeRecycleItem(ctx context.Context, key, path string) error { rp, err := fs.getRecyclePath(ctx) if err != nil { return errors.Wrap(err, "ocfs: error resolving recycle path") } - ip := filepath.Join(rp, filepath.Clean(ref.ResourceId.OpaqueId)) + ip := filepath.Join(rp, filepath.Clean(key)) // TODO check permission? // check permissions @@ -2086,7 +2086,7 @@ func (fs *ocfs) PurgeRecycleItem(ctx context.Context, ref *provider.Reference) e if err != nil { return errors.Wrap(err, "ocfs: error deleting recycle item") } - err = os.RemoveAll(filepath.Join(filepath.Dir(rp), "versions", filepath.Clean(ref.ResourceId.OpaqueId))) + err = os.RemoveAll(filepath.Join(filepath.Dir(rp), "versions", filepath.Clean(key))) if err != nil { return errors.Wrap(err, "ocfs: error deleting recycle item versions") } @@ -2153,7 +2153,7 @@ func (fs *ocfs) convertToRecycleItem(ctx context.Context, rp string, md os.FileI } } -func (fs *ocfs) ListRecycle(ctx context.Context, ref *provider.Reference) ([]*provider.RecycleItem, error) { +func (fs *ocfs) ListRecycle(ctx context.Context, key, path string) ([]*provider.RecycleItem, error) { // TODO check permission? on what? user must be the owner? rp, err := fs.getRecyclePath(ctx) if err != nil { @@ -2161,7 +2161,7 @@ func (fs *ocfs) ListRecycle(ctx context.Context, ref *provider.Reference) ([]*pr } // list files folder - mds, err := ioutil.ReadDir(filepath.Join(rp, ref.Path)) + mds, err := ioutil.ReadDir(filepath.Join(rp, key)) if err != nil { log := appctx.GetLogger(ctx) log.Debug().Err(err).Str("path", rp).Msg("trash not readable") @@ -2180,18 +2180,18 @@ func (fs *ocfs) ListRecycle(ctx context.Context, ref *provider.Reference) ([]*pr return items, nil } -func (fs *ocfs) RestoreRecycleItem(ctx context.Context, trashRef *provider.Reference, restoreRef *provider.Reference) error { +func (fs *ocfs) RestoreRecycleItem(ctx context.Context, key, path string, restoreRef *provider.Reference) error { // TODO check permission? on what? user must be the owner? log := appctx.GetLogger(ctx) rp, err := fs.getRecyclePath(ctx) if err != nil { return errors.Wrap(err, "ocfs: error resolving recycle path") } - src := filepath.Join(rp, filepath.Clean(trashRef.ResourceId.OpaqueId)) + src := filepath.Join(rp, filepath.Clean(key)) suffix := filepath.Ext(src) if len(suffix) == 0 || !strings.HasPrefix(suffix, ".d") { - log.Error().Str("key", trashRef.ResourceId.OpaqueId).Str("path", src).Msg("invalid trash item suffix") + log.Error().Str("key", key).Str("path", src).Msg("invalid trash item suffix") return nil } @@ -2201,20 +2201,20 @@ func (fs *ocfs) RestoreRecycleItem(ctx context.Context, trashRef *provider.Refer if restoreRef.Path == "" { v, err := xattr.Get(src, trashOriginPrefix) if err != nil { - log.Error().Err(err).Str("key", trashRef.ResourceId.OpaqueId).Str("path", src).Msg("could not read origin") + log.Error().Err(err).Str("key", key).Str("path", src).Msg("could not read origin") } restoreRef.Path = filepath.Join("/", filepath.Clean(string(v)), strings.TrimSuffix(filepath.Base(src), suffix)) } tgt := fs.toInternalPath(ctx, restoreRef.Path) // move back to original location if err := os.Rename(src, tgt); err != nil { - log.Error().Err(err).Str("key", trashRef.ResourceId.OpaqueId).Str("restorePath", restoreRef.Path).Str("src", src).Str("tgt", tgt).Msg("could not restore item") + log.Error().Err(err).Str("key", key).Str("restorePath", restoreRef.Path).Str("src", src).Str("tgt", tgt).Msg("could not restore item") return errors.Wrap(err, "ocfs: could not restore item") } // unset trash origin location in metadata if err := xattr.Remove(tgt, trashOriginPrefix); err != nil { // just a warning, will be overwritten next time it is deleted - log.Warn().Err(err).Str("key", trashRef.ResourceId.OpaqueId).Str("tgt", tgt).Msg("could not unset origin") + log.Warn().Err(err).Str("key", key).Str("tgt", tgt).Msg("could not unset origin") } // TODO(jfd) restore versions diff --git a/pkg/storage/fs/owncloudsql/owncloudsql.go b/pkg/storage/fs/owncloudsql/owncloudsql.go index 431b4600e1a..b398ecb40b6 100644 --- a/pkg/storage/fs/owncloudsql/owncloudsql.go +++ b/pkg/storage/fs/owncloudsql/owncloudsql.go @@ -1892,12 +1892,12 @@ func (fs *ocfs) RestoreRevision(ctx context.Context, ref *provider.Reference, re return fs.propagate(ctx, ip) } -func (fs *ocfs) PurgeRecycleItem(ctx context.Context, ref *provider.Reference) error { +func (fs *ocfs) PurgeRecycleItem(ctx context.Context, key, path string) error { rp, err := fs.getRecyclePath(ctx) if err != nil { return errors.Wrap(err, "ocfs: error resolving recycle path") } - ip := filepath.Join(rp, filepath.Clean(ref.ResourceId.OpaqueId)) + ip := filepath.Join(rp, filepath.Clean(key)) // TODO check permission? // check permissions @@ -1918,12 +1918,12 @@ func (fs *ocfs) PurgeRecycleItem(ctx context.Context, ref *provider.Reference) e if err != nil { return errors.Wrap(err, "ocfs: error deleting recycle item") } - err = os.RemoveAll(filepath.Join(filepath.Dir(rp), "versions", filepath.Clean(ref.ResourceId.OpaqueId))) + err = os.RemoveAll(filepath.Join(filepath.Dir(rp), "versions", filepath.Clean(key))) if err != nil { return errors.Wrap(err, "ocfs: error deleting recycle item versions") } - base, ttime, err := splitTrashKey(ref.ResourceId.OpaqueId) + base, ttime, err := splitTrashKey(key) if err != nil { return err } @@ -2000,7 +2000,7 @@ func (fs *ocfs) convertToRecycleItem(ctx context.Context, md os.FileInfo) *provi } } -func (fs *ocfs) ListRecycle(ctx context.Context, ref *provider.Reference) ([]*provider.RecycleItem, error) { +func (fs *ocfs) ListRecycle(ctx context.Context, key, path string) ([]*provider.RecycleItem, error) { // TODO check permission? on what? user must be the owner? rp, err := fs.getRecyclePath(ctx) if err != nil { @@ -2027,32 +2027,32 @@ func (fs *ocfs) ListRecycle(ctx context.Context, ref *provider.Reference) ([]*pr return items, nil } -func (fs *ocfs) RestoreRecycleItem(ctx context.Context, trashRef *provider.Reference, restoreRef *provider.Reference) error { +func (fs *ocfs) RestoreRecycleItem(ctx context.Context, key, path string, restoreRef *provider.Reference) error { // TODO check permission? on what? user must be the owner? log := appctx.GetLogger(ctx) rp, err := fs.getRecyclePath(ctx) if err != nil { return errors.Wrap(err, "ocfs: error resolving recycle path") } - src := filepath.Join(rp, filepath.Clean(trashRef.ResourceId.OpaqueId)) + src := filepath.Join(rp, filepath.Clean(key)) suffix := filepath.Ext(src) if len(suffix) == 0 || !strings.HasPrefix(suffix, ".d") { - log.Error().Str("key", trashRef.ResourceId.OpaqueId).Str("path", src).Msg("invalid trash item suffix") + log.Error().Str("key", key).Str("path", src).Msg("invalid trash item suffix") return nil } if restoreRef.Path == "" { v, err := xattr.Get(src, trashOriginPrefix) if err != nil { - log.Error().Err(err).Str("key", trashRef.ResourceId.OpaqueId).Str("path", src).Msg("could not read origin") + log.Error().Err(err).Str("key", key).Str("path", src).Msg("could not read origin") } restoreRef.Path = filepath.Join("/", filepath.Clean(string(v)), strings.TrimSuffix(filepath.Base(src), suffix)) } tgt := fs.toInternalPath(ctx, restoreRef.Path) // move back to original location if err := os.Rename(src, tgt); err != nil { - log.Error().Err(err).Str("key", trashRef.ResourceId.OpaqueId).Str("restorePath", restoreRef.Path).Str("src", src).Str("tgt", tgt).Msg("could not restore item") + log.Error().Err(err).Str("key", key).Str("restorePath", restoreRef.Path).Str("src", src).Str("tgt", tgt).Msg("could not restore item") return errors.Wrap(err, "ocfs: could not restore item") } diff --git a/pkg/storage/fs/s3/s3.go b/pkg/storage/fs/s3/s3.go index d2494fbbf0b..cab0463f72b 100644 --- a/pkg/storage/fs/s3/s3.go +++ b/pkg/storage/fs/s3/s3.go @@ -646,7 +646,7 @@ func (fs *s3FS) RestoreRevision(ctx context.Context, ref *provider.Reference, re return errtypes.NotSupported("restore revision") } -func (fs *s3FS) PurgeRecycleItem(ctx context.Context, ref *provider.Reference) error { +func (fs *s3FS) PurgeRecycleItem(ctx context.Context, key, path string) error { return errtypes.NotSupported("purge recycle item") } @@ -654,10 +654,10 @@ func (fs *s3FS) EmptyRecycle(ctx context.Context) error { return errtypes.NotSupported("empty recycle") } -func (fs *s3FS) ListRecycle(ctx context.Context, ref *provider.Reference) ([]*provider.RecycleItem, error) { +func (fs *s3FS) ListRecycle(ctx context.Context, key, path string) ([]*provider.RecycleItem, error) { return nil, errtypes.NotSupported("list recycle") } -func (fs *s3FS) RestoreRecycleItem(ctx context.Context, trashRef *provider.Reference, restoreRef *provider.Reference) error { +func (fs *s3FS) RestoreRecycleItem(ctx context.Context, key, path string, restoreRef *provider.Reference) error { return errtypes.NotSupported("restore recycle") } diff --git a/pkg/storage/storage.go b/pkg/storage/storage.go index 401116daade..91a0e1a7b65 100644 --- a/pkg/storage/storage.go +++ b/pkg/storage/storage.go @@ -42,9 +42,9 @@ type FS interface { ListRevisions(ctx context.Context, ref *provider.Reference) ([]*provider.FileVersion, error) DownloadRevision(ctx context.Context, ref *provider.Reference, key string) (io.ReadCloser, error) RestoreRevision(ctx context.Context, ref *provider.Reference, key string) error - ListRecycle(ctx context.Context, ref *provider.Reference) ([]*provider.RecycleItem, error) - RestoreRecycleItem(ctx context.Context, trashRef *provider.Reference, restoreRef *provider.Reference) error - PurgeRecycleItem(ctx context.Context, ref *provider.Reference) error + ListRecycle(ctx context.Context, key, path string) ([]*provider.RecycleItem, error) + RestoreRecycleItem(ctx context.Context, key, path string, restoreRef *provider.Reference) error + PurgeRecycleItem(ctx context.Context, key, path string) error EmptyRecycle(ctx context.Context) error GetPathByID(ctx context.Context, id *provider.ResourceId) (string, error) AddGrant(ctx context.Context, ref *provider.Reference, g *provider.Grant) error diff --git a/pkg/storage/utils/decomposedfs/recycle.go b/pkg/storage/utils/decomposedfs/recycle.go index 51b107f7515..d5a0d38929b 100644 --- a/pkg/storage/utils/decomposedfs/recycle.go +++ b/pkg/storage/utils/decomposedfs/recycle.go @@ -46,7 +46,7 @@ import ( // contain a directory with symlinks to trash files for every userid/"root" // ListRecycle returns the list of available recycle items -func (fs *Decomposedfs) ListRecycle(ctx context.Context, ref *provider.Reference) ([]*provider.RecycleItem, error) { +func (fs *Decomposedfs) ListRecycle(ctx context.Context, key, path string) ([]*provider.RecycleItem, error) { log := appctx.GetLogger(ctx) items := make([]*provider.RecycleItem, 0) @@ -65,12 +65,12 @@ func (fs *Decomposedfs) ListRecycle(ctx context.Context, ref *provider.Reference } } - if ref.Path == "/" { + if path == "/" { return fs.listTrashRoot(ctx) } trashRoot := fs.getRecycleRoot(ctx) - f, err := os.Open(filepath.Join(trashRoot, ref.Path)) + f, err := os.Open(filepath.Join(trashRoot, key, path)) if err != nil { if os.IsNotExist(err) { return items, nil @@ -79,8 +79,7 @@ func (fs *Decomposedfs) ListRecycle(ctx context.Context, ref *provider.Reference } defer f.Close() - root, tail := shiftPath(ref.Path) - parentNode, err := os.Readlink(filepath.Join(trashRoot, root)) + parentNode, err := os.Readlink(filepath.Join(trashRoot, key)) if err != nil { log.Error().Err(err).Str("trashRoot", trashRoot).Msg("error reading trash link, skipping") return nil, err @@ -90,7 +89,7 @@ func (fs *Decomposedfs) ListRecycle(ctx context.Context, ref *provider.Reference return nil, err } else if !md.IsDir() { // this is the case when we want to directly list a file in the trashbin - item, err := fs.createTrashItem(ctx, parentNode, filepath.Dir(tail), filepath.Join(trashRoot, ref.Path)) + item, err := fs.createTrashItem(ctx, parentNode, filepath.Dir(path), filepath.Join(trashRoot, key, path)) if err != nil { return items, err } @@ -103,7 +102,7 @@ func (fs *Decomposedfs) ListRecycle(ctx context.Context, ref *provider.Reference return nil, err } for i := range names { - if item, err := fs.createTrashItem(ctx, parentNode, tail, filepath.Join(trashRoot, ref.Path, names[i])); err == nil { + if item, err := fs.createTrashItem(ctx, parentNode, path, filepath.Join(trashRoot, key, path, names[i])); err == nil { items = append(items, item) } } @@ -259,11 +258,11 @@ func (fs *Decomposedfs) listTrashRoot(ctx context.Context) ([]*provider.RecycleI } // RestoreRecycleItem restores the specified item -func (fs *Decomposedfs) RestoreRecycleItem(ctx context.Context, trashRef *provider.Reference, restoreRef *provider.Reference) error { +func (fs *Decomposedfs) RestoreRecycleItem(ctx context.Context, key, path string, restoreRef *provider.Reference) error { if restoreRef == nil { restoreRef = &provider.Reference{} } - rn, restoreFunc, err := fs.tp.RestoreRecycleItemFunc(ctx, trashRef.ResourceId.OpaqueId, trashRef.Path, restoreRef.Path) + rn, restoreFunc, err := fs.tp.RestoreRecycleItemFunc(ctx, key, path, restoreRef.Path) if err != nil { return err } @@ -276,7 +275,7 @@ func (fs *Decomposedfs) RestoreRecycleItem(ctx context.Context, trashRef *provid case err != nil: return errtypes.InternalError(err.Error()) case !ok: - return errtypes.PermissionDenied(trashRef.ResourceId.OpaqueId) + return errtypes.PermissionDenied(key) } // Run the restore func @@ -284,8 +283,8 @@ func (fs *Decomposedfs) RestoreRecycleItem(ctx context.Context, trashRef *provid } // PurgeRecycleItem purges the specified item -func (fs *Decomposedfs) PurgeRecycleItem(ctx context.Context, ref *provider.Reference) error { - rn, purgeFunc, err := fs.tp.PurgeRecycleItemFunc(ctx, ref.ResourceId.OpaqueId, ref.Path) +func (fs *Decomposedfs) PurgeRecycleItem(ctx context.Context, key, path string) error { + rn, purgeFunc, err := fs.tp.PurgeRecycleItemFunc(ctx, key, path) if err != nil { return err } @@ -298,7 +297,7 @@ func (fs *Decomposedfs) PurgeRecycleItem(ctx context.Context, ref *provider.Refe case err != nil: return errtypes.InternalError(err.Error()) case !ok: - return errtypes.PermissionDenied(ref.ResourceId.OpaqueId) + return errtypes.PermissionDenied(key) } // Run the purge func @@ -333,20 +332,3 @@ func (fs *Decomposedfs) getRecycleRoot(ctx context.Context) string { } return filepath.Join(fs.o.Root, "trash", "root") } - -// shiftPath splits off the first component of p, which will be cleaned of -// relative components before processing. head will never contain a slash and -// tail will always be a rooted path without trailing slash. -// see https://blog.merovius.de/2017/06/18/how-not-to-use-an-http-router.html -// and https://gist.github.com/weatherglass/62bd8a704d4dfdc608fe5c5cb5a6980c#gistcomment-2161690 for the zero alloc code below -func shiftPath(p string) (head, tail string) { - if p == "" { - return "", "/" - } - p = strings.TrimPrefix(path.Clean(p), "/") - i := strings.Index(p, "/") - if i < 0 { - return p, "/" - } - return p[:i], p[i:] -} diff --git a/pkg/storage/utils/eosfs/eosfs.go b/pkg/storage/utils/eosfs/eosfs.go index ef071bc6059..4bc20d01c61 100644 --- a/pkg/storage/utils/eosfs/eosfs.go +++ b/pkg/storage/utils/eosfs/eosfs.go @@ -1362,7 +1362,7 @@ func (fs *eosfs) RestoreRevision(ctx context.Context, ref *provider.Reference, r return fs.c.RollbackToVersion(ctx, uid, gid, fn, revisionKey) } -func (fs *eosfs) PurgeRecycleItem(ctx context.Context, ref *provider.Reference) error { +func (fs *eosfs) PurgeRecycleItem(ctx context.Context, key, itemPath string) error { return errtypes.NotSupported("eosfs: operation not supported") } @@ -1380,7 +1380,7 @@ func (fs *eosfs) EmptyRecycle(ctx context.Context) error { return fs.c.PurgeDeletedEntries(ctx, uid, gid) } -func (fs *eosfs) ListRecycle(ctx context.Context, ref *provider.Reference) ([]*provider.RecycleItem, error) { +func (fs *eosfs) ListRecycle(ctx context.Context, key, itemPath string) ([]*provider.RecycleItem, error) { u, err := getUser(ctx) if err != nil { return nil, errors.Wrap(err, "eosfs: no user in ctx") @@ -1411,7 +1411,7 @@ func (fs *eosfs) ListRecycle(ctx context.Context, ref *provider.Reference) ([]*p return recycleEntries, nil } -func (fs *eosfs) RestoreRecycleItem(ctx context.Context, trashRef *provider.Reference, restoreRef *provider.Reference) error { +func (fs *eosfs) RestoreRecycleItem(ctx context.Context, key, itemPath string, restoreRef *provider.Reference) error { u, err := getUser(ctx) if err != nil { return errors.Wrap(err, "eosfs: no user in ctx") @@ -1422,7 +1422,7 @@ func (fs *eosfs) RestoreRecycleItem(ctx context.Context, trashRef *provider.Refe return err } - return fs.c.RestoreDeletedEntry(ctx, uid, gid, trashRef.ResourceId.OpaqueId) + return fs.c.RestoreDeletedEntry(ctx, uid, gid, key) } func (fs *eosfs) convertToRecycleItem(ctx context.Context, eosDeletedItem *eosclient.DeletedEntry) (*provider.RecycleItem, error) { diff --git a/pkg/storage/utils/localfs/localfs.go b/pkg/storage/utils/localfs/localfs.go index a4c526a61a6..8c3690fa846 100644 --- a/pkg/storage/utils/localfs/localfs.go +++ b/pkg/storage/utils/localfs/localfs.go @@ -1131,8 +1131,8 @@ func (fs *localfs) RestoreRevision(ctx context.Context, ref *provider.Reference, return fs.propagate(ctx, np) } -func (fs *localfs) PurgeRecycleItem(ctx context.Context, ref *provider.Reference) error { - rp := fs.wrapRecycleBin(ctx, ref.ResourceId.OpaqueId) +func (fs *localfs) PurgeRecycleItem(ctx context.Context, key, itemPath string) error { + rp := fs.wrapRecycleBin(ctx, key) if err := os.Remove(rp); err != nil { return errors.Wrap(err, "localfs: error deleting recycle item") @@ -1181,7 +1181,7 @@ func (fs *localfs) convertToRecycleItem(ctx context.Context, rp string, md os.Fi } } -func (fs *localfs) ListRecycle(ctx context.Context, ref *provider.Reference) ([]*provider.RecycleItem, error) { +func (fs *localfs) ListRecycle(ctx context.Context, key, path string) ([]*provider.RecycleItem, error) { rp := fs.wrapRecycleBin(ctx, "/") @@ -1199,14 +1199,14 @@ func (fs *localfs) ListRecycle(ctx context.Context, ref *provider.Reference) ([] return items, nil } -func (fs *localfs) RestoreRecycleItem(ctx context.Context, trashRef *provider.Reference, restoreRef *provider.Reference) error { +func (fs *localfs) RestoreRecycleItem(ctx context.Context, key, itemPath string, restoreRef *provider.Reference) error { - suffix := path.Ext(trashRef.ResourceId.OpaqueId) + suffix := path.Ext(key) if len(suffix) == 0 || !strings.HasPrefix(suffix, ".d") { return errors.New("localfs: invalid trash item suffix") } - filePath, err := fs.getRecycledEntry(ctx, trashRef.ResourceId.OpaqueId) + filePath, err := fs.getRecycledEntry(ctx, key) if err != nil { return errors.Wrap(err, "localfs: invalid key") } @@ -1225,10 +1225,10 @@ func (fs *localfs) RestoreRecycleItem(ctx context.Context, trashRef *provider.Re return errors.New("localfs: can't restore - file already exists at original path") } - rp := fs.wrapRecycleBin(ctx, trashRef.ResourceId.OpaqueId) + rp := fs.wrapRecycleBin(ctx, key) if _, err = os.Stat(rp); err != nil { if os.IsNotExist(err) { - return errtypes.NotFound(trashRef.ResourceId.OpaqueId) + return errtypes.NotFound(key) } return errors.Wrap(err, "localfs: error stating "+rp) } @@ -1237,7 +1237,7 @@ func (fs *localfs) RestoreRecycleItem(ctx context.Context, trashRef *provider.Re return errors.Wrap(err, "ocfs: could not restore item") } - err = fs.removeFromRecycledDB(ctx, trashRef.ResourceId.OpaqueId) + err = fs.removeFromRecycledDB(ctx, key) if err != nil { return errors.Wrap(err, "localfs: error adding entry to DB") }