From 72c228bb9d21873f7d4e3cfad020c041c0ffe108 Mon Sep 17 00:00:00 2001 From: oupson Date: Sat, 10 Dec 2022 17:36:48 +0100 Subject: [PATCH 01/11] Update deps --- Cargo.lock | 125 +++++++++++++++++++++++++---------------------------- 1 file changed, 59 insertions(+), 66 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 85b18bf..38d87e7 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -25,9 +25,9 @@ dependencies = [ [[package]] name = "aes" -version = "0.8.1" +version = "0.8.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bfe0133578c0986e1fe3dfcd4af1cc5b2dd6c3dbf534d69916ce16a2701d40ba" +checksum = "433cfd6710c9986c576a25ca913c39d66a6474107b406f34f91d4a8923395241" dependencies = [ "cfg-if", "cipher 0.4.3", @@ -50,18 +50,18 @@ dependencies = [ [[package]] name = "aho-corasick" -version = "0.7.19" +version = "0.7.20" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b4f55bd91a0978cbfd91c457a164bab8b4001c833b7f323132c0a4e1922dd44e" +checksum = "cc936419f96fa211c1b9166887b38e5e40b19958e5b895be7c1f93adec7071ac" dependencies = [ "memchr", ] [[package]] name = "anyhow" -version = "1.0.65" +version = "1.0.66" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "98161a4e3e2184da77bb14f02184cdd111e83bbbcc9979dfee3c44b9a85f5602" +checksum = "216261ddc8289130e551ddcd5ce8a064710c0d064a4d2895c67151c92b5443f6" [[package]] name = "atty" @@ -82,9 +82,9 @@ checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa" [[package]] name = "base64" -version = "0.13.0" +version = "0.13.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "904dfeac50f3cdaba28fc6f57fdcddb75f49ed61346676a78c4ffe55877802fd" +checksum = "9e1b586273c5702936fe7b7d6896644d8be71e6314cfe09d3167c95f712589e8" [[package]] name = "base64ct" @@ -149,9 +149,9 @@ dependencies = [ [[package]] name = "clap" -version = "3.2.22" +version = "3.2.23" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "86447ad904c7fb335a790c9d7fe3d0d971dc523b8ccd1561a520de9a85302750" +checksum = "71655c45cb9845d3270c9d6df84ebe72b4dad3c2ba3f7023ad47c144e4e473a5" dependencies = [ "atty", "bitflags", @@ -216,9 +216,9 @@ dependencies = [ [[package]] name = "digest" -version = "0.10.5" +version = "0.10.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "adfbc57365a37acbd2ebf2b64d7e69bb766e2fea813521ed536f5d0520dcf86c" +checksum = "8168378f4e5023e7218c89c891c0fd8ecdb5e5e4f18cb78f38cf245dd021e76f" dependencies = [ "block-buffer", "crypto-common", @@ -236,9 +236,9 @@ dependencies = [ [[package]] name = "env_logger" -version = "0.9.1" +version = "0.9.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c90bf5f19754d10198ccb95b70664fc925bd1fc090a0fd9a6ebc54acc8cd6272" +checksum = "a12e6657c4c97ebab115a42dcee77225f7f482cdd841cf7088c657a42e9e00e7" dependencies = [ "atty", "humantime", @@ -274,9 +274,9 @@ dependencies = [ [[package]] name = "getrandom" -version = "0.2.7" +version = "0.2.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4eb1a864a501629691edf6c15a593b7a51eebaa1e8468e9ddc623de7c9b58ec6" +checksum = "c05aeb6a22b8f62540c194aac980f2115af067bfe15a0734d7277a768d396b31" dependencies = [ "cfg-if", "libc", @@ -340,9 +340,9 @@ checksum = "9a3a5bfb195931eeb336b2a7b4d761daec841b97f947d34394601737a7bba5e4" [[package]] name = "indexmap" -version = "1.9.1" +version = "1.9.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "10a35a97730320ffe8e2d410b5d3b69279b98d2c14bdb8b70ea89ecf7888d41e" +checksum = "1885e79c1fc4b10f0e172c475f458b7f7b93061064d98c3293e98c5ba0c8b399" dependencies = [ "autocfg", "hashbrown", @@ -366,9 +366,9 @@ checksum = "4217ad341ebadf8d8e724e264f13e593e0648f5b3e94b3896a5df283be015ecc" [[package]] name = "libc" -version = "0.2.134" +version = "0.2.138" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "329c933548736bc49fd575ee68c89e8be4d260064184389a5b77517cddd99ffb" +checksum = "db6d7e329c562c5dfab7a46a2afabc8b987ab9a4834c9d1ca04dc54c1546cef8" [[package]] name = "log" @@ -387,9 +387,9 @@ checksum = "2dffe52ecf27772e601905b7522cb4ef790d2cc203488bbd0e2fe85fcb74566d" [[package]] name = "once_cell" -version = "1.15.0" +version = "1.16.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e82dad04139b71a90c080c8463fe0dc7902db5192d939bd0950f074d014339e1" +checksum = "86f0b0d4bf799edbc74508c1e8bf170ff5f41238e5f8225603ca7caaae2b7860" [[package]] name = "opaque-debug" @@ -399,9 +399,9 @@ checksum = "624a8340c38c1b80fd549087862da4ba43e08858af025b236e509b6649fc13d5" [[package]] name = "os_str_bytes" -version = "6.3.0" +version = "6.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9ff7415e9ae3fff1225851df9e0d9e4e5479f947619774677a63572e55e80eff" +checksum = "9b7820b9daea5457c9f21c69448905d723fbd21136ccf521748f23fd49e723ee" [[package]] name = "page_size" @@ -471,9 +471,9 @@ dependencies = [ [[package]] name = "proc-macro2" -version = "1.0.46" +version = "1.0.47" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "94e2ef8dbfc347b10c094890f778ee2e36ca9bb4262e86dc99cd217e35f3470b" +checksum = "5ea3d908b0e36316caf9e9e2c4625cdde190a7e6f440d794667ed17a1855e725" dependencies = [ "unicode-ident", ] @@ -498,9 +498,9 @@ dependencies = [ [[package]] name = "regex" -version = "1.6.0" +version = "1.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4c4eb3267174b8c6c2f654116623910a0fef09c4753f8dd83db29c48a0df988b" +checksum = "e076559ef8e241f2ae3479e36f97bd5741c0330689e217ad51ce2c76808b868a" dependencies = [ "aho-corasick", "memchr", @@ -509,15 +509,26 @@ dependencies = [ [[package]] name = "regex-syntax" -version = "0.6.27" +version = "0.6.28" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a3f87b73ce11b1619a3c6332f45341e0047173771e8b8b73f87bfeefb7b56244" +checksum = "456c603be3e8d448b072f410900c09faf164fbce2d480456f50eea6e25f9c848" [[package]] name = "rpassword" -version = "7.0.0" +version = "7.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6678cf63ab3491898c0d021b493c94c9b221d91295294a2a5746eacbe5928322" +dependencies = [ + "libc", + "rtoolbox", + "winapi", +] + +[[package]] +name = "rtoolbox" +version = "0.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "26b763cb66df1c928432cc35053f8bd4cec3335d8559fc16010017d16b3c1680" +checksum = "034e22c514f5c0cb8a10ff341b9b048b5ceb21591f31c8f44c43b960f9b3524a" dependencies = [ "libc", "winapi", @@ -553,7 +564,7 @@ dependencies = [ name = "rustcryptfs-lib" version = "0.1.0" dependencies = [ - "aes 0.8.1", + "aes 0.8.2", "aes-gcm", "base64", "cipher 0.4.3", @@ -603,18 +614,18 @@ dependencies = [ [[package]] name = "serde" -version = "1.0.145" +version = "1.0.149" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "728eb6351430bccb993660dfffc5a72f91ccc1295abaa8ce19b27ebe4f75568b" +checksum = "256b9932320c590e707b94576e3cc1f7c9024d0ee6612dfbcf1cb106cbe8e055" dependencies = [ "serde_derive", ] [[package]] name = "serde_derive" -version = "1.0.145" +version = "1.0.149" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "81fa1584d3d1bcacd84c277a0dfe21f5b0f6accf4a23d04d4c6d61f1af522b4c" +checksum = "b4eae9b04cbffdfd550eb462ed33bc6a1b68c935127d008b27444d08380f94e4" dependencies = [ "proc-macro2", "quote", @@ -623,9 +634,9 @@ dependencies = [ [[package]] name = "serde_json" -version = "1.0.85" +version = "1.0.89" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e55a28e3aaef9d5ce0506d0a14dbba8054ddc7e499ef522dd8b26859ec9d4a44" +checksum = "020ff22c755c2ed3f8cf162dbb41a7268d934702f3ed3631656ea597e08fc3db" dependencies = [ "itoa", "ryu", @@ -663,27 +674,15 @@ checksum = "6bdef32e8150c2a081110b42772ffe7d7c9032b606bc226c8260fd97e0976601" [[package]] name = "syn" -version = "1.0.102" +version = "1.0.105" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3fcd952facd492f9be3ef0d0b7032a6e442ee9b361d4acc2b1d0c4aaa5f613a1" +checksum = "60b9b43d45702de4c839cb9b51d9f529c5dd26a4aff255b42b1ebc03e88ee908" dependencies = [ "proc-macro2", "quote", "unicode-ident", ] -[[package]] -name = "synstructure" -version = "0.12.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f36bdaa60a83aca3921b5259d5400cbf5e90fc51931376a9bd4a0eb79aa7210f" -dependencies = [ - "proc-macro2", - "quote", - "syn", - "unicode-xid", -] - [[package]] name = "termcolor" version = "1.1.3" @@ -695,9 +694,9 @@ dependencies = [ [[package]] name = "textwrap" -version = "0.15.1" +version = "0.16.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "949517c0cf1bf4ee812e2e07e08ab448e3ae0d23472aee8a06c985f0c8815b16" +checksum = "222a222a5bfe1bba4a77b45ec488a741b3cb8872e5e499451fd7d0129c9c7c3d" [[package]] name = "thiserror" @@ -721,9 +720,9 @@ dependencies = [ [[package]] name = "typenum" -version = "1.15.0" +version = "1.16.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dcf81ac59edc17cc8697ff311e8f5ef2d99fcbd9817b34cec66f90b6c3dfd987" +checksum = "497961ef93d974e23eb6f433eb5fe1b7930b659f06d12dec6fc44a8f554c0bba" [[package]] name = "unicode-ident" @@ -731,12 +730,6 @@ version = "1.0.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6ceab39d59e4c9499d4e5a8ee0e2735b891bb7308ac83dfb4e80cad195c9f6f3" -[[package]] -name = "unicode-xid" -version = "0.2.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f962df74c8c05a667b5ee8bcf162993134c104e96440b663c8daa176dc772d8c" - [[package]] name = "universal-hash" version = "0.4.1" @@ -812,11 +805,11 @@ dependencies = [ [[package]] name = "zerocopy-derive" -version = "0.3.1" +version = "0.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a0fbc82b82efe24da867ee52e015e58178684bd9dd64c34e66bdf21da2582a9f" +checksum = "6505e6815af7de1746a08f69c69606bb45695a17149517680f3b2149713b19a3" dependencies = [ "proc-macro2", + "quote", "syn", - "synstructure", ] From d078839814332882c75e5269131b11e72bff92e0 Mon Sep 17 00:00:00 2001 From: oupson Date: Sun, 3 Dec 2023 16:10:22 +0100 Subject: [PATCH 02/11] Basic projfs support : file enumation is working --- .gitignore | 4 +- Cargo.lock | 101 ++++++++++++ Cargo.toml | 3 +- rustcryptfs-mount/Cargo.toml | 3 + rustcryptfs-mount/src/lib.rs | 13 ++ rustcryptfs-projfs/Cargo.toml | 22 +++ rustcryptfs-projfs/src/error.rs | 19 +++ rustcryptfs-projfs/src/lib.rs | 199 +++++++++++++++++++++++ rustcryptfs-projfs/src/projfs.rs | 267 +++++++++++++++++++++++++++++++ rustcryptfs/src/main.rs | 13 +- 10 files changed, 641 insertions(+), 3 deletions(-) create mode 100644 rustcryptfs-projfs/Cargo.toml create mode 100644 rustcryptfs-projfs/src/error.rs create mode 100644 rustcryptfs-projfs/src/lib.rs create mode 100644 rustcryptfs-projfs/src/projfs.rs diff --git a/.gitignore b/.gitignore index 077b91f..93aa485 100644 --- a/.gitignore +++ b/.gitignore @@ -2,4 +2,6 @@ *.py enc mount -.cargo \ No newline at end of file +.cargo + +test.ps1 \ No newline at end of file diff --git a/Cargo.lock b/Cargo.lock index 38d87e7..e67349e 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -214,6 +214,16 @@ dependencies = [ "cipher 0.3.0", ] +[[package]] +name = "ctrlc" +version = "3.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1d91974fbbe88ec1df0c24a4f00f99583667a7e2e6272b2b92d294d81e462173" +dependencies = [ + "nix", + "winapi", +] + [[package]] name = "digest" version = "0.10.6" @@ -385,6 +395,18 @@ version = "2.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2dffe52ecf27772e601905b7522cb4ef790d2cc203488bbd0e2fe85fcb74566d" +[[package]] +name = "nix" +version = "0.25.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f346ff70e7dbfd675fe90590b92d59ef2de15a8779ae305ebcbfd3f0caf59be4" +dependencies = [ + "autocfg", + "bitflags", + "cfg-if", + "libc", +] + [[package]] name = "once_cell" version = "1.16.0" @@ -582,6 +604,19 @@ name = "rustcryptfs-mount" version = "0.1.0" dependencies = [ "rustcryptfs-fuse", + "rustcryptfs-projfs", +] + +[[package]] +name = "rustcryptfs-projfs" +version = "0.1.0" +dependencies = [ + "ctrlc", + "libc", + "log", + "rustcryptfs-lib", + "thiserror", + "windows-sys", ] [[package]] @@ -793,6 +828,72 @@ version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" +[[package]] +name = "windows-sys" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d" +dependencies = [ + "windows-targets", +] + +[[package]] +name = "windows-targets" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8a18201040b24831fbb9e4eb208f8892e1f50a37feb53cc7ff887feb8f50e7cd" +dependencies = [ + "windows_aarch64_gnullvm", + "windows_aarch64_msvc", + "windows_i686_gnu", + "windows_i686_msvc", + "windows_x86_64_gnu", + "windows_x86_64_gnullvm", + "windows_x86_64_msvc", +] + +[[package]] +name = "windows_aarch64_gnullvm" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cb7764e35d4db8a7921e09562a0304bf2f93e0a51bfccee0bd0bb0b666b015ea" + +[[package]] +name = "windows_aarch64_msvc" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bbaa0368d4f1d2aaefc55b6fcfee13f41544ddf36801e793edbbfd7d7df075ef" + +[[package]] +name = "windows_i686_gnu" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a28637cb1fa3560a16915793afb20081aba2c92ee8af57b4d5f28e4b3e7df313" + +[[package]] +name = "windows_i686_msvc" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ffe5e8e31046ce6230cc7215707b816e339ff4d4d67c65dffa206fd0f7aa7b9a" + +[[package]] +name = "windows_x86_64_gnu" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3d6fa32db2bc4a2f5abeacf2b69f7992cd09dca97498da74a151a3132c26befd" + +[[package]] +name = "windows_x86_64_gnullvm" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1a657e1e9d3f514745a572a6846d3c7aa7dbe1658c056ed9c3344c4109a6949e" + +[[package]] +name = "windows_x86_64_msvc" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dff9641d1cd4be8d1a070daf9e3773c5f67e78b4d9d42263020c057706765c04" + [[package]] name = "zerocopy" version = "0.6.1" diff --git a/Cargo.toml b/Cargo.toml index 2fd6a7d..29f9886 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -3,7 +3,8 @@ members = [ "rustcryptfs", "rustcryptfs-lib", "rustcryptfs-fuse", - "rustcryptfs-mount" + "rustcryptfs-mount", + "rustcryptfs-projfs" ] [profile.release] diff --git a/rustcryptfs-mount/Cargo.toml b/rustcryptfs-mount/Cargo.toml index 00f85d8..5e2ff81 100644 --- a/rustcryptfs-mount/Cargo.toml +++ b/rustcryptfs-mount/Cargo.toml @@ -11,3 +11,6 @@ repository = "https://github.com/oupson/rustcryptfs/" [target.'cfg(target_os = "linux")'.dependencies] rustcryptfs-fuse = { path = "../rustcryptfs-fuse" } + +[target.'cfg(target_os = "windows")'.dependencies] +rustcryptfs-projfs = { path = "../rustcryptfs-projfs" } \ No newline at end of file diff --git a/rustcryptfs-mount/src/lib.rs b/rustcryptfs-mount/src/lib.rs index 107aa9d..0b933c0 100644 --- a/rustcryptfs-mount/src/lib.rs +++ b/rustcryptfs-mount/src/lib.rs @@ -12,3 +12,16 @@ where fs.mount(mount_point)?; Ok(()) } + +#[cfg(target_os = "windows")] +pub fn mount

(path: P, mount_point: P, password: &str) -> rustcryptfs_projfs::error::Result<()> +where + P: AsRef, +{ + use rustcryptfs_projfs::EncryptedFs; + + let fs = EncryptedFs::new(path, password)?; + + fs.mount(mount_point)?; + Ok(()) +} diff --git a/rustcryptfs-projfs/Cargo.toml b/rustcryptfs-projfs/Cargo.toml new file mode 100644 index 0000000..38a2081 --- /dev/null +++ b/rustcryptfs-projfs/Cargo.toml @@ -0,0 +1,22 @@ +[package] +name = "rustcryptfs-projfs" +version = "0.1.0" +edition = "2021" + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[dependencies] +log = "0.4" +rustcryptfs-lib = { path = "../rustcryptfs-lib" } +thiserror = "1.0" +libc = "0.2" +ctrlc = "3.2" + +[dependencies.windows-sys] +version = "0.52.0" +features = [ + "Win32_Storage_ProjectedFileSystem", + "Win32_Foundation", + "Win32_System_Com", + "Win32_System_Diagnostics_Debug" +] \ No newline at end of file diff --git a/rustcryptfs-projfs/src/error.rs b/rustcryptfs-projfs/src/error.rs new file mode 100644 index 0000000..b465903 --- /dev/null +++ b/rustcryptfs-projfs/src/error.rs @@ -0,0 +1,19 @@ +use rustcryptfs_lib::filename::FilenameCipherError; +use thiserror::Error; + +pub type Result = std::result::Result; + +#[derive(Debug, Error)] +pub enum Error { + #[error(transparent)] + IoError(#[from] std::io::Error), + + #[error(transparent)] + WindowsError(#[from] super::WinError), + + #[error(transparent)] + RustCryptFsError(#[from] rustcryptfs_lib::error::Error), + + #[error(transparent)] + RustCryptFsFilenameError(#[from] FilenameCipherError), +} diff --git a/rustcryptfs-projfs/src/lib.rs b/rustcryptfs-projfs/src/lib.rs new file mode 100644 index 0000000..bda3375 --- /dev/null +++ b/rustcryptfs-projfs/src/lib.rs @@ -0,0 +1,199 @@ +use std::collections::HashMap; +use std::ffi::{OsString, CStr, CString}; +use std::hash::{Hash, Hasher}; +use std::iter::Map; +use std::path::PathBuf; +use std::{ + error::Error, fmt::Display, mem::MaybeUninit, os::windows::prelude::OsStrExt, path::Path, +}; + +use std::sync::mpsc::channel; + +use libc::c_void; +use rustcryptfs_lib::GocryptFs; + +use error::Result; +use windows_sys::Win32::Foundation::GetLastError; +use windows_sys::Win32::Storage::ProjectedFileSystem::PRJ_PLACEHOLDER_VERSION_INFO; +use windows_sys::Win32::System::Diagnostics::Debug::{ + FormatMessageA, FORMAT_MESSAGE_ALLOCATE_BUFFER, FORMAT_MESSAGE_FROM_SYSTEM, + FORMAT_MESSAGE_IGNORE_INSERTS, +}; +use windows_sys::{ + core::GUID, + Win32::{ + Storage::ProjectedFileSystem::{ + PrjMarkDirectoryAsPlaceholder, PrjStartVirtualizing, PrjStopVirtualizing, + PRJ_CALLBACKS, PRJ_NAMESPACE_VIRTUALIZATION_CONTEXT, + }, + System::Com::CoCreateGuid, + }, +}; + +pub mod error; +mod projfs; + +#[repr(transparent)] +#[derive(Debug)] +pub struct WinError(i32); + +impl Display for WinError { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + let mut buffer = std::ptr::null_mut(); + let size = unsafe { + FormatMessageA( + FORMAT_MESSAGE_ALLOCATE_BUFFER + | FORMAT_MESSAGE_FROM_SYSTEM + | FORMAT_MESSAGE_IGNORE_INSERTS, + std::ptr::null(), + self.0 as u32, + 0, + &mut buffer as *mut *mut i8 as *mut _, + 0, + std::ptr::null(), + ) + }; + + let buffer = unsafe { CStr::from_ptr(buffer) }; + + write!(f, "Windows Error : 0x{:08X} :{}", self.0, buffer.to_string_lossy()) + } +} + +impl Error for WinError {} + +macro_rules! win_to_res { + ($l:expr) => {{ + let res = $l; + + if (res < 0) { + Err(WinError(res)) + } else { + Ok(res) + } + }}; +} + +#[repr(transparent)] +struct WinGuid(GUID); + +impl PartialEq for WinGuid { + fn eq(&self, other: &Self) -> bool { + self.0.data1 == other.0.data1 + && self.0.data2 == other.0.data2 + && self.0.data3 == other.0.data3 + && self.0.data4 == other.0.data4 + } +} + +impl Eq for WinGuid {} + +impl Hash for WinGuid { + fn hash(&self, state: &mut H) { + self.0.data1.hash(state); + self.0.data2.hash(state); + self.0.data3.hash(state); + self.0.data4.hash(state); + } +} + +pub struct EncryptedFs { + fs: GocryptFs, + filename_map: HashMap, + enum_map: HashMap, + base_path : PathBuf +} + +impl EncryptedFs { + pub(crate) fn retrieve_filename<'p>(&'p self, filename: &'p Path) -> Option<&'p Path> { + if filename.as_os_str().len() == 0 { + Some(filename) + } else { + self.filename_map.get(filename).map(|p| p.as_path()) + } + } + + pub(crate) fn insert_filename(&mut self, filename: PathBuf, real_path: PathBuf) { + self.filename_map.insert(filename, real_path); + } +} + +impl EncryptedFs { + pub fn new

(path: P, password: &str) -> Result + where + P: AsRef, + { + let path = path.as_ref(); + + log::info!("Opening dir ..."); + let fs = GocryptFs::open(path, password)?; + + println!("Filesystem mounted and ready."); + + Ok(Self { + fs, + filename_map: Default::default(), + enum_map: Default::default(), + base_path: path.to_owned() + }) + } + + pub fn mount

(self, mountpoint: P) -> crate::Result<()> + where + P: AsRef, + { + unsafe { + let mut instance_id: GUID = MaybeUninit::zeroed().assume_init(); + win_to_res!(CoCreateGuid(&mut instance_id))?; + + let mut root_name: Vec = mountpoint.as_ref().as_os_str().encode_wide().collect(); + root_name.push(0); + + let info: PRJ_PLACEHOLDER_VERSION_INFO = MaybeUninit::zeroed().assume_init(); + + let ptr = root_name.as_ptr(); + win_to_res!(PrjMarkDirectoryAsPlaceholder( + ptr, + std::ptr::null(), + &info, + &instance_id + ))?; + + let mut callback_table: PRJ_CALLBACKS = MaybeUninit::zeroed().assume_init(); + + callback_table.StartDirectoryEnumerationCallback = Some(projfs::start_enum_callback); + callback_table.EndDirectoryEnumerationCallback = Some(projfs::end_enum_callback); + callback_table.GetDirectoryEnumerationCallback = Some(projfs::get_enum_callback); + callback_table.GetPlaceholderInfoCallback = Some(projfs::get_placeholder_info_callback); + callback_table.GetFileDataCallback = Some(projfs::get_file_data_callback); + + let this = Box::leak(Box::new(self)) as *mut EncryptedFs; + + let mut instance_handle: PRJ_NAMESPACE_VIRTUALIZATION_CONTEXT = + MaybeUninit::zeroed().assume_init(); + win_to_res!(PrjStartVirtualizing( + ptr, + &callback_table, + this as *const c_void, + std::ptr::null(), + &mut instance_handle + ))?; + + log::trace!("mounted"); + + let (tx, rx) = channel(); + + ctrlc::set_handler(move || tx.send(()).expect("Could not send signal on channel.")) + .expect("Error setting Ctrl-C handler"); + + rx.recv().expect("Could not receive from channel."); + + println!("Exiting ..."); + + PrjStopVirtualizing(instance_handle); + + drop(Box::from_raw(this)); + } + Ok(()) + } +} diff --git a/rustcryptfs-projfs/src/projfs.rs b/rustcryptfs-projfs/src/projfs.rs new file mode 100644 index 0000000..9584ab2 --- /dev/null +++ b/rustcryptfs-projfs/src/projfs.rs @@ -0,0 +1,267 @@ +use std::{ + ffi::OsString, + fs::{File, ReadDir}, + io::Read, + os::windows::{ffi::OsStrExt, fs::MetadataExt, prelude::OsStringExt}, + path::PathBuf, +}; + +use log::trace; +use rustcryptfs_lib::filename::EncodedFilename; +use windows_sys::{ + core::{GUID, HRESULT, PCWSTR}, + Win32::Storage::ProjectedFileSystem::{ + PrjFillDirEntryBuffer2, PrjWritePlaceholderInfo, PRJ_CALLBACK_DATA, + PRJ_DIR_ENTRY_BUFFER_HANDLE, PRJ_FILE_BASIC_INFO, PRJ_PLACEHOLDER_INFO, + PRJ_PLACEHOLDER_INFO_0, + }, +}; + +use crate::EncryptedFs; + +unsafe fn u16_ptr_to_string(ptr: *const u16) -> OsString { + let len = (0..).take_while(|&i| *ptr.offset(i) != 0).count(); + let slice = std::slice::from_raw_parts(ptr, len); + + OsString::from_wide(slice) +} + +#[derive(Debug)] +pub(crate) struct DirEnumData { + diriv: [u8; 16], + r: ReadDir, +} + +pub(crate) unsafe extern "system" fn start_enum_callback( + callback_data: *const PRJ_CALLBACK_DATA, + enumeration_id: *const GUID, +) -> HRESULT { + let callback_data = &*callback_data; + let instance_context = &mut *(callback_data.InstanceContext as *mut EncryptedFs); + let filename = PathBuf::from(u16_ptr_to_string(callback_data.FilePathName)); + log::trace!("start_enum_callback called for {:?}", filename); + + let path = match instance_context.retrieve_filename(&filename) { + Some(p) => p.to_path_buf(), + None => { + let parent = filename.parent().unwrap(); + let name = filename.file_name().unwrap(); + let real_parent = instance_context.retrieve_filename(&parent).unwrap(); + + let mut iv = [0u8; 16]; + + { + let mut iv_file = File::open(real_parent.join("gocryptfs.diriv")).unwrap(); + iv_file.read_exact(&mut iv).unwrap(); + } + + let d = instance_context + .fs + .filename_decoder() + .get_cipher_for_dir(&iv); + + let encrypted_name = d.encrypt_filename(&name.to_string_lossy()).unwrap(); + + let encoded_name = match &encrypted_name { + EncodedFilename::ShortFilename(s) => s, + EncodedFilename::LongFilename(l) => l.filename(), + }; + + let real_path = real_parent.join(encoded_name); + + instance_context.insert_filename(filename, real_path.clone()); + + real_path + } + }; + + let path = instance_context.base_path.join(path); + + let mut iv = [0u8; 16]; + + { + let mut iv_file = File::open(path.join("gocryptfs.diriv")).unwrap(); + iv_file.read_exact(&mut iv).unwrap(); + } + + let r = std::fs::read_dir(path).unwrap(); + + instance_context.enum_map.insert( + crate::WinGuid(*enumeration_id), + DirEnumData { r: r, diriv: iv }, + ); + + 0 +} + +pub(crate) unsafe extern "system" fn end_enum_callback( + callback_data: *const PRJ_CALLBACK_DATA, + enumeration_id: *const GUID, +) -> HRESULT { + log::trace!("end_enum_callback called"); + + let callback_data = &*callback_data; + let instance_context = &mut *(callback_data.InstanceContext as *mut EncryptedFs); + + instance_context + .enum_map + .remove(&crate::WinGuid(*enumeration_id)); + + 0 +} + +pub(crate) unsafe extern "system" fn get_enum_callback( + callback_data: *const PRJ_CALLBACK_DATA, + enumeration_id: *const GUID, + search_expression: PCWSTR, + dir_entry_buffer_handle: PRJ_DIR_ENTRY_BUFFER_HANDLE, +) -> ::windows_sys::core::HRESULT { + log::trace!("get_enum_callback called"); + + let callback_data = &*callback_data; + let instance_context = &mut *(callback_data.InstanceContext as *mut EncryptedFs); + + let data = instance_context + .enum_map + .get_mut(&crate::WinGuid(*enumeration_id)) + .unwrap(); + + log::trace!("foo {:?}", data); + + while let Some(e) = data.r.next() { + let entry = e.unwrap(); + + if entry.file_name() == "gocryptfs.diriv" || entry.file_name() == "gocryptfs.conf" { + continue; + } + + let metadata = entry.metadata().unwrap(); + + let mut os_str = instance_context + .fs + .filename_decoder() + .get_cipher_for_dir(&data.diriv) + .decode_filename(&*entry.file_name().to_string_lossy()) + .unwrap() + .encode_utf16() + .collect::>(); + + os_str.push(0); + + let a = os_str.as_ptr(); + + let infos = PRJ_FILE_BASIC_INFO { + IsDirectory: if metadata.is_dir() { 1 } else { 0 }, + FileSize: metadata.file_size() as i64, + CreationTime: 0, + LastAccessTime: 0, + LastWriteTime: 0, + ChangeTime: 0, + FileAttributes: 0, + }; + + PrjFillDirEntryBuffer2(dir_entry_buffer_handle, a, &infos, std::ptr::null()); + } + + 0 +} + +pub(crate) unsafe extern "system" fn get_placeholder_info_callback( + callback_data: *const PRJ_CALLBACK_DATA, +) -> ::windows_sys::core::HRESULT { + let callback_data = &*callback_data; + let instance_context = &mut *(callback_data.InstanceContext as *mut EncryptedFs); + let filename = PathBuf::from(u16_ptr_to_string(callback_data.FilePathName)); + + log::trace!("get_placeholder_info_callback called : {:?}", filename); + + let path = match instance_context.retrieve_filename(&filename) { + Some(p) => instance_context.base_path.join(p.to_path_buf()), + None => { + let parent = filename.parent().unwrap(); + let name = filename.file_name().unwrap(); + let real_parent = instance_context.retrieve_filename(&parent).unwrap(); + + trace!("real parent : {:?}", real_parent); + + let mut iv = [0u8; 16]; + + { + let mut iv_file = File::open( + instance_context + .base_path + .join(real_parent) + .join("gocryptfs.diriv"), + ) + .unwrap(); + iv_file.read_exact(&mut iv).unwrap(); + } + + let d = instance_context + .fs + .filename_decoder() + .get_cipher_for_dir(&iv); + + let encrypted_name = d.encrypt_filename(&name.to_string_lossy()).unwrap(); + + let encoded_name = match &encrypted_name { + EncodedFilename::ShortFilename(s) => s, + EncodedFilename::LongFilename(l) => l.filename(), + }; + + let real_path = real_parent.join(encoded_name); + + instance_context.insert_filename(filename, real_path.clone()); + + instance_context.base_path.join(real_path) + } + }; + + log::trace!("real path : {:?}", path); + + match path.metadata() { + Ok(metadata) => { + let infos = PRJ_PLACEHOLDER_INFO { + FileBasicInfo: PRJ_FILE_BASIC_INFO { + IsDirectory: if metadata.is_dir() { 1 } else { 0 }, + FileSize: metadata.file_size() as i64, + CreationTime: 0, + LastAccessTime: 0, + LastWriteTime: 0, + ChangeTime: 0, + FileAttributes: 0, + }, + EaInformation: std::mem::zeroed(), + SecurityInformation: std::mem::zeroed(), + StreamsInformation: std::mem::zeroed(), + VersionInfo: std::mem::zeroed(), + VariableData: std::mem::zeroed(), + }; + + let hr = PrjWritePlaceholderInfo( + callback_data.NamespaceVirtualizationContext, + callback_data.FilePathName, + &infos, + std::mem::size_of_val(&infos) as u32, + ); + + trace!("{} {}", super::WinError(hr), std::mem::size_of_val(&infos)); + + 0 + } + Err(e) => { + log::trace!("{}", e); + 0x80004005u32 as i32 + } + } +} + +pub(crate) unsafe extern "system" fn get_file_data_callback( + callback_data: *const PRJ_CALLBACK_DATA, + byte_offset: u64, + length: u32, +) -> HRESULT { + log::trace!("get_file_data_callback called"); + + 0 +} diff --git a/rustcryptfs/src/main.rs b/rustcryptfs/src/main.rs index edd9845..a22fcca 100644 --- a/rustcryptfs/src/main.rs +++ b/rustcryptfs/src/main.rs @@ -140,5 +140,16 @@ fn mount(mount: &MountCommand) -> anyhow::Result<()> { #[cfg(target_os = "windows")] #[cfg(feature = "mount")] fn mount(mount: &MountCommand) -> anyhow::Result<()> { - unimplemented!() + use anyhow::Context; + + let password = if let Some(password) = &mount.password { + password.clone() + } else { + rpassword::prompt_password("Your password: ")? + }; + + rustcryptfs_mount::mount(&mount.path, &mount.mountpoint, &password) + .context("Failed to run gocryptfs")?; + + Ok(()) } From 40d1be90cf8f1750f04e3b74972412c2699e62b9 Mon Sep 17 00:00:00 2001 From: oupson Date: Sun, 3 Dec 2023 16:26:29 +0100 Subject: [PATCH 03/11] Fix code duplication --- rustcryptfs-projfs/src/lib.rs | 53 ++++++++++++++++++++-- rustcryptfs-projfs/src/projfs.rs | 78 +------------------------------- 2 files changed, 51 insertions(+), 80 deletions(-) diff --git a/rustcryptfs-projfs/src/lib.rs b/rustcryptfs-projfs/src/lib.rs index bda3375..e1a37f5 100644 --- a/rustcryptfs-projfs/src/lib.rs +++ b/rustcryptfs-projfs/src/lib.rs @@ -1,6 +1,8 @@ use std::collections::HashMap; -use std::ffi::{OsString, CStr, CString}; +use std::ffi::{CStr, CString, OsString}; +use std::fs::File; use std::hash::{Hash, Hasher}; +use std::io::Read; use std::iter::Map; use std::path::PathBuf; use std::{ @@ -13,6 +15,7 @@ use libc::c_void; use rustcryptfs_lib::GocryptFs; use error::Result; +use rustcryptfs_lib::filename::EncodedFilename; use windows_sys::Win32::Foundation::GetLastError; use windows_sys::Win32::Storage::ProjectedFileSystem::PRJ_PLACEHOLDER_VERSION_INFO; use windows_sys::Win32::System::Diagnostics::Debug::{ @@ -56,7 +59,12 @@ impl Display for WinError { let buffer = unsafe { CStr::from_ptr(buffer) }; - write!(f, "Windows Error : 0x{:08X} :{}", self.0, buffer.to_string_lossy()) + write!( + f, + "Windows Error : 0x{:08X} :{}", + self.0, + buffer.to_string_lossy() + ) } } @@ -101,7 +109,7 @@ pub struct EncryptedFs { fs: GocryptFs, filename_map: HashMap, enum_map: HashMap, - base_path : PathBuf + base_path: PathBuf, } impl EncryptedFs { @@ -116,6 +124,43 @@ impl EncryptedFs { pub(crate) fn insert_filename(&mut self, filename: PathBuf, real_path: PathBuf) { self.filename_map.insert(filename, real_path); } + + pub(crate) fn get_path(&mut self, filename: PathBuf) -> PathBuf { + let path = match self.retrieve_filename(&filename) { + Some(p) => p.to_path_buf(), + None => { + let parent = filename.parent().unwrap(); + let name = filename.file_name().unwrap(); + let real_parent: &Path = self.retrieve_filename(&parent).unwrap(); + + let mut iv = [0u8; 16]; + + { + let mut iv_file = + File::open(self.base_path.join(real_parent).join("gocryptfs.diriv")) + .unwrap(); + iv_file.read_exact(&mut iv).unwrap(); + } + + let d = self.fs.filename_decoder().get_cipher_for_dir(&iv); + + let encrypted_name = d.encrypt_filename(&name.to_string_lossy()).unwrap(); + + let encoded_name = match &encrypted_name { + EncodedFilename::ShortFilename(s) => s, + EncodedFilename::LongFilename(l) => l.filename(), + }; + + let real_path = real_parent.join(encoded_name); + + self.insert_filename(filename, real_path.clone()); + + real_path + } + }; + + self.base_path.join(path) + } } impl EncryptedFs { @@ -134,7 +179,7 @@ impl EncryptedFs { fs, filename_map: Default::default(), enum_map: Default::default(), - base_path: path.to_owned() + base_path: path.to_owned(), }) } diff --git a/rustcryptfs-projfs/src/projfs.rs b/rustcryptfs-projfs/src/projfs.rs index 9584ab2..a563846 100644 --- a/rustcryptfs-projfs/src/projfs.rs +++ b/rustcryptfs-projfs/src/projfs.rs @@ -41,41 +41,7 @@ pub(crate) unsafe extern "system" fn start_enum_callback( let filename = PathBuf::from(u16_ptr_to_string(callback_data.FilePathName)); log::trace!("start_enum_callback called for {:?}", filename); - let path = match instance_context.retrieve_filename(&filename) { - Some(p) => p.to_path_buf(), - None => { - let parent = filename.parent().unwrap(); - let name = filename.file_name().unwrap(); - let real_parent = instance_context.retrieve_filename(&parent).unwrap(); - - let mut iv = [0u8; 16]; - - { - let mut iv_file = File::open(real_parent.join("gocryptfs.diriv")).unwrap(); - iv_file.read_exact(&mut iv).unwrap(); - } - - let d = instance_context - .fs - .filename_decoder() - .get_cipher_for_dir(&iv); - - let encrypted_name = d.encrypt_filename(&name.to_string_lossy()).unwrap(); - - let encoded_name = match &encrypted_name { - EncodedFilename::ShortFilename(s) => s, - EncodedFilename::LongFilename(l) => l.filename(), - }; - - let real_path = real_parent.join(encoded_name); - - instance_context.insert_filename(filename, real_path.clone()); - - real_path - } - }; - - let path = instance_context.base_path.join(path); + let path = instance_context.get_path(filename); let mut iv = [0u8; 16]; @@ -175,47 +141,7 @@ pub(crate) unsafe extern "system" fn get_placeholder_info_callback( log::trace!("get_placeholder_info_callback called : {:?}", filename); - let path = match instance_context.retrieve_filename(&filename) { - Some(p) => instance_context.base_path.join(p.to_path_buf()), - None => { - let parent = filename.parent().unwrap(); - let name = filename.file_name().unwrap(); - let real_parent = instance_context.retrieve_filename(&parent).unwrap(); - - trace!("real parent : {:?}", real_parent); - - let mut iv = [0u8; 16]; - - { - let mut iv_file = File::open( - instance_context - .base_path - .join(real_parent) - .join("gocryptfs.diriv"), - ) - .unwrap(); - iv_file.read_exact(&mut iv).unwrap(); - } - - let d = instance_context - .fs - .filename_decoder() - .get_cipher_for_dir(&iv); - - let encrypted_name = d.encrypt_filename(&name.to_string_lossy()).unwrap(); - - let encoded_name = match &encrypted_name { - EncodedFilename::ShortFilename(s) => s, - EncodedFilename::LongFilename(l) => l.filename(), - }; - - let real_path = real_parent.join(encoded_name); - - instance_context.insert_filename(filename, real_path.clone()); - - instance_context.base_path.join(real_path) - } - }; + let path = instance_context.get_path(filename); log::trace!("real path : {:?}", path); From 565c670bbc327e93a689a4fa62857395686b26ab Mon Sep 17 00:00:00 2001 From: oupson Date: Sun, 3 Dec 2023 16:54:19 +0100 Subject: [PATCH 04/11] Very basic get_file_data_callback and fix file size --- rustcryptfs-projfs/src/projfs.rs | 112 ++++++++++++++++++++++++++++--- 1 file changed, 102 insertions(+), 10 deletions(-) diff --git a/rustcryptfs-projfs/src/projfs.rs b/rustcryptfs-projfs/src/projfs.rs index a563846..e9c6313 100644 --- a/rustcryptfs-projfs/src/projfs.rs +++ b/rustcryptfs-projfs/src/projfs.rs @@ -1,19 +1,19 @@ use std::{ ffi::OsString, fs::{File, ReadDir}, - io::Read, - os::windows::{ffi::OsStrExt, fs::MetadataExt, prelude::OsStringExt}, + io::{Read, Seek, SeekFrom}, + os::windows::{fs::MetadataExt, prelude::OsStringExt}, path::PathBuf, }; use log::trace; -use rustcryptfs_lib::filename::EncodedFilename; +use rustcryptfs_lib::content::ContentEnc; use windows_sys::{ core::{GUID, HRESULT, PCWSTR}, Win32::Storage::ProjectedFileSystem::{ - PrjFillDirEntryBuffer2, PrjWritePlaceholderInfo, PRJ_CALLBACK_DATA, - PRJ_DIR_ENTRY_BUFFER_HANDLE, PRJ_FILE_BASIC_INFO, PRJ_PLACEHOLDER_INFO, - PRJ_PLACEHOLDER_INFO_0, + PrjAllocateAlignedBuffer, PrjFillDirEntryBuffer2, PrjFreeAlignedBuffer, + PrjGetVirtualizationInstanceInfo, PrjWriteFileData, PrjWritePlaceholderInfo, + PRJ_CALLBACK_DATA, PRJ_DIR_ENTRY_BUFFER_HANDLE, PRJ_FILE_BASIC_INFO, PRJ_PLACEHOLDER_INFO, }, }; @@ -118,7 +118,11 @@ pub(crate) unsafe extern "system" fn get_enum_callback( let infos = PRJ_FILE_BASIC_INFO { IsDirectory: if metadata.is_dir() { 1 } else { 0 }, - FileSize: metadata.file_size() as i64, + FileSize: if metadata.is_dir() { + metadata.file_size() as i64 + } else { + ContentEnc::get_real_size(metadata.file_size()) as i64 + }, CreationTime: 0, LastAccessTime: 0, LastWriteTime: 0, @@ -150,7 +154,11 @@ pub(crate) unsafe extern "system" fn get_placeholder_info_callback( let infos = PRJ_PLACEHOLDER_INFO { FileBasicInfo: PRJ_FILE_BASIC_INFO { IsDirectory: if metadata.is_dir() { 1 } else { 0 }, - FileSize: metadata.file_size() as i64, + FileSize: if metadata.is_dir() { + metadata.file_size() as i64 + } else { + ContentEnc::get_real_size(metadata.file_size()) as i64 + }, CreationTime: 0, LastAccessTime: 0, LastWriteTime: 0, @@ -177,7 +185,7 @@ pub(crate) unsafe extern "system" fn get_placeholder_info_callback( } Err(e) => { log::trace!("{}", e); - 0x80004005u32 as i32 + 0x80004005u32 as i32 // TODO } } } @@ -187,7 +195,91 @@ pub(crate) unsafe extern "system" fn get_file_data_callback( byte_offset: u64, length: u32, ) -> HRESULT { - log::trace!("get_file_data_callback called"); + let callback_data = &*callback_data; + let instance_context = &mut *(callback_data.InstanceContext as *mut EncryptedFs); + let filename = PathBuf::from(u16_ptr_to_string(callback_data.FilePathName)); + + let mut infos = std::mem::zeroed(); + PrjGetVirtualizationInstanceInfo(callback_data.NamespaceVirtualizationContext, &mut infos); + + trace!("{}", infos.WriteAlignment); + + log::trace!("get_file_data_callback called : {:?}", filename); + + let path = instance_context.get_path(filename); + + log::trace!("real path : {:?}", path); + + let size = length as usize; + + let mut file = File::open(path).unwrap(); + let decoder = instance_context.fs.content_decoder(); + + let mut buf = [0u8; 18]; + let n = file.read(&mut buf).unwrap(); + let id = if n < 18 { None } else { Some(&buf[2..]) }; + + let mut block_index = byte_offset / 4096; + + let mut buffer = Vec::with_capacity(size); + + let mut rem = size; + + let mut buf = [0u8; 4096 + 32]; + + file.seek(SeekFrom::Start(18 + block_index * (4096 + 32))) + .unwrap(); + + { + let n = file.read(&mut buf).unwrap(); + + let res = decoder + .decrypt_block(&mut buf[..n], block_index, id) + .unwrap(); + + let seek = (byte_offset as u64 - block_index * 4096) as usize; + buffer.extend_from_slice(&res[seek..]); + + block_index += 1; + + rem -= res.len() - seek; + } + + while rem > 0 { + let n = file.read(&mut buf).unwrap(); + + if n == 0 { + break; + } + + let res = decoder + .decrypt_block(&mut buf[..n], block_index, id) + .unwrap(); + + let size = res.len().min(rem); + + buffer.extend_from_slice(&res[..size]); + + block_index += 1; + + rem -= size; + } + + let prjbuf = + PrjAllocateAlignedBuffer(callback_data.NamespaceVirtualizationContext, buffer.len()) + as *mut u8; + + prjbuf.copy_from(buffer.as_ptr(), buffer.len()); + + PrjWriteFileData( + callback_data.NamespaceVirtualizationContext, + &callback_data.DataStreamId, + prjbuf as *mut _, + byte_offset, + buffer.len() as u32, + ); + + PrjFreeAlignedBuffer(prjbuf as *mut _); 0 } From aec2f657550c497f987e70b05f581e207d1a22b8 Mon Sep 17 00:00:00 2001 From: oupson Date: Sun, 3 Dec 2023 19:55:04 +0100 Subject: [PATCH 05/11] Fix file duplication : windows expect file to be sorted Cause why the fork not --- rustcryptfs-projfs/src/projfs.rs | 164 +++++++++++++++++++++---------- 1 file changed, 110 insertions(+), 54 deletions(-) diff --git a/rustcryptfs-projfs/src/projfs.rs b/rustcryptfs-projfs/src/projfs.rs index e9c6313..29dee38 100644 --- a/rustcryptfs-projfs/src/projfs.rs +++ b/rustcryptfs-projfs/src/projfs.rs @@ -1,22 +1,41 @@ use std::{ - ffi::OsString, - fs::{File, ReadDir}, + cmp::Ordering, + ffi::{c_ulong, CStr, CString, OsString}, + fs::{DirEntry, File, ReadDir}, io::{Read, Seek, SeekFrom}, os::windows::{fs::MetadataExt, prelude::OsStringExt}, path::PathBuf, + slice::Iter, }; use log::trace; use rustcryptfs_lib::content::ContentEnc; use windows_sys::{ core::{GUID, HRESULT, PCWSTR}, - Win32::Storage::ProjectedFileSystem::{ - PrjAllocateAlignedBuffer, PrjFillDirEntryBuffer2, PrjFreeAlignedBuffer, - PrjGetVirtualizationInstanceInfo, PrjWriteFileData, PrjWritePlaceholderInfo, - PRJ_CALLBACK_DATA, PRJ_DIR_ENTRY_BUFFER_HANDLE, PRJ_FILE_BASIC_INFO, PRJ_PLACEHOLDER_INFO, + Win32::{ + Foundation::ERROR_FILE_NOT_FOUND, + Storage::ProjectedFileSystem::{ + PrjAllocateAlignedBuffer, PrjFileNameCompare, PrjFillDirEntryBuffer, + PrjFillDirEntryBuffer2, PrjFreeAlignedBuffer, PrjGetVirtualizationInstanceInfo, + PrjWriteFileData, PrjWritePlaceholderInfo, PRJ_CALLBACK_DATA, + PRJ_CB_DATA_FLAG_ENUM_RESTART_SCAN, PRJ_DIR_ENTRY_BUFFER_HANDLE, PRJ_FILE_BASIC_INFO, + PRJ_PLACEHOLDER_INFO, + }, + System::Diagnostics::Debug::FACILITY_WIN32, }, }; +// TODO windows::core::HRESULT + +#[inline] +pub fn HRESULT_FROM_WIN32(x: c_ulong) -> HRESULT { + if x as i32 <= 0 { + x as i32 + } else { + ((x & 0x0000FFFF) | ((FACILITY_WIN32 as u32) << 16) | 0x80000000) as i32 + } +} + use crate::EncryptedFs; unsafe fn u16_ptr_to_string(ptr: *const u16) -> OsString { @@ -26,10 +45,11 @@ unsafe fn u16_ptr_to_string(ptr: *const u16) -> OsString { OsString::from_wide(slice) } -#[derive(Debug)] pub(crate) struct DirEnumData { diriv: [u8; 16], - r: ReadDir, + last_entry: Option<(Vec, PRJ_FILE_BASIC_INFO)>, + entries: Vec<(Vec, DirEntry)>, + iter_index: Option, } pub(crate) unsafe extern "system" fn start_enum_callback( @@ -39,7 +59,11 @@ pub(crate) unsafe extern "system" fn start_enum_callback( let callback_data = &*callback_data; let instance_context = &mut *(callback_data.InstanceContext as *mut EncryptedFs); let filename = PathBuf::from(u16_ptr_to_string(callback_data.FilePathName)); - log::trace!("start_enum_callback called for {:?}", filename); + log::trace!( + "start_enum_callback called for {:?} {}", + filename, + *callback_data.FilePathName + ); let path = instance_context.get_path(filename); @@ -50,11 +74,46 @@ pub(crate) unsafe extern "system" fn start_enum_callback( iv_file.read_exact(&mut iv).unwrap(); } - let r = std::fs::read_dir(path).unwrap(); + let mut entries = std::fs::read_dir(path) + .unwrap() + .filter_map(|e| e.ok()) + .filter(|e| e.file_name() != "gocryptfs.conf" && e.file_name() != "gocryptfs.diriv") + .map(|entry| { + log::trace!("{:?}", entry.file_name()); + ( + instance_context + .fs + .filename_decoder() + .get_cipher_for_dir(&iv) + .decode_filename(&*entry.file_name().to_string_lossy()) + .unwrap() + .encode_utf16() + .chain(std::iter::once(0)) + .collect::>(), + entry, + ) + }) + .collect::>(); + + entries.sort_by(|entry1, entry2| { + let comp = PrjFileNameCompare(entry1.0.as_ptr(), entry2.0.as_ptr()); + if comp < 0 { + Ordering::Less + } else if comp > 0 { + Ordering::Greater + } else { + Ordering::Equal + } + }); instance_context.enum_map.insert( crate::WinGuid(*enumeration_id), - DirEnumData { r: r, diriv: iv }, + DirEnumData { + diriv: iv, + last_entry: None, + entries, + iter_index: None, + }, ); 0 @@ -82,57 +141,61 @@ pub(crate) unsafe extern "system" fn get_enum_callback( search_expression: PCWSTR, dir_entry_buffer_handle: PRJ_DIR_ENTRY_BUFFER_HANDLE, ) -> ::windows_sys::core::HRESULT { - log::trace!("get_enum_callback called"); - let callback_data = &*callback_data; let instance_context = &mut *(callback_data.InstanceContext as *mut EncryptedFs); + log::debug!( + "get_enum_callback called : {}", + callback_data.Flags & PRJ_CB_DATA_FLAG_ENUM_RESTART_SCAN + ); + let data = instance_context .enum_map .get_mut(&crate::WinGuid(*enumeration_id)) .unwrap(); - log::trace!("foo {:?}", data); + if callback_data.Flags & PRJ_CB_DATA_FLAG_ENUM_RESTART_SCAN == 1 { + data.last_entry = None; + data.iter_index = Some(0); + } - while let Some(e) = data.r.next() { - let entry = e.unwrap(); + let mut last_index = data.iter_index.unwrap_or(0); - if entry.file_name() == "gocryptfs.diriv" || entry.file_name() == "gocryptfs.conf" { - continue; + if let Some((last_filename, last_info)) = std::mem::replace(&mut data.last_entry, None) { + PrjFillDirEntryBuffer(last_filename.as_ptr(), &last_info, dir_entry_buffer_handle); } - let metadata = entry.metadata().unwrap(); - - let mut os_str = instance_context - .fs - .filename_decoder() - .get_cipher_for_dir(&data.diriv) - .decode_filename(&*entry.file_name().to_string_lossy()) - .unwrap() - .encode_utf16() - .collect::>(); - - os_str.push(0); + while last_index < data.entries.len() { + let (filename, entry) = &data.entries[last_index]; - let a = os_str.as_ptr(); + let metadata = entry.metadata().unwrap(); let infos = PRJ_FILE_BASIC_INFO { IsDirectory: if metadata.is_dir() { 1 } else { 0 }, FileSize: if metadata.is_dir() { - metadata.file_size() as i64 + 0 } else { ContentEnc::get_real_size(metadata.file_size()) as i64 }, - CreationTime: 0, - LastAccessTime: 0, - LastWriteTime: 0, - ChangeTime: 0, + CreationTime: metadata.creation_time() as i64, + LastAccessTime: metadata.last_access_time() as i64, + LastWriteTime: metadata.last_write_time() as i64, + ChangeTime: metadata.last_write_time() as i64, FileAttributes: 0, }; - PrjFillDirEntryBuffer2(dir_entry_buffer_handle, a, &infos, std::ptr::null()); + // TODO check if HRESULT_FROM_WIN32(ERROR_INSUFFICIENT_BUFFER) + if PrjFillDirEntryBuffer(filename.as_ptr(), &infos, dir_entry_buffer_handle) != 0 { + trace!("not enough size in buffer"); + data.last_entry = Some((filename.clone(), infos)); + break; + } + + last_index += 1; } + data.iter_index = Some(last_index); + 0 } @@ -151,25 +214,19 @@ pub(crate) unsafe extern "system" fn get_placeholder_info_callback( match path.metadata() { Ok(metadata) => { - let infos = PRJ_PLACEHOLDER_INFO { - FileBasicInfo: PRJ_FILE_BASIC_INFO { + let mut infos: PRJ_PLACEHOLDER_INFO = std::mem::zeroed(); + infos.FileBasicInfo = PRJ_FILE_BASIC_INFO { IsDirectory: if metadata.is_dir() { 1 } else { 0 }, FileSize: if metadata.is_dir() { - metadata.file_size() as i64 + 0 } else { ContentEnc::get_real_size(metadata.file_size()) as i64 }, - CreationTime: 0, - LastAccessTime: 0, - LastWriteTime: 0, - ChangeTime: 0, + CreationTime: metadata.creation_time() as i64, + LastAccessTime: metadata.last_access_time() as i64, + LastWriteTime: metadata.last_write_time() as i64, + ChangeTime: metadata.last_write_time() as i64, FileAttributes: 0, - }, - EaInformation: std::mem::zeroed(), - SecurityInformation: std::mem::zeroed(), - StreamsInformation: std::mem::zeroed(), - VersionInfo: std::mem::zeroed(), - VariableData: std::mem::zeroed(), }; let hr = PrjWritePlaceholderInfo( @@ -179,13 +236,12 @@ pub(crate) unsafe extern "system" fn get_placeholder_info_callback( std::mem::size_of_val(&infos) as u32, ); - trace!("{} {}", super::WinError(hr), std::mem::size_of_val(&infos)); - - 0 + hr } Err(e) => { log::trace!("{}", e); - 0x80004005u32 as i32 // TODO + + HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND) } } } From f68ffc811e45b74a0e4d6daeeff208894aed3c9c Mon Sep 17 00:00:00 2001 From: oupson Date: Sun, 3 Dec 2023 20:02:31 +0100 Subject: [PATCH 06/11] Small code cleanup --- rustcryptfs-projfs/src/projfs.rs | 37 +++++++++++++------------------- 1 file changed, 15 insertions(+), 22 deletions(-) diff --git a/rustcryptfs-projfs/src/projfs.rs b/rustcryptfs-projfs/src/projfs.rs index 29dee38..5f544f3 100644 --- a/rustcryptfs-projfs/src/projfs.rs +++ b/rustcryptfs-projfs/src/projfs.rs @@ -1,11 +1,10 @@ use std::{ cmp::Ordering, - ffi::{c_ulong, CStr, CString, OsString}, - fs::{DirEntry, File, ReadDir}, + ffi::{c_ulong, OsString}, + fs::{DirEntry, File}, io::{Read, Seek, SeekFrom}, os::windows::{fs::MetadataExt, prelude::OsStringExt}, path::PathBuf, - slice::Iter, }; use log::trace; @@ -16,10 +15,9 @@ use windows_sys::{ Foundation::ERROR_FILE_NOT_FOUND, Storage::ProjectedFileSystem::{ PrjAllocateAlignedBuffer, PrjFileNameCompare, PrjFillDirEntryBuffer, - PrjFillDirEntryBuffer2, PrjFreeAlignedBuffer, PrjGetVirtualizationInstanceInfo, - PrjWriteFileData, PrjWritePlaceholderInfo, PRJ_CALLBACK_DATA, - PRJ_CB_DATA_FLAG_ENUM_RESTART_SCAN, PRJ_DIR_ENTRY_BUFFER_HANDLE, PRJ_FILE_BASIC_INFO, - PRJ_PLACEHOLDER_INFO, + PrjFreeAlignedBuffer, PrjGetVirtualizationInstanceInfo, PrjWriteFileData, + PrjWritePlaceholderInfo, PRJ_CALLBACK_DATA, PRJ_CB_DATA_FLAG_ENUM_RESTART_SCAN, + PRJ_DIR_ENTRY_BUFFER_HANDLE, PRJ_FILE_BASIC_INFO, PRJ_PLACEHOLDER_INFO, }, System::Diagnostics::Debug::FACILITY_WIN32, }, @@ -46,7 +44,6 @@ unsafe fn u16_ptr_to_string(ptr: *const u16) -> OsString { } pub(crate) struct DirEnumData { - diriv: [u8; 16], last_entry: Option<(Vec, PRJ_FILE_BASIC_INFO)>, entries: Vec<(Vec, DirEntry)>, iter_index: Option, @@ -79,7 +76,6 @@ pub(crate) unsafe extern "system" fn start_enum_callback( .filter_map(|e| e.ok()) .filter(|e| e.file_name() != "gocryptfs.conf" && e.file_name() != "gocryptfs.diriv") .map(|entry| { - log::trace!("{:?}", entry.file_name()); ( instance_context .fs @@ -109,7 +105,6 @@ pub(crate) unsafe extern "system" fn start_enum_callback( instance_context.enum_map.insert( crate::WinGuid(*enumeration_id), DirEnumData { - diriv: iv, last_entry: None, entries, iter_index: None, @@ -135,10 +130,12 @@ pub(crate) unsafe extern "system" fn end_enum_callback( 0 } + +// TODO : Search expression pub(crate) unsafe extern "system" fn get_enum_callback( callback_data: *const PRJ_CALLBACK_DATA, enumeration_id: *const GUID, - search_expression: PCWSTR, + _search_expression: PCWSTR, dir_entry_buffer_handle: PRJ_DIR_ENTRY_BUFFER_HANDLE, ) -> ::windows_sys::core::HRESULT { let callback_data = &*callback_data; @@ -163,7 +160,7 @@ pub(crate) unsafe extern "system" fn get_enum_callback( if let Some((last_filename, last_info)) = std::mem::replace(&mut data.last_entry, None) { PrjFillDirEntryBuffer(last_filename.as_ptr(), &last_info, dir_entry_buffer_handle); - } + } while last_index < data.entries.len() { let (filename, entry) = &data.entries[last_index]; @@ -210,23 +207,21 @@ pub(crate) unsafe extern "system" fn get_placeholder_info_callback( let path = instance_context.get_path(filename); - log::trace!("real path : {:?}", path); - match path.metadata() { Ok(metadata) => { let mut infos: PRJ_PLACEHOLDER_INFO = std::mem::zeroed(); infos.FileBasicInfo = PRJ_FILE_BASIC_INFO { - IsDirectory: if metadata.is_dir() { 1 } else { 0 }, - FileSize: if metadata.is_dir() { + IsDirectory: if metadata.is_dir() { 1 } else { 0 }, + FileSize: if metadata.is_dir() { 0 - } else { - ContentEnc::get_real_size(metadata.file_size()) as i64 - }, + } else { + ContentEnc::get_real_size(metadata.file_size()) as i64 + }, CreationTime: metadata.creation_time() as i64, LastAccessTime: metadata.last_access_time() as i64, LastWriteTime: metadata.last_write_time() as i64, ChangeTime: metadata.last_write_time() as i64, - FileAttributes: 0, + FileAttributes: 0, }; let hr = PrjWritePlaceholderInfo( @@ -264,8 +259,6 @@ pub(crate) unsafe extern "system" fn get_file_data_callback( let path = instance_context.get_path(filename); - log::trace!("real path : {:?}", path); - let size = length as usize; let mut file = File::open(path).unwrap(); From b39c0030710132ce4794bae063e75d0f775ecbdb Mon Sep 17 00:00:00 2001 From: oupson Date: Thu, 7 Dec 2023 10:00:45 +0100 Subject: [PATCH 07/11] Improve reading of files --- rustcryptfs-fuse/src/error.rs | 3 +- rustcryptfs-lib/src/config/mod.rs | 2 +- rustcryptfs-lib/src/content/mod.rs | 4 +- rustcryptfs-projfs/src/lib.rs | 32 +++++--- rustcryptfs-projfs/src/projfs.rs | 60 +++++--------- rustcryptfs-projfs/src/write_buffer.rs | 105 +++++++++++++++++++++++++ rustcryptfs/src/args.rs | 12 +-- 7 files changed, 152 insertions(+), 66 deletions(-) create mode 100644 rustcryptfs-projfs/src/write_buffer.rs diff --git a/rustcryptfs-fuse/src/error.rs b/rustcryptfs-fuse/src/error.rs index 13b06cf..c754927 100644 --- a/rustcryptfs-fuse/src/error.rs +++ b/rustcryptfs-fuse/src/error.rs @@ -15,7 +15,6 @@ pub enum Error { RustCryptFsFilenameError(#[from] FilenameCipherError), } - pub(crate) trait ErrorExt { fn to_raw_code(&self) -> i32; } @@ -30,4 +29,4 @@ impl ErrorExt for rustcryptfs_lib::error::Error { rustcryptfs_lib::error::Error::IoError(e) => e.raw_os_error().unwrap(), } } -} \ No newline at end of file +} diff --git a/rustcryptfs-lib/src/config/mod.rs b/rustcryptfs-lib/src/config/mod.rs index 656990b..a970c4c 100644 --- a/rustcryptfs-lib/src/config/mod.rs +++ b/rustcryptfs-lib/src/config/mod.rs @@ -71,7 +71,7 @@ impl CryptConf { /// See gocryptfs documentation about [master key](https://nuetzlich.net/gocryptfs/forward_mode_crypto/#master-key-storage). /// /// ![TODO NAME THIS IMAGE](https://nuetzlich.net/gocryptfs/img/master-key.svg) - /// + /// /// # Errors /// Return an error when the master key don't have the required size or if the decrypting failed. pub fn get_master_key(&self, password: &[u8]) -> Result<[u8; 32], ConfigError> { diff --git a/rustcryptfs-lib/src/content/mod.rs b/rustcryptfs-lib/src/content/mod.rs index fb03c75..1c0f14b 100644 --- a/rustcryptfs-lib/src/content/mod.rs +++ b/rustcryptfs-lib/src/content/mod.rs @@ -19,7 +19,7 @@ pub struct ContentEnc { impl ContentEnc { /// Init a new `ContentEnc` from the master key and the iv len. - /// + /// /// # Errors /// Return an error if the filename key cannot be derived from the `master_key`. pub fn new(master_key: &[u8], iv_len: u8) -> Result { @@ -35,7 +35,7 @@ impl ContentEnc { /// Decrypt a encrypted block of len (`iv_len` + `decrypted_block_size` + `iv_len`), with the block number and the file id. /// The content of block is replaced with the plain text, in form of iv + plaintext + tag. - /// + /// /// # Errors /// Return an error if `block` is too short, or if the nonce is full of 0, or if the decrypting failed. pub fn decrypt_block<'a>( diff --git a/rustcryptfs-projfs/src/lib.rs b/rustcryptfs-projfs/src/lib.rs index e1a37f5..9360427 100644 --- a/rustcryptfs-projfs/src/lib.rs +++ b/rustcryptfs-projfs/src/lib.rs @@ -1,22 +1,22 @@ -use std::collections::HashMap; -use std::ffi::{CStr, CString, OsString}; -use std::fs::File; -use std::hash::{Hash, Hasher}; -use std::io::Read; -use std::iter::Map; -use std::path::PathBuf; use std::{ - error::Error, fmt::Display, mem::MaybeUninit, os::windows::prelude::OsStrExt, path::Path, + collections::HashMap, + error::Error, + ffi::CStr, + fmt::Display, + fs::File, + hash::{Hash, Hasher}, + io::Read, + mem::MaybeUninit, + os::{raw::c_void, windows::prelude::OsStrExt}, + path::{Path, PathBuf}, + slice, + sync::mpsc::channel, }; -use std::sync::mpsc::channel; - -use libc::c_void; use rustcryptfs_lib::GocryptFs; use error::Result; use rustcryptfs_lib::filename::EncodedFilename; -use windows_sys::Win32::Foundation::GetLastError; use windows_sys::Win32::Storage::ProjectedFileSystem::PRJ_PLACEHOLDER_VERSION_INFO; use windows_sys::Win32::System::Diagnostics::Debug::{ FormatMessageA, FORMAT_MESSAGE_ALLOCATE_BUFFER, FORMAT_MESSAGE_FROM_SYSTEM, @@ -35,6 +35,7 @@ use windows_sys::{ pub mod error; mod projfs; +pub(crate) mod write_buffer; #[repr(transparent)] #[derive(Debug)] @@ -57,7 +58,12 @@ impl Display for WinError { ) }; - let buffer = unsafe { CStr::from_ptr(buffer) }; + let buffer = unsafe { + CStr::from_bytes_with_nul_unchecked(slice::from_raw_parts( + buffer as *mut u8, + (size + 1) as usize, + )) + }; write!( f, diff --git a/rustcryptfs-projfs/src/projfs.rs b/rustcryptfs-projfs/src/projfs.rs index 5f544f3..3ba719a 100644 --- a/rustcryptfs-projfs/src/projfs.rs +++ b/rustcryptfs-projfs/src/projfs.rs @@ -14,10 +14,9 @@ use windows_sys::{ Win32::{ Foundation::ERROR_FILE_NOT_FOUND, Storage::ProjectedFileSystem::{ - PrjAllocateAlignedBuffer, PrjFileNameCompare, PrjFillDirEntryBuffer, - PrjFreeAlignedBuffer, PrjGetVirtualizationInstanceInfo, PrjWriteFileData, - PrjWritePlaceholderInfo, PRJ_CALLBACK_DATA, PRJ_CB_DATA_FLAG_ENUM_RESTART_SCAN, - PRJ_DIR_ENTRY_BUFFER_HANDLE, PRJ_FILE_BASIC_INFO, PRJ_PLACEHOLDER_INFO, + PrjFileNameCompare, PrjFillDirEntryBuffer, PrjWritePlaceholderInfo, PRJ_CALLBACK_DATA, + PRJ_CB_DATA_FLAG_ENUM_RESTART_SCAN, PRJ_DIR_ENTRY_BUFFER_HANDLE, PRJ_FILE_BASIC_INFO, + PRJ_PLACEHOLDER_INFO, }, System::Diagnostics::Debug::FACILITY_WIN32, }, @@ -26,7 +25,7 @@ use windows_sys::{ // TODO windows::core::HRESULT #[inline] -pub fn HRESULT_FROM_WIN32(x: c_ulong) -> HRESULT { +pub fn hresult_from_win32(x: c_ulong) -> HRESULT { if x as i32 <= 0 { x as i32 } else { @@ -56,11 +55,7 @@ pub(crate) unsafe extern "system" fn start_enum_callback( let callback_data = &*callback_data; let instance_context = &mut *(callback_data.InstanceContext as *mut EncryptedFs); let filename = PathBuf::from(u16_ptr_to_string(callback_data.FilePathName)); - log::trace!( - "start_enum_callback called for {:?} {}", - filename, - *callback_data.FilePathName - ); + log::trace!("start_enum_callback called",); let path = instance_context.get_path(filename); @@ -130,7 +125,6 @@ pub(crate) unsafe extern "system" fn end_enum_callback( 0 } - // TODO : Search expression pub(crate) unsafe extern "system" fn get_enum_callback( callback_data: *const PRJ_CALLBACK_DATA, @@ -178,7 +172,7 @@ pub(crate) unsafe extern "system" fn get_enum_callback( LastAccessTime: metadata.last_access_time() as i64, LastWriteTime: metadata.last_write_time() as i64, ChangeTime: metadata.last_write_time() as i64, - FileAttributes: 0, + FileAttributes: metadata.file_attributes(), }; // TODO check if HRESULT_FROM_WIN32(ERROR_INSUFFICIENT_BUFFER) @@ -203,7 +197,7 @@ pub(crate) unsafe extern "system" fn get_placeholder_info_callback( let instance_context = &mut *(callback_data.InstanceContext as *mut EncryptedFs); let filename = PathBuf::from(u16_ptr_to_string(callback_data.FilePathName)); - log::trace!("get_placeholder_info_callback called : {:?}", filename); + log::trace!("get_placeholder_info_callback called"); let path = instance_context.get_path(filename); @@ -221,7 +215,7 @@ pub(crate) unsafe extern "system" fn get_placeholder_info_callback( LastAccessTime: metadata.last_access_time() as i64, LastWriteTime: metadata.last_write_time() as i64, ChangeTime: metadata.last_write_time() as i64, - FileAttributes: 0, + FileAttributes: metadata.file_attributes(), }; let hr = PrjWritePlaceholderInfo( @@ -236,7 +230,7 @@ pub(crate) unsafe extern "system" fn get_placeholder_info_callback( Err(e) => { log::trace!("{}", e); - HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND) + hresult_from_win32(ERROR_FILE_NOT_FOUND) } } } @@ -250,14 +244,7 @@ pub(crate) unsafe extern "system" fn get_file_data_callback( let instance_context = &mut *(callback_data.InstanceContext as *mut EncryptedFs); let filename = PathBuf::from(u16_ptr_to_string(callback_data.FilePathName)); - let mut infos = std::mem::zeroed(); - PrjGetVirtualizationInstanceInfo(callback_data.NamespaceVirtualizationContext, &mut infos); - - trace!("{}", infos.WriteAlignment); - - log::trace!("get_file_data_callback called : {:?}", filename); - - let path = instance_context.get_path(filename); + let path = instance_context.get_path(filename.clone()); let size = length as usize; @@ -270,10 +257,13 @@ pub(crate) unsafe extern "system" fn get_file_data_callback( let mut block_index = byte_offset / 4096; - let mut buffer = Vec::with_capacity(size); - let mut rem = size; + let mut writter = crate::write_buffer::WriteBuffer::new( + callback_data.NamespaceVirtualizationContext, + callback_data.DataStreamId, + byte_offset, + ); let mut buf = [0u8; 4096 + 32]; file.seek(SeekFrom::Start(18 + block_index * (4096 + 32))) @@ -287,8 +277,8 @@ pub(crate) unsafe extern "system" fn get_file_data_callback( .unwrap(); let seek = (byte_offset as u64 - block_index * 4096) as usize; - buffer.extend_from_slice(&res[seek..]); + writter.append_buf(&res[seek..]); block_index += 1; rem -= res.len() - seek; @@ -307,28 +297,14 @@ pub(crate) unsafe extern "system" fn get_file_data_callback( let size = res.len().min(rem); - buffer.extend_from_slice(&res[..size]); + writter.append_buf(&res[..size]); block_index += 1; rem -= size; } - let prjbuf = - PrjAllocateAlignedBuffer(callback_data.NamespaceVirtualizationContext, buffer.len()) - as *mut u8; - - prjbuf.copy_from(buffer.as_ptr(), buffer.len()); - - PrjWriteFileData( - callback_data.NamespaceVirtualizationContext, - &callback_data.DataStreamId, - prjbuf as *mut _, - byte_offset, - buffer.len() as u32, - ); - - PrjFreeAlignedBuffer(prjbuf as *mut _); + writter.finish(); 0 } diff --git a/rustcryptfs-projfs/src/write_buffer.rs b/rustcryptfs-projfs/src/write_buffer.rs new file mode 100644 index 0000000..f4c9adf --- /dev/null +++ b/rustcryptfs-projfs/src/write_buffer.rs @@ -0,0 +1,105 @@ +use std::ffi::c_void; + +use windows_sys::{ + core::GUID, + Win32::Storage::ProjectedFileSystem::{ + PrjAllocateAlignedBuffer, PrjFreeAlignedBuffer, PrjGetVirtualizationInstanceInfo, + PrjWriteFileData, PRJ_VIRTUALIZATION_INSTANCE_INFO, + }, +}; + +pub(crate) struct WriteBuffer { + buffer_size: usize, + namespace_virtualization_context: isize, + data_stream_id: GUID, + prjfs_buf: *mut c_void, + file_offset: u64, + offset: usize, +} + +impl WriteBuffer { + pub(crate) fn new( + namespace_virtualization_context: isize, + data_stream_id: GUID, + file_offset: u64, + ) -> Self { + let (size, buf) = unsafe { + let mut info: PRJ_VIRTUALIZATION_INSTANCE_INFO = std::mem::zeroed(); + PrjGetVirtualizationInstanceInfo(namespace_virtualization_context, &mut info); + + let size = (info.WriteAlignment * 100) as usize; + ( + size, + PrjAllocateAlignedBuffer(namespace_virtualization_context, size), + ) + }; + + Self { + buffer_size: size, + namespace_virtualization_context, + data_stream_id, + prjfs_buf: buf, + file_offset, + offset: 0, + } + } + + pub(crate) fn append_buf(&mut self, buf: &[u8]) -> usize { + let mut remaining_buf = buf; + let mut written = 0; + + while !remaining_buf.is_empty() { + let to_copy = (self.buffer_size - self.offset).min(remaining_buf.len()); + + unsafe { + (self.prjfs_buf as *mut u8) + .offset(self.offset as isize) + .copy_from(remaining_buf.as_ptr(), to_copy); + } + + self.offset += to_copy; + + if self.offset == self.buffer_size { + unsafe { + PrjWriteFileData( + self.namespace_virtualization_context, + &self.data_stream_id, + self.prjfs_buf, + self.file_offset, + self.buffer_size as u32, + ) + }; + + self.file_offset += self.buffer_size as u64; + self.offset = 0; + written += self.buffer_size; + }; + + remaining_buf = &remaining_buf[to_copy..]; + } + written + } + + pub(crate) fn finish(&mut self) -> usize { + let written = self.offset; + unsafe { + PrjWriteFileData( + self.namespace_virtualization_context, + &self.data_stream_id, + self.prjfs_buf, + self.file_offset, + self.offset as u32, + ) + }; + self.file_offset += self.offset as u64; + self.offset = 0; + written + } +} + +impl Drop for WriteBuffer { + fn drop(&mut self) { + unsafe { PrjFreeAlignedBuffer(self.prjfs_buf) }; + self.prjfs_buf = std::ptr::null_mut(); + } +} diff --git a/rustcryptfs/src/args.rs b/rustcryptfs/src/args.rs index b21f2b2..45464f1 100644 --- a/rustcryptfs/src/args.rs +++ b/rustcryptfs/src/args.rs @@ -27,29 +27,29 @@ pub(crate) enum Commands { #[derive(Debug, Parser)] pub(crate) struct DecryptCommand { /// The file to decrypt - pub(crate) file_path : String, + pub(crate) file_path: String, /// Path to the gocryptfs directory #[clap(short('g'), long)] - pub(crate) gocryptfs_path : Option, + pub(crate) gocryptfs_path: Option, /// The password #[clap(short, long)] - pub(crate) password : Option + pub(crate) password: Option, } #[derive(Debug, Parser)] pub(crate) struct LsCommand { /// The directory - pub(crate) folder_path : String, + pub(crate) folder_path: String, /// Path to the gocryptfs directory #[clap(short('g'), long)] - pub(crate) gocryptfs_path : Option, + pub(crate) gocryptfs_path: Option, /// The password #[clap(short, long)] - pub(crate) password : Option + pub(crate) password: Option, } #[cfg(feature = "mount")] From 9900ab55ada39d1a2b5b641a538229d346da82ca Mon Sep 17 00:00:00 2001 From: oupson Date: Thu, 7 Dec 2023 19:58:36 +0100 Subject: [PATCH 08/11] Clean mount point on stop --- rustcryptfs-projfs/src/lib.rs | 114 +++++++++++++++++++++++++++++-- rustcryptfs-projfs/src/projfs.rs | 4 ++ 2 files changed, 111 insertions(+), 7 deletions(-) diff --git a/rustcryptfs-projfs/src/lib.rs b/rustcryptfs-projfs/src/lib.rs index 9360427..b266960 100644 --- a/rustcryptfs-projfs/src/lib.rs +++ b/rustcryptfs-projfs/src/lib.rs @@ -2,7 +2,7 @@ use std::{ collections::HashMap, error::Error, ffi::CStr, - fmt::Display, + fmt::{Debug, Display}, fs::File, hash::{Hash, Hasher}, io::Read, @@ -10,14 +10,19 @@ use std::{ os::{raw::c_void, windows::prelude::OsStrExt}, path::{Path, PathBuf}, slice, - sync::mpsc::channel, + sync::{atomic::AtomicBool, mpsc::channel}, }; +use log::{info, trace, warn}; use rustcryptfs_lib::GocryptFs; use error::Result; use rustcryptfs_lib::filename::EncodedFilename; -use windows_sys::Win32::Storage::ProjectedFileSystem::PRJ_PLACEHOLDER_VERSION_INFO; +use windows_sys::Win32::Storage::ProjectedFileSystem::{ + PrjDeleteFile, PrjGetOnDiskFileState, PRJ_FILE_STATE, PRJ_PLACEHOLDER_VERSION_INFO, + PRJ_UPDATE_ALLOW_DIRTY_DATA, PRJ_UPDATE_ALLOW_DIRTY_METADATA, PRJ_UPDATE_ALLOW_READ_ONLY, + PRJ_UPDATE_ALLOW_TOMBSTONE, +}; use windows_sys::Win32::System::Diagnostics::Debug::{ FormatMessageA, FORMAT_MESSAGE_ALLOCATE_BUFFER, FORMAT_MESSAGE_FROM_SYSTEM, FORMAT_MESSAGE_IGNORE_INSERTS, @@ -38,7 +43,6 @@ mod projfs; pub(crate) mod write_buffer; #[repr(transparent)] -#[derive(Debug)] pub struct WinError(i32); impl Display for WinError { @@ -74,6 +78,37 @@ impl Display for WinError { } } +impl Debug for WinError { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + let mut buffer = std::ptr::null_mut(); + let size = unsafe { + FormatMessageA( + FORMAT_MESSAGE_ALLOCATE_BUFFER + | FORMAT_MESSAGE_FROM_SYSTEM + | FORMAT_MESSAGE_IGNORE_INSERTS, + std::ptr::null(), + self.0 as u32, + 0, + &mut buffer as *mut *mut i8 as *mut _, + 0, + std::ptr::null(), + ) + }; + + let buffer = unsafe { + CStr::from_bytes_with_nul_unchecked(slice::from_raw_parts( + buffer as *mut u8, + (size + 1) as usize, + )) + }; + + f.debug_struct("WinError") + .field("error_code", &format!("0x{:08X}", self.0)) + .field("msg", &buffer.to_string_lossy()) + .finish() + } +} + impl Error for WinError {} macro_rules! win_to_res { @@ -116,6 +151,7 @@ pub struct EncryptedFs { filename_map: HashMap, enum_map: HashMap, base_path: PathBuf, + is_stopping: AtomicBool, } impl EncryptedFs { @@ -176,7 +212,7 @@ impl EncryptedFs { { let path = path.as_ref(); - log::info!("Opening dir ..."); + info!("Opening dir ..."); let fs = GocryptFs::open(path, password)?; println!("Filesystem mounted and ready."); @@ -186,6 +222,7 @@ impl EncryptedFs { filename_map: Default::default(), enum_map: Default::default(), base_path: path.to_owned(), + is_stopping: AtomicBool::new(false), }) } @@ -193,11 +230,12 @@ impl EncryptedFs { where P: AsRef, { + let mountpoint = mountpoint.as_ref(); unsafe { let mut instance_id: GUID = MaybeUninit::zeroed().assume_init(); win_to_res!(CoCreateGuid(&mut instance_id))?; - let mut root_name: Vec = mountpoint.as_ref().as_os_str().encode_wide().collect(); + let mut root_name: Vec = mountpoint.as_os_str().encode_wide().collect(); root_name.push(0); let info: PRJ_PLACEHOLDER_VERSION_INFO = MaybeUninit::zeroed().assume_init(); @@ -230,7 +268,7 @@ impl EncryptedFs { &mut instance_handle ))?; - log::trace!("mounted"); + trace!("mounted"); let (tx, rx) = channel(); @@ -241,6 +279,12 @@ impl EncryptedFs { println!("Exiting ..."); + (*this) + .is_stopping + .store(true, std::sync::atomic::Ordering::Relaxed); + + delete_recursively(instance_handle, &mountpoint, &mountpoint)?; + PrjStopVirtualizing(instance_handle); drop(Box::from_raw(this)); @@ -248,3 +292,59 @@ impl EncryptedFs { Ok(()) } } + +unsafe fn delete_recursively( + instance: PRJ_NAMESPACE_VIRTUALIZATION_CONTEXT, + root_path: &Path, + path: &Path, +) -> Result<()> { + let mut iter = std::fs::read_dir(path)?.filter_map(|r| r.ok()); + while let Some(e) = iter.next() { + let mut file_state: PRJ_FILE_STATE = std::mem::zeroed(); + let wide_name = e + .path() + .as_os_str() + .encode_wide() + .chain(std::iter::once(0)) + .collect::>(); + + if win_to_res!(PrjGetOnDiskFileState(wide_name.as_ptr(), &mut file_state)).is_ok() { + let path = e.path(); + let delete_result = if e.file_type()?.is_dir() { + delete_recursively(instance, root_path, &path)?; + delete_file_from_projection(instance, path.strip_prefix(root_path).unwrap()) + } else { + delete_file_from_projection(instance, path.strip_prefix(root_path).unwrap()) + }; + + if let Err(e) = delete_result { + warn!("failed to delete a file : {}", e); + } + } + } + + Ok(()) +} + +fn delete_file_from_projection( + instance: PRJ_NAMESPACE_VIRTUALIZATION_CONTEXT, + filename: &Path, +) -> Result<()> { + let filename = filename + .as_os_str() + .encode_wide() + .chain(std::iter::once(0)) + .collect::>(); + unsafe { + win_to_res!(PrjDeleteFile( + instance, + filename.as_ptr(), + PRJ_UPDATE_ALLOW_DIRTY_DATA + | PRJ_UPDATE_ALLOW_DIRTY_METADATA + | PRJ_UPDATE_ALLOW_READ_ONLY + | PRJ_UPDATE_ALLOW_TOMBSTONE, + std::ptr::null_mut() + ))?; + } + Ok(()) +} diff --git a/rustcryptfs-projfs/src/projfs.rs b/rustcryptfs-projfs/src/projfs.rs index 3ba719a..0544565 100644 --- a/rustcryptfs-projfs/src/projfs.rs +++ b/rustcryptfs-projfs/src/projfs.rs @@ -140,6 +140,10 @@ pub(crate) unsafe extern "system" fn get_enum_callback( callback_data.Flags & PRJ_CB_DATA_FLAG_ENUM_RESTART_SCAN ); + if instance_context.is_stopping.load(std::sync::atomic::Ordering::Relaxed) { + return 0; + } + let data = instance_context .enum_map .get_mut(&crate::WinGuid(*enumeration_id)) From 15411046dc0ebda27a592288822ab4d57a45b3e9 Mon Sep 17 00:00:00 2001 From: oupson Date: Thu, 7 Dec 2023 20:17:02 +0100 Subject: [PATCH 09/11] Use trait instead of macros for windows error handling --- rustcryptfs-projfs/src/error.rs | 95 ++++++++++++++++++++++++- rustcryptfs-projfs/src/lib.rs | 121 +++++--------------------------- 2 files changed, 112 insertions(+), 104 deletions(-) diff --git a/rustcryptfs-projfs/src/error.rs b/rustcryptfs-projfs/src/error.rs index b465903..077aee3 100644 --- a/rustcryptfs-projfs/src/error.rs +++ b/rustcryptfs-projfs/src/error.rs @@ -1,5 +1,15 @@ +use std::{ + ffi::CStr, + fmt::{Debug, Display}, + slice, +}; + use rustcryptfs_lib::filename::FilenameCipherError; use thiserror::Error; +use windows_sys::Win32::System::Diagnostics::Debug::{ + FormatMessageA, FORMAT_MESSAGE_ALLOCATE_BUFFER, FORMAT_MESSAGE_FROM_SYSTEM, + FORMAT_MESSAGE_IGNORE_INSERTS, +}; pub type Result = std::result::Result; @@ -9,7 +19,7 @@ pub enum Error { IoError(#[from] std::io::Error), #[error(transparent)] - WindowsError(#[from] super::WinError), + WindowsError(#[from] WinError), #[error(transparent)] RustCryptFsError(#[from] rustcryptfs_lib::error::Error), @@ -17,3 +27,86 @@ pub enum Error { #[error(transparent)] RustCryptFsFilenameError(#[from] FilenameCipherError), } + +#[repr(transparent)] +pub struct WinError(pub i32); + +impl Display for WinError { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + let mut buffer = std::ptr::null_mut(); + let size = unsafe { + FormatMessageA( + FORMAT_MESSAGE_ALLOCATE_BUFFER + | FORMAT_MESSAGE_FROM_SYSTEM + | FORMAT_MESSAGE_IGNORE_INSERTS, + std::ptr::null(), + self.0 as u32, + 0, + &mut buffer as *mut *mut i8 as *mut _, + 0, + std::ptr::null(), + ) + }; + + let buffer = unsafe { + CStr::from_bytes_with_nul_unchecked(slice::from_raw_parts( + buffer as *mut u8, + (size + 1) as usize, + )) + }; + + write!( + f, + "Windows Error : 0x{:08X} :{}", + self.0, + buffer.to_string_lossy() + ) + } +} + +impl Debug for WinError { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + let mut buffer = std::ptr::null_mut(); + let size = unsafe { + FormatMessageA( + FORMAT_MESSAGE_ALLOCATE_BUFFER + | FORMAT_MESSAGE_FROM_SYSTEM + | FORMAT_MESSAGE_IGNORE_INSERTS, + std::ptr::null(), + self.0 as u32, + 0, + &mut buffer as *mut *mut i8 as *mut _, + 0, + std::ptr::null(), + ) + }; + + let buffer = unsafe { + CStr::from_bytes_with_nul_unchecked(slice::from_raw_parts( + buffer as *mut u8, + (size + 1) as usize, + )) + }; + + f.debug_struct("WinError") + .field("error_code", &format!("0x{:08X}", self.0)) + .field("msg", &buffer.to_string_lossy()) + .finish() + } +} + +impl std::error::Error for WinError {} + +pub trait ToWinResult: Sized { + fn to_win_result(self) -> std::result::Result; +} + +impl ToWinResult for i32 { + fn to_win_result(self) -> std::result::Result { + if self < 0 { + Err(crate::error::WinError(self)) + } else { + Ok(self) + } + } +} diff --git a/rustcryptfs-projfs/src/lib.rs b/rustcryptfs-projfs/src/lib.rs index b266960..ccef8ce 100644 --- a/rustcryptfs-projfs/src/lib.rs +++ b/rustcryptfs-projfs/src/lib.rs @@ -1,15 +1,11 @@ use std::{ collections::HashMap, - error::Error, - ffi::CStr, - fmt::{Debug, Display}, fs::File, hash::{Hash, Hasher}, io::Read, mem::MaybeUninit, os::{raw::c_void, windows::prelude::OsStrExt}, path::{Path, PathBuf}, - slice, sync::{atomic::AtomicBool, mpsc::channel}, }; @@ -23,10 +19,7 @@ use windows_sys::Win32::Storage::ProjectedFileSystem::{ PRJ_UPDATE_ALLOW_DIRTY_DATA, PRJ_UPDATE_ALLOW_DIRTY_METADATA, PRJ_UPDATE_ALLOW_READ_ONLY, PRJ_UPDATE_ALLOW_TOMBSTONE, }; -use windows_sys::Win32::System::Diagnostics::Debug::{ - FormatMessageA, FORMAT_MESSAGE_ALLOCATE_BUFFER, FORMAT_MESSAGE_FROM_SYSTEM, - FORMAT_MESSAGE_IGNORE_INSERTS, -}; + use windows_sys::{ core::GUID, Win32::{ @@ -38,91 +31,12 @@ use windows_sys::{ }, }; +use crate::error::ToWinResult; + pub mod error; mod projfs; pub(crate) mod write_buffer; -#[repr(transparent)] -pub struct WinError(i32); - -impl Display for WinError { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - let mut buffer = std::ptr::null_mut(); - let size = unsafe { - FormatMessageA( - FORMAT_MESSAGE_ALLOCATE_BUFFER - | FORMAT_MESSAGE_FROM_SYSTEM - | FORMAT_MESSAGE_IGNORE_INSERTS, - std::ptr::null(), - self.0 as u32, - 0, - &mut buffer as *mut *mut i8 as *mut _, - 0, - std::ptr::null(), - ) - }; - - let buffer = unsafe { - CStr::from_bytes_with_nul_unchecked(slice::from_raw_parts( - buffer as *mut u8, - (size + 1) as usize, - )) - }; - - write!( - f, - "Windows Error : 0x{:08X} :{}", - self.0, - buffer.to_string_lossy() - ) - } -} - -impl Debug for WinError { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - let mut buffer = std::ptr::null_mut(); - let size = unsafe { - FormatMessageA( - FORMAT_MESSAGE_ALLOCATE_BUFFER - | FORMAT_MESSAGE_FROM_SYSTEM - | FORMAT_MESSAGE_IGNORE_INSERTS, - std::ptr::null(), - self.0 as u32, - 0, - &mut buffer as *mut *mut i8 as *mut _, - 0, - std::ptr::null(), - ) - }; - - let buffer = unsafe { - CStr::from_bytes_with_nul_unchecked(slice::from_raw_parts( - buffer as *mut u8, - (size + 1) as usize, - )) - }; - - f.debug_struct("WinError") - .field("error_code", &format!("0x{:08X}", self.0)) - .field("msg", &buffer.to_string_lossy()) - .finish() - } -} - -impl Error for WinError {} - -macro_rules! win_to_res { - ($l:expr) => {{ - let res = $l; - - if (res < 0) { - Err(WinError(res)) - } else { - Ok(res) - } - }}; -} - #[repr(transparent)] struct WinGuid(GUID); @@ -233,7 +147,7 @@ impl EncryptedFs { let mountpoint = mountpoint.as_ref(); unsafe { let mut instance_id: GUID = MaybeUninit::zeroed().assume_init(); - win_to_res!(CoCreateGuid(&mut instance_id))?; + CoCreateGuid(&mut instance_id).to_win_result()?; let mut root_name: Vec = mountpoint.as_os_str().encode_wide().collect(); root_name.push(0); @@ -241,12 +155,8 @@ impl EncryptedFs { let info: PRJ_PLACEHOLDER_VERSION_INFO = MaybeUninit::zeroed().assume_init(); let ptr = root_name.as_ptr(); - win_to_res!(PrjMarkDirectoryAsPlaceholder( - ptr, - std::ptr::null(), - &info, - &instance_id - ))?; + PrjMarkDirectoryAsPlaceholder(ptr, std::ptr::null(), &info, &instance_id) + .to_win_result()?; let mut callback_table: PRJ_CALLBACKS = MaybeUninit::zeroed().assume_init(); @@ -260,13 +170,14 @@ impl EncryptedFs { let mut instance_handle: PRJ_NAMESPACE_VIRTUALIZATION_CONTEXT = MaybeUninit::zeroed().assume_init(); - win_to_res!(PrjStartVirtualizing( + PrjStartVirtualizing( ptr, &callback_table, this as *const c_void, std::ptr::null(), - &mut instance_handle - ))?; + &mut instance_handle, + ) + .to_win_result()?; trace!("mounted"); @@ -308,7 +219,10 @@ unsafe fn delete_recursively( .chain(std::iter::once(0)) .collect::>(); - if win_to_res!(PrjGetOnDiskFileState(wide_name.as_ptr(), &mut file_state)).is_ok() { + if PrjGetOnDiskFileState(wide_name.as_ptr(), &mut file_state) + .to_win_result() + .is_ok() + { let path = e.path(); let delete_result = if e.file_type()?.is_dir() { delete_recursively(instance, root_path, &path)?; @@ -336,15 +250,16 @@ fn delete_file_from_projection( .chain(std::iter::once(0)) .collect::>(); unsafe { - win_to_res!(PrjDeleteFile( + PrjDeleteFile( instance, filename.as_ptr(), PRJ_UPDATE_ALLOW_DIRTY_DATA | PRJ_UPDATE_ALLOW_DIRTY_METADATA | PRJ_UPDATE_ALLOW_READ_ONLY | PRJ_UPDATE_ALLOW_TOMBSTONE, - std::ptr::null_mut() - ))?; + std::ptr::null_mut(), + ) + .to_win_result()?; } Ok(()) } From 8ee94a1f97e615f774c67d9d8d62e28e44d2e96a Mon Sep 17 00:00:00 2001 From: oupson Date: Sat, 9 Dec 2023 15:38:54 +0100 Subject: [PATCH 10/11] Add windows to readme and small cleanups --- Cargo.toml | 1 + README.md | 4 ++-- rustcryptfs-projfs/src/lib.rs | 4 +--- rustcryptfs-projfs/src/projfs.rs | 15 +++++---------- 4 files changed, 9 insertions(+), 15 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 29f9886..bae08e5 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,4 +1,5 @@ [workspace] +resolver = "2" members = [ "rustcryptfs", "rustcryptfs-lib", diff --git a/README.md b/README.md index f9f1b75..af13151 100644 --- a/README.md +++ b/README.md @@ -5,8 +5,8 @@ An implementation of [gocryptfs](https://github.com/rfjakob/gocryptfs) in Rust. - [x] Linux (via FUSE) - [x] read - [ ] write -- [ ] Windows - - [ ] read +- [x] Windows + - [x] read - [ ] write ## Features diff --git a/rustcryptfs-projfs/src/lib.rs b/rustcryptfs-projfs/src/lib.rs index ccef8ce..6e2e981 100644 --- a/rustcryptfs-projfs/src/lib.rs +++ b/rustcryptfs-projfs/src/lib.rs @@ -9,7 +9,7 @@ use std::{ sync::{atomic::AtomicBool, mpsc::channel}, }; -use log::{info, trace, warn}; +use log::{info, warn}; use rustcryptfs_lib::GocryptFs; use error::Result; @@ -179,8 +179,6 @@ impl EncryptedFs { ) .to_win_result()?; - trace!("mounted"); - let (tx, rx) = channel(); ctrlc::set_handler(move || tx.send(()).expect("Could not send signal on channel.")) diff --git a/rustcryptfs-projfs/src/projfs.rs b/rustcryptfs-projfs/src/projfs.rs index 0544565..54c329c 100644 --- a/rustcryptfs-projfs/src/projfs.rs +++ b/rustcryptfs-projfs/src/projfs.rs @@ -52,10 +52,10 @@ pub(crate) unsafe extern "system" fn start_enum_callback( callback_data: *const PRJ_CALLBACK_DATA, enumeration_id: *const GUID, ) -> HRESULT { + trace!("start_enum_callback"); let callback_data = &*callback_data; let instance_context = &mut *(callback_data.InstanceContext as *mut EncryptedFs); let filename = PathBuf::from(u16_ptr_to_string(callback_data.FilePathName)); - log::trace!("start_enum_callback called",); let path = instance_context.get_path(filename); @@ -113,8 +113,7 @@ pub(crate) unsafe extern "system" fn end_enum_callback( callback_data: *const PRJ_CALLBACK_DATA, enumeration_id: *const GUID, ) -> HRESULT { - log::trace!("end_enum_callback called"); - + trace!("end_enum_callback"); let callback_data = &*callback_data; let instance_context = &mut *(callback_data.InstanceContext as *mut EncryptedFs); @@ -132,14 +131,10 @@ pub(crate) unsafe extern "system" fn get_enum_callback( _search_expression: PCWSTR, dir_entry_buffer_handle: PRJ_DIR_ENTRY_BUFFER_HANDLE, ) -> ::windows_sys::core::HRESULT { + trace!("get_enum_callback"); let callback_data = &*callback_data; let instance_context = &mut *(callback_data.InstanceContext as *mut EncryptedFs); - log::debug!( - "get_enum_callback called : {}", - callback_data.Flags & PRJ_CB_DATA_FLAG_ENUM_RESTART_SCAN - ); - if instance_context.is_stopping.load(std::sync::atomic::Ordering::Relaxed) { return 0; } @@ -197,12 +192,11 @@ pub(crate) unsafe extern "system" fn get_enum_callback( pub(crate) unsafe extern "system" fn get_placeholder_info_callback( callback_data: *const PRJ_CALLBACK_DATA, ) -> ::windows_sys::core::HRESULT { + trace!("get_placeholder_info_callback"); let callback_data = &*callback_data; let instance_context = &mut *(callback_data.InstanceContext as *mut EncryptedFs); let filename = PathBuf::from(u16_ptr_to_string(callback_data.FilePathName)); - log::trace!("get_placeholder_info_callback called"); - let path = instance_context.get_path(filename); match path.metadata() { @@ -244,6 +238,7 @@ pub(crate) unsafe extern "system" fn get_file_data_callback( byte_offset: u64, length: u32, ) -> HRESULT { + trace!("get_file_data_callback"); let callback_data = &*callback_data; let instance_context = &mut *(callback_data.InstanceContext as *mut EncryptedFs); let filename = PathBuf::from(u16_ptr_to_string(callback_data.FilePathName)); From 4ee7af162d41dafd3bf1ab2222e948ef942d283e Mon Sep 17 00:00:00 2001 From: oupson Date: Sat, 9 Dec 2023 15:57:25 +0100 Subject: [PATCH 11/11] Implement file searching --- rustcryptfs-projfs/src/projfs.rs | 50 +++++++++++++++++++++++++++----- 1 file changed, 43 insertions(+), 7 deletions(-) diff --git a/rustcryptfs-projfs/src/projfs.rs b/rustcryptfs-projfs/src/projfs.rs index 54c329c..6f96390 100644 --- a/rustcryptfs-projfs/src/projfs.rs +++ b/rustcryptfs-projfs/src/projfs.rs @@ -7,12 +7,12 @@ use std::{ path::PathBuf, }; -use log::trace; +use log::{trace, warn}; use rustcryptfs_lib::content::ContentEnc; use windows_sys::{ core::{GUID, HRESULT, PCWSTR}, Win32::{ - Foundation::ERROR_FILE_NOT_FOUND, + Foundation::{ERROR_FILE_NOT_FOUND, E_INVALIDARG}, Storage::ProjectedFileSystem::{ PrjFileNameCompare, PrjFillDirEntryBuffer, PrjWritePlaceholderInfo, PRJ_CALLBACK_DATA, PRJ_CB_DATA_FLAG_ENUM_RESTART_SCAN, PRJ_DIR_ENTRY_BUFFER_HANDLE, PRJ_FILE_BASIC_INFO, @@ -46,6 +46,7 @@ pub(crate) struct DirEnumData { last_entry: Option<(Vec, PRJ_FILE_BASIC_INFO)>, entries: Vec<(Vec, DirEntry)>, iter_index: Option, + search_expression: Option>, } pub(crate) unsafe extern "system" fn start_enum_callback( @@ -103,6 +104,7 @@ pub(crate) unsafe extern "system" fn start_enum_callback( last_entry: None, entries, iter_index: None, + search_expression: None, }, ); @@ -128,36 +130,70 @@ pub(crate) unsafe extern "system" fn end_enum_callback( pub(crate) unsafe extern "system" fn get_enum_callback( callback_data: *const PRJ_CALLBACK_DATA, enumeration_id: *const GUID, - _search_expression: PCWSTR, + search_expression: PCWSTR, dir_entry_buffer_handle: PRJ_DIR_ENTRY_BUFFER_HANDLE, ) -> ::windows_sys::core::HRESULT { trace!("get_enum_callback"); let callback_data = &*callback_data; let instance_context = &mut *(callback_data.InstanceContext as *mut EncryptedFs); - if instance_context.is_stopping.load(std::sync::atomic::Ordering::Relaxed) { + if instance_context + .is_stopping + .load(std::sync::atomic::Ordering::Relaxed) + { return 0; } - let data = instance_context + let data = if let Some(data) = instance_context .enum_map .get_mut(&crate::WinGuid(*enumeration_id)) - .unwrap(); + { + data + } else { + warn!("unknown enumeration"); + return E_INVALIDARG; + }; if callback_data.Flags & PRJ_CB_DATA_FLAG_ENUM_RESTART_SCAN == 1 { data.last_entry = None; data.iter_index = Some(0); + + if search_expression != std::ptr::null() { + let len = libc::wcslen(search_expression) + 1; + data.search_expression = + Some(std::slice::from_raw_parts(search_expression, len).to_vec()); + } else { + data.search_expression = None; + } } let mut last_index = data.iter_index.unwrap_or(0); if let Some((last_filename, last_info)) = std::mem::replace(&mut data.last_entry, None) { - PrjFillDirEntryBuffer(last_filename.as_ptr(), &last_info, dir_entry_buffer_handle); + let insert = if let Some(search_expression) = &data.search_expression { + PrjFileNameCompare(last_filename.as_ptr(), search_expression.as_ptr()) != 0 + } else { + false + }; + + if insert { + PrjFillDirEntryBuffer(last_filename.as_ptr(), &last_info, dir_entry_buffer_handle); + } } while last_index < data.entries.len() { let (filename, entry) = &data.entries[last_index]; + let insert = if let Some(search_expression) = &data.search_expression { + PrjFileNameCompare(filename.as_ptr(), search_expression.as_ptr()) != 0 + } else { + false + }; + + if !insert { + continue; + } + let metadata = entry.metadata().unwrap(); let infos = PRJ_FILE_BASIC_INFO {