Skip to content

Commit

Permalink
implement purging of specific files in the trash-bin
Browse files Browse the repository at this point in the history
  • Loading branch information
David Christofas committed Jun 25, 2021
1 parent d9d5609 commit 602d1ca
Show file tree
Hide file tree
Showing 12 changed files with 41 additions and 36 deletions.
2 changes: 1 addition & 1 deletion internal/grpc/services/storageprovider/storageprovider.go
Original file line number Diff line number Diff line change
Expand Up @@ -848,7 +848,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().GetResourceId().OpaqueId); err != nil {
if err := s.storage.PurgeRecycleItem(ctx, req.GetRef()); err != nil {
var st *rpc.Status
switch err.(type) {
case errtypes.IsNotFound:
Expand Down
5 changes: 3 additions & 2 deletions internal/http/services/owncloud/ocdav/trashbin.go
Original file line number Diff line number Diff line change
Expand Up @@ -134,7 +134,7 @@ func (h *TrashbinHandler) Handler(s *svc) http.Handler {
}

if r.Method == "DELETE" {
h.delete(w, r, s, u, key)
h.delete(w, r, s, u, key, r.URL.Path)
return
}

Expand Down Expand Up @@ -555,7 +555,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 string) {
func (h *TrashbinHandler) delete(w http.ResponseWriter, r *http.Request, s *svc, u *userpb.User, key, path string) {
ctx := r.Context()
ctx, span := trace.StartSpan(ctx, "erase")
defer span.End()
Expand Down Expand Up @@ -599,6 +599,7 @@ func (h *TrashbinHandler) delete(w http.ResponseWriter, r *http.Request, s *svc,
StorageId: sRes.Info.Id.StorageId,
OpaqueId: key,
},
Path: utils.MakeRelativePath(path),
},
}

Expand Down
8 changes: 4 additions & 4 deletions pkg/storage/fs/owncloud/owncloud.go
Original file line number Diff line number Diff line change
Expand Up @@ -2056,12 +2056,12 @@ func (fs *ocfs) RestoreRevision(ctx context.Context, ref *provider.Reference, re
return fs.propagate(ctx, ip)
}

func (fs *ocfs) PurgeRecycleItem(ctx context.Context, key string) error {
func (fs *ocfs) PurgeRecycleItem(ctx context.Context, ref *provider.Reference) error {
rp, err := fs.getRecyclePath(ctx)
if err != nil {
return errors.Wrap(err, "ocfs: error resolving recycle path")
}
ip := filepath.Join(rp, filepath.Clean(key))
ip := filepath.Join(rp, filepath.Clean(ref.ResourceId.OpaqueId))
// TODO check permission?

// check permissions
Expand All @@ -2082,7 +2082,7 @@ func (fs *ocfs) PurgeRecycleItem(ctx context.Context, key string) error {
if err != nil {
return errors.Wrap(err, "ocfs: error deleting recycle item")
}
err = os.RemoveAll(filepath.Join(filepath.Dir(rp), "versions", filepath.Clean(key)))
err = os.RemoveAll(filepath.Join(filepath.Dir(rp), "versions", filepath.Clean(ref.ResourceId.OpaqueId)))
if err != nil {
return errors.Wrap(err, "ocfs: error deleting recycle item versions")
}
Expand Down Expand Up @@ -2157,7 +2157,7 @@ func (fs *ocfs) ListRecycle(ctx context.Context, ref *provider.Reference) ([]*pr
}

// list files folder
mds, err := ioutil.ReadDir(rp)
mds, err := ioutil.ReadDir(filepath.Join(rp, ref.Path))
if err != nil {
log := appctx.GetLogger(ctx)
log.Debug().Err(err).Str("path", rp).Msg("trash not readable")
Expand Down
8 changes: 4 additions & 4 deletions pkg/storage/fs/owncloudsql/owncloudsql.go
Original file line number Diff line number Diff line change
Expand Up @@ -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, key string) error {
func (fs *ocfs) PurgeRecycleItem(ctx context.Context, ref *provider.Reference) error {
rp, err := fs.getRecyclePath(ctx)
if err != nil {
return errors.Wrap(err, "ocfs: error resolving recycle path")
}
ip := filepath.Join(rp, filepath.Clean(key))
ip := filepath.Join(rp, filepath.Clean(ref.ResourceId.OpaqueId))
// TODO check permission?

// check permissions
Expand All @@ -1918,12 +1918,12 @@ func (fs *ocfs) PurgeRecycleItem(ctx context.Context, key string) error {
if err != nil {
return errors.Wrap(err, "ocfs: error deleting recycle item")
}
err = os.RemoveAll(filepath.Join(filepath.Dir(rp), "versions", filepath.Clean(key)))
err = os.RemoveAll(filepath.Join(filepath.Dir(rp), "versions", filepath.Clean(ref.ResourceId.OpaqueId)))
if err != nil {
return errors.Wrap(err, "ocfs: error deleting recycle item versions")
}

base, ttime, err := splitTrashKey(key)
base, ttime, err := splitTrashKey(ref.ResourceId.OpaqueId)
if err != nil {
return err
}
Expand Down
2 changes: 1 addition & 1 deletion pkg/storage/fs/s3/s3.go
Original file line number Diff line number Diff line change
Expand Up @@ -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, key string) error {
func (fs *s3FS) PurgeRecycleItem(ctx context.Context, ref *provider.Reference) error {
return errtypes.NotSupported("purge recycle item")
}

Expand Down
2 changes: 1 addition & 1 deletion pkg/storage/storage.go
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ type FS interface {
RestoreRevision(ctx context.Context, ref *provider.Reference, key string) error
ListRecycle(ctx context.Context, ref *provider.Reference) ([]*provider.RecycleItem, error)
RestoreRecycleItem(ctx context.Context, key string, restoreRef *provider.Reference) error
PurgeRecycleItem(ctx context.Context, key string) error
PurgeRecycleItem(ctx context.Context, ref *provider.Reference) 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
Expand Down
2 changes: 1 addition & 1 deletion pkg/storage/utils/decomposedfs/decomposedfs.go
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,7 @@ type Tree interface {
Move(ctx context.Context, oldNode *node.Node, newNode *node.Node) (err error)
Delete(ctx context.Context, node *node.Node) (err error)
RestoreRecycleItemFunc(ctx context.Context, key, restorePath string) (*node.Node, func() error, error) // FIXME REFERENCE use ref instead of path
PurgeRecycleItemFunc(ctx context.Context, key string) (*node.Node, func() error, error)
PurgeRecycleItemFunc(ctx context.Context, key, purgePath string) (*node.Node, func() error, error)

WriteBlob(key string, reader io.Reader) error
ReadBlob(key string) (io.ReadCloser, error)
Expand Down
6 changes: 3 additions & 3 deletions pkg/storage/utils/decomposedfs/recycle.go
Original file line number Diff line number Diff line change
Expand Up @@ -284,8 +284,8 @@ func (fs *Decomposedfs) RestoreRecycleItem(ctx context.Context, key string, rest
}

// PurgeRecycleItem purges the specified item
func (fs *Decomposedfs) PurgeRecycleItem(ctx context.Context, key string) error {
rn, purgeFunc, err := fs.tp.PurgeRecycleItemFunc(ctx, key)
func (fs *Decomposedfs) PurgeRecycleItem(ctx context.Context, ref *provider.Reference) error {
rn, purgeFunc, err := fs.tp.PurgeRecycleItemFunc(ctx, ref.ResourceId.OpaqueId, ref.Path)
if err != nil {
return err
}
Expand All @@ -298,7 +298,7 @@ func (fs *Decomposedfs) PurgeRecycleItem(ctx context.Context, key string) error
case err != nil:
return errtypes.InternalError(err.Error())
case !ok:
return errtypes.PermissionDenied(key)
return errtypes.PermissionDenied(ref.ResourceId.OpaqueId)
}

// Run the purge func
Expand Down
32 changes: 18 additions & 14 deletions pkg/storage/utils/decomposedfs/tree/tree.go
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,6 @@ import (
"os"
"path/filepath"
"strconv"
"strings"
"time"

userpb "github.com/cs3org/go-cs3apis/cs3/identity/user/v1beta1"
Expand Down Expand Up @@ -347,7 +346,7 @@ func (t *Tree) Delete(ctx context.Context, n *node.Node) (err error) {

// RestoreRecycleItemFunc returns a node and a function to restore it from the trash
func (t *Tree) RestoreRecycleItemFunc(ctx context.Context, key, restorePath string) (*node.Node, func() error, error) {
rn, trashItem, deletedNodePath, origin, err := t.readRecycleItem(ctx, key)
rn, trashItem, deletedNodePath, origin, err := t.readRecycleItem(ctx, key, "")
if err != nil {
return nil, nil, err
}
Expand Down Expand Up @@ -397,8 +396,8 @@ func (t *Tree) RestoreRecycleItemFunc(ctx context.Context, key, restorePath stri
}

// PurgeRecycleItemFunc returns a node and a function to purge it from the trash
func (t *Tree) PurgeRecycleItemFunc(ctx context.Context, key string) (*node.Node, func() error, error) {
rn, trashItem, deletedNodePath, _, err := t.readRecycleItem(ctx, key)
func (t *Tree) PurgeRecycleItemFunc(ctx context.Context, key string, path string) (*node.Node, func() error, error) {
rn, trashItem, deletedNodePath, _, err := t.readRecycleItem(ctx, key, path)
if err != nil {
return nil, nil, err
}
Expand Down Expand Up @@ -632,25 +631,22 @@ func (t *Tree) createNode(n *node.Node, owner *userpb.UserId) (err error) {
}

// TODO refactor the returned params into Node properties? would make all the path transformations go away...
func (t *Tree) readRecycleItem(ctx context.Context, key string) (n *node.Node, trashItem string, deletedNodePath string, origin string, err error) {
func (t *Tree) readRecycleItem(ctx context.Context, key, path string) (n *node.Node, trashItem string, deletedNodePath string, origin string, err error) {
if key == "" {
return nil, "", "", "", errtypes.InternalError("key is empty")
}

u := user.ContextMustGetUser(ctx)
trashItem = filepath.Join(t.lookup.InternalRoot(), "trash", u.Id.OpaqueId, key)
trashItem = filepath.Join(t.lookup.InternalRoot(), "trash", u.Id.OpaqueId, key, path)

var link string
link, err = os.Readlink(trashItem)
if err != nil {
appctx.GetLogger(ctx).Error().Err(err).Str("trashItem", trashItem).Msg("error reading trash link")
return
}
parts := strings.SplitN(filepath.Base(link), ".T.", 2)
if len(parts) != 2 {
appctx.GetLogger(ctx).Error().Err(err).Str("trashItem", trashItem).Interface("parts", parts).Msg("malformed trash link")
return
}

nodeID := filepath.Base(link)

var attrBytes []byte
deletedNodePath = t.lookup.InternalPath(filepath.Base(link))
Expand All @@ -669,7 +665,7 @@ func (t *Tree) readRecycleItem(ctx context.Context, key string) (n *node.Node, t
return
}

n = node.New(parts[0], "", "", 0, "", owner, t.lookup)
n = node.New(nodeID, "", "", 0, "", owner, t.lookup)
// lookup blobID in extended attributes
if attrBytes, err = xattr.Get(deletedNodePath, xattrs.BlobIDAttr); err == nil {
n.BlobID = string(attrBytes)
Expand All @@ -693,9 +689,17 @@ func (t *Tree) readRecycleItem(ctx context.Context, key string) (n *node.Node, t
// get origin node
origin = "/"

trashItemRoot := filepath.Join(t.lookup.InternalRoot(), "trash", u.Id.OpaqueId, key)
rootLink, err := os.Readlink(trashItemRoot)
if err != nil {
appctx.GetLogger(ctx).Error().Err(err).Str("trashItem", trashItem).Msg("error reading trash link")
return
}

deletedNodeRootPath := t.lookup.InternalPath(filepath.Base(rootLink))
// lookup origin path in extended attributes
if attrBytes, err = xattr.Get(deletedNodePath, xattrs.TrashOriginAttr); err == nil {
origin = string(attrBytes)
if attrBytes, err = xattr.Get(deletedNodeRootPath, xattrs.TrashOriginAttr); err == nil {
origin = filepath.Join(string(attrBytes), path)
} else {
log.Error().Err(err).Str("trashItem", trashItem).Str("link", link).Str("deletedNodePath", deletedNodePath).Msg("could not read origin path, restoring to /")
}
Expand Down
4 changes: 2 additions & 2 deletions pkg/storage/utils/decomposedfs/tree/tree_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -115,7 +115,7 @@ var _ = Describe("Tree", func() {
_, err := os.Stat(trashPath)
Expect(err).ToNot(HaveOccurred())

_, purgeFunc, err := t.PurgeRecycleItemFunc(env.Ctx, n.ID)
_, purgeFunc, err := t.PurgeRecycleItemFunc(env.Ctx, n.ID, "")
Expect(err).ToNot(HaveOccurred())
Expect(purgeFunc()).To(Succeed())
})
Expand Down Expand Up @@ -203,7 +203,7 @@ var _ = Describe("Tree", func() {
_, err := os.Stat(trashPath)
Expect(err).ToNot(HaveOccurred())

_, purgeFunc, err := t.PurgeRecycleItemFunc(env.Ctx, n.ID)
_, purgeFunc, err := t.PurgeRecycleItemFunc(env.Ctx, n.ID, "")
Expect(err).ToNot(HaveOccurred())
Expect(purgeFunc()).To(Succeed())
})
Expand Down
2 changes: 1 addition & 1 deletion pkg/storage/utils/eosfs/eosfs.go
Original file line number Diff line number Diff line change
Expand Up @@ -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, key string) error {
func (fs *eosfs) PurgeRecycleItem(ctx context.Context, ref *provider.Reference) error {
return errtypes.NotSupported("eosfs: operation not supported")
}

Expand Down
4 changes: 2 additions & 2 deletions pkg/storage/utils/localfs/localfs.go
Original file line number Diff line number Diff line change
Expand Up @@ -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, key string) error {
rp := fs.wrapRecycleBin(ctx, key)
func (fs *localfs) PurgeRecycleItem(ctx context.Context, ref *provider.Reference) error {
rp := fs.wrapRecycleBin(ctx, ref.ResourceId.OpaqueId)

if err := os.Remove(rp); err != nil {
return errors.Wrap(err, "localfs: error deleting recycle item")
Expand Down

0 comments on commit 602d1ca

Please sign in to comment.