From 64c8e57e3f9eee294913df4b15bb036ff8824e17 Mon Sep 17 00:00:00 2001 From: Jon-Luke Biddle Date: Tue, 31 Mar 2026 18:24:37 -0600 Subject: [PATCH 01/13] upgrade to rust 2024 --- Cargo.lock | 237 ++++++++++++++++------------------- dokan-sys/Cargo.toml | 2 +- dokan-sys/src/lib.rs | 56 ++++----- dokan/Cargo.toml | 2 +- dokan/examples/memfs/main.rs | 6 +- dokan/src/data/find_data.rs | 6 +- dokan/src/operations.rs | 50 ++++---- dokan/src/usage_tests.rs | 17 +-- 8 files changed, 180 insertions(+), 196 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index f8234ae..88149e6 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4,18 +4,18 @@ version = 4 [[package]] name = "aho-corasick" -version = "1.1.3" +version = "1.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8e60d3430d3a69478ad0993f19238d2df97c507009a52b3c10addcd7f6bcb916" +checksum = "ddd31a130427c27518df266943a5308ed92d4b226cc639f5a8f1002816174301" dependencies = [ "memchr", ] [[package]] name = "anstream" -version = "0.6.18" +version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8acc5369981196006228e28809f761875c0327210a891e941f4c683b3a99529b" +checksum = "824a212faf96e9acacdbd09febd34438f8f711fb84e09a8916013cd7815ca28d" dependencies = [ "anstyle", "anstyle-parse", @@ -28,65 +28,69 @@ dependencies = [ [[package]] name = "anstyle" -version = "1.0.10" +version = "1.0.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "55cc3b69f167a1ef2e161439aa98aed94e6028e5f9a59be9a6ffb47aef1651f9" +checksum = "940b3a0ca603d1eade50a4846a2afffd5ef57a9feac2c0e2ec2e14f9ead76000" [[package]] name = "anstyle-parse" -version = "0.2.6" +version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3b2d16507662817a6a20a9ea92df6652ee4f94f914589377d69f3b21bc5798a9" +checksum = "52ce7f38b242319f7cabaa6813055467063ecdc9d355bbb4ce0c68908cd8130e" dependencies = [ "utf8parse", ] [[package]] name = "anstyle-query" -version = "1.1.2" +version = "1.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "79947af37f4177cfead1110013d678905c37501914fba0efea834c3fe9a8d60c" +checksum = "40c48f72fd53cd289104fc64099abca73db4166ad86ea0b4341abe65af83dadc" dependencies = [ "windows-sys", ] [[package]] name = "anstyle-wincon" -version = "3.0.7" +version = "3.0.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ca3534e77181a9cc07539ad51f2141fe32f6c3ffd4df76db8ad92346b003ae4e" +checksum = "291e6a250ff86cd4a820112fb8898808a366d8f9f58ce16d1f538353ad55747d" dependencies = [ "anstyle", - "once_cell", + "once_cell_polyfill", "windows-sys", ] [[package]] -name = "autocfg" -version = "1.4.0" +name = "bitflags" +version = "2.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ace50bade8e6234aa140d9a2f552bbee1db4d353f69b8217bc503490fc1a9f26" +checksum = "843867be96c8daad0d758b57df9392b6d8d271134fce549de6ce169ff98a92af" [[package]] -name = "bitflags" -version = "2.9.0" +name = "block2" +version = "0.6.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5c8214115b7bf84099f1309324e63141d4c5d7cc26862f97a0a857dbefe165bd" +checksum = "cdeb9d870516001442e364c5220d3574d2da8dc765554b4a617230d33fa58ef5" +dependencies = [ + "objc2", +] [[package]] name = "cc" -version = "1.2.20" +version = "1.2.58" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "04da6a0d40b948dfc4fa8f5bbf402b0fc1a64a28dbf7d12ffd683550f2c1b63a" +checksum = "e1e928d4b69e3077709075a938a05ffbedfa53a84c8f766efbf8220bb1ff60e1" dependencies = [ + "find-msvc-tools", "shlex", ] [[package]] name = "cfg-if" -version = "1.0.0" +version = "1.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" +checksum = "9330f8b2ff13f34540b44e946ef35111825727b38d33286ef986142615121801" [[package]] name = "cfg_aliases" @@ -96,18 +100,18 @@ checksum = "613afe47fcd5fac7ccf1db93babcb082c5994d996f20b8b159f2ad1658eb5724" [[package]] name = "clap" -version = "4.5.37" +version = "4.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eccb054f56cbd38340b380d4a8e69ef1f02f1af43db2f0cc817a4774d80ae071" +checksum = "b193af5b67834b676abd72466a96c1024e6a6ad978a1f484bd90b85c94041351" dependencies = [ "clap_builder", ] [[package]] name = "clap_builder" -version = "4.5.37" +version = "4.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "efd9466fac8543255d3b1fcad4762c5e116ffe808c8a3043d4263cd4fd4862a2" +checksum = "714a53001bf66416adb0e2ef5ac857140e7dc3a0c48fb28b2f10762fc4b5069f" dependencies = [ "anstream", "anstyle", @@ -117,26 +121,39 @@ dependencies = [ [[package]] name = "clap_lex" -version = "0.7.4" +version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f46ad14479a25103f283c0f10005961cf086d8dc42205bb44c46ac563475dca6" +checksum = "c8d4a3bb8b1e0c1050499d1815f5ab16d04f0959b233085fb31653fbfc9d98f9" [[package]] name = "colorchoice" -version = "1.0.3" +version = "1.0.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5b63caa9aa9397e2d9480a9b13673856c78d8ac123288526c37d7839f2a86990" +checksum = "1d07550c9036bf2ae0c684c4297d503f838287c83c53686d05370d0e139ae570" [[package]] name = "ctrlc" -version = "3.4.6" +version = "3.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "697b5419f348fd5ae2478e8018cb016c00a5881c7f46c717de98ffd135a5651c" +checksum = "e0b1fab2ae45819af2d0731d60f2afe17227ebb1a1538a236da84c93e9a60162" dependencies = [ + "dispatch2", "nix", "windows-sys", ] +[[package]] +name = "dispatch2" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e0e367e4e7da84520dedcac1901e4da967309406d1e51017ae1abfb97adbd38" +dependencies = [ + "bitflags", + "block2", + "libc", + "objc2", +] + [[package]] name = "dokan" version = "0.3.1+dokan230" @@ -161,11 +178,17 @@ dependencies = [ "winapi", ] +[[package]] +name = "find-msvc-tools" +version = "0.1.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5baebc0774151f905a1a2cc41989300b1e6fbb29aff0ceffa1064fdd3088d582" + [[package]] name = "is_terminal_polyfill" -version = "1.70.1" +version = "1.70.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7943c866cc5cd64cbc25b2e01621d07fa8eb2a1a23160ee81ce38704e97b8ecf" +checksum = "a6cb138bb79a146c1bd460005623e142ef0181e3d0219cb493e02f7d08a35695" [[package]] name = "lazy_static" @@ -175,31 +198,30 @@ checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe" [[package]] name = "libc" -version = "0.2.172" +version = "0.2.183" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d750af042f7ef4f724306de029d18836c26c1765a54a6a3f094cbd23a7267ffa" +checksum = "b5b646652bf6661599e1da8901b3b9522896f01e736bad5f723fe7a3a27f899d" [[package]] name = "lock_api" -version = "0.4.12" +version = "0.4.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "07af8b9cdd281b7915f413fa73f29ebd5d55d0d3f0155584dade1ff18cea1b17" +checksum = "224399e74b87b5f3557511d98dff8b14089b3dadafcab6bb93eab67d3aace965" dependencies = [ - "autocfg", "scopeguard", ] [[package]] name = "memchr" -version = "2.7.4" +version = "2.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "78ca9ab1a0babb1e7d5695e3530886289c18cf2f87ec19a575a0abdce112e3a3" +checksum = "f8ca58f447f06ed17d5fc4043ce1b10dd205e060fb3ce5b979b8ed8e59ff3f79" [[package]] name = "nix" -version = "0.29.0" +version = "0.31.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "71e2746dc3a24dd78b3cfcb7be93368c6de9963d30f43a6a73998a9cf4b17b46" +checksum = "5d6d0705320c1e6ba1d912b5e37cf18071b6c2e9b7fa8215a1e8a7651966f5d3" dependencies = [ "bitflags", "cfg-if", @@ -208,16 +230,31 @@ dependencies = [ ] [[package]] -name = "once_cell" -version = "1.21.3" +name = "objc2" +version = "0.6.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3a12a8ed07aefc768292f076dc3ac8c48f3781c8f2d5851dd3d98950e8c5a89f" +dependencies = [ + "objc2-encode", +] + +[[package]] +name = "objc2-encode" +version = "4.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ef25abbcd74fb2609453eb695bd2f860d389e457f67dc17cafc8b8cbc89d0c33" + +[[package]] +name = "once_cell_polyfill" +version = "1.70.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "42f5e15c9953c5e4ccceeb2e7382a716482c34515315f7b03532b8b4e8393d2d" +checksum = "384b8ab6d37215f3c5301a95a4accb5d64aa607f1fcb26a11b5303878451b4fe" [[package]] name = "parking_lot" -version = "0.12.3" +version = "0.12.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f1bf18183cf54e8d6059647fc3063646a1801cf30896933ec2311622cc4b9a27" +checksum = "93857453250e3077bd71ff98b6a65ea6621a19bb0f559a85248955ac12c45a1a" dependencies = [ "lock_api", "parking_lot_core", @@ -225,31 +262,31 @@ dependencies = [ [[package]] name = "parking_lot_core" -version = "0.9.10" +version = "0.9.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1e401f977ab385c9e4e3ab30627d6f26d00e2c73eef317493c4ec6d468726cf8" +checksum = "2621685985a2ebf1c516881c026032ac7deafcda1a2c9b7850dc81e3dfcb64c1" dependencies = [ "cfg-if", "libc", "redox_syscall", "smallvec", - "windows-targets", + "windows-link", ] [[package]] name = "redox_syscall" -version = "0.5.11" +version = "0.5.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d2f103c6d277498fbceb16e84d317e2a400f160f46904d5f5410848c829511a3" +checksum = "ed2bf2547551a7053d6fdfafda3f938979645c44812fbfcda098faae3f1a362d" dependencies = [ "bitflags", ] [[package]] name = "regex" -version = "1.11.1" +version = "1.12.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b544ef1b4eac5dc2db33ea63606ae9ffcfac26c1416a2806ae0bf5f56b201191" +checksum = "e10754a14b9137dd7b1e3e5b0493cc9171fdd105e0ab477f51b72e7f3ac0e276" dependencies = [ "aho-corasick", "memchr", @@ -259,9 +296,9 @@ dependencies = [ [[package]] name = "regex-automata" -version = "0.4.9" +version = "0.4.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "809e8dc61f6de73b46c85f4c96486310fe304c434cfa43669d7b40f711150908" +checksum = "6e1dd4122fc1595e8162618945476892eefca7b88c52820e74af6262213cae8f" dependencies = [ "aho-corasick", "memchr", @@ -270,9 +307,9 @@ dependencies = [ [[package]] name = "regex-syntax" -version = "0.8.5" +version = "0.8.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2b15c43186be67a4fd63bee50d0303afffcef381492ebe2c5d87f324e1b8815c" +checksum = "dc897dd8d9e8bd1ed8cdad82b5966c3e0ecae09fb1907d58efaa013543185d0a" [[package]] name = "scopeguard" @@ -288,9 +325,9 @@ checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64" [[package]] name = "smallvec" -version = "1.15.0" +version = "1.15.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8917285742e9f3e1683f0a9c4e6b57960b7314d0b08d30d1ecd426713ee2eee9" +checksum = "67b1b7a3b5fe4f1376887184045fcf45c69e92af734b7aaddc05fb777b6fbd03" [[package]] name = "strsim" @@ -306,9 +343,9 @@ checksum = "06abde3611657adf66d383f00b093d7faecc7fa57071cce2578660c9f1010821" [[package]] name = "widestring" -version = "1.2.0" +version = "1.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dd7cf3379ca1aac9eea11fba24fd7e315d621f8dfe35c8d7d2be8b793726e07d" +checksum = "72069c3113ab32ab29e5584db3c6ec55d416895e60715417b5b883a357c3e471" [[package]] name = "winapi" @@ -333,74 +370,16 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" [[package]] -name = "windows-sys" -version = "0.59.0" +name = "windows-link" +version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1e38bc4d79ed67fd075bcc251a1c39b32a1776bbe92e5bef1f0bf1f8c531853b" -dependencies = [ - "windows-targets", -] +checksum = "f0805222e57f7521d6a62e36fa9163bc891acd422f971defe97d64e70d0a4fe5" [[package]] -name = "windows-targets" -version = "0.52.6" +name = "windows-sys" +version = "0.61.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9b724f72796e036ab90c1021d4780d4d3d648aca59e491e6b98e725b84e99973" +checksum = "ae137229bcbd6cdf0f7b80a31df61766145077ddf49416a728b02cb3921ff3fc" 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", + "windows-link", ] - -[[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..fb1dedd 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" diff --git a/dokan-sys/src/lib.rs b/dokan-sys/src/lib.rs index 13976bf..7a48f26 100644 --- a/dokan-sys/src/lib.rs +++ b/dokan-sys/src/lib.rs @@ -93,8 +93,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,7 +125,7 @@ pub type PDOKAN_IO_SECURITY_CONTEXT = *mut DOKAN_IO_SECURITY_CONTEXT; #[derive(Clone)] pub struct DOKAN_OPERATIONS { pub ZwCreateFile: Option< - extern "stdcall" fn( + extern "system" fn( FileName: LPCWSTR, SecurityContext: PDOKAN_IO_SECURITY_CONTEXT, DesiredAccess: ACCESS_MASK, @@ -136,10 +136,10 @@ 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( + extern "system" fn( FileName: LPCWSTR, Buffer: LPVOID, BufferLength: DWORD, @@ -149,7 +149,7 @@ pub struct DOKAN_OPERATIONS { ) -> NTSTATUS, >, pub WriteFile: Option< - extern "stdcall" fn( + extern "system" fn( FileName: LPCWSTR, Buffer: LPCVOID, NumberOfBytesToWrite: DWORD, @@ -159,23 +159,23 @@ pub struct DOKAN_OPERATIONS { ) -> NTSTATUS, >, pub FlushFileBuffers: - Option NTSTATUS>, + Option NTSTATUS>, pub GetFileInformation: Option< - extern "stdcall" fn( + extern "system" fn( FileName: LPCWSTR, Buffer: LPBY_HANDLE_FILE_INFORMATION, DokanFileInfo: PDOKAN_FILE_INFO, ) -> NTSTATUS, >, pub FindFiles: Option< - extern "stdcall" fn( + extern "system" fn( FileName: LPCWSTR, FillFindData: PFillFindData, DokanFileInfo: PDOKAN_FILE_INFO, ) -> NTSTATUS, >, pub FindFilesWithPattern: Option< - extern "stdcall" fn( + extern "system" fn( PathName: LPCWSTR, SearchPattern: LPCWSTR, FillFindData: PFillFindData, @@ -183,14 +183,14 @@ pub struct DOKAN_OPERATIONS { ) -> NTSTATUS, >, pub SetFileAttributes: Option< - extern "stdcall" fn( + extern "system" fn( FileName: LPCWSTR, FileAttributes: DWORD, DokanFileInfo: PDOKAN_FILE_INFO, ) -> NTSTATUS, >, pub SetFileTime: Option< - extern "stdcall" fn( + extern "system" fn( FileName: LPCWSTR, creation_time: *const FILETIME, last_access_time: *const FILETIME, @@ -199,11 +199,11 @@ pub struct DOKAN_OPERATIONS { ) -> NTSTATUS, >, pub DeleteFile: - Option NTSTATUS>, + Option NTSTATUS>, pub DeleteDirectory: - Option NTSTATUS>, + Option NTSTATUS>, pub MoveFile: Option< - extern "stdcall" fn( + extern "system" fn( FileName: LPCWSTR, NewFileName: LPCWSTR, ReplaceIfExisting: BOOL, @@ -211,21 +211,21 @@ pub struct DOKAN_OPERATIONS { ) -> NTSTATUS, >, pub SetEndOfFile: Option< - extern "stdcall" fn( + extern "system" fn( FileName: LPCWSTR, ByteOffset: LONGLONG, DokanFileInfo: PDOKAN_FILE_INFO, ) -> NTSTATUS, >, pub SetAllocationSize: Option< - extern "stdcall" fn( + extern "system" fn( FileName: LPCWSTR, AllocSize: LONGLONG, DokanFileInfo: PDOKAN_FILE_INFO, ) -> NTSTATUS, >, pub LockFile: Option< - extern "stdcall" fn( + extern "system" fn( FileName: LPCWSTR, ByteOffset: LONGLONG, Length: LONGLONG, @@ -233,7 +233,7 @@ pub struct DOKAN_OPERATIONS { ) -> NTSTATUS, >, pub UnlockFile: Option< - extern "stdcall" fn( + extern "system" fn( FileName: LPCWSTR, ByteOffset: LONGLONG, Length: LONGLONG, @@ -241,7 +241,7 @@ pub struct DOKAN_OPERATIONS { ) -> NTSTATUS, >, pub GetDiskFreeSpace: Option< - extern "stdcall" fn( + extern "system" fn( FreeBytesAvailable: PULONGLONG, TotalNumberOfBytes: PULONGLONG, TotalNumberOfFreeBytes: PULONGLONG, @@ -249,7 +249,7 @@ pub struct DOKAN_OPERATIONS { ) -> NTSTATUS, >, pub GetVolumeInformation: Option< - extern "stdcall" fn( + extern "system" fn( VolumeNameBuffer: LPWSTR, VolumeNameSize: DWORD, VolumeSerialNumber: LPDWORD, @@ -261,11 +261,11 @@ pub struct DOKAN_OPERATIONS { ) -> NTSTATUS, >, pub Mounted: Option< - extern "stdcall" fn(MountPoint: LPCWSTR, DokanFileInfo: PDOKAN_FILE_INFO) -> NTSTATUS, + extern "system" fn(MountPoint: LPCWSTR, DokanFileInfo: PDOKAN_FILE_INFO) -> NTSTATUS, >, - pub Unmounted: Option NTSTATUS>, + pub Unmounted: Option NTSTATUS>, pub GetFileSecurity: Option< - extern "stdcall" fn( + extern "system" fn( FileName: LPCWSTR, PSECURITY_INFORMATION: PSECURITY_INFORMATION, PSECURITY_DESCRIPTOR: PSECURITY_DESCRIPTOR, @@ -275,7 +275,7 @@ pub struct DOKAN_OPERATIONS { ) -> NTSTATUS, >, pub SetFileSecurity: Option< - extern "stdcall" fn( + extern "system" fn( FileName: LPCWSTR, SecurityInformation: PSECURITY_INFORMATION, SecurityDescriptor: PSECURITY_DESCRIPTOR, @@ -284,7 +284,7 @@ pub struct DOKAN_OPERATIONS { ) -> NTSTATUS, >, pub FindStreams: Option< - extern "stdcall" fn( + extern "system" fn( FileName: LPCWSTR, FillFindStreamData: PFillFindStreamData, FindStreamContext: PVOID, @@ -316,7 +316,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; diff --git a/dokan/Cargo.toml b/dokan/Cargo.toml index af3ccd1..702931b 100644 --- a/dokan/Cargo.toml +++ b/dokan/Cargo.toml @@ -10,7 +10,7 @@ keywords = ["dokan", "bindings", "driver", "filesystem"] categories = ["external-ffi-bindings"] readme = "README.md" license = "MIT" -edition = "2021" +edition = "2024" [badges] appveyor = { repository = "Liryna/dokan-rust" } diff --git a/dokan/examples/memfs/main.rs b/dokan/examples/memfs/main.rs index 35de54d..f7e9463 100644 --- a/dokan/examples/memfs/main.rs +++ b/dokan/examples/memfs/main.rs @@ -692,12 +692,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; } diff --git a/dokan/src/data/find_data.rs b/dokan/src/data/find_data.rs index c500cf8..c9ad4a7 100644 --- a/dokan/src/data/find_data.rs +++ b/dokan/src/data/find_data.rs @@ -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 { @@ -137,11 +137,11 @@ mod tests { } } - 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/operations.rs b/dokan/src/operations.rs index 2c56991..5772dd0 100644 --- a/dokan/src/operations.rs +++ b/dokan/src/operations.rs @@ -23,7 +23,7 @@ use crate::{ operations_helpers::{wrap_nt_result, wrap_unit, NtResult}, }; -pub extern "stdcall" fn create_file<'c, 'h: 'c, FSH: FileSystemHandler<'c, 'h> + 'h>( +pub extern "system" fn create_file<'c, 'h: 'c, FSH: FileSystemHandler<'c, 'h> + 'h>( file_name: LPCWSTR, security_context: PDOKAN_IO_SECURITY_CONTEXT, desired_access: ACCESS_MASK, @@ -64,7 +64,7 @@ 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>( +pub extern "system" fn cleanup<'c, 'h: 'c, FSH: FileSystemHandler<'c, 'h> + 'h>( file_name: LPCWSTR, dokan_file_info: PDOKAN_FILE_INFO, ) { @@ -75,7 +75,7 @@ pub extern "stdcall" fn cleanup<'c, 'h: 'c, FSH: FileSystemHandler<'c, 'h> + 'h> }); } -pub extern "stdcall" fn close_file<'c, 'h: 'c, FSH: FileSystemHandler<'c, 'h> + 'h>( +pub extern "system" fn close_file<'c, 'h: 'c, FSH: FileSystemHandler<'c, 'h> + 'h>( file_name: LPCWSTR, dokan_file_info: PDOKAN_FILE_INFO, ) { @@ -87,7 +87,7 @@ pub extern "stdcall" fn close_file<'c, 'h: 'c, FSH: FileSystemHandler<'c, 'h> + }); } -pub extern "stdcall" fn read_file<'c, 'h: 'c, FSH: FileSystemHandler<'c, 'h> + 'h>( +pub extern "system" fn read_file<'c, 'h: 'c, FSH: FileSystemHandler<'c, 'h> + 'h>( file_name: LPCWSTR, buffer: LPVOID, buffer_length: DWORD, @@ -108,7 +108,7 @@ 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>( +pub extern "system" fn write_file<'c, 'h: 'c, FSH: FileSystemHandler<'c, 'h> + 'h>( file_name: LPCWSTR, buffer: LPCVOID, number_of_bytes_to_write: DWORD, @@ -129,7 +129,7 @@ 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>( +pub extern "system" fn flush_file_buffers<'c, 'h: 'c, FSH: FileSystemHandler<'c, 'h> + 'h>( file_name: LPCWSTR, dokan_file_info: PDOKAN_FILE_INFO, ) -> NTSTATUS { @@ -141,7 +141,7 @@ 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>( +pub extern "system" fn get_file_information<'c, 'h: 'c, FSH: FileSystemHandler<'c, 'h> + 'h>( file_name: LPCWSTR, buffer: LPBY_HANDLE_FILE_INFORMATION, dokan_file_info: PDOKAN_FILE_INFO, @@ -157,7 +157,7 @@ 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>( +pub extern "system" fn find_files<'c, 'h: 'c, FSH: FileSystemHandler<'c, 'h> + 'h>( file_name: LPCWSTR, fill_find_data: PFillFindData, dokan_file_info: PDOKAN_FILE_INFO, @@ -171,7 +171,7 @@ 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>( +pub extern "system" fn find_files_with_pattern<'c, 'h: 'c, FSH: FileSystemHandler<'c, 'h> + 'h>( file_name: LPCWSTR, search_pattern: LPCWSTR, fill_find_data: PFillFindData, @@ -192,7 +192,7 @@ 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>( +pub extern "system" fn set_file_attributes<'c, 'h: 'c, FSH: FileSystemHandler<'c, 'h> + 'h>( file_name: LPCWSTR, file_attributes: DWORD, dokan_file_info: PDOKAN_FILE_INFO, @@ -205,7 +205,7 @@ 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>( +pub extern "system" fn set_file_time<'c, 'h: 'c, FSH: FileSystemHandler<'c, 'h> + 'h>( file_name: LPCWSTR, creation_time: *const FILETIME, last_access_time: *const FILETIME, @@ -226,7 +226,7 @@ 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>( +pub extern "system" fn delete_file<'c, 'h: 'c, FSH: FileSystemHandler<'c, 'h> + 'h>( file_name: LPCWSTR, dokan_file_info: PDOKAN_FILE_INFO, ) -> NTSTATUS { @@ -237,7 +237,7 @@ 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>( +pub extern "system" fn delete_directory<'c, 'h: 'c, FSH: FileSystemHandler<'c, 'h> + 'h>( file_name: LPCWSTR, dokan_file_info: PDOKAN_FILE_INFO, ) -> NTSTATUS { @@ -249,7 +249,7 @@ 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>( +pub extern "system" fn move_file<'c, 'h: 'c, FSH: FileSystemHandler<'c, 'h> + 'h>( file_name: LPCWSTR, new_file_name: LPCWSTR, replace_if_existing: BOOL, @@ -269,7 +269,7 @@ 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>( +pub extern "system" fn set_end_of_file<'c, 'h: 'c, FSH: FileSystemHandler<'c, 'h> + 'h>( file_name: LPCWSTR, byte_offset: LONGLONG, dokan_file_info: PDOKAN_FILE_INFO, @@ -282,7 +282,7 @@ 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>( +pub extern "system" fn set_allocation_size<'c, 'h: 'c, FSH: FileSystemHandler<'c, 'h> + 'h>( file_name: LPCWSTR, alloc_size: LONGLONG, dokan_file_info: PDOKAN_FILE_INFO, @@ -326,7 +326,7 @@ 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>( +pub extern "system" fn lock_file<'c, 'h: 'c, FSH: FileSystemHandler<'c, 'h> + 'h>( file_name: LPCWSTR, byte_offset: LONGLONG, length: LONGLONG, @@ -341,7 +341,7 @@ 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>( +pub extern "system" fn unlock_file<'c, 'h: 'c, FSH: FileSystemHandler<'c, 'h> + 'h>( file_name: LPCWSTR, byte_offset: LONGLONG, length: LONGLONG, @@ -356,7 +356,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,7 +380,7 @@ 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>( +pub extern "system" fn get_volume_information<'c, 'h: 'c, FSH: FileSystemHandler<'c, 'h> + 'h>( volume_name_buffer: LPWSTR, volume_name_size: DWORD, volume_serial_number: LPDWORD, @@ -416,7 +416,7 @@ 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>( +pub extern "system" fn mounted<'c, 'h: 'c, FSH: FileSystemHandler<'c, 'h> + 'h>( mount_point: LPCWSTR, dokan_file_info: PDOKAN_FILE_INFO, ) -> NTSTATUS { @@ -427,7 +427,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,7 +436,7 @@ 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>( +pub extern "system" fn get_file_security<'c, 'h: 'c, FSH: FileSystemHandler<'c, 'h> + 'h>( file_name: LPCWSTR, security_information: PSECURITY_INFORMATION, security_descriptor: PSECURITY_DESCRIPTOR, @@ -467,7 +467,7 @@ 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>( +pub extern "system" fn set_file_security<'c, 'h: 'c, FSH: FileSystemHandler<'c, 'h> + 'h>( file_name: LPCWSTR, security_information: PSECURITY_INFORMATION, security_descriptor: PSECURITY_DESCRIPTOR, @@ -488,7 +488,7 @@ 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>( +pub extern "system" fn find_streams<'c, 'h: 'c, FSH: FileSystemHandler<'c, 'h> + 'h>( file_name: LPCWSTR, fill_find_stream_data: PFillFindStreamData, find_stream_context: PVOID, diff --git a/dokan/src/usage_tests.rs b/dokan/src/usage_tests.rs index 1876456..4af41c5 100644 --- a/dokan/src/usage_tests.rs +++ b/dokan/src/usage_tests.rs @@ -1468,13 +1468,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"); + } } }); } From 396fd7762bf5be5c2152ca5f523b4cc8c6cfe97f Mon Sep 17 00:00:00 2001 From: Jon-Luke Biddle Date: Tue, 31 Mar 2026 18:27:22 -0600 Subject: [PATCH 02/13] add .lock file to .gitignore --- .gitignore | 1 + Cargo.lock | 385 ----------------------------------------------------- 2 files changed, 1 insertion(+), 385 deletions(-) delete mode 100644 Cargo.lock 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 88149e6..0000000 --- a/Cargo.lock +++ /dev/null @@ -1,385 +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.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ddd31a130427c27518df266943a5308ed92d4b226cc639f5a8f1002816174301" -dependencies = [ - "memchr", -] - -[[package]] -name = "anstream" -version = "1.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "824a212faf96e9acacdbd09febd34438f8f711fb84e09a8916013cd7815ca28d" -dependencies = [ - "anstyle", - "anstyle-parse", - "anstyle-query", - "anstyle-wincon", - "colorchoice", - "is_terminal_polyfill", - "utf8parse", -] - -[[package]] -name = "anstyle" -version = "1.0.14" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "940b3a0ca603d1eade50a4846a2afffd5ef57a9feac2c0e2ec2e14f9ead76000" - -[[package]] -name = "anstyle-parse" -version = "1.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "52ce7f38b242319f7cabaa6813055467063ecdc9d355bbb4ce0c68908cd8130e" -dependencies = [ - "utf8parse", -] - -[[package]] -name = "anstyle-query" -version = "1.1.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "40c48f72fd53cd289104fc64099abca73db4166ad86ea0b4341abe65af83dadc" -dependencies = [ - "windows-sys", -] - -[[package]] -name = "anstyle-wincon" -version = "3.0.11" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "291e6a250ff86cd4a820112fb8898808a366d8f9f58ce16d1f538353ad55747d" -dependencies = [ - "anstyle", - "once_cell_polyfill", - "windows-sys", -] - -[[package]] -name = "bitflags" -version = "2.11.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "843867be96c8daad0d758b57df9392b6d8d271134fce549de6ce169ff98a92af" - -[[package]] -name = "block2" -version = "0.6.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cdeb9d870516001442e364c5220d3574d2da8dc765554b4a617230d33fa58ef5" -dependencies = [ - "objc2", -] - -[[package]] -name = "cc" -version = "1.2.58" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e1e928d4b69e3077709075a938a05ffbedfa53a84c8f766efbf8220bb1ff60e1" -dependencies = [ - "find-msvc-tools", - "shlex", -] - -[[package]] -name = "cfg-if" -version = "1.0.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9330f8b2ff13f34540b44e946ef35111825727b38d33286ef986142615121801" - -[[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.6.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b193af5b67834b676abd72466a96c1024e6a6ad978a1f484bd90b85c94041351" -dependencies = [ - "clap_builder", -] - -[[package]] -name = "clap_builder" -version = "4.6.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "714a53001bf66416adb0e2ef5ac857140e7dc3a0c48fb28b2f10762fc4b5069f" -dependencies = [ - "anstream", - "anstyle", - "clap_lex", - "strsim", -] - -[[package]] -name = "clap_lex" -version = "1.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c8d4a3bb8b1e0c1050499d1815f5ab16d04f0959b233085fb31653fbfc9d98f9" - -[[package]] -name = "colorchoice" -version = "1.0.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1d07550c9036bf2ae0c684c4297d503f838287c83c53686d05370d0e139ae570" - -[[package]] -name = "ctrlc" -version = "3.5.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e0b1fab2ae45819af2d0731d60f2afe17227ebb1a1538a236da84c93e9a60162" -dependencies = [ - "dispatch2", - "nix", - "windows-sys", -] - -[[package]] -name = "dispatch2" -version = "0.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1e0e367e4e7da84520dedcac1901e4da967309406d1e51017ae1abfb97adbd38" -dependencies = [ - "bitflags", - "block2", - "libc", - "objc2", -] - -[[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 = "find-msvc-tools" -version = "0.1.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5baebc0774151f905a1a2cc41989300b1e6fbb29aff0ceffa1064fdd3088d582" - -[[package]] -name = "is_terminal_polyfill" -version = "1.70.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a6cb138bb79a146c1bd460005623e142ef0181e3d0219cb493e02f7d08a35695" - -[[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.183" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b5b646652bf6661599e1da8901b3b9522896f01e736bad5f723fe7a3a27f899d" - -[[package]] -name = "lock_api" -version = "0.4.14" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "224399e74b87b5f3557511d98dff8b14089b3dadafcab6bb93eab67d3aace965" -dependencies = [ - "scopeguard", -] - -[[package]] -name = "memchr" -version = "2.8.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f8ca58f447f06ed17d5fc4043ce1b10dd205e060fb3ce5b979b8ed8e59ff3f79" - -[[package]] -name = "nix" -version = "0.31.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5d6d0705320c1e6ba1d912b5e37cf18071b6c2e9b7fa8215a1e8a7651966f5d3" -dependencies = [ - "bitflags", - "cfg-if", - "cfg_aliases", - "libc", -] - -[[package]] -name = "objc2" -version = "0.6.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3a12a8ed07aefc768292f076dc3ac8c48f3781c8f2d5851dd3d98950e8c5a89f" -dependencies = [ - "objc2-encode", -] - -[[package]] -name = "objc2-encode" -version = "4.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ef25abbcd74fb2609453eb695bd2f860d389e457f67dc17cafc8b8cbc89d0c33" - -[[package]] -name = "once_cell_polyfill" -version = "1.70.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "384b8ab6d37215f3c5301a95a4accb5d64aa607f1fcb26a11b5303878451b4fe" - -[[package]] -name = "parking_lot" -version = "0.12.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "93857453250e3077bd71ff98b6a65ea6621a19bb0f559a85248955ac12c45a1a" -dependencies = [ - "lock_api", - "parking_lot_core", -] - -[[package]] -name = "parking_lot_core" -version = "0.9.12" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2621685985a2ebf1c516881c026032ac7deafcda1a2c9b7850dc81e3dfcb64c1" -dependencies = [ - "cfg-if", - "libc", - "redox_syscall", - "smallvec", - "windows-link", -] - -[[package]] -name = "redox_syscall" -version = "0.5.18" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ed2bf2547551a7053d6fdfafda3f938979645c44812fbfcda098faae3f1a362d" -dependencies = [ - "bitflags", -] - -[[package]] -name = "regex" -version = "1.12.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e10754a14b9137dd7b1e3e5b0493cc9171fdd105e0ab477f51b72e7f3ac0e276" -dependencies = [ - "aho-corasick", - "memchr", - "regex-automata", - "regex-syntax", -] - -[[package]] -name = "regex-automata" -version = "0.4.14" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6e1dd4122fc1595e8162618945476892eefca7b88c52820e74af6262213cae8f" -dependencies = [ - "aho-corasick", - "memchr", - "regex-syntax", -] - -[[package]] -name = "regex-syntax" -version = "0.8.10" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dc897dd8d9e8bd1ed8cdad82b5966c3e0ecae09fb1907d58efaa013543185d0a" - -[[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.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "67b1b7a3b5fe4f1376887184045fcf45c69e92af734b7aaddc05fb777b6fbd03" - -[[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.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "72069c3113ab32ab29e5584db3c6ec55d416895e60715417b5b883a357c3e471" - -[[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-link" -version = "0.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f0805222e57f7521d6a62e36fa9163bc891acd422f971defe97d64e70d0a4fe5" - -[[package]] -name = "windows-sys" -version = "0.61.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ae137229bcbd6cdf0f7b80a31df61766145077ddf49416a728b02cb3921ff3fc" -dependencies = [ - "windows-link", -] From 43a4a995d284b62afd2e5dc19deb673bb5418c96 Mon Sep 17 00:00:00 2001 From: Jon-Luke Biddle Date: Tue, 31 Mar 2026 19:22:06 -0600 Subject: [PATCH 03/13] upgrade dependencies --- dokan-sys/Cargo.toml | 3 +- dokan-sys/src/lib.rs | 131 +++++++++------- dokan-sys/src/win32.rs | 9 +- dokan/Cargo.toml | 17 +- dokan/examples/memfs/main.rs | 166 ++++++++++++-------- dokan/examples/memfs/path.rs | 4 +- dokan/examples/memfs/security.rs | 218 +++++++++++++------------- dokan/src/data/file_info.rs | 2 +- dokan/src/data/file_time_operation.rs | 2 +- dokan/src/data/fill_data.rs | 7 +- dokan/src/data/find_data.rs | 18 +-- dokan/src/data/mount_point.rs | 4 +- dokan/src/data/operation_info.rs | 6 +- dokan/src/file_system.rs | 23 +-- dokan/src/file_system_handler.rs | 11 +- dokan/src/lib.rs | 26 ++- dokan/src/notify.rs | 2 +- dokan/src/operations.rs | 79 +++++----- dokan/src/operations_helpers.rs | 5 +- dokan/src/to_file_time.rs | 2 +- dokan/src/usage_tests.rs | 103 ++++++------ 21 files changed, 440 insertions(+), 398 deletions(-) diff --git a/dokan-sys/Cargo.toml b/dokan-sys/Cargo.toml index fb1dedd..b30c03b 100644 --- a/dokan-sys/Cargo.toml +++ b/dokan-sys/Cargo.toml @@ -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 7a48f26..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, @@ -126,7 +140,7 @@ pub type PDOKAN_IO_SECURITY_CONTEXT = *mut DOKAN_IO_SECURITY_CONTEXT; pub struct DOKAN_OPERATIONS { pub ZwCreateFile: Option< extern "system" fn( - FileName: LPCWSTR, + 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 "system" fn( - FileName: LPCWSTR, + FileName: PCWSTR, Buffer: LPVOID, BufferLength: DWORD, ReadLength: LPDWORD, @@ -150,7 +164,7 @@ pub struct DOKAN_OPERATIONS { >, pub WriteFile: Option< extern "system" fn( - FileName: LPCWSTR, + 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 "system" fn( - FileName: LPCWSTR, + FileName: PCWSTR, Buffer: LPBY_HANDLE_FILE_INFORMATION, DokanFileInfo: PDOKAN_FILE_INFO, ) -> NTSTATUS, >, pub FindFiles: Option< extern "system" fn( - FileName: LPCWSTR, + FileName: PCWSTR, FillFindData: PFillFindData, DokanFileInfo: PDOKAN_FILE_INFO, ) -> NTSTATUS, >, pub FindFilesWithPattern: Option< extern "system" fn( - PathName: LPCWSTR, - SearchPattern: LPCWSTR, + PathName: PCWSTR, + SearchPattern: PCWSTR, FillFindData: PFillFindData, DokanFileInfo: PDOKAN_FILE_INFO, ) -> NTSTATUS, >, pub SetFileAttributes: Option< extern "system" fn( - FileName: LPCWSTR, + FileName: PCWSTR, FileAttributes: DWORD, DokanFileInfo: PDOKAN_FILE_INFO, ) -> NTSTATUS, >, pub SetFileTime: Option< extern "system" fn( - FileName: LPCWSTR, + FileName: PCWSTR, creation_time: *const FILETIME, last_access_time: *const FILETIME, last_write_time: *const FILETIME, @@ -199,34 +213,34 @@ pub struct DOKAN_OPERATIONS { ) -> NTSTATUS, >, pub DeleteFile: - Option NTSTATUS>, + Option NTSTATUS>, pub DeleteDirectory: - Option NTSTATUS>, + Option NTSTATUS>, pub MoveFile: Option< extern "system" fn( - FileName: LPCWSTR, - NewFileName: LPCWSTR, + FileName: PCWSTR, + NewFileName: PCWSTR, ReplaceIfExisting: BOOL, DokanFileInfo: PDOKAN_FILE_INFO, ) -> NTSTATUS, >, pub SetEndOfFile: Option< extern "system" fn( - FileName: LPCWSTR, + FileName: PCWSTR, ByteOffset: LONGLONG, DokanFileInfo: PDOKAN_FILE_INFO, ) -> NTSTATUS, >, pub SetAllocationSize: Option< extern "system" fn( - FileName: LPCWSTR, + FileName: PCWSTR, AllocSize: LONGLONG, DokanFileInfo: PDOKAN_FILE_INFO, ) -> NTSTATUS, >, pub LockFile: Option< extern "system" fn( - FileName: LPCWSTR, + FileName: PCWSTR, ByteOffset: LONGLONG, Length: LONGLONG, DokanFileInfo: PDOKAN_FILE_INFO, @@ -234,7 +248,7 @@ pub struct DOKAN_OPERATIONS { >, pub UnlockFile: Option< extern "system" fn( - FileName: LPCWSTR, + FileName: PCWSTR, ByteOffset: LONGLONG, Length: LONGLONG, DokanFileInfo: PDOKAN_FILE_INFO, @@ -250,23 +264,22 @@ pub struct DOKAN_OPERATIONS { >, pub GetVolumeInformation: Option< extern "system" fn( - VolumeNameBuffer: LPWSTR, + 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 "system" fn(MountPoint: LPCWSTR, DokanFileInfo: PDOKAN_FILE_INFO) -> NTSTATUS, - >, + pub Mounted: + Option NTSTATUS>, pub Unmounted: Option NTSTATUS>, pub GetFileSecurity: Option< extern "system" fn( - FileName: LPCWSTR, + FileName: PCWSTR, PSECURITY_INFORMATION: PSECURITY_INFORMATION, PSECURITY_DESCRIPTOR: PSECURITY_DESCRIPTOR, BufferLength: ULONG, @@ -276,7 +289,7 @@ pub struct DOKAN_OPERATIONS { >, pub SetFileSecurity: Option< extern "system" fn( - FileName: LPCWSTR, + FileName: PCWSTR, SecurityInformation: PSECURITY_INFORMATION, SecurityDescriptor: PSECURITY_DESCRIPTOR, BufferLength: ULONG, @@ -285,7 +298,7 @@ pub struct DOKAN_OPERATIONS { >, pub FindStreams: Option< extern "system" fn( - FileName: LPCWSTR, + 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, @@ -333,7 +346,7 @@ unsafe extern "system" { pub fn DokanRegisterWaitForFileSystemClosed( DokanInstance: DOKAN_HANDLE, WaitHandle: PHANDLE, - Callback: WAITORTIMERCALLBACKFUNC, + Callback: WAITORTIMERCALLBACK, Context: PVOID, dwMilliseconds: ULONG, ) -> BOOL; @@ -343,8 +356,8 @@ unsafe extern "system" { ) -> 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 @@ unsafe extern "system" { ); 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 702931b..8ce203d 100644 --- a/dokan/Cargo.toml +++ b/dokan/Cargo.toml @@ -16,16 +16,25 @@ edition = "2024" 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 f7e9463..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(), @@ -760,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); @@ -887,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(); @@ -1003,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); @@ -1071,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) @@ -1090,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 { @@ -1100,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(); @@ -1197,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(), }) @@ -1223,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, @@ -1241,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 c9ad4a7..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 { @@ -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,11 +129,7 @@ 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(()) } } } 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..4d86b82 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)] 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 5772dd0..5dd2c69 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 "system" fn create_file<'c, 'h: 'c, FSH: FileSystemHandler<'c, 'h> + 'h>( - file_name: LPCWSTR, + file_name: PCWSTR, security_context: PDOKAN_IO_SECURITY_CONTEXT, desired_access: ACCESS_MASK, file_attributes: ULONG, @@ -65,7 +64,7 @@ pub extern "system" fn create_file<'c, 'h: 'c, FSH: FileSystemHandler<'c, 'h> + } pub extern "system" fn cleanup<'c, 'h: 'c, FSH: FileSystemHandler<'c, 'h> + 'h>( - file_name: LPCWSTR, + file_name: PCWSTR, dokan_file_info: PDOKAN_FILE_INFO, ) { wrap_unit(|| unsafe { @@ -76,7 +75,7 @@ pub extern "system" fn cleanup<'c, 'h: 'c, FSH: FileSystemHandler<'c, 'h> + 'h>( } pub extern "system" fn close_file<'c, 'h: 'c, FSH: FileSystemHandler<'c, 'h> + 'h>( - file_name: LPCWSTR, + file_name: PCWSTR, dokan_file_info: PDOKAN_FILE_INFO, ) { wrap_unit(|| unsafe { @@ -88,7 +87,7 @@ pub extern "system" fn close_file<'c, 'h: 'c, FSH: FileSystemHandler<'c, 'h> + ' } pub extern "system" fn read_file<'c, 'h: 'c, FSH: FileSystemHandler<'c, 'h> + 'h>( - file_name: LPCWSTR, + file_name: PCWSTR, buffer: LPVOID, buffer_length: DWORD, read_length: LPDWORD, @@ -109,7 +108,7 @@ pub extern "system" fn read_file<'c, 'h: 'c, FSH: FileSystemHandler<'c, 'h> + 'h } pub extern "system" fn write_file<'c, 'h: 'c, FSH: FileSystemHandler<'c, 'h> + 'h>( - file_name: LPCWSTR, + file_name: PCWSTR, buffer: LPCVOID, number_of_bytes_to_write: DWORD, number_of_bytes_written: LPDWORD, @@ -130,7 +129,7 @@ pub extern "system" fn write_file<'c, 'h: 'c, FSH: FileSystemHandler<'c, 'h> + ' } pub extern "system" fn flush_file_buffers<'c, 'h: 'c, FSH: FileSystemHandler<'c, 'h> + 'h>( - file_name: LPCWSTR, + file_name: PCWSTR, dokan_file_info: PDOKAN_FILE_INFO, ) -> NTSTATUS { wrap_nt_result(|| unsafe { @@ -142,7 +141,7 @@ pub extern "system" fn flush_file_buffers<'c, 'h: 'c, FSH: FileSystemHandler<'c, } pub extern "system" fn get_file_information<'c, 'h: 'c, FSH: FileSystemHandler<'c, 'h> + 'h>( - file_name: LPCWSTR, + file_name: PCWSTR, buffer: LPBY_HANDLE_FILE_INFORMATION, dokan_file_info: PDOKAN_FILE_INFO, ) -> NTSTATUS { @@ -158,7 +157,7 @@ pub extern "system" fn get_file_information<'c, 'h: 'c, FSH: FileSystemHandler<' } pub extern "system" fn find_files<'c, 'h: 'c, FSH: FileSystemHandler<'c, 'h> + 'h>( - file_name: LPCWSTR, + file_name: PCWSTR, fill_find_data: PFillFindData, dokan_file_info: PDOKAN_FILE_INFO, ) -> NTSTATUS { @@ -172,8 +171,8 @@ pub extern "system" fn find_files<'c, 'h: 'c, FSH: FileSystemHandler<'c, 'h> + ' } pub extern "system" fn find_files_with_pattern<'c, 'h: 'c, FSH: FileSystemHandler<'c, 'h> + 'h>( - file_name: LPCWSTR, - search_pattern: LPCWSTR, + file_name: PCWSTR, + search_pattern: PCWSTR, fill_find_data: PFillFindData, dokan_file_info: PDOKAN_FILE_INFO, ) -> NTSTATUS { @@ -193,7 +192,7 @@ pub extern "system" fn find_files_with_pattern<'c, 'h: 'c, FSH: FileSystemHandle } pub extern "system" fn set_file_attributes<'c, 'h: 'c, FSH: FileSystemHandler<'c, 'h> + 'h>( - file_name: LPCWSTR, + file_name: PCWSTR, file_attributes: DWORD, dokan_file_info: PDOKAN_FILE_INFO, ) -> NTSTATUS { @@ -206,7 +205,7 @@ pub extern "system" fn set_file_attributes<'c, 'h: 'c, FSH: FileSystemHandler<'c } pub extern "system" fn set_file_time<'c, 'h: 'c, FSH: FileSystemHandler<'c, 'h> + 'h>( - file_name: LPCWSTR, + file_name: PCWSTR, creation_time: *const FILETIME, last_access_time: *const FILETIME, last_write_time: *const FILETIME, @@ -227,7 +226,7 @@ pub extern "system" fn set_file_time<'c, 'h: 'c, FSH: FileSystemHandler<'c, 'h> } pub extern "system" fn delete_file<'c, 'h: 'c, FSH: FileSystemHandler<'c, 'h> + 'h>( - file_name: LPCWSTR, + file_name: PCWSTR, dokan_file_info: PDOKAN_FILE_INFO, ) -> NTSTATUS { wrap_nt_result(|| unsafe { @@ -238,7 +237,7 @@ pub extern "system" fn delete_file<'c, 'h: 'c, FSH: FileSystemHandler<'c, 'h> + } pub extern "system" fn delete_directory<'c, 'h: 'c, FSH: FileSystemHandler<'c, 'h> + 'h>( - file_name: LPCWSTR, + file_name: PCWSTR, dokan_file_info: PDOKAN_FILE_INFO, ) -> NTSTATUS { wrap_nt_result(|| unsafe { @@ -250,8 +249,8 @@ pub extern "system" fn delete_directory<'c, 'h: 'c, FSH: FileSystemHandler<'c, ' } pub extern "system" fn move_file<'c, 'h: 'c, FSH: FileSystemHandler<'c, 'h> + 'h>( - file_name: LPCWSTR, - new_file_name: LPCWSTR, + file_name: PCWSTR, + new_file_name: PCWSTR, replace_if_existing: BOOL, dokan_file_info: PDOKAN_FILE_INFO, ) -> NTSTATUS { @@ -270,7 +269,7 @@ pub extern "system" fn move_file<'c, 'h: 'c, FSH: FileSystemHandler<'c, 'h> + 'h } pub extern "system" fn set_end_of_file<'c, 'h: 'c, FSH: FileSystemHandler<'c, 'h> + 'h>( - file_name: LPCWSTR, + file_name: PCWSTR, byte_offset: LONGLONG, dokan_file_info: PDOKAN_FILE_INFO, ) -> NTSTATUS { @@ -283,7 +282,7 @@ pub extern "system" fn set_end_of_file<'c, 'h: 'c, FSH: FileSystemHandler<'c, 'h } pub extern "system" fn set_allocation_size<'c, 'h: 'c, FSH: FileSystemHandler<'c, 'h> + 'h>( - file_name: LPCWSTR, + file_name: PCWSTR, alloc_size: LONGLONG, dokan_file_info: PDOKAN_FILE_INFO, ) -> NTSTATUS { @@ -299,7 +298,7 @@ pub extern "system" fn set_allocation_size<'c, 'h: 'c, FSH: FileSystemHandler<'c // 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, @@ -327,7 +326,7 @@ fn lock_unlock_file<'c, 'h: 'c, FSH: FileSystemHandler<'c, 'h> + 'h>( } pub extern "system" fn lock_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, @@ -342,7 +341,7 @@ pub extern "system" fn lock_file<'c, 'h: 'c, FSH: FileSystemHandler<'c, 'h> + 'h } pub extern "system" fn 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, @@ -381,12 +380,12 @@ pub extern "system" fn get_disk_free_space<'c, 'h: 'c, FSH: FileSystemHandler<'c } pub extern "system" fn get_volume_information<'c, 'h: 'c, FSH: FileSystemHandler<'c, 'h> + 'h>( - volume_name_buffer: LPWSTR, + 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 { @@ -417,7 +416,7 @@ pub extern "system" fn get_volume_information<'c, 'h: 'c, FSH: FileSystemHandler } pub extern "system" fn mounted<'c, 'h: 'c, FSH: FileSystemHandler<'c, 'h> + 'h>( - mount_point: LPCWSTR, + mount_point: PCWSTR, dokan_file_info: PDOKAN_FILE_INFO, ) -> NTSTATUS { wrap_nt_result(|| unsafe { @@ -437,7 +436,7 @@ pub extern "system" fn unmounted<'c, 'h: 'c, FSH: FileSystemHandler<'c, 'h> + 'h } pub extern "system" fn get_file_security<'c, 'h: 'c, FSH: FileSystemHandler<'c, 'h> + 'h>( - file_name: LPCWSTR, + file_name: PCWSTR, security_information: PSECURITY_INFORMATION, security_descriptor: PSECURITY_DESCRIPTOR, buffer_length: ULONG, @@ -468,7 +467,7 @@ pub extern "system" fn get_file_security<'c, 'h: 'c, FSH: FileSystemHandler<'c, } pub extern "system" fn set_file_security<'c, 'h: 'c, FSH: FileSystemHandler<'c, 'h> + 'h>( - file_name: LPCWSTR, + file_name: PCWSTR, security_information: PSECURITY_INFORMATION, security_descriptor: PSECURITY_DESCRIPTOR, buffer_length: ULONG, @@ -489,7 +488,7 @@ pub extern "system" fn set_file_security<'c, 'h: 'c, FSH: FileSystemHandler<'c, } pub extern "system" fn find_streams<'c, 'h: 'c, FSH: FileSystemHandler<'c, 'h> + 'h>( - file_name: LPCWSTR, + 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 4af41c5..2e3e5e2 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, @@ -882,7 +896,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(); init(); @@ -951,8 +965,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 +1013,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 +1080,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 +1094,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); @@ -1432,7 +1440,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") @@ -1566,7 +1574,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), From 8a309daaa1df4be9d008e7290b03b28f4f9cb0ca Mon Sep 17 00:00:00 2001 From: Jon-Luke Biddle Date: Tue, 31 Mar 2026 19:23:47 -0600 Subject: [PATCH 04/13] ci build --- .github/workflows/build.yml | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) create mode 100644 .github/workflows/build.yml diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml new file mode 100644 index 0000000..2507171 --- /dev/null +++ b/.github/workflows/build.yml @@ -0,0 +1,23 @@ +name: Build + +on: + push: + branches: [master] + pull_request: + branches: [master] + +jobs: + build: + runs-on: windows-latest + steps: + - uses: actions/checkout@v4 + with: + submodules: recursive + + - uses: dtolnay/rust-toolchain@stable + + - name: Build + run: cargo check --examples --tests + + - name: Test + run: cargo test From 5040782da4c6e9a49586b6e343a1a4682157cdc0 Mon Sep 17 00:00:00 2001 From: Jon-Luke Biddle Date: Tue, 31 Mar 2026 19:29:17 -0600 Subject: [PATCH 05/13] fix mutex poison --- dokan/src/usage_tests.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dokan/src/usage_tests.rs b/dokan/src/usage_tests.rs index 2e3e5e2..e8b8c68 100644 --- a/dokan/src/usage_tests.rs +++ b/dokan/src/usage_tests.rs @@ -896,7 +896,7 @@ pub fn test_flags() -> MountFlags { #[allow(unused_must_use)] pub fn with_test_drive(scope: Scope) { - let _guard = TEST_DRIVE_LOCK.lock().unwrap(); + let _guard = TEST_DRIVE_LOCK.lock().unwrap_or_else(|e| e.into_inner()); init(); From 354bf6aeea485022ef52383ce479d724c902fadd Mon Sep 17 00:00:00 2001 From: Jon-Luke Biddle Date: Tue, 31 Mar 2026 19:29:40 -0600 Subject: [PATCH 06/13] install dokan driver through winget --- .github/workflows/build.yml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 2507171..21011d0 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -14,6 +14,9 @@ jobs: 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 From a50b74ac67ec4ae87108c7986f3bdd2971163e88 Mon Sep 17 00:00:00 2001 From: Jon-Luke Biddle Date: Tue, 31 Mar 2026 19:37:37 -0600 Subject: [PATCH 07/13] fix undefined behavior leading to panic --- dokan/src/data/operation_info.rs | 13 ++++++++++++- dokan/src/operations.rs | 8 ++++++-- 2 files changed, 18 insertions(+), 3 deletions(-) diff --git a/dokan/src/data/operation_info.rs b/dokan/src/data/operation_info.rs index 4d86b82..714b845 100644 --- a/dokan/src/data/operation_info.rs +++ b/dokan/src/data/operation_info.rs @@ -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/operations.rs b/dokan/src/operations.rs index 5dd2c69..700f382 100644 --- a/dokan/src/operations.rs +++ b/dokan/src/operations.rs @@ -70,7 +70,9 @@ pub extern "system" fn cleanup<'c, 'h: 'c, FSH: FileSystemHandler<'c, 'h> + 'h>( 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); + } }); } @@ -81,7 +83,9 @@ pub extern "system" fn close_file<'c, 'h: 'c, FSH: FileSystemHandler<'c, 'h> + ' 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(); }); } From cac725c6636cea8860ea2b05454af7421f13cff8 Mon Sep 17 00:00:00 2001 From: Jon-Luke Biddle Date: Tue, 31 Mar 2026 19:44:02 -0600 Subject: [PATCH 08/13] handle tests on windows server --- dokan/src/usage_tests.rs | 21 +++++++++++++++++++-- 1 file changed, 19 insertions(+), 2 deletions(-) diff --git a/dokan/src/usage_tests.rs b/dokan/src/usage_tests.rs index e8b8c68..f6abc9b 100644 --- a/dokan/src/usage_tests.rs +++ b/dokan/src/usage_tests.rs @@ -872,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 @@ -1362,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]; @@ -1378,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); From 9d8caf1ff6aa5a781ab4b9b1d576de8ede2e5076 Mon Sep 17 00:00:00 2001 From: Jon-Luke Biddle Date: Fri, 3 Apr 2026 18:48:08 -0600 Subject: [PATCH 09/13] fix: resolve CI failures on Windows Server - Replace hardcoded sleep with synchronous mount point polling using list_mount_points() to wait for the previous unmount to complete before mounting again, preventing a race condition. - Remove check_pid from metadata-only handlers (get_file_information, find_files, find_streams) so system services probing the volume get valid responses instead of ACCESS_DENIED retry loops. - Keep check_pid in signal-sending handlers (read_file, write_file, flush_file_buffers, etc.) to prevent cache manager paging I/O from polluting the test signal channel. --- dokan/src/usage_tests.rs | 28 ++++++++++++++++++++++------ 1 file changed, 22 insertions(+), 6 deletions(-) diff --git a/dokan/src/usage_tests.rs b/dokan/src/usage_tests.rs index f6abc9b..d3eb303 100644 --- a/dokan/src/usage_tests.rs +++ b/dokan/src/usage_tests.rs @@ -65,7 +65,7 @@ use crate::{ MountOptions, data::{ CreateFileInfo, DiskSpaceInfo, FileInfo, FileTimeOperation, FillDataResult, FindData, - FindStreamData, OperationInfo, VolumeInfo, + FindStreamData, OperationInfo, VolumeInfo, list_mount_points, }, file_system_handler::OperationResult, init, notify_create, notify_delete, notify_rename, notify_update, notify_xattr_update, @@ -481,7 +481,6 @@ impl<'a, 'b: 'a> FileSystemHandler<'a, 'b> for TestHandler { info: &OperationInfo<'a, 'b, Self>, _context: &'a Self::Context, ) -> OperationResult { - check_pid(info.pid())?; Ok(FileInfo { attributes: if info.is_dir() { FILE_ATTRIBUTE_DIRECTORY @@ -501,10 +500,9 @@ impl<'a, 'b: 'a> FileSystemHandler<'a, 'b> for TestHandler { &'b self, file_name: &U16CStr, mut fill_find_data: impl FnMut(&FindData) -> FillDataResult, - info: &OperationInfo<'a, 'b, Self>, + _info: &OperationInfo<'a, 'b, Self>, _context: &'a Self::Context, ) -> OperationResult<()> { - check_pid(info.pid())?; let file_name = file_name.to_string_lossy(); match file_name.as_ref() { "\\test_find_files" => fill_find_data(&FindData { @@ -841,10 +839,9 @@ impl<'a, 'b: 'a> FileSystemHandler<'a, 'b> for TestHandler { &'b self, file_name: &U16CStr, mut fill_find_stream_data: impl FnMut(&FindStreamData) -> FillDataResult, - info: &OperationInfo<'a, 'b, Self>, + _info: &OperationInfo<'a, 'b, Self>, _context: &'a Self::Context, ) -> OperationResult<()> { - check_pid(info.pid())?; let file_name = file_name.to_string_lossy(); if &file_name == "\\test_find_streams" { fill_find_stream_data(&FindStreamData { @@ -916,6 +913,25 @@ pub fn with_test_drive(scope: Scope) { // In case previous tests failed and didn't unmount the drive. unmount(convert_str("Z:\\")); + // DokanRemoveMountPoint is asynchronous — wait until Z:\ is no longer in the + // active mount point list before mounting again. Without this, on Windows Server + // a pending release can race with the next mount and tear it down immediately. + let deadline = std::time::Instant::now() + Duration::from_secs(5); + while std::time::Instant::now() < deadline { + let z_mounted = list_mount_points(false) + .map(|list| { + (&list).into_iter().any(|mp| { + mp.mount_point + .is_some_and(|p| p.to_string_lossy().contains("Z:")) + }) + }) + .unwrap_or(false); + if !z_mounted { + break; + } + thread::sleep(Duration::from_millis(50)); + } + let (tx_instance, rx_instance) = mpsc::sync_channel(1); let (tx_signal, rx_signal) = mpsc::sync_channel(1024); From 975970508ccf8d20463c51410113a7ab0524719e Mon Sep 17 00:00:00 2001 From: Jon-Luke Biddle Date: Fri, 3 Apr 2026 18:51:36 -0600 Subject: [PATCH 10/13] fix: resolve all clippy warnings and errors - Replace tabs with spaces in doc comments (tabs_in_doc_comments) - Use ptr::read_unaligned instead of transmute_copy with raw pointer dereference in FileTimeOperation::from (not_unsafe_ptr_arg_deref) - Remove useless transmute of i64 to i64 in FindStreamData (useless_transmute) - Extract LockUnlockFn type alias to reduce type complexity (type_complexity) --- dokan/src/data/file_time_operation.rs | 4 ++-- dokan/src/data/find_data.rs | 4 ++-- dokan/src/lib.rs | 18 +++++++++--------- dokan/src/operations.rs | 18 ++++++++++-------- 4 files changed, 23 insertions(+), 21 deletions(-) diff --git a/dokan/src/data/file_time_operation.rs b/dokan/src/data/file_time_operation.rs index 2cf2b00..11ea9c3 100644 --- a/dokan/src/data/file_time_operation.rs +++ b/dokan/src/data/file_time_operation.rs @@ -1,5 +1,5 @@ use std::{ - mem::transmute_copy, + ptr, time::{Duration, SystemTime, UNIX_EPOCH}, }; @@ -23,7 +23,7 @@ pub enum FileTimeOperation { impl From<*const FILETIME> for FileTimeOperation { fn from(time: *const FILETIME) -> Self { unsafe { - let time_val = transmute_copy::<_, i64>(&*time); + let time_val = ptr::read_unaligned(time as *const i64); match time_val { 0 => FileTimeOperation::DontChange, -1 => FileTimeOperation::DisableUpdate, diff --git a/dokan/src/data/find_data.rs b/dokan/src/data/find_data.rs index 4ff311b..c3be2c9 100644 --- a/dokan/src/data/find_data.rs +++ b/dokan/src/data/find_data.rs @@ -1,4 +1,4 @@ -use std::{mem::transmute, time::SystemTime}; +use std::time::SystemTime; use dokan_sys::win32::WIN32_FIND_STREAM_DATA; use widestring::U16CString; @@ -90,7 +90,7 @@ impl ToRawStruct for FindStreamData { let mut c_stream_name = [0; MAX_STREAM_NAME]; c_stream_name[..name_slice.len()].copy_from_slice(name_slice); Some(WIN32_FIND_STREAM_DATA { - StreamSize: unsafe { transmute(self.size) }, + StreamSize: self.size, cStreamName: c_stream_name, }) } else { diff --git a/dokan/src/lib.rs b/dokan/src/lib.rs index 3f5662c..fca4c50 100644 --- a/dokan/src/lib.rs +++ b/dokan/src/lib.rs @@ -180,17 +180,17 @@ fn can_map_win32_error_to_ntstatus() { /// # use windows_sys::Win32::{Foundation::NTSTATUS, System::Environment::GetCurrentDirectoryW}; /// # /// fn get_current_directory() -> Result { -/// unsafe { -/// let len = GetCurrentDirectoryW(0, ptr::null_mut()); -/// win32_ensure(len != 0)?; +/// unsafe { +/// let len = GetCurrentDirectoryW(0, ptr::null_mut()); +/// win32_ensure(len != 0)?; /// -/// let mut buffer = Vec::with_capacity(len as usize); -/// let actual_len = GetCurrentDirectoryW(len, buffer.as_mut_ptr()); -/// win32_ensure(actual_len != 0)?; -/// assert_eq!(actual_len, len); +/// let mut buffer = Vec::with_capacity(len as usize); +/// let actual_len = GetCurrentDirectoryW(len, buffer.as_mut_ptr()); +/// win32_ensure(actual_len != 0)?; +/// assert_eq!(actual_len, len); /// -/// Ok(U16CString::from_vec_unchecked(buffer)) -/// } +/// Ok(U16CString::from_vec_unchecked(buffer)) +/// } /// } /// ``` pub fn win32_ensure(condition: bool) -> Result<(), NTSTATUS> { diff --git a/dokan/src/operations.rs b/dokan/src/operations.rs index 700f382..6131bfd 100644 --- a/dokan/src/operations.rs +++ b/dokan/src/operations.rs @@ -301,19 +301,21 @@ pub extern "system" fn set_allocation_size<'c, 'h: 'c, FSH: FileSystemHandler<'c // Extern stdcall functions with similar bodies but not called directly with trigger a compiler bug when built in // 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 +type LockUnlockFn<'c, 'h, FSH> = fn( + &'h FSH, + &U16CStr, + i64, + i64, + &OperationInfo<'c, 'h, FSH>, + &'c >::Context, +) -> NtResult; + fn lock_unlock_file<'c, 'h: 'c, FSH: FileSystemHandler<'c, 'h> + 'h>( file_name: PCWSTR, byte_offset: LONGLONG, length: LONGLONG, dokan_file_info: PDOKAN_FILE_INFO, - func: fn( - &'h FSH, - &U16CStr, - i64, - i64, - &OperationInfo<'c, 'h, FSH>, - &'c FSH::Context, - ) -> NtResult, + func: LockUnlockFn<'c, 'h, FSH>, ) -> NTSTATUS { wrap_nt_result(|| unsafe { let file_name = U16CStr::from_ptr_str(file_name); From c6d3199b8549a1554bd1652ef234467e1c89b029 Mon Sep 17 00:00:00 2001 From: Jon-Luke Biddle Date: Fri, 3 Apr 2026 18:59:26 -0600 Subject: [PATCH 11/13] fix: wait for mount point release after test teardown The previous fix only polled list_mount_points before mounting. But the race occurs when the previous test's Drop (which calls unmount) is still being processed by the driver when the next test mounts. Now with_test_drive also waits after the drive thread joins, ensuring the driver has fully released Z:\ before the mutex is released and the next test can start. Extracted wait_for_z_unmounted() helper to deduplicate the polling logic. --- dokan/src/usage_tests.rs | 31 ++++++++++++++++++++----------- 1 file changed, 20 insertions(+), 11 deletions(-) diff --git a/dokan/src/usage_tests.rs b/dokan/src/usage_tests.rs index d3eb303..5872be0 100644 --- a/dokan/src/usage_tests.rs +++ b/dokan/src/usage_tests.rs @@ -905,17 +905,11 @@ pub fn test_flags() -> MountFlags { } #[allow(unused_must_use)] -pub fn with_test_drive(scope: Scope) { - let _guard = TEST_DRIVE_LOCK.lock().unwrap_or_else(|e| e.into_inner()); - - init(); - - // In case previous tests failed and didn't unmount the drive. - unmount(convert_str("Z:\\")); - - // DokanRemoveMountPoint is asynchronous — wait until Z:\ is no longer in the - // active mount point list before mounting again. Without this, on Windows Server - // a pending release can race with the next mount and tear it down immediately. +/// Polls `list_mount_points` until `Z:` is no longer in the active mount list. +/// DokanRemoveMountPoint is asynchronous — the driver may still be processing +/// a teardown even after the user-space call returns. Without this wait, a +/// pending release can race with the next mount and tear it down immediately. +fn wait_for_z_unmounted() { let deadline = std::time::Instant::now() + Duration::from_secs(5); while std::time::Instant::now() < deadline { let z_mounted = list_mount_points(false) @@ -931,6 +925,16 @@ pub fn with_test_drive(scope: Scope) { } thread::sleep(Duration::from_millis(50)); } +} + +pub fn with_test_drive(scope: Scope) { + let _guard = TEST_DRIVE_LOCK.lock().unwrap_or_else(|e| e.into_inner()); + + init(); + + // In case previous tests failed and didn't unmount the drive. + let _ = unmount(convert_str("Z:\\")); + wait_for_z_unmounted(); let (tx_instance, rx_instance) = mpsc::sync_channel(1); @@ -967,6 +971,11 @@ pub fn with_test_drive(scope: Scope) { drive_thread_handle.join().unwrap(); + // Wait for the driver to fully release the mount point before returning. + // Without this, the next test may mount on Z:\ while a pending driver-level + // release is still in-flight, which can tear down the new mount immediately. + wait_for_z_unmounted(); + shutdown(); } From b3092bc6c62ae262b59c8ed22dec08322b61a186 Mon Sep 17 00:00:00 2001 From: Jon-Luke Biddle Date: Fri, 3 Apr 2026 19:10:46 -0600 Subject: [PATCH 12/13] feat: add unmount_and_wait() for synchronous unmount DokanRemoveMountPoint is asynchronous - it signals the driver to release the mount point but returns before the teardown completes. Any caller who unmounts and remounts on the same drive letter risks a race where a pending release tears down the new mount. Add unmount_and_wait() that polls list_mount_points() until the mount point is fully released, with a configurable timeout. Update unmount() docs to clearly state it is asynchronous and recommend the new function for sequential unmount/remount scenarios. Replace hand-rolled polling in test harness with unmount_and_wait(). --- dokan/src/lib.rs | 47 +++++++++++++++++++++++++++++++++++++++- dokan/src/usage_tests.rs | 39 +++++---------------------------- 2 files changed, 52 insertions(+), 34 deletions(-) diff --git a/dokan/src/lib.rs b/dokan/src/lib.rs index fca4c50..34fd4e3 100644 --- a/dokan/src/lib.rs +++ b/dokan/src/lib.rs @@ -33,6 +33,8 @@ mod to_file_time; #[cfg(test)] mod usage_tests; +use std::time::Duration; + use dokan_sys::*; use widestring::U16CStr; use windows_sys::Win32::Foundation::{FALSE, GetLastError, NTSTATUS, TRUE}; @@ -277,12 +279,55 @@ fn test_map_kernel_to_user_create_file_flags() { /// Unmounts a Dokan volume from the specified mount point. /// -/// Returns whether it succeeded. +/// **Note:** This function is asynchronous — it signals the Dokan driver to release the mount +/// point and returns immediately. The driver-level teardown may still be in progress when it +/// returns. If you need to remount on the same mount point, use [`unmount_and_wait`] instead +/// to avoid a race where a pending release tears down the new mount. +/// +/// Returns whether the unmount request was accepted. #[must_use] pub fn unmount(mount_point: impl AsRef) -> bool { unsafe { DokanRemoveMountPoint(mount_point.as_ref().as_ptr()) == TRUE } } +/// Unmounts a Dokan volume and waits for the mount point to be fully released. +/// +/// This is the synchronous counterpart to [`unmount`]. After signaling the Dokan driver to +/// release the mount point, it polls [`list_mount_points`] until the mount point no longer +/// appears in the active mount list, or the timeout expires. +/// +/// Use this when you need to remount on the same mount point, or when you need to ensure the +/// volume is fully torn down before proceeding. +/// +/// Returns `true` if the mount point was successfully released within the timeout. +/// Returns `false` if the unmount request was rejected or the timeout expired. +#[must_use] +pub fn unmount_and_wait(mount_point: impl AsRef, timeout: Duration) -> bool { + let mount_point = mount_point.as_ref(); + if !unmount(mount_point) { + return false; + } + + let mount_point_str = mount_point.to_string_lossy(); + let deadline = std::time::Instant::now() + timeout; + loop { + let still_mounted = list_mount_points(false) + .map(|list| { + (&list) + .into_iter() + .any(|mp| mp.mount_point.is_some_and(|p| p.to_string_lossy() == mount_point_str)) + }) + .unwrap_or(false); + if !still_mounted { + return true; + } + if std::time::Instant::now() >= deadline { + return false; + } + std::thread::sleep(Duration::from_millis(50)); + } +} + /// Output stream to write debug messages to. /// /// Used by [`set_debug_stream`]. diff --git a/dokan/src/usage_tests.rs b/dokan/src/usage_tests.rs index 5872be0..97ed96c 100644 --- a/dokan/src/usage_tests.rs +++ b/dokan/src/usage_tests.rs @@ -65,14 +65,14 @@ use crate::{ MountOptions, data::{ CreateFileInfo, DiskSpaceInfo, FileInfo, FileTimeOperation, FillDataResult, FindData, - FindStreamData, OperationInfo, VolumeInfo, list_mount_points, + FindStreamData, OperationInfo, VolumeInfo, }, file_system_handler::OperationResult, init, notify_create, notify_delete, notify_rename, notify_update, notify_xattr_update, operations_helpers::NtResult, shutdown, to_file_time::ToFileTime, - unmount, + unmount_and_wait, }; pub fn convert_str(s: impl AsRef) -> U16CString { @@ -904,37 +904,15 @@ pub fn test_flags() -> MountFlags { flags } -#[allow(unused_must_use)] -/// Polls `list_mount_points` until `Z:` is no longer in the active mount list. -/// DokanRemoveMountPoint is asynchronous — the driver may still be processing -/// a teardown even after the user-space call returns. Without this wait, a -/// pending release can race with the next mount and tear it down immediately. -fn wait_for_z_unmounted() { - let deadline = std::time::Instant::now() + Duration::from_secs(5); - while std::time::Instant::now() < deadline { - let z_mounted = list_mount_points(false) - .map(|list| { - (&list).into_iter().any(|mp| { - mp.mount_point - .is_some_and(|p| p.to_string_lossy().contains("Z:")) - }) - }) - .unwrap_or(false); - if !z_mounted { - break; - } - thread::sleep(Duration::from_millis(50)); - } -} - pub fn with_test_drive(scope: Scope) { let _guard = TEST_DRIVE_LOCK.lock().unwrap_or_else(|e| e.into_inner()); init(); // In case previous tests failed and didn't unmount the drive. - let _ = unmount(convert_str("Z:\\")); - wait_for_z_unmounted(); + // unmount_and_wait ensures the driver has fully released the mount point + // before we attempt to mount again. + let _ = unmount_and_wait(convert_str("Z:\\"), Duration::from_secs(5)); let (tx_instance, rx_instance) = mpsc::sync_channel(1); @@ -966,16 +944,11 @@ pub fn with_test_drive(scope: Scope) { instance: RefCell::new(None), }); - assert!(unmount(convert_str("Z:\\"))); + assert!(unmount_and_wait(convert_str("Z:\\"), Duration::from_secs(5))); assert_eq!(rx_signal.recv().unwrap(), HandlerSignal::Unmounted); drive_thread_handle.join().unwrap(); - // Wait for the driver to fully release the mount point before returning. - // Without this, the next test may mount on Z:\ while a pending driver-level - // release is still in-flight, which can tear down the new mount immediately. - wait_for_z_unmounted(); - shutdown(); } From a01841c855aefd3cbaaf042f90d16d5b4bc34692 Mon Sep 17 00:00:00 2001 From: Jon-Luke Biddle Date: Fri, 3 Apr 2026 19:26:15 -0600 Subject: [PATCH 13/13] fix: guard all dispatch operations against null file context The dispatch layer in operations.rs previously called the panicking info.context() method for all file operations except cleanup and close_file. When create_file fails (e.g. for system service probes), the context is never stored, but the driver still dispatches subsequent operations for that handle. Each of those operations would panic on the null context dereference. Replace all info.context() calls in the dispatch layer with info.try_context().ok_or(STATUS_INVALID_HANDLE)?, so that operations on handles without a valid context return STATUS_INVALID_HANDLE instead of panicking. This means user handlers are never called with invalid context - the guard is enforced by the dispatch layer. Deprecate the panicking context() method on OperationInfo in favor of try_context(), which returns Option and lets callers handle the null case gracefully. --- dokan/src/data/operation_info.rs | 13 +++++++ dokan/src/lib.rs | 7 ++-- dokan/src/operations.rs | 58 +++++++++++++++++++++----------- dokan/src/usage_tests.rs | 5 ++- 4 files changed, 59 insertions(+), 24 deletions(-) diff --git a/dokan/src/data/operation_info.rs b/dokan/src/data/operation_info.rs index 714b845..72de56d 100644 --- a/dokan/src/data/operation_info.rs +++ b/dokan/src/data/operation_info.rs @@ -50,6 +50,19 @@ impl<'c, 'h: 'c, FSH: FileSystemHandler<'c, 'h> + 'h> OperationInfo<'c, 'h, FSH> } } + /// Returns the file context, panicking if it is null. + /// + /// # Deprecated + /// + /// Use [`try_context`] instead, which returns `Option<&Context>` and lets you handle + /// the null case gracefully. The dispatch layer already guards against null contexts + /// before calling handler methods, so this method should rarely be needed. + /// + /// [`try_context`]: Self::try_context + #[deprecated( + since = "0.4.0", + note = "use try_context() instead to handle null contexts gracefully" + )] pub fn context(&self) -> &'c FSH::Context { self.try_context().expect( "file context is null — create_file may have failed or context was already dropped", diff --git a/dokan/src/lib.rs b/dokan/src/lib.rs index 34fd4e3..c608de7 100644 --- a/dokan/src/lib.rs +++ b/dokan/src/lib.rs @@ -313,9 +313,10 @@ pub fn unmount_and_wait(mount_point: impl AsRef, timeout: Duration) -> loop { let still_mounted = list_mount_points(false) .map(|list| { - (&list) - .into_iter() - .any(|mp| mp.mount_point.is_some_and(|p| p.to_string_lossy() == mount_point_str)) + (&list).into_iter().any(|mp| { + mp.mount_point + .is_some_and(|p| p.to_string_lossy() == mount_point_str) + }) }) .unwrap_or(false); if !still_mounted { diff --git a/dokan/src/operations.rs b/dokan/src/operations.rs index 6131bfd..f2c820f 100644 --- a/dokan/src/operations.rs +++ b/dokan/src/operations.rs @@ -10,7 +10,10 @@ use dokan_sys::{ }; use widestring::U16CStr; use windows_sys::Win32::{ - Foundation::{FILETIME, NTSTATUS, STATUS_BUFFER_OVERFLOW, STATUS_OBJECT_NAME_COLLISION, TRUE}, + Foundation::{ + FILETIME, NTSTATUS, STATUS_BUFFER_OVERFLOW, STATUS_INVALID_HANDLE, + STATUS_OBJECT_NAME_COLLISION, TRUE, + }, Security::PSECURITY_DESCRIPTOR, }; use windows_sys::core::BOOL; @@ -102,9 +105,10 @@ pub extern "system" fn read_file<'c, 'h: 'c, FSH: FileSystemHandler<'c, 'h> + 'h *read_length = 0; let file_name = U16CStr::from_ptr_str(file_name); let info = OperationInfo::<'c, 'h, FSH>::new(dokan_file_info); + let context = info.try_context().ok_or(STATUS_INVALID_HANDLE)?; let buffer = slice::from_raw_parts_mut(buffer as *mut _, buffer_length as usize); info.handler() - .read_file(file_name, offset, buffer, &info, info.context()) + .read_file(file_name, offset, buffer, &info, context) .map(|bytes_read| { *read_length = bytes_read; }) @@ -123,9 +127,10 @@ pub extern "system" fn write_file<'c, 'h: 'c, FSH: FileSystemHandler<'c, 'h> + ' *number_of_bytes_written = 0; let file_name = U16CStr::from_ptr_str(file_name); let info = OperationInfo::<'c, 'h, FSH>::new(dokan_file_info); + let context = info.try_context().ok_or(STATUS_INVALID_HANDLE)?; let buffer = slice::from_raw_parts(buffer as *mut _, number_of_bytes_to_write as usize); info.handler() - .write_file(file_name, offset, buffer, &info, info.context()) + .write_file(file_name, offset, buffer, &info, context) .map(|bytes_written| { *number_of_bytes_written = bytes_written; }) @@ -139,8 +144,8 @@ pub extern "system" fn flush_file_buffers<'c, 'h: 'c, FSH: FileSystemHandler<'c, wrap_nt_result(|| unsafe { let file_name = U16CStr::from_ptr_str(file_name); let info = OperationInfo::<'c, 'h, FSH>::new(dokan_file_info); - info.handler() - .flush_file_buffers(file_name, &info, info.context()) + let context = info.try_context().ok_or(STATUS_INVALID_HANDLE)?; + info.handler().flush_file_buffers(file_name, &info, context) }) } @@ -152,8 +157,9 @@ pub extern "system" fn get_file_information<'c, 'h: 'c, FSH: FileSystemHandler<' wrap_nt_result(|| unsafe { let file_name = U16CStr::from_ptr_str(file_name); let info = OperationInfo::<'c, 'h, FSH>::new(dokan_file_info); + let context = info.try_context().ok_or(STATUS_INVALID_HANDLE)?; info.handler() - .get_file_information(file_name, &info, info.context()) + .get_file_information(file_name, &info, context) .map(|file_info| { *buffer = file_info.to_raw_struct(); }) @@ -169,8 +175,9 @@ pub extern "system" fn find_files<'c, 'h: 'c, FSH: FileSystemHandler<'c, 'h> + ' let file_name = U16CStr::from_ptr_str(file_name); let fill_wrapper = wrap_fill_data(fill_find_data, dokan_file_info, 0); let info = OperationInfo::<'c, 'h, FSH>::new(dokan_file_info); + let context = info.try_context().ok_or(STATUS_INVALID_HANDLE)?; info.handler() - .find_files(file_name, fill_wrapper, &info, info.context()) + .find_files(file_name, fill_wrapper, &info, context) }) } @@ -185,12 +192,13 @@ pub extern "system" fn find_files_with_pattern<'c, 'h: 'c, FSH: FileSystemHandle let search_pattern = U16CStr::from_ptr_str(search_pattern); let fill_wrapper = wrap_fill_data(fill_find_data, dokan_file_info, 0); let info = OperationInfo::<'c, 'h, FSH>::new(dokan_file_info); + let context = info.try_context().ok_or(STATUS_INVALID_HANDLE)?; info.handler().find_files_with_pattern( file_name, search_pattern, fill_wrapper, &info, - info.context(), + context, ) }) } @@ -203,8 +211,9 @@ pub extern "system" fn set_file_attributes<'c, 'h: 'c, FSH: FileSystemHandler<'c wrap_nt_result(|| unsafe { let file_name = U16CStr::from_ptr_str(file_name); let info = OperationInfo::<'c, 'h, FSH>::new(dokan_file_info); + let context = info.try_context().ok_or(STATUS_INVALID_HANDLE)?; info.handler() - .set_file_attributes(file_name, file_attributes, &info, info.context()) + .set_file_attributes(file_name, file_attributes, &info, context) }) } @@ -218,13 +227,14 @@ pub extern "system" fn set_file_time<'c, 'h: 'c, FSH: FileSystemHandler<'c, 'h> wrap_nt_result(|| unsafe { let file_name = U16CStr::from_ptr_str(file_name); let info = OperationInfo::<'c, 'h, FSH>::new(dokan_file_info); + let context = info.try_context().ok_or(STATUS_INVALID_HANDLE)?; info.handler().set_file_time( file_name, creation_time.into(), last_access_time.into(), last_write_time.into(), &info, - info.context(), + context, ) }) } @@ -236,7 +246,8 @@ pub extern "system" fn delete_file<'c, 'h: 'c, FSH: FileSystemHandler<'c, 'h> + wrap_nt_result(|| unsafe { let file_name = U16CStr::from_ptr_str(file_name); let info = OperationInfo::<'c, 'h, FSH>::new(dokan_file_info); - info.handler().delete_file(file_name, &info, info.context()) + let context = info.try_context().ok_or(STATUS_INVALID_HANDLE)?; + info.handler().delete_file(file_name, &info, context) }) } @@ -247,8 +258,8 @@ pub extern "system" fn delete_directory<'c, 'h: 'c, FSH: FileSystemHandler<'c, ' wrap_nt_result(|| unsafe { let file_name = U16CStr::from_ptr_str(file_name); let info = OperationInfo::<'c, 'h, FSH>::new(dokan_file_info); - info.handler() - .delete_directory(file_name, &info, info.context()) + let context = info.try_context().ok_or(STATUS_INVALID_HANDLE)?; + info.handler().delete_directory(file_name, &info, context) }) } @@ -262,12 +273,13 @@ pub extern "system" fn move_file<'c, 'h: 'c, FSH: FileSystemHandler<'c, 'h> + 'h let file_name = U16CStr::from_ptr_str(file_name); let new_file_name = U16CStr::from_ptr_str(new_file_name); let info = OperationInfo::<'c, 'h, FSH>::new(dokan_file_info); + let context = info.try_context().ok_or(STATUS_INVALID_HANDLE)?; info.handler().move_file( file_name, new_file_name, replace_if_existing == TRUE, &info, - info.context(), + context, ) }) } @@ -280,8 +292,9 @@ pub extern "system" fn set_end_of_file<'c, 'h: 'c, FSH: FileSystemHandler<'c, 'h wrap_nt_result(|| unsafe { let file_name = U16CStr::from_ptr_str(file_name); let info = OperationInfo::<'c, 'h, FSH>::new(dokan_file_info); + let context = info.try_context().ok_or(STATUS_INVALID_HANDLE)?; info.handler() - .set_end_of_file(file_name, byte_offset, &info, info.context()) + .set_end_of_file(file_name, byte_offset, &info, context) }) } @@ -293,8 +306,9 @@ pub extern "system" fn set_allocation_size<'c, 'h: 'c, FSH: FileSystemHandler<'c wrap_nt_result(|| unsafe { let file_name = U16CStr::from_ptr_str(file_name); let info = OperationInfo::<'c, 'h, FSH>::new(dokan_file_info); + let context = info.try_context().ok_or(STATUS_INVALID_HANDLE)?; info.handler() - .set_allocation_size(file_name, alloc_size, &info, info.context()) + .set_allocation_size(file_name, alloc_size, &info, context) }) } @@ -320,13 +334,14 @@ fn lock_unlock_file<'c, 'h: 'c, FSH: FileSystemHandler<'c, 'h> + 'h>( wrap_nt_result(|| unsafe { let file_name = U16CStr::from_ptr_str(file_name); let info = OperationInfo::<'c, 'h, FSH>::new(dokan_file_info); + let context = info.try_context().ok_or(STATUS_INVALID_HANDLE)?; func( info.handler(), file_name, byte_offset, length, &info, - info.context(), + context, ) }) } @@ -452,6 +467,7 @@ pub extern "system" fn get_file_security<'c, 'h: 'c, FSH: FileSystemHandler<'c, wrap_nt_result(|| unsafe { let file_name = U16CStr::from_ptr_str(file_name); let info = OperationInfo::<'c, 'h, FSH>::new(dokan_file_info); + let context = info.try_context().ok_or(STATUS_INVALID_HANDLE)?; info.handler() .get_file_security( file_name, @@ -459,7 +475,7 @@ pub extern "system" fn get_file_security<'c, 'h: 'c, FSH: FileSystemHandler<'c, security_descriptor, buffer_length, &info, - info.context(), + context, ) .and_then(|needed| { *length_needed = needed; @@ -482,13 +498,14 @@ pub extern "system" fn set_file_security<'c, 'h: 'c, FSH: FileSystemHandler<'c, wrap_nt_result(|| unsafe { let file_name = U16CStr::from_ptr_str(file_name); let info = OperationInfo::<'c, 'h, FSH>::new(dokan_file_info); + let context = info.try_context().ok_or(STATUS_INVALID_HANDLE)?; info.handler().set_file_security( file_name, *security_information, security_descriptor, buffer_length, &info, - info.context(), + context, ) }) } @@ -503,7 +520,8 @@ pub extern "system" fn find_streams<'c, 'h: 'c, FSH: FileSystemHandler<'c, 'h> + let file_name = U16CStr::from_ptr_str(file_name); let fill_wrapper = wrap_fill_data(fill_find_stream_data, find_stream_context, 1); let info = OperationInfo::<'c, 'h, FSH>::new(dokan_file_info); + let context = info.try_context().ok_or(STATUS_INVALID_HANDLE)?; info.handler() - .find_streams(file_name, fill_wrapper, &info, info.context()) + .find_streams(file_name, fill_wrapper, &info, context) }) } diff --git a/dokan/src/usage_tests.rs b/dokan/src/usage_tests.rs index 97ed96c..dd13153 100644 --- a/dokan/src/usage_tests.rs +++ b/dokan/src/usage_tests.rs @@ -944,7 +944,10 @@ pub fn with_test_drive(scope: Scope) { instance: RefCell::new(None), }); - assert!(unmount_and_wait(convert_str("Z:\\"), Duration::from_secs(5))); + assert!(unmount_and_wait( + convert_str("Z:\\"), + Duration::from_secs(5) + )); assert_eq!(rx_signal.recv().unwrap(), HandlerSignal::Unmounted); drive_thread_handle.join().unwrap();