Skip to content

Commit

Permalink
Add the remove_all function.
Browse files Browse the repository at this point in the history
  • Loading branch information
aert committed Jul 12, 2019
1 parent 9c7363d commit f033dc3
Show file tree
Hide file tree
Showing 4 changed files with 82 additions and 31 deletions.
10 changes: 10 additions & 0 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -32,10 +32,20 @@ pub enum Error {
},
}

/// Removes a single file.
pub fn remove<T: AsRef<Path>>(path: T) -> Result<(), Error> {
platform::remove(path)
}

/// Removes all files specified by the collection of paths provided as an argument.
pub fn remove_all<I, T>(paths: I) -> Result<(), Error>
where
I: IntoIterator<Item = T>,
T: AsRef<Path>,
{
platform::remove_all(paths)
}

pub fn is_implemented() -> bool {
platform::is_implemented()
}
35 changes: 24 additions & 11 deletions src/linux.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,18 +6,21 @@ use std::process::Command;

use crate::Error;

static DEFAULT_TRASH: &str = "gio";

pub fn is_implemented() -> bool {
true
}

/// This is based on the electron library's implementation.
/// See: https://github.com/electron/electron/blob/34c4c8d5088fa183f56baea28809de6f2a427e02/shell/common/platform_util_linux.cc#L96
pub fn remove<T: AsRef<Path>>(path: T) -> Result<(), Error> {
static DEFAULT_TRASH: &str = "gio";

let full_path = path
.as_ref()
.canonicalize()
pub fn remove_all<I, T>(paths: I) -> Result<(), Error>
where
I: IntoIterator<Item = T>,
T: AsRef<Path>,
{
let paths = paths.into_iter();
let full_paths = paths
.map(|x| x.as_ref().canonicalize())
.collect::<Result<Vec<_>, _>>()
.map_err(|e| Error::CanonicalizePath {
code: e.raw_os_error(),
})?;
Expand All @@ -35,17 +38,21 @@ pub fn remove<T: AsRef<Path>>(path: T) -> Result<(), Error> {
}
};

let mut argv = Vec::<OsString>::new();
let mut argv = Vec::<OsString>::with_capacity(full_paths.len() + 2);

if trash == "kioclient5" || trash == "kioclient" {
//argv.push(trash.into());
argv.push("move".into());
argv.push(full_path.into());
for full_path in full_paths.iter() {
argv.push(full_path.into());
}
argv.push("trash:/".into());
} else {
//argv.push_back(ELECTRON_DEFAULT_TRASH);
argv.push("trash".into());
argv.push(full_path.into());
for full_path in full_paths.iter() {
argv.push(full_path.into());
}
}

// Execute command
Expand All @@ -62,6 +69,12 @@ pub fn remove<T: AsRef<Path>>(path: T) -> Result<(), Error> {
Ok(())
}

/// This is based on the electron library's implementation.
/// See: https://github.com/electron/electron/blob/34c4c8d5088fa183f56baea28809de6f2a427e02/shell/common/platform_util_linux.cc#L96
pub fn remove<T: AsRef<Path>>(path: T) -> Result<(), Error> {
remove_all(&[path])
}

#[derive(PartialEq)]
enum DesktopEnvironment {
Other,
Expand Down
17 changes: 16 additions & 1 deletion src/tests.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
use crate::remove;
use crate::{remove, remove_all};
use std::fs::File;

#[test]
Expand All @@ -9,3 +9,18 @@ fn create_remove() {
remove(path).unwrap();
assert!(File::open(path).is_err());
}

#[test]
fn create_multiple_remove_all() {
let count: usize = 3;

let paths: Vec<_> = (0..count).map(|i| format!("test_file_to_remove_{}", i)).collect();
for path in paths.iter() {
File::create(path).unwrap();
}

remove_all(&paths).unwrap();
for path in paths.iter() {
assert!(File::open(path).is_err());
}
}
51 changes: 32 additions & 19 deletions src/windows.rs
Original file line number Diff line number Diff line change
Expand Up @@ -19,32 +19,40 @@ pub fn is_implemented() -> bool {
true
}

/// See https://docs.microsoft.com/en-us/windows/win32/api/shellapi/ns-shellapi-_shfileopstructa
pub fn remove<T: AsRef<Path>>(path: T) -> Result<(), Error> {
let canonical = path
.as_ref()
.canonicalize()
pub fn remove_all<I, T>(paths: I) -> Result<(), Error>
where
I: IntoIterator<Item = T>,
T: AsRef<Path>,
{
let paths = paths.into_iter();
let full_paths = paths
.map(|x| x.as_ref().canonicalize())
.collect::<Result<Vec<_>, _>>()
.map_err(|e| Error::CanonicalizePath {
code: e.raw_os_error(),
})?;
let mut from = OsString::from(canonical);
from.push("\0\0"); // The string has to be double zero terminated.

let mut encode_wide = from.as_os_str().encode_wide();

// Remove the "\\?\" prefix as `SHFileOperationW` fails if such a prefix is part of the path.
// See:
// https://docs.microsoft.com/en-us/windows/win32/api/shellapi/ns-shellapi-_shfileopstructa
assert_eq!(encode_wide.next(), Some('\\' as u16));
assert_eq!(encode_wide.next(), Some('\\' as u16));
assert_eq!(encode_wide.next(), Some('?' as u16));
assert_eq!(encode_wide.next(), Some('\\' as u16));
let wide_path: Vec<_> = encode_wide.collect();
let mut from = OsString::new();
let mut wide_paths = Vec::with_capacity(full_paths.len());
for path in full_paths.iter() {
let mut os_string = OsString::from(canonical);
os_string.push("\0");
let mut encode_wide = os_string.as_os_str().encode_wide();
// Remove the "\\?\" prefix as `SHFileOperationW` fails if such a prefix is part of the path.
// See:
// https://docs.microsoft.com/en-us/windows/win32/api/shellapi/ns-shellapi-_shfileopstructa
assert_eq!(encode_wide.next(), Some('\\' as u16));
assert_eq!(encode_wide.next(), Some('\\' as u16));
assert_eq!(encode_wide.next(), Some('?' as u16));
assert_eq!(encode_wide.next(), Some('\\' as u16));
let mut wide_path: Vec<_> = encode_wide.collect();
wide_paths.append(&mut wide_path);
}
wide_paths.push(0); // The string has to be double zero terminated.

let mut fileop = SHFILEOPSTRUCTW {
hwnd: 0 as HWND,
wFunc: FO_DELETE as UINT,
pFrom: wide_path.as_ptr() as PCZZWSTR,
pFrom: wide_paths.as_ptr() as PCZZWSTR,
pTo: std::ptr::null(),
fFlags: FOF_ALLOWUNDO | FOF_SILENT | FOF_WANTNUKEWARNING,
fAnyOperationsAborted: 0,
Expand All @@ -60,3 +68,8 @@ pub fn remove<T: AsRef<Path>>(path: T) -> Result<(), Error> {
Err(Error::Remove { code: Some(result) })
}
}

/// See https://docs.microsoft.com/en-us/windows/win32/api/shellapi/ns-shellapi-_shfileopstructa
pub fn remove<T: AsRef<Path>>(path: T) -> Result<(), Error> {
remove_all(&[path])
}

0 comments on commit f033dc3

Please sign in to comment.