AI codebase review
fix: pin parent directory and verify owner/type before trashing Trash renamed the item by path after the confirmation dialog, so a parent directory swapped for a symlink since the scan (e.g. by another user, while an administrator cleans their home) redirected the move to an unrelated file. The parent is now opened once and the item is checked (owner and file type as scanned) and renamed relative to that fd. macOS volume trash directories now get the same ownership/symlink checks as freedesktop.org ones on Linux. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 5.5
parent
ab3ff7b842
commit
3ec5bd7e65
@@ -29,7 +29,7 @@ func Reveal(path string) error {
|
||||
// Trash moves path to the freedesktop.org trash: the home trash when on the
|
||||
// same filesystem, otherwise $topdir/.Trash-$uid on the item's filesystem.
|
||||
// It never copies across filesystems and never deletes.
|
||||
func Trash(path string) error {
|
||||
func Trash(path string, want Expect) error {
|
||||
if err := checkAbs(path); err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -99,7 +99,7 @@ func Trash(path string) error {
|
||||
os.Remove(ip)
|
||||
return errors.Join(werr, cerr)
|
||||
}
|
||||
if err := os.Rename(path, dst); err != nil {
|
||||
if err := renameChecked(path, dst, want); err != nil {
|
||||
os.Remove(ip)
|
||||
return err
|
||||
}
|
||||
@@ -108,31 +108,6 @@ func Trash(path string) error {
|
||||
return errors.New("trash: too many items with the same name")
|
||||
}
|
||||
|
||||
// ensurePrivateDir creates dir (mode 0700) if missing; an existing entry must
|
||||
// be a real directory (not a symlink) owned by us. With strict (trash on a
|
||||
// shared filesystem) it must also be inaccessible to others, as the
|
||||
// freedesktop.org spec requires; home trash directories made by desktop
|
||||
// environments are sometimes 0755, which is harmless there.
|
||||
func ensurePrivateDir(dir string, strict bool) error {
|
||||
if err := os.Mkdir(dir, 0o700); err != nil && !errors.Is(err, os.ErrExist) {
|
||||
return err
|
||||
}
|
||||
fi, err := os.Lstat(dir)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
st := fi.Sys().(*syscall.Stat_t)
|
||||
switch {
|
||||
case !fi.IsDir():
|
||||
return errors.New("not a directory (symlink?)")
|
||||
case int(st.Uid) != os.Getuid():
|
||||
return errors.New("owned by another user")
|
||||
case strict && fi.Mode().Perm()&0o077 != 0:
|
||||
return errors.New("accessible to other users")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// mountTop returns the top directory of the filesystem containing path.
|
||||
func mountTop(path string, dev uint64) string {
|
||||
cur := filepath.Dir(path)
|
||||
|
||||
Reference in New Issue
Block a user