Skip to content

Commit

Permalink
Handle file id clashes when a file/dir was copied/restored with xattrs
Browse files Browse the repository at this point in the history
  • Loading branch information
aduffeck committed Aug 20, 2024
1 parent eb189d0 commit 937e7fc
Showing 1 changed file with 66 additions and 43 deletions.
109 changes: 66 additions & 43 deletions pkg/storage/fs/posix/tree/assimilation.go
Original file line number Diff line number Diff line change
Expand Up @@ -338,56 +338,69 @@ func (t *Tree) assimilate(item scanItem) error {
id, err = t.lookup.MetadataBackend().Get(context.Background(), item.Path, prefixes.IDAttr)
if err == nil {
previousPath, ok := t.lookup.(*lookup.Lookup).GetCachedID(context.Background(), spaceID, string(id))

// This item had already been assimilated in the past. Update the path
_ = t.lookup.(*lookup.Lookup).CacheID(context.Background(), spaceID, string(id), item.Path)

previousParentID, _ := t.lookup.MetadataBackend().Get(context.Background(), item.Path, prefixes.ParentidAttr)

fi, err := t.updateFile(item.Path, string(id), spaceID)
if err != nil {
return err
}

// was it moved?
// was it moved or copied/restored with a clashing id?
if ok && len(previousParentID) > 0 && previousPath != item.Path {
// purge original metadata. Only delete the path entry using DeletePath(reverse lookup), not the whole entry pair.
_ = t.lookup.(*lookup.Lookup).IDCache.DeletePath(context.Background(), previousPath)
_ = t.lookup.MetadataBackend().Purge(previousPath)

if fi.IsDir() {
// if it was moved and it is a directory we need to propagate the move
go func() { _ = t.WarmupIDCache(item.Path, false) }()
}
_, err := os.Stat(previousPath)
if err == nil {
// this id clashes with an existing id -> clear metadata and re-assimilate

t.lookup.MetadataBackend().Purge(context.Background(), item.Path)
go func() {
_ = t.assimilate(scanItem{Path: item.Path, ForceRescan: true})
}()
} else {
// this is a move
// purge original metadata. Only delete the path entry using DeletePath(reverse lookup), not the whole entry pair.
_ = t.lookup.(*lookup.Lookup).IDCache.DeletePath(context.Background(), previousPath)
_ = t.lookup.MetadataBackend().Purge(context.Background(), previousPath)

parentID, err := t.lookup.MetadataBackend().Get(context.Background(), item.Path, prefixes.ParentidAttr)
if err == nil && len(parentID) > 0 {
ref := &provider.Reference{
ResourceId: &provider.ResourceId{
StorageId: t.options.MountID,
SpaceId: spaceID,
OpaqueId: string(parentID),
},
Path: filepath.Base(item.Path),
fi, err := os.Stat(item.Path)
if err != nil {
return err
}
oldRef := &provider.Reference{
ResourceId: &provider.ResourceId{
StorageId: t.options.MountID,
SpaceId: spaceID,
OpaqueId: string(previousParentID),
},
Path: filepath.Base(previousPath),
if fi.IsDir() {
// if it was moved and it is a directory we need to propagate the move
go func() { _ = t.WarmupIDCache(item.Path, false) }()
}

parentID, err := t.lookup.MetadataBackend().Get(context.Background(), item.Path, prefixes.ParentidAttr)
if err == nil && len(parentID) > 0 {
ref := &provider.Reference{
ResourceId: &provider.ResourceId{
StorageId: t.options.MountID,
SpaceId: spaceID,
OpaqueId: string(parentID),
},
Path: filepath.Base(item.Path),
}
oldRef := &provider.Reference{
ResourceId: &provider.ResourceId{
StorageId: t.options.MountID,
SpaceId: spaceID,
OpaqueId: string(previousParentID),
},
Path: filepath.Base(previousPath),
}
t.PublishEvent(events.ItemMoved{
SpaceOwner: user,
Executant: user,
Owner: user,
Ref: ref,
OldReference: oldRef,
Timestamp: utils.TSNow(),
})
}
t.PublishEvent(events.ItemMoved{
SpaceOwner: user,
Executant: user,
Owner: user,
Ref: ref,
OldReference: oldRef,
Timestamp: utils.TSNow(),
})
}
// }
} else {
// This item had already been assimilated in the past. Update the path
_ = t.lookup.(*lookup.Lookup).CacheID(context.Background(), spaceID, string(id), item.Path)

_, err := t.updateFile(item.Path, string(id), spaceID)
if err != nil {
return err
}
}
} else {
// assimilate new file
Expand Down Expand Up @@ -584,6 +597,16 @@ func (t *Tree) WarmupIDCache(root string, assimilate bool) error {

id, ok := attribs[prefixes.IDAttr]
if ok {
// Check if the item on the previous still exists. In this case it might have been a copy with extended attributes -> set new ID
previousPath, ok := t.lookup.(*lookup.Lookup).GetCachedID(context.Background(), string(spaceID), string(id))
if ok && previousPath != path {
// this id clashes with an existing id -> clear metadata and re-assimilate
_, err := os.Stat(previousPath)
if err == nil {
t.lookup.MetadataBackend().Purge(context.Background(), path)
_ = t.assimilate(scanItem{Path: path, ForceRescan: true})
}
}
_ = t.lookup.(*lookup.Lookup).CacheID(context.Background(), string(spaceID), string(id), path)
}
} else if assimilate {
Expand Down

0 comments on commit 937e7fc

Please sign in to comment.