linux: Prevent target file from being trashed when trashing symlink (#22704)

Closes #22399

Currently, the target file is being trashed when trashing a symlink, and
the symlink remains intact. Symlinks are not handled separately yet, so
when `open` is used on a symlink, it gets resolved to the target file.

To fix this, we can get the file descriptor of the symlink by passing
`libc::O_PATH | libc::O_NOFOLLOW` flags to `open`, and then pass this
file descriptor to the existing `trash::trash_file` from `ashpd`.
However, this would result in an error because `ashpd` currently does
not support trashing symlink files. I have created an issue for it here:
[https://github.com/bilelmoussaoui/ashpd/issues/255](https://github.com/bilelmoussaoui/ashpd/issues/255).

For the time being, this PR partially fixes the issue by removing the
symlink without trashing so that the target file won't be affected. Once
the upstream bug is fixed, we can switch this remove action back to
trashing.

Release Notes:

- Fixed target file from being trashed when trashing symlink on Linux.
This commit is contained in:
tims 2025-01-07 05:43:16 +05:30 committed by GitHub
parent d2d1779e0d
commit 7d0c571a8f
No known key found for this signature in database
GPG key ID: B5690EEEBB952194

View file

@ -11,8 +11,7 @@ use git::GitHostingProviderRegistry;
use ashpd::desktop::trash;
#[cfg(any(target_os = "linux", target_os = "freebsd"))]
use smol::process::Command;
#[cfg(any(target_os = "linux", target_os = "freebsd"))]
use std::fs::File;
#[cfg(unix)]
use std::os::fd::AsFd;
#[cfg(unix)]
@ -445,7 +444,13 @@ impl Fs for RealFs {
#[cfg(any(target_os = "linux", target_os = "freebsd"))]
async fn trash_file(&self, path: &Path, _options: RemoveOptions) -> Result<()> {
let file = File::open(path)?;
if let Ok(Some(metadata)) = self.metadata(path).await {
if metadata.is_symlink {
// TODO: trash_file does not support trashing symlinks yet - https://github.com/bilelmoussaoui/ashpd/issues/255
return self.remove_file(path, RemoveOptions::default()).await;
}
}
let file = smol::fs::File::open(path).await?;
match trash::trash_file(&file.as_fd()).await {
Ok(_) => Ok(()),
Err(err) => Err(anyhow::Error::new(err)),