Skip to content

Cannot find trash directory if home is symlink on Linux #98

@Tuupertunut

Description

@Tuupertunut

OS: Ubuntu 22.04
Python: 3.13
send2trash: 1.8.3

When I try to send a file in my home directory to trash, send2trash does not find the trash directory in my home in /home/username/.local/share/Trash and tries to fall back to a device specific trash. My home directory /home/username is a symlink pointing to /home/ad/lxhome/x/username/Linux for enterprise reasons. The link is on a different filesystem device than my home directory.

Why this happens:

# Pull this out so it's easy to stub (to avoid stubbing lstat itself)
def get_dev(path):
return os.lstat(path).st_dev
def send2trash(paths):
paths = preprocess_paths(paths)
for path in paths:
if isinstance(path, text_type):
path_b = fsencode(path)
elif isinstance(path, bytes):
path_b = path
else:
raise TypeError("str, bytes or PathLike expected, not %r" % type(path))
if not op.exists(path_b):
raise OSError(errno.ENOENT, "File not found: %s" % path)
# ...should check whether the user has the necessary permissions to delete
# it, before starting the trashing operation itself. [2]
if not os.access(path_b, os.W_OK):
raise OSError(errno.EACCES, "Permission denied: %s" % path)
path_dev = get_dev(path_b)
# If XDG_DATA_HOME or HOMETRASH do not yet exist we need to stat the
# home directory, and these paths will be created further on if needed.
trash_dev = get_dev(op.expanduser(b"~"))
# if the file to be trashed is on the same device as HOMETRASH we
# want to move it there.
if path_dev == trash_dev:
topdir = XDG_DATA_HOME
dest_trash = HOMETRASH_B
else:
topdir = find_mount_point(path_b)
trash_dev = get_dev(topdir)
if trash_dev != path_dev:
raise OSError("Couldn't find mount point for %s" % path)
dest_trash = find_ext_volume_trash(topdir)
try:
trash_move(path_b, dest_trash, topdir)
except OSError as error:
# Cross link errors default back to HOMETRASH
if error.errno == errno.EXDEV:
trash_move(path_b, HOMETRASH_B, XDG_DATA_HOME, cross_dev=True)
else:
raise

Here on line 198 the code tries to determine if my home is on the same device as the file to be trashed. It expands ~ to /home/username and calls get_dev() on it. On line 175 it calls os.lstat().st_dev to find the device. lstat does not follow the symlink /home/username but returns the device where the link itself is located and incorrectly determines that my home is on a different device.

How to fix:

Use os.stat() instead to determine the device of the home directory, as it follows any symbolic links it encounters. Another option would be to find the device of ~/. instead of ~.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions