Skip to content

Commit

Permalink
Adding support for notifications, minor bugfixes and code improvement…
Browse files Browse the repository at this point in the history
…s (PR #4)

* Adding support for file system notifications
* Some code refactoring
* Fixed memory leak when projection start failed
* Adding support for search expressions
  • Loading branch information
WolverinDEV authored Dec 29, 2023
2 parents 661ce17 + 6291f84 commit 1a2513b
Show file tree
Hide file tree
Showing 8 changed files with 509 additions and 189 deletions.
3 changes: 2 additions & 1 deletion .github/workflows/rust.yml
Original file line number Diff line number Diff line change
Expand Up @@ -43,9 +43,10 @@ jobs:
- name: Build
run: cargo build --all-targets
- name: Test
run: cargo test
run: cargo test -- --nocapture
env:
RUST_LOG: trace
RUST_TEST_THREADS: 1
deploy:
runs-on: windows-latest
needs: tests
Expand Down
2 changes: 1 addition & 1 deletion Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

14 changes: 14 additions & 0 deletions examples/virtual-fs/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ use std::{
Cursor,
Read,
},
ops::ControlFlow,
path::PathBuf,
};

Expand All @@ -13,6 +14,7 @@ use windows_projfs::{
DirectoryEntry,
DirectoryInfo,
FileInfo,
Notification,
ProjectedFileSystem,
ProjectedFileSystemSource,
};
Expand Down Expand Up @@ -47,6 +49,18 @@ impl ProjectedFileSystemSource for VirtualProjectedSource {

Ok(Box::new(Cursor::new(buffer)))
}

fn handle_notification(&self, notification: &Notification) -> ControlFlow<()> {
log::debug!("Notification: {:?}", notification);
if notification.is_cancelable()
&& !matches!(notification, Notification::FilePreConvertToFull(_))
{
/* Try to cancel all possible actions to make the file system read only. */
ControlFlow::Break(())
} else {
ControlFlow::Continue(())
}
}
}

#[derive(clap::Parser)]
Expand Down
2 changes: 1 addition & 1 deletion windows-projfs/Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[package]
name = "windows-projfs"
version = "0.1.2"
version = "0.1.3"
edition = "2021"
authors = ["M. Hadenfeldt <[email protected]>"]
description = "A rust library for the Windows projected file system API"
Expand Down
93 changes: 93 additions & 0 deletions windows-projfs/src/callback_data.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@
use std::{
ffi::OsString,
os::windows::ffi::OsStringExt,
path::PathBuf,
};

use windows::{
core::{
GUID,
HRESULT,
},
Win32::{
Foundation::STATUS_SUCCESS,
Storage::ProjectedFileSystem::{
PRJ_CALLBACK_DATA,
PRJ_CALLBACK_DATA_FLAGS,
PRJ_NAMESPACE_VIRTUALIZATION_CONTEXT,
},
},
};

#[allow(unused)]
pub struct CallbackData<'a, C> {
pub flags: PRJ_CALLBACK_DATA_FLAGS,

pub namespace_virtualization_context: PRJ_NAMESPACE_VIRTUALIZATION_CONTEXT,
pub command_id: i32,

pub file_id: GUID,
pub data_stream_id: GUID,

// Unknown how to handle (yet)
// pub VersionInfo: *mut PRJ_PLACEHOLDER_VERSION_INFO,
pub file_path: Option<PathBuf>,

pub triggering_process_id: u32,
pub triggering_process_image_file_name: Option<String>,

/// The projection context should be a valid reference as long
/// as this callback data exists.
pub context: &'a C,
// pub extended_parameters: Mutex<Option<PRJ_COMPLETE_COMMAND_EXTENDED_PARAMETERS>>,
}

impl<'a, C> CallbackData<'a, C> {
pub fn execute<F>(self, executor: F) -> HRESULT
where
F: FnOnce(&Self) -> Result<(), HRESULT>,
{
match executor(&self) {
Ok(_) => STATUS_SUCCESS.to_hresult(),
Err(code) => code,
}
}
}

impl<'a, C> From<*const PRJ_CALLBACK_DATA> for CallbackData<'a, C> {
fn from(value: *const PRJ_CALLBACK_DATA) -> Self {
let value = unsafe { value.as_ref() }.expect("callback data should never be null");
let file_path = if value.FilePathName.is_null() {
None
} else {
Some(PathBuf::from(OsString::from_wide(unsafe {
value.FilePathName.as_wide()
})))
};

let triggering_process_image_file_name = if value.TriggeringProcessImageFileName.is_null() {
None
} else {
Some(String::from_utf16_lossy(unsafe {
value.TriggeringProcessImageFileName.as_wide()
}))
};

let context = unsafe { &mut *(value.InstanceContext as *mut C) };
Self {
flags: value.Flags,

namespace_virtualization_context: value.NamespaceVirtualizationContext,
command_id: value.CommandId,

file_path,
file_id: value.FileId,
data_stream_id: value.DataStreamId,

triggering_process_id: value.TriggeringProcessId,
triggering_process_image_file_name,

context,
}
}
}
Loading

0 comments on commit 1a2513b

Please sign in to comment.