### Example Usage of who_locks_file Source: https://docs.rs/wholock/0.0.1/src/wholock/lib.rs.html Demonstrates how to call the `who_locks_file` function and process its results. Handles both successful retrieval of locking processes and potential errors. ```rust use wholock::{who_locks_file, ProcessInfo}; match who_locks_file("C:\\path\\to\\file.txt") { Ok(processes) => { for process in processes { println!("Process {} ({}) has locked the file", process.process_name, process.pid); } }, Err(e) => println!("Error occurred: {:?}", e), } ``` -------------------------------- ### Safely Get Ok Value with into_ok (Nightly) Source: https://docs.rs/wholock/0.0.1/wholock/type.WholockResult.html The `into_ok()` method (nightly-only) returns the contained Ok value and is guaranteed not to panic. It serves as a compile-time safeguard against future changes that might introduce panics. ```rust fn only_good_news() -> Result { Ok("this is fine".into()) } let s: String = only_good_news().into_ok(); println!("{s}"); ``` -------------------------------- ### Get References to Result Values Source: https://docs.rs/wholock/0.0.1/wholock/type.WholockResult.html Use `as_ref()` to get a `Result` containing references to the contained values without consuming the original `Result`. This is useful for inspecting values without taking ownership. ```rust let x: Result = Ok(2); assert_eq!(x.as_ref(), Ok(&2)); let x: Result = Err("Error"); assert_eq!(x.as_ref(), Err(&"Error")); ``` -------------------------------- ### Chain Fallible Operations with and_then Source: https://docs.rs/wholock/0.0.1/wholock/type.WholockResult.html Use and_then to chain operations that return a Result. The provided examples demonstrate successful mapping and error propagation. ```rust fn sq_then_to_string(x: u32) -> Result { x.checked_mul(x).map(|sq| sq.to_string()).ok_or("overflowed") } assert_eq!(Ok(2).and_then(sq_then_to_string), Ok(4.to_string())); assert_eq!(Ok(1_000_000).and_then(sq_then_to_string), Err("overflowed")); assert_eq!(Err("not a number").and_then(sq_then_to_string), Err("not a number")); ``` ```rust use std::{io::ErrorKind, path::Path}; // Note: on Windows "/" maps to "C:\" let root_modified_time = Path::new("/").metadata().and_then(|md| md.modified()); assert!(root_modified_time.is_ok()); let should_fail = Path::new("/bad/path").metadata().and_then(|md| md.modified()); assert!(should_fail.is_err()); assert_eq!(should_fail.unwrap_err().kind(), ErrorKind::NotFound); ``` -------------------------------- ### Get Mutable References to Result Values Source: https://docs.rs/wholock/0.0.1/wholock/type.WholockResult.html Use `as_mut()` to get a `Result` containing mutable references to the contained values, allowing in-place modification. This is essential when you need to change the value within a `Result`. ```rust fn mutate(r: &mut Result) { match r.as_mut() { Ok(v) => *v = 42, Err(e) => *e = 0, } } let mut x: Result = Ok(2); mutate(&mut x); assert_eq!(x.unwrap(), 42); let mut x: Result = Err(13); mutate(&mut x); assert_eq!(x.unwrap_err(), 0); ``` -------------------------------- ### Calculate Sum of Elements with Error Handling Source: https://docs.rs/wholock/0.0.1/wholock/type.WholockResult.html Illustrates the `sum` method for iterators of `Result`s. The summation proceeds only if all elements are `Ok`. If a negative element is encountered (which maps to an `Err` in this example), the summation stops and returns that `Err`. ```rust let f = |&x: &i32| if x < 0 { Err("Negative element found") } else { Ok(x) }; let v = vec![1, 2]; let res: Result = v.iter().map(f).sum(); assert_eq!(res, Ok(3)); ``` ```rust let v = vec![1, -2]; let res: Result = v.iter().map(f).sum(); assert_eq!(res, Err("Negative element found")); ``` -------------------------------- ### Unwrap Ok Value in Rust Source: https://docs.rs/wholock/0.0.1/wholock/type.WholockResult.html Use `unwrap()` to get the contained Ok value. Panics if the value is an Err, using the Err's value as the panic message. ```rust let x: Result = Ok(2); assert_eq!(x.unwrap(), 2); ``` -------------------------------- ### Get Win32 Error Message Source: https://docs.rs/wholock/0.0.1/src/wholock/error.rs.html A helper function to retrieve a human-readable error message for a given Win32 error code. Requires the `windows` crate and specific system diagnostics APIs. ```rust use windows::core::PWSTR; use windows::Win32::System::Diagnostics::Debug::{FormatMessageW, FORMAT_MESSAGE_FROM_SYSTEM}; pub(crate) fn get_win32_error_message(error: &WIN32_ERROR) -> String { let mut buffer = [0u16; 512]; unsafe { let size = FormatMessageW( FORMAT_MESSAGE_FROM_SYSTEM, None, error.0, 0, PWSTR::from_raw(buffer.as_mut_ptr()), buffer.len() as u32, None, ); if size == 0 { return format!("Unknown error {}", error.0); } String::from_utf16_lossy(&buffer[..size as usize]) .trim() .to_string() } } ``` -------------------------------- ### Safely Get Err Value with into_err (Nightly) Source: https://docs.rs/wholock/0.0.1/wholock/type.WholockResult.html The `into_err()` method (nightly-only) returns the contained Err value and is guaranteed not to panic. It acts as a compile-time safeguard against future changes that might introduce panics. ```rust fn only_bad_news() -> Result { Err("Oops, it failed".into()) } let error: String = only_bad_news().into_err(); println!("{error}"); ``` -------------------------------- ### Build Process Name Dictionary Source: https://docs.rs/wholock/0.0.1/src/wholock/interop.rs.html Constructs a mapping of process IDs to process names using the sysinfo crate. ```rust #[allow(dead_code)] pub(crate) fn build_process_name_dict() -> WholockResult> { use sysinfo::System; let mut sys = System::new_all(); sys.refresh_all(); let mut process_name_dict: std::collections::HashMap = std::collections::HashMap::new(); for (pid, process) in sys.processes() { process_name_dict.insert((*pid).into(), process.name().to_string_lossy().to_string()); } Ok(process_name_dict) } ``` -------------------------------- ### Unit Tests for System Utilities Source: https://docs.rs/wholock/0.0.1/src/wholock/interop.rs.html Test suite for verifying handle table retrieval, file locking checks, and process information. ```rust #[cfg(test)] mod tests { use super::*; use std::fs::File; use std::io::Write; use std::os::windows::io::AsRawHandle; use tempfile::tempdir; use windows::Win32::System::Threading::GetCurrentProcess; #[test] fn test_query_system_information_buffer() { let result = query_system_information_buffer(SYSTEM_EXTENDED_HANDLE_INFORMATION); assert!(result.is_ok()); let buffer = result.unwrap(); assert!(!buffer.is_empty()); } #[test] fn test_get_handle_table() { let buffer = query_system_information_buffer(SYSTEM_EXTENDED_HANDLE_INFORMATION).unwrap(); let table = get_handle_table(&buffer); assert!(!table.is_empty()); } // to be fixed #[test] #[ignore] fn test_check_if_locked_file() { assert!(check_if_locked_file( r"C:\Users\test\file.txt", r"C:\Users\test" )); assert!(check_if_locked_file( r"C:\Users\test\file.txt", r"c:\users\test\file.txt" )); assert!(!check_if_locked_file( r"C:\Users\other\file.txt", r"C:\Users\test" )); } #[test] fn test_get_handle_owner_info() { let current_process = unsafe { GetCurrentProcess() }; let result = get_handle_owner_info(current_process); assert!(result.is_ok()); let owner_info = result.unwrap(); assert!(!owner_info.is_empty()); assert!(owner_info.contains('\\')); } #[test] fn test_get_final_path_name_by_handle() { let dir = tempdir().unwrap(); ``` -------------------------------- ### Get the minimum of two Result values Source: https://docs.rs/wholock/0.0.1/wholock/type.WholockResult.html Returns the minimum of two Result values. Requires that T and E implement Ord. ```rust fn min(self, other: Self) -> Self where Self: Sized, ``` -------------------------------- ### Get the maximum of two Result values Source: https://docs.rs/wholock/0.0.1/wholock/type.WholockResult.html Returns the maximum of two Result values. Requires that T and E implement Ord. ```rust fn max(self, other: Self) -> Self where Self: Sized, ``` -------------------------------- ### String and Path Conversion Utilities Source: https://docs.rs/wholock/0.0.1/src/wholock/interop.rs.html Helper functions for converting wide character buffers to strings and extracting filenames from paths. ```rust fn convert_wide_buffer(buffer: &[u16], len: usize) -> WholockResult { let os_str = OsString::from_wide(&buffer[..len]); os_str .into_string() .map_err(|_| WholockError::EncodingError("Invalid UTF-16 sequence".to_string())) } fn extract_filename(path: &str) -> WholockResult { std::path::Path::new(path) .file_name() .and_then(|n| n.to_str()) .map(|s| s.to_string()) .ok_or_else(|| WholockError::PathError("Invalid file path".to_string())) } ``` -------------------------------- ### Test process name dictionary construction Source: https://docs.rs/wholock/0.0.1/src/wholock/interop.rs.html Ensures the process name dictionary is successfully built and is not empty. ```rust #[test] fn test_build_process_name_dict() { let result = build_process_name_dict(); assert!(result.is_ok()); let dict = result.unwrap(); assert!(!dict.is_empty()); } ``` -------------------------------- ### Retrieve Process Information Source: https://docs.rs/wholock/0.0.1/src/wholock/interop.rs.html Opens a process by PID and retrieves its full image path and executable name. ```rust pub(crate) fn get_process_info(pid: u32) -> WholockResult<(String, String)> { unsafe { let handle = OpenProcess(PROCESS_QUERY_LIMITED_INFORMATION, false, pid).map_err(|e| { WholockError::ProcessError(format!( "Failed to open process {}: {}", pid, get_win32_error_message(&WIN32_ERROR(e.code().0 as u32)) )) })?; let safe_handle = SafeHandle::new(handle)?; let mut buffer = [0u16; MAX_PATH as usize + 1]; let mut size = buffer.len() as u32; QueryFullProcessImageNameW( safe_handle.as_raw(), windows::Win32::System::Threading::PROCESS_NAME_FORMAT(0), PWSTR::from_raw(buffer.as_mut_ptr()), &mut size, ) .map_err(|e| WholockError::Win32Error(WIN32_ERROR(e.code().0 as u32)))?; let path_str = convert_wide_buffer(&buffer, size as usize)?; let exe_name = extract_filename(&path_str)?; Ok((exe_name, path_str)) } } ``` -------------------------------- ### TryInto Trait Methods Source: https://docs.rs/wholock/0.0.1/wholock/error/enum.WholockError.html Documentation for the conversion methods provided by the TryInto trait. ```APIDOC ## Type Error ### Description The type returned in the event of a conversion error. --- ## fn try_into ### Description Performs the conversion from the source type to the target type. ### Returns - **Result>::Error>** - A Result containing the converted type or the conversion error. ``` -------------------------------- ### Unwrap Error Value in Rust Source: https://docs.rs/wholock/0.0.1/wholock/type.WholockResult.html Use `unwrap_err()` to get the contained Err value. Panics if the value is an Ok, using the Ok's value as the panic message. ```rust let x: Result = Ok(2); x.unwrap_err(); // panics with `2` ``` ```rust let x: Result = Err("emergency failure"); assert_eq!(x.unwrap_err(), "emergency failure"); ``` -------------------------------- ### Implement From for WholockError Source: https://docs.rs/wholock/0.0.1/src/wholock/error.rs.html Enables direct conversion of `windows::Win32::Foundation::WIN32_ERROR` into `WholockError::Win32Error`. ```rust impl From for WholockError { fn from(error: WIN32_ERROR) -> Self { WholockError::Win32Error(error) } } ``` -------------------------------- ### pub fn ok(self) -> Option Source: https://docs.rs/wholock/0.0.1/wholock/type.WholockResult.html Converts a Result into an Option, consuming the Result and discarding any error value. ```APIDOC ## pub fn ok(self) -> Option ### Description Converts from `Result` to `Option`. Consumes `self`, and discarding the error, if any. ### Method `Result::ok` ### Request Example ```rust let x: Result = Ok(2); assert_eq!(x.ok(), Some(2)); let x: Result = Err("Nothing here"); assert_eq!(x.ok(), None); ``` ### Response Example ```json { "example": "Some(value)" or "None" } ``` ``` -------------------------------- ### Windows System Handle Interop Structures and Functions Source: https://docs.rs/wholock/0.0.1/src/wholock/interop.rs.html Defines structures for system handle information and provides functions to query system information buffers and parse handle tables. ```rust 1use crate::{error::get_win32_error_message, error::WholockError, WholockResult}; 2use std::{ 3 ffi::{c_void, OsString}, 4 mem, 5 os::{ 6 raw::{c_ulong, c_ushort}, 7 windows::ffi::OsStringExt, 8 }, 9 ptr::{self, addr_of}, 10 slice, 11}; 12use windows::core::{PCWSTR, PWSTR}; 13use windows::Win32::Foundation::HANDLE; 14use windows::Win32::Foundation::{ 15 CloseHandle, DuplicateHandle, DUPLICATE_HANDLE_OPTIONS, MAX_PATH, 16}; 17use windows::Win32::Security::{GetTokenInformation, TokenUser, TOKEN_QUERY, TOKEN_USER}; 18use windows::Win32::Security::{LookupAccountSidW, SID_NAME_USE}; 19use windows::Win32::Storage::FileSystem::{ 20 GetFinalPathNameByHandleW, GETFINALPATHNAMEBYHANDLE_FLAGS, 21}; 22use windows::Win32::System::Threading::{ 23 OpenProcess, OpenProcessToken, QueryFullProcessImageNameW, PROCESS_ACCESS_RIGHTS, 24 PROCESS_QUERY_LIMITED_INFORMATION, 25}; 26use windows::{ 27 Wdk::System::SystemInformation::{NtQuerySystemInformation, SYSTEM_INFORMATION_CLASS}, 28 Win32::Foundation::WIN32_ERROR, 29}; 30 31pub(crate) const SYSTEM_EXTENDED_HANDLE_INFORMATION: SYSTEM_INFORMATION_CLASS = 32 SYSTEM_INFORMATION_CLASS(0x40); 33pub(crate) const PROCESS_ACCESS_RIGHTS_DUP_HANDLE: PROCESS_ACCESS_RIGHTS = 34 PROCESS_ACCESS_RIGHTS(0x0040); 35pub(crate) const PROCESS_ACCESS_RIGHTS_QUERY_INFORMATION: PROCESS_ACCESS_RIGHTS = 36 PROCESS_ACCESS_RIGHTS(0x0400); 37 38pub(crate) struct SystemHandleInformationEx { 39 number_of_handles: usize, 40 _reserved: usize, 41 handles: [SystemHandleTableEntryInfoEx; 1], 42} 43 44pub(crate) struct SystemHandleTableEntryInfoEx { 45 #[allow(dead_code)] 46 object: *mut c_void, 47 unique_process_id: usize, 48 handle_value: *mut c_void, 49 #[allow(dead_code)] 50 granted_access: c_ulong, 51 #[allow(dead_code)] 52 creator_back_trace_index: c_ushort, 53 #[allow(dead_code)] 54 object_type_index: c_ushort, 55 #[allow(dead_code)] 56 handle_attributes: c_ulong, 57 _reserved: c_ulong, 58} 59 60pub(crate) struct HandleEntry(SystemHandleTableEntryInfoEx); 61 62impl HandleEntry { 63 #[allow(dead_code)] 64 fn object(&self) -> *mut c_void { 65 self.0.object 66 } 67 pub fn unique_process_id(&self) -> usize { 68 self.0.unique_process_id 69 } 70 fn handle_value(&self) -> *mut c_void { 71 self.0.handle_value 72 } 73 #[allow(dead_code)] 74 fn granted_access(&self) -> c_ulong { 75 self.0.granted_access 76 } 77 #[allow(dead_code)] 78 fn creator_back_trace_index(&self) -> c_ushort { 79 self.0.creator_back_trace_index 80 } 81 #[allow(dead_code)] 82 fn object_type_index(&self) -> c_ushort { 83 self.0.object_type_index 84 } 85 #[allow(dead_code)] 86 fn handle_attributes(&self) -> c_ulong { 87 self.0.handle_attributes 88 } 89} 90 91pub(crate) fn query_system_information_buffer( 92 information_class: SYSTEM_INFORMATION_CLASS, 93) -> WholockResult> { 94 let mut buffer: Vec = vec![]; 95 loop { 96 let mut return_length = 0; 97 let result = unsafe { 98 NtQuerySystemInformation( 99 information_class, 100 buffer.as_mut_ptr().cast(), 101 buffer.len() as c_ulong, 102 &mut return_length, 103 ) 104 }; 105 let return_length = return_length as usize; 106 107 if result.is_ok() { 108 return Ok(buffer); 109 } else if result.is_err() { 110 if return_length > buffer.len() { 111 buffer.clear(); 112 buffer.reserve_exact(return_length); 113 buffer.resize(return_length, 0); 114 } else { 115 return Err(WholockError::SystemInfoError( 116 "Failed to query system information".to_string(), 117 )); 118 } 119 } 120 } 121} 122 123pub(crate) fn get_handle_table(buffer: &[u8]) -> &[HandleEntry] { 124 let info_ptr: *const SystemHandleInformationEx = buffer.as_ptr().cast(); 125 let table_ptr: *const HandleEntry = unsafe { addr_of!((*info_ptr).handles).cast() }; 126 let len = unsafe { addr_of!((*info_ptr).number_of_handles).read_unaligned() }; 127 let table_offset = unsafe { table_ptr.cast::().offset_from(buffer.as_ptr()) }; 128 let max_len = (buffer.len() - table_offset as usize) / mem::size_of::(); 129 assert!(len <= max_len); 130 unsafe { slice::from_raw_parts(table_ptr, len) } 131} 132 133#[allow(dead_code)] 134pub(crate) fn query_system_info() { 135 use log::debug; 136 137 let buffer = query_system_information_buffer(SYSTEM_EXTENDED_HANDLE_INFORMATION).unwrap(); 138 let table = get_handle_table(&buffer); 139 for (i, entry) in table.iter().enumerate() { 140 debug!("entry {i}:"); 141 debug!(" Object = {:p}", entry.object()); ``` -------------------------------- ### Expect Error Value with Custom Message in Rust Source: https://docs.rs/wholock/0.0.1/wholock/type.WholockResult.html Use `expect_err()` to get the contained Err value. Panics if the value is an Ok, including the provided message and the Ok's content in the panic message. ```rust let x: Result = Ok(10); x.expect_err("Testing expect_err"); // panics with `Testing expect_err: 10` ``` -------------------------------- ### Test file path resolution from handle Source: https://docs.rs/wholock/0.0.1/src/wholock/interop.rs.html Verifies that a file path can be correctly retrieved from a file handle. ```rust let file_path = dir.path().join("test.txt"); let mut file = File::create(&file_path).unwrap(); writeln!(file, "test content").unwrap(); let file = File::open(&file_path).unwrap(); let handle = HANDLE(file.as_raw_handle() as _); let result = get_final_path_name_by_handle(&handle); assert!(result.is_ok()); let path = result.unwrap(); assert!(path.contains("test.txt")); } ``` -------------------------------- ### ProcessInfo Trait Implementations Source: https://docs.rs/wholock/0.0.1/wholock/struct.ProcessInfo.html Overview of trait implementations available for the ProcessInfo struct. ```APIDOC ## Trait Implementations for ProcessInfo ### Debug Allows the ProcessInfo struct to be formatted for debugging purposes. ### Freeze, RefUnwindSafe, Send, Sync, Unpin, UnwindSafe These are auto-trait implementations indicating thread safety and memory safety characteristics. ``` -------------------------------- ### Unwrap or Default Value in Rust Source: https://docs.rs/wholock/0.0.1/wholock/type.WholockResult.html Use `unwrap_or_default()` to get the contained Ok value or the default value for the type if it's an Err. This is useful for converting strings to numbers, providing 0 for invalid inputs. ```rust let good_year_from_input = "1909"; let bad_year_from_input = "190blarg"; let good_year = good_year_from_input.parse().unwrap_or_default(); let bad_year = bad_year_from_input.parse().unwrap_or_default(); assert_eq!(1909, good_year); assert_eq!(0, bad_year); ``` -------------------------------- ### Panic with Custom Message using unwrap Source: https://docs.rs/wholock/0.0.1/wholock/type.WholockResult.html Demonstrates how `unwrap()` panics with a custom message when the Result is an Err. ```rust let x: Result = Err("emergency failure"); x.unwrap(); // panics with `emergency failure` ``` -------------------------------- ### Test current process information Source: https://docs.rs/wholock/0.0.1/src/wholock/interop.rs.html Verifies that process information for the current process can be retrieved and validated. ```rust #[test_log::test] fn test_current_process() { let pid = std::process::id(); let (name, path) = get_process_info(pid).unwrap(); assert!(!name.is_empty()); assert!(std::path::Path::new(&path).exists()); assert_eq!( name, std::path::Path::new(&path) .file_name() .unwrap() .to_str() .unwrap() ); } } ``` -------------------------------- ### Provide Default Value with unwrap_or Source: https://docs.rs/wholock/0.0.1/wholock/type.WholockResult.html Returns the contained Ok value or a provided default. Arguments are evaluated eagerly. ```rust let default = 2; let x: Result = Ok(9); assert_eq!(x.unwrap_or(default), 9); let x: Result = Err("error"); assert_eq!(x.unwrap_or(default), default); ``` -------------------------------- ### Define ProcessInfo Struct Source: https://docs.rs/wholock/0.0.1/wholock/struct.ProcessInfo.html Defines the structure for holding process information, including PID, name, executable path, domain username, and a list of locked files. ```rust pub struct ProcessInfo { pub pid: u32, pub process_name: String, pub process_exe_path: String, pub domain_username: String, pub locked_file: Vec, } ``` -------------------------------- ### Implement From for WholockError Source: https://docs.rs/wholock/0.0.1/src/wholock/error.rs.html Enables direct conversion of `windows::core::Error` into `WholockError::WindowsError`. ```rust impl From for WholockError { fn from(error: WindowsError) -> Self { WholockError::WindowsError(error) } } ``` -------------------------------- ### IntoIterator for Result (Ok case) Source: https://docs.rs/wholock/0.0.1/wholock/type.WholockResult.html Demonstrates converting an Ok(u32) Result into an iterator that yields the contained value. ```rust let x: Result = Ok(5); let v: Vec = x.into_iter().collect(); assert_eq!(v, [5]); ``` -------------------------------- ### Implement Debug for ProcessInfo Source: https://docs.rs/wholock/0.0.1/wholock/struct.ProcessInfo.html Provides a way to format the ProcessInfo struct for debugging purposes. This implementation allows the struct to be printed using the debug formatter. ```rust fn fmt(&self, f: &mut Formatter<'_>) -> Result ``` -------------------------------- ### Return Alternative Result with or Source: https://docs.rs/wholock/0.0.1/wholock/type.WholockResult.html Returns the provided result if the current one is Err. Arguments are evaluated eagerly. ```rust let x: Result = Ok(2); let y: Result = Err("late error"); assert_eq!(x.or(y), Ok(2)); let x: Result = Err("early error"); let y: Result = Ok(2); assert_eq!(x.or(y), Ok(2)); let x: Result = Err("not a 2"); let y: Result = Err("late error"); assert_eq!(x.or(y), Err("late error")); let x: Result = Ok(2); let y: Result = Ok(100); assert_eq!(x.or(y), Ok(2)); ``` -------------------------------- ### Implement Any for Generic Type T Source: https://docs.rs/wholock/0.0.1/wholock/struct.ProcessInfo.html Provides runtime type information for any type T that is 'static and ?Sized. This is a blanket implementation. ```rust fn type_id(&self) -> TypeId ``` -------------------------------- ### Result Trait Implementations Source: https://docs.rs/wholock/0.0.1/wholock/type.WholockResult.html Overview of trait implementations for Result including comparison, aggregation, and control flow traits. ```APIDOC ## Result Trait Implementations ### Description This section covers the implementation of standard library traits for the `Result` type, enabling comparison, summation, product calculation, and integration with the `?` operator. ### Traits - **PartialOrd**: Implements comparison operators (`<`, `<=`, `>`, `>=`) for `Result` when `T` and `E` implement `PartialOrd`. - **Product**: Implements `product` for iterators of `Result`, returning the product or the first `Err` encountered. - **Sum**: Implements `sum` for iterators of `Result`, returning the sum or the first `Err` encountered. - **Termination**: Implements `report` to convert `Result` into an `ExitCode` for process termination. - **Try**: Experimental trait for `?` operator support, defining `Output` and `Residual` types. ### Examples #### Product Example ```rust let nums = vec!["5", "10", "1", "2"]; let total: Result = nums.iter().map(|w| w.parse::()).product(); assert_eq!(total, Ok(100)); ``` #### Sum Example ```rust let f = |&x: &i32| if x < 0 { Err("Negative element found") } else { Ok(x) }; let v = vec![1, 2]; let res: Result = v.iter().map(f).sum(); assert_eq!(res, Ok(3)); ``` ``` -------------------------------- ### SafeHandle RAII Wrapper Source: https://docs.rs/wholock/0.0.1/src/wholock/interop.rs.html A wrapper for Windows HANDLE that ensures resources are closed automatically when dropped. ```rust struct SafeHandle(HANDLE); impl SafeHandle { fn new(handle: HANDLE) -> WholockResult { if handle.is_invalid() { return Err(WholockError::HandleError("Invalid handle".to_string())); } Ok(Self(handle)) } fn as_raw(&self) -> HANDLE { self.0 } } impl Drop for SafeHandle { fn drop(&mut self) { if !self.0.is_invalid() { unsafe { if let Err(e) = CloseHandle(self.0) { log::error!( "Failed to close handle: {}", get_win32_error_message(&WIN32_ERROR(e.code().0 as u32)) ); } } } } } ``` -------------------------------- ### Normalize and Compare Paths Source: https://docs.rs/wholock/0.0.1/src/wholock/interop.rs.html Normalizes file paths by converting separators and casing for consistent comparison. ```rust fn normalize_path(path: &str) -> String { path.replace('/', "\\") .to_lowercase() .trim_start_matches(r"\\?\") .to_string() } pub(crate) fn check_if_locked_file(path: &str, target_path: &str) -> bool { normalize_path(path) == normalize_path(target_path) } ``` -------------------------------- ### Identify Processes Locking a File Source: https://docs.rs/wholock/0.0.1/src/wholock/lib.rs.html Use this function to find all processes that have a lock on a specified file. It requires the file path as input and returns a list of `ProcessInfo` structs, each containing details about a locking process. Ensure necessary system permissions are available. ```rust pub fn who_locks_file(path: &str) -> WholockResult> { let current_process: windows::Win32::Foundation::HANDLE = unsafe { GetCurrentProcess() }; let mut result: Vec = vec![]; let buffer = query_system_information_buffer(SYSTEM_EXTENDED_HANDLE_INFORMATION)?; let table = get_handle_table(&buffer); for (pid, handles) in table .iter() .into_group_map_by(|elt| elt.unique_process_id()) { if let Ok(open_process) = unsafe { OpenProcess( PROCESS_ACCESS_RIGHTS_DUP_HANDLE | PROCESS_ACCESS_RIGHTS_QUERY_INFORMATION, false, pid.try_into().unwrap(), ) } { if open_process.is_invalid() { continue; } let mut process_info = ProcessInfo { pid: pid.try_into().unwrap(), process_name: "".to_string(), process_exe_path: "".to_string(), domain_username: "".to_string(), locked_file: vec![], }; for handle in handles.iter() { let handle_entry = *handle; let dup_handle = HandleWrapper::new( duplicate_handle( current_process, open_process, handle_entry, )?, ); if dup_handle.is_invalid() { continue; } let reopened_handle = unsafe { ReOpenFile( dup_handle.get(), 0, FILE_SHARE_MODE(0), FILE_FLAGS_AND_ATTRIBUTES(0), ) }; if reopened_handle.is_err() || reopened_handle.as_ref().unwrap().is_invalid() { continue; } let reopened_handle = HandleWrapper::new(reopened_handle.unwrap()); if let Ok(full_name) = get_final_path_name_by_handle(&reopened_handle.get()) { if check_if_locked_file(&full_name, path) { ``` -------------------------------- ### Trait Implementations Source: https://docs.rs/wholock/0.0.1/wholock/type.WholockResult.html Standard trait implementations for the Result type. ```APIDOC ## Trait Implementations ### Clone - **Description**: Implemented for Result where T and E are Clone. ### Debug - **Description**: Implemented for Result where T and E are Debug. ### From> - **Description**: Converts from Either to Result with Right => Ok and Left => Err. ### FromIterator> - **Description**: Implemented for Result where V implements FromIterator. ``` -------------------------------- ### Resolve File Path from Handle Source: https://docs.rs/wholock/0.0.1/src/wholock/interop.rs.html Retrieves the full path of a file given its handle, handling buffer resizing if the initial allocation is insufficient. ```rust pub(crate) fn get_final_path_name_by_handle(h_file: &HANDLE) -> WholockResult { let mut buf = vec![0u16; 1024]; let mut result = unsafe { GetFinalPathNameByHandleW(*h_file, &mut buf, GETFINALPATHNAMEBYHANDLE_FLAGS(0)) }; if result == 0 { return Err(WholockError::Win32Error(WIN32_ERROR(0x00000008))); } if result as usize > buf.len() { buf.resize(result as usize, 0); result = unsafe { GetFinalPathNameByHandleW(*h_file, &mut buf, GETFINALPATHNAMEBYHANDLE_FLAGS(0)) }; } if result == 0 { return Err(WholockError::Win32Error(WIN32_ERROR(0x0000000D))); } let file_path = OsString::from_wide(&buf); let file_path = file_path.to_string_lossy().to_string(); Ok(if file_path.starts_with(r"\\?\") { file_path .strip_prefix(r"\\?\") .unwrap_or(&file_path) .to_string() } else { file_path }) } ``` -------------------------------- ### Find and Terminate Process Locking a File Source: https://docs.rs/wholock/0.0.1/wholock/fn.unlock_file.html Use this snippet to find processes that are locking a specific file and then terminate the first process found. Ensure you handle potential errors during file locking checks and process termination. ```rust use wholock::{who_locks_file, unlock_file}; // Find processes locking a file let processes = who_locks_file("C:\\path\\to\\file.txt").unwrap(); // Terminate the first process found if let Some(process) = processes.first() { match unlock_file(process.pid) { Ok(_) => println!("Successfully terminated process {}", process.pid), Err(e) => println!("Failed to terminate process: {:?}", e), } } ``` -------------------------------- ### Convert Result Ok Value to Option Source: https://docs.rs/wholock/0.0.1/wholock/type.WholockResult.html The `ok()` method consumes a Result and returns an Option containing the Ok value, or None if the Result was an Err. This is useful for discarding errors when only the success value is needed. ```rust let x: Result = Ok(2); assert_eq!(x.ok(), Some(2)); let x: Result = Err("Nothing here"); assert_eq!(x.ok(), None); ``` -------------------------------- ### Implement From for WholockError Source: https://docs.rs/wholock/0.0.1/src/wholock/error.rs.html Enables direct conversion of a `String` into `WholockError::Other` for general-purpose error reporting. ```rust impl From for WholockError { fn from(error: String) -> Self { WholockError::Other(error) } } ``` -------------------------------- ### ProcessInfo Struct Source: https://docs.rs/wholock/0.0.1/wholock/struct.ProcessInfo.html Details of the ProcessInfo struct, including its fields and their types. ```APIDOC ## Struct ProcessInfo ### Description Represents information about a running process. ### Fields - **pid** (u32) - The process ID. - **process_name** (String) - The name of the process. - **process_exe_path** (String) - The full path to the process executable. - **domain_username** (String) - The domain and username associated with the process. - **locked_file** (Vec) - A list of files locked by the process. ``` -------------------------------- ### pub fn map(self, op: F) -> Result Source: https://docs.rs/wholock/0.0.1/wholock/type.WholockResult.html Maps a Result to Result by applying a function to the contained Ok value, leaving Err values untouched. ```APIDOC ## pub fn map(self, op: F) -> Result ### Description Maps a `Result` to `Result` by applying a function to a contained `Ok` value, leaving an `Err` value untouched. This function can be used to compose the results of two functions. ### Method `Result::map` ### Request Example ```rust let line = "1\n2\n3\n4\n"; for num in line.lines() { match num.parse::().map(|i| i * 2) { Ok(n) => println!("{n}"), Err(..) => {} } } ``` ### Response Example ```json { "example": "Result" } ``` ``` -------------------------------- ### Identify processes locking a file Source: https://docs.rs/wholock/0.0.1/wholock/fn.who_locks_file.html Use this function to find all processes that have a lock on a specific file. Ensure the file path is correctly specified. Errors may occur if system handle information cannot be queried. ```rust use wholock::{who_locks_file, ProcessInfo}; match who_locks_file("C:\\path\\to\\file.txt") { Ok(processes) => { for process in processes { println!("Process {} ({}) has locked the file", process.process_name, process.pid); } }, Err(e) => println!("Error occurred: {:?}", e), } ``` -------------------------------- ### Retrieve Process Handle Owner Information Source: https://docs.rs/wholock/0.0.1/src/wholock/interop.rs.html Queries the process token to resolve the user SID and account name associated with a given handle. ```rust pub(crate) fn get_handle_owner_info(handle: HANDLE) -> WholockResult { unsafe { let mut token_handle: HANDLE = HANDLE::default(); let result = OpenProcessToken(handle, TOKEN_QUERY, &mut token_handle); if result.is_err() { return Err(std::io::Error::last_os_error().into()); } let mut token_info_len = 0; let _ = GetTokenInformation(token_handle, TokenUser, None, 0, &mut token_info_len); let mut token_info = vec![0u8; token_info_len as usize]; if GetTokenInformation( token_handle, TokenUser, Some(token_info.as_mut_ptr() as *mut _), token_info_len, &mut token_info_len, ) .is_err() { return Err(std::io::Error::last_os_error().into()); } let token_user = &*(token_info.as_ptr() as *const TOKEN_USER); let sid = token_user.User.Sid; let mut name_size = 0u32; let mut domain_size = 0u32; let mut sid_type = SID_NAME_USE::default(); let _ = LookupAccountSidW( PCWSTR::null(), sid, PWSTR::null(), &mut name_size, PWSTR::null(), &mut domain_size, &mut sid_type, ); let mut name = vec![0u16; name_size as usize]; let mut domain = vec![0u16; domain_size as usize]; if LookupAccountSidW( PCWSTR::null(), sid, PWSTR::from_raw(name.as_mut_ptr()), &mut name_size, PWSTR::from_raw(domain.as_mut_ptr()), &mut domain_size, &mut sid_type, ) .is_err() { return Err(std::io::Error::last_os_error().into()); } let name = String::from_utf16_lossy(&name[..name_size as usize]); ``` -------------------------------- ### Calculate Product of Parsed Integers from Iterator Source: https://docs.rs/wholock/0.0.1/wholock/type.WholockResult.html Demonstrates using the `product` method on an iterator of `Result`s. If any element fails to parse, the entire operation returns an `Err`. Otherwise, it returns the product of all successfully parsed numbers. ```rust let nums = vec!["5", "10", "1", "2"]; let total: Result = nums.iter().map(|w| w.parse::()).product(); assert_eq!(total, Ok(100)); ``` ```rust let nums = vec!["5", "10", "one", "2"]; let total: Result = nums.iter().map(|w| w.parse::()).product(); assert!(total.is_err()); ``` -------------------------------- ### Duplicate a Windows Handle Source: https://docs.rs/wholock/0.0.1/src/wholock/interop.rs.html Duplicates a handle from an owner process into the current process context. ```rust pub(crate) fn duplicate_handle( current_process: windows::Win32::Foundation::HANDLE, handle_owner_process: windows::Win32::Foundation::HANDLE, handle: &HandleEntry, ) -> WholockResult { let mut target_handle: windows::Win32::Foundation::HANDLE = windows::Win32::Foundation::HANDLE(ptr::null_mut()); let result = unsafe { DuplicateHandle( handle_owner_process, windows::Win32::Foundation::HANDLE(handle.handle_value()), current_process, &mut target_handle, 0, false, DUPLICATE_HANDLE_OPTIONS(0), ) }; match result { Ok(_) => Ok(target_handle), Err(_) => { let err = unsafe { windows::Win32::Foundation::GetLastError() }; Err(WholockError::Win32Error(err)) } } } ``` -------------------------------- ### IntoIterator for Result (Err case) Source: https://docs.rs/wholock/0.0.1/wholock/type.WholockResult.html Demonstrates converting an Err(&str) Result into an iterator that yields no values. ```rust let x: Result = Err("nothing!"); let v: Vec = x.into_iter().collect(); assert_eq!(v, []); ``` -------------------------------- ### Clone Result<&mut T, E> to Result Source: https://docs.rs/wholock/0.0.1/wholock/type.WholockResult.html Maps a Result<&mut T, E> to a Result by cloning the contents of the Ok part. Requires T to implement the Clone trait. ```rust let mut val = 12; let x: Result<&mut i32, i32> = Ok(&mut val); assert_eq!(x, Ok(&mut 12)); let cloned = x.cloned(); assert_eq!(cloned, Ok(12)); ``` -------------------------------- ### fn from_iter Source: https://docs.rs/wholock/0.0.1/wholock/type.WholockResult.html Takes each element in the Iterator: if it is an Err, no further elements are taken, and the Err is returned. Should no Err occur, a container with the values of each Result is returned. ```APIDOC ## fn from_iter(iter: I) -> Result ### Description Takes each element in the Iterator: if it is an Err, no further elements are taken, and the Err is returned. Should no Err occur, a container with the values of each Result is returned. ### Parameters - **iter** (I) - Required - An iterator that implements IntoIterator where Item = Result. ``` -------------------------------- ### Wholock Functions Source: https://docs.rs/wholock/0.0.1/wholock/all.html This section details the available functions within the wholock crate. ```APIDOC ## Functions ### `unlock_file` #### Description Unlocks a file. ### `who_locks_file` #### Description Identifies who is locking a file. ``` -------------------------------- ### Wholock Structs Source: https://docs.rs/wholock/0.0.1/wholock/all.html This section details the available structs within the wholock crate. ```APIDOC ## Structs ### `ProcessInfo` #### Description Represents information about a process. ``` -------------------------------- ### Copy Result<&mut T, E> to Result Source: https://docs.rs/wholock/0.0.1/wholock/type.WholockResult.html Maps a Result<&mut T, E> to a Result by copying the contents of the Ok part. Requires T to implement the Copy trait. ```rust let mut val = 12; let x: Result<&mut i32, i32> = Ok(&mut val); assert_eq!(x, Ok(&mut 12)); let copied = x.copied(); assert_eq!(copied, Ok(12)); ``` -------------------------------- ### Unwrap `Ok` Value with `expect` (Panics on `Err`) Source: https://docs.rs/wholock/0.0.1/wholock/type.WholockResult.html The `expect` method returns the contained `Ok` value or panics if the `Result` is `Err`. The panic message includes the provided message and the error's content. Use with caution, as panics can abort the program. ```rust let x: Result = Err("emergency failure"); x.expect("Testing expect"); // panics with `Testing expect: emergency failure` ``` ```rust let path = std::env::var("IMPORTANT_PATH") .expect("env variable `IMPORTANT_PATH` should be set by `wrapper_script.sh`"); ``` -------------------------------- ### Test wide buffer conversion Source: https://docs.rs/wholock/0.0.1/src/wholock/interop.rs.html Validates conversion of UTF-16 buffers to strings and handles encoding errors. ```rust #[test] fn test_convert_wide_buffer() { let test_str = "Hello, 世界"; let wide: Vec = test_str.encode_utf16().collect(); let result = convert_wide_buffer(&wide, wide.len()); assert!(result.is_ok()); assert_eq!(result.unwrap(), test_str); let invalid_utf16 = vec![0xD800]; let result = convert_wide_buffer(&invalid_utf16, invalid_utf16.len()); assert!(matches!(result, Err(WholockError::EncodingError(_)))); } ``` -------------------------------- ### Test filename extraction Source: https://docs.rs/wholock/0.0.1/src/wholock/interop.rs.html Checks the extraction of filenames from paths and error handling for invalid paths. ```rust #[test] fn test_extract_filename() { let path = r"C:\Users\test\file.txt"; let result = extract_filename(path); assert!(result.is_ok()); assert_eq!(result.unwrap(), "file.txt"); let invalid_path = ""; let result = extract_filename(invalid_path); assert!(matches!(result, Err(WholockError::PathError(_)))); } ``` -------------------------------- ### Result::as_deref_mut Source: https://docs.rs/wholock/0.0.1/wholock/type.WholockResult.html Converts `&mut Result` to `Result<&mut ::Target, &mut E>` by coercing the `Ok` variant via `DerefMut`. ```APIDOC ## GET /api/health ### Description Checks the health status of the application. ### Method GET ### Endpoint /api/health ### Response #### Success Response (200 OK) - **status** (string) - The health status of the application (e.g., "healthy", "degraded", "unhealthy"). #### Response Example ```json { "status": "healthy" } ``` ``` -------------------------------- ### pub const fn as_ref(&self) -> Result<&T, &E> Source: https://docs.rs/wholock/0.0.1/wholock/type.WholockResult.html Converts a reference to a Result into a Result<&T, &E>, allowing immutable access to the contained values. ```APIDOC ## pub const fn as_ref(&self) -> Result<&T, &E> ### Description Converts from `&Result` to `Result<&T, &E>`. Produces a new `Result`, containing a reference into the original, leaving the original in place. ### Method `Result::as_ref` ### Request Example ```rust let x: Result = Ok(2); assert_eq!(x.as_ref(), Ok(&2)); let x: Result = Err("Error"); assert_eq!(x.as_ref(), Err(&"Error")); ``` ### Response Example ```json { "example": "Ok(&value)" or "Err(&error_value)" } ``` ``` -------------------------------- ### WholockResult Enum Variants Source: https://docs.rs/wholock/0.0.1/wholock/type.WholockResult.html Illustrates the structure of the WholockResult enum, showing its Ok and Err variants. ```rust pub enum WholockResult { Ok(T), Err(WholockError), } ``` -------------------------------- ### Implement From for WholockError Source: https://docs.rs/wholock/0.0.1/src/wholock/error.rs.html Enables direct conversion of `std::io::Error` into `WholockError::IoError`. ```rust impl From for WholockError { fn from(error: std::io::Error) -> Self { WholockError::IoError(error) } } ```