Skip to content

Commit

Permalink
Initial
Browse files Browse the repository at this point in the history
  • Loading branch information
ArturKovacs committed Jul 3, 2019
0 parents commit 4c23314
Show file tree
Hide file tree
Showing 8 changed files with 150 additions and 0 deletions.
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
/target
**/*.rs.bk
Cargo.lock
10 changes: 10 additions & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
[package]
name = "trash"
version = "0.1.0"
authors = ["Artur Kovacs <kovacs.artur.barnabas@gmail.com>"]
edition = "2018"

[dependencies]

[target.'cfg(windows)'.dependencies]
winapi = { version = "0.3.7", features = ["shellapi", "winerror"] }
6 changes: 6 additions & 0 deletions Readme.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@

## About

Trash is a Rust library that provides functionality to move files to the operating system's Recycle Bin.

Note that this libaray is in early development. It is planned to be multi-platform but I only have a Windows and a Linux system, so creating a pull request with MacOS support would be very much appretiated.
41 changes: 41 additions & 0 deletions src/lib.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
use std::path::Path;

#[cfg(test)]
mod tests;

#[cfg(windows)]
#[path = "windows.rs"]
mod platform;

#[cfg(linux)]
#[path = "linux.rs"]
mod platform;

#[cfg(macos)]
#[path = "macos.rs"]
mod platform;

use platform::*;

#[derive(Debug)]
pub enum Error {
Unknown,

/// Error while canonicalizing path
CanonicalizePath {
code: Option<i32>,
},

/// Error while performing the remove operation
Remove {
code: i32,
},
}

pub fn remove<T: AsRef<Path>>(path: T) -> Result<(), Error> {
platform_remove(path)
}

pub fn is_implemented() -> bool {
platform::is_implemented()
}
9 changes: 9 additions & 0 deletions src/linux.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@

pub fn is_implemented() -> bool {
false
}

pub fn platform_remove<T: AsRef<Path>>(path: T) -> Result<(), Error> {
unimplemented!();
}

8 changes: 8 additions & 0 deletions src/macos.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@

pub fn is_implemented() -> bool {
false
}

pub fn platform_remove<T: AsRef<Path>>(path: T) -> Result<(), Error> {
unimplemented!();
}
11 changes: 11 additions & 0 deletions src/tests.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
use crate::remove;
use std::fs::File;

#[test]
fn create_remove() {
let path = "test_file_to_remove";
File::create(path).unwrap();

remove(path).unwrap();
assert!(File::open(path).is_err());
}
62 changes: 62 additions & 0 deletions src/windows.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
use std::ffi::OsString;
use std::os::windows::ffi::OsStrExt;
use std::path::Path;

use winapi::{
shared::minwindef::UINT,
shared::windef::HWND,
shared::winerror::S_OK,
um::shellapi::{
SHFileOperationW, FOF_ALLOWUNDO, FOF_SILENT, FOF_WANTNUKEWARNING, FO_DELETE,
SHFILEOPSTRUCTW,
},
um::winnt::PCZZWSTR,
};

use crate::Error;

pub fn is_implemented() -> bool {
true
}

/// See https://docs.microsoft.com/en-us/windows/win32/api/shellapi/ns-shellapi-_shfileopstructa
pub fn platform_remove<T: AsRef<Path>>(path: T) -> Result<(), Error> {
let canonical = path
.as_ref()
.canonicalize()
.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 fileop = SHFILEOPSTRUCTW {
hwnd: 0 as HWND,
wFunc: FO_DELETE as UINT,
pFrom: wide_path.as_ptr() as PCZZWSTR,
pTo: std::ptr::null(),
fFlags: FOF_ALLOWUNDO | FOF_SILENT | FOF_WANTNUKEWARNING,
fAnyOperationsAborted: 0,
hNameMappings: std::ptr::null_mut(),
lpszProgressTitle: std::ptr::null(),
};

let result = unsafe { SHFileOperationW(&mut fileop as *mut SHFILEOPSTRUCTW) };

if result == S_OK {
Ok(())
} else {
Err(Error::Remove { code: result })
}
}

0 comments on commit 4c23314

Please sign in to comment.