winfsp_wrs/callback.rs
1//! This module is mostly about implementing the `FileSystemInterface` trait.
2//!
3//! The thing to consider here is we expose the `FileSystemInterface` trait as a high level
4//! construct in order to build a structure of pointer (the `FSP_FILE_SYSTEM_INTERFACE` WinFSP
5//! actually wants).
6//!
7//! However, there is no 1-to-1 relationship between trait implementation and struct of pointers:
8//! a struct of pointer can have `NULL` pointers which is not possible to express when implementing
9//! a trait (I've tried some tricks with function pointer comparison, but it doesn't support
10//! methods with `foo: impl Type` parameter !)
11//!
12//! Hence, why we ask the end user to both implement the methods he needs AND set corresponding
13//! `xxx_DEFINED` boolean (this way all methods with the boolean not set will be set as `NULL`
14//! in the struct of pointers).
15//!
16//! ## Bonus: Why do we provide a `unreachable!()` default implementation for each method in the trait ?
17//!
18//! Providing no default implementation means the end user implementing this trait would
19//! have to implement all the methods.
20//!
21//! However, most of the time, not all methods need to be implemented (see for instance
22//! the methods related to reparse points).
23//!
24//! In this case what should be the implementation of such method ?
25//!
26//! The obvious answer is "just implement with a unreachable and you're good to go !".
27//! However, this has multiple drawbacks:
28//! - It is much more verbose
29//! - It feels very weird to define a method, but with a unreachable, so this method is not
30//! really "defined" and hence the `xxx_DEFINED` boolean should not be set !
31//! - It is very tempting to implement those methods by returning a `NTSTATUS`
32//! `STATUS_NOT_IMPLEMENTED`... which cause very hard to track bugs ! (This used to be
33//! how winfsp_wrs worked, guessed how much time I spent pinpointing the issue ^^)
34//!
35//! So the alternative is set those default implementations in the trait, so this way the
36//! end user only have to define the methods (and the corresponding `xxx_DEFINED`) he uses.
37
38use std::sync::Arc;
39use widestring::U16CStr;
40use windows_sys::Win32::Foundation::{STATUS_BUFFER_OVERFLOW, STATUS_REPARSE, STATUS_SUCCESS};
41use winfsp_wrs_sys::{
42 FspFileSystemAddDirInfo, FspFileSystemFindReparsePoint, FspFileSystemResolveReparsePoints,
43 FspFileSystemStopServiceIfNecessary, BOOLEAN, FSP_FILE_SYSTEM, FSP_FILE_SYSTEM_INTERFACE,
44 FSP_FSCTL_DIR_INFO, FSP_FSCTL_FILE_INFO, FSP_FSCTL_VOLUME_INFO, NTSTATUS,
45 PFILE_FULL_EA_INFORMATION, PIO_STATUS_BLOCK, PSECURITY_DESCRIPTOR, PSIZE_T, PUINT32, PULONG,
46 PVOID, PWSTR, SECURITY_INFORMATION, SIZE_T, UINT32, UINT64, ULONG,
47};
48
49use crate::{
50 CleanupFlags, CreateFileInfo, CreateOptions, DirInfo, FileAccessRights, FileAttributes,
51 FileContextMode, FileInfo, PSecurityDescriptor, SecurityDescriptor, VolumeInfo, WriteMode,
52};
53
54/// Implement only if necessary at your own risk
55pub trait FileContextKind {
56 const MODE: FileContextMode;
57 /// # Safety
58 ///
59 /// Write the data into winfsp's `PVOID *PFileContext`
60 /// This is called in winfsp-wrs after calling FileSystemContext::open
61 unsafe fn write(self, out: *mut PVOID);
62 /// # Safety
63 ///
64 /// Retrieve the data from winfsp's `FileContext`
65 /// This is called in winfsp-wrs before calling FileSystemContext::read/write etc.
66 unsafe fn access(raw: PVOID) -> Self;
67 /// # Safety
68 ///
69 /// Retrieve the data from winfsp's `FileContext`
70 /// This is called in winfsp-wrs before calling FileSystemContext::close
71 unsafe fn access_for_close(raw: PVOID) -> Self;
72}
73
74impl<T> FileContextKind for Arc<T> {
75 const MODE: FileContextMode = FileContextMode::Descriptor;
76
77 unsafe fn write(self, out: *mut PVOID) {
78 out.write(Arc::into_raw(self).cast_mut().cast())
79 }
80
81 // the refcount must be incremented to keep the arc alive after being consumed
82 // by drop
83 unsafe fn access(raw: PVOID) -> Self {
84 Arc::increment_strong_count(raw as *const T);
85 Self::access_for_close(raw)
86 }
87
88 // the refcount should not be incremented so that when all operations are
89 // complete the arc can be freed
90 unsafe fn access_for_close(raw: PVOID) -> Self {
91 Arc::from_raw(raw as *const T)
92 }
93}
94
95impl FileContextKind for usize {
96 const MODE: FileContextMode = FileContextMode::Node;
97
98 // basic write
99 unsafe fn write(self, out: *mut PVOID) {
100 out.write(self as *mut _)
101 }
102
103 // basic access
104 unsafe fn access(raw: PVOID) -> Self {
105 raw as usize
106 }
107
108 // basic access
109 unsafe fn access_for_close(raw: PVOID) -> Self {
110 raw as usize
111 }
112}
113
114/// High level interface over `FSP_FILE_SYSTEM_INTERFACE`.
115///
116/// This trait requires to overwrite all WinFSP callbacks you need and it corresponding
117/// `xxx_DEFINED` associated const boolean.
118///
119/// This is needed to properly build the `FSP_FILE_SYSTEM_INTERFACE` struct, as
120/// a callback pointer set to `NULL` (i.e. if `xxx_DEFINED=false`) leads to a different
121/// behavior that a callback pointer containing a mock implementation (e.g.
122/// returning `Err(STATUS_NOT_IMPLEMENTED)`).
123///
124/// So the way to work with this trait is to overwrite the method and `xxx_DEFINED` for
125/// each function pointer you will need in `FSP_FILE_SYSTEM_INTERFACE`:
126///
127/// ```rust
128/// struct MyFS;
129/// impl FileSystemInterface for MyFS {
130/// type FileContext: usize;
131/// // `CREATE_DEFINED` not overwritten, hence `FSP_FILE_SYSTEM_INTERFACE.Create == NULL`
132/// const CREATE_EX_DEFINED: bool = true; // i.e. `FSP_FILE_SYSTEM_INTERFACE.CreateEx != NULL`
133/// fn create_ex(
134/// &self,
135/// file_name: &U16CStr,
136/// create_file_info: CreateFileInfo,
137/// security_descriptor: SecurityDescriptor,
138/// buffer: &[u8],
139/// extra_buffer_is_reparse_point: bool,
140/// ) -> Result<(Self::FileContext, FileInfo), NTSTATUS> {
141/// ...
142/// }
143/// }
144/// ```
145///
146/// *Notes*:
147/// - Associated method and `xxx_DEFINED` const must be overwritten together, as the
148/// method is simply ignored if `xxx_DEFINED` is not set, and setting `xxx_DEFINED`
149/// without overwritting the method means the function pointer relies on the method
150/// default implementation that panics whenever used (ah !).
151/// - If your are curious about the reason for using a trait here instead of a struct (or
152/// associated const fields with `Option<fn()>` type in the trait instead of methods), it
153/// all boils down to the fact some methods have an `impl Fn` function pointer as argument,
154/// which is only possible in trait method.
155pub trait FileSystemInterface {
156 type FileContext: FileContextKind;
157
158 const GET_VOLUME_INFO_DEFINED: bool = false;
159 const SET_VOLUME_LABEL_DEFINED: bool = false;
160 const GET_SECURITY_BY_NAME_DEFINED: bool = false;
161 const CREATE_DEFINED: bool = false;
162 const CREATE_EX_DEFINED: bool = false;
163 const OPEN_DEFINED: bool = false;
164 const OVERWRITE_DEFINED: bool = false;
165 const OVERWRITE_EX_DEFINED: bool = false;
166 const CLEANUP_DEFINED: bool = false;
167 const CLOSE_DEFINED: bool = false;
168 const READ_DEFINED: bool = false;
169 const WRITE_DEFINED: bool = false;
170 const FLUSH_DEFINED: bool = false;
171 const GET_FILE_INFO_DEFINED: bool = false;
172 const SET_BASIC_INFO_DEFINED: bool = false;
173 const SET_FILE_SIZE_DEFINED: bool = false;
174 const CAN_DELETE_DEFINED: bool = false;
175 const RENAME_DEFINED: bool = false;
176 const GET_SECURITY_DEFINED: bool = false;
177 const SET_SECURITY_DEFINED: bool = false;
178 const READ_DIRECTORY_DEFINED: bool = false;
179 const GET_REPARSE_POINT_DEFINED: bool = false;
180 const SET_REPARSE_POINT_DEFINED: bool = false;
181 const DELETE_REPARSE_POINT_DEFINED: bool = false;
182 const GET_STREAM_INFO_DEFINED: bool = false;
183 const GET_DIR_INFO_BY_NAME_DEFINED: bool = false;
184 const CONTROL_DEFINED: bool = false;
185 const SET_DELETE_DEFINED: bool = false;
186 const GET_EA_DEFINED: bool = false;
187 const SET_EA_DEFINED: bool = false;
188 const DISPATCHER_STOPPED_DEFINED: bool = false;
189 const RESOLVE_REPARSE_POINTS_DEFINED: bool = false;
190
191 /// Get volume information.
192 fn get_volume_info(&self) -> Result<VolumeInfo, NTSTATUS> {
193 unreachable!("To be used, trait method must be overwritten !");
194 }
195
196 /// Set volume label.
197 fn set_volume_label(&self, _volume_label: &U16CStr) -> Result<VolumeInfo, NTSTATUS> {
198 unreachable!("To be used, trait method must be overwritten !");
199 }
200
201 /// Get file or directory attributes and security descriptor given a file name.
202 ///
203 /// [out]:
204 /// - file_attributes
205 /// - security descriptor
206 /// - reparse (false if `reparse_point` is not supported)
207 ///
208 /// [help]:
209 /// - find_reparse_point (optional, can be ignored): Helper to find reparse
210 /// points (`get_reparse_point_by_name` should be implemented).
211 /// If reparse point is found, return the `FileAttributes` and `reparse` should be
212 /// set to `true`.
213 fn get_security_by_name(
214 &self,
215 _file_name: &U16CStr,
216 _find_reparse_point: impl Fn() -> Option<FileAttributes>,
217 ) -> Result<(FileAttributes, PSecurityDescriptor, bool), NTSTATUS> {
218 unreachable!("To be used, trait method must be overwritten !");
219 }
220
221 /// Create new file or directory.
222 ///
223 /// Note: `FileSystemContext::create_ex` takes precedence over `FileSystemContext::create`
224 fn create(
225 &self,
226 _file_name: &U16CStr,
227 _create_file_info: CreateFileInfo,
228 _security_descriptor: SecurityDescriptor,
229 ) -> Result<(Self::FileContext, FileInfo), NTSTATUS> {
230 unreachable!("To be used, trait method must be overwritten !");
231 }
232
233 /// Create new file or directory.
234 ///
235 /// This function works like `create`, except that it also accepts an extra buffer
236 /// that may contain extended attributes or a reparse point.
237 ///
238 /// Note: `FileSystemContext::create_ex` takes precedence over `FileSystemContext::create`
239 fn create_ex(
240 &self,
241 _file_name: &U16CStr,
242 _create_file_info: CreateFileInfo,
243 _security_descriptor: SecurityDescriptor,
244 _buffer: &[u8],
245 _extra_buffer_is_reparse_point: bool,
246 ) -> Result<(Self::FileContext, FileInfo), NTSTATUS> {
247 unreachable!("To be used, trait method must be overwritten !");
248 }
249
250 /// Open a file or directory.
251 fn open(
252 &self,
253 _file_name: &U16CStr,
254 _create_options: CreateOptions,
255 _granted_access: FileAccessRights,
256 ) -> Result<(Self::FileContext, FileInfo), NTSTATUS> {
257 unreachable!("To be used, trait method must be overwritten !");
258 }
259
260 /// Overwrite a file.
261 ///
262 /// Note: `FileSystemContext::overwrite_ex` takes precedence over `FileSystemContext::overwrite`
263 fn overwrite(
264 &self,
265 _file_context: Self::FileContext,
266 _file_attributes: FileAttributes,
267 _replace_file_attributes: bool,
268 _allocation_size: u64,
269 ) -> Result<FileInfo, NTSTATUS> {
270 unreachable!("To be used, trait method must be overwritten !");
271 }
272
273 /// Overwrite a file.
274 ///
275 /// This function works like `overwrite`, except that it also accepts EA (extended attributes).
276 ///
277 /// Note: `FileSystemContext::overwrite_ex` takes precedence over `FileSystemContext::overwrite`
278 fn overwrite_ex(
279 &self,
280 _file_context: Self::FileContext,
281 _file_attributes: FileAttributes,
282 _replace_file_attributes: bool,
283 _allocation_size: u64,
284 _buffer: &[u8],
285 ) -> Result<FileInfo, NTSTATUS> {
286 unreachable!("To be used, trait method must be overwritten !");
287 }
288
289 /// Cleanup a file.
290 fn cleanup(
291 &self,
292 _file_context: Self::FileContext,
293 _file_name: Option<&U16CStr>,
294 _flags: CleanupFlags,
295 ) {
296 unreachable!("To be used, trait method must be overwritten !");
297 }
298
299 /// Close a file.
300 fn close(&self, _file_context: Self::FileContext) {
301 unreachable!("To be used, trait method must be overwritten !");
302 }
303
304 /// Read a file.
305 fn read(
306 &self,
307 _file_context: Self::FileContext,
308 _buffer: &mut [u8],
309 _offset: u64,
310 ) -> Result<usize, NTSTATUS> {
311 unreachable!("To be used, trait method must be overwritten !");
312 }
313
314 /// Write a file.
315 fn write(
316 &self,
317 _file_context: Self::FileContext,
318 _buffer: &[u8],
319 _mode: WriteMode,
320 ) -> Result<(usize, FileInfo), NTSTATUS> {
321 unreachable!("To be used, trait method must be overwritten !");
322 }
323
324 /// Flush a file or volume.
325 fn flush(&self, _file_context: Self::FileContext) -> Result<FileInfo, NTSTATUS> {
326 unreachable!("To be used, trait method must be overwritten !");
327 }
328
329 /// Get file or directory information.
330 fn get_file_info(&self, _file_context: Self::FileContext) -> Result<FileInfo, NTSTATUS> {
331 unreachable!("To be used, trait method must be overwritten !");
332 }
333
334 /// Set file or directory basic information.
335 fn set_basic_info(
336 &self,
337 _file_context: Self::FileContext,
338 _file_attributes: FileAttributes,
339 _creation_time: u64,
340 _last_access_time: u64,
341 _last_write_time: u64,
342 _change_time: u64,
343 ) -> Result<FileInfo, NTSTATUS> {
344 unreachable!("To be used, trait method must be overwritten !");
345 }
346
347 /// Set file/allocation size.
348 fn set_file_size(
349 &self,
350 _file_context: Self::FileContext,
351 _new_size: u64,
352 _set_allocation_size: bool,
353 ) -> Result<FileInfo, NTSTATUS> {
354 unreachable!("To be used, trait method must be overwritten !");
355 }
356
357 /// Determine whether a file or directory can be deleted.
358 ///
359 /// Note: `FileSystemContext::set_delete` takes precedence over `FileSystemContext::can_delete`
360 fn can_delete(
361 &self,
362 _file_context: Self::FileContext,
363 _file_name: &U16CStr,
364 ) -> Result<(), NTSTATUS> {
365 unreachable!("To be used, trait method must be overwritten !");
366 }
367
368 /// Renames a file or directory.
369 fn rename(
370 &self,
371 _file_context: Self::FileContext,
372 _file_name: &U16CStr,
373 _new_file_name: &U16CStr,
374 _replace_if_exists: bool,
375 ) -> Result<(), NTSTATUS> {
376 unreachable!("To be used, trait method must be overwritten !");
377 }
378
379 /// Get file or directory security descriptor.
380 fn get_security(
381 &self,
382 _file_context: Self::FileContext,
383 ) -> Result<PSecurityDescriptor, NTSTATUS> {
384 unreachable!("To be used, trait method must be overwritten !");
385 }
386
387 /// Set file or directory security descriptor.
388 fn set_security(
389 &self,
390 _file_context: Self::FileContext,
391 _security_information: u32,
392 _modification_descriptor: PSecurityDescriptor,
393 ) -> Result<(), NTSTATUS> {
394 unreachable!("To be used, trait method must be overwritten !");
395 }
396
397 /// Read a directory.
398 ///
399 /// `add_dir_info` returns `false` if there is no more space left to add elements.
400 fn read_directory(
401 &self,
402 _file_context: Self::FileContext,
403 _marker: Option<&U16CStr>,
404 _add_dir_info: impl FnMut(DirInfo) -> bool,
405 ) -> Result<(), NTSTATUS> {
406 unreachable!("To be used, trait method must be overwritten !");
407 }
408
409 /// Get reparse point.
410 fn get_reparse_point(
411 &self,
412 _file_context: Self::FileContext,
413 _file_name: &U16CStr,
414 _buffer: &mut [u8],
415 ) -> Result<usize, NTSTATUS> {
416 unreachable!("To be used, trait method must be overwritten !");
417 }
418
419 /// Set reparse point.
420 fn set_reparse_point(
421 &self,
422 _file_context: Self::FileContext,
423 _file_name: &U16CStr,
424 _buffer: &mut [u8],
425 ) -> Result<(), NTSTATUS> {
426 unreachable!("To be used, trait method must be overwritten !");
427 }
428
429 /// Delete reparse point.
430 fn delete_reparse_point(
431 &self,
432 _file_context: Self::FileContext,
433 _file_name: &U16CStr,
434 _buffer: &mut [u8],
435 ) -> Result<(), NTSTATUS> {
436 unreachable!("To be used, trait method must be overwritten !");
437 }
438
439 /// Get named streams information.
440 fn get_stream_info(
441 &self,
442 _file_context: Self::FileContext,
443 _buffer: &mut [u8],
444 ) -> Result<usize, NTSTATUS> {
445 unreachable!("To be used, trait method must be overwritten !");
446 }
447
448 /// Get directory information for a single file or directory within a parent
449 /// directory.
450 fn get_dir_info_by_name(
451 &self,
452 _file_context: Self::FileContext,
453 _file_name: &U16CStr,
454 ) -> Result<FileInfo, NTSTATUS> {
455 unreachable!("To be used, trait method must be overwritten !");
456 }
457
458 /// Process control code.
459 fn control(
460 &self,
461 _file_context: Self::FileContext,
462 _control_code: u32,
463 _input_buffer: &[u8],
464 _output_buffer: &mut [u8],
465 ) -> Result<usize, NTSTATUS> {
466 unreachable!("To be used, trait method must be overwritten !");
467 }
468
469 /// Set the file delete flag.
470 ///
471 /// Note: `FileSystemContext::set_delete` takes precedence over `FileSystemContext::can_delete`
472 fn set_delete(
473 &self,
474 _file_context: Self::FileContext,
475 _file_name: &U16CStr,
476 _delete_file: bool,
477 ) -> Result<(), NTSTATUS> {
478 unreachable!("To be used, trait method must be overwritten !");
479 }
480
481 /// Get extended attributes.
482 fn get_ea(&self, _file_context: Self::FileContext, _buffer: &[u8]) -> Result<usize, NTSTATUS> {
483 unreachable!("To be used, trait method must be overwritten !");
484 }
485
486 /// Set extended attributes.
487 fn set_ea(
488 &self,
489 _file_context: Self::FileContext,
490 _buffer: &[u8],
491 ) -> Result<FileInfo, NTSTATUS> {
492 unreachable!("To be used, trait method must be overwritten !");
493 }
494
495 fn dispatcher_stopped(&self, _normally: bool) {
496 unreachable!("To be used, trait method must be overwritten !");
497 }
498
499 /// Get reparse point given a file name.
500 ///
501 /// This method is used as a callback parameter to `FspFileSystemFindReparsePoint` &
502 /// `FspFileSystemResolveReparsePoints` helpers to respectively implement
503 /// `FSP_FILE_SYSTEM_INTERFACE`'s `GetSecurityByName` & `ResolveReparsePoints`.
504 fn get_reparse_point_by_name(
505 &self,
506 _file_name: &U16CStr,
507 _is_directory: bool,
508 _buffer: Option<&mut [u8]>,
509 ) -> Result<usize, NTSTATUS> {
510 unreachable!("To be used, trait method must be overwritten !");
511 }
512}
513
514/// `TrampolineInterface` fills the gap between the high level `FileSystemInterface`
515/// and the `FSP_FILE_SYSTEM_INTERFACE` C struct that WinFSP expects from us.
516pub(crate) struct TrampolineInterface;
517
518impl TrampolineInterface {
519 /// Get volume information.
520 /// - FileSystem - The file system on which this request is posted.
521 /// - VolumeInfo - [out] Pointer to a structure that will receive the volume
522 /// information on successful return from this call.
523 unsafe extern "C" fn get_volume_info_ext<C: FileSystemInterface>(
524 file_system: *mut FSP_FILE_SYSTEM,
525 volume_info: *mut FSP_FSCTL_VOLUME_INFO,
526 ) -> NTSTATUS {
527 let fs = &*(*file_system).UserContext.cast::<C>();
528
529 match C::get_volume_info(fs) {
530 Ok(vi) => {
531 *volume_info = vi.0;
532 STATUS_SUCCESS
533 }
534 Err(e) => e,
535 }
536 }
537
538 /// Set volume label.
539 /// - FileSystem - The file system on which this request is posted.
540 /// - VolumeLabel - The new label for the volume.
541 /// - VolumeInfo - [out] Pointer to a structure that will receive the volume
542 /// information on successful return from this call.
543 unsafe extern "C" fn set_volume_label_w_ext<C: FileSystemInterface>(
544 file_system: *mut FSP_FILE_SYSTEM,
545 volume_label: PWSTR,
546 volume_info: *mut FSP_FSCTL_VOLUME_INFO,
547 ) -> NTSTATUS {
548 let fs = &*(*file_system).UserContext.cast::<C>();
549
550 match C::set_volume_label(fs, U16CStr::from_ptr_str(volume_label)) {
551 Ok(vi) => {
552 *volume_info = vi.0;
553 STATUS_SUCCESS
554 }
555 Err(e) => e,
556 }
557 }
558
559 /// Get file or directory attributes and security descriptor given a file name.
560 /// - FileSystem - The file system on which this request is posted.
561 /// - FileName - The name of the file or directory to get the attributes and
562 /// security descriptor for.
563 /// - PFileAttributes - Pointer to a memory location that will receive the file
564 /// attributes on successful return from this call. May be NULL.
565 ///
566 /// If this call returns STATUS_REPARSE, the file system MAY place here the
567 /// index of the first reparse point within FileName. The file system MAY also
568 /// leave this at its default value of 0.
569 ///
570 /// - SecurityDescriptor - Pointer to a buffer that will receive the file
571 /// security descriptor on successful return from this call. May be NULL.
572 /// - PSecurityDescriptorSize - [in,out] Pointer to the security descriptor
573 /// buffer size. On input it contains the size of the security descriptor
574 /// buffer. On output it will contain the actual size of the security
575 /// descriptor copied into the security descriptor buffer. May be NULL.
576 ///
577 /// Remarks: STATUS_REPARSE should be returned by file systems that support
578 /// reparse points when they encounter a FileName that contains reparse points
579 /// anywhere but the final path component.
580 unsafe extern "C" fn get_security_by_name_ext<C: FileSystemInterface>(
581 file_system: *mut FSP_FILE_SYSTEM,
582 file_name: PWSTR,
583 p_file_attributes: PUINT32,
584 security_descriptor: PSECURITY_DESCRIPTOR,
585 p_security_descriptor_size: *mut SIZE_T,
586 ) -> NTSTATUS {
587 let fs = &*(*file_system).UserContext.cast::<C>();
588
589 let find_reparse_point = || -> Option<FileAttributes> {
590 let mut reparse_index = 0;
591 unsafe {
592 if FspFileSystemFindReparsePoint(
593 file_system,
594 Some(Self::get_reparse_point_by_name_ext::<C>),
595 std::ptr::null_mut(),
596 file_name,
597 &mut reparse_index,
598 ) != 0
599 {
600 Some(FileAttributes(reparse_index))
601 } else {
602 None
603 }
604 }
605 };
606
607 let file_name = U16CStr::from_ptr_str(file_name);
608
609 match C::get_security_by_name(fs, file_name, find_reparse_point) {
610 Ok((fa, sd, reparse)) => {
611 if !p_file_attributes.is_null() {
612 p_file_attributes.write(fa.0)
613 }
614
615 if !p_security_descriptor_size.is_null() {
616 if sd.len() as SIZE_T > p_security_descriptor_size.read() {
617 // In case of overflow error, winfsp will retry with a new
618 // allocation based on `p_security_descriptor_size`. Hence we
619 // must update this value to the required size.
620 p_security_descriptor_size.write(sd.len() as SIZE_T);
621 return STATUS_BUFFER_OVERFLOW;
622 }
623
624 p_security_descriptor_size.write(sd.len() as SIZE_T);
625
626 if !security_descriptor.is_null() {
627 std::ptr::copy(sd.inner(), security_descriptor, sd.len());
628 }
629 }
630
631 if reparse {
632 STATUS_REPARSE
633 } else {
634 STATUS_SUCCESS
635 }
636 }
637 Err(e) => e,
638 }
639 }
640
641 /// Open a file or directory.
642 /// - FileSystem - The file system on which this request is posted.
643 /// - FileName - The name of the file or directory to be opened.
644 /// - CreateOptions - Create options for this request. This parameter has the
645 /// same meaning as the CreateOptions parameter of the NtCreateFile API. User
646 /// mode file systems typically do not need to do anything special with
647 /// respect to this parameter. Some file systems may also want to pay
648 /// attention to the FILE_NO_INTERMEDIATE_BUFFERING and FILE_WRITE_THROUGH
649 /// flags, although these are typically handled by the FSD component.
650 /// - GrantedAccess - Determines the specific access rights that have been
651 /// granted for this request. Upon receiving this call all access checks have
652 /// been performed and the user mode file system need not perform any
653 /// additional checks. However this parameter may be useful to a user mode
654 /// file system; for example the WinFsp-FUSE layer uses this parameter to
655 /// determine which flags to use in its POSIX open() call.
656 /// - PFileContext - [out] Pointer that will receive the file context on
657 /// successful return from this call.
658 /// - FileInfo - [out] Pointer to a structure that will receive the file
659 /// information on successful return from this call. This information
660 /// includes file attributes, file times, etc.
661 unsafe extern "C" fn open_ext<C: FileSystemInterface>(
662 file_system: *mut FSP_FILE_SYSTEM,
663 file_name: PWSTR,
664 create_options: UINT32,
665 granted_access: UINT32,
666 p_file_context: *mut PVOID,
667 file_info: *mut FSP_FSCTL_FILE_INFO,
668 ) -> NTSTATUS {
669 let fs = &*(*file_system).UserContext.cast::<C>();
670 let file_name = U16CStr::from_ptr_str(file_name);
671
672 match C::open(
673 fs,
674 file_name,
675 CreateOptions(create_options),
676 FileAccessRights(granted_access),
677 ) {
678 Ok((fctx, finfo)) => {
679 C::FileContext::write(fctx, p_file_context);
680 *file_info = finfo.0;
681 STATUS_SUCCESS
682 }
683 Err(e) => e,
684 }
685 }
686
687 /// Cleanup a file.
688 /// - FileSystem - The file system on which this request is posted.
689 /// - FileContext - The file context of the file or directory to cleanup.
690 /// - FileName - The name of the file or directory to cleanup. Sent only when a
691 /// Delete is requested.
692 /// - Flags - These flags determine whether the file was modified and whether
693 /// to delete the file.
694 unsafe extern "C" fn cleanup_ext<C: FileSystemInterface>(
695 file_system: *mut FSP_FILE_SYSTEM,
696 file_context: PVOID,
697 file_name: PWSTR,
698 flags: ULONG,
699 ) {
700 let fs = &*(*file_system).UserContext.cast::<C>();
701 let fctx = C::FileContext::access(file_context);
702
703 let file_name = if file_name.is_null() {
704 None
705 } else {
706 Some(U16CStr::from_ptr_str(file_name))
707 };
708
709 C::cleanup(fs, fctx, file_name, CleanupFlags(flags as i32))
710 }
711
712 /// Close a file.
713 /// - FileSystem - The file system on which this request is posted.
714 /// - FileContext - The file context of the file or directory to be closed.
715 unsafe extern "C" fn close_ext<C: FileSystemInterface>(
716 file_system: *mut FSP_FILE_SYSTEM,
717 file_context: PVOID,
718 ) {
719 let fs = &*(*file_system).UserContext.cast::<C>();
720 let fctx = C::FileContext::access_for_close(file_context);
721 C::close(fs, fctx);
722 }
723
724 /// Read a file.
725 /// - FileSystem - The file system on which this request is posted.
726 /// - FileContext - The file context of the file to be read.
727 /// - Buffer - Pointer to a buffer that will receive the results of the read
728 /// operation.
729 /// - Offset - Offset within the file to read from.
730 /// - Length - Length of data to read.
731 /// - PBytesTransferred - [out] Pointer to a memory location that will receive
732 /// the actual number of bytes read.
733 unsafe extern "C" fn read_ext<C: FileSystemInterface>(
734 file_system: *mut FSP_FILE_SYSTEM,
735 file_context: PVOID,
736 buffer: PVOID,
737 offset: UINT64,
738 length: ULONG,
739 p_bytes_transferred: PULONG,
740 ) -> NTSTATUS {
741 let fs = &*(*file_system).UserContext.cast::<C>();
742 let fctx = C::FileContext::access(file_context);
743 let buffer = if !buffer.is_null() {
744 std::slice::from_raw_parts_mut(buffer.cast(), length as usize)
745 } else {
746 &mut []
747 };
748
749 match C::read(fs, fctx, buffer, offset) {
750 Ok(bytes_transferred) => {
751 *p_bytes_transferred = bytes_transferred as ULONG;
752 STATUS_SUCCESS
753 }
754 Err(e) => e,
755 }
756 }
757
758 /// Write a file.
759 /// - FileSystem - The file system on which this request is posted.
760 /// - FileContext - The file context of the file to be written.
761 /// - Buffer - Pointer to a buffer that contains the data to write.
762 /// - Offset - Offset within the file to write to.
763 /// - Length - Length of data to write.
764 /// - WriteToEndOfFile - When TRUE the file system must write to the current
765 /// end of file. In this case the Offset parameter will contain the value -1.
766 /// - ConstrainedIo - When TRUE the file system must not extend the file (i.e.
767 /// change the file size).
768 /// - PBytesTransferred - [out] Pointer to a memory location that will receive
769 /// the actual number of bytes written.
770 /// - FileInfo - [out] Pointer to a structure that will receive the file
771 /// information on successful return from this call. This information
772 /// includes file attributes, file times, etc.
773 unsafe extern "C" fn write_ext<C: FileSystemInterface>(
774 file_system: *mut FSP_FILE_SYSTEM,
775 file_context: PVOID,
776 buffer: PVOID,
777 offset: UINT64,
778 length: ULONG,
779 write_to_end_of_file: BOOLEAN,
780 constrained_io: BOOLEAN,
781 p_bytes_transferred: PULONG,
782 file_info: *mut FSP_FSCTL_FILE_INFO,
783 ) -> NTSTATUS {
784 let fs = &*(*file_system).UserContext.cast::<C>();
785 let fctx = C::FileContext::access(file_context);
786 let buffer = if !buffer.is_null() {
787 std::slice::from_raw_parts(buffer.cast(), length as usize)
788 } else {
789 &[]
790 };
791
792 let mode = match (write_to_end_of_file != 0, constrained_io != 0) {
793 (false, false) => WriteMode::Normal { offset },
794 (false, true) => WriteMode::ConstrainedIO { offset },
795 (true, false) => WriteMode::WriteToEOF,
796 (true, true) => {
797 *p_bytes_transferred = 0;
798 return Self::get_file_info_ext::<C>(file_system, file_context, file_info);
799 }
800 };
801
802 match C::write(fs, fctx, buffer, mode) {
803 Ok((bytes_transfered, finfo)) => {
804 *p_bytes_transferred = bytes_transfered as ULONG;
805 *file_info = finfo.0;
806 STATUS_SUCCESS
807 }
808 Err(e) => e,
809 }
810 }
811
812 /// Flush a file or volume.
813 /// - FileSystem - The file system on which this request is posted.
814 /// - FileContext - The file context of the file to be flushed. When NULL the
815 /// whole volume is being flushed.
816 /// - FileInfo - [out] Pointer to a structure that will receive the file
817 /// information on successful return from this call. This information
818 /// includes file attributes, file times, etc. Used when flushing file (not
819 /// volume).
820 unsafe extern "C" fn flush_ext<C: FileSystemInterface>(
821 file_system: *mut FSP_FILE_SYSTEM,
822 file_context: PVOID,
823 file_info: *mut FSP_FSCTL_FILE_INFO,
824 ) -> NTSTATUS {
825 let fs = &*(*file_system).UserContext.cast::<C>();
826 let fctx = C::FileContext::access(file_context);
827
828 match C::flush(fs, fctx) {
829 Ok(finfo) => {
830 *file_info = finfo.0;
831 STATUS_SUCCESS
832 }
833 Err(e) => e,
834 }
835 }
836
837 /// Get file or directory information.
838 /// - FileSystem - The file system on which this request is posted.
839 /// - FileContext - The file context of the file or directory to get
840 /// information for.
841 /// - FileInfo - [out] Pointer to a structure that will receive the file
842 /// information on successful return from this call. This information
843 /// includes file attributes, file times, etc.
844 unsafe extern "C" fn get_file_info_ext<C: FileSystemInterface>(
845 file_system: *mut FSP_FILE_SYSTEM,
846 file_context: PVOID,
847 file_info: *mut FSP_FSCTL_FILE_INFO,
848 ) -> NTSTATUS {
849 let fs = &*(*file_system).UserContext.cast::<C>();
850 let fctx = C::FileContext::access(file_context);
851
852 match C::get_file_info(fs, fctx) {
853 Ok(ret) => {
854 *file_info = ret.0;
855 STATUS_SUCCESS
856 }
857 Err(e) => e,
858 }
859 }
860
861 /// Set file or directory basic information.
862 /// - FileSystem - The file system on which this request is posted.
863 /// - FileContext - The file context of the file or directory to set
864 /// information for.
865 /// - FileAttributes - File attributes to apply to the file or directory. If
866 /// the value INVALID_FILE_ATTRIBUTES is sent, the file attributes should not
867 /// be changed.
868 /// - CreationTime - Creation time to apply to the file or directory. If the
869 /// value 0 is sent, the creation time should not be changed.
870 /// - LastAccessTime - Last access time to apply to the file or directory. If
871 /// the value 0 is sent, the last access time should not be changed.
872 /// - LastWriteTime - Last write time to apply to the file or directory. If the
873 /// value 0 is sent, the last write time should not be changed.
874 /// - ChangeTime - Change time to apply to the file or directory. If the value
875 /// 0 is sent, the change time should not be changed.
876 /// - FileInfo - [out] Pointer to a structure that will receive the file
877 /// information on successful return from this call. This information
878 /// includes file attributes, file times, etc.
879 unsafe extern "C" fn set_basic_info_ext<C: FileSystemInterface>(
880 file_system: *mut FSP_FILE_SYSTEM,
881 file_context: PVOID,
882 file_attributes: UINT32,
883 creation_time: UINT64,
884 last_access_time: UINT64,
885 last_write_time: UINT64,
886 change_time: UINT64,
887 file_info: *mut FSP_FSCTL_FILE_INFO,
888 ) -> NTSTATUS {
889 let fs = &*(*file_system).UserContext.cast::<C>();
890 let fctx = C::FileContext::access(file_context);
891
892 match C::set_basic_info(
893 fs,
894 fctx,
895 FileAttributes(file_attributes),
896 creation_time,
897 last_access_time,
898 last_write_time,
899 change_time,
900 ) {
901 Ok(finfo) => {
902 *file_info = finfo.0;
903 STATUS_SUCCESS
904 }
905 Err(e) => e,
906 }
907 }
908
909 /// Set file/allocation size.
910 /// - FileSystem - The file system on which this request is posted.
911 /// - FileContext - The file context of the file to set the file/allocation
912 /// size for.
913 /// - NewSize - New file/allocation size to apply to the file.
914 /// - SetAllocationSize - If TRUE, then the allocation size is being set. if
915 /// FALSE, then the file size is being set.
916 /// - FileInfo - [out] Pointer to a structure that will receive the file
917 /// information on successful return from this call. This information
918 /// includes file attributes, file times, etc.
919 unsafe extern "C" fn set_file_size_ext<C: FileSystemInterface>(
920 file_system: *mut FSP_FILE_SYSTEM,
921 file_context: PVOID,
922 new_size: UINT64,
923 set_allocation_size: BOOLEAN,
924 file_info: *mut FSP_FSCTL_FILE_INFO,
925 ) -> NTSTATUS {
926 let fs = &*(*file_system).UserContext.cast::<C>();
927 let fctx = C::FileContext::access(file_context);
928
929 match C::set_file_size(fs, fctx, new_size, set_allocation_size != 0) {
930 Ok(finfo) => {
931 *file_info = finfo.0;
932 STATUS_SUCCESS
933 }
934 Err(e) => e,
935 }
936 }
937
938 /// Determine whether a file or directory can be deleted.
939 /// - FileSystem - The file system on which this request is posted.
940 /// - FileContext - The file context of the file or directory to cleanup.
941 /// - FileName - The name of the file or directory to cleanup. Sent only when a
942 /// Delete is requested.
943 /// - Flags - These flags determine whether the file was modified and whether
944 /// to delete the file.
945 unsafe extern "C" fn can_delete_ext<C: FileSystemInterface>(
946 file_system: *mut FSP_FILE_SYSTEM,
947 file_context: PVOID,
948 file_name: PWSTR,
949 ) -> NTSTATUS {
950 let fs = &*(*file_system).UserContext.cast::<C>();
951 let fctx = C::FileContext::access(file_context);
952 let file_name = U16CStr::from_ptr_str(file_name);
953
954 match C::can_delete(fs, fctx, file_name) {
955 Ok(()) => STATUS_SUCCESS,
956 Err(e) => e,
957 }
958 }
959
960 /// Renames a file or directory.
961 /// - FileSystem - The file system on which this request is posted.
962 /// - FileContext - The file context of the file or directory to be renamed.
963 /// - FileName - The current name of the file or directory to rename.
964 /// - NewFileName - The new name for the file or directory.
965 /// - ReplaceIfExists - Whether to replace a file that already exists at
966 /// NewFileName.
967 unsafe extern "C" fn rename_ext<C: FileSystemInterface>(
968 file_system: *mut FSP_FILE_SYSTEM,
969 file_context: PVOID,
970 file_name: PWSTR,
971 new_file_name: PWSTR,
972 replace_if_exists: BOOLEAN,
973 ) -> NTSTATUS {
974 let fs = &*(*file_system).UserContext.cast::<C>();
975 let fctx = C::FileContext::access(file_context);
976 let file_name = U16CStr::from_ptr_str(file_name);
977 let new_file_name = U16CStr::from_ptr_str(new_file_name);
978
979 match C::rename(fs, fctx, file_name, new_file_name, replace_if_exists != 0) {
980 Ok(()) => STATUS_SUCCESS,
981 Err(e) => e,
982 }
983 }
984
985 /// Get file or directory security descriptor.
986 /// - FileSystem - The file system on which this request is posted.
987 /// - FileContext - The file context of the file or directory to get the
988 /// security descriptor for.
989 /// - SecurityDescriptor - Pointer to a buffer that will receive the file
990 /// security descriptor on successful return from this call. May be NULL.
991 /// - PSecurityDescriptorSize - [in,out] Pointer to the security descriptor
992 /// buffer size. On input it contains the size of the security descriptor
993 /// buffer. On output it will contain the actual size of the security
994 /// descriptor copied into the security descriptor buffer. Cannot be NULL.
995 unsafe extern "C" fn get_security_ext<C: FileSystemInterface>(
996 file_system: *mut FSP_FILE_SYSTEM,
997 file_context: PVOID,
998 security_descriptor: PSECURITY_DESCRIPTOR,
999 p_security_descriptor_size: *mut SIZE_T,
1000 ) -> NTSTATUS {
1001 let fs = &*(*file_system).UserContext.cast::<C>();
1002 let fctx = C::FileContext::access(file_context);
1003
1004 match C::get_security(fs, fctx) {
1005 Ok(sd) => {
1006 if !p_security_descriptor_size.is_null() {
1007 if sd.len() as SIZE_T > p_security_descriptor_size.read() {
1008 return STATUS_BUFFER_OVERFLOW;
1009 }
1010 p_security_descriptor_size.write(sd.len() as SIZE_T);
1011 if !security_descriptor.is_null() {
1012 std::ptr::copy(sd.inner(), security_descriptor, sd.len())
1013 }
1014 }
1015
1016 STATUS_SUCCESS
1017 }
1018 Err(e) => e,
1019 }
1020 }
1021
1022 /// Set file or directory security descriptor.
1023 /// - FileSystem - The file system on which this request is posted.
1024 /// - FileContext - The file context of the file or directory to set the
1025 /// security descriptor for.
1026 /// - SecurityInformation - Describes what parts of the file or directory
1027 /// security descriptor should be modified.
1028 /// - ModificationDescriptor - Describes the modifications to apply to the file
1029 /// or directory security descriptor.
1030 unsafe extern "C" fn set_security_ext<C: FileSystemInterface>(
1031 file_system: *mut FSP_FILE_SYSTEM,
1032 file_context: PVOID,
1033 security_information: SECURITY_INFORMATION,
1034 modification_descriptor: PSECURITY_DESCRIPTOR,
1035 ) -> NTSTATUS {
1036 let fs = &*(*file_system).UserContext.cast::<C>();
1037 let fctx = C::FileContext::access(file_context);
1038
1039 let modification_descriptor = PSecurityDescriptor::from_ptr(modification_descriptor);
1040
1041 match C::set_security(fs, fctx, security_information, modification_descriptor) {
1042 Ok(()) => STATUS_SUCCESS,
1043 Err(e) => e,
1044 }
1045 }
1046
1047 /// Read a directory.
1048 /// - FileSystem - The file system on which this request is posted.
1049 /// - FileContext - The file context of the directory to be read.
1050 /// - Pattern - The pattern to match against files in this directory. Can be
1051 /// NULL. The file system can choose to ignore this parameter as the FSD will
1052 /// always perform its own pattern matching on the returned results.
1053 /// - Marker - A file name that marks where in the directory to start reading.
1054 /// Files with names that are greater than (not equal to) this marker (in the
1055 /// directory order determined by the file system) should be returned. Can be
1056 /// NULL.
1057 /// - Buffer - Pointer to a buffer that will receive the results of the read
1058 /// operation.
1059 /// - Length - Length of data to read.
1060 /// - PBytesTransferred - [out] Pointer to a memory location that will receive
1061 /// the actual number of bytes read.
1062 unsafe extern "C" fn read_directory_ext<C: FileSystemInterface>(
1063 file_system: *mut FSP_FILE_SYSTEM,
1064 file_context: PVOID,
1065 _pattern: PWSTR,
1066 marker: PWSTR,
1067 buffer: PVOID,
1068 length: ULONG,
1069 p_bytes_transferred: PULONG,
1070 ) -> NTSTATUS {
1071 let fs = &*(*file_system).UserContext.cast::<C>();
1072 let fctx = C::FileContext::access(file_context);
1073
1074 let marker = if marker.is_null() {
1075 None
1076 } else {
1077 Some(U16CStr::from_ptr_str(marker))
1078 };
1079
1080 let mut buffer_full = false;
1081 let add_dir_info = |mut dir_info: DirInfo| {
1082 let added = FspFileSystemAddDirInfo(
1083 (&mut dir_info as *mut DirInfo).cast(),
1084 buffer,
1085 length,
1086 p_bytes_transferred,
1087 ) != 0;
1088 if !added {
1089 buffer_full = true;
1090 }
1091 added
1092 };
1093
1094 match C::read_directory(fs, fctx, marker, add_dir_info) {
1095 Ok(()) => {
1096 if !buffer_full {
1097 // EOF marker
1098 FspFileSystemAddDirInfo(
1099 std::ptr::null_mut(),
1100 buffer,
1101 length,
1102 p_bytes_transferred,
1103 );
1104 }
1105 STATUS_SUCCESS
1106 }
1107 Err(e) => e,
1108 }
1109 }
1110
1111 unsafe extern "C" fn get_reparse_point_by_name_ext<C: FileSystemInterface>(
1112 file_system: *mut FSP_FILE_SYSTEM,
1113 _context: PVOID,
1114 file_name: PWSTR,
1115 is_directory: BOOLEAN,
1116 buffer: PVOID,
1117 psize: PSIZE_T,
1118 ) -> NTSTATUS {
1119 let fs = &*(*file_system).UserContext.cast::<C>();
1120 let file_name = U16CStr::from_ptr_str_mut(file_name);
1121 let buffer = if !buffer.is_null() {
1122 Some(std::slice::from_raw_parts_mut(
1123 buffer.cast(),
1124 psize.read() as usize,
1125 ))
1126 } else {
1127 None
1128 };
1129
1130 match C::get_reparse_point_by_name(fs, file_name, is_directory != 0, buffer) {
1131 Ok(bytes_transferred) => {
1132 psize.write(bytes_transferred as SIZE_T);
1133 STATUS_SUCCESS
1134 }
1135 Err(e) => e,
1136 }
1137 }
1138
1139 /// Resolve reparse points.
1140 /// - FileSystem - The file system on which this request is posted.
1141 /// - FileName - The name of the file or directory to have its reparse points
1142 /// resolved.
1143 /// - ReparsePointIndex - The index of the first reparse point within FileName.
1144 /// - ResolveLastPathComponent - If FALSE, the last path component of FileName
1145 /// should not be resolved, even if it is a reparse point that can be
1146 /// resolved. If TRUE, all path components should be resolved if possible.
1147 /// - PIoStatus - Pointer to storage that will receive the status to return to
1148 /// the FSD. When this function succeeds it must set PIoStatus->Status to
1149 /// STATUS_REPARSE and PIoStatus->Information to either IO_REPARSE or the
1150 /// reparse tag.
1151 /// - Buffer - Pointer to a buffer that will receive the resolved file name
1152 /// (IO_REPARSE) or reparse data (reparse tag). If the function returns a
1153 /// file name, it should not be NULL terminated.
1154 /// - PSize - [in,out] Pointer to the buffer size. On input it contains the
1155 /// size of the buffer. On output it will contain the actual size of data
1156 /// copied.
1157 unsafe extern "C" fn resolve_reparse_points_ext<C: FileSystemInterface>(
1158 file_system: *mut FSP_FILE_SYSTEM,
1159 file_name: PWSTR,
1160 reparse_point_index: UINT32,
1161 resolve_last_path_component: BOOLEAN,
1162 p_io_status: PIO_STATUS_BLOCK,
1163 buffer: PVOID,
1164 p_size: PSIZE_T,
1165 ) -> NTSTATUS {
1166 FspFileSystemResolveReparsePoints(
1167 file_system,
1168 Some(Self::get_reparse_point_by_name_ext::<C>),
1169 std::ptr::null_mut(),
1170 file_name,
1171 reparse_point_index,
1172 resolve_last_path_component,
1173 p_io_status,
1174 buffer,
1175 p_size,
1176 )
1177 }
1178
1179 /// Get reparse point.
1180 /// - FileSystem - The file system on which this request is posted.
1181 /// - FileContext - The file context of the reparse point.
1182 /// - FileName - The file name of the reparse point.
1183 /// - Buffer - Pointer to a buffer that will receive the results of this
1184 /// operation. If the function returns a symbolic link path, it should not be
1185 /// NULL terminated.
1186 /// - PSize - [in,out] Pointer to the buffer size. On input it contains the
1187 /// size of the buffer. On output it will contain the actual size of data
1188 /// copied.
1189 unsafe extern "C" fn get_reparse_point_ext<C: FileSystemInterface>(
1190 file_system: *mut FSP_FILE_SYSTEM,
1191 file_context: PVOID,
1192 file_name: PWSTR,
1193 buffer: PVOID,
1194 p_size: PSIZE_T,
1195 ) -> NTSTATUS {
1196 let fs = &*(*file_system).UserContext.cast::<C>();
1197 let fctx = C::FileContext::access(file_context);
1198 let file_name = U16CStr::from_ptr_str(file_name);
1199 let buffer = if !buffer.is_null() {
1200 std::slice::from_raw_parts_mut(buffer.cast(), *p_size as usize)
1201 } else {
1202 &mut []
1203 };
1204
1205 match C::get_reparse_point(fs, fctx, file_name, buffer) {
1206 Ok(byte_transferred) => {
1207 p_size.write(byte_transferred as SIZE_T);
1208 STATUS_SUCCESS
1209 }
1210 Err(e) => e,
1211 }
1212 }
1213
1214 /// Set reparse point.
1215 /// - FileSystem - The file system on which this request is posted.
1216 /// - FileContext - The file context of the reparse point.
1217 /// - FileName - The file name of the reparse point.
1218 /// - Buffer - Pointer to a buffer that contains the data for this operation.
1219 /// If this buffer contains a symbolic link path, it should not be assumed to
1220 /// be NULL terminated.
1221 /// - Size - Size of data to write.
1222 unsafe extern "C" fn set_reparse_point_ext<C: FileSystemInterface>(
1223 file_system: *mut FSP_FILE_SYSTEM,
1224 file_context: PVOID,
1225 file_name: PWSTR,
1226 buffer: PVOID,
1227 size: SIZE_T,
1228 ) -> NTSTATUS {
1229 let fs = &*(*file_system).UserContext.cast::<C>();
1230 let fctx = C::FileContext::access(file_context);
1231 let file_name = U16CStr::from_ptr_str(file_name);
1232 let buffer = if !buffer.is_null() {
1233 std::slice::from_raw_parts_mut(buffer.cast(), size as usize)
1234 } else {
1235 &mut []
1236 };
1237
1238 match C::set_reparse_point(fs, fctx, file_name, buffer) {
1239 Ok(()) => STATUS_SUCCESS,
1240 Err(e) => e,
1241 }
1242 }
1243
1244 /// Delete reparse point.
1245 /// - FileSystem - The file system on which this request is posted.
1246 /// - FileContext - The file context of the reparse point.
1247 /// - FileName - The file name of the reparse point.
1248 /// - Buffer - Pointer to a buffer that contains the data for this operation.
1249 /// - Size - Size of data to write.
1250 unsafe extern "C" fn delete_reparse_point_ext<C: FileSystemInterface>(
1251 file_system: *mut FSP_FILE_SYSTEM,
1252 file_context: PVOID,
1253 file_name: PWSTR,
1254 buffer: PVOID,
1255 size: SIZE_T,
1256 ) -> NTSTATUS {
1257 let fs = &*(*file_system).UserContext.cast::<C>();
1258 let fctx = C::FileContext::access(file_context);
1259 let file_name = U16CStr::from_ptr_str(file_name);
1260 let buffer = if !buffer.is_null() {
1261 std::slice::from_raw_parts_mut(buffer.cast(), size as usize)
1262 } else {
1263 &mut []
1264 };
1265
1266 match C::delete_reparse_point(fs, fctx, file_name, buffer) {
1267 Ok(()) => STATUS_SUCCESS,
1268 Err(e) => e,
1269 }
1270 }
1271
1272 /// Get named streams information.
1273 /// - FileSystem - The file system on which this request is posted.
1274 /// - FileContext - The file context of the file or directory to get stream
1275 /// information for.
1276 /// - Buffer - Pointer to a buffer that will receive the stream information.
1277 /// - Length - Length of buffer.
1278 /// - PBytesTransferred - [out] Pointer to a memory location that will receive
1279 /// the actual number of bytes stored.
1280 unsafe extern "C" fn get_stream_info_ext<C: FileSystemInterface>(
1281 file_system: *mut FSP_FILE_SYSTEM,
1282 file_context: PVOID,
1283 buffer: PVOID,
1284 length: ULONG,
1285 p_bytes_transferred: PULONG,
1286 ) -> NTSTATUS {
1287 let fs = &*(*file_system).UserContext.cast::<C>();
1288 let fctx = C::FileContext::access(file_context);
1289 let buffer = if !buffer.is_null() {
1290 std::slice::from_raw_parts_mut(buffer.cast(), length as usize)
1291 } else {
1292 &mut []
1293 };
1294
1295 match C::get_stream_info(fs, fctx, buffer) {
1296 Ok(bytes_transferred) => {
1297 p_bytes_transferred.write(bytes_transferred as ULONG);
1298 STATUS_SUCCESS
1299 }
1300 Err(e) => e,
1301 }
1302 }
1303
1304 /// Get directory information for a single file or directory within a parent
1305 /// directory.
1306 /// - FileSystem - The file system on which this request is posted.
1307 /// - FileContext - The file context of the parent directory.
1308 /// - FileName - The name of the file or directory to get information for. This
1309 /// name is relative to the parent directory and is a single path component.
1310 /// - DirInfo - [out] Pointer to a structure that will receive the directory
1311 /// information on successful return from this call. This information
1312 /// includes the file name, but also file attributes, file times, etc.
1313 unsafe extern "C" fn get_dir_info_by_name_ext<C: FileSystemInterface>(
1314 file_system: *mut FSP_FILE_SYSTEM,
1315 file_context: PVOID,
1316 file_name: PWSTR,
1317 dir_info: *mut FSP_FSCTL_DIR_INFO,
1318 ) -> NTSTATUS {
1319 let fs = &*(*file_system).UserContext.cast::<C>();
1320 let fctx = C::FileContext::access(file_context);
1321 let file_name = U16CStr::from_ptr_str(file_name);
1322
1323 match C::get_dir_info_by_name(fs, fctx, file_name) {
1324 Ok(finfo) => {
1325 (*dir_info).Size =
1326 (std::mem::size_of::<FSP_FSCTL_DIR_INFO>() + file_name.len() * 2) as u16;
1327 (*dir_info).FileInfo = finfo.0;
1328 std::ptr::copy(
1329 file_name.as_ptr(),
1330 (*dir_info).FileNameBuf.as_mut_ptr(),
1331 file_name.len(),
1332 );
1333 STATUS_SUCCESS
1334 }
1335 Err(e) => e,
1336 }
1337 }
1338
1339 /// Process control code.
1340 /// - FileSystem - The file system on which this request is posted.
1341 /// - FileContext - The file context of the file or directory to be controled.
1342 /// - ControlCode - The control code for the operation. This code must have a
1343 /// DeviceType with bit 0x8000 set and must have a TransferType of
1344 /// METHOD_BUFFERED.
1345 /// - InputBuffer - Pointer to a buffer that contains the input data.
1346 /// - InputBufferLength - Input data length.
1347 /// - OutputBuffer - Pointer to a buffer that will receive the output data.
1348 /// - OutputBufferLength - Output data length.
1349 /// - PBytesTransferred - [out] Pointer to a memory location that will receive
1350 /// the actual number of bytes transferred.
1351 unsafe extern "C" fn control_ext<C: FileSystemInterface>(
1352 file_system: *mut FSP_FILE_SYSTEM,
1353 file_context: PVOID,
1354 control_code: UINT32,
1355 input_buffer: PVOID,
1356 input_buffer_length: ULONG,
1357 output_buffer: PVOID,
1358 output_buffer_length: ULONG,
1359 p_bytes_transferred: PULONG,
1360 ) -> NTSTATUS {
1361 let fs = &*(*file_system).UserContext.cast::<C>();
1362 let fctx = C::FileContext::access(file_context);
1363 let input = if !input_buffer.is_null() {
1364 std::slice::from_raw_parts(input_buffer.cast(), input_buffer_length as usize)
1365 } else {
1366 &[]
1367 };
1368 let output = if !output_buffer.is_null() {
1369 std::slice::from_raw_parts_mut(output_buffer.cast(), output_buffer_length as usize)
1370 } else {
1371 &mut []
1372 };
1373
1374 match C::control(fs, fctx, control_code, input, output) {
1375 Ok(bytes_transferred) => {
1376 p_bytes_transferred.write(bytes_transferred as ULONG);
1377 STATUS_SUCCESS
1378 }
1379 Err(e) => e,
1380 }
1381 }
1382
1383 /// Set the file delete flag.
1384 /// - FileSystem - The file system on which this request is posted.
1385 /// - FileContext - The file context of the file or directory to set the delete
1386 /// flag for.
1387 /// - FileName - The name of the file or directory to set the delete flag for.
1388 /// - DeleteFile - If set to TRUE the FSD indicates that the file will be
1389 /// deleted on Cleanup; otherwise it will not be deleted. It is legal to
1390 /// receive multiple SetDelete calls for the same file with different
1391 /// DeleteFile parameters.
1392 unsafe extern "C" fn set_delete_ext<C: FileSystemInterface>(
1393 file_system: *mut FSP_FILE_SYSTEM,
1394 file_context: PVOID,
1395 file_name: PWSTR,
1396 delete_file_w: BOOLEAN,
1397 ) -> NTSTATUS {
1398 let fs = &*(*file_system).UserContext.cast::<C>();
1399 let fctx = C::FileContext::access(file_context);
1400 let file_name = U16CStr::from_ptr_str(file_name);
1401
1402 match C::set_delete(fs, fctx, file_name, delete_file_w != 0) {
1403 Ok(()) => STATUS_SUCCESS,
1404 Err(e) => e,
1405 }
1406 }
1407
1408 /// Create new file or directory.
1409 /// - FileSystem - The file system on which this request is posted.
1410 /// - FileName - The name of the file or directory to be created.
1411 /// - CreateOptions - Create options for this request. This parameter has the
1412 /// same meaning as the CreateOptions parameter of the NtCreateFile API. User
1413 /// mode file systems should typically only be concerned with the flag
1414 /// FILE_DIRECTORY_FILE, which is an instruction to create a directory rather
1415 /// than a file. Some file systems may also want to pay attention to the
1416 /// FILE_NO_INTERMEDIATE_BUFFERING and FILE_WRITE_THROUGH flags, although
1417 /// these are typically handled by the FSD component.
1418 /// - GrantedAccess - Determines the specific access rights that have been
1419 /// granted for this request. Upon receiving this call all access checks have
1420 /// been performed and the user mode file system need not perform any
1421 /// additional checks. However this parameter may be useful to a user mode
1422 /// file system; for example the WinFsp-FUSE layer uses this parameter to
1423 /// determine which flags to use in its POSIX open() call.
1424 /// - FileAttributes - File attributes to apply to the newly created file or
1425 /// directory.
1426 /// - SecurityDescriptor - Security descriptor to apply to the newly created
1427 /// file or directory. This security descriptor will always be in
1428 /// self-relative format. Its length can be retrieved using the Windows
1429 /// GetSecurityDescriptorLength API. Will be NULL for named streams.
1430 /// - AllocationSize - Allocation size for the newly created file.
1431 /// - PFileContext - [out] Pointer that will receive the file context on
1432 /// successful return from this call.
1433 /// - FileInfo - [out] Pointer to a structure that will receive the file
1434 /// information on successful return from this call. This information
1435 /// includes file attributes, file times, etc.
1436 unsafe extern "C" fn create_ext<C: FileSystemInterface>(
1437 file_system: *mut FSP_FILE_SYSTEM,
1438 file_name: PWSTR,
1439 create_options: UINT32,
1440 granted_access: UINT32,
1441 file_attributes: UINT32,
1442 security_descriptor: PSECURITY_DESCRIPTOR,
1443 allocation_size: UINT64,
1444 p_file_context: *mut PVOID,
1445 file_info: *mut FSP_FSCTL_FILE_INFO,
1446 ) -> NTSTATUS {
1447 let fs = &*(*file_system).UserContext.cast::<C>();
1448 let file_name = U16CStr::from_ptr_str(file_name);
1449 let sd = SecurityDescriptor::from_ptr(security_descriptor);
1450
1451 match C::create(
1452 fs,
1453 file_name,
1454 CreateFileInfo {
1455 create_options: CreateOptions(create_options),
1456 granted_access: FileAccessRights(granted_access),
1457 file_attributes: FileAttributes(file_attributes),
1458 allocation_size,
1459 },
1460 sd,
1461 ) {
1462 Ok((fctx, finfo)) => {
1463 C::FileContext::write(fctx, p_file_context);
1464 *file_info = finfo.0;
1465 STATUS_SUCCESS
1466 }
1467 Err(e) => e,
1468 }
1469 }
1470
1471 /// Create new file or directory.
1472 /// - FileSystem - The file system on which this request is posted.
1473 /// - FileName - The name of the file or directory to be created.
1474 /// - CreateOptions - Create options for this request. This parameter has the
1475 /// same meaning as the CreateOptions parameter of the NtCreateFile API. User
1476 /// mode file systems should typically only be concerned with the flag
1477 /// FILE_DIRECTORY_FILE, which is an instruction to create a directory rather
1478 /// than a file. Some file systems may also want to pay attention to the
1479 /// FILE_NO_INTERMEDIATE_BUFFERING and FILE_WRITE_THROUGH flags, although
1480 /// these are typically handled by the FSD component.
1481 /// - GrantedAccess - Determines the specific access rights that have been
1482 /// granted for this request. Upon receiving this call all access checks have
1483 /// been performed and the user mode file system need not perform any
1484 /// additional checks. However this parameter may be useful to a user mode
1485 /// file system; for example the WinFsp-FUSE layer uses this parameter to
1486 /// determine which flags to use in its POSIX open() call.
1487 /// - FileAttributes - File attributes to apply to the newly created file or
1488 /// directory.
1489 /// - SecurityDescriptor - Security descriptor to apply to the newly created
1490 /// file or directory. This security descriptor will always be in
1491 /// self-relative format. Its length can be retrieved using the Windows
1492 /// GetSecurityDescriptorLength API. Will be NULL for named streams.
1493 /// - AllocationSize - Allocation size for the newly created file.
1494 /// - ExtraBuffer - Extended attributes or reparse point buffer.
1495 /// - ExtraLength - Extended attributes or reparse point buffer length.
1496 /// - ExtraBufferIsReparsePoint - FALSE: extra buffer is extended attributes;
1497 /// TRUE: extra buffer is reparse point.
1498 /// - PFileContext - [out] Pointer that will receive the file context on
1499 /// successful return from this call.
1500 /// - FileInfo - [out] Pointer to a structure that will receive the file
1501 /// information on successful return from this call. This information
1502 /// includes file attributes, file times, etc.
1503 unsafe extern "C" fn create_ex_ext<C: FileSystemInterface>(
1504 file_system: *mut FSP_FILE_SYSTEM,
1505 file_name: PWSTR,
1506 create_options: UINT32,
1507 granted_access: UINT32,
1508 file_attributes: UINT32,
1509 security_descriptor: PSECURITY_DESCRIPTOR,
1510 allocation_size: UINT64,
1511 extra_buffer: PVOID,
1512 extra_length: ULONG,
1513 extra_buffer_is_reparse_point: BOOLEAN,
1514 p_file_context: *mut PVOID,
1515 file_info: *mut FSP_FSCTL_FILE_INFO,
1516 ) -> NTSTATUS {
1517 let fs = &*(*file_system).UserContext.cast::<C>();
1518 let file_name = U16CStr::from_ptr_str(file_name);
1519 let sd = SecurityDescriptor::from_ptr(security_descriptor);
1520 let buffer = if !extra_buffer.is_null() {
1521 std::slice::from_raw_parts(extra_buffer.cast(), extra_length as usize)
1522 } else {
1523 &[]
1524 };
1525
1526 match C::create_ex(
1527 fs,
1528 file_name,
1529 CreateFileInfo {
1530 create_options: CreateOptions(create_options),
1531 granted_access: FileAccessRights(granted_access),
1532 file_attributes: FileAttributes(file_attributes),
1533 allocation_size,
1534 },
1535 sd,
1536 buffer,
1537 extra_buffer_is_reparse_point != 0,
1538 ) {
1539 Ok((fctx, finfo)) => {
1540 C::FileContext::write(fctx, p_file_context);
1541 *file_info = finfo.0;
1542 STATUS_SUCCESS
1543 }
1544 Err(e) => e,
1545 }
1546 }
1547
1548 /// Overwrite a file.
1549 /// - FileSystem - The file system on which this request is posted.
1550 /// - FileContext - The file context of the file to overwrite.
1551 /// - FileAttributes - File attributes to apply to the overwritten file.
1552 /// - ReplaceFileAttributes - When TRUE the existing file attributes should be
1553 /// replaced with the new ones. When FALSE the existing file attributes
1554 /// should be merged (or'ed) with the new ones.
1555 /// - AllocationSize - Allocation size for the overwritten file.
1556 /// - FileInfo - [out] Pointer to a structure that will receive the file
1557 /// information on successful return from this call. This information
1558 /// includes file attributes, file times, etc.
1559 unsafe extern "C" fn overwrite_ext<C: FileSystemInterface>(
1560 file_system: *mut FSP_FILE_SYSTEM,
1561 file_context: PVOID,
1562 file_attributes: UINT32,
1563 replace_file_attributes: BOOLEAN,
1564 allocation_size: UINT64,
1565 file_info: *mut FSP_FSCTL_FILE_INFO,
1566 ) -> NTSTATUS {
1567 let fs = &*(*file_system).UserContext.cast::<C>();
1568 let fctx = C::FileContext::access(file_context);
1569
1570 match C::overwrite(
1571 fs,
1572 fctx,
1573 FileAttributes(file_attributes),
1574 replace_file_attributes != 0,
1575 allocation_size,
1576 ) {
1577 Ok(finfo) => {
1578 *file_info = finfo.0;
1579 STATUS_SUCCESS
1580 }
1581 Err(e) => e,
1582 }
1583 }
1584
1585 /// Overwrite a file.
1586 /// - FileSystem - The file system on which this request is posted.
1587 /// - FileContext - The file context of the file to overwrite.
1588 /// - FileAttributes - File attributes to apply to the overwritten file.
1589 /// - ReplaceFileAttributes - When TRUE the existing file attributes should be
1590 /// replaced with the new ones. When FALSE the existing file attributes
1591 /// should be merged (or'ed) with the new ones.
1592 /// - AllocationSize - Allocation size for the overwritten file.
1593 /// - Ea - Extended attributes buffer.
1594 /// - EaLength - Extended attributes buffer length.
1595 /// - FileInfo - [out] Pointer to a structure that will receive the file
1596 /// information on successful return from this call. This information
1597 /// includes file attributes, file times, etc.
1598 unsafe extern "C" fn overwrite_ex_ext<C: FileSystemInterface>(
1599 file_system: *mut FSP_FILE_SYSTEM,
1600 file_context: PVOID,
1601 file_attributes: UINT32,
1602 replace_file_attributes: BOOLEAN,
1603 allocation_size: UINT64,
1604 ea: PFILE_FULL_EA_INFORMATION,
1605 ea_length: ULONG,
1606 file_info: *mut FSP_FSCTL_FILE_INFO,
1607 ) -> NTSTATUS {
1608 let fs = &*(*file_system).UserContext.cast::<C>();
1609 let fctx = C::FileContext::access(file_context);
1610 let buffer = if !ea.is_null() {
1611 std::slice::from_raw_parts(ea.cast(), ea_length as usize)
1612 } else {
1613 &[]
1614 };
1615
1616 match C::overwrite_ex(
1617 fs,
1618 fctx,
1619 FileAttributes(file_attributes),
1620 replace_file_attributes != 0,
1621 allocation_size,
1622 buffer,
1623 ) {
1624 Ok(finfo) => {
1625 *file_info = finfo.0;
1626 STATUS_SUCCESS
1627 }
1628 Err(e) => e,
1629 }
1630 }
1631
1632 /// Get extended attributes.
1633 /// - FileSystem - The file system on which this request is posted.
1634 /// - FileContext - The file context of the file to get extended attributes
1635 /// for.
1636 /// - Ea - Extended attributes buffer.
1637 /// - EaLength - Extended attributes buffer length.
1638 /// - PBytesTransferred - [out] Pointer to a memory location that will receive
1639 /// the actual number of bytes transferred.
1640 unsafe extern "C" fn get_ea_ext<C: FileSystemInterface>(
1641 file_system: *mut FSP_FILE_SYSTEM,
1642 file_context: PVOID,
1643 ea: PFILE_FULL_EA_INFORMATION,
1644 ea_length: ULONG,
1645 p_bytes_transferred: PULONG,
1646 ) -> NTSTATUS {
1647 let fs = &*(*file_system).UserContext.cast::<C>();
1648 let fctx = C::FileContext::access(file_context);
1649 let buffer = if !ea.is_null() {
1650 std::slice::from_raw_parts(ea.cast(), ea_length as usize)
1651 } else {
1652 &[]
1653 };
1654
1655 match C::get_ea(fs, fctx, buffer) {
1656 Ok(bytes_transfered) => {
1657 p_bytes_transferred.write(bytes_transfered as ULONG);
1658 STATUS_SUCCESS
1659 }
1660 Err(e) => e,
1661 }
1662 }
1663
1664 /// Set extended attributes.
1665 /// - FileSystem - The file system on which this request is posted.
1666 /// - FileContext - The file context of the file to set extended attributes
1667 /// for.
1668 /// - Ea - Extended attributes buffer.
1669 /// - EaLength - Extended attributes buffer length.
1670 /// - FileInfo - [out] Pointer to a structure that will receive the file
1671 /// information on successful return from this call. This information
1672 /// includes file attributes, file times, etc.
1673 unsafe extern "C" fn set_ea_ext<C: FileSystemInterface>(
1674 file_system: *mut FSP_FILE_SYSTEM,
1675 file_context: PVOID,
1676 ea: PFILE_FULL_EA_INFORMATION,
1677 ea_length: ULONG,
1678 file_info: *mut FSP_FSCTL_FILE_INFO,
1679 ) -> NTSTATUS {
1680 let fs = &*(*file_system).UserContext.cast::<C>();
1681 let fctx = C::FileContext::access(file_context);
1682 let buffer = if !ea.is_null() {
1683 std::slice::from_raw_parts(ea.cast(), ea_length as usize)
1684 } else {
1685 &[]
1686 };
1687
1688 match C::set_ea(fs, fctx, buffer) {
1689 Ok(info) => {
1690 file_info.write(info.0);
1691 STATUS_SUCCESS
1692 }
1693 Err(e) => e,
1694 }
1695 }
1696
1697 unsafe extern "C" fn dispatcher_stopped_ext<C: FileSystemInterface>(
1698 file_system: *mut FSP_FILE_SYSTEM,
1699 normally: BOOLEAN,
1700 ) {
1701 let fs = &*(*file_system).UserContext.cast::<C>();
1702
1703 C::dispatcher_stopped(fs, normally != 0);
1704
1705 FspFileSystemStopServiceIfNecessary(file_system, normally)
1706 }
1707
1708 pub(crate) fn interface<Ctx: FileSystemInterface>() -> FSP_FILE_SYSTEM_INTERFACE {
1709 macro_rules! set_fn_pointer_or_null {
1710 ($flag_name:ident, $fn_ext_name:ident) => {
1711 if Ctx::$flag_name {
1712 Some(Self::$fn_ext_name::<Ctx>)
1713 } else {
1714 None
1715 }
1716 };
1717 }
1718
1719 FSP_FILE_SYSTEM_INTERFACE {
1720 GetVolumeInfo: set_fn_pointer_or_null!(GET_VOLUME_INFO_DEFINED, get_volume_info_ext),
1721 SetVolumeLabelW: set_fn_pointer_or_null!(
1722 SET_VOLUME_LABEL_DEFINED,
1723 set_volume_label_w_ext
1724 ),
1725 GetSecurityByName: set_fn_pointer_or_null!(
1726 GET_SECURITY_BY_NAME_DEFINED,
1727 get_security_by_name_ext
1728 ),
1729 Create: set_fn_pointer_or_null!(CREATE_DEFINED, create_ext),
1730 CreateEx: set_fn_pointer_or_null!(CREATE_EX_DEFINED, create_ex_ext),
1731 Open: set_fn_pointer_or_null!(OPEN_DEFINED, open_ext),
1732 Overwrite: set_fn_pointer_or_null!(OVERWRITE_DEFINED, overwrite_ext),
1733 OverwriteEx: set_fn_pointer_or_null!(OVERWRITE_EX_DEFINED, overwrite_ex_ext),
1734 Cleanup: set_fn_pointer_or_null!(CLEANUP_DEFINED, cleanup_ext),
1735 Close: set_fn_pointer_or_null!(CLOSE_DEFINED, close_ext),
1736 Read: set_fn_pointer_or_null!(READ_DEFINED, read_ext),
1737 Write: set_fn_pointer_or_null!(WRITE_DEFINED, write_ext),
1738 Flush: set_fn_pointer_or_null!(FLUSH_DEFINED, flush_ext),
1739 GetFileInfo: set_fn_pointer_or_null!(GET_FILE_INFO_DEFINED, get_file_info_ext),
1740 SetBasicInfo: set_fn_pointer_or_null!(SET_BASIC_INFO_DEFINED, set_basic_info_ext),
1741 SetFileSize: set_fn_pointer_or_null!(SET_FILE_SIZE_DEFINED, set_file_size_ext),
1742 CanDelete: set_fn_pointer_or_null!(CAN_DELETE_DEFINED, can_delete_ext),
1743 Rename: set_fn_pointer_or_null!(RENAME_DEFINED, rename_ext),
1744 GetSecurity: set_fn_pointer_or_null!(GET_SECURITY_DEFINED, get_security_ext),
1745 SetSecurity: set_fn_pointer_or_null!(SET_SECURITY_DEFINED, set_security_ext),
1746 ReadDirectory: set_fn_pointer_or_null!(READ_DIRECTORY_DEFINED, read_directory_ext),
1747 GetReparsePoint: set_fn_pointer_or_null!(
1748 GET_REPARSE_POINT_DEFINED,
1749 get_reparse_point_ext
1750 ),
1751 SetReparsePoint: set_fn_pointer_or_null!(
1752 SET_REPARSE_POINT_DEFINED,
1753 set_reparse_point_ext
1754 ),
1755 DeleteReparsePoint: set_fn_pointer_or_null!(
1756 DELETE_REPARSE_POINT_DEFINED,
1757 delete_reparse_point_ext
1758 ),
1759 GetStreamInfo: set_fn_pointer_or_null!(GET_STREAM_INFO_DEFINED, get_stream_info_ext),
1760 GetDirInfoByName: set_fn_pointer_or_null!(
1761 GET_DIR_INFO_BY_NAME_DEFINED,
1762 get_dir_info_by_name_ext
1763 ),
1764 Control: set_fn_pointer_or_null!(CONTROL_DEFINED, control_ext),
1765 SetDelete: set_fn_pointer_or_null!(SET_DELETE_DEFINED, set_delete_ext),
1766 GetEa: set_fn_pointer_or_null!(GET_EA_DEFINED, get_ea_ext),
1767 SetEa: set_fn_pointer_or_null!(SET_EA_DEFINED, set_ea_ext),
1768 DispatcherStopped: set_fn_pointer_or_null!(
1769 DISPATCHER_STOPPED_DEFINED,
1770 dispatcher_stopped_ext
1771 ),
1772 ResolveReparsePoints: set_fn_pointer_or_null!(
1773 RESOLVE_REPARSE_POINTS_DEFINED,
1774 resolve_reparse_points_ext
1775 ),
1776
1777 ..Default::default() // Initializing `Obsolete0` & `Reserved` fields
1778 }
1779 }
1780}