Skip to content

Detect mount points using realpath #12

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 6 commits into from
May 22, 2025
Merged

Detect mount points using realpath #12

merged 6 commits into from
May 22, 2025

Conversation

kmarius
Copy link
Contributor

@kmarius kmarius commented May 18, 2025

Mountpoints are currently not detected properly, e.g. if the path contains symlinks. Consider the symlink /home/john/Data -> /mnt/data, where /mnt/data is not the same filesystem as / (assuming /home/john is in the root filesystem). Trashing /home/john/Data/a.txt will find the mount point /, because only the parents (/home/john/Data, /home/john/, /home, /) are considered.

This patch replaces checking the parents for mount points by comparing st_dev of the file to be trashed with st_dev of all mount points.

I'm not sure the removed test can be replaced usefully.

@kmarius
Copy link
Contributor Author

kmarius commented May 18, 2025

df actually checks all mount points with matching st_dev and chooses the longest shortest (?) one. Will look into it.

@umlx5h
Copy link
Owner

umlx5h commented May 18, 2025

Thanks for the PR, I'll check it later.
As I recall, I referred to trash-cli for this part of the implementation, but I wonder if trash-cli has the same problem.

@kmarius
Copy link
Contributor Author

kmarius commented May 18, 2025

I'm coming from trash-cli which is why I noticed this issue. I just checked, it essentially calls realpath on the path to take care of it. I'm not sure that that is compliant with the spec, as it will create .Trash directories outside of the filesystem root if the trashed file is in a bind-mounted subdirectory of the filesystem (I just tried that).

Surely, the definition for $topdir,

Top directory , $topdir — the directory where a file system is mounted. “/” is the top directory for the root file system, but not for the other mounted file systems. For example, separate file systems might be mounted on “/home”, “/media/flash”, etc. In this text, the designation “$topdir” is used for “any top directory”.

means the mount point of the (entire) filesystem (i.e. its root) and not a bind mount to some subtree.

Edit: If I am wrong here, then resolving symlinks and traversing the parents is the way to go.

@kmarius
Copy link
Contributor Author

kmarius commented May 18, 2025

Ok, bind mounts are kinda wonky. If I again have a mount /mnt/data, and a bind mount /mnt/a -> /mnt/data/john, when trashing /mnt/a/b.txt,
Dolphin will

  1. Create /mnt/a/.Trash-1000
  2. Move b.txt into ~/.local/Trash

Nautilus will simply offer to permanently delete the file.
All trash directories exist (in /mnt/data) and are used otherwise (e.g. when trashing /mnt/data/john/b.txt)

Edit: I found this old issue: https://gitlab.gnome.org/GNOME/glib/-/issues/251
My take-away is that .Trash* should be created in the bind-mount root (e.g. /mnt/a/.Trash* even though /mnt/data/.Trash* exists), because renaming over bind mount boundaries doesn't necessarily work. The correct mount point would have to be found via the parents (with resolving symlinks/realpath).

@kmarius kmarius changed the title Detect mount points by comparing st_dev Detect mount points using realpath May 18, 2025
Copy link
Owner

@umlx5h umlx5h left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I've confirmed that trash-cli and trashy are fine and gtrash has the problem.
I've made some comments, please check them out.

if m.Mountpoint == mountpoint {
break OUTER
}
if mounted, err := mountinfo_Mounted(candidate); err == nil && mounted {
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think an err check is needed
(If for some reason mountpoints could not be taken or something unlitely. It is better to return an error and exit early)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That seems sensible.


// iterate over the parents of the real (without symlinks) path until we find a mount point

candidate, err := realpath_Realpath(path)
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can't this library be replaced by the standard library filepath.EvalSymlink?

https://pkg.go.dev/path/filepath#EvalSymlinks

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, that works since we are passing absolute paths (I did not know about that one)

// getfsstat(2) used on Mac (BSD)
mountpoints, err := mountinfo_GetMounts(nil)

// iterate over the parents of the real (without symlinks) path until we find a mount point
Copy link
Owner

@umlx5h umlx5h May 20, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is it okay to convert to realpath if the file to be deleted is itself a link file?
We want to target the link itself for deletion, not the link destination, so we may need to skip the realpath process in the case of a link file.

So I think we need a condition to determine if path is a linked file using Lstat.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good point. I think we need to look up the real path of the dirname of the file since the trash directory only depends on the directory the file (or link) is in.

* use filepath.EvalSymlinks
* resolve only symlinks of the parent
* update trashdir_test
@umlx5h umlx5h merged commit a741836 into umlx5h:main May 22, 2025
1 of 2 checks passed
@umlx5h
Copy link
Owner

umlx5h commented May 22, 2025

Thanks. I will release it later.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants