mirror of
https://github.com/winfsp/winfsp.git
synced 2025-04-22 08:23:05 -05:00
sys, dll: reparse point (symbolic link) support: WIP
This commit is contained in:
parent
380ec074ca
commit
a8d76d3e46
@ -124,7 +124,9 @@ typedef struct
|
|||||||
UINT32 CasePreservedNames:1; /* file system preserves the case of file names */
|
UINT32 CasePreservedNames:1; /* file system preserves the case of file names */
|
||||||
UINT32 UnicodeOnDisk:1; /* file system supports Unicode in file names */
|
UINT32 UnicodeOnDisk:1; /* file system supports Unicode in file names */
|
||||||
UINT32 PersistentAcls:1; /* file system preserves and enforces access control lists */
|
UINT32 PersistentAcls:1; /* file system preserves and enforces access control lists */
|
||||||
UINT32 ReparsePoints:1; /* file system supports reparse points (!!!: unimplemented) */
|
UINT32 ReparsePoints:1; /* file system supports reparse points */
|
||||||
|
UINT32 ReparsePointPrivilegeCheck:1;/* file system perform reparse point privilege checks */
|
||||||
|
UINT32 SymbolicLinksOnly:1; /* file system supports only symbolic link reparse points */
|
||||||
UINT32 NamedStreams:1; /* file system supports named streams (!!!: unimplemented) */
|
UINT32 NamedStreams:1; /* file system supports named streams (!!!: unimplemented) */
|
||||||
UINT32 HardLinks:1; /* unimplemented; set to 0 */
|
UINT32 HardLinks:1; /* unimplemented; set to 0 */
|
||||||
UINT32 ExtendedAttributes:1; /* unimplemented; set to 0 */
|
UINT32 ExtendedAttributes:1; /* unimplemented; set to 0 */
|
||||||
@ -288,6 +290,13 @@ typedef struct
|
|||||||
FSP_FSCTL_TRANSACT_BUF Pattern;
|
FSP_FSCTL_TRANSACT_BUF Pattern;
|
||||||
} QueryDirectory;
|
} QueryDirectory;
|
||||||
struct
|
struct
|
||||||
|
{
|
||||||
|
UINT64 UserContext;
|
||||||
|
UINT64 UserContext2;
|
||||||
|
UINT32 FsControlCode;
|
||||||
|
FSP_FSCTL_TRANSACT_BUF Buffer;
|
||||||
|
} FileSystemControl;
|
||||||
|
struct
|
||||||
{
|
{
|
||||||
UINT64 UserContext;
|
UINT64 UserContext;
|
||||||
UINT64 UserContext2;
|
UINT64 UserContext2;
|
||||||
@ -328,9 +337,10 @@ typedef struct
|
|||||||
FSP_FSCTL_FILE_INFO FileInfo;
|
FSP_FSCTL_FILE_INFO FileInfo;
|
||||||
} Opened;
|
} Opened;
|
||||||
/* IoStatus.Status == STATUS_REPARSE */
|
/* IoStatus.Status == STATUS_REPARSE */
|
||||||
struct
|
union
|
||||||
{
|
{
|
||||||
FSP_FSCTL_TRANSACT_BUF FileName; /* file name to use for STATUS_REPARSE */
|
FSP_FSCTL_TRANSACT_BUF FileName; /* IoStatus.Information == IO_REPARSE (== 0) */
|
||||||
|
FSP_FSCTL_TRANSACT_BUF Data; /* IoStatus.Information > IO_REMOUNT (== 1) */
|
||||||
} Reparse;
|
} Reparse;
|
||||||
} Create;
|
} Create;
|
||||||
struct
|
struct
|
||||||
@ -358,6 +368,10 @@ typedef struct
|
|||||||
FSP_FSCTL_VOLUME_INFO VolumeInfo;
|
FSP_FSCTL_VOLUME_INFO VolumeInfo;
|
||||||
} SetVolumeInformation;
|
} SetVolumeInformation;
|
||||||
struct
|
struct
|
||||||
|
{
|
||||||
|
FSP_FSCTL_TRANSACT_BUF Buffer;
|
||||||
|
} FileSystemControl;
|
||||||
|
struct
|
||||||
{
|
{
|
||||||
FSP_FSCTL_TRANSACT_BUF SecurityDescriptor;
|
FSP_FSCTL_TRANSACT_BUF SecurityDescriptor;
|
||||||
} QuerySecurity;
|
} QuerySecurity;
|
||||||
|
@ -54,6 +54,35 @@ typedef NTSTATUS FSP_FILE_SYSTEM_OPERATION_GUARD(FSP_FILE_SYSTEM *,
|
|||||||
FSP_FSCTL_TRANSACT_REQ *, FSP_FSCTL_TRANSACT_RSP *);
|
FSP_FSCTL_TRANSACT_REQ *, FSP_FSCTL_TRANSACT_RSP *);
|
||||||
typedef NTSTATUS FSP_FILE_SYSTEM_OPERATION(FSP_FILE_SYSTEM *,
|
typedef NTSTATUS FSP_FILE_SYSTEM_OPERATION(FSP_FILE_SYSTEM *,
|
||||||
FSP_FSCTL_TRANSACT_REQ *, FSP_FSCTL_TRANSACT_RSP *);
|
FSP_FSCTL_TRANSACT_REQ *, FSP_FSCTL_TRANSACT_RSP *);
|
||||||
|
/**
|
||||||
|
* User mode file system locking strategy.
|
||||||
|
*
|
||||||
|
* Two concurrency models are provided:
|
||||||
|
*
|
||||||
|
* 1. A fine-grained concurrency model where file system NAMESPACE accesses
|
||||||
|
* are guarded using an exclusive-shared (read-write) lock. File I/O is not
|
||||||
|
* guarded and concurrent reads/writes/etc. are possible. [Note that the FSD
|
||||||
|
* will still apply an exclusive-shared lock PER INDIVIDUAL FILE, but it will
|
||||||
|
* not limit I/O operations for different files.]
|
||||||
|
*
|
||||||
|
* The fine-grained concurrency model applies the exclusive-shared lock as
|
||||||
|
* follows:
|
||||||
|
* <ul>
|
||||||
|
* <li>EXCL: SetVolumeLabel, Create, Cleanup(Delete), SetInformation(Rename)</li>
|
||||||
|
* <li>SHRD: GetVolumeInfo, Open, SetInformation(Disposition), ReadDirectory</li>
|
||||||
|
* <li>NONE: all other operations</li>
|
||||||
|
* </ul>
|
||||||
|
*
|
||||||
|
* 2. A coarse-grained concurrency model where all file system accesses are
|
||||||
|
* guarded by a mutually exclusive lock.
|
||||||
|
*
|
||||||
|
* @see FspFileSystemSetOperationGuardStrategy
|
||||||
|
*/
|
||||||
|
typedef enum
|
||||||
|
{
|
||||||
|
FSP_FILE_SYSTEM_OPERATION_GUARD_STRATEGY_FINE = 0,
|
||||||
|
FSP_FILE_SYSTEM_OPERATION_GUARD_STRATEGY_COARSE,
|
||||||
|
} FSP_FILE_SYSTEM_OPERATION_GUARD_STRATEGY;
|
||||||
/**
|
/**
|
||||||
* @class FSP_FILE_SYSTEM
|
* @class FSP_FILE_SYSTEM
|
||||||
* File system interface.
|
* File system interface.
|
||||||
@ -74,7 +103,7 @@ typedef struct _FSP_FILE_SYSTEM_INTERFACE
|
|||||||
* Pointer to a structure that will receive the volume information on successful return
|
* Pointer to a structure that will receive the volume information on successful return
|
||||||
* from this call.
|
* from this call.
|
||||||
* @return
|
* @return
|
||||||
* STATUS_SUCCESS on error code.
|
* STATUS_SUCCESS or error code.
|
||||||
*/
|
*/
|
||||||
NTSTATUS (*GetVolumeInfo)(FSP_FILE_SYSTEM *FileSystem,
|
NTSTATUS (*GetVolumeInfo)(FSP_FILE_SYSTEM *FileSystem,
|
||||||
FSP_FSCTL_TRANSACT_REQ *Request,
|
FSP_FSCTL_TRANSACT_REQ *Request,
|
||||||
@ -92,7 +121,7 @@ typedef struct _FSP_FILE_SYSTEM_INTERFACE
|
|||||||
* Pointer to a structure that will receive the volume information on successful return
|
* Pointer to a structure that will receive the volume information on successful return
|
||||||
* from this call.
|
* from this call.
|
||||||
* @return
|
* @return
|
||||||
* STATUS_SUCCESS on error code.
|
* STATUS_SUCCESS or error code.
|
||||||
*/
|
*/
|
||||||
NTSTATUS (*SetVolumeLabel)(FSP_FILE_SYSTEM *FileSystem,
|
NTSTATUS (*SetVolumeLabel)(FSP_FILE_SYSTEM *FileSystem,
|
||||||
FSP_FSCTL_TRANSACT_REQ *Request,
|
FSP_FSCTL_TRANSACT_REQ *Request,
|
||||||
@ -116,7 +145,11 @@ typedef struct _FSP_FILE_SYSTEM_INTERFACE
|
|||||||
* security descriptor buffer. On output it will contain the actual size of the security
|
* security descriptor buffer. On output it will contain the actual size of the security
|
||||||
* descriptor copied into the security descriptor buffer. May be NULL.
|
* descriptor copied into the security descriptor buffer. May be NULL.
|
||||||
* @return
|
* @return
|
||||||
* STATUS_SUCCESS on error code.
|
* STATUS_SUCCESS, STATUS_REPARSE or error code.
|
||||||
|
*
|
||||||
|
* STATUS_REPARSE should be returned by file systems that support reparse points when
|
||||||
|
* they encounter a FileName that contains reparse points anywhere but the final path
|
||||||
|
* component.
|
||||||
*/
|
*/
|
||||||
NTSTATUS (*GetSecurityByName)(FSP_FILE_SYSTEM *FileSystem,
|
NTSTATUS (*GetSecurityByName)(FSP_FILE_SYSTEM *FileSystem,
|
||||||
PWSTR FileName, PUINT32 PFileAttributes,
|
PWSTR FileName, PUINT32 PFileAttributes,
|
||||||
@ -158,7 +191,7 @@ typedef struct _FSP_FILE_SYSTEM_INTERFACE
|
|||||||
* Pointer to a structure that will receive the file information on successful return
|
* Pointer to a structure that will receive the file information on successful return
|
||||||
* from this call. This information includes file attributes, file times, etc.
|
* from this call. This information includes file attributes, file times, etc.
|
||||||
* @return
|
* @return
|
||||||
* STATUS_SUCCESS on error code.
|
* STATUS_SUCCESS or error code.
|
||||||
*/
|
*/
|
||||||
NTSTATUS (*Create)(FSP_FILE_SYSTEM *FileSystem,
|
NTSTATUS (*Create)(FSP_FILE_SYSTEM *FileSystem,
|
||||||
FSP_FSCTL_TRANSACT_REQ *Request,
|
FSP_FSCTL_TRANSACT_REQ *Request,
|
||||||
@ -193,7 +226,7 @@ typedef struct _FSP_FILE_SYSTEM_INTERFACE
|
|||||||
* Pointer to a structure that will receive the file information on successful return
|
* Pointer to a structure that will receive the file information on successful return
|
||||||
* from this call. This information includes file attributes, file times, etc.
|
* from this call. This information includes file attributes, file times, etc.
|
||||||
* @return
|
* @return
|
||||||
* STATUS_SUCCESS on error code.
|
* STATUS_SUCCESS or error code.
|
||||||
*/
|
*/
|
||||||
NTSTATUS (*Open)(FSP_FILE_SYSTEM *FileSystem,
|
NTSTATUS (*Open)(FSP_FILE_SYSTEM *FileSystem,
|
||||||
FSP_FSCTL_TRANSACT_REQ *Request,
|
FSP_FSCTL_TRANSACT_REQ *Request,
|
||||||
@ -217,7 +250,7 @@ typedef struct _FSP_FILE_SYSTEM_INTERFACE
|
|||||||
* Pointer to a structure that will receive the file information on successful return
|
* Pointer to a structure that will receive the file information on successful return
|
||||||
* from this call. This information includes file attributes, file times, etc.
|
* from this call. This information includes file attributes, file times, etc.
|
||||||
* @return
|
* @return
|
||||||
* STATUS_SUCCESS on error code.
|
* STATUS_SUCCESS or error code.
|
||||||
*/
|
*/
|
||||||
NTSTATUS (*Overwrite)(FSP_FILE_SYSTEM *FileSystem,
|
NTSTATUS (*Overwrite)(FSP_FILE_SYSTEM *FileSystem,
|
||||||
FSP_FSCTL_TRANSACT_REQ *Request,
|
FSP_FSCTL_TRANSACT_REQ *Request,
|
||||||
@ -292,7 +325,7 @@ typedef struct _FSP_FILE_SYSTEM_INTERFACE
|
|||||||
* @param PBytesTransferred [out]
|
* @param PBytesTransferred [out]
|
||||||
* Pointer to a memory location that will receive the actual number of bytes read.
|
* Pointer to a memory location that will receive the actual number of bytes read.
|
||||||
* @return
|
* @return
|
||||||
* STATUS_SUCCESS on error code. STATUS_PENDING is supported allowing for asynchronous
|
* STATUS_SUCCESS or error code. STATUS_PENDING is supported allowing for asynchronous
|
||||||
* operation.
|
* operation.
|
||||||
*/
|
*/
|
||||||
NTSTATUS (*Read)(FSP_FILE_SYSTEM *FileSystem,
|
NTSTATUS (*Read)(FSP_FILE_SYSTEM *FileSystem,
|
||||||
@ -325,7 +358,7 @@ typedef struct _FSP_FILE_SYSTEM_INTERFACE
|
|||||||
* Pointer to a structure that will receive the file information on successful return
|
* Pointer to a structure that will receive the file information on successful return
|
||||||
* from this call. This information includes file attributes, file times, etc.
|
* from this call. This information includes file attributes, file times, etc.
|
||||||
* @return
|
* @return
|
||||||
* STATUS_SUCCESS on error code. STATUS_PENDING is supported allowing for asynchronous
|
* STATUS_SUCCESS or error code. STATUS_PENDING is supported allowing for asynchronous
|
||||||
* operation.
|
* operation.
|
||||||
*/
|
*/
|
||||||
NTSTATUS (*Write)(FSP_FILE_SYSTEM *FileSystem,
|
NTSTATUS (*Write)(FSP_FILE_SYSTEM *FileSystem,
|
||||||
@ -345,7 +378,7 @@ typedef struct _FSP_FILE_SYSTEM_INTERFACE
|
|||||||
* @param FileNode
|
* @param FileNode
|
||||||
* The file node of the file to be flushed. When NULL the whole volume is being flushed.
|
* The file node of the file to be flushed. When NULL the whole volume is being flushed.
|
||||||
* @return
|
* @return
|
||||||
* STATUS_SUCCESS on error code.
|
* STATUS_SUCCESS or error code.
|
||||||
*/
|
*/
|
||||||
NTSTATUS (*Flush)(FSP_FILE_SYSTEM *FileSystem,
|
NTSTATUS (*Flush)(FSP_FILE_SYSTEM *FileSystem,
|
||||||
FSP_FSCTL_TRANSACT_REQ *Request,
|
FSP_FSCTL_TRANSACT_REQ *Request,
|
||||||
@ -363,7 +396,7 @@ typedef struct _FSP_FILE_SYSTEM_INTERFACE
|
|||||||
* Pointer to a structure that will receive the file information on successful return
|
* Pointer to a structure that will receive the file information on successful return
|
||||||
* from this call. This information includes file attributes, file times, etc.
|
* from this call. This information includes file attributes, file times, etc.
|
||||||
* @return
|
* @return
|
||||||
* STATUS_SUCCESS on error code.
|
* STATUS_SUCCESS or error code.
|
||||||
*/
|
*/
|
||||||
NTSTATUS (*GetFileInfo)(FSP_FILE_SYSTEM *FileSystem,
|
NTSTATUS (*GetFileInfo)(FSP_FILE_SYSTEM *FileSystem,
|
||||||
FSP_FSCTL_TRANSACT_REQ *Request,
|
FSP_FSCTL_TRANSACT_REQ *Request,
|
||||||
@ -394,7 +427,7 @@ typedef struct _FSP_FILE_SYSTEM_INTERFACE
|
|||||||
* Pointer to a structure that will receive the file information on successful return
|
* Pointer to a structure that will receive the file information on successful return
|
||||||
* from this call. This information includes file attributes, file times, etc.
|
* from this call. This information includes file attributes, file times, etc.
|
||||||
* @return
|
* @return
|
||||||
* STATUS_SUCCESS on error code.
|
* STATUS_SUCCESS or error code.
|
||||||
*/
|
*/
|
||||||
NTSTATUS (*SetBasicInfo)(FSP_FILE_SYSTEM *FileSystem,
|
NTSTATUS (*SetBasicInfo)(FSP_FILE_SYSTEM *FileSystem,
|
||||||
FSP_FSCTL_TRANSACT_REQ *Request,
|
FSP_FSCTL_TRANSACT_REQ *Request,
|
||||||
@ -435,7 +468,7 @@ typedef struct _FSP_FILE_SYSTEM_INTERFACE
|
|||||||
* Pointer to a structure that will receive the file information on successful return
|
* Pointer to a structure that will receive the file information on successful return
|
||||||
* from this call. This information includes file attributes, file times, etc.
|
* from this call. This information includes file attributes, file times, etc.
|
||||||
* @return
|
* @return
|
||||||
* STATUS_SUCCESS on error code.
|
* STATUS_SUCCESS or error code.
|
||||||
*/
|
*/
|
||||||
NTSTATUS (*SetFileSize)(FSP_FILE_SYSTEM *FileSystem,
|
NTSTATUS (*SetFileSize)(FSP_FILE_SYSTEM *FileSystem,
|
||||||
FSP_FSCTL_TRANSACT_REQ *Request,
|
FSP_FSCTL_TRANSACT_REQ *Request,
|
||||||
@ -463,7 +496,7 @@ typedef struct _FSP_FILE_SYSTEM_INTERFACE
|
|||||||
* @param FileName
|
* @param FileName
|
||||||
* The name of the file or directory to test for deletion.
|
* The name of the file or directory to test for deletion.
|
||||||
* @return
|
* @return
|
||||||
* STATUS_SUCCESS on error code.
|
* STATUS_SUCCESS or error code.
|
||||||
* @see
|
* @see
|
||||||
* Cleanup
|
* Cleanup
|
||||||
*/
|
*/
|
||||||
@ -495,7 +528,7 @@ typedef struct _FSP_FILE_SYSTEM_INTERFACE
|
|||||||
* @param ReplaceIfExists
|
* @param ReplaceIfExists
|
||||||
* Whether to replace a file that already exists at NewFileName.
|
* Whether to replace a file that already exists at NewFileName.
|
||||||
* @return
|
* @return
|
||||||
* STATUS_SUCCESS on error code.
|
* STATUS_SUCCESS or error code.
|
||||||
*/
|
*/
|
||||||
NTSTATUS (*Rename)(FSP_FILE_SYSTEM *FileSystem,
|
NTSTATUS (*Rename)(FSP_FILE_SYSTEM *FileSystem,
|
||||||
FSP_FSCTL_TRANSACT_REQ *Request,
|
FSP_FSCTL_TRANSACT_REQ *Request,
|
||||||
@ -516,7 +549,7 @@ typedef struct _FSP_FILE_SYSTEM_INTERFACE
|
|||||||
* security descriptor buffer. On output it will contain the actual size of the security
|
* security descriptor buffer. On output it will contain the actual size of the security
|
||||||
* descriptor copied into the security descriptor buffer. Cannot be NULL.
|
* descriptor copied into the security descriptor buffer. Cannot be NULL.
|
||||||
* @return
|
* @return
|
||||||
* STATUS_SUCCESS on error code.
|
* STATUS_SUCCESS or error code.
|
||||||
*/
|
*/
|
||||||
NTSTATUS (*GetSecurity)(FSP_FILE_SYSTEM *FileSystem,
|
NTSTATUS (*GetSecurity)(FSP_FILE_SYSTEM *FileSystem,
|
||||||
FSP_FSCTL_TRANSACT_REQ *Request,
|
FSP_FSCTL_TRANSACT_REQ *Request,
|
||||||
@ -535,7 +568,7 @@ typedef struct _FSP_FILE_SYSTEM_INTERFACE
|
|||||||
* Security descriptor to apply to the file or directory. This security descriptor will
|
* Security descriptor to apply to the file or directory. This security descriptor will
|
||||||
* always be in self-relative format.
|
* always be in self-relative format.
|
||||||
* @return
|
* @return
|
||||||
* STATUS_SUCCESS on error code.
|
* STATUS_SUCCESS or error code.
|
||||||
*/
|
*/
|
||||||
NTSTATUS (*SetSecurity)(FSP_FILE_SYSTEM *FileSystem,
|
NTSTATUS (*SetSecurity)(FSP_FILE_SYSTEM *FileSystem,
|
||||||
FSP_FSCTL_TRANSACT_REQ *Request,
|
FSP_FSCTL_TRANSACT_REQ *Request,
|
||||||
@ -566,7 +599,7 @@ typedef struct _FSP_FILE_SYSTEM_INTERFACE
|
|||||||
* @param PBytesTransferred [out]
|
* @param PBytesTransferred [out]
|
||||||
* Pointer to a memory location that will receive the actual number of bytes read.
|
* Pointer to a memory location that will receive the actual number of bytes read.
|
||||||
* @return
|
* @return
|
||||||
* STATUS_SUCCESS on error code. STATUS_PENDING is supported allowing for asynchronous
|
* STATUS_SUCCESS or error code. STATUS_PENDING is supported allowing for asynchronous
|
||||||
* operation.
|
* operation.
|
||||||
* @see
|
* @see
|
||||||
* FspFileSystemAddDirInfo
|
* FspFileSystemAddDirInfo
|
||||||
@ -576,12 +609,123 @@ typedef struct _FSP_FILE_SYSTEM_INTERFACE
|
|||||||
PVOID FileNode, PVOID Buffer, UINT64 Offset, ULONG Length,
|
PVOID FileNode, PVOID Buffer, UINT64 Offset, ULONG Length,
|
||||||
PWSTR Pattern,
|
PWSTR Pattern,
|
||||||
PULONG PBytesTransferred);
|
PULONG PBytesTransferred);
|
||||||
|
/**
|
||||||
|
* Resolve reparse points.
|
||||||
|
*
|
||||||
|
* A file or directory can contain a reparse point. A reparse point is data that has
|
||||||
|
* special meaning to the file system, Windows or user applications. For example, NTFS
|
||||||
|
* and Windows use reparse points to implement symbolic links. As another example,
|
||||||
|
* a particular file system may use reparse points to emulate UNIX FIFO's.
|
||||||
|
*
|
||||||
|
* Reparse points are a general mechanism for attaching special behavior to files. WinFsp
|
||||||
|
* supports any kind of reparse point. The symbolic link reparse point however is so
|
||||||
|
* important for many file systems (especially POSIX ones) that WinFsp implements special
|
||||||
|
* support for it.
|
||||||
|
*
|
||||||
|
* This function is expected to resolve as many reparse points as possible. If a reparse
|
||||||
|
* point is encountered that is not understood by the file system further reparse point
|
||||||
|
* resolution should stop; the reparse point data should be returned to the FSD with status
|
||||||
|
* STATUS_REPARSE/reparse-tag. If a reparse point (symbolic link) is encountered that is
|
||||||
|
* understood by the file system but points outside it, the reparse point should be
|
||||||
|
* resolved, but further reparse point resolution should stop; the resolved file name
|
||||||
|
* should be returned to the FSD with status STATUS_REPARSE/IO_REPARSE.
|
||||||
|
*
|
||||||
|
* @param FileSystem
|
||||||
|
* The file system on which this request is posted.
|
||||||
|
* @param FileName
|
||||||
|
* The name of the file or directory to have its reparse points resolved.
|
||||||
|
* @param OpenReparsePoint
|
||||||
|
* If TRUE, the last path component of FileName should not be resolved, even
|
||||||
|
* if it is a reparse point that can be resolved. If FALSE, all path components
|
||||||
|
* should be resolved if possible.
|
||||||
|
* @param PIoStatus
|
||||||
|
* Pointer to storage that will receive the status to return to the FSD. When
|
||||||
|
* this function succeeds it must set PIoStatus->Status to STATUS_REPARSE and
|
||||||
|
* PIoStatus->Information to either IO_REPARSE or the reparse tag.
|
||||||
|
* @param Buffer
|
||||||
|
* Pointer to a buffer that will receive the resolved file name (IO_REPARSE) or
|
||||||
|
* reparse data (reparse tag). If the function returns a file name, it should
|
||||||
|
* not be NULL terminated.
|
||||||
|
* @param PSize [in,out]
|
||||||
|
* Pointer to the buffer size. On input it contains the size of the buffer.
|
||||||
|
* On output it will contain the actual size of data copied.
|
||||||
|
* @return
|
||||||
|
* STATUS_REPARSE or error code.
|
||||||
|
*/
|
||||||
|
NTSTATUS (*ResolveReparsePoints)(FSP_FILE_SYSTEM *FileSystem,
|
||||||
|
PWSTR FileName, BOOLEAN OpenReparsePoint,
|
||||||
|
PIO_STATUS_BLOCK PIoStatus, PVOID Buffer, PSIZE_T PSize);
|
||||||
|
/**
|
||||||
|
* Get reparse point.
|
||||||
|
*
|
||||||
|
* The behavior of this function depends on the value of FSP_FSCTL_VOLUME_PARAMS ::
|
||||||
|
* SymbolicLinksOnly. If the value of SymbolicLinksOnly is FALSE the file system
|
||||||
|
* supports full reparse points and this function is expected to fill the buffer
|
||||||
|
* with a full reparse point. If the value of SymbolicLinksOnly is TRUE the file
|
||||||
|
* system supports symbolic links only as reparse points and this function is
|
||||||
|
* expected to fill the buffer with the symbolic link path.
|
||||||
|
*
|
||||||
|
* @param FileSystem
|
||||||
|
* The file system on which this request is posted.
|
||||||
|
* @param Request
|
||||||
|
* The request posted by the kernel mode FSD.
|
||||||
|
* @param FileNode
|
||||||
|
* The file node of the reparse point.
|
||||||
|
* @param FileName
|
||||||
|
* The file name of the reparse point.
|
||||||
|
* @param Buffer
|
||||||
|
* Pointer to a buffer that will receive the results of this operation. If
|
||||||
|
* the function returns a symbolic link path, it should not be NULL terminated.
|
||||||
|
* @param PSize [in,out]
|
||||||
|
* Pointer to the buffer size. On input it contains the size of the buffer.
|
||||||
|
* On output it will contain the actual size of data copied.
|
||||||
|
* @return
|
||||||
|
* STATUS_SUCCESS or error code.
|
||||||
|
* @see
|
||||||
|
* SetReparsePoint
|
||||||
|
*/
|
||||||
|
NTSTATUS (*GetReparsePoint)(FSP_FILE_SYSTEM *FileSystem,
|
||||||
|
FSP_FSCTL_TRANSACT_REQ *Request,
|
||||||
|
PVOID FileNode,
|
||||||
|
PWSTR FileName, PVOID Buffer, PSIZE_T PSize);
|
||||||
|
/**
|
||||||
|
* Set reparse point.
|
||||||
|
*
|
||||||
|
* The behavior of this function depends on the value of FSP_FSCTL_VOLUME_PARAMS ::
|
||||||
|
* SymbolicLinksOnly. If the value of SymbolicLinksOnly is FALSE the file system
|
||||||
|
* supports full reparse points and this function is expected to set the reparse point
|
||||||
|
* contained in the buffer. If the value of SymbolicLinksOnly is TRUE the file
|
||||||
|
* system supports symbolic links only as reparse points and this function is
|
||||||
|
* expected to set the symbolic link path contained in the buffer.
|
||||||
|
*
|
||||||
|
* @param FileSystem
|
||||||
|
* The file system on which this request is posted.
|
||||||
|
* @param Request
|
||||||
|
* The request posted by the kernel mode FSD.
|
||||||
|
* @param FileNode
|
||||||
|
* The file node of the reparse point.
|
||||||
|
* @param FileName
|
||||||
|
* The file name of the reparse point.
|
||||||
|
* @param Buffer
|
||||||
|
* Pointer to a buffer that contains the data for this operation. If this buffer
|
||||||
|
* contains a symbolic link path, it should not be assumed to be NULL terminated.
|
||||||
|
* @param Size
|
||||||
|
* Size of data to write.
|
||||||
|
* @return
|
||||||
|
* STATUS_SUCCESS or error code.
|
||||||
|
* @see
|
||||||
|
* GetReparsePoint
|
||||||
|
*/
|
||||||
|
NTSTATUS (*SetReparsePoint)(FSP_FILE_SYSTEM *FileSystem,
|
||||||
|
FSP_FSCTL_TRANSACT_REQ *Request,
|
||||||
|
PVOID FileNode,
|
||||||
|
PWSTR FileName, PVOID Buffer, SIZE_T Size);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* This ensures that this interface will always contain 64 function pointers.
|
* This ensures that this interface will always contain 64 function pointers.
|
||||||
* Please update when changing the interface as it is important for future compatibility.
|
* Please update when changing the interface as it is important for future compatibility.
|
||||||
*/
|
*/
|
||||||
NTSTATUS (*Reserved[45])();
|
NTSTATUS (*Reserved[42])();
|
||||||
} FSP_FILE_SYSTEM_INTERFACE;
|
} FSP_FILE_SYSTEM_INTERFACE;
|
||||||
#if defined(WINFSP_DLL_INTERNAL)
|
#if defined(WINFSP_DLL_INTERNAL)
|
||||||
/*
|
/*
|
||||||
@ -591,11 +735,6 @@ typedef struct _FSP_FILE_SYSTEM_INTERFACE
|
|||||||
static_assert(sizeof(FSP_FILE_SYSTEM_INTERFACE) == 64 * sizeof(NTSTATUS (*)()),
|
static_assert(sizeof(FSP_FILE_SYSTEM_INTERFACE) == 64 * sizeof(NTSTATUS (*)()),
|
||||||
"FSP_FILE_SYSTEM_INTERFACE must have 64 entries.");
|
"FSP_FILE_SYSTEM_INTERFACE must have 64 entries.");
|
||||||
#endif
|
#endif
|
||||||
typedef enum
|
|
||||||
{
|
|
||||||
FSP_FILE_SYSTEM_OPERATION_GUARD_STRATEGY_FINE = 0,
|
|
||||||
FSP_FILE_SYSTEM_OPERATION_GUARD_STRATEGY_COARSE,
|
|
||||||
} FSP_FILE_SYSTEM_OPERATION_GUARD_STRATEGY;
|
|
||||||
typedef struct _FSP_FILE_SYSTEM
|
typedef struct _FSP_FILE_SYSTEM
|
||||||
{
|
{
|
||||||
UINT16 Version;
|
UINT16 Version;
|
||||||
@ -628,7 +767,7 @@ typedef struct _FSP_FILE_SYSTEM
|
|||||||
* Pointer that will receive the file system object created on successful return from this
|
* Pointer that will receive the file system object created on successful return from this
|
||||||
* call.
|
* call.
|
||||||
* @return
|
* @return
|
||||||
* STATUS_SUCCESS on error code.
|
* STATUS_SUCCESS or error code.
|
||||||
*/
|
*/
|
||||||
FSP_API NTSTATUS FspFileSystemCreate(PWSTR DevicePath,
|
FSP_API NTSTATUS FspFileSystemCreate(PWSTR DevicePath,
|
||||||
const FSP_FSCTL_VOLUME_PARAMS *VolumeParams,
|
const FSP_FSCTL_VOLUME_PARAMS *VolumeParams,
|
||||||
@ -654,7 +793,7 @@ FSP_API VOID FspFileSystemDelete(FSP_FILE_SYSTEM *FileSystem);
|
|||||||
* The mount point for the new file system. A value of NULL means that the file system should
|
* The mount point for the new file system. A value of NULL means that the file system should
|
||||||
* use the next available drive letter counting downwards from Z: as its mount point.
|
* use the next available drive letter counting downwards from Z: as its mount point.
|
||||||
* @return
|
* @return
|
||||||
* STATUS_SUCCESS on error code.
|
* STATUS_SUCCESS or error code.
|
||||||
*/
|
*/
|
||||||
FSP_API NTSTATUS FspFileSystemSetMountPoint(FSP_FILE_SYSTEM *FileSystem, PWSTR MountPoint);
|
FSP_API NTSTATUS FspFileSystemSetMountPoint(FSP_FILE_SYSTEM *FileSystem, PWSTR MountPoint);
|
||||||
/**
|
/**
|
||||||
@ -677,7 +816,7 @@ FSP_API VOID FspFileSystemRemoveMountPoint(FSP_FILE_SYSTEM *FileSystem);
|
|||||||
* The number of threads for the file system dispatcher. A value of 0 will create a default
|
* The number of threads for the file system dispatcher. A value of 0 will create a default
|
||||||
* number of threads and should be chosen in most cases.
|
* number of threads and should be chosen in most cases.
|
||||||
* @return
|
* @return
|
||||||
* STATUS_SUCCESS on error code.
|
* STATUS_SUCCESS or error code.
|
||||||
*/
|
*/
|
||||||
FSP_API NTSTATUS FspFileSystemStartDispatcher(FSP_FILE_SYSTEM *FileSystem, ULONG ThreadCount);
|
FSP_API NTSTATUS FspFileSystemStartDispatcher(FSP_FILE_SYSTEM *FileSystem, ULONG ThreadCount);
|
||||||
/**
|
/**
|
||||||
@ -740,6 +879,16 @@ VOID FspFileSystemSetOperationGuard(FSP_FILE_SYSTEM *FileSystem,
|
|||||||
FileSystem->EnterOperation = EnterOperation;
|
FileSystem->EnterOperation = EnterOperation;
|
||||||
FileSystem->LeaveOperation = LeaveOperation;
|
FileSystem->LeaveOperation = LeaveOperation;
|
||||||
}
|
}
|
||||||
|
/**
|
||||||
|
* Set file system locking strategy.
|
||||||
|
*
|
||||||
|
* @param FileSystem
|
||||||
|
* The file system object.
|
||||||
|
* @param GuardStrategy
|
||||||
|
* The locking (guard) strategy.
|
||||||
|
* @see
|
||||||
|
* FSP_FILE_SYSTEM_OPERATION_GUARD_STRATEGY
|
||||||
|
*/
|
||||||
static inline
|
static inline
|
||||||
VOID FspFileSystemSetOperationGuardStrategy(FSP_FILE_SYSTEM *FileSystem,
|
VOID FspFileSystemSetOperationGuardStrategy(FSP_FILE_SYSTEM *FileSystem,
|
||||||
FSP_FILE_SYSTEM_OPERATION_GUARD_STRATEGY GuardStrategy)
|
FSP_FILE_SYSTEM_OPERATION_GUARD_STRATEGY GuardStrategy)
|
||||||
@ -807,6 +956,8 @@ FSP_API NTSTATUS FspFileSystemOpSetVolumeInformation(FSP_FILE_SYSTEM *FileSystem
|
|||||||
FSP_FSCTL_TRANSACT_REQ *Request, FSP_FSCTL_TRANSACT_RSP *Response);
|
FSP_FSCTL_TRANSACT_REQ *Request, FSP_FSCTL_TRANSACT_RSP *Response);
|
||||||
FSP_API NTSTATUS FspFileSystemOpQueryDirectory(FSP_FILE_SYSTEM *FileSystem,
|
FSP_API NTSTATUS FspFileSystemOpQueryDirectory(FSP_FILE_SYSTEM *FileSystem,
|
||||||
FSP_FSCTL_TRANSACT_REQ *Request, FSP_FSCTL_TRANSACT_RSP *Response);
|
FSP_FSCTL_TRANSACT_REQ *Request, FSP_FSCTL_TRANSACT_RSP *Response);
|
||||||
|
FSP_API NTSTATUS FspFileSystemOpFileSystemControl(FSP_FILE_SYSTEM *FileSystem,
|
||||||
|
FSP_FSCTL_TRANSACT_REQ *Request, FSP_FSCTL_TRANSACT_RSP *Response);
|
||||||
FSP_API NTSTATUS FspFileSystemOpQuerySecurity(FSP_FILE_SYSTEM *FileSystem,
|
FSP_API NTSTATUS FspFileSystemOpQuerySecurity(FSP_FILE_SYSTEM *FileSystem,
|
||||||
FSP_FSCTL_TRANSACT_REQ *Request, FSP_FSCTL_TRANSACT_RSP *Response);
|
FSP_FSCTL_TRANSACT_REQ *Request, FSP_FSCTL_TRANSACT_RSP *Response);
|
||||||
FSP_API NTSTATUS FspFileSystemOpSetSecurity(FSP_FILE_SYSTEM *FileSystem,
|
FSP_API NTSTATUS FspFileSystemOpSetSecurity(FSP_FILE_SYSTEM *FileSystem,
|
||||||
@ -973,7 +1124,7 @@ ULONG FspServiceRun(PWSTR ServiceName,
|
|||||||
* Pointer that will receive the service object created on successful return from this
|
* Pointer that will receive the service object created on successful return from this
|
||||||
* call.
|
* call.
|
||||||
* @return
|
* @return
|
||||||
* STATUS_SUCCESS on error code.
|
* STATUS_SUCCESS or error code.
|
||||||
*/
|
*/
|
||||||
FSP_API NTSTATUS FspServiceCreate(PWSTR ServiceName,
|
FSP_API NTSTATUS FspServiceCreate(PWSTR ServiceName,
|
||||||
FSP_SERVICE_START *OnStart,
|
FSP_SERVICE_START *OnStart,
|
||||||
@ -1053,7 +1204,7 @@ FSP_API ULONG FspServiceGetExitCode(FSP_SERVICE *Service);
|
|||||||
* @param Service
|
* @param Service
|
||||||
* The service object.
|
* The service object.
|
||||||
* @return
|
* @return
|
||||||
* STATUS_SUCCESS on error code.
|
* STATUS_SUCCESS or error code.
|
||||||
*/
|
*/
|
||||||
FSP_API NTSTATUS FspServiceLoop(FSP_SERVICE *Service);
|
FSP_API NTSTATUS FspServiceLoop(FSP_SERVICE *Service);
|
||||||
/**
|
/**
|
||||||
@ -1066,7 +1217,7 @@ FSP_API NTSTATUS FspServiceLoop(FSP_SERVICE *Service);
|
|||||||
* @param Service
|
* @param Service
|
||||||
* The service object.
|
* The service object.
|
||||||
* @return
|
* @return
|
||||||
* STATUS_SUCCESS on error code.
|
* STATUS_SUCCESS or error code.
|
||||||
*/
|
*/
|
||||||
FSP_API VOID FspServiceStop(FSP_SERVICE *Service);
|
FSP_API VOID FspServiceStop(FSP_SERVICE *Service);
|
||||||
/**
|
/**
|
||||||
|
@ -96,6 +96,7 @@ FSP_API NTSTATUS FspFileSystemCreate(PWSTR DevicePath,
|
|||||||
FileSystem->Operations[FspFsctlTransactQueryVolumeInformationKind] = FspFileSystemOpQueryVolumeInformation;
|
FileSystem->Operations[FspFsctlTransactQueryVolumeInformationKind] = FspFileSystemOpQueryVolumeInformation;
|
||||||
FileSystem->Operations[FspFsctlTransactSetVolumeInformationKind] = FspFileSystemOpSetVolumeInformation;
|
FileSystem->Operations[FspFsctlTransactSetVolumeInformationKind] = FspFileSystemOpSetVolumeInformation;
|
||||||
FileSystem->Operations[FspFsctlTransactQueryDirectoryKind] = FspFileSystemOpQueryDirectory;
|
FileSystem->Operations[FspFsctlTransactQueryDirectoryKind] = FspFileSystemOpQueryDirectory;
|
||||||
|
FileSystem->Operations[FspFsctlTransactFileSystemControlKind] = FspFileSystemOpFileSystemControl;
|
||||||
FileSystem->Operations[FspFsctlTransactQuerySecurityKind] = FspFileSystemOpQuerySecurity;
|
FileSystem->Operations[FspFsctlTransactQuerySecurityKind] = FspFileSystemOpQuerySecurity;
|
||||||
FileSystem->Operations[FspFsctlTransactSetSecurityKind] = FspFileSystemOpSetSecurity;
|
FileSystem->Operations[FspFsctlTransactSetSecurityKind] = FspFileSystemOpSetSecurity;
|
||||||
FileSystem->Interface = Interface;
|
FileSystem->Interface = Interface;
|
||||||
|
263
src/dll/fsop.c
263
src/dll/fsop.c
@ -17,25 +17,38 @@
|
|||||||
|
|
||||||
#include <dll/library.h>
|
#include <dll/library.h>
|
||||||
|
|
||||||
/*
|
/* the following definitions appear to be missing from the user mode headers */
|
||||||
* The FspFileSystemOpEnter/FspFileSystemOpLeave functions guard against
|
#define SYMLINK_FLAG_RELATIVE 1
|
||||||
* concurrent accesses. Two concurrency models are provided:
|
typedef struct _REPARSE_DATA_BUFFER
|
||||||
*
|
{
|
||||||
* 1. A fine-grained concurrency model where file system NAMESPACE accesses
|
ULONG ReparseTag;
|
||||||
* are guarded using an exclusive-shared (read-write) lock. File I/O is not
|
USHORT ReparseDataLength;
|
||||||
* guarded and concurrent reads/writes/etc. are possible. [Note that the FSD
|
USHORT Reserved;
|
||||||
* will still apply an exclusive-shared lock PER INDIVIDUAL FILE, but it will
|
union
|
||||||
* not limit I/O operations for different files.]
|
{
|
||||||
*
|
struct
|
||||||
* The fine-grained concurrency model applies the exclusive-shared lock as
|
{
|
||||||
* follows:
|
USHORT SubstituteNameOffset;
|
||||||
* - EXCL: SetVolumeLabel, Create, Cleanup(Delete), SetInformation(Rename)
|
USHORT SubstituteNameLength;
|
||||||
* - SHRD: GetVolumeInfo, Open, SetInformation(Disposition), ReadDirectory
|
USHORT PrintNameOffset;
|
||||||
* - NONE: all other operations
|
USHORT PrintNameLength;
|
||||||
*
|
ULONG Flags;
|
||||||
* 2. A coarse-grained concurrency model where all file system accesses are
|
WCHAR PathBuffer[1];
|
||||||
* guarded by a mutually exclusive lock.
|
} SymbolicLinkReparseBuffer;
|
||||||
*/
|
struct
|
||||||
|
{
|
||||||
|
USHORT SubstituteNameOffset;
|
||||||
|
USHORT SubstituteNameLength;
|
||||||
|
USHORT PrintNameOffset;
|
||||||
|
USHORT PrintNameLength;
|
||||||
|
WCHAR PathBuffer[1];
|
||||||
|
} MountPointReparseBuffer;
|
||||||
|
struct
|
||||||
|
{
|
||||||
|
UCHAR DataBuffer[1];
|
||||||
|
} GenericReparseBuffer;
|
||||||
|
} DUMMYUNIONNAME;
|
||||||
|
} REPARSE_DATA_BUFFER, *PREPARSE_DATA_BUFFER;
|
||||||
|
|
||||||
FSP_API NTSTATUS FspFileSystemOpEnter(FSP_FILE_SYSTEM *FileSystem,
|
FSP_API NTSTATUS FspFileSystemOpEnter(FSP_FILE_SYSTEM *FileSystem,
|
||||||
FSP_FSCTL_TRANSACT_REQ *Request, FSP_FSCTL_TRANSACT_RSP *Response)
|
FSP_FSCTL_TRANSACT_REQ *Request, FSP_FSCTL_TRANSACT_RSP *Response)
|
||||||
@ -107,9 +120,34 @@ FSP_API NTSTATUS FspFileSystemOpLeave(FSP_FILE_SYSTEM *FileSystem,
|
|||||||
return STATUS_SUCCESS;
|
return STATUS_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static inline
|
||||||
|
NTSTATUS FspFileSystemResolveReparsePoints(FSP_FILE_SYSTEM *FileSystem,
|
||||||
|
FSP_FSCTL_TRANSACT_REQ *Request, FSP_FSCTL_TRANSACT_RSP *Response)
|
||||||
|
{
|
||||||
|
NTSTATUS Result = STATUS_INVALID_DEVICE_REQUEST;
|
||||||
|
IO_STATUS_BLOCK IoStatus;
|
||||||
|
SIZE_T Size;
|
||||||
|
|
||||||
|
if (0 != FileSystem->Interface->ResolveReparsePoints)
|
||||||
|
{
|
||||||
|
memset(&IoStatus, 0, sizeof IoStatus);
|
||||||
|
Size = FSP_FSCTL_TRANSACT_RSP_SIZEMAX - FIELD_OFFSET(FSP_FSCTL_TRANSACT_RSP, Buffer);
|
||||||
|
Result = FileSystem->Interface->ResolveReparsePoints(FileSystem,
|
||||||
|
(PWSTR)Request->Buffer,
|
||||||
|
!!(Request->Req.Create.CreateOptions & FILE_OPEN_REPARSE_POINT),
|
||||||
|
&IoStatus,
|
||||||
|
Response->Buffer,
|
||||||
|
&Size);
|
||||||
|
if (STATUS_REPARSE == Result)
|
||||||
|
Response->IoStatus.Information = (UINT32)IoStatus.Information;
|
||||||
|
}
|
||||||
|
|
||||||
|
return Result;
|
||||||
|
}
|
||||||
|
|
||||||
static inline
|
static inline
|
||||||
NTSTATUS FspFileSystemCreateCheck(FSP_FILE_SYSTEM *FileSystem,
|
NTSTATUS FspFileSystemCreateCheck(FSP_FILE_SYSTEM *FileSystem,
|
||||||
FSP_FSCTL_TRANSACT_REQ *Request,
|
FSP_FSCTL_TRANSACT_REQ *Request, FSP_FSCTL_TRANSACT_RSP *Response,
|
||||||
BOOLEAN AllowTraverseCheck, PUINT32 PGrantedAccess,
|
BOOLEAN AllowTraverseCheck, PUINT32 PGrantedAccess,
|
||||||
PSECURITY_DESCRIPTOR *PSecurityDescriptor)
|
PSECURITY_DESCRIPTOR *PSecurityDescriptor)
|
||||||
{
|
{
|
||||||
@ -128,7 +166,9 @@ NTSTATUS FspFileSystemCreateCheck(FSP_FILE_SYSTEM *FileSystem,
|
|||||||
(Request->Req.Create.CreateOptions & FILE_DIRECTORY_FILE) ?
|
(Request->Req.Create.CreateOptions & FILE_DIRECTORY_FILE) ?
|
||||||
FILE_ADD_SUBDIRECTORY : FILE_ADD_FILE,
|
FILE_ADD_SUBDIRECTORY : FILE_ADD_FILE,
|
||||||
PGrantedAccess, PSecurityDescriptor);
|
PGrantedAccess, PSecurityDescriptor);
|
||||||
if (NT_SUCCESS(Result))
|
if (STATUS_REPARSE == Result)
|
||||||
|
Result = FspFileSystemResolveReparsePoints(FileSystem, Request, Response);
|
||||||
|
else if (NT_SUCCESS(Result))
|
||||||
{
|
{
|
||||||
*PGrantedAccess = (MAXIMUM_ALLOWED & Request->Req.Create.DesiredAccess) ?
|
*PGrantedAccess = (MAXIMUM_ALLOWED & Request->Req.Create.DesiredAccess) ?
|
||||||
FspGetFileGenericMapping()->GenericAll : Request->Req.Create.DesiredAccess;
|
FspGetFileGenericMapping()->GenericAll : Request->Req.Create.DesiredAccess;
|
||||||
@ -139,7 +179,7 @@ NTSTATUS FspFileSystemCreateCheck(FSP_FILE_SYSTEM *FileSystem,
|
|||||||
|
|
||||||
static inline
|
static inline
|
||||||
NTSTATUS FspFileSystemOpenCheck(FSP_FILE_SYSTEM *FileSystem,
|
NTSTATUS FspFileSystemOpenCheck(FSP_FILE_SYSTEM *FileSystem,
|
||||||
FSP_FSCTL_TRANSACT_REQ *Request,
|
FSP_FSCTL_TRANSACT_REQ *Request, FSP_FSCTL_TRANSACT_RSP *Response,
|
||||||
BOOLEAN AllowTraverseCheck, PUINT32 PGrantedAccess)
|
BOOLEAN AllowTraverseCheck, PUINT32 PGrantedAccess)
|
||||||
{
|
{
|
||||||
NTSTATUS Result;
|
NTSTATUS Result;
|
||||||
@ -158,7 +198,9 @@ NTSTATUS FspFileSystemOpenCheck(FSP_FILE_SYSTEM *FileSystem,
|
|||||||
Request->Req.Create.DesiredAccess |
|
Request->Req.Create.DesiredAccess |
|
||||||
((Request->Req.Create.CreateOptions & FILE_DELETE_ON_CLOSE) ? DELETE : 0),
|
((Request->Req.Create.CreateOptions & FILE_DELETE_ON_CLOSE) ? DELETE : 0),
|
||||||
PGrantedAccess);
|
PGrantedAccess);
|
||||||
if (NT_SUCCESS(Result))
|
if (STATUS_REPARSE == Result)
|
||||||
|
Result = FspFileSystemResolveReparsePoints(FileSystem, Request, Response);
|
||||||
|
else if (NT_SUCCESS(Result))
|
||||||
{
|
{
|
||||||
if (0 == (Request->Req.Create.DesiredAccess & MAXIMUM_ALLOWED))
|
if (0 == (Request->Req.Create.DesiredAccess & MAXIMUM_ALLOWED))
|
||||||
*PGrantedAccess &= ~DELETE | (Request->Req.Create.DesiredAccess & DELETE);
|
*PGrantedAccess &= ~DELETE | (Request->Req.Create.DesiredAccess & DELETE);
|
||||||
@ -169,7 +211,7 @@ NTSTATUS FspFileSystemOpenCheck(FSP_FILE_SYSTEM *FileSystem,
|
|||||||
|
|
||||||
static inline
|
static inline
|
||||||
NTSTATUS FspFileSystemOverwriteCheck(FSP_FILE_SYSTEM *FileSystem,
|
NTSTATUS FspFileSystemOverwriteCheck(FSP_FILE_SYSTEM *FileSystem,
|
||||||
FSP_FSCTL_TRANSACT_REQ *Request,
|
FSP_FSCTL_TRANSACT_REQ *Request, FSP_FSCTL_TRANSACT_RSP *Response,
|
||||||
BOOLEAN AllowTraverseCheck, PUINT32 PGrantedAccess)
|
BOOLEAN AllowTraverseCheck, PUINT32 PGrantedAccess)
|
||||||
{
|
{
|
||||||
NTSTATUS Result;
|
NTSTATUS Result;
|
||||||
@ -191,7 +233,9 @@ NTSTATUS FspFileSystemOverwriteCheck(FSP_FILE_SYSTEM *FileSystem,
|
|||||||
(Supersede ? DELETE : FILE_WRITE_DATA) |
|
(Supersede ? DELETE : FILE_WRITE_DATA) |
|
||||||
((Request->Req.Create.CreateOptions & FILE_DELETE_ON_CLOSE) ? DELETE : 0),
|
((Request->Req.Create.CreateOptions & FILE_DELETE_ON_CLOSE) ? DELETE : 0),
|
||||||
PGrantedAccess);
|
PGrantedAccess);
|
||||||
if (NT_SUCCESS(Result))
|
if (STATUS_REPARSE == Result)
|
||||||
|
Result = FspFileSystemResolveReparsePoints(FileSystem, Request, Response);
|
||||||
|
else if (NT_SUCCESS(Result))
|
||||||
{
|
{
|
||||||
if (0 == (Request->Req.Create.DesiredAccess & MAXIMUM_ALLOWED))
|
if (0 == (Request->Req.Create.DesiredAccess & MAXIMUM_ALLOWED))
|
||||||
*PGrantedAccess &= ~(DELETE | FILE_WRITE_DATA) |
|
*PGrantedAccess &= ~(DELETE | FILE_WRITE_DATA) |
|
||||||
@ -201,6 +245,26 @@ NTSTATUS FspFileSystemOverwriteCheck(FSP_FILE_SYSTEM *FileSystem,
|
|||||||
return Result;
|
return Result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static inline
|
||||||
|
NTSTATUS FspFileSystemOpenTargetDirectoryCheck(FSP_FILE_SYSTEM *FileSystem,
|
||||||
|
FSP_FSCTL_TRANSACT_REQ *Request, FSP_FSCTL_TRANSACT_RSP *Response,
|
||||||
|
PUINT32 PGrantedAccess)
|
||||||
|
{
|
||||||
|
NTSTATUS Result;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* OpenTargetDirectoryCheck consists of checking the parent directory
|
||||||
|
* for the desired access.
|
||||||
|
*/
|
||||||
|
|
||||||
|
Result = FspAccessCheck(FileSystem, Request, TRUE, TRUE, Request->Req.Create.DesiredAccess,
|
||||||
|
PGrantedAccess);
|
||||||
|
if (STATUS_REPARSE == Result)
|
||||||
|
Result = FspFileSystemResolveReparsePoints(FileSystem, Request, Response);
|
||||||
|
|
||||||
|
return Result;
|
||||||
|
}
|
||||||
|
|
||||||
static inline
|
static inline
|
||||||
NTSTATUS FspFileSystemRenameCheck(FSP_FILE_SYSTEM *FileSystem,
|
NTSTATUS FspFileSystemRenameCheck(FSP_FILE_SYSTEM *FileSystem,
|
||||||
FSP_FSCTL_TRANSACT_REQ *Request)
|
FSP_FSCTL_TRANSACT_REQ *Request)
|
||||||
@ -235,7 +299,9 @@ NTSTATUS FspFileSystemRenameCheck(FSP_FILE_SYSTEM *FileSystem,
|
|||||||
CreateRequest->Size = sizeof CreateRequest +
|
CreateRequest->Size = sizeof CreateRequest +
|
||||||
Request->Req.SetInformation.Info.Rename.NewFileName.Size;
|
Request->Req.SetInformation.Info.Rename.NewFileName.Size;
|
||||||
CreateRequest->Kind = FspFsctlTransactCreateKind;
|
CreateRequest->Kind = FspFsctlTransactCreateKind;
|
||||||
CreateRequest->Req.Create.CreateOptions = FILE_DELETE_ON_CLOSE; /* force read-only check! */
|
CreateRequest->Req.Create.CreateOptions =
|
||||||
|
FILE_DELETE_ON_CLOSE | /* force read-only check! */
|
||||||
|
FILE_OPEN_REPARSE_POINT; /* allow rename over reparse point */
|
||||||
CreateRequest->Req.Create.AccessToken = Request->Req.SetInformation.Info.Rename.AccessToken;
|
CreateRequest->Req.Create.AccessToken = Request->Req.SetInformation.Info.Rename.AccessToken;
|
||||||
CreateRequest->Req.Create.UserMode = TRUE;
|
CreateRequest->Req.Create.UserMode = TRUE;
|
||||||
CreateRequest->FileName.Offset = 0;
|
CreateRequest->FileName.Offset = 0;
|
||||||
@ -248,6 +314,9 @@ NTSTATUS FspFileSystemRenameCheck(FSP_FILE_SYSTEM *FileSystem,
|
|||||||
|
|
||||||
MemFree(CreateRequest);
|
MemFree(CreateRequest);
|
||||||
|
|
||||||
|
if (STATUS_REPARSE == Result)
|
||||||
|
Result = STATUS_SUCCESS; /* file system should not return STATUS_REPARSE during rename */
|
||||||
|
|
||||||
return Result;
|
return Result;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -260,8 +329,9 @@ static NTSTATUS FspFileSystemOpCreate_FileCreate(FSP_FILE_SYSTEM *FileSystem,
|
|||||||
PVOID FileNode;
|
PVOID FileNode;
|
||||||
FSP_FSCTL_FILE_INFO FileInfo;
|
FSP_FSCTL_FILE_INFO FileInfo;
|
||||||
|
|
||||||
Result = FspFileSystemCreateCheck(FileSystem, Request, TRUE, &GrantedAccess, &ParentDescriptor);
|
Result = FspFileSystemCreateCheck(FileSystem, Request, Response, TRUE,
|
||||||
if (!NT_SUCCESS(Result))
|
&GrantedAccess, &ParentDescriptor);
|
||||||
|
if (!NT_SUCCESS(Result) || STATUS_REPARSE == Result)
|
||||||
return Result;
|
return Result;
|
||||||
|
|
||||||
Result = FspCreateSecurityDescriptor(FileSystem, Request, ParentDescriptor, &ObjectDescriptor);
|
Result = FspCreateSecurityDescriptor(FileSystem, Request, ParentDescriptor, &ObjectDescriptor);
|
||||||
@ -294,8 +364,8 @@ static NTSTATUS FspFileSystemOpCreate_FileOpen(FSP_FILE_SYSTEM *FileSystem,
|
|||||||
PVOID FileNode;
|
PVOID FileNode;
|
||||||
FSP_FSCTL_FILE_INFO FileInfo;
|
FSP_FSCTL_FILE_INFO FileInfo;
|
||||||
|
|
||||||
Result = FspFileSystemOpenCheck(FileSystem, Request, TRUE, &GrantedAccess);
|
Result = FspFileSystemOpenCheck(FileSystem, Request, Response, TRUE, &GrantedAccess);
|
||||||
if (!NT_SUCCESS(Result))
|
if (!NT_SUCCESS(Result) || STATUS_REPARSE == Result)
|
||||||
return Result;
|
return Result;
|
||||||
|
|
||||||
FileNode = 0;
|
FileNode = 0;
|
||||||
@ -323,8 +393,8 @@ static NTSTATUS FspFileSystemOpCreate_FileOpenIf(FSP_FILE_SYSTEM *FileSystem,
|
|||||||
FSP_FSCTL_FILE_INFO FileInfo;
|
FSP_FSCTL_FILE_INFO FileInfo;
|
||||||
BOOLEAN Create = FALSE;
|
BOOLEAN Create = FALSE;
|
||||||
|
|
||||||
Result = FspFileSystemOpenCheck(FileSystem, Request, TRUE, &GrantedAccess);
|
Result = FspFileSystemOpenCheck(FileSystem, Request, Response, TRUE, &GrantedAccess);
|
||||||
if (!NT_SUCCESS(Result))
|
if (!NT_SUCCESS(Result) || STATUS_REPARSE == Result)
|
||||||
{
|
{
|
||||||
if (STATUS_OBJECT_NAME_NOT_FOUND != Result)
|
if (STATUS_OBJECT_NAME_NOT_FOUND != Result)
|
||||||
return Result;
|
return Result;
|
||||||
@ -348,8 +418,9 @@ static NTSTATUS FspFileSystemOpCreate_FileOpenIf(FSP_FILE_SYSTEM *FileSystem,
|
|||||||
|
|
||||||
if (Create)
|
if (Create)
|
||||||
{
|
{
|
||||||
Result = FspFileSystemCreateCheck(FileSystem, Request, FALSE, &GrantedAccess, &ParentDescriptor);
|
Result = FspFileSystemCreateCheck(FileSystem, Request, Response, FALSE,
|
||||||
if (!NT_SUCCESS(Result))
|
&GrantedAccess, &ParentDescriptor);
|
||||||
|
if (!NT_SUCCESS(Result) || STATUS_REPARSE == Result)
|
||||||
return Result;
|
return Result;
|
||||||
|
|
||||||
Result = FspCreateSecurityDescriptor(FileSystem, Request, ParentDescriptor, &ObjectDescriptor);
|
Result = FspCreateSecurityDescriptor(FileSystem, Request, ParentDescriptor, &ObjectDescriptor);
|
||||||
@ -384,8 +455,8 @@ static NTSTATUS FspFileSystemOpCreate_FileOverwrite(FSP_FILE_SYSTEM *FileSystem,
|
|||||||
FSP_FSCTL_FILE_INFO FileInfo;
|
FSP_FSCTL_FILE_INFO FileInfo;
|
||||||
BOOLEAN Supersede = FILE_SUPERSEDE == ((Request->Req.Create.CreateOptions >> 24) & 0xff);
|
BOOLEAN Supersede = FILE_SUPERSEDE == ((Request->Req.Create.CreateOptions >> 24) & 0xff);
|
||||||
|
|
||||||
Result = FspFileSystemOverwriteCheck(FileSystem, Request, TRUE, &GrantedAccess);
|
Result = FspFileSystemOverwriteCheck(FileSystem, Request, Response, TRUE, &GrantedAccess);
|
||||||
if (!NT_SUCCESS(Result))
|
if (!NT_SUCCESS(Result) || STATUS_REPARSE == Result)
|
||||||
return Result;
|
return Result;
|
||||||
|
|
||||||
FileNode = 0;
|
FileNode = 0;
|
||||||
@ -413,8 +484,8 @@ static NTSTATUS FspFileSystemOpCreate_FileOverwriteIf(FSP_FILE_SYSTEM *FileSyste
|
|||||||
FSP_FSCTL_FILE_INFO FileInfo;
|
FSP_FSCTL_FILE_INFO FileInfo;
|
||||||
BOOLEAN Create = FALSE;
|
BOOLEAN Create = FALSE;
|
||||||
|
|
||||||
Result = FspFileSystemOverwriteCheck(FileSystem, Request, TRUE, &GrantedAccess);
|
Result = FspFileSystemOverwriteCheck(FileSystem, Request, Response, TRUE, &GrantedAccess);
|
||||||
if (!NT_SUCCESS(Result))
|
if (!NT_SUCCESS(Result) || STATUS_REPARSE == Result)
|
||||||
{
|
{
|
||||||
if (STATUS_OBJECT_NAME_NOT_FOUND != Result)
|
if (STATUS_OBJECT_NAME_NOT_FOUND != Result)
|
||||||
return Result;
|
return Result;
|
||||||
@ -438,8 +509,9 @@ static NTSTATUS FspFileSystemOpCreate_FileOverwriteIf(FSP_FILE_SYSTEM *FileSyste
|
|||||||
|
|
||||||
if (Create)
|
if (Create)
|
||||||
{
|
{
|
||||||
Result = FspFileSystemCreateCheck(FileSystem, Request, FALSE, &GrantedAccess, &ParentDescriptor);
|
Result = FspFileSystemCreateCheck(FileSystem, Request, Response,
|
||||||
if (!NT_SUCCESS(Result))
|
FALSE, &GrantedAccess, &ParentDescriptor);
|
||||||
|
if (!NT_SUCCESS(Result) || STATUS_REPARSE == Result)
|
||||||
return Result;
|
return Result;
|
||||||
|
|
||||||
Result = FspCreateSecurityDescriptor(FileSystem, Request, ParentDescriptor, &ObjectDescriptor);
|
Result = FspCreateSecurityDescriptor(FileSystem, Request, ParentDescriptor, &ObjectDescriptor);
|
||||||
@ -476,9 +548,8 @@ static NTSTATUS FspFileSystemOpCreate_FileOpenTargetDirectory(FSP_FILE_SYSTEM *F
|
|||||||
FSP_FSCTL_FILE_INFO FileInfo;
|
FSP_FSCTL_FILE_INFO FileInfo;
|
||||||
UINT32 Information;
|
UINT32 Information;
|
||||||
|
|
||||||
Result = FspAccessCheck(FileSystem, Request, TRUE, TRUE,
|
Result = FspFileSystemOpenTargetDirectoryCheck(FileSystem, Request, Response, &GrantedAccess);
|
||||||
Request->Req.Create.DesiredAccess, &GrantedAccess);
|
if (!NT_SUCCESS(Result) || STATUS_REPARSE == Result)
|
||||||
if (!NT_SUCCESS(Result))
|
|
||||||
return Result;
|
return Result;
|
||||||
|
|
||||||
FileNode = 0;
|
FileNode = 0;
|
||||||
@ -819,6 +890,112 @@ FSP_API NTSTATUS FspFileSystemOpQueryDirectory(FSP_FILE_SYSTEM *FileSystem,
|
|||||||
return Result;
|
return Result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
FSP_API NTSTATUS FspFileSystemOpFileSystemControl(FSP_FILE_SYSTEM *FileSystem,
|
||||||
|
FSP_FSCTL_TRANSACT_REQ *Request, FSP_FSCTL_TRANSACT_RSP *Response)
|
||||||
|
{
|
||||||
|
NTSTATUS Result;
|
||||||
|
PREPARSE_DATA_BUFFER SymlinkReparseData;
|
||||||
|
SIZE_T Offset, Size;
|
||||||
|
|
||||||
|
Result = STATUS_INVALID_DEVICE_REQUEST;
|
||||||
|
switch (Request->Req.FileSystemControl.FsControlCode)
|
||||||
|
{
|
||||||
|
case FSCTL_GET_REPARSE_POINT:
|
||||||
|
if (0 != FileSystem->Interface->GetReparsePoint)
|
||||||
|
{
|
||||||
|
SymlinkReparseData = (PREPARSE_DATA_BUFFER)Response->Buffer;
|
||||||
|
memset(SymlinkReparseData, 0, sizeof *SymlinkReparseData);
|
||||||
|
|
||||||
|
if (1/*!!!: SymbolicLinksOnly*/)
|
||||||
|
{
|
||||||
|
Size = FSP_FSCTL_TRANSACT_RSP_SIZEMAX - FIELD_OFFSET(FSP_FSCTL_TRANSACT_RSP, Buffer) -
|
||||||
|
sizeof(*SymlinkReparseData);
|
||||||
|
Size /= 2; /* need space for SubstituteName and PrintName */
|
||||||
|
Result = FileSystem->Interface->GetReparsePoint(FileSystem, Request,
|
||||||
|
(PVOID)Request->Req.FileSystemControl.UserContext,
|
||||||
|
(PWSTR)Request->Buffer,
|
||||||
|
SymlinkReparseData->SymbolicLinkReparseBuffer.PathBuffer,
|
||||||
|
&Size);
|
||||||
|
if (NT_SUCCESS(Result))
|
||||||
|
{
|
||||||
|
Offset = 0;
|
||||||
|
if (Size > 4 * sizeof(WCHAR) &&
|
||||||
|
'\\' == SymlinkReparseData->SymbolicLinkReparseBuffer.PathBuffer[0] &&
|
||||||
|
'?' == SymlinkReparseData->SymbolicLinkReparseBuffer.PathBuffer[1] &&
|
||||||
|
'?' == SymlinkReparseData->SymbolicLinkReparseBuffer.PathBuffer[2] &&
|
||||||
|
'\\' == SymlinkReparseData->SymbolicLinkReparseBuffer.PathBuffer[3])
|
||||||
|
Offset = 4 * sizeof(WCHAR);
|
||||||
|
|
||||||
|
SymlinkReparseData->ReparseTag = IO_REPARSE_TAG_SYMLINK;
|
||||||
|
SymlinkReparseData->ReparseDataLength = (USHORT)(
|
||||||
|
FIELD_OFFSET(REPARSE_DATA_BUFFER, SymbolicLinkReparseBuffer.PathBuffer) -
|
||||||
|
FIELD_OFFSET(REPARSE_DATA_BUFFER, SymbolicLinkReparseBuffer) +
|
||||||
|
Size + Size - Offset);
|
||||||
|
SymlinkReparseData->SymbolicLinkReparseBuffer.SubstituteNameOffset =
|
||||||
|
0;
|
||||||
|
SymlinkReparseData->SymbolicLinkReparseBuffer.SubstituteNameLength =
|
||||||
|
(USHORT)Size;
|
||||||
|
SymlinkReparseData->SymbolicLinkReparseBuffer.PrintNameOffset =
|
||||||
|
(USHORT)Size;
|
||||||
|
SymlinkReparseData->SymbolicLinkReparseBuffer.PrintNameLength =
|
||||||
|
(USHORT)(Size - Offset);
|
||||||
|
SymlinkReparseData->SymbolicLinkReparseBuffer.Flags =
|
||||||
|
Size > 1 * sizeof(WCHAR) &&
|
||||||
|
'\\' == SymlinkReparseData->SymbolicLinkReparseBuffer.PathBuffer[0] ?
|
||||||
|
0 : SYMLINK_FLAG_RELATIVE;
|
||||||
|
RtlMoveMemory(
|
||||||
|
SymlinkReparseData->SymbolicLinkReparseBuffer.PathBuffer + Size / sizeof(WCHAR),
|
||||||
|
SymlinkReparseData->SymbolicLinkReparseBuffer.PathBuffer + Offset / sizeof(WCHAR),
|
||||||
|
(DWORD)(Size - Offset));
|
||||||
|
|
||||||
|
Response->Rsp.FileSystemControl.Buffer.Size = (UINT16)Size;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Size = FSP_FSCTL_TRANSACT_RSP_SIZEMAX - FIELD_OFFSET(FSP_FSCTL_TRANSACT_RSP, Buffer);
|
||||||
|
Result = FileSystem->Interface->GetReparsePoint(FileSystem, Request,
|
||||||
|
(PVOID)Request->Req.FileSystemControl.UserContext,
|
||||||
|
(PWSTR)Request->Buffer, SymlinkReparseData, &Size);
|
||||||
|
if (NT_SUCCESS(Result))
|
||||||
|
Response->Rsp.FileSystemControl.Buffer.Size = (UINT16)Size;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case FSCTL_SET_REPARSE_POINT:
|
||||||
|
if (0 != FileSystem->Interface->SetReparsePoint)
|
||||||
|
{
|
||||||
|
SymlinkReparseData = (PREPARSE_DATA_BUFFER)
|
||||||
|
(Request->Buffer + Request->Req.FileSystemControl.Buffer.Offset);
|
||||||
|
|
||||||
|
if (1/*!!!: SymbolicLinksOnly*/)
|
||||||
|
{
|
||||||
|
Result = FileSystem->Interface->SetReparsePoint(FileSystem, Request,
|
||||||
|
(PVOID)Request->Req.FileSystemControl.UserContext,
|
||||||
|
(PWSTR)Request->Buffer,
|
||||||
|
SymlinkReparseData->SymbolicLinkReparseBuffer.PathBuffer +
|
||||||
|
SymlinkReparseData->SymbolicLinkReparseBuffer.SubstituteNameLength / sizeof(WCHAR),
|
||||||
|
SymlinkReparseData->SymbolicLinkReparseBuffer.SubstituteNameLength);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
Result = FileSystem->Interface->SetReparsePoint(FileSystem, Request,
|
||||||
|
(PVOID)Request->Req.FileSystemControl.UserContext,
|
||||||
|
(PWSTR)Request->Buffer,
|
||||||
|
SymlinkReparseData,
|
||||||
|
Request->Req.FileSystemControl.Buffer.Size);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case FSCTL_DELETE_REPARSE_POINT:
|
||||||
|
if (0 != FileSystem->Interface->SetReparsePoint)
|
||||||
|
Result = FileSystem->Interface->SetReparsePoint(FileSystem, Request,
|
||||||
|
(PVOID)Request->Req.FileSystemControl.UserContext,
|
||||||
|
(PWSTR)Request->Buffer, 0, 0);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
return STATUS_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
FSP_API NTSTATUS FspFileSystemOpQuerySecurity(FSP_FILE_SYSTEM *FileSystem,
|
FSP_API NTSTATUS FspFileSystemOpQuerySecurity(FSP_FILE_SYSTEM *FileSystem,
|
||||||
FSP_FSCTL_TRANSACT_REQ *Request, FSP_FSCTL_TRANSACT_RSP *Response)
|
FSP_FSCTL_TRANSACT_REQ *Request, FSP_FSCTL_TRANSACT_RSP *Response)
|
||||||
{
|
{
|
||||||
|
@ -111,18 +111,47 @@ FSP_API NTSTATUS FspAccessCheckEx(FSP_FILE_SYSTEM *FileSystem,
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
Result = FspGetSecurityByName(FileSystem, Prefix, 0,
|
Result = FspGetSecurityByName(FileSystem, Prefix, &FileAttributes,
|
||||||
&SecurityDescriptor, &SecurityDescriptorSize);
|
&SecurityDescriptor, &SecurityDescriptorSize);
|
||||||
|
|
||||||
FspPathCombine(FileName, Remain);
|
FspPathCombine(FileName, Remain);
|
||||||
|
|
||||||
if (!NT_SUCCESS(Result))
|
if (!NT_SUCCESS(Result) || STATUS_REPARSE == Result)
|
||||||
{
|
{
|
||||||
if (STATUS_OBJECT_NAME_NOT_FOUND == Result)
|
if (STATUS_OBJECT_NAME_NOT_FOUND == Result)
|
||||||
Result = STATUS_OBJECT_PATH_NOT_FOUND;
|
Result = STATUS_OBJECT_PATH_NOT_FOUND;
|
||||||
goto exit;
|
goto exit;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* We check to see if this is a reparse point and then immediately return
|
||||||
|
* STATUS_REPARSE. We do this check BEFORE the directory check, because
|
||||||
|
* contrary to NTFS we want to allow non-directory symlinks to directories.
|
||||||
|
*
|
||||||
|
* Note that this effectively turns off traverse checking a path comprised of
|
||||||
|
* reparse points even when the originating process does not have the Traverse
|
||||||
|
* privilege. [I am not sure what NTFS does in this case, but POSIX symlinks
|
||||||
|
* behave similarly.] We will still traverse check the reparsed path when
|
||||||
|
* the FSD sends it back to us though!
|
||||||
|
*
|
||||||
|
* Now if the reparse points are not symlinks (or symlink-like) things
|
||||||
|
* get even more complicated. Argh! Windows!
|
||||||
|
*/
|
||||||
|
if (FileAttributes & FILE_ATTRIBUTE_REPARSE_POINT)
|
||||||
|
{
|
||||||
|
Result = STATUS_REPARSE;
|
||||||
|
goto exit;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Check if this is a directory, otherwise the path is invalid.
|
||||||
|
*/
|
||||||
|
if (0 == (FileAttributes & FILE_ATTRIBUTE_DIRECTORY))
|
||||||
|
{
|
||||||
|
Result = STATUS_OBJECT_PATH_NOT_FOUND; /* use STATUS_OBJECT_PATH_INVALID? */
|
||||||
|
goto exit;
|
||||||
|
}
|
||||||
|
|
||||||
if (0 < SecurityDescriptorSize)
|
if (0 < SecurityDescriptorSize)
|
||||||
{
|
{
|
||||||
if (AccessCheck(SecurityDescriptor, (HANDLE)Request->Req.Create.AccessToken, FILE_TRAVERSE,
|
if (AccessCheck(SecurityDescriptor, (HANDLE)Request->Req.Create.AccessToken, FILE_TRAVERSE,
|
||||||
@ -138,93 +167,115 @@ FSP_API NTSTATUS FspAccessCheckEx(FSP_FILE_SYSTEM *FileSystem,
|
|||||||
|
|
||||||
Result = FspGetSecurityByName(FileSystem, FileName, &FileAttributes,
|
Result = FspGetSecurityByName(FileSystem, FileName, &FileAttributes,
|
||||||
&SecurityDescriptor, &SecurityDescriptorSize);
|
&SecurityDescriptor, &SecurityDescriptorSize);
|
||||||
if (!NT_SUCCESS(Result))
|
if (!NT_SUCCESS(Result) || STATUS_REPARSE == Result)
|
||||||
goto exit;
|
goto exit;
|
||||||
|
|
||||||
|
if (Request->Req.Create.UserMode && 0 < SecurityDescriptorSize)
|
||||||
|
{
|
||||||
|
if (AccessCheck(SecurityDescriptor, (HANDLE)Request->Req.Create.AccessToken, DesiredAccess,
|
||||||
|
&FspFileGenericMapping, PrivilegeSet, &PrivilegeSetLength, PGrantedAccess, &AccessStatus))
|
||||||
|
Result = AccessStatus ? STATUS_SUCCESS : STATUS_ACCESS_DENIED;
|
||||||
|
else
|
||||||
|
Result = FspNtStatusFromWin32(GetLastError());
|
||||||
|
if (!NT_SUCCESS(Result))
|
||||||
|
{
|
||||||
|
/*
|
||||||
|
* If the desired access includes the DELETE or FILE_READ_ATTRIBUTES
|
||||||
|
* (or MAXIMUM_ALLOWED) rights we must still check with our parent to
|
||||||
|
* see if it gives us access (through the FILE_DELETE_CHILD and
|
||||||
|
* FILE_LIST_DIRECTORY rights).
|
||||||
|
*
|
||||||
|
* Does the Windows security model suck? Ermmmm...
|
||||||
|
*/
|
||||||
|
if (STATUS_ACCESS_DENIED != Result ||
|
||||||
|
0 == ((MAXIMUM_ALLOWED | DELETE | FILE_READ_ATTRIBUTES) & DesiredAccess))
|
||||||
|
goto exit;
|
||||||
|
|
||||||
|
Result = FspAccessCheck(FileSystem, Request, TRUE, FALSE,
|
||||||
|
(MAXIMUM_ALLOWED & DesiredAccess) ? (FILE_DELETE_CHILD | FILE_LIST_DIRECTORY) :
|
||||||
|
(
|
||||||
|
((DELETE & DesiredAccess) ? FILE_DELETE_CHILD : 0) |
|
||||||
|
((FILE_READ_ATTRIBUTES & DesiredAccess) ? FILE_LIST_DIRECTORY : 0)
|
||||||
|
),
|
||||||
|
&ParentAccess);
|
||||||
|
if (!NT_SUCCESS(Result))
|
||||||
|
{
|
||||||
|
/* any failure just becomes ACCESS DENIED at this point */
|
||||||
|
Result = STATUS_ACCESS_DENIED;
|
||||||
|
goto exit;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* redo the access check but remove the DELETE and/or FILE_READ_ATTRIBUTES rights */
|
||||||
|
DesiredAccess2 = DesiredAccess & ~(
|
||||||
|
((FILE_DELETE_CHILD & ParentAccess) ? DELETE : 0) |
|
||||||
|
((FILE_LIST_DIRECTORY & ParentAccess) ? FILE_READ_ATTRIBUTES : 0));
|
||||||
|
if (0 != DesiredAccess2)
|
||||||
|
{
|
||||||
|
if (AccessCheck(SecurityDescriptor, (HANDLE)Request->Req.Create.AccessToken, DesiredAccess2,
|
||||||
|
&FspFileGenericMapping, PrivilegeSet, &PrivilegeSetLength, PGrantedAccess, &AccessStatus))
|
||||||
|
Result = AccessStatus ? STATUS_SUCCESS : STATUS_ACCESS_DENIED;
|
||||||
|
else
|
||||||
|
/* any failure just becomes ACCESS DENIED at this point */
|
||||||
|
Result = STATUS_ACCESS_DENIED;
|
||||||
|
if (!NT_SUCCESS(Result))
|
||||||
|
goto exit;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (FILE_DELETE_CHILD & ParentAccess)
|
||||||
|
*PGrantedAccess |= DELETE;
|
||||||
|
if (FILE_LIST_DIRECTORY & ParentAccess)
|
||||||
|
*PGrantedAccess |= FILE_READ_ATTRIBUTES;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (CheckParentDirectory)
|
||||||
|
{
|
||||||
|
/*
|
||||||
|
* We check to see if this is a reparse point and then immediately return
|
||||||
|
* STATUS_REPARSE. We do this check BEFORE the directory check, because
|
||||||
|
* contrary to NTFS we want to allow non-directory symlinks to directories.
|
||||||
|
*/
|
||||||
|
if (FileAttributes & FILE_ATTRIBUTE_REPARSE_POINT)
|
||||||
|
{
|
||||||
|
Result = STATUS_REPARSE;
|
||||||
|
goto exit;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (0 == (FileAttributes & FILE_ATTRIBUTE_DIRECTORY))
|
||||||
|
{
|
||||||
|
Result = STATUS_NOT_A_DIRECTORY;
|
||||||
|
goto exit;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
/*
|
||||||
|
* We check to see if this is a reparse point and FILE_OPEN_REPARSE_POINT
|
||||||
|
* was not specified, in which case we return STATUS_REPARSE.
|
||||||
|
*/
|
||||||
|
if (0 != (FileAttributes & FILE_ATTRIBUTE_REPARSE_POINT) &&
|
||||||
|
0 == (Request->Req.Create.CreateOptions & FILE_OPEN_REPARSE_POINT))
|
||||||
|
{
|
||||||
|
Result = STATUS_REPARSE;
|
||||||
|
goto exit;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((Request->Req.Create.CreateOptions & FILE_DIRECTORY_FILE) &&
|
||||||
|
0 == (FileAttributes & FILE_ATTRIBUTE_DIRECTORY))
|
||||||
|
{
|
||||||
|
Result = STATUS_NOT_A_DIRECTORY;
|
||||||
|
goto exit;
|
||||||
|
}
|
||||||
|
if ((Request->Req.Create.CreateOptions & FILE_NON_DIRECTORY_FILE) &&
|
||||||
|
0 != (FileAttributes & FILE_ATTRIBUTE_DIRECTORY))
|
||||||
|
{
|
||||||
|
Result = STATUS_FILE_IS_A_DIRECTORY;
|
||||||
|
goto exit;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (Request->Req.Create.UserMode)
|
if (Request->Req.Create.UserMode)
|
||||||
{
|
{
|
||||||
if (0 < SecurityDescriptorSize)
|
|
||||||
{
|
|
||||||
if (AccessCheck(SecurityDescriptor, (HANDLE)Request->Req.Create.AccessToken, DesiredAccess,
|
|
||||||
&FspFileGenericMapping, PrivilegeSet, &PrivilegeSetLength, PGrantedAccess, &AccessStatus))
|
|
||||||
Result = AccessStatus ? STATUS_SUCCESS : STATUS_ACCESS_DENIED;
|
|
||||||
else
|
|
||||||
Result = FspNtStatusFromWin32(GetLastError());
|
|
||||||
if (!NT_SUCCESS(Result))
|
|
||||||
{
|
|
||||||
/*
|
|
||||||
* If the desired access includes the DELETE or FILE_READ_ATTRIBUTES
|
|
||||||
* (or MAXIMUM_ALLOWED) rights we must still check with our parent to
|
|
||||||
* see if it gives us access (through the FILE_DELETE_CHILD and
|
|
||||||
* FILE_LIST_DIRECTORY rights).
|
|
||||||
*
|
|
||||||
* Does the Windows security model suck? Ermmmm...
|
|
||||||
*/
|
|
||||||
if (STATUS_ACCESS_DENIED != Result ||
|
|
||||||
0 == ((MAXIMUM_ALLOWED | DELETE | FILE_READ_ATTRIBUTES) & DesiredAccess))
|
|
||||||
goto exit;
|
|
||||||
|
|
||||||
Result = FspAccessCheck(FileSystem, Request, TRUE, FALSE,
|
|
||||||
(MAXIMUM_ALLOWED & DesiredAccess) ? (FILE_DELETE_CHILD | FILE_LIST_DIRECTORY) :
|
|
||||||
(
|
|
||||||
((DELETE & DesiredAccess) ? FILE_DELETE_CHILD : 0) |
|
|
||||||
((FILE_READ_ATTRIBUTES & DesiredAccess) ? FILE_LIST_DIRECTORY : 0)
|
|
||||||
),
|
|
||||||
&ParentAccess);
|
|
||||||
if (!NT_SUCCESS(Result))
|
|
||||||
{
|
|
||||||
/* any failure just becomes ACCESS DENIED at this point */
|
|
||||||
Result = STATUS_ACCESS_DENIED;
|
|
||||||
goto exit;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* redo the access check but remove the DELETE and/or FILE_READ_ATTRIBUTES rights */
|
|
||||||
DesiredAccess2 = DesiredAccess & ~(
|
|
||||||
((FILE_DELETE_CHILD & ParentAccess) ? DELETE : 0) |
|
|
||||||
((FILE_LIST_DIRECTORY & ParentAccess) ? FILE_READ_ATTRIBUTES : 0));
|
|
||||||
if (0 != DesiredAccess2)
|
|
||||||
{
|
|
||||||
if (AccessCheck(SecurityDescriptor, (HANDLE)Request->Req.Create.AccessToken, DesiredAccess2,
|
|
||||||
&FspFileGenericMapping, PrivilegeSet, &PrivilegeSetLength, PGrantedAccess, &AccessStatus))
|
|
||||||
Result = AccessStatus ? STATUS_SUCCESS : STATUS_ACCESS_DENIED;
|
|
||||||
else
|
|
||||||
/* any failure just becomes ACCESS DENIED at this point */
|
|
||||||
Result = STATUS_ACCESS_DENIED;
|
|
||||||
if (!NT_SUCCESS(Result))
|
|
||||||
goto exit;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (FILE_DELETE_CHILD & ParentAccess)
|
|
||||||
*PGrantedAccess |= DELETE;
|
|
||||||
if (FILE_LIST_DIRECTORY & ParentAccess)
|
|
||||||
*PGrantedAccess |= FILE_READ_ATTRIBUTES;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (CheckParentDirectory)
|
|
||||||
{
|
|
||||||
if (0 == (FileAttributes & FILE_ATTRIBUTE_DIRECTORY))
|
|
||||||
{
|
|
||||||
Result = STATUS_NOT_A_DIRECTORY;
|
|
||||||
goto exit;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
if ((Request->Req.Create.CreateOptions & FILE_DIRECTORY_FILE) &&
|
|
||||||
0 == (FileAttributes & FILE_ATTRIBUTE_DIRECTORY))
|
|
||||||
{
|
|
||||||
Result = STATUS_NOT_A_DIRECTORY;
|
|
||||||
goto exit;
|
|
||||||
}
|
|
||||||
if ((Request->Req.Create.CreateOptions & FILE_NON_DIRECTORY_FILE) &&
|
|
||||||
0 != (FileAttributes & FILE_ATTRIBUTE_DIRECTORY))
|
|
||||||
{
|
|
||||||
Result = STATUS_FILE_IS_A_DIRECTORY;
|
|
||||||
goto exit;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (0 != (FileAttributes & FILE_ATTRIBUTE_READONLY))
|
if (0 != (FileAttributes & FILE_ATTRIBUTE_READONLY))
|
||||||
{
|
{
|
||||||
if (DesiredAccess &
|
if (DesiredAccess &
|
||||||
|
@ -335,9 +335,12 @@ static NTSTATUS FspFsvolCreateNoLock(
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* fix FileAttributes */
|
/* fix FileAttributes */
|
||||||
ClearFlag(FileAttributes, FILE_ATTRIBUTE_NORMAL | FILE_ATTRIBUTE_DIRECTORY);
|
ClearFlag(FileAttributes,
|
||||||
|
FILE_ATTRIBUTE_NORMAL | FILE_ATTRIBUTE_DIRECTORY | FILE_ATTRIBUTE_REPARSE_POINT);
|
||||||
if (CreateOptions & FILE_DIRECTORY_FILE)
|
if (CreateOptions & FILE_DIRECTORY_FILE)
|
||||||
SetFlag(FileAttributes, FILE_ATTRIBUTE_DIRECTORY);
|
SetFlag(FileAttributes, FILE_ATTRIBUTE_DIRECTORY);
|
||||||
|
if (CreateOptions & FILE_OPEN_REPARSE_POINT)
|
||||||
|
SetFlag(FileAttributes, FILE_ATTRIBUTE_REPARSE_POINT);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* The new request is associated with our IRP. Go ahead and associate our FileNode/FileDesc
|
* The new request is associated with our IRP. Go ahead and associate our FileNode/FileDesc
|
||||||
@ -486,6 +489,7 @@ NTSTATUS FspFsvolCreateComplete(
|
|||||||
FSP_FILE_NODE *FileNode = FileDesc->FileNode;
|
FSP_FILE_NODE *FileNode = FileDesc->FileNode;
|
||||||
FSP_FILE_NODE *OpenedFileNode;
|
FSP_FILE_NODE *OpenedFileNode;
|
||||||
UNICODE_STRING ReparseFileName;
|
UNICODE_STRING ReparseFileName;
|
||||||
|
PREPARSE_DATA_BUFFER ReparseData;
|
||||||
|
|
||||||
if (FspFsctlTransactCreateKind == Request->Kind)
|
if (FspFsctlTransactCreateKind == Request->Kind)
|
||||||
{
|
{
|
||||||
@ -498,20 +502,25 @@ NTSTATUS FspFsvolCreateComplete(
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* special case STATUS_REPARSE */
|
/* special case STATUS_REPARSE */
|
||||||
if (STATUS_REPARSE == Result)
|
if (STATUS_REPARSE == Response->IoStatus.Status)
|
||||||
{
|
{
|
||||||
ReparseFileName.Buffer =
|
if (IO_REMOUNT == Response->IoStatus.Information)
|
||||||
(PVOID)(Response->Buffer + Response->Rsp.Create.Reparse.FileName.Offset);
|
|
||||||
ReparseFileName.Length = ReparseFileName.MaximumLength =
|
|
||||||
Response->Rsp.Create.Reparse.FileName.Size;
|
|
||||||
|
|
||||||
Result = STATUS_ACCESS_DENIED;
|
|
||||||
if (IO_REPARSE == Response->IoStatus.Information)
|
|
||||||
{
|
{
|
||||||
if (0 == ReparseFileName.Length ||
|
Irp->IoStatus.Information = IO_REMOUNT;
|
||||||
(PUINT8)ReparseFileName.Buffer + ReparseFileName.Length >
|
Result = STATUS_REPARSE;
|
||||||
(PUINT8)Response + Response->Size)
|
FSP_RETURN();
|
||||||
FSP_RETURN();
|
}
|
||||||
|
else if (IO_REPARSE == Response->IoStatus.Information)
|
||||||
|
{
|
||||||
|
ReparseFileName.Buffer =
|
||||||
|
(PVOID)(Response->Buffer + Response->Rsp.Create.Reparse.FileName.Offset);
|
||||||
|
ReparseFileName.Length = ReparseFileName.MaximumLength =
|
||||||
|
Response->Rsp.Create.Reparse.FileName.Size;
|
||||||
|
|
||||||
|
if ((PUINT8)ReparseFileName.Buffer + ReparseFileName.Length >
|
||||||
|
(PUINT8)Response + Response->Size ||
|
||||||
|
0 == ReparseFileName.Length)
|
||||||
|
FSP_RETURN(Result = STATUS_REPARSE_POINT_NOT_RESOLVED);
|
||||||
|
|
||||||
if (ReparseFileName.Length > FileObject->FileName.MaximumLength)
|
if (ReparseFileName.Length > FileObject->FileName.MaximumLength)
|
||||||
{
|
{
|
||||||
@ -539,19 +548,43 @@ NTSTATUS FspFsvolCreateComplete(
|
|||||||
* STATUS_REPARSE status returned by the filter. Therefore, it is not
|
* STATUS_REPARSE status returned by the filter. Therefore, it is not
|
||||||
* the responsibility of the filter to free that file object.
|
* the responsibility of the filter to free that file object.
|
||||||
*/
|
*/
|
||||||
}
|
|
||||||
else
|
|
||||||
if (IO_REMOUNT == Response->IoStatus.Information)
|
|
||||||
{
|
|
||||||
if (0 != ReparseFileName.Length)
|
|
||||||
FSP_RETURN();
|
|
||||||
}
|
|
||||||
else
|
|
||||||
FSP_RETURN();
|
|
||||||
|
|
||||||
Irp->IoStatus.Information = (ULONG_PTR)Response->IoStatus.Information;
|
Irp->IoStatus.Information = IO_REPARSE;
|
||||||
Result = Response->IoStatus.Status;
|
Result = STATUS_REPARSE;
|
||||||
FSP_RETURN();
|
FSP_RETURN();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
ReparseData = (PVOID)(Response->Buffer + Response->Rsp.Create.Reparse.Data.Offset);
|
||||||
|
|
||||||
|
if ((PUINT8)ReparseData + Response->Rsp.Create.Reparse.Data.Size >
|
||||||
|
(PUINT8)Response + Response->Size)
|
||||||
|
{
|
||||||
|
Result = STATUS_IO_REPARSE_DATA_INVALID;
|
||||||
|
FSP_RETURN();
|
||||||
|
}
|
||||||
|
|
||||||
|
Result = FsRtlValidateReparsePointBuffer(Response->Rsp.Create.Reparse.Data.Size,
|
||||||
|
ReparseData);
|
||||||
|
if (!NT_SUCCESS(Result))
|
||||||
|
FSP_RETURN();
|
||||||
|
|
||||||
|
ASSERT(0 == Irp->Tail.Overlay.AuxiliaryBuffer);
|
||||||
|
Irp->Tail.Overlay.AuxiliaryBuffer = FspAllocNonPagedExternal(
|
||||||
|
Response->Rsp.Create.Reparse.Data.Size);
|
||||||
|
if (0 == Irp->Tail.Overlay.AuxiliaryBuffer)
|
||||||
|
{
|
||||||
|
Result = STATUS_INSUFFICIENT_RESOURCES;
|
||||||
|
FSP_RETURN();
|
||||||
|
}
|
||||||
|
|
||||||
|
RtlCopyMemory(Irp->Tail.Overlay.AuxiliaryBuffer, ReparseData,
|
||||||
|
Response->Rsp.Create.Reparse.Data.Size);
|
||||||
|
|
||||||
|
Irp->IoStatus.Information = ReparseData->ReparseTag;
|
||||||
|
Result = STATUS_REPARSE;
|
||||||
|
FSP_RETURN();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* fix FileNode->FileName if we were doing SL_OPEN_TARGET_DIRECTORY */
|
/* fix FileNode->FileName if we were doing SL_OPEN_TARGET_DIRECTORY */
|
||||||
|
218
src/sys/fsctl.c
218
src/sys/fsctl.c
@ -18,21 +18,36 @@
|
|||||||
#include <sys/driver.h>
|
#include <sys/driver.h>
|
||||||
|
|
||||||
static NTSTATUS FspFsctlFileSystemControl(
|
static NTSTATUS FspFsctlFileSystemControl(
|
||||||
PDEVICE_OBJECT DeviceObject, PIRP Irp, PIO_STACK_LOCATION IrpSp);
|
PDEVICE_OBJECT FsctlDeviceObject, PIRP Irp, PIO_STACK_LOCATION IrpSp);
|
||||||
|
static NTSTATUS FspFsvolFileSystemControlReparsePoint(
|
||||||
|
PDEVICE_OBJECT FsvolDeviceObject, PIRP Irp, PIO_STACK_LOCATION IrpSp,
|
||||||
|
BOOLEAN IsWrite);
|
||||||
|
static NTSTATUS FspFsvolFileSystemControlReparsePointComplete(
|
||||||
|
PIRP Irp, const FSP_FSCTL_TRANSACT_RSP *Response,
|
||||||
|
BOOLEAN IsWrite);
|
||||||
static NTSTATUS FspFsvolFileSystemControl(
|
static NTSTATUS FspFsvolFileSystemControl(
|
||||||
PDEVICE_OBJECT DeviceObject, PIRP Irp, PIO_STACK_LOCATION IrpSp);
|
PDEVICE_OBJECT FsvolDeviceObject, PIRP Irp, PIO_STACK_LOCATION IrpSp);
|
||||||
FSP_IOCMPL_DISPATCH FspFsvolFileSystemControlComplete;
|
FSP_IOCMPL_DISPATCH FspFsvolFileSystemControlComplete;
|
||||||
|
static FSP_IOP_REQUEST_FINI FspFsvolFileSystemControlRequestFini;
|
||||||
FSP_DRIVER_DISPATCH FspFileSystemControl;
|
FSP_DRIVER_DISPATCH FspFileSystemControl;
|
||||||
|
|
||||||
#ifdef ALLOC_PRAGMA
|
#ifdef ALLOC_PRAGMA
|
||||||
#pragma alloc_text(PAGE, FspFsctlFileSystemControl)
|
#pragma alloc_text(PAGE, FspFsctlFileSystemControl)
|
||||||
|
#pragma alloc_text(PAGE, FspFsvolFileSystemControlReparsePoint)
|
||||||
|
#pragma alloc_text(PAGE, FspFsvolFileSystemControlReparsePointComplete)
|
||||||
#pragma alloc_text(PAGE, FspFsvolFileSystemControl)
|
#pragma alloc_text(PAGE, FspFsvolFileSystemControl)
|
||||||
#pragma alloc_text(PAGE, FspFsvolFileSystemControlComplete)
|
#pragma alloc_text(PAGE, FspFsvolFileSystemControlComplete)
|
||||||
|
#pragma alloc_text(PAGE, FspFsvolFileSystemControlRequestFini)
|
||||||
#pragma alloc_text(PAGE, FspFileSystemControl)
|
#pragma alloc_text(PAGE, FspFileSystemControl)
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
enum
|
||||||
|
{
|
||||||
|
RequestFileNode = 0,
|
||||||
|
};
|
||||||
|
|
||||||
static NTSTATUS FspFsctlFileSystemControl(
|
static NTSTATUS FspFsctlFileSystemControl(
|
||||||
PDEVICE_OBJECT DeviceObject, PIRP Irp, PIO_STACK_LOCATION IrpSp)
|
PDEVICE_OBJECT FsctlDeviceObject, PIRP Irp, PIO_STACK_LOCATION IrpSp)
|
||||||
{
|
{
|
||||||
PAGED_CODE();
|
PAGED_CODE();
|
||||||
|
|
||||||
@ -44,32 +59,160 @@ static NTSTATUS FspFsctlFileSystemControl(
|
|||||||
{
|
{
|
||||||
case FSP_FSCTL_VOLUME_NAME:
|
case FSP_FSCTL_VOLUME_NAME:
|
||||||
if (0 != IrpSp->FileObject->FsContext2)
|
if (0 != IrpSp->FileObject->FsContext2)
|
||||||
Result = FspVolumeGetName(DeviceObject, Irp, IrpSp);
|
Result = FspVolumeGetName(FsctlDeviceObject, Irp, IrpSp);
|
||||||
break;
|
break;
|
||||||
case FSP_FSCTL_VOLUME_LIST:
|
case FSP_FSCTL_VOLUME_LIST:
|
||||||
Result = FspVolumeGetNameList(DeviceObject, Irp, IrpSp);
|
Result = FspVolumeGetNameList(FsctlDeviceObject, Irp, IrpSp);
|
||||||
break;
|
break;
|
||||||
case FSP_FSCTL_TRANSACT:
|
case FSP_FSCTL_TRANSACT:
|
||||||
case FSP_FSCTL_TRANSACT_BATCH:
|
case FSP_FSCTL_TRANSACT_BATCH:
|
||||||
if (0 != IrpSp->FileObject->FsContext2)
|
if (0 != IrpSp->FileObject->FsContext2)
|
||||||
Result = FspVolumeTransact(DeviceObject, Irp, IrpSp);
|
Result = FspVolumeTransact(FsctlDeviceObject, Irp, IrpSp);
|
||||||
break;
|
break;
|
||||||
case FSP_FSCTL_STOP:
|
case FSP_FSCTL_STOP:
|
||||||
if (0 != IrpSp->FileObject->FsContext2)
|
if (0 != IrpSp->FileObject->FsContext2)
|
||||||
Result = FspVolumeStop(DeviceObject, Irp, IrpSp);
|
Result = FspVolumeStop(FsctlDeviceObject, Irp, IrpSp);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case IRP_MN_MOUNT_VOLUME:
|
case IRP_MN_MOUNT_VOLUME:
|
||||||
Result = FspVolumeMount(DeviceObject, Irp, IrpSp);
|
Result = FspVolumeMount(FsctlDeviceObject, Irp, IrpSp);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
return Result;
|
return Result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static NTSTATUS FspFsvolFileSystemControlReparsePoint(
|
||||||
|
PDEVICE_OBJECT FsvolDeviceObject, PIRP Irp, PIO_STACK_LOCATION IrpSp,
|
||||||
|
BOOLEAN IsWrite)
|
||||||
|
{
|
||||||
|
PAGED_CODE();
|
||||||
|
|
||||||
|
/* is this a valid FileObject? */
|
||||||
|
if (!FspFileNodeIsValid(IrpSp->FileObject->FsContext))
|
||||||
|
return STATUS_INVALID_DEVICE_REQUEST;
|
||||||
|
|
||||||
|
NTSTATUS Result;
|
||||||
|
FSP_FSVOL_DEVICE_EXTENSION *FsvolDeviceExtension = FspFsvolDeviceExtension(FsvolDeviceObject);
|
||||||
|
PFILE_OBJECT FileObject = IrpSp->FileObject;
|
||||||
|
FSP_FILE_NODE *FileNode = FileObject->FsContext;
|
||||||
|
FSP_FILE_DESC *FileDesc = FileObject->FsContext2;
|
||||||
|
ULONG FsControlCode = IrpSp->Parameters.FileSystemControl.FsControlCode;
|
||||||
|
PVOID InputBuffer = Irp->AssociatedIrp.SystemBuffer;
|
||||||
|
PVOID OutputBuffer = Irp->UserBuffer;
|
||||||
|
ULONG InputBufferLength = IrpSp->Parameters.FileSystemControl.InputBufferLength;
|
||||||
|
ULONG OutputBufferLength = IrpSp->Parameters.FileSystemControl.OutputBufferLength;
|
||||||
|
ULONG ReparseTag;
|
||||||
|
FSP_FSCTL_TRANSACT_REQ *Request;
|
||||||
|
|
||||||
|
ASSERT(FileNode == FileDesc->FileNode);
|
||||||
|
|
||||||
|
/* do we support reparse points? */
|
||||||
|
if (!FsvolDeviceExtension->VolumeParams.ReparsePoints)
|
||||||
|
return STATUS_INVALID_DEVICE_REQUEST;
|
||||||
|
|
||||||
|
if (IsWrite)
|
||||||
|
{
|
||||||
|
if (0 == InputBuffer || 0 == InputBufferLength ||
|
||||||
|
FSP_FSCTL_TRANSACT_REQ_SIZEMAX - FIELD_OFFSET(FSP_FSCTL_TRANSACT_REQ, Buffer) -
|
||||||
|
(FileNode->FileName.Length + sizeof(WCHAR)) < InputBufferLength)
|
||||||
|
return STATUS_INVALID_PARAMETER;
|
||||||
|
|
||||||
|
Result = FsRtlValidateReparsePointBuffer(InputBufferLength, InputBuffer);
|
||||||
|
if (!NT_SUCCESS(Result))
|
||||||
|
return Result;
|
||||||
|
|
||||||
|
ReparseTag = ((PREPARSE_DATA_BUFFER)InputBuffer)->ReparseTag;
|
||||||
|
|
||||||
|
/* NTFS severely limits symbolic links; we will not do that unless our file system asks */
|
||||||
|
if (FsvolDeviceExtension->VolumeParams.ReparsePointPrivilegeCheck)
|
||||||
|
{
|
||||||
|
if (IO_REPARSE_TAG_SYMLINK == ReparseTag &&
|
||||||
|
KernelMode != Irp->RequestorMode &&
|
||||||
|
SeSinglePrivilegeCheck(RtlConvertLongToLuid(SE_CREATE_SYMBOLIC_LINK_PRIVILEGE),
|
||||||
|
UserMode))
|
||||||
|
return STATUS_ACCESS_DENIED;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (0 != InputBuffer || 0 != InputBufferLength ||
|
||||||
|
0 == OutputBuffer || 0 == OutputBufferLength)
|
||||||
|
return STATUS_INVALID_PARAMETER;
|
||||||
|
|
||||||
|
Result = FspBufferUserBuffer(Irp, OutputBufferLength, IoWriteAccess);
|
||||||
|
if (!NT_SUCCESS(Result))
|
||||||
|
return Result;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (IsWrite)
|
||||||
|
FspFileNodeAcquireExclusive(FileNode, Full);
|
||||||
|
else
|
||||||
|
FspFileNodeAcquireShared(FileNode, Full);
|
||||||
|
|
||||||
|
Result = FspIopCreateRequestEx(Irp, &FileNode->FileName, InputBufferLength,
|
||||||
|
FspFsvolFileSystemControlRequestFini, &Request);
|
||||||
|
if (!NT_SUCCESS(Result))
|
||||||
|
{
|
||||||
|
FspFileNodeRelease(FileNode, Full);
|
||||||
|
return Result;
|
||||||
|
}
|
||||||
|
|
||||||
|
Request->Kind = FspFsctlTransactFileSystemControlKind;
|
||||||
|
Request->Req.FileSystemControl.UserContext = FileNode->UserContext;
|
||||||
|
Request->Req.FileSystemControl.UserContext2 = FileDesc->UserContext2;
|
||||||
|
Request->Req.FileSystemControl.FsControlCode = FsControlCode;
|
||||||
|
if (IsWrite)
|
||||||
|
{
|
||||||
|
Request->Req.FileSystemControl.Buffer.Offset = Request->FileName.Size;
|
||||||
|
Request->Req.FileSystemControl.Buffer.Size = (UINT16)InputBufferLength;
|
||||||
|
RtlCopyMemory(Request->Buffer + Request->Req.FileSystemControl.Buffer.Offset,
|
||||||
|
InputBuffer, InputBufferLength);
|
||||||
|
}
|
||||||
|
|
||||||
|
FspFileNodeSetOwner(FileNode, Full, Request);
|
||||||
|
FspIopRequestContext(Request, RequestFileNode) = FileNode;
|
||||||
|
|
||||||
|
return FSP_STATUS_IOQ_POST;
|
||||||
|
}
|
||||||
|
|
||||||
|
static NTSTATUS FspFsvolFileSystemControlReparsePointComplete(
|
||||||
|
PIRP Irp, const FSP_FSCTL_TRANSACT_RSP *Response,
|
||||||
|
BOOLEAN IsWrite)
|
||||||
|
{
|
||||||
|
PAGED_CODE();
|
||||||
|
|
||||||
|
if (!IsWrite)
|
||||||
|
return STATUS_SUCCESS;
|
||||||
|
|
||||||
|
NTSTATUS Result;
|
||||||
|
PIO_STACK_LOCATION IrpSp = IoGetCurrentIrpStackLocation(Irp);
|
||||||
|
PVOID OutputBuffer = Irp->AssociatedIrp.SystemBuffer; /* see FspBufferUserBuffer call */
|
||||||
|
ULONG OutputBufferLength = IrpSp->Parameters.FileSystemControl.OutputBufferLength;
|
||||||
|
|
||||||
|
if (Response->Buffer + Response->Rsp.FileSystemControl.Buffer.Offset +
|
||||||
|
Response->Rsp.FileSystemControl.Buffer.Size > (PUINT8)Response + Response->Size)
|
||||||
|
return STATUS_IO_REPARSE_DATA_INVALID;
|
||||||
|
|
||||||
|
Result = FsRtlValidateReparsePointBuffer(Response->Rsp.FileSystemControl.Buffer.Size,
|
||||||
|
(PVOID)(Response->Buffer + Response->Rsp.FileSystemControl.Buffer.Offset));
|
||||||
|
if (!NT_SUCCESS(Result))
|
||||||
|
return Result;
|
||||||
|
|
||||||
|
if (Response->Rsp.FileSystemControl.Buffer.Size > OutputBufferLength)
|
||||||
|
return STATUS_BUFFER_TOO_SMALL;
|
||||||
|
|
||||||
|
RtlCopyMemory(OutputBuffer, Response->Buffer + Response->Rsp.FileSystemControl.Buffer.Offset,
|
||||||
|
Response->Rsp.FileSystemControl.Buffer.Size);
|
||||||
|
|
||||||
|
Irp->IoStatus.Information = Response->Rsp.FileSystemControl.Buffer.Size;
|
||||||
|
|
||||||
|
return STATUS_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
static NTSTATUS FspFsvolFileSystemControl(
|
static NTSTATUS FspFsvolFileSystemControl(
|
||||||
PDEVICE_OBJECT DeviceObject, PIRP Irp, PIO_STACK_LOCATION IrpSp)
|
PDEVICE_OBJECT FsvolDeviceObject, PIRP Irp, PIO_STACK_LOCATION IrpSp)
|
||||||
{
|
{
|
||||||
PAGED_CODE();
|
PAGED_CODE();
|
||||||
|
|
||||||
@ -81,7 +224,14 @@ static NTSTATUS FspFsvolFileSystemControl(
|
|||||||
{
|
{
|
||||||
case FSP_FSCTL_WORK:
|
case FSP_FSCTL_WORK:
|
||||||
case FSP_FSCTL_WORK_BEST_EFFORT:
|
case FSP_FSCTL_WORK_BEST_EFFORT:
|
||||||
Result = FspVolumeWork(DeviceObject, Irp, IrpSp);
|
Result = FspVolumeWork(FsvolDeviceObject, Irp, IrpSp);
|
||||||
|
break;
|
||||||
|
case FSCTL_GET_REPARSE_POINT:
|
||||||
|
Result = FspFsvolFileSystemControlReparsePoint(FsvolDeviceObject, Irp, IrpSp, FALSE);
|
||||||
|
break;
|
||||||
|
case FSCTL_SET_REPARSE_POINT:
|
||||||
|
case FSCTL_DELETE_REPARSE_POINT:
|
||||||
|
Result = FspFsvolFileSystemControlReparsePoint(FsvolDeviceObject, Irp, IrpSp, TRUE);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
@ -95,6 +245,44 @@ NTSTATUS FspFsvolFileSystemControlComplete(
|
|||||||
{
|
{
|
||||||
FSP_ENTER_IOC(PAGED_CODE());
|
FSP_ENTER_IOC(PAGED_CODE());
|
||||||
|
|
||||||
|
if (!NT_SUCCESS(Response->IoStatus.Status))
|
||||||
|
{
|
||||||
|
Irp->IoStatus.Information = 0;
|
||||||
|
Result = Response->IoStatus.Status;
|
||||||
|
FSP_RETURN();
|
||||||
|
}
|
||||||
|
|
||||||
|
PFILE_OBJECT FileObject = IrpSp->FileObject;
|
||||||
|
FSP_FILE_NODE *FileNode = FileObject->FsContext;
|
||||||
|
FSP_FSCTL_TRANSACT_REQ *Request = FspIrpRequest(Irp);
|
||||||
|
|
||||||
|
switch (IrpSp->MinorFunction)
|
||||||
|
{
|
||||||
|
case IRP_MN_USER_FS_REQUEST:
|
||||||
|
switch (IrpSp->Parameters.FileSystemControl.FsControlCode)
|
||||||
|
{
|
||||||
|
case FSCTL_GET_REPARSE_POINT:
|
||||||
|
Result = FspFsvolFileSystemControlReparsePointComplete(Irp, Response, FALSE);
|
||||||
|
break;
|
||||||
|
case FSCTL_SET_REPARSE_POINT:
|
||||||
|
case FSCTL_DELETE_REPARSE_POINT:
|
||||||
|
Result = FspFsvolFileSystemControlReparsePointComplete(Irp, Response, TRUE);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
ASSERT(0);
|
||||||
|
Result = STATUS_INVALID_PARAMETER;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
ASSERT(0);
|
||||||
|
Result = STATUS_INVALID_PARAMETER;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
FspIopRequestContext(Request, RequestFileNode) = 0;
|
||||||
|
FspFileNodeReleaseOwner(FileNode, Full, Request);
|
||||||
|
|
||||||
FSP_LEAVE_IOC(
|
FSP_LEAVE_IOC(
|
||||||
"%s%sFileObject=%p",
|
"%s%sFileObject=%p",
|
||||||
IRP_MN_USER_FS_REQUEST == IrpSp->MinorFunction ?
|
IRP_MN_USER_FS_REQUEST == IrpSp->MinorFunction ?
|
||||||
@ -103,6 +291,16 @@ NTSTATUS FspFsvolFileSystemControlComplete(
|
|||||||
IrpSp->FileObject);
|
IrpSp->FileObject);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static VOID FspFsvolFileSystemControlRequestFini(FSP_FSCTL_TRANSACT_REQ *Request, PVOID Context[4])
|
||||||
|
{
|
||||||
|
PAGED_CODE();
|
||||||
|
|
||||||
|
FSP_FILE_NODE *FileNode = Context[RequestFileNode];
|
||||||
|
|
||||||
|
if (0 != FileNode)
|
||||||
|
FspFileNodeReleaseOwner(FileNode, Full, Request);
|
||||||
|
}
|
||||||
|
|
||||||
NTSTATUS FspFileSystemControl(
|
NTSTATUS FspFileSystemControl(
|
||||||
PDEVICE_OBJECT DeviceObject, PIRP Irp)
|
PDEVICE_OBJECT DeviceObject, PIRP Irp)
|
||||||
{
|
{
|
||||||
|
@ -59,6 +59,8 @@ typedef struct _MEMFS_FILE_NODE
|
|||||||
SIZE_T FileSecuritySize;
|
SIZE_T FileSecuritySize;
|
||||||
PVOID FileSecurity;
|
PVOID FileSecurity;
|
||||||
PVOID FileData;
|
PVOID FileData;
|
||||||
|
SIZE_T ReparseDataSize;
|
||||||
|
PVOID ReparseData;
|
||||||
ULONG RefCount;
|
ULONG RefCount;
|
||||||
} MEMFS_FILE_NODE;
|
} MEMFS_FILE_NODE;
|
||||||
|
|
||||||
@ -358,7 +360,7 @@ static NTSTATUS Create(FSP_FILE_SYSTEM *FileSystem,
|
|||||||
NTSTATUS Result;
|
NTSTATUS Result;
|
||||||
BOOLEAN Inserted;
|
BOOLEAN Inserted;
|
||||||
|
|
||||||
if (CreateOptions & FILE_DIRECTORY_FILE)
|
if (CreateOptions & (FILE_DIRECTORY_FILE | FILE_OPEN_REPARSE_POINT))
|
||||||
AllocationSize = 0;
|
AllocationSize = 0;
|
||||||
|
|
||||||
FileNode = MemfsFileNodeMapGet(Memfs->FileNodeMap, FileName);
|
FileNode = MemfsFileNodeMapGet(Memfs->FileNodeMap, FileName);
|
||||||
@ -930,6 +932,33 @@ static NTSTATUS ReadDirectory(FSP_FILE_SYSTEM *FileSystem,
|
|||||||
return STATUS_SUCCESS;
|
return STATUS_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static NTSTATUS ResolveReparsePoints(FSP_FILE_SYSTEM *FileSystem,
|
||||||
|
PWSTR FileName, BOOLEAN OpenReparsePoint,
|
||||||
|
PIO_STATUS_BLOCK PIoStatus, PVOID Buffer, PSIZE_T PSize)
|
||||||
|
{
|
||||||
|
return STATUS_INVALID_DEVICE_REQUEST;
|
||||||
|
}
|
||||||
|
|
||||||
|
static NTSTATUS GetReparsePoint(FSP_FILE_SYSTEM *FileSystem,
|
||||||
|
FSP_FSCTL_TRANSACT_REQ *Request,
|
||||||
|
PVOID FileNode0,
|
||||||
|
PWSTR FileName, PVOID Buffer, PSIZE_T PSize)
|
||||||
|
{
|
||||||
|
MEMFS_FILE_NODE *FileNode = (MEMFS_FILE_NODE *)FileNode0;
|
||||||
|
|
||||||
|
return STATUS_INVALID_DEVICE_REQUEST;
|
||||||
|
}
|
||||||
|
|
||||||
|
static NTSTATUS SetReparsePoint(FSP_FILE_SYSTEM *FileSystem,
|
||||||
|
FSP_FSCTL_TRANSACT_REQ *Request,
|
||||||
|
PVOID FileNode0,
|
||||||
|
PWSTR FileName, PVOID Buffer, SIZE_T Size)
|
||||||
|
{
|
||||||
|
MEMFS_FILE_NODE *FileNode = (MEMFS_FILE_NODE *)FileNode0;
|
||||||
|
|
||||||
|
return STATUS_INVALID_DEVICE_REQUEST;
|
||||||
|
}
|
||||||
|
|
||||||
static FSP_FILE_SYSTEM_INTERFACE MemfsInterface =
|
static FSP_FILE_SYSTEM_INTERFACE MemfsInterface =
|
||||||
{
|
{
|
||||||
GetVolumeInfo,
|
GetVolumeInfo,
|
||||||
@ -951,6 +980,9 @@ static FSP_FILE_SYSTEM_INTERFACE MemfsInterface =
|
|||||||
GetSecurity,
|
GetSecurity,
|
||||||
SetSecurity,
|
SetSecurity,
|
||||||
ReadDirectory,
|
ReadDirectory,
|
||||||
|
ResolveReparsePoints,
|
||||||
|
GetReparsePoint,
|
||||||
|
SetReparsePoint,
|
||||||
};
|
};
|
||||||
|
|
||||||
NTSTATUS MemfsCreate(
|
NTSTATUS MemfsCreate(
|
||||||
|
Loading…
x
Reference in New Issue
Block a user