Skip to content

Commit

Permalink
Fix for failing to delete files on Freedesktop systems (eg Linux) (#34)
Browse files Browse the repository at this point in the history
* Fix for failing to delete files on Linux #30

* Fix clippy warnings

* Fix clippy warnings
  • Loading branch information
ArturKovacs committed Aug 15, 2021
1 parent 2a1eaf8 commit bd8679c
Show file tree
Hide file tree
Showing 2 changed files with 51 additions and 17 deletions.
5 changes: 5 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,11 @@

Dates are specified in YYYY-MM-DD format.

# Unreleased

## Changed
- Fix failing to delete files on some freedesktop (eg Linux) systems when the home was not mounted at the root.

# v2.0.1 on 2021-05-02

## Changed
Expand Down
63 changes: 46 additions & 17 deletions src/freedesktop.rs
Original file line number Diff line number Diff line change
Expand Up @@ -30,25 +30,17 @@ impl PlatformTrashContext {
}
impl TrashContext {
pub(crate) fn delete_all_canonicalized(&self, full_paths: Vec<PathBuf>) -> Result<(), Error> {
let root = Path::new("/");
let home_trash = home_trash()?;
let mount_points = get_mount_points()?;
let home_topdir = home_topdir(&mount_points)?;
debug!("The home topdir is {:?}", home_topdir);
let uid = unsafe { libc::getuid() };
for path in full_paths {
debug!("Deleting {:?}", path);
let mut topdir = None;
for mount_point in mount_points.iter() {
if mount_point.mnt_dir == root {
continue;
}
if path.starts_with(&mount_point.mnt_dir) {
topdir = Some(&mount_point.mnt_dir);
break;
}
}
let topdir = if let Some(t) = topdir { t } else { root };
let topdir = get_topdir_for_path(&path, &mount_points);
debug!("The topdir of this file is {:?}", topdir);
if topdir == root {
if topdir == home_topdir {
debug!("The topdir was identical to the home topdir, so moving to the home trash.");
// Note that the following function creates the trash folder
// and its required subfolders in case they don't exist.
move_to_trash(path, &home_trash, topdir)?;
Expand Down Expand Up @@ -470,7 +462,7 @@ where
}
} else {
// Symlink or file
file(&src, &dst)?;
file(src, dst)?;
}
Ok(())
}
Expand Down Expand Up @@ -567,6 +559,43 @@ fn home_trash() -> Result<PathBuf, Error> {
})
}

fn home_topdir(mnt_points: &[MountPoint]) -> Result<PathBuf, Error> {
if let Some(data_home) = std::env::var_os("XDG_DATA_HOME") {
if data_home.len() > 0 {
let data_home_path = AsRef::<Path>::as_ref(data_home.as_os_str());
return Ok(get_topdir_for_path(data_home_path, mnt_points).to_owned());
}
}
if let Some(home) = std::env::var_os("HOME") {
if home.len() > 0 {
let home_path = AsRef::<Path>::as_ref(home.as_os_str());
return Ok(get_topdir_for_path(home_path, mnt_points).to_owned());
}
}
Err(Error::Unknown {
description: "Neither the XDG_DATA_HOME nor the HOME environment variable was found".into(),
})
}

fn get_topdir_for_path<'a>(path: &Path, mnt_points: &'a [MountPoint]) -> &'a Path {
let root: &'static Path = Path::new("/");
let mut topdir = None;
for mount_point in mnt_points.iter() {
if mount_point.mnt_dir == root {
continue;
}
if path.starts_with(&mount_point.mnt_dir) {
topdir = Some(&mount_point.mnt_dir);
break;
}
}
if let Some(t) = topdir {
t
} else {
root
}
}

struct MountPoint {
mnt_dir: PathBuf,
_mnt_type: String,
Expand All @@ -579,11 +608,11 @@ fn get_mount_points() -> Result<Vec<MountPoint>, Error> {
let mounts_path = CString::new("/proc/mounts").unwrap();
let mut file =
unsafe { libc::fopen(mounts_path.as_c_str().as_ptr(), read_arg.as_c_str().as_ptr()) };
if file == std::ptr::null_mut() {
if file.is_null() {
let mtab_path = CString::new("/etc/mtab").unwrap();
file = unsafe { libc::fopen(mtab_path.as_c_str().as_ptr(), read_arg.as_c_str().as_ptr()) };
}
if file == std::ptr::null_mut() {
if file.is_null() {
return Err(Error::Unknown {
description: "Neither '/proc/mounts' nor '/etc/mtab' could be opened.".into(),
});
Expand All @@ -592,7 +621,7 @@ fn get_mount_points() -> Result<Vec<MountPoint>, Error> {
let mut result = Vec::new();
loop {
let mntent = unsafe { libc::getmntent(file) };
if mntent == std::ptr::null_mut() {
if mntent.is_null() {
break;
}
let dir = unsafe { CStr::from_ptr((*mntent).mnt_dir).to_str().unwrap() };
Expand Down

0 comments on commit bd8679c

Please sign in to comment.