diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml new file mode 100644 index 0000000..21011d0 --- /dev/null +++ b/.github/workflows/build.yml @@ -0,0 +1,26 @@ +name: Build + +on: + push: + branches: [master] + pull_request: + branches: [master] + +jobs: + build: + runs-on: windows-latest + steps: + - uses: actions/checkout@v4 + with: + submodules: recursive + + - name: Install Dokan + run: winget install -e --id dokan-dev.Dokany --accept-source-agreements --accept-package-agreements + + - uses: dtolnay/rust-toolchain@stable + + - name: Build + run: cargo check --examples --tests + + - name: Test + run: cargo test diff --git a/.gitignore b/.gitignore index 332008f..7377b8f 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,4 @@ /target **/*.rs.bk .idea/ +Cargo.lock diff --git a/Cargo.lock b/Cargo.lock deleted file mode 100644 index f8234ae..0000000 --- a/Cargo.lock +++ /dev/null @@ -1,406 +0,0 @@ -# This file is automatically @generated by Cargo. -# It is not intended for manual editing. -version = 4 - -[[package]] -name = "aho-corasick" -version = "1.1.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8e60d3430d3a69478ad0993f19238d2df97c507009a52b3c10addcd7f6bcb916" -dependencies = [ - "memchr", -] - -[[package]] -name = "anstream" -version = "0.6.18" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8acc5369981196006228e28809f761875c0327210a891e941f4c683b3a99529b" -dependencies = [ - "anstyle", - "anstyle-parse", - "anstyle-query", - "anstyle-wincon", - "colorchoice", - "is_terminal_polyfill", - "utf8parse", -] - -[[package]] -name = "anstyle" -version = "1.0.10" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "55cc3b69f167a1ef2e161439aa98aed94e6028e5f9a59be9a6ffb47aef1651f9" - -[[package]] -name = "anstyle-parse" -version = "0.2.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3b2d16507662817a6a20a9ea92df6652ee4f94f914589377d69f3b21bc5798a9" -dependencies = [ - "utf8parse", -] - -[[package]] -name = "anstyle-query" -version = "1.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "79947af37f4177cfead1110013d678905c37501914fba0efea834c3fe9a8d60c" -dependencies = [ - "windows-sys", -] - -[[package]] -name = "anstyle-wincon" -version = "3.0.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ca3534e77181a9cc07539ad51f2141fe32f6c3ffd4df76db8ad92346b003ae4e" -dependencies = [ - "anstyle", - "once_cell", - "windows-sys", -] - -[[package]] -name = "autocfg" -version = "1.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ace50bade8e6234aa140d9a2f552bbee1db4d353f69b8217bc503490fc1a9f26" - -[[package]] -name = "bitflags" -version = "2.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5c8214115b7bf84099f1309324e63141d4c5d7cc26862f97a0a857dbefe165bd" - -[[package]] -name = "cc" -version = "1.2.20" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "04da6a0d40b948dfc4fa8f5bbf402b0fc1a64a28dbf7d12ffd683550f2c1b63a" -dependencies = [ - "shlex", -] - -[[package]] -name = "cfg-if" -version = "1.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" - -[[package]] -name = "cfg_aliases" -version = "0.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "613afe47fcd5fac7ccf1db93babcb082c5994d996f20b8b159f2ad1658eb5724" - -[[package]] -name = "clap" -version = "4.5.37" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eccb054f56cbd38340b380d4a8e69ef1f02f1af43db2f0cc817a4774d80ae071" -dependencies = [ - "clap_builder", -] - -[[package]] -name = "clap_builder" -version = "4.5.37" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "efd9466fac8543255d3b1fcad4762c5e116ffe808c8a3043d4263cd4fd4862a2" -dependencies = [ - "anstream", - "anstyle", - "clap_lex", - "strsim", -] - -[[package]] -name = "clap_lex" -version = "0.7.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f46ad14479a25103f283c0f10005961cf086d8dc42205bb44c46ac563475dca6" - -[[package]] -name = "colorchoice" -version = "1.0.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5b63caa9aa9397e2d9480a9b13673856c78d8ac123288526c37d7839f2a86990" - -[[package]] -name = "ctrlc" -version = "3.4.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "697b5419f348fd5ae2478e8018cb016c00a5881c7f46c717de98ffd135a5651c" -dependencies = [ - "nix", - "windows-sys", -] - -[[package]] -name = "dokan" -version = "0.3.1+dokan230" -dependencies = [ - "bitflags", - "clap", - "ctrlc", - "dokan-sys", - "lazy_static", - "parking_lot", - "regex", - "widestring", - "winapi", -] - -[[package]] -name = "dokan-sys" -version = "0.3.1+dokan230" -dependencies = [ - "cc", - "libc", - "winapi", -] - -[[package]] -name = "is_terminal_polyfill" -version = "1.70.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7943c866cc5cd64cbc25b2e01621d07fa8eb2a1a23160ee81ce38704e97b8ecf" - -[[package]] -name = "lazy_static" -version = "1.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe" - -[[package]] -name = "libc" -version = "0.2.172" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d750af042f7ef4f724306de029d18836c26c1765a54a6a3f094cbd23a7267ffa" - -[[package]] -name = "lock_api" -version = "0.4.12" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "07af8b9cdd281b7915f413fa73f29ebd5d55d0d3f0155584dade1ff18cea1b17" -dependencies = [ - "autocfg", - "scopeguard", -] - -[[package]] -name = "memchr" -version = "2.7.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "78ca9ab1a0babb1e7d5695e3530886289c18cf2f87ec19a575a0abdce112e3a3" - -[[package]] -name = "nix" -version = "0.29.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "71e2746dc3a24dd78b3cfcb7be93368c6de9963d30f43a6a73998a9cf4b17b46" -dependencies = [ - "bitflags", - "cfg-if", - "cfg_aliases", - "libc", -] - -[[package]] -name = "once_cell" -version = "1.21.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "42f5e15c9953c5e4ccceeb2e7382a716482c34515315f7b03532b8b4e8393d2d" - -[[package]] -name = "parking_lot" -version = "0.12.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f1bf18183cf54e8d6059647fc3063646a1801cf30896933ec2311622cc4b9a27" -dependencies = [ - "lock_api", - "parking_lot_core", -] - -[[package]] -name = "parking_lot_core" -version = "0.9.10" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1e401f977ab385c9e4e3ab30627d6f26d00e2c73eef317493c4ec6d468726cf8" -dependencies = [ - "cfg-if", - "libc", - "redox_syscall", - "smallvec", - "windows-targets", -] - -[[package]] -name = "redox_syscall" -version = "0.5.11" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d2f103c6d277498fbceb16e84d317e2a400f160f46904d5f5410848c829511a3" -dependencies = [ - "bitflags", -] - -[[package]] -name = "regex" -version = "1.11.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b544ef1b4eac5dc2db33ea63606ae9ffcfac26c1416a2806ae0bf5f56b201191" -dependencies = [ - "aho-corasick", - "memchr", - "regex-automata", - "regex-syntax", -] - -[[package]] -name = "regex-automata" -version = "0.4.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "809e8dc61f6de73b46c85f4c96486310fe304c434cfa43669d7b40f711150908" -dependencies = [ - "aho-corasick", - "memchr", - "regex-syntax", -] - -[[package]] -name = "regex-syntax" -version = "0.8.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2b15c43186be67a4fd63bee50d0303afffcef381492ebe2c5d87f324e1b8815c" - -[[package]] -name = "scopeguard" -version = "1.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49" - -[[package]] -name = "shlex" -version = "1.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64" - -[[package]] -name = "smallvec" -version = "1.15.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8917285742e9f3e1683f0a9c4e6b57960b7314d0b08d30d1ecd426713ee2eee9" - -[[package]] -name = "strsim" -version = "0.11.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4f" - -[[package]] -name = "utf8parse" -version = "0.2.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "06abde3611657adf66d383f00b093d7faecc7fa57071cce2578660c9f1010821" - -[[package]] -name = "widestring" -version = "1.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dd7cf3379ca1aac9eea11fba24fd7e315d621f8dfe35c8d7d2be8b793726e07d" - -[[package]] -name = "winapi" -version = "0.3.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419" -dependencies = [ - "winapi-i686-pc-windows-gnu", - "winapi-x86_64-pc-windows-gnu", -] - -[[package]] -name = "winapi-i686-pc-windows-gnu" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" - -[[package]] -name = "winapi-x86_64-pc-windows-gnu" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" - -[[package]] -name = "windows-sys" -version = "0.59.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1e38bc4d79ed67fd075bcc251a1c39b32a1776bbe92e5bef1f0bf1f8c531853b" -dependencies = [ - "windows-targets", -] - -[[package]] -name = "windows-targets" -version = "0.52.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9b724f72796e036ab90c1021d4780d4d3d648aca59e491e6b98e725b84e99973" -dependencies = [ - "windows_aarch64_gnullvm", - "windows_aarch64_msvc", - "windows_i686_gnu", - "windows_i686_gnullvm", - "windows_i686_msvc", - "windows_x86_64_gnu", - "windows_x86_64_gnullvm", - "windows_x86_64_msvc", -] - -[[package]] -name = "windows_aarch64_gnullvm" -version = "0.52.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3" - -[[package]] -name = "windows_aarch64_msvc" -version = "0.52.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469" - -[[package]] -name = "windows_i686_gnu" -version = "0.52.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8e9b5ad5ab802e97eb8e295ac6720e509ee4c243f69d781394014ebfe8bbfa0b" - -[[package]] -name = "windows_i686_gnullvm" -version = "0.52.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66" - -[[package]] -name = "windows_i686_msvc" -version = "0.52.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66" - -[[package]] -name = "windows_x86_64_gnu" -version = "0.52.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78" - -[[package]] -name = "windows_x86_64_gnullvm" -version = "0.52.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d" - -[[package]] -name = "windows_x86_64_msvc" -version = "0.52.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec" diff --git a/dokan-sys/Cargo.toml b/dokan-sys/Cargo.toml index ae10f8f..b30c03b 100644 --- a/dokan-sys/Cargo.toml +++ b/dokan-sys/Cargo.toml @@ -10,7 +10,7 @@ keywords = ["ffi", "dokan", "bindings", "driver", "filesystem"] categories = ["external-ffi-bindings"] readme = "README.md" license = "MIT" -edition = "2021" +edition = "2024" links = "dokan" build = "build.rs" @@ -18,8 +18,7 @@ build = "build.rs" appveyor = { repository = "Liryna/dokan-rust" } [dependencies] -libc = "0.2" -winapi = { version = "0.3", features = ["std", "basetsd", "fileapi", "minwinbase", "minwindef", "ntdef", "winnt"] } +windows-sys = { version = "0.61", features = ["Win32_Foundation", "Win32_Storage_FileSystem", "Win32_Security", "Win32_System_IO", "Win32_System_Threading"] } [build-dependencies] cc = "1.2" diff --git a/dokan-sys/src/lib.rs b/dokan-sys/src/lib.rs index 13976bf..2701246 100644 --- a/dokan-sys/src/lib.rs +++ b/dokan-sys/src/lib.rs @@ -13,26 +13,40 @@ //! [Dokan's documentation]: https://dokan-dev.github.io/dokany-doc/html/ //! [`dokan`]: https://crates.io/crates/dokan -use libc::c_int; +use core::ffi::{c_int, c_void}; use win32::PWIN32_FIND_STREAM_DATA; -use winapi::{ - shared::{ - basetsd::ULONG64, - minwindef::{BOOL, DWORD, FILETIME, LPCVOID, LPDWORD, LPVOID, MAX_PATH}, - ntdef::{ - BOOLEAN, HANDLE, LONGLONG, LPCWSTR, LPWSTR, NTSTATUS, PULONG, PULONGLONG, PVOID, SCHAR, - UCHAR, ULONG, UNICODE_STRING, USHORT, WCHAR, - }, - }, - um::{ - fileapi::LPBY_HANDLE_FILE_INFORMATION, - minwinbase::PWIN32_FIND_DATAW, - winnt::{ - ACCESS_MASK, PHANDLE, PSECURITY_DESCRIPTOR, PSECURITY_INFORMATION, - WAITORTIMERCALLBACKFUNC, - }, - }, +use windows_sys::Win32::{ + Foundation::{FILETIME, HANDLE, MAX_PATH, NTSTATUS, UNICODE_STRING}, + Security::PSECURITY_DESCRIPTOR, + Storage::FileSystem::{BY_HANDLE_FILE_INFORMATION, WIN32_FIND_DATAW}, + System::Threading::WAITORTIMERCALLBACK, }; +use windows_sys::core::{BOOL, PCWSTR, PWSTR}; + +/// Win32 `BOOLEAN` type (unsigned 8-bit). +pub type BOOLEAN = u8; + +// Type aliases matching the old winapi names for compatibility. +pub type ULONG64 = u64; +pub type DWORD = u32; +pub type ULONG = u32; +pub type USHORT = u16; +pub type UCHAR = u8; +pub type WCHAR = u16; +pub type SCHAR = i8; +pub type LONGLONG = i64; +pub type ACCESS_MASK = u32; + +pub type PVOID = *mut c_void; +pub type LPVOID = *mut c_void; +pub type LPCVOID = *const c_void; +pub type LPDWORD = *mut u32; +pub type PULONG = *mut u32; +pub type PULONGLONG = *mut u64; +pub type PHANDLE = *mut HANDLE; +pub type PSECURITY_INFORMATION = *mut u32; +pub type LPBY_HANDLE_FILE_INFORMATION = *mut BY_HANDLE_FILE_INFORMATION; +pub type PWIN32_FIND_DATAW = *mut WIN32_FIND_DATAW; pub mod win32; @@ -52,7 +66,7 @@ pub const DOKAN_OPTION_ENABLE_UNMOUNT_NETWORK_DRIVE: ULONG = 1 << 10; pub const DOKAN_OPTION_DISPATCH_DRIVER_LOGS: ULONG = 1 << 11; pub const DOKAN_OPTION_ALLOW_IPC_BATCHING: ULONG = 1 << 12; -pub type DOKAN_HANDLE = *mut libc::c_void; +pub type DOKAN_HANDLE = *mut c_void; pub type PDOKAN_HANDLE = *mut DOKAN_HANDLE; pub const VOLUME_SECURITY_DESCRIPTOR_MAX_SIZE: usize = 1024 * 16; @@ -64,8 +78,8 @@ pub struct DOKAN_OPTIONS { pub SingleThread: BOOLEAN, pub Options: ULONG, pub GlobalContext: ULONG64, - pub MountPoint: LPCWSTR, - pub UNCName: LPCWSTR, + pub MountPoint: PCWSTR, + pub UNCName: PCWSTR, pub Timeout: ULONG, pub AllocationUnitSize: ULONG, pub SectorSize: ULONG, @@ -93,8 +107,8 @@ pub struct DOKAN_FILE_INFO { pub type PDOKAN_FILE_INFO = *mut DOKAN_FILE_INFO; -pub type PFillFindData = unsafe extern "stdcall" fn(PWIN32_FIND_DATAW, PDOKAN_FILE_INFO) -> c_int; -pub type PFillFindStreamData = unsafe extern "stdcall" fn(PWIN32_FIND_STREAM_DATA, PVOID) -> BOOL; +pub type PFillFindData = unsafe extern "system" fn(PWIN32_FIND_DATAW, PDOKAN_FILE_INFO) -> c_int; +pub type PFillFindStreamData = unsafe extern "system" fn(PWIN32_FIND_STREAM_DATA, PVOID) -> BOOL; #[repr(C)] pub struct DOKAN_ACCESS_STATE { @@ -125,8 +139,8 @@ pub type PDOKAN_IO_SECURITY_CONTEXT = *mut DOKAN_IO_SECURITY_CONTEXT; #[derive(Clone)] pub struct DOKAN_OPERATIONS { pub ZwCreateFile: Option< - extern "stdcall" fn( - FileName: LPCWSTR, + extern "system" fn( + FileName: PCWSTR, SecurityContext: PDOKAN_IO_SECURITY_CONTEXT, DesiredAccess: ACCESS_MASK, FileAttributes: ULONG, @@ -136,11 +150,11 @@ pub struct DOKAN_OPERATIONS { DokanFileInfo: PDOKAN_FILE_INFO, ) -> NTSTATUS, >, - pub Cleanup: Option, - pub CloseFile: Option, + pub Cleanup: Option, + pub CloseFile: Option, pub ReadFile: Option< - extern "stdcall" fn( - FileName: LPCWSTR, + extern "system" fn( + FileName: PCWSTR, Buffer: LPVOID, BufferLength: DWORD, ReadLength: LPDWORD, @@ -149,8 +163,8 @@ pub struct DOKAN_OPERATIONS { ) -> NTSTATUS, >, pub WriteFile: Option< - extern "stdcall" fn( - FileName: LPCWSTR, + extern "system" fn( + FileName: PCWSTR, Buffer: LPCVOID, NumberOfBytesToWrite: DWORD, NumberOfBytesWritten: LPDWORD, @@ -159,39 +173,39 @@ pub struct DOKAN_OPERATIONS { ) -> NTSTATUS, >, pub FlushFileBuffers: - Option NTSTATUS>, + Option NTSTATUS>, pub GetFileInformation: Option< - extern "stdcall" fn( - FileName: LPCWSTR, + extern "system" fn( + FileName: PCWSTR, Buffer: LPBY_HANDLE_FILE_INFORMATION, DokanFileInfo: PDOKAN_FILE_INFO, ) -> NTSTATUS, >, pub FindFiles: Option< - extern "stdcall" fn( - FileName: LPCWSTR, + extern "system" fn( + FileName: PCWSTR, FillFindData: PFillFindData, DokanFileInfo: PDOKAN_FILE_INFO, ) -> NTSTATUS, >, pub FindFilesWithPattern: Option< - extern "stdcall" fn( - PathName: LPCWSTR, - SearchPattern: LPCWSTR, + extern "system" fn( + PathName: PCWSTR, + SearchPattern: PCWSTR, FillFindData: PFillFindData, DokanFileInfo: PDOKAN_FILE_INFO, ) -> NTSTATUS, >, pub SetFileAttributes: Option< - extern "stdcall" fn( - FileName: LPCWSTR, + extern "system" fn( + FileName: PCWSTR, FileAttributes: DWORD, DokanFileInfo: PDOKAN_FILE_INFO, ) -> NTSTATUS, >, pub SetFileTime: Option< - extern "stdcall" fn( - FileName: LPCWSTR, + extern "system" fn( + FileName: PCWSTR, creation_time: *const FILETIME, last_access_time: *const FILETIME, last_write_time: *const FILETIME, @@ -199,49 +213,49 @@ pub struct DOKAN_OPERATIONS { ) -> NTSTATUS, >, pub DeleteFile: - Option NTSTATUS>, + Option NTSTATUS>, pub DeleteDirectory: - Option NTSTATUS>, + Option NTSTATUS>, pub MoveFile: Option< - extern "stdcall" fn( - FileName: LPCWSTR, - NewFileName: LPCWSTR, + extern "system" fn( + FileName: PCWSTR, + NewFileName: PCWSTR, ReplaceIfExisting: BOOL, DokanFileInfo: PDOKAN_FILE_INFO, ) -> NTSTATUS, >, pub SetEndOfFile: Option< - extern "stdcall" fn( - FileName: LPCWSTR, + extern "system" fn( + FileName: PCWSTR, ByteOffset: LONGLONG, DokanFileInfo: PDOKAN_FILE_INFO, ) -> NTSTATUS, >, pub SetAllocationSize: Option< - extern "stdcall" fn( - FileName: LPCWSTR, + extern "system" fn( + FileName: PCWSTR, AllocSize: LONGLONG, DokanFileInfo: PDOKAN_FILE_INFO, ) -> NTSTATUS, >, pub LockFile: Option< - extern "stdcall" fn( - FileName: LPCWSTR, + extern "system" fn( + FileName: PCWSTR, ByteOffset: LONGLONG, Length: LONGLONG, DokanFileInfo: PDOKAN_FILE_INFO, ) -> NTSTATUS, >, pub UnlockFile: Option< - extern "stdcall" fn( - FileName: LPCWSTR, + extern "system" fn( + FileName: PCWSTR, ByteOffset: LONGLONG, Length: LONGLONG, DokanFileInfo: PDOKAN_FILE_INFO, ) -> NTSTATUS, >, pub GetDiskFreeSpace: Option< - extern "stdcall" fn( + extern "system" fn( FreeBytesAvailable: PULONGLONG, TotalNumberOfBytes: PULONGLONG, TotalNumberOfFreeBytes: PULONGLONG, @@ -249,24 +263,23 @@ pub struct DOKAN_OPERATIONS { ) -> NTSTATUS, >, pub GetVolumeInformation: Option< - extern "stdcall" fn( - VolumeNameBuffer: LPWSTR, + extern "system" fn( + VolumeNameBuffer: PWSTR, VolumeNameSize: DWORD, VolumeSerialNumber: LPDWORD, MaximumComponentLength: LPDWORD, FileSystemFlags: LPDWORD, - FileSystemNameBuffer: LPWSTR, + FileSystemNameBuffer: PWSTR, FileSystemNameSize: DWORD, DokanFileInfo: PDOKAN_FILE_INFO, ) -> NTSTATUS, >, - pub Mounted: Option< - extern "stdcall" fn(MountPoint: LPCWSTR, DokanFileInfo: PDOKAN_FILE_INFO) -> NTSTATUS, - >, - pub Unmounted: Option NTSTATUS>, + pub Mounted: + Option NTSTATUS>, + pub Unmounted: Option NTSTATUS>, pub GetFileSecurity: Option< - extern "stdcall" fn( - FileName: LPCWSTR, + extern "system" fn( + FileName: PCWSTR, PSECURITY_INFORMATION: PSECURITY_INFORMATION, PSECURITY_DESCRIPTOR: PSECURITY_DESCRIPTOR, BufferLength: ULONG, @@ -275,8 +288,8 @@ pub struct DOKAN_OPERATIONS { ) -> NTSTATUS, >, pub SetFileSecurity: Option< - extern "stdcall" fn( - FileName: LPCWSTR, + extern "system" fn( + FileName: PCWSTR, SecurityInformation: PSECURITY_INFORMATION, SecurityDescriptor: PSECURITY_DESCRIPTOR, BufferLength: ULONG, @@ -284,8 +297,8 @@ pub struct DOKAN_OPERATIONS { ) -> NTSTATUS, >, pub FindStreams: Option< - extern "stdcall" fn( - FileName: LPCWSTR, + extern "system" fn( + FileName: PCWSTR, FillFindStreamData: PFillFindStreamData, FindStreamContext: PVOID, DokanFileInfo: PDOKAN_FILE_INFO, @@ -307,7 +320,7 @@ pub const DOKAN_VERSION_ERROR: c_int = -7; #[repr(C)] pub struct DOKAN_MOUNT_POINT_INFO { pub Type: ULONG, - pub MountPoint: [WCHAR; MAX_PATH], + pub MountPoint: [WCHAR; MAX_PATH as usize], pub UNCName: [WCHAR; 64], pub DeviceName: [WCHAR; 64], pub SessionId: ULONG, @@ -316,7 +329,7 @@ pub struct DOKAN_MOUNT_POINT_INFO { pub type PDOKAN_MOUNT_POINT_INFO = *mut DOKAN_MOUNT_POINT_INFO; -extern "stdcall" { +unsafe extern "system" { pub fn DokanInit(); pub fn DokanShutdown(); pub fn DokanMain(DokanOptions: PDOKAN_OPTIONS, DokanOperations: PDOKAN_OPERATIONS) -> c_int; @@ -333,7 +346,7 @@ extern "stdcall" { pub fn DokanRegisterWaitForFileSystemClosed( DokanInstance: DOKAN_HANDLE, WaitHandle: PHANDLE, - Callback: WAITORTIMERCALLBACKFUNC, + Callback: WAITORTIMERCALLBACK, Context: PVOID, dwMilliseconds: ULONG, ) -> BOOL; @@ -343,8 +356,8 @@ extern "stdcall" { ) -> BOOL; pub fn DokanCloseHandle(DokanInstance: DOKAN_HANDLE); pub fn DokanUnmount(DriveLetter: WCHAR) -> BOOL; - pub fn DokanRemoveMountPoint(MountPoint: LPCWSTR) -> BOOL; - pub fn DokanIsNameInExpression(Expression: LPCWSTR, Name: LPCWSTR, IgnoreCase: BOOL) -> BOOL; + pub fn DokanRemoveMountPoint(MountPoint: PCWSTR) -> BOOL; + pub fn DokanIsNameInExpression(Expression: PCWSTR, Name: PCWSTR, IgnoreCase: BOOL) -> BOOL; pub fn DokanVersion() -> ULONG; pub fn DokanDriverVersion() -> ULONG; pub fn DokanResetTimeout(Timeout: ULONG, DokanFileInfo: PDOKAN_FILE_INFO) -> BOOL; @@ -362,20 +375,20 @@ extern "stdcall" { ); pub fn DokanNotifyCreate( DokanInstance: DOKAN_HANDLE, - FilePath: LPCWSTR, + FilePath: PCWSTR, IsDirectory: BOOL, ) -> BOOL; pub fn DokanNotifyDelete( DokanInstance: DOKAN_HANDLE, - FilePath: LPCWSTR, + FilePath: PCWSTR, IsDirectory: BOOL, ) -> BOOL; - pub fn DokanNotifyUpdate(DokanInstance: DOKAN_HANDLE, FilePath: LPCWSTR) -> BOOL; - pub fn DokanNotifyXAttrUpdate(DokanInstance: DOKAN_HANDLE, FilePath: LPCWSTR) -> BOOL; + pub fn DokanNotifyUpdate(DokanInstance: DOKAN_HANDLE, FilePath: PCWSTR) -> BOOL; + pub fn DokanNotifyXAttrUpdate(DokanInstance: DOKAN_HANDLE, FilePath: PCWSTR) -> BOOL; pub fn DokanNotifyRename( DokanInstance: DOKAN_HANDLE, - OldPath: LPCWSTR, - NewPath: LPCWSTR, + OldPath: PCWSTR, + NewPath: PCWSTR, IsDirectory: BOOL, IsInSameDirectory: BOOL, ) -> BOOL; diff --git a/dokan-sys/src/win32.rs b/dokan-sys/src/win32.rs index 8172942..54c5e7a 100644 --- a/dokan-sys/src/win32.rs +++ b/dokan-sys/src/win32.rs @@ -1,12 +1,9 @@ -use winapi::shared::{ - minwindef::MAX_PATH, - ntdef::{LARGE_INTEGER, WCHAR}, -}; +use windows_sys::Win32::Foundation::MAX_PATH; #[repr(C)] pub struct WIN32_FIND_STREAM_DATA { - pub StreamSize: LARGE_INTEGER, - pub cStreamName: [WCHAR; MAX_PATH + 36], + pub StreamSize: i64, + pub cStreamName: [u16; MAX_PATH as usize + 36], } pub type PWIN32_FIND_STREAM_DATA = *mut WIN32_FIND_STREAM_DATA; diff --git a/dokan/Cargo.toml b/dokan/Cargo.toml index af3ccd1..8ce203d 100644 --- a/dokan/Cargo.toml +++ b/dokan/Cargo.toml @@ -10,22 +10,31 @@ keywords = ["dokan", "bindings", "driver", "filesystem"] categories = ["external-ffi-bindings"] readme = "README.md" license = "MIT" -edition = "2021" +edition = "2024" [badges] appveyor = { repository = "Liryna/dokan-rust" } [dependencies] -bitflags = "2.9" +bitflags = "2.11" dokan-sys = { path = "../dokan-sys" } widestring = "1.2" -winapi = { version = "0.3", features = ["std", "errhandlingapi", "handleapi", "heapapi", "ioapiset", "minwinbase", "minwindef", "ntdef", "ntstatus", "processenv", "processthreadsapi", "sddl", "securitybaseapi", "synchapi", "winbase", "winerror", "winnt"] } +windows-sys = { version = "0.61", features = [ + "Win32_Foundation", + "Win32_Storage_FileSystem", + "Win32_Security", + "Win32_Security_Authorization", + "Win32_System_Environment", + "Win32_System_IO", + "Win32_System_Memory", + "Win32_System_RemoteDesktop", + "Win32_System_SystemServices", + "Win32_System_Threading", +] } [dev-dependencies] clap = "4.5" ctrlc = "3.4" -lazy_static = "1.5" -parking_lot = "0.12" regex = "1.11" [package.metadata.docs.rs] diff --git a/dokan/examples/memfs/main.rs b/dokan/examples/memfs/main.rs index 35de54d..394c65c 100644 --- a/dokan/examples/memfs/main.rs +++ b/dokan/examples/memfs/main.rs @@ -7,27 +7,46 @@ use std::{ hash::{Hash, Hasher}, os::windows::io::AsRawHandle, sync::{ - atomic::{AtomicBool, AtomicU64, Ordering}, Arc, Mutex, RwLock, Weak, + atomic::{AtomicBool, AtomicU64, Ordering}, }, time::SystemTime, }; use clap::{Arg, ArgAction, Command}; use dokan::{ - init, shutdown, unmount, CreateFileInfo, DiskSpaceInfo, FileInfo, FileSystemHandler, - FileSystemMounter, FileTimeOperation, FillDataError, FillDataResult, FindData, FindStreamData, - MountFlags, MountOptions, OperationInfo, OperationResult, VolumeInfo, IO_SECURITY_CONTEXT, + CreateFileInfo, DiskSpaceInfo, FileInfo, FileSystemHandler, FileSystemMounter, + FileTimeOperation, FillDataError, FillDataResult, FindData, FindStreamData, + IO_SECURITY_CONTEXT, MountFlags, MountOptions, OperationInfo, OperationResult, VolumeInfo, + init, shutdown, unmount, }; -use dokan_sys::win32::{ - FILE_CREATE, FILE_DELETE_ON_CLOSE, FILE_DIRECTORY_FILE, FILE_MAXIMUM_DISPOSITION, - FILE_NON_DIRECTORY_FILE, FILE_OPEN, FILE_OPEN_IF, FILE_OVERWRITE, FILE_OVERWRITE_IF, - FILE_SUPERSEDE, +use dokan_sys::{ + ACCESS_MASK, + win32::{ + FILE_CREATE, FILE_DELETE_ON_CLOSE, FILE_DIRECTORY_FILE, FILE_MAXIMUM_DISPOSITION, + FILE_NON_DIRECTORY_FILE, FILE_OPEN, FILE_OPEN_IF, FILE_OVERWRITE, FILE_OVERWRITE_IF, + FILE_SUPERSEDE, + }, }; use widestring::{U16CStr, U16CString, U16Str, U16String}; -use winapi::{ - shared::{ntdef, ntstatus::*}, - um::winnt, +use windows_sys::Win32::{ + Foundation::{ + HANDLE, STATUS_ACCESS_DENIED, STATUS_BUFFER_OVERFLOW, STATUS_CANNOT_DELETE, + STATUS_DELETE_PENDING, STATUS_DIRECTORY_NOT_EMPTY, STATUS_FILE_IS_A_DIRECTORY, + STATUS_INVALID_DEVICE_REQUEST, STATUS_INVALID_PARAMETER, STATUS_NOT_A_DIRECTORY, + STATUS_OBJECT_NAME_COLLISION, STATUS_OBJECT_NAME_INVALID, STATUS_OBJECT_NAME_NOT_FOUND, + STATUS_SHARING_VIOLATION, + }, + Security::PSECURITY_DESCRIPTOR, + Storage::FileSystem::{ + FILE_APPEND_DATA, FILE_ATTRIBUTE_ARCHIVE, FILE_ATTRIBUTE_DIRECTORY, FILE_ATTRIBUTE_HIDDEN, + FILE_ATTRIBUTE_NORMAL, FILE_ATTRIBUTE_NOT_CONTENT_INDEXED, FILE_ATTRIBUTE_OFFLINE, + FILE_ATTRIBUTE_READONLY, FILE_ATTRIBUTE_SYSTEM, FILE_ATTRIBUTE_TEMPORARY, FILE_WRITE_DATA, + }, + System::SystemServices::{ + FILE_CASE_PRESERVED_NAMES, FILE_CASE_SENSITIVE_SEARCH, FILE_NAMED_STREAMS, + FILE_PERSISTENT_ACLS, FILE_UNICODE_ON_DISK, + }, }; use crate::{path::FullName, security::SecurityDescriptor}; @@ -56,13 +75,13 @@ struct Attributes { impl Attributes { fn new(attrs: u32) -> Self { - const SUPPORTED_ATTRS: u32 = winnt::FILE_ATTRIBUTE_ARCHIVE - | winnt::FILE_ATTRIBUTE_HIDDEN - | winnt::FILE_ATTRIBUTE_NOT_CONTENT_INDEXED - | winnt::FILE_ATTRIBUTE_OFFLINE - | winnt::FILE_ATTRIBUTE_READONLY - | winnt::FILE_ATTRIBUTE_SYSTEM - | winnt::FILE_ATTRIBUTE_TEMPORARY; + const SUPPORTED_ATTRS: u32 = FILE_ATTRIBUTE_ARCHIVE + | FILE_ATTRIBUTE_HIDDEN + | FILE_ATTRIBUTE_NOT_CONTENT_INDEXED + | FILE_ATTRIBUTE_OFFLINE + | FILE_ATTRIBUTE_READONLY + | FILE_ATTRIBUTE_SYSTEM + | FILE_ATTRIBUTE_TEMPORARY; Self { value: attrs & SUPPORTED_ATTRS, } @@ -71,10 +90,10 @@ impl Attributes { fn get_output_attrs(&self, is_dir: bool) -> u32 { let mut attrs = self.value; if is_dir { - attrs |= winnt::FILE_ATTRIBUTE_DIRECTORY; + attrs |= FILE_ATTRIBUTE_DIRECTORY; } if attrs == 0 { - attrs = winnt::FILE_ATTRIBUTE_NORMAL + attrs = FILE_ATTRIBUTE_NORMAL } attrs } @@ -410,13 +429,13 @@ impl MemFsHandler { name: &FullName, attrs: u32, delete_pending: bool, - creator_desc: winnt::PSECURITY_DESCRIPTOR, - token: ntdef::HANDLE, + creator_desc: PSECURITY_DESCRIPTOR, + token: HANDLE, parent: &Arc, children: &mut HashMap, is_dir: bool, ) -> OperationResult> { - if attrs & winnt::FILE_ATTRIBUTE_READONLY > 0 && delete_pending { + if attrs & FILE_ATTRIBUTE_READONLY > 0 && delete_pending { return Err(STATUS_CANNOT_DELETE); } let mut stat = Stat::new( @@ -435,10 +454,11 @@ impl MemFsHandler { None } else { let stream = Arc::new(RwLock::new(AltStream::new())); - assert!(stat - .alt_streams - .insert(EntryName(stream_info.name.to_owned()), Arc::clone(&stream)) - .is_none()); + assert!( + stat.alt_streams + .insert(EntryName(stream_info.name.to_owned()), Arc::clone(&stream)) + .is_none() + ); Some(stream) } } else { @@ -449,9 +469,11 @@ impl MemFsHandler { } else { Entry::File(Arc::new(FileEntry::new(stat))) }; - assert!(children - .insert(EntryName(name.file_name.to_owned()), entry.clone()) - .is_none()); + assert!( + children + .insert(EntryName(name.file_name.to_owned()), entry.clone()) + .is_none() + ); parent.stat.write().unwrap().update_mtime(SystemTime::now()); let is_dir = is_dir && stream.is_some(); Ok(CreateFileInfo { @@ -479,7 +501,7 @@ impl<'c, 'h: 'c> FileSystemHandler<'c, 'h> for MemFsHandler { &'h self, file_name: &U16CStr, security_context: &IO_SECURITY_CONTEXT, - desired_access: winnt::ACCESS_MASK, + desired_access: ACCESS_MASK, file_attributes: u32, _share_access: u32, create_disposition: u32, @@ -502,18 +524,18 @@ impl<'c, 'h: 'c> FileSystemHandler<'c, 'h> for MemFsHandler { let mut children = parent.children.write().unwrap(); if let Some(entry) = children.get(EntryNameRef::new(name.file_name)) { let stat = entry.stat().read().unwrap(); - let is_readonly = stat.attrs.value & winnt::FILE_ATTRIBUTE_READONLY > 0; + let is_readonly = stat.attrs.value & FILE_ATTRIBUTE_READONLY > 0; let is_hidden_system = create_disposition == FILE_OVERWRITE_IF - && (stat.attrs.value & winnt::FILE_ATTRIBUTE_HIDDEN > 0 - && !(file_attributes & winnt::FILE_ATTRIBUTE_HIDDEN > 0) - || stat.attrs.value & winnt::FILE_ATTRIBUTE_SYSTEM > 0 - && !(file_attributes & winnt::FILE_ATTRIBUTE_SYSTEM > 0)); + && (stat.attrs.value & FILE_ATTRIBUTE_HIDDEN > 0 + && !(file_attributes & FILE_ATTRIBUTE_HIDDEN > 0) + || stat.attrs.value & FILE_ATTRIBUTE_SYSTEM > 0 + && !(file_attributes & FILE_ATTRIBUTE_SYSTEM > 0)); if is_readonly && delete_pending { return Err(STATUS_CANNOT_DELETE); } if is_readonly - && (desired_access & winnt::FILE_WRITE_DATA > 0 - || desired_access & winnt::FILE_APPEND_DATA > 0) + && (desired_access & FILE_WRITE_DATA > 0 + || desired_access & FILE_APPEND_DATA > 0) { return Err(STATUS_ACCESS_DENIED); } @@ -538,7 +560,7 @@ impl<'c, 'h: 'c> FileSystemHandler<'c, 'h> for MemFsHandler { if create_disposition != FILE_SUPERSEDE && is_readonly { return Err(STATUS_ACCESS_DENIED); } - stat.attrs.value |= winnt::FILE_ATTRIBUTE_ARCHIVE; + stat.attrs.value |= FILE_ATTRIBUTE_ARCHIVE; stat.update_mtime(SystemTime::now()); stream.write().unwrap().data.clear(); } @@ -557,10 +579,14 @@ impl<'c, 'h: 'c> FileSystemHandler<'c, 'h> for MemFsHandler { } let stream = Arc::new(RwLock::new(AltStream::new())); stat.update_atime(SystemTime::now()); - assert!(stat - .alt_streams - .insert(EntryName(stream_info.name.to_owned()), Arc::clone(&stream)) - .is_none()); + assert!( + stat.alt_streams + .insert( + EntryName(stream_info.name.to_owned()), + Arc::clone(&stream) + ) + .is_none() + ); Some((stream, true)) } } @@ -590,9 +616,8 @@ impl<'c, 'h: 'c> FileSystemHandler<'c, 'h> for MemFsHandler { } file.data.write().unwrap().clear(); let mut stat = file.stat.write().unwrap(); - stat.attrs = Attributes::new( - file_attributes | winnt::FILE_ATTRIBUTE_ARCHIVE, - ); + stat.attrs = + Attributes::new(file_attributes | FILE_ATTRIBUTE_ARCHIVE); stat.update_mtime(SystemTime::now()); } FILE_CREATE => return Err(STATUS_OBJECT_NAME_COLLISION), @@ -653,7 +678,7 @@ impl<'c, 'h: 'c> FileSystemHandler<'c, 'h> for MemFsHandler { } else { self.create_new( &name, - file_attributes | winnt::FILE_ATTRIBUTE_ARCHIVE, + file_attributes | FILE_ATTRIBUTE_ARCHIVE, delete_pending, security_context.AccessState.SecurityDescriptor, token.as_raw_handle(), @@ -692,12 +717,14 @@ impl<'c, 'h: 'c> FileSystemHandler<'c, 'h> for MemFsHandler { context: &'c Self::Context, ) { let mut stat = context.entry.stat().write().unwrap(); - if let Some(mtime) = context.mtime_delayed.lock().unwrap().clone() { + let mtime_delayed = context.mtime_delayed.lock().unwrap().clone(); + if let Some(mtime) = mtime_delayed { if mtime > stat.mtime { stat.mtime = mtime; } } - if let Some(atime) = context.atime_delayed.lock().unwrap().clone() { + let atime_delayed = context.atime_delayed.lock().unwrap().clone(); + if let Some(atime) = atime_delayed { if atime > stat.atime { stat.atime = atime; } @@ -758,7 +785,7 @@ impl<'c, 'h: 'c> FileSystemHandler<'c, 'h> for MemFsHandler { Err(STATUS_ACCESS_DENIED) }; if ret.is_ok() { - context.entry.stat().write().unwrap().attrs.value |= winnt::FILE_ATTRIBUTE_ARCHIVE; + context.entry.stat().write().unwrap().attrs.value |= FILE_ATTRIBUTE_ARCHIVE; let now = SystemTime::now(); if context.mtime_enabled.load(Ordering::Relaxed) { *context.mtime_delayed.lock().unwrap() = Some(now); @@ -885,7 +912,7 @@ impl<'c, 'h: 'c> FileSystemHandler<'c, 'h> for MemFsHandler { info: &OperationInfo<'c, 'h, Self>, context: &'c Self::Context, ) -> OperationResult<()> { - if context.entry.stat().read().unwrap().attrs.value & winnt::FILE_ATTRIBUTE_READONLY > 0 { + if context.entry.stat().read().unwrap().attrs.value & FILE_ATTRIBUTE_READONLY > 0 { return Err(STATUS_CANNOT_DELETE); } let alt_stream = context.alt_stream.read().unwrap(); @@ -1001,10 +1028,11 @@ impl<'c, 'h: 'c> FileSystemHandler<'c, 'h> for MemFsHandler { stream.data = data.clone(); data.clear(); let stream = Arc::new(RwLock::new(stream)); - assert!(stat - .alt_streams - .insert(EntryName(dst_name.to_owned()), Arc::clone(&stream)) - .is_none()); + assert!( + stat.alt_streams + .insert(EntryName(dst_name.to_owned()), Arc::clone(&stream)) + .is_none() + ); *context.alt_stream.write().unwrap() = Some(stream); } else { return Err(STATUS_OBJECT_NAME_INVALID); @@ -1069,8 +1097,8 @@ impl<'c, 'h: 'c> FileSystemHandler<'c, 'h> for MemFsHandler { Err(STATUS_ACCESS_DENIED) } else { let stat = entry.stat().read().unwrap(); - let can_replace = stat.handle_count > 0 - || stat.attrs.value & winnt::FILE_ATTRIBUTE_READONLY > 0; + let can_replace = + stat.handle_count > 0 || stat.attrs.value & FILE_ATTRIBUTE_READONLY > 0; std::mem::drop(stat); if can_replace { Err(STATUS_ACCESS_DENIED) @@ -1088,9 +1116,11 @@ impl<'c, 'h: 'c> FileSystemHandler<'c, 'h> for MemFsHandler { check_can_move(&mut children)?; // Remove first in case moving to the same name. let entry = children.remove(src_name_ref).unwrap(); - assert!(children - .insert(EntryName(dst_name.file_name.to_owned()), entry) - .is_none()); + assert!( + children + .insert(EntryName(dst_name.file_name.to_owned()), entry) + .is_none() + ); src_parent.stat.write().unwrap().update_mtime(now); context.update_atime(&mut context.entry.stat().write().unwrap(), now); } else { @@ -1098,9 +1128,11 @@ impl<'c, 'h: 'c> FileSystemHandler<'c, 'h> for MemFsHandler { let mut dst_children = dst_parent.children.write().unwrap(); check_can_move(&mut dst_children)?; let entry = src_children.remove(src_name_ref).unwrap(); - assert!(dst_children - .insert(EntryName(dst_name.file_name.to_owned()), entry) - .is_none()); + assert!( + dst_children + .insert(EntryName(dst_name.file_name.to_owned()), entry) + .is_none() + ); src_parent.stat.write().unwrap().update_mtime(now); dst_parent.stat.write().unwrap().update_mtime(now); let mut stat = context.entry.stat().write().unwrap(); @@ -1195,11 +1227,11 @@ impl<'c, 'h: 'c> FileSystemHandler<'c, 'h> for MemFsHandler { name: U16CString::from_str("dokan-rust memfs").unwrap(), serial_number: 0, max_component_length: path::MAX_COMPONENT_LENGTH, - fs_flags: winnt::FILE_CASE_PRESERVED_NAMES - | winnt::FILE_CASE_SENSITIVE_SEARCH - | winnt::FILE_UNICODE_ON_DISK - | winnt::FILE_PERSISTENT_ACLS - | winnt::FILE_NAMED_STREAMS, + fs_flags: FILE_CASE_PRESERVED_NAMES + | FILE_CASE_SENSITIVE_SEARCH + | FILE_UNICODE_ON_DISK + | FILE_PERSISTENT_ACLS + | FILE_NAMED_STREAMS, // Custom names don't play well with UAC. fs_name: U16CString::from_str("NTFS").unwrap(), }) @@ -1221,7 +1253,7 @@ impl<'c, 'h: 'c> FileSystemHandler<'c, 'h> for MemFsHandler { &'h self, _file_name: &U16CStr, security_information: u32, - security_descriptor: winnt::PSECURITY_DESCRIPTOR, + security_descriptor: PSECURITY_DESCRIPTOR, buffer_length: u32, _info: &OperationInfo<'c, 'h, Self>, context: &'c Self::Context, @@ -1239,7 +1271,7 @@ impl<'c, 'h: 'c> FileSystemHandler<'c, 'h> for MemFsHandler { &'h self, _file_name: &U16CStr, security_information: u32, - security_descriptor: winnt::PSECURITY_DESCRIPTOR, + security_descriptor: PSECURITY_DESCRIPTOR, _buffer_length: u32, _info: &OperationInfo<'c, 'h, Self>, context: &'c Self::Context, diff --git a/dokan/examples/memfs/path.rs b/dokan/examples/memfs/path.rs index def1585..1a4b6c0 100644 --- a/dokan/examples/memfs/path.rs +++ b/dokan/examples/memfs/path.rs @@ -2,7 +2,9 @@ use std::{borrow::Borrow, sync::Arc}; use dokan::OperationResult; use widestring::{U16CStr, U16Str, U16String}; -use winapi::shared::ntstatus::*; +use windows_sys::Win32::Foundation::{ + STATUS_ACCESS_DENIED, STATUS_OBJECT_NAME_INVALID, STATUS_OBJECT_PATH_NOT_FOUND, +}; use crate::{DirEntry, Entry, EntryName, EntryNameRef}; diff --git a/dokan/examples/memfs/security.rs b/dokan/examples/memfs/security.rs index 2b77590..52ab1e1 100644 --- a/dokan/examples/memfs/security.rs +++ b/dokan/examples/memfs/security.rs @@ -1,18 +1,39 @@ use std::{mem, pin::Pin, ptr}; -use dokan::{map_win32_error_to_ntstatus, win32_ensure, OperationResult}; -use winapi::{ - shared::{minwindef, ntdef, ntstatus::*, winerror}, - um::{errhandlingapi::GetLastError, heapapi, securitybaseapi, winnt}, +use dokan::{OperationResult, map_win32_error_to_ntstatus, win32_ensure}; +use windows_sys::Win32::{ + Foundation::{ + ERROR_INSUFFICIENT_BUFFER, FALSE, GetLastError, HANDLE, STATUS_INVALID_PARAMETER, TRUE, + }, + Security::{ + ACCESS_ALLOWED_ACE, ACL, ACL_REVISION, AddAccessAllowedAceEx, CONTAINER_INHERIT_ACE, + CreatePrivateObjectSecurity, CreateWellKnownSid, DestroyPrivateObjectSecurity, + GENERIC_MAPPING, GetPrivateObjectSecurity, GetSecurityDescriptorLength, InitializeAcl, + InitializeSecurityDescriptor, IsValidSecurityDescriptor, MakeSelfRelativeSD, + OBJECT_INHERIT_ACE, PSECURITY_DESCRIPTOR, PSID, SECURITY_DESCRIPTOR, SEF_AVOID_OWNER_CHECK, + SEF_AVOID_PRIVILEGE_CHECK, SID, SetPrivateObjectSecurityEx, SetSecurityDescriptorDacl, + SetSecurityDescriptorGroup, SetSecurityDescriptorOwner, WELL_KNOWN_SID_TYPE, + WinAuthenticatedUserSid, WinBuiltinAdministratorsSid, WinBuiltinUsersSid, + WinLocalSystemSid, + }, + Storage::FileSystem::{ + DELETE, FILE_ALL_ACCESS, FILE_GENERIC_EXECUTE, FILE_GENERIC_READ, FILE_GENERIC_WRITE, + }, + System::{ + Memory::{GetProcessHeap, HeapAlloc, HeapFree}, + SystemServices::SECURITY_DESCRIPTOR_REVISION, + }, }; +type PACL = *mut ACL; + #[derive(Debug)] struct PrivateObjectSecurity { - value: winnt::PSECURITY_DESCRIPTOR, + value: PSECURITY_DESCRIPTOR, } impl PrivateObjectSecurity { - unsafe fn from_raw(ptr: winnt::PSECURITY_DESCRIPTOR) -> Self { + unsafe fn from_raw(ptr: PSECURITY_DESCRIPTOR) -> Self { Self { value: ptr } } } @@ -20,32 +41,32 @@ impl PrivateObjectSecurity { impl Drop for PrivateObjectSecurity { fn drop(&mut self) { unsafe { - securitybaseapi::DestroyPrivateObjectSecurity(&mut self.value); + DestroyPrivateObjectSecurity(&mut self.value); } } } #[derive(Debug)] pub struct SecurityDescriptor { - desc_ptr: winnt::PSECURITY_DESCRIPTOR, + desc_ptr: PSECURITY_DESCRIPTOR, } unsafe impl Sync for SecurityDescriptor {} unsafe impl Send for SecurityDescriptor {} -fn get_well_known_sid(sid_type: winnt::WELL_KNOWN_SID_TYPE) -> OperationResult> { +fn get_well_known_sid(sid_type: WELL_KNOWN_SID_TYPE) -> OperationResult> { unsafe { let mut sid = - vec![0u8; mem::size_of::() + mem::size_of::() * 7].into_boxed_slice(); + vec![0u8; mem::size_of::() + mem::size_of::() * 7].into_boxed_slice(); let mut len = sid.len() as u32; win32_ensure( - securitybaseapi::CreateWellKnownSid( + CreateWellKnownSid( sid_type, ptr::null_mut(), - sid.as_mut_ptr() as winnt::PSID, + sid.as_mut_ptr() as PSID, &mut len, - ) == minwindef::TRUE, + ) == TRUE, )?; Ok(sid) } @@ -53,114 +74,109 @@ fn get_well_known_sid(sid_type: winnt::WELL_KNOWN_SID_TYPE) -> OperationResult OperationResult> { unsafe { - let admins_sid = get_well_known_sid(winnt::WinBuiltinAdministratorsSid)?; - let system_sid = get_well_known_sid(winnt::WinLocalSystemSid)?; - let auth_sid = get_well_known_sid(winnt::WinAuthenticatedUserSid)?; - let users_sid = get_well_known_sid(winnt::WinBuiltinUsersSid)?; + let admins_sid = get_well_known_sid(WinBuiltinAdministratorsSid)?; + let system_sid = get_well_known_sid(WinLocalSystemSid)?; + let auth_sid = get_well_known_sid(WinAuthenticatedUserSid)?; + let users_sid = get_well_known_sid(WinBuiltinUsersSid)?; - let acl_len = mem::size_of::() - + (mem::size_of::() - mem::size_of::()) * 4 + let acl_len = mem::size_of::() + + (mem::size_of::() - mem::size_of::()) * 4 + admins_sid.len() + system_sid.len() + auth_sid.len() + users_sid.len(); let mut acl = vec![0u8; acl_len].into_boxed_slice(); win32_ensure( - securitybaseapi::InitializeAcl( - acl.as_mut_ptr() as winnt::PACL, + InitializeAcl( + acl.as_mut_ptr() as PACL, acl_len as u32, - winnt::ACL_REVISION as u32, - ) == minwindef::TRUE, + ACL_REVISION as u32, + ) == TRUE, )?; - let flags = (winnt::CONTAINER_INHERIT_ACE | winnt::OBJECT_INHERIT_ACE) as u32; + let flags = (CONTAINER_INHERIT_ACE | OBJECT_INHERIT_ACE) as u32; win32_ensure( - securitybaseapi::AddAccessAllowedAceEx( - acl.as_mut_ptr() as winnt::PACL, - winnt::ACL_REVISION as u32, + AddAccessAllowedAceEx( + acl.as_mut_ptr() as PACL, + ACL_REVISION as u32, flags, - winnt::FILE_ALL_ACCESS, - admins_sid.as_ptr() as winnt::PSID, - ) == minwindef::TRUE, + FILE_ALL_ACCESS, + admins_sid.as_ptr() as PSID, + ) == TRUE, )?; win32_ensure( - securitybaseapi::AddAccessAllowedAceEx( - acl.as_mut_ptr() as winnt::PACL, - winnt::ACL_REVISION as u32, + AddAccessAllowedAceEx( + acl.as_mut_ptr() as PACL, + ACL_REVISION as u32, flags, - winnt::FILE_ALL_ACCESS, - system_sid.as_ptr() as winnt::PSID, - ) == minwindef::TRUE, + FILE_ALL_ACCESS, + system_sid.as_ptr() as PSID, + ) == TRUE, )?; win32_ensure( - securitybaseapi::AddAccessAllowedAceEx( - acl.as_mut_ptr() as winnt::PACL, - winnt::ACL_REVISION as u32, + AddAccessAllowedAceEx( + acl.as_mut_ptr() as PACL, + ACL_REVISION as u32, flags, - winnt::FILE_GENERIC_READ - | winnt::FILE_GENERIC_WRITE - | winnt::FILE_GENERIC_EXECUTE - | winnt::DELETE, - auth_sid.as_ptr() as winnt::PSID, - ) == minwindef::TRUE, + FILE_GENERIC_READ | FILE_GENERIC_WRITE | FILE_GENERIC_EXECUTE | DELETE, + auth_sid.as_ptr() as PSID, + ) == TRUE, )?; win32_ensure( - securitybaseapi::AddAccessAllowedAceEx( - acl.as_mut_ptr() as winnt::PACL, - winnt::ACL_REVISION as u32, + AddAccessAllowedAceEx( + acl.as_mut_ptr() as PACL, + ACL_REVISION as u32, flags, - winnt::FILE_GENERIC_READ | winnt::FILE_GENERIC_EXECUTE, - users_sid.as_ptr() as winnt::PSID, - ) == minwindef::TRUE, + FILE_GENERIC_READ | FILE_GENERIC_EXECUTE, + users_sid.as_ptr() as PSID, + ) == TRUE, )?; Ok(acl) } } -const FILE_GENERIC_MAPPING: winnt::GENERIC_MAPPING = winnt::GENERIC_MAPPING { - GenericRead: winnt::FILE_GENERIC_READ, - GenericWrite: winnt::FILE_GENERIC_WRITE, - GenericExecute: winnt::FILE_GENERIC_EXECUTE, - GenericAll: winnt::FILE_ALL_ACCESS, +const FILE_GENERIC_MAPPING: GENERIC_MAPPING = GENERIC_MAPPING { + GenericRead: FILE_GENERIC_READ, + GenericWrite: FILE_GENERIC_WRITE, + GenericExecute: FILE_GENERIC_EXECUTE, + GenericAll: FILE_ALL_ACCESS, }; impl SecurityDescriptor { pub fn new_inherited( parent_desc: &SecurityDescriptor, - creator_desc: winnt::PSECURITY_DESCRIPTOR, - token: ntdef::HANDLE, + creator_desc: PSECURITY_DESCRIPTOR, + token: HANDLE, is_dir: bool, ) -> OperationResult { unsafe { - if !creator_desc.is_null() - && securitybaseapi::IsValidSecurityDescriptor(creator_desc) == minwindef::FALSE - { + if !creator_desc.is_null() && IsValidSecurityDescriptor(creator_desc) == FALSE { return Err(STATUS_INVALID_PARAMETER); } let mut priv_desc = ptr::null_mut(); win32_ensure( - securitybaseapi::CreatePrivateObjectSecurity( + CreatePrivateObjectSecurity( parent_desc.desc_ptr, creator_desc, &mut priv_desc, - is_dir as minwindef::BOOL, + is_dir as i32, token, &FILE_GENERIC_MAPPING as *const _ as *mut _, - ) == minwindef::TRUE, + ) == TRUE, )?; let priv_desc = PrivateObjectSecurity::from_raw(priv_desc); - let heap = heapapi::GetProcessHeap(); + let heap = GetProcessHeap(); win32_ensure(!heap.is_null())?; - let len = securitybaseapi::GetSecurityDescriptorLength(priv_desc.value) as usize; - let buf = heapapi::HeapAlloc(heap, 0, len); + let len = GetSecurityDescriptorLength(priv_desc.value) as usize; + let buf = HeapAlloc(heap, 0, len); win32_ensure(!buf.is_null())?; ptr::copy_nonoverlapping(priv_desc.value as *const u8, buf as *mut _, len); @@ -169,62 +185,44 @@ impl SecurityDescriptor { } pub fn new_default() -> OperationResult { - let owner_sid = Pin::new(get_well_known_sid(winnt::WinLocalSystemSid)?); - let group_sid = Pin::new(get_well_known_sid(winnt::WinLocalSystemSid)?); + let owner_sid = Pin::new(get_well_known_sid(WinLocalSystemSid)?); + let group_sid = Pin::new(get_well_known_sid(WinLocalSystemSid)?); let dacl = Pin::new(create_default_dacl()?); unsafe { - let mut abs_desc = mem::zeroed::(); - let abs_desc_ptr = &mut abs_desc as *mut _ as winnt::PSECURITY_DESCRIPTOR; + let mut abs_desc = mem::zeroed::(); + let abs_desc_ptr = &mut abs_desc as *mut _ as PSECURITY_DESCRIPTOR; win32_ensure( - securitybaseapi::InitializeSecurityDescriptor( - abs_desc_ptr, - winnt::SECURITY_DESCRIPTOR_REVISION, - ) == minwindef::TRUE, + InitializeSecurityDescriptor(abs_desc_ptr, SECURITY_DESCRIPTOR_REVISION) == TRUE, )?; win32_ensure( - securitybaseapi::SetSecurityDescriptorOwner( - abs_desc_ptr, - owner_sid.as_ptr() as winnt::PSID, - minwindef::FALSE, - ) == minwindef::TRUE, + SetSecurityDescriptorOwner(abs_desc_ptr, owner_sid.as_ptr() as PSID, FALSE) == TRUE, )?; win32_ensure( - securitybaseapi::SetSecurityDescriptorGroup( - abs_desc_ptr, - group_sid.as_ptr() as winnt::PSID, - minwindef::FALSE, - ) == minwindef::TRUE, + SetSecurityDescriptorGroup(abs_desc_ptr, group_sid.as_ptr() as PSID, FALSE) == TRUE, )?; win32_ensure( - securitybaseapi::SetSecurityDescriptorDacl( - abs_desc_ptr, - minwindef::TRUE, - dacl.as_ptr() as winnt::PACL, - minwindef::FALSE, - ) == minwindef::TRUE, + SetSecurityDescriptorDacl(abs_desc_ptr, TRUE, dacl.as_ptr() as PACL, FALSE) == TRUE, )?; let mut len = 0; - let ret = securitybaseapi::MakeSelfRelativeSD(abs_desc_ptr, ptr::null_mut(), &mut len); + let ret = MakeSelfRelativeSD(abs_desc_ptr, ptr::null_mut(), &mut len); let err = GetLastError(); - if ret != minwindef::FALSE || err != winerror::ERROR_INSUFFICIENT_BUFFER { + if ret != FALSE || err != ERROR_INSUFFICIENT_BUFFER { return Err(map_win32_error_to_ntstatus(err)); } - let heap = heapapi::GetProcessHeap(); + let heap = GetProcessHeap(); win32_ensure(!heap.is_null())?; - let buf = heapapi::HeapAlloc(heap, 0, len as usize); + let buf = HeapAlloc(heap, 0, len as usize); win32_ensure(!buf.is_null())?; - win32_ensure( - securitybaseapi::MakeSelfRelativeSD(abs_desc_ptr, buf, &mut len) == minwindef::TRUE, - )?; + win32_ensure(MakeSelfRelativeSD(abs_desc_ptr, buf, &mut len) == TRUE)?; Ok(Self { desc_ptr: buf }) } @@ -232,25 +230,25 @@ impl SecurityDescriptor { pub fn get_security_info( &self, - sec_info: winnt::SECURITY_INFORMATION, - sec_desc: winnt::PSECURITY_DESCRIPTOR, + sec_info: u32, + sec_desc: PSECURITY_DESCRIPTOR, sec_desc_len: u32, ) -> OperationResult { unsafe { - let len = securitybaseapi::GetSecurityDescriptorLength(self.desc_ptr); + let len = GetSecurityDescriptorLength(self.desc_ptr); if len > sec_desc_len { return Ok(len); } let mut ret_len = 0; win32_ensure( - securitybaseapi::GetPrivateObjectSecurity( + GetPrivateObjectSecurity( self.desc_ptr, sec_info, sec_desc, sec_desc_len, &mut ret_len, - ) == minwindef::TRUE, + ) == TRUE, )?; Ok(len) @@ -259,23 +257,23 @@ impl SecurityDescriptor { pub fn set_security_info( &mut self, - sec_info: winnt::SECURITY_INFORMATION, - sec_desc: winnt::PSECURITY_DESCRIPTOR, + sec_info: u32, + sec_desc: PSECURITY_DESCRIPTOR, ) -> OperationResult<()> { unsafe { - if securitybaseapi::IsValidSecurityDescriptor(sec_desc) == minwindef::FALSE { + if IsValidSecurityDescriptor(sec_desc) == FALSE { return Err(STATUS_INVALID_PARAMETER); } win32_ensure( - securitybaseapi::SetPrivateObjectSecurityEx( + SetPrivateObjectSecurityEx( sec_info, sec_desc, &mut self.desc_ptr, - winnt::SEF_AVOID_PRIVILEGE_CHECK | winnt::SEF_AVOID_OWNER_CHECK, + SEF_AVOID_PRIVILEGE_CHECK | SEF_AVOID_OWNER_CHECK, &FILE_GENERIC_MAPPING as *const _ as *mut _, ptr::null_mut(), - ) == minwindef::TRUE, + ) == TRUE, )?; Ok(()) @@ -286,7 +284,7 @@ impl SecurityDescriptor { impl Drop for SecurityDescriptor { fn drop(&mut self) { unsafe { - heapapi::HeapFree(heapapi::GetProcessHeap(), 0, self.desc_ptr); + HeapFree(GetProcessHeap(), 0, self.desc_ptr); } } } diff --git a/dokan/src/data/file_info.rs b/dokan/src/data/file_info.rs index 78d85b3..65e2c6a 100644 --- a/dokan/src/data/file_info.rs +++ b/dokan/src/data/file_info.rs @@ -1,6 +1,6 @@ use std::time::SystemTime; -use winapi::um::fileapi::BY_HANDLE_FILE_INFORMATION; +use windows_sys::Win32::Storage::FileSystem::BY_HANDLE_FILE_INFORMATION; use crate::to_file_time::ToFileTime; diff --git a/dokan/src/data/file_time_operation.rs b/dokan/src/data/file_time_operation.rs index b995a8b..2cf2b00 100644 --- a/dokan/src/data/file_time_operation.rs +++ b/dokan/src/data/file_time_operation.rs @@ -3,7 +3,7 @@ use std::{ time::{Duration, SystemTime, UNIX_EPOCH}, }; -use winapi::shared::minwindef::FILETIME; +use windows_sys::Win32::Foundation::FILETIME; use crate::to_file_time::FILETIME_OFFSET; diff --git a/dokan/src/data/fill_data.rs b/dokan/src/data/fill_data.rs index 2e42c58..7fdd3dc 100644 --- a/dokan/src/data/fill_data.rs +++ b/dokan/src/data/fill_data.rs @@ -3,17 +3,14 @@ use std::{ fmt::{self, Display, Formatter}, }; -use winapi::shared::{ - ntdef::NTSTATUS, - ntstatus::{STATUS_BUFFER_OVERFLOW, STATUS_INTERNAL_ERROR}, -}; +use windows_sys::Win32::Foundation::{NTSTATUS, STATUS_BUFFER_OVERFLOW, STATUS_INTERNAL_ERROR}; /// Error type for the `fill_data` callbacks. #[derive(Debug, Copy, Clone, Eq, PartialEq)] pub enum FillDataError { /// File name exceeds the limit of [`MAX_PATH`]. /// - /// [`MAX_PATH`]: winapi::shared::minwindef::MAX_PATH + /// [`MAX_PATH`]: windows_sys::Win32::Foundation::MAX_PATH NameTooLong, /// Buffer is full. diff --git a/dokan/src/data/find_data.rs b/dokan/src/data/find_data.rs index c500cf8..4ff311b 100644 --- a/dokan/src/data/find_data.rs +++ b/dokan/src/data/find_data.rs @@ -2,9 +2,9 @@ use std::{mem::transmute, time::SystemTime}; use dokan_sys::win32::WIN32_FIND_STREAM_DATA; use widestring::U16CString; -use winapi::{shared::minwindef::MAX_PATH, um::minwinbase::WIN32_FIND_DATAW}; +use windows_sys::Win32::{Foundation::MAX_PATH, Storage::FileSystem::WIN32_FIND_DATAW}; -use crate::{to_file_time::ToFileTime, FillDataError, FillDataResult}; +use crate::{FillDataError, FillDataResult, to_file_time::ToFileTime}; pub(crate) trait ToRawStruct { fn to_raw_struct(&self) -> Option; @@ -43,8 +43,8 @@ pub struct FindData { impl ToRawStruct for FindData { fn to_raw_struct(&self) -> Option { let name_slice = self.file_name.as_slice_with_nul(); - if name_slice.len() <= MAX_PATH { - let mut c_file_name = [0; MAX_PATH]; + if name_slice.len() <= MAX_PATH as usize { + let mut c_file_name = [0; MAX_PATH as usize]; c_file_name[..name_slice.len()].copy_from_slice(name_slice); Some(WIN32_FIND_DATAW { dwFileAttributes: self.attributes, @@ -81,7 +81,7 @@ pub struct FindStreamData { pub name: U16CString, } -const MAX_STREAM_NAME: usize = MAX_PATH + 36; +const MAX_STREAM_NAME: usize = MAX_PATH as usize + 36; impl ToRawStruct for FindStreamData { fn to_raw_struct(&self) -> Option { @@ -100,7 +100,7 @@ impl ToRawStruct for FindStreamData { } pub(crate) fn wrap_fill_data, TArg: Copy, TResult: PartialEq>( - fill_data: unsafe extern "stdcall" fn(*mut T, TArg) -> TResult, + fill_data: unsafe extern "system" fn(*mut T, TArg) -> TResult, fill_data_arg: TArg, success_value: TResult, ) -> impl FnMut(&U) -> FillDataResult { @@ -118,8 +118,8 @@ pub(crate) fn wrap_fill_data, TArg: Copy, TResult: PartialE mod tests { use std::ptr; + use core::ffi::c_int; use dokan_sys::PDOKAN_FILE_INFO; - use winapi::ctypes::c_int; use super::*; @@ -129,19 +129,15 @@ mod tests { impl ToRawStruct<()> for ToRawStructStub { fn to_raw_struct(&self) -> Option<()> { - if self.should_fail { - None - } else { - Some(()) - } + if self.should_fail { None } else { Some(()) } } } - extern "stdcall" fn fill_data_stub(_data: *mut (), _info: PDOKAN_FILE_INFO) -> c_int { + extern "system" fn fill_data_stub(_data: *mut (), _info: PDOKAN_FILE_INFO) -> c_int { 0 } - extern "stdcall" fn failing_fill_data_stub(_data: *mut (), _info: PDOKAN_FILE_INFO) -> c_int { + extern "system" fn failing_fill_data_stub(_data: *mut (), _info: PDOKAN_FILE_INFO) -> c_int { 1 } diff --git a/dokan/src/data/mount_point.rs b/dokan/src/data/mount_point.rs index cadaf1d..98a9f25 100644 --- a/dokan/src/data/mount_point.rs +++ b/dokan/src/data/mount_point.rs @@ -1,11 +1,11 @@ use std::{iter::Map, mem::transmute, slice}; +use dokan_sys::ULONG; use dokan_sys::{ win32::{FILE_DEVICE_DISK_FILE_SYSTEM, FILE_DEVICE_NETWORK_FILE_SYSTEM}, *, }; use widestring::U16CStr; -use winapi::shared::minwindef::ULONG; /// Mount point device type. #[repr(u32)] @@ -116,7 +116,7 @@ fn can_list_mount_points() { use std::process; use regex::Regex; - use winapi::{shared::minwindef::TRUE, um::processthreadsapi::ProcessIdToSessionId}; + use windows_sys::Win32::{Foundation::TRUE, System::RemoteDesktop::ProcessIdToSessionId}; use crate::usage_tests::{convert_str, with_test_drive}; diff --git a/dokan/src/data/operation_info.rs b/dokan/src/data/operation_info.rs index 02d8628..714b845 100644 --- a/dokan/src/data/operation_info.rs +++ b/dokan/src/data/operation_info.rs @@ -5,12 +5,12 @@ use std::{ }; use dokan_sys::{ - DokanOpenRequestorToken, DokanResetTimeout, DOKAN_FILE_INFO, DOKAN_OPTIONS, PDOKAN_FILE_INFO, + DOKAN_FILE_INFO, DOKAN_OPTIONS, DokanOpenRequestorToken, DokanResetTimeout, PDOKAN_FILE_INFO, }; use widestring::U16CStr; -use winapi::{shared::minwindef::TRUE, um::handleapi::INVALID_HANDLE_VALUE}; +use windows_sys::Win32::Foundation::{INVALID_HANDLE_VALUE, TRUE}; -use crate::{file_system_handler::FileSystemHandler, MountFlags}; +use crate::{MountFlags, file_system_handler::FileSystemHandler}; /// Information about the current operation. #[derive(Debug)] @@ -41,8 +41,19 @@ impl<'c, 'h: 'c, FSH: FileSystemHandler<'c, 'h> + 'h> OperationInfo<'c, 'h, FSH> unsafe { &*(self.mount_options().GlobalContext as *const _) } } + pub fn try_context(&self) -> Option<&'c FSH::Context> { + let ptr = self.file_info().Context as *const FSH::Context; + if ptr.is_null() { + None + } else { + unsafe { Some(&*ptr) } + } + } + pub fn context(&self) -> &'c FSH::Context { - unsafe { &*(self.file_info().Context as *const _) } + self.try_context().expect( + "file context is null — create_file may have failed or context was already dropped", + ) } pub fn drop_context(&mut self) { diff --git a/dokan/src/file_system.rs b/dokan/src/file_system.rs index 938f281..7f6b97b 100644 --- a/dokan/src/file_system.rs +++ b/dokan/src/file_system.rs @@ -8,21 +8,22 @@ use std::{ }; use bitflags::bitflags; +use dokan_sys::SCHAR; use dokan_sys::{ - DokanCloseHandle, DokanCreateFileSystem, DokanWaitForFileSystemClosed, - DOKAN_DRIVER_INSTALL_ERROR, DOKAN_DRIVE_LETTER_ERROR, DOKAN_ERROR, DOKAN_HANDLE, - DOKAN_MOUNT_ERROR, DOKAN_MOUNT_POINT_ERROR, DOKAN_OPERATIONS, DOKAN_OPTIONS, - DOKAN_OPTION_ALLOW_IPC_BATCHING, DOKAN_OPTION_ALT_STREAM, DOKAN_OPTION_CASE_SENSITIVE, - DOKAN_OPTION_CURRENT_SESSION, DOKAN_OPTION_DEBUG, DOKAN_OPTION_DISPATCH_DRIVER_LOGS, + DOKAN_DRIVE_LETTER_ERROR, DOKAN_DRIVER_INSTALL_ERROR, DOKAN_ERROR, DOKAN_HANDLE, + DOKAN_MOUNT_ERROR, DOKAN_MOUNT_POINT_ERROR, DOKAN_OPERATIONS, DOKAN_OPTION_ALLOW_IPC_BATCHING, + DOKAN_OPTION_ALT_STREAM, DOKAN_OPTION_CASE_SENSITIVE, DOKAN_OPTION_CURRENT_SESSION, + DOKAN_OPTION_DEBUG, DOKAN_OPTION_DISPATCH_DRIVER_LOGS, DOKAN_OPTION_ENABLE_UNMOUNT_NETWORK_DRIVE, DOKAN_OPTION_FILELOCK_USER_MODE, DOKAN_OPTION_MOUNT_MANAGER, DOKAN_OPTION_NETWORK, DOKAN_OPTION_REMOVABLE, DOKAN_OPTION_STDERR, - DOKAN_OPTION_WRITE_PROTECT, DOKAN_START_ERROR, DOKAN_SUCCESS, DOKAN_VERSION_ERROR, + DOKAN_OPTION_WRITE_PROTECT, DOKAN_OPTIONS, DOKAN_START_ERROR, DOKAN_SUCCESS, + DOKAN_VERSION_ERROR, DokanCloseHandle, DokanCreateFileSystem, DokanWaitForFileSystemClosed, VOLUME_SECURITY_DESCRIPTOR_MAX_SIZE, }; use widestring::U16CStr; -use winapi::{shared::ntdef::SCHAR, um::winbase::INFINITE}; +use windows_sys::Win32::System::Threading::INFINITE; -use crate::{file_system_handler::FileSystemHandler, operations, WRAPPER_VERSION}; +use crate::{WRAPPER_VERSION, file_system_handler::FileSystemHandler, operations}; bitflags! { /// Flags that control behavior of the mounted volume, as part of [`MountOptions`]. @@ -182,7 +183,9 @@ impl Display for FileSystemMountError { FileSystemMountError::DriveLetter => "bad drive letter", FileSystemMountError::DriverInstall => "can't install driver", FileSystemMountError::Start => "the driver responds that something is wrong", - FileSystemMountError::Mount => "can't assign a drive letter or mount point, probably already used by another volume", + FileSystemMountError::Mount => { + "can't assign a drive letter or mount point, probably already used by another volume" + } FileSystemMountError::MountPoint => "the mount point is invalid", FileSystemMountError::Version => "requested an incompatible version", }; @@ -315,7 +318,7 @@ fn can_fail_to_mount() { use crate::{ init, shutdown, - usage_tests::{convert_str, TestHandler}, + usage_tests::{TestHandler, convert_str}, }; let (tx, _rx) = mpsc::sync_channel(1024); diff --git a/dokan/src/file_system_handler.rs b/dokan/src/file_system_handler.rs index 84805b5..b68ecdf 100644 --- a/dokan/src/file_system_handler.rs +++ b/dokan/src/file_system_handler.rs @@ -1,8 +1,9 @@ +use dokan_sys::ACCESS_MASK; use dokan_sys::DOKAN_IO_SECURITY_CONTEXT; use widestring::U16CStr; -use winapi::{ - shared::{ntdef::NTSTATUS, ntstatus::STATUS_NOT_IMPLEMENTED}, - um::winnt::{ACCESS_MASK, PSECURITY_DESCRIPTOR}, +use windows_sys::Win32::{ + Foundation::{NTSTATUS, STATUS_NOT_IMPLEMENTED}, + Security::PSECURITY_DESCRIPTOR, }; use crate::data::{ @@ -32,7 +33,7 @@ pub type OperationResult = Result; /// [`close_file`]: Self::close_file /// [`create_file`]: Self::create_file /// [`map_win32_error_to_ntstatus`]: crate::map_win32_error_to_ntstatus -/// [`GetLastError`]: winapi::um::errhandlingapi::GetLastError +/// [`GetLastError`]: windows_sys::Win32::Foundation::GetLastError #[allow(unused_variables)] pub trait FileSystemHandler<'c, 'h: 'c>: Sync + Sized + 'h { /// Type of the context associated with an open file object. @@ -433,7 +434,7 @@ pub trait FileSystemHandler<'c, 'h: 'c>: Sync + Sized + 'h { /// /// See [`GetFileSecurity`] for more information. /// - /// [`STATUS_BUFFER_OVERFLOW`]: winapi::shared::ntstatus::STATUS_BUFFER_OVERFLOW + /// [`STATUS_BUFFER_OVERFLOW`]: windows_sys::Win32::Foundation::STATUS_BUFFER_OVERFLOW /// [`GetFileSecurity`]: https://docs.microsoft.com/en-us/windows/win32/api/winbase/nf-winbase-getfilesecuritya fn get_file_security( &'h self, diff --git a/dokan/src/lib.rs b/dokan/src/lib.rs index f2777fa..3f5662c 100644 --- a/dokan/src/lib.rs +++ b/dokan/src/lib.rs @@ -16,11 +16,11 @@ //! //! Please note that some of the constants from Win32 API that might be used when interacting with //! this crate are not provided directly here. However, you can easily find them in the -//! [`winapi`] crate. +//! [`windows-sys`] crate. //! //! [Dokan]: https://dokan-dev.github.io/ //! [`dokan-sys`]: https://crates.io/crates/dokan-sys -//! [`winapi`]: https://crates.io/crates/winapi +//! [`windows-sys`]: https://crates.io/crates/windows-sys mod data; mod file_system; @@ -35,13 +35,7 @@ mod usage_tests; use dokan_sys::*; use widestring::U16CStr; -use winapi::{ - shared::{ - minwindef::{DWORD, FALSE, TRUE}, - ntdef::NTSTATUS, - }, - um::{errhandlingapi::GetLastError, winnt::ACCESS_MASK}, -}; +use windows_sys::Win32::Foundation::{FALSE, GetLastError, NTSTATUS, TRUE}; pub use crate::{data::*, file_system::*, file_system_handler::*, notify::*}; @@ -159,7 +153,7 @@ pub fn map_win32_error_to_ntstatus(error: DWORD) -> NTSTATUS { #[test] fn can_map_win32_error_to_ntstatus() { - use winapi::shared::{ntstatus::STATUS_INTERNAL_ERROR, winerror::ERROR_INTERNAL_ERROR}; + use windows_sys::Win32::Foundation::{ERROR_INTERNAL_ERROR, STATUS_INTERNAL_ERROR}; assert_eq!( map_win32_error_to_ntstatus(ERROR_INTERNAL_ERROR), @@ -183,7 +177,7 @@ fn can_map_win32_error_to_ntstatus() { /// # /// # use dokan::win32_ensure; /// # use widestring::U16CString; -/// # use winapi::{shared::ntdef::NTSTATUS, um::processenv::GetCurrentDirectoryW}; +/// # use windows_sys::Win32::{Foundation::NTSTATUS, System::Environment::GetCurrentDirectoryW}; /// # /// fn get_current_directory() -> Result { /// unsafe { @@ -257,12 +251,10 @@ pub fn map_kernel_to_user_create_file_flags( #[test] fn test_map_kernel_to_user_create_file_flags() { use dokan_sys::win32::{FILE_OPEN, FILE_WRITE_THROUGH}; - use winapi::um::{ - fileapi::OPEN_EXISTING, - winbase::FILE_FLAG_WRITE_THROUGH, - winnt::{ - FILE_ALL_ACCESS, FILE_ATTRIBUTE_NORMAL, GENERIC_ALL, GENERIC_EXECUTE, GENERIC_READ, - GENERIC_WRITE, + use windows_sys::Win32::{ + Foundation::{GENERIC_ALL, GENERIC_EXECUTE, GENERIC_READ, GENERIC_WRITE}, + Storage::FileSystem::{ + FILE_ALL_ACCESS, FILE_ATTRIBUTE_NORMAL, FILE_FLAG_WRITE_THROUGH, OPEN_EXISTING, }, }; diff --git a/dokan/src/notify.rs b/dokan/src/notify.rs index 9a710af..4ede2fe 100644 --- a/dokan/src/notify.rs +++ b/dokan/src/notify.rs @@ -3,7 +3,7 @@ use dokan_sys::{ DokanNotifyXAttrUpdate, }; use widestring::U16CStr; -use winapi::shared::minwindef::TRUE; +use windows_sys::Win32::Foundation::TRUE; use crate::FileSystemHandle; diff --git a/dokan/src/operations.rs b/dokan/src/operations.rs index 2c56991..700f382 100644 --- a/dokan/src/operations.rs +++ b/dokan/src/operations.rs @@ -1,30 +1,29 @@ use std::slice; use dokan_sys::{ + ACCESS_MASK, DWORD, LONGLONG, LPBY_HANDLE_FILE_INFORMATION, LPCVOID, LPDWORD, LPVOID, + PSECURITY_INFORMATION, PULONG, PULONGLONG, PVOID, ULONG, +}; +use dokan_sys::{ + PDOKAN_FILE_INFO, PDOKAN_IO_SECURITY_CONTEXT, PFillFindData, PFillFindStreamData, win32::{FILE_OPEN_IF, FILE_OVERWRITE_IF, FILE_SUPERSEDE}, - PFillFindData, PFillFindStreamData, PDOKAN_FILE_INFO, PDOKAN_IO_SECURITY_CONTEXT, }; use widestring::U16CStr; -use winapi::{ - shared::{ - minwindef::{BOOL, DWORD, FILETIME, LPCVOID, LPDWORD, LPVOID, PULONG, TRUE, ULONG}, - ntdef::{LONGLONG, LPCWSTR, LPWSTR, NTSTATUS, PULONGLONG, PVOID}, - ntstatus::{STATUS_BUFFER_OVERFLOW, STATUS_OBJECT_NAME_COLLISION}, - }, - um::{ - fileapi::LPBY_HANDLE_FILE_INFORMATION, - winnt::{ACCESS_MASK, PSECURITY_DESCRIPTOR, PSECURITY_INFORMATION}, - }, +use windows_sys::Win32::{ + Foundation::{FILETIME, NTSTATUS, STATUS_BUFFER_OVERFLOW, STATUS_OBJECT_NAME_COLLISION, TRUE}, + Security::PSECURITY_DESCRIPTOR, }; +use windows_sys::core::BOOL; +use windows_sys::core::{PCWSTR, PWSTR}; use crate::{ - data::{wrap_fill_data, OperationInfo}, + data::{OperationInfo, wrap_fill_data}, file_system_handler::FileSystemHandler, - operations_helpers::{wrap_nt_result, wrap_unit, NtResult}, + operations_helpers::{NtResult, wrap_nt_result, wrap_unit}, }; -pub extern "stdcall" fn create_file<'c, 'h: 'c, FSH: FileSystemHandler<'c, 'h> + 'h>( - file_name: LPCWSTR, +pub extern "system" fn create_file<'c, 'h: 'c, FSH: FileSystemHandler<'c, 'h> + 'h>( + file_name: PCWSTR, security_context: PDOKAN_IO_SECURITY_CONTEXT, desired_access: ACCESS_MASK, file_attributes: ULONG, @@ -64,31 +63,35 @@ pub extern "stdcall" fn create_file<'c, 'h: 'c, FSH: FileSystemHandler<'c, 'h> + }) } -pub extern "stdcall" fn cleanup<'c, 'h: 'c, FSH: FileSystemHandler<'c, 'h> + 'h>( - file_name: LPCWSTR, +pub extern "system" fn cleanup<'c, 'h: 'c, FSH: FileSystemHandler<'c, 'h> + 'h>( + file_name: PCWSTR, dokan_file_info: PDOKAN_FILE_INFO, ) { wrap_unit(|| unsafe { let file_name = U16CStr::from_ptr_str(file_name); let info = OperationInfo::<'c, 'h, FSH>::new(dokan_file_info); - info.handler().cleanup(file_name, &info, info.context()); + if let Some(context) = info.try_context() { + info.handler().cleanup(file_name, &info, context); + } }); } -pub extern "stdcall" fn close_file<'c, 'h: 'c, FSH: FileSystemHandler<'c, 'h> + 'h>( - file_name: LPCWSTR, +pub extern "system" fn close_file<'c, 'h: 'c, FSH: FileSystemHandler<'c, 'h> + 'h>( + file_name: PCWSTR, dokan_file_info: PDOKAN_FILE_INFO, ) { wrap_unit(|| unsafe { let file_name = U16CStr::from_ptr_str(file_name); let mut info = OperationInfo::<'c, 'h, FSH>::new(dokan_file_info); - info.handler().close_file(file_name, &info, info.context()); + if let Some(context) = info.try_context() { + info.handler().close_file(file_name, &info, context); + } info.drop_context(); }); } -pub extern "stdcall" fn read_file<'c, 'h: 'c, FSH: FileSystemHandler<'c, 'h> + 'h>( - file_name: LPCWSTR, +pub extern "system" fn read_file<'c, 'h: 'c, FSH: FileSystemHandler<'c, 'h> + 'h>( + file_name: PCWSTR, buffer: LPVOID, buffer_length: DWORD, read_length: LPDWORD, @@ -108,8 +111,8 @@ pub extern "stdcall" fn read_file<'c, 'h: 'c, FSH: FileSystemHandler<'c, 'h> + ' }) } -pub extern "stdcall" fn write_file<'c, 'h: 'c, FSH: FileSystemHandler<'c, 'h> + 'h>( - file_name: LPCWSTR, +pub extern "system" fn write_file<'c, 'h: 'c, FSH: FileSystemHandler<'c, 'h> + 'h>( + file_name: PCWSTR, buffer: LPCVOID, number_of_bytes_to_write: DWORD, number_of_bytes_written: LPDWORD, @@ -129,8 +132,8 @@ pub extern "stdcall" fn write_file<'c, 'h: 'c, FSH: FileSystemHandler<'c, 'h> + }) } -pub extern "stdcall" fn flush_file_buffers<'c, 'h: 'c, FSH: FileSystemHandler<'c, 'h> + 'h>( - file_name: LPCWSTR, +pub extern "system" fn flush_file_buffers<'c, 'h: 'c, FSH: FileSystemHandler<'c, 'h> + 'h>( + file_name: PCWSTR, dokan_file_info: PDOKAN_FILE_INFO, ) -> NTSTATUS { wrap_nt_result(|| unsafe { @@ -141,8 +144,8 @@ pub extern "stdcall" fn flush_file_buffers<'c, 'h: 'c, FSH: FileSystemHandler<'c }) } -pub extern "stdcall" fn get_file_information<'c, 'h: 'c, FSH: FileSystemHandler<'c, 'h> + 'h>( - file_name: LPCWSTR, +pub extern "system" fn get_file_information<'c, 'h: 'c, FSH: FileSystemHandler<'c, 'h> + 'h>( + file_name: PCWSTR, buffer: LPBY_HANDLE_FILE_INFORMATION, dokan_file_info: PDOKAN_FILE_INFO, ) -> NTSTATUS { @@ -157,8 +160,8 @@ pub extern "stdcall" fn get_file_information<'c, 'h: 'c, FSH: FileSystemHandler< }) } -pub extern "stdcall" fn find_files<'c, 'h: 'c, FSH: FileSystemHandler<'c, 'h> + 'h>( - file_name: LPCWSTR, +pub extern "system" fn find_files<'c, 'h: 'c, FSH: FileSystemHandler<'c, 'h> + 'h>( + file_name: PCWSTR, fill_find_data: PFillFindData, dokan_file_info: PDOKAN_FILE_INFO, ) -> NTSTATUS { @@ -171,9 +174,9 @@ pub extern "stdcall" fn find_files<'c, 'h: 'c, FSH: FileSystemHandler<'c, 'h> + }) } -pub extern "stdcall" fn find_files_with_pattern<'c, 'h: 'c, FSH: FileSystemHandler<'c, 'h> + 'h>( - file_name: LPCWSTR, - search_pattern: LPCWSTR, +pub extern "system" fn find_files_with_pattern<'c, 'h: 'c, FSH: FileSystemHandler<'c, 'h> + 'h>( + file_name: PCWSTR, + search_pattern: PCWSTR, fill_find_data: PFillFindData, dokan_file_info: PDOKAN_FILE_INFO, ) -> NTSTATUS { @@ -192,8 +195,8 @@ pub extern "stdcall" fn find_files_with_pattern<'c, 'h: 'c, FSH: FileSystemHandl }) } -pub extern "stdcall" fn set_file_attributes<'c, 'h: 'c, FSH: FileSystemHandler<'c, 'h> + 'h>( - file_name: LPCWSTR, +pub extern "system" fn set_file_attributes<'c, 'h: 'c, FSH: FileSystemHandler<'c, 'h> + 'h>( + file_name: PCWSTR, file_attributes: DWORD, dokan_file_info: PDOKAN_FILE_INFO, ) -> NTSTATUS { @@ -205,8 +208,8 @@ pub extern "stdcall" fn set_file_attributes<'c, 'h: 'c, FSH: FileSystemHandler<' }) } -pub extern "stdcall" fn set_file_time<'c, 'h: 'c, FSH: FileSystemHandler<'c, 'h> + 'h>( - file_name: LPCWSTR, +pub extern "system" fn set_file_time<'c, 'h: 'c, FSH: FileSystemHandler<'c, 'h> + 'h>( + file_name: PCWSTR, creation_time: *const FILETIME, last_access_time: *const FILETIME, last_write_time: *const FILETIME, @@ -226,8 +229,8 @@ pub extern "stdcall" fn set_file_time<'c, 'h: 'c, FSH: FileSystemHandler<'c, 'h> }) } -pub extern "stdcall" fn delete_file<'c, 'h: 'c, FSH: FileSystemHandler<'c, 'h> + 'h>( - file_name: LPCWSTR, +pub extern "system" fn delete_file<'c, 'h: 'c, FSH: FileSystemHandler<'c, 'h> + 'h>( + file_name: PCWSTR, dokan_file_info: PDOKAN_FILE_INFO, ) -> NTSTATUS { wrap_nt_result(|| unsafe { @@ -237,8 +240,8 @@ pub extern "stdcall" fn delete_file<'c, 'h: 'c, FSH: FileSystemHandler<'c, 'h> + }) } -pub extern "stdcall" fn delete_directory<'c, 'h: 'c, FSH: FileSystemHandler<'c, 'h> + 'h>( - file_name: LPCWSTR, +pub extern "system" fn delete_directory<'c, 'h: 'c, FSH: FileSystemHandler<'c, 'h> + 'h>( + file_name: PCWSTR, dokan_file_info: PDOKAN_FILE_INFO, ) -> NTSTATUS { wrap_nt_result(|| unsafe { @@ -249,9 +252,9 @@ pub extern "stdcall" fn delete_directory<'c, 'h: 'c, FSH: FileSystemHandler<'c, }) } -pub extern "stdcall" fn move_file<'c, 'h: 'c, FSH: FileSystemHandler<'c, 'h> + 'h>( - file_name: LPCWSTR, - new_file_name: LPCWSTR, +pub extern "system" fn move_file<'c, 'h: 'c, FSH: FileSystemHandler<'c, 'h> + 'h>( + file_name: PCWSTR, + new_file_name: PCWSTR, replace_if_existing: BOOL, dokan_file_info: PDOKAN_FILE_INFO, ) -> NTSTATUS { @@ -269,8 +272,8 @@ pub extern "stdcall" fn move_file<'c, 'h: 'c, FSH: FileSystemHandler<'c, 'h> + ' }) } -pub extern "stdcall" fn set_end_of_file<'c, 'h: 'c, FSH: FileSystemHandler<'c, 'h> + 'h>( - file_name: LPCWSTR, +pub extern "system" fn set_end_of_file<'c, 'h: 'c, FSH: FileSystemHandler<'c, 'h> + 'h>( + file_name: PCWSTR, byte_offset: LONGLONG, dokan_file_info: PDOKAN_FILE_INFO, ) -> NTSTATUS { @@ -282,8 +285,8 @@ pub extern "stdcall" fn set_end_of_file<'c, 'h: 'c, FSH: FileSystemHandler<'c, ' }) } -pub extern "stdcall" fn set_allocation_size<'c, 'h: 'c, FSH: FileSystemHandler<'c, 'h> + 'h>( - file_name: LPCWSTR, +pub extern "system" fn set_allocation_size<'c, 'h: 'c, FSH: FileSystemHandler<'c, 'h> + 'h>( + file_name: PCWSTR, alloc_size: LONGLONG, dokan_file_info: PDOKAN_FILE_INFO, ) -> NTSTATUS { @@ -299,7 +302,7 @@ pub extern "stdcall" fn set_allocation_size<'c, 'h: 'c, FSH: FileSystemHandler<' // release mode. It seems that extracting the function bodies into a common function works around this bug. // See https://github.com/rust-lang/rust/issues/72212 fn lock_unlock_file<'c, 'h: 'c, FSH: FileSystemHandler<'c, 'h> + 'h>( - file_name: LPCWSTR, + file_name: PCWSTR, byte_offset: LONGLONG, length: LONGLONG, dokan_file_info: PDOKAN_FILE_INFO, @@ -326,8 +329,8 @@ fn lock_unlock_file<'c, 'h: 'c, FSH: FileSystemHandler<'c, 'h> + 'h>( }) } -pub extern "stdcall" fn lock_file<'c, 'h: 'c, FSH: FileSystemHandler<'c, 'h> + 'h>( - file_name: LPCWSTR, +pub extern "system" fn lock_file<'c, 'h: 'c, FSH: FileSystemHandler<'c, 'h> + 'h>( + file_name: PCWSTR, byte_offset: LONGLONG, length: LONGLONG, dokan_file_info: PDOKAN_FILE_INFO, @@ -341,8 +344,8 @@ pub extern "stdcall" fn lock_file<'c, 'h: 'c, FSH: FileSystemHandler<'c, 'h> + ' ) } -pub extern "stdcall" fn unlock_file<'c, 'h: 'c, FSH: FileSystemHandler<'c, 'h> + 'h>( - file_name: LPCWSTR, +pub extern "system" fn unlock_file<'c, 'h: 'c, FSH: FileSystemHandler<'c, 'h> + 'h>( + file_name: PCWSTR, byte_offset: LONGLONG, length: LONGLONG, dokan_file_info: PDOKAN_FILE_INFO, @@ -356,7 +359,7 @@ pub extern "stdcall" fn unlock_file<'c, 'h: 'c, FSH: FileSystemHandler<'c, 'h> + ) } -pub extern "stdcall" fn get_disk_free_space<'c, 'h: 'c, FSH: FileSystemHandler<'c, 'h> + 'h>( +pub extern "system" fn get_disk_free_space<'c, 'h: 'c, FSH: FileSystemHandler<'c, 'h> + 'h>( free_bytes_available: PULONGLONG, total_number_of_bytes: PULONGLONG, total_number_of_free_bytes: PULONGLONG, @@ -380,13 +383,13 @@ pub extern "stdcall" fn get_disk_free_space<'c, 'h: 'c, FSH: FileSystemHandler<' }) } -pub extern "stdcall" fn get_volume_information<'c, 'h: 'c, FSH: FileSystemHandler<'c, 'h> + 'h>( - volume_name_buffer: LPWSTR, +pub extern "system" fn get_volume_information<'c, 'h: 'c, FSH: FileSystemHandler<'c, 'h> + 'h>( + volume_name_buffer: PWSTR, volume_name_size: DWORD, volume_serial_number: LPDWORD, maximum_component_length: LPDWORD, file_system_flags: LPDWORD, - file_system_name_buffer: LPWSTR, + file_system_name_buffer: PWSTR, file_system_name_size: DWORD, dokan_file_info: PDOKAN_FILE_INFO, ) -> NTSTATUS { @@ -416,8 +419,8 @@ pub extern "stdcall" fn get_volume_information<'c, 'h: 'c, FSH: FileSystemHandle }) } -pub extern "stdcall" fn mounted<'c, 'h: 'c, FSH: FileSystemHandler<'c, 'h> + 'h>( - mount_point: LPCWSTR, +pub extern "system" fn mounted<'c, 'h: 'c, FSH: FileSystemHandler<'c, 'h> + 'h>( + mount_point: PCWSTR, dokan_file_info: PDOKAN_FILE_INFO, ) -> NTSTATUS { wrap_nt_result(|| unsafe { @@ -427,7 +430,7 @@ pub extern "stdcall" fn mounted<'c, 'h: 'c, FSH: FileSystemHandler<'c, 'h> + 'h> }) } -pub extern "stdcall" fn unmounted<'c, 'h: 'c, FSH: FileSystemHandler<'c, 'h> + 'h>( +pub extern "system" fn unmounted<'c, 'h: 'c, FSH: FileSystemHandler<'c, 'h> + 'h>( dokan_file_info: PDOKAN_FILE_INFO, ) -> NTSTATUS { wrap_nt_result(|| { @@ -436,8 +439,8 @@ pub extern "stdcall" fn unmounted<'c, 'h: 'c, FSH: FileSystemHandler<'c, 'h> + ' }) } -pub extern "stdcall" fn get_file_security<'c, 'h: 'c, FSH: FileSystemHandler<'c, 'h> + 'h>( - file_name: LPCWSTR, +pub extern "system" fn get_file_security<'c, 'h: 'c, FSH: FileSystemHandler<'c, 'h> + 'h>( + file_name: PCWSTR, security_information: PSECURITY_INFORMATION, security_descriptor: PSECURITY_DESCRIPTOR, buffer_length: ULONG, @@ -467,8 +470,8 @@ pub extern "stdcall" fn get_file_security<'c, 'h: 'c, FSH: FileSystemHandler<'c, }) } -pub extern "stdcall" fn set_file_security<'c, 'h: 'c, FSH: FileSystemHandler<'c, 'h> + 'h>( - file_name: LPCWSTR, +pub extern "system" fn set_file_security<'c, 'h: 'c, FSH: FileSystemHandler<'c, 'h> + 'h>( + file_name: PCWSTR, security_information: PSECURITY_INFORMATION, security_descriptor: PSECURITY_DESCRIPTOR, buffer_length: ULONG, @@ -488,8 +491,8 @@ pub extern "stdcall" fn set_file_security<'c, 'h: 'c, FSH: FileSystemHandler<'c, }) } -pub extern "stdcall" fn find_streams<'c, 'h: 'c, FSH: FileSystemHandler<'c, 'h> + 'h>( - file_name: LPCWSTR, +pub extern "system" fn find_streams<'c, 'h: 'c, FSH: FileSystemHandler<'c, 'h> + 'h>( + file_name: PCWSTR, fill_find_stream_data: PFillFindStreamData, find_stream_context: PVOID, dokan_file_info: PDOKAN_FILE_INFO, diff --git a/dokan/src/operations_helpers.rs b/dokan/src/operations_helpers.rs index 0f10980..d7ffa63 100644 --- a/dokan/src/operations_helpers.rs +++ b/dokan/src/operations_helpers.rs @@ -1,9 +1,6 @@ use std::panic::{self, UnwindSafe}; -use winapi::shared::{ - ntdef::NTSTATUS, - ntstatus::{STATUS_INTERNAL_ERROR, STATUS_SUCCESS}, -}; +use windows_sys::Win32::Foundation::{NTSTATUS, STATUS_INTERNAL_ERROR, STATUS_SUCCESS}; pub type NtResult = Result<(), NTSTATUS>; diff --git a/dokan/src/to_file_time.rs b/dokan/src/to_file_time.rs index 10bc3bb..63d9a7c 100644 --- a/dokan/src/to_file_time.rs +++ b/dokan/src/to_file_time.rs @@ -1,6 +1,6 @@ use std::time::{Duration, SystemTime, UNIX_EPOCH}; -use winapi::shared::minwindef::FILETIME; +use windows_sys::Win32::Foundation::FILETIME; pub const FILETIME_OFFSET: Duration = Duration::from_secs(11644473600); diff --git a/dokan/src/usage_tests.rs b/dokan/src/usage_tests.rs index 1876456..f6abc9b 100644 --- a/dokan/src/usage_tests.rs +++ b/dokan/src/usage_tests.rs @@ -1,5 +1,3 @@ -extern crate lazy_static; -extern crate parking_lot; extern crate regex; use std::{ @@ -9,43 +7,62 @@ use std::{ os::windows::prelude::{AsRawHandle, FromRawHandle, OwnedHandle}, pin::Pin, process, ptr, + sync::LazyLock, sync::mpsc::{self, Receiver, SyncSender}, thread, time::{Duration, UNIX_EPOCH}, }; +use dokan_sys::LPVOID; use dokan_sys::win32::{ FILE_NON_DIRECTORY_FILE, FILE_OPEN, FILE_SYNCHRONOUS_IO_NONALERT, FILE_WRITE_THROUGH, WIN32_FIND_STREAM_DATA, }; -use parking_lot::Mutex; +use std::sync::Mutex; use widestring::{U16CStr, U16CString}; -use winapi::{ - shared::{ - minwindef::{BOOL, FALSE, HLOCAL, LPCVOID, LPVOID, MAX_PATH, TRUE}, - ntdef::{HANDLE, NTSTATUS, NULL}, - ntstatus::{STATUS_ACCESS_DENIED, STATUS_NOT_IMPLEMENTED, STATUS_SUCCESS}, - sddl::ConvertSidToStringSidW, - winerror::{ - ERROR_HANDLE_EOF, ERROR_INSUFFICIENT_BUFFER, ERROR_INTERNAL_ERROR, ERROR_IO_PENDING, - ERROR_NO_MORE_FILES, - }, +use windows_sys::Win32::{ + Foundation::{ + CloseHandle, ERROR_HANDLE_EOF, ERROR_INSUFFICIENT_BUFFER, ERROR_INTERNAL_ERROR, + ERROR_IO_PENDING, ERROR_NO_MORE_FILES, FALSE, GENERIC_ALL, GENERIC_READ, GetLastError, + HANDLE, INVALID_HANDLE_VALUE, LocalFree, MAX_PATH, NTSTATUS, STATUS_ACCESS_DENIED, + STATUS_NOT_IMPLEMENTED, STATUS_SUCCESS, TRUE, + }, + Security::{ + Authorization::ConvertSidToStringSidW, EqualSid, GetFileSecurityW, + GetSecurityDescriptorOwner, GetTokenInformation, InitializeSecurityDescriptor, + MakeSelfRelativeSD, OWNER_SECURITY_INFORMATION, PSECURITY_DESCRIPTOR, SECURITY_DESCRIPTOR, + SetFileSecurityW, SetSecurityDescriptorOwner, TOKEN_QUERY, TOKEN_USER, TokenUser, }, - um::{ - errhandlingapi::GetLastError, - fileapi::*, - handleapi::{CloseHandle, INVALID_HANDLE_VALUE}, - ioapiset::GetOverlappedResult, - minwinbase::OVERLAPPED, - processthreadsapi::{GetCurrentProcess, OpenProcessToken}, - securitybaseapi::*, - synchapi::CreateEventW, - winbase::*, - winnt::*, + Storage::FileSystem::{ + CreateFileW, DeleteFileW, FILE_ACTION_ADDED, FILE_ACTION_MODIFIED, FILE_ACTION_REMOVED, + FILE_ACTION_RENAMED_NEW_NAME, FILE_ACTION_RENAMED_OLD_NAME, FILE_ALL_ACCESS, + FILE_ATTRIBUTE_DIRECTORY, FILE_ATTRIBUTE_NORMAL, FILE_ATTRIBUTE_READONLY, FILE_BEGIN, + FILE_FLAG_BACKUP_SEMANTICS, FILE_FLAG_OVERLAPPED, FILE_FLAG_WRITE_THROUGH, + FILE_NOTIFY_CHANGE_ATTRIBUTES, FILE_NOTIFY_CHANGE_FILE_NAME, FILE_NOTIFY_INFORMATION, + FILE_SHARE_READ, FindClose, FindFirstFileW, FindFirstStreamW, FindNextFileW, + FindNextStreamW, FindStreamInfoStandard, FlushFileBuffers, GetDiskFreeSpaceExW, + GetFileInformationByHandle, GetVolumeInformationW, LockFile, MOVEFILE_REPLACE_EXISTING, + MoveFileExW, OPEN_EXISTING, ReadDirectoryChangesW, ReadFile, RemoveDirectoryW, + SetEndOfFile, SetFileAttributesW, SetFilePointer, SetFileTime, SetFileValidData, + UnlockFile, WriteFile, + }, + System::{ + IO::{GetOverlappedResult, OVERLAPPED}, + SystemServices::{ + FILE_CASE_PRESERVED_NAMES, FILE_CASE_SENSITIVE_SEARCH, FILE_NAMED_STREAMS, + FILE_UNICODE_ON_DISK, SECURITY_DESCRIPTOR_REVISION, + }, + Threading::{CreateEventW, GetCurrentProcess, OpenProcessToken}, }, }; +use windows_sys::core::BOOL; + +#[allow(non_camel_case_types)] +type SECURITY_INFORMATION = u32; use crate::{ + FileSystemHandle, FileSystemHandler, FileSystemMounter, IO_SECURITY_CONTEXT, MountFlags, + MountOptions, data::{ CreateFileInfo, DiskSpaceInfo, FileInfo, FileTimeOperation, FillDataResult, FindData, FindStreamData, OperationInfo, VolumeInfo, @@ -55,8 +72,7 @@ use crate::{ operations_helpers::NtResult, shutdown, to_file_time::ToFileTime, - unmount, FileSystemHandle, FileSystemHandler, FileSystemMounter, MountFlags, MountOptions, - IO_SECURITY_CONTEXT, + unmount, }; pub fn convert_str(s: impl AsRef) -> U16CString { @@ -183,7 +199,7 @@ fn get_descriptor_owner(desc: PSECURITY_DESCRIPTOR) -> (U16CString, BOOL) { let mut ps = ptr::null_mut(); assert_eq_win32!(ConvertSidToStringSidW(psid, &mut ps), TRUE); let sid = U16CStr::from_ptr_str(ps).to_owned(); - assert_eq_win32!(LocalFree(ps as HLOCAL), NULL); + assert_eq_win32!(LocalFree(ps as _), ptr::null_mut()); (sid, owner_defaulted) } } @@ -228,7 +244,7 @@ fn get_current_user_info() -> Pin> { fn create_test_descriptor() -> Vec { unsafe { let mut user_info_buffer = get_current_user_info(); - let user_info = &*(user_info_buffer.as_mut_ptr() as PTOKEN_USER); + let user_info = &*(user_info_buffer.as_mut_ptr() as *const TOKEN_USER); let mut abs_desc = mem::zeroed::(); let abs_desc_ptr = &mut abs_desc as *mut _ as PSECURITY_DESCRIPTOR; assert_eq_win32!( @@ -842,9 +858,7 @@ impl<'a, 'b: 'a> FileSystemHandler<'a, 'b> for TestHandler { } } -lazy_static::lazy_static! { - static ref TEST_DRIVE_LOCK: Mutex<()> = Mutex::new(()); -} +static TEST_DRIVE_LOCK: LazyLock> = LazyLock::new(|| Mutex::new(())); pub struct TestDriveContext<'a> { rx_instance: &'a Receiver, @@ -858,6 +872,19 @@ impl TestDriveContext<'_> { self.rx_signal.recv().unwrap() } + /// Receives signals until one matches the predicate, discarding others. + /// This is useful when Windows may inject additional calls (e.g. extra + /// `GetFileSecurity` queries with different `security_information` values) + /// that aren't relevant to the test assertion. + pub fn signal_matching(&self, pred: impl Fn(&HandlerSignal) -> bool) -> HandlerSignal { + loop { + let sig = self.signal(); + if pred(&sig) { + return sig; + } + } + } + pub fn instance(&self) -> FileSystemHandle { *self .instance @@ -882,7 +909,7 @@ pub fn test_flags() -> MountFlags { #[allow(unused_must_use)] pub fn with_test_drive(scope: Scope) { - let _guard = TEST_DRIVE_LOCK.lock(); + let _guard = TEST_DRIVE_LOCK.lock().unwrap_or_else(|e| e.into_inner()); init(); @@ -951,8 +978,8 @@ fn supports_panic_in_handler() { fn can_retrieve_volume_information() { with_test_drive(|_| unsafe { let path = convert_str("Z:\\"); - let mut volume_name = [0; MAX_PATH + 1]; - let mut fs_name = [0; MAX_PATH + 1]; + let mut volume_name = [0; MAX_PATH as usize + 1]; + let mut fs_name = [0; MAX_PATH as usize + 1]; let mut serial_number = 0; let mut max_component_length = 0; let mut fs_flags = 0; @@ -999,9 +1026,9 @@ fn can_retrieve_disk_space() { assert_eq_win32!( GetDiskFreeSpaceExW( path.as_ptr(), - &mut free_bytes_available as *mut _ as PULARGE_INTEGER, - &mut total_number_of_bytes as *mut _ as PULARGE_INTEGER, - &mut total_number_of_free_bytes as *mut _ as PULARGE_INTEGER, + &mut free_bytes_available, + &mut total_number_of_bytes, + &mut total_number_of_free_bytes, ), TRUE ); @@ -1066,7 +1093,7 @@ fn can_read_from_and_write_to_file() { assert_eq_win32!( ReadFile( hf, - buf.as_mut_ptr() as LPVOID, + buf.as_mut_ptr(), buf.len() as u32, &mut len, ptr::null_mut() @@ -1080,13 +1107,7 @@ fn can_read_from_and_write_to_file() { assert_eq!(context.signal(), HandlerSignal::ReadFile(0, buf.len())); let mut bytes_written = 0; assert_eq_win32!( - WriteFile( - hf, - buf.as_ptr() as LPCVOID, - len, - &mut bytes_written, - ptr::null_mut() - ), + WriteFile(hf, buf.as_ptr(), len, &mut bytes_written, ptr::null_mut()), TRUE ); assert_eq!(bytes_written, len); @@ -1354,7 +1375,9 @@ fn can_get_file_security() { ); assert_eq!(GetLastError(), ERROR_INSUFFICIENT_BUFFER); assert_eq!( - context.signal(), + context.signal_matching( + |s| matches!(s, HandlerSignal::GetFileSecurity(si, _) if *si == OWNER_SECURITY_INFORMATION) + ), HandlerSignal::GetFileSecurity(OWNER_SECURITY_INFORMATION, 0) ); let mut desc = vec![0u8; desc_len as usize]; @@ -1370,7 +1393,9 @@ fn can_get_file_security() { ); assert_eq!(desc.len(), desc_len as usize); assert_eq!( - context.signal(), + context.signal_matching( + |s| matches!(s, HandlerSignal::GetFileSecurity(si, _) if *si == OWNER_SECURITY_INFORMATION) + ), HandlerSignal::GetFileSecurity(OWNER_SECURITY_INFORMATION, desc_len) ); assert_eq!(desc, expected_desc); @@ -1432,7 +1457,7 @@ fn can_find_streams() { 0, ); assert_ne_win32!(hf, INVALID_HANDLE_VALUE); - assert_eq!(data.StreamSize.QuadPart(), &42); + assert_eq!(data.StreamSize, 42); assert_eq!( U16CStr::from_slice_truncate(&data.cStreamName).unwrap(), convert_str("::$DATA") @@ -1468,13 +1493,16 @@ fn can_open_requester_token() { let expected_info_buffer = get_current_user_info(); let hf = open_file("Z:\\test_open_requester_token"); assert_eq_win32!(CloseHandle(hf), TRUE); - if let HandlerSignal::OpenRequesterToken(info_buffer) = context.signal() { - let expected_info = &*(expected_info_buffer.as_ptr() as *const TOKEN_USER); - let info = &*(info_buffer.as_ptr() as *const TOKEN_USER); - assert_eq_win32!(EqualSid(info.User.Sid, expected_info.User.Sid), TRUE); - assert_eq!(info.User.Attributes, expected_info.User.Attributes); - } else { - panic!("unexpected signal type"); + match context.signal() { + HandlerSignal::OpenRequesterToken(info_buffer) => { + let expected_info = &*(expected_info_buffer.as_ptr() as *const TOKEN_USER); + let info = &*(info_buffer.as_ptr() as *const TOKEN_USER); + assert_eq_win32!(EqualSid(info.User.Sid, expected_info.User.Sid), TRUE); + assert_eq!(info.User.Attributes, expected_info.User.Attributes); + } + _ => { + panic!("unexpected signal type"); + } } }); } @@ -1563,7 +1591,8 @@ impl DirectoryChangeIterator { hd: OwnedHandle::from_raw_handle(hd), buf: Pin::new(vec![ 0; - mem::size_of::() + MAX_PATH + mem::size_of::() + + MAX_PATH as usize ]), offset: 0, he: OwnedHandle::from_raw_handle(he),