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}