diff --git a/Cargo.toml b/Cargo.toml index 8464810..f0d691c 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,18 +1,15 @@ [package] -name = "name_exchanger_rs" -version = "1.6.0" +name = "name_exchanger_rs" +version = "2.0.0" edition = "2021" -# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [lib] crate-type = ["cdylib"] -#crate-type = ["staticlib"] -name = "name_exchanger_rs" [profile.release] -lto = true +lto = true codegen-units = 1 -opt-level = "z" -strip = true +opt-level = "z" +strip = true [dependencies] diff --git a/src/file_rename.rs b/src/file_rename.rs index e0ce7be..913e9e7 100644 --- a/src/file_rename.rs +++ b/src/file_rename.rs @@ -79,7 +79,7 @@ impl NameExchange { } ///改名具体执行部分 - pub fn rename_each(&self, is_nested: bool, file1_first: bool) -> u8 { + pub fn rename_each(&self, is_nested: bool, file1_first: bool) -> i32 { let mut path1 = self.f2.exchange.original_path.clone(); let mut final_name1 = self.f2.exchange.new_path.clone(); let mut path2 = self.f1.exchange.original_path.clone(); @@ -93,13 +93,13 @@ impl NameExchange { tmp_name2 = self.f2.exchange.pre_path.clone(); } - let get_err_or_ok = |x: io::Result<()>| -> u8 { + let get_err_or_ok = |x: io::Result<()>| -> i32 { match x { Ok(_) => 0, Err(x) => match x.kind() { - io::ErrorKind::PermissionDenied => 3, - io::ErrorKind::AlreadyExists => 4, - _ => 255, + io::ErrorKind::PermissionDenied => return 2_i32, + io::ErrorKind::AlreadyExists => return 3_i32, + _ => return 255_i32, }, } }; diff --git a/src/lib.rs b/src/lib.rs index 8e84693..b7fc5b4 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,5 +1,7 @@ -use std::ffi::{c_char, CStr}; -use std::path::PathBuf; +use std::{ + ffi::{c_char, CStr}, + path::PathBuf, +}; use file_rename::NameExchange; use path_checkout::GetPathInfo; @@ -8,42 +10,46 @@ mod path_checkout; #[no_mangle] /// # Safety -/// 最终暴露的执行函数 -pub unsafe extern "C" fn exchange(path1: *const c_char, path2: *const c_char) -> u8 { +/// 最终暴露的执行函数,传入两个路径String,返回一个u8 +/// +/// 0 => Success,1 => No Exist +/// +/// 2 => Permission Denied,3 => New File Already Exists +/// +/// 255 => UNKNOWN ERROR +pub extern "C" fn exchange(path1: *const c_char, path2: *const c_char) -> i32 { let binding = std::env::current_exe().unwrap(); let exe_dir = binding.parent().unwrap(); - let path1 = unsafe { CStr::from_ptr(path1).to_str().unwrap().to_owned() }; - let path2 = unsafe { CStr::from_ptr(path2) } - .to_str() - .unwrap() - .to_owned(); + let transformer = |s: *const c_char| unsafe { CStr::from_ptr(s) }.to_string_lossy().to_string(); + + let path1 = transformer(path1); + let path2 = transformer(path2); let mut all_infos = NameExchange::new(); // 用于校验文件夹路径最后是否为斜杠与双引号的闭包 let dir_check = |s: String| { - let s = PathBuf::from(s); + let mut s = s; if s.ends_with("\"") { - let s = s.to_str().unwrap().strip_suffix("\"").unwrap(); - let s = if s.ends_with("\\") { - s.strip_suffix("\\").unwrap() - } else { - s - }; - PathBuf::from(s) - } else { - s - } + s = s.strip_suffix("\"").unwrap().to_string() + }; + if s.ends_with("\\") { + s = s.strip_suffix("\\").unwrap().to_string() + }; + PathBuf::from(s) }; let mut packed_path = GetPathInfo { path1: dir_check(path1), path2: dir_check(path2), }; - (all_infos.f1.is_exist, all_infos.f2.is_exist) = (packed_path).if_no_exist(exe_dir); - if all_infos.f1.is_exist || all_infos.f2.is_exist { - return 1; + (all_infos.f1.is_exist, all_infos.f2.is_exist) = (packed_path).if_exist(exe_dir); + if (!all_infos.f1.is_exist) || (!all_infos.f2.is_exist) { + return 1_i32; + } + if packed_path.path1 == packed_path.path2 { + return 2_i32; } all_infos.f1.exchange.original_path = packed_path.path1.clone(); all_infos.f2.exchange.original_path = packed_path.path2.clone(); @@ -67,16 +73,23 @@ pub unsafe extern "C" fn exchange(path1: *const c_char, path2: *const c_char) -> &all_infos.f1.packed_info.name, &all_infos.f2.packed_info.ext, ); + let mut packed_path_new = GetPathInfo { //其实没必要mut path1: all_infos.f1.exchange.new_path.clone(), path2: all_infos.f2.exchange.new_path.clone(), }; - - //println!("{:?} {:?}", &packed_path_new.path1, &packed_path_new.path2); //test - let (exist_new_1, exist_new_2) = GetPathInfo::if_no_exist(&mut packed_path_new, exe_dir); - if (!exist_new_1) || (!exist_new_2) { - return 4; + let (exist_new_1, exist_new_2) = GetPathInfo::if_exist(&mut packed_path_new, exe_dir); + let same_dir = GetPathInfo::if_same_dir(&packed_path_new); + if !same_dir && (exist_new_1 || exist_new_2) { + //不能因为rename函数里面有就删了…… + /* + println!( + "same:{}\tnew1:{}\tnew2:{}", + same_dir, exist_new_1, exist_new_2 + ); + */ + return 3_i32; } //1 -> file1 should be renamed first @@ -119,3 +132,37 @@ pub unsafe extern "C" fn exchange(path1: *const c_char, path2: *const c_char) -> } } } + +#[cfg(test)] +mod tests { + use std::env::args; + use std::{ffi::CString, fs::remove_file}; + + fn clear_olds() { + let _ = remove_file("file1.ext1"); + let _ = remove_file("file2.ext2"); + let _ = remove_file("file2.ext1"); + let _ = remove_file("file1.ext2"); + + let mut new_file1 = std::fs::File::create("file1.ext1").unwrap(); + let mut new_file2 = std::fs::File::create("file2.ext2").unwrap(); + let _ = std::io::Write::write_all(&mut new_file1, b""); + let _ = std::io::Write::write_all(&mut new_file2, b""); + } + #[test] + fn it_works() { + clear_olds(); + // 0 => Success,1 => No Exist + // 2 => Permission Denied,3 => New File Already Exists + + let trans = |s: String| CString::new(s).unwrap(); + let _test_path1 = trans(r"file1.ext1".to_owned()); + let _test_path2 = trans(r"file1.ext1".to_owned()); + + let mut a: Vec = args().map(|f| trans(f)).collect(); + a.remove(0); + + let run_result = super::exchange(a[1].as_ptr(), a[2].as_ptr()); + println!("{}", run_result); + } +} diff --git a/src/path_checkout.rs b/src/path_checkout.rs index 6e7691d..552a1a9 100644 --- a/src/path_checkout.rs +++ b/src/path_checkout.rs @@ -27,14 +27,21 @@ pub struct GetPathInfo { /// 所有路径相关的操作 impl GetPathInfo { /// 校验路径是否存在;如果是相对路径,尝试转化为绝对路径 - pub fn if_no_exist(&mut self, exe_path: &Path) -> (bool, bool) { - if self.path1.exists() && self.path1.is_relative() { - self.path1 = exe_path.join(self.path1.clone()); + pub fn if_exist(&mut self, dir: &Path) -> (bool, bool) { + if self.path1.is_relative() { + self.path1 = dir.join(self.path1.clone().file_name().unwrap()); } - if self.path2.exists() && self.path2.is_relative() { - self.path2 = exe_path.join(self.path2.clone()); + if self.path2.is_relative() { + self.path2 = dir.join(self.path2.clone().file_name().unwrap()); } - (!&self.path1.exists(), !&self.path2.exists()) + /* + println!( + "Path1: {}\tPath2: {}", + self.path1.display(), + self.path2.display() + ); //test + */ + (self.path1.exists(), self.path2.exists()) } ///输入的文件类型是否为文件夹 @@ -42,6 +49,10 @@ impl GetPathInfo { (self.path1.is_file(), self.path2.is_file()) } + pub fn if_same_dir(&self) -> bool { + self.path1.parent().unwrap() == self.path2.parent().unwrap() + } + ///检测是否存在包含关系(父子目录问题) pub fn if_root(&self) -> u8 { //下面必须统一取小写或大写,因为rust的“contains()”大小写敏感