mirror of
				https://github.com/winfsp/winfsp.git
				synced 2025-10-30 19:48:38 -05:00 
			
		
		
		
	dll: fuse: multiple improvements and fixes
- Symlinks: Now supports conventing a directory into a symlink reparse point. - Symlinks: The determination of whether a symlink is a file or directory is now possible for file systems that do not support slashdot (/.) queries. - EA: Now allows the removal of non-existant EA without error (this is allowed on Windows).
This commit is contained in:
		| @@ -197,7 +197,8 @@ enum | |||||||
|     /* user-mode flags */\ |     /* user-mode flags */\ | ||||||
|     UINT32 UmFileContextIsUserContext2:1;   /* user mode: FileContext parameter is UserContext2 */\ |     UINT32 UmFileContextIsUserContext2:1;   /* user mode: FileContext parameter is UserContext2 */\ | ||||||
|     UINT32 UmFileContextIsFullContext:1;    /* user mode: FileContext parameter is FullContext */\ |     UINT32 UmFileContextIsFullContext:1;    /* user mode: FileContext parameter is FullContext */\ | ||||||
|     UINT32 UmReservedFlags:6;\ |     UINT32 UmNoReparsePointsDirCheck:1;     /* user mode: no dir option check for reparse points */\ | ||||||
|  |     UINT32 UmReservedFlags:5;\ | ||||||
|     /* additional kernel-mode flags */\ |     /* additional kernel-mode flags */\ | ||||||
|     UINT32 AllowOpenInKernelMode:1;         /* allow kernel mode to open files when possible */\ |     UINT32 AllowOpenInKernelMode:1;         /* allow kernel mode to open files when possible */\ | ||||||
|     UINT32 CasePreservedExtendedAttributes:1;   /* preserve case of EA (default is UPPERCASE) */\ |     UINT32 CasePreservedExtendedAttributes:1;   /* preserve case of EA (default is UPPERCASE) */\ | ||||||
|   | |||||||
| @@ -1143,7 +1143,13 @@ typedef struct _FSP_FILE_SYSTEM | |||||||
|     FSP_FILE_SYSTEM_OPERATION_GUARD_STRATEGY OpGuardStrategy; |     FSP_FILE_SYSTEM_OPERATION_GUARD_STRATEGY OpGuardStrategy; | ||||||
|     SRWLOCK OpGuardLock; |     SRWLOCK OpGuardLock; | ||||||
|     BOOLEAN UmFileContextIsUserContext2, UmFileContextIsFullContext; |     BOOLEAN UmFileContextIsUserContext2, UmFileContextIsFullContext; | ||||||
|  |     UINT16 UmNoReparsePointsDirCheck:1; | ||||||
|  |     UINT16 UmReservedFlags:15; | ||||||
| } FSP_FILE_SYSTEM; | } FSP_FILE_SYSTEM; | ||||||
|  | FSP_FSCTL_STATIC_ASSERT( | ||||||
|  |     (4 == sizeof(PVOID) && 660 == sizeof(FSP_FILE_SYSTEM)) || | ||||||
|  |     (8 == sizeof(PVOID) && 792 == sizeof(FSP_FILE_SYSTEM)), | ||||||
|  |     "sizeof(FSP_FILE_SYSTEM) must be exactly 660 in 32-bit and 792 in 64-bit."); | ||||||
| typedef struct _FSP_FILE_SYSTEM_OPERATION_CONTEXT | typedef struct _FSP_FILE_SYSTEM_OPERATION_CONTEXT | ||||||
| { | { | ||||||
|     FSP_FSCTL_TRANSACT_REQ *Request; |     FSP_FSCTL_TRANSACT_REQ *Request; | ||||||
|   | |||||||
| @@ -161,6 +161,7 @@ FSP_API NTSTATUS FspFileSystemCreate(PWSTR DevicePath, | |||||||
|  |  | ||||||
|     FileSystem->UmFileContextIsUserContext2 = !!VolumeParams->UmFileContextIsUserContext2; |     FileSystem->UmFileContextIsUserContext2 = !!VolumeParams->UmFileContextIsUserContext2; | ||||||
|     FileSystem->UmFileContextIsFullContext = !!VolumeParams->UmFileContextIsFullContext; |     FileSystem->UmFileContextIsFullContext = !!VolumeParams->UmFileContextIsFullContext; | ||||||
|  |     FileSystem->UmNoReparsePointsDirCheck = VolumeParams->UmNoReparsePointsDirCheck; | ||||||
|  |  | ||||||
|     *PFileSystem = FileSystem; |     *PFileSystem = FileSystem; | ||||||
|  |  | ||||||
|   | |||||||
| @@ -642,6 +642,7 @@ FSP_FUSE_API struct fuse *fsp_fuse_new(struct fsp_fuse_env *env, | |||||||
|     opt_data.VolumeParams.RejectIrpPriorToTransact0 = TRUE; |     opt_data.VolumeParams.RejectIrpPriorToTransact0 = TRUE; | ||||||
| #endif | #endif | ||||||
|     opt_data.VolumeParams.UmFileContextIsUserContext2 = TRUE; |     opt_data.VolumeParams.UmFileContextIsUserContext2 = TRUE; | ||||||
|  |     opt_data.VolumeParams.UmNoReparsePointsDirCheck = TRUE; | ||||||
|     if (L'\0' == opt_data.VolumeParams.FileSystemName[0]) |     if (L'\0' == opt_data.VolumeParams.FileSystemName[0]) | ||||||
|         memcpy(opt_data.VolumeParams.FileSystemName, L"FUSE", 5 * sizeof(WCHAR)); |         memcpy(opt_data.VolumeParams.FileSystemName, L"FUSE", 5 * sizeof(WCHAR)); | ||||||
|  |  | ||||||
|   | |||||||
| @@ -21,6 +21,13 @@ | |||||||
|  |  | ||||||
| #include <dll/fuse/library.h> | #include <dll/fuse/library.h> | ||||||
|  |  | ||||||
|  | static NTSTATUS fsp_fuse_intf_GetReparsePointByName( | ||||||
|  |     FSP_FILE_SYSTEM *FileSystem, PVOID Context, | ||||||
|  |     PWSTR FileName, BOOLEAN IsDirectory, PVOID Buffer, PSIZE_T PSize); | ||||||
|  | static NTSTATUS fsp_fuse_intf_SetEaEntry( | ||||||
|  |     FSP_FILE_SYSTEM *FileSystem, PVOID Context, | ||||||
|  |     PFILE_FULL_EA_INFORMATION SingleEa); | ||||||
|  |  | ||||||
| static inline | static inline | ||||||
| VOID fsp_fuse_op_enter_lock(FSP_FILE_SYSTEM *FileSystem, | VOID fsp_fuse_op_enter_lock(FSP_FILE_SYSTEM *FileSystem, | ||||||
|     FSP_FSCTL_TRANSACT_REQ *Request, FSP_FSCTL_TRANSACT_RSP *Response) |     FSP_FSCTL_TRANSACT_REQ *Request, FSP_FSCTL_TRANSACT_RSP *Response) | ||||||
| @@ -304,6 +311,9 @@ static BOOLEAN fsp_fuse_intf_CheckSymlinkDirectory(FSP_FILE_SYSTEM *FileSystem, | |||||||
|     const char *PosixPath) |     const char *PosixPath) | ||||||
| { | { | ||||||
|     struct fuse *f = FileSystem->UserContext; |     struct fuse *f = FileSystem->UserContext; | ||||||
|  |  | ||||||
|  |     if (FSP_FUSE_HAS_SLASHDOT(f)) | ||||||
|  |     { | ||||||
|         char *PosixDotPath = 0; |         char *PosixDotPath = 0; | ||||||
|         size_t Length; |         size_t Length; | ||||||
|         struct fuse_stat_ex stbuf; |         struct fuse_stat_ex stbuf; | ||||||
| @@ -332,6 +342,81 @@ static BOOLEAN fsp_fuse_intf_CheckSymlinkDirectory(FSP_FILE_SYSTEM *FileSystem, | |||||||
|  |  | ||||||
|         return Result; |         return Result; | ||||||
|     } |     } | ||||||
|  |     else | ||||||
|  |     { | ||||||
|  |         PWSTR WindowsPath = 0, P; | ||||||
|  |         char *PosixResolvedPath = 0; | ||||||
|  |         UINT32 ReparsePointIndex; | ||||||
|  |         UINT32 ResolvedFileAttributes = -1; | ||||||
|  |         IO_STATUS_BLOCK IoStatus; | ||||||
|  |         union | ||||||
|  |         { | ||||||
|  |             REPARSE_DATA_BUFFER V; | ||||||
|  |             UINT8 B[FIELD_OFFSET(REPARSE_DATA_BUFFER, SymbolicLinkReparseBuffer.PathBuffer) + | ||||||
|  |                 FSP_FSCTL_TRANSACT_PATH_SIZEMAX + sizeof(WCHAR)/* add space for term-0 */]; | ||||||
|  |         } ReparseDataBuf; | ||||||
|  |         SIZE_T ReparseDataSize; | ||||||
|  |         struct fuse_stat_ex stbuf; | ||||||
|  |         int err; | ||||||
|  |         NTSTATUS Result; | ||||||
|  |  | ||||||
|  |         Result = FspPosixMapPosixToWindowsPath(PosixPath, &WindowsPath); | ||||||
|  |         if (!NT_SUCCESS(Result)) | ||||||
|  |             goto exit; | ||||||
|  |  | ||||||
|  |         ReparsePointIndex = 0; | ||||||
|  |         for (P = WindowsPath; '\0' != *P; P++) | ||||||
|  |             if (L'\\' == *P) | ||||||
|  |                 ReparsePointIndex = (UINT32)(P + 1 - WindowsPath); | ||||||
|  |  | ||||||
|  |         ReparseDataSize = sizeof ReparseDataBuf - sizeof(WCHAR)/* leave space for term-0 */; | ||||||
|  |         Result = FspFileSystemResolveReparsePoints(FileSystem, | ||||||
|  |             fsp_fuse_intf_GetReparsePointByName, &ResolvedFileAttributes, | ||||||
|  |             WindowsPath, ReparsePointIndex, TRUE, | ||||||
|  |             &IoStatus, &ReparseDataBuf, | ||||||
|  |             &ReparseDataSize); | ||||||
|  |         if (!NT_SUCCESS(Result)) | ||||||
|  |             goto exit; | ||||||
|  |  | ||||||
|  |         if (IO_REPARSE_TAG_SYMLINK != ReparseDataBuf.V.ReparseTag) | ||||||
|  |         { | ||||||
|  |             Result = STATUS_UNSUCCESSFUL; | ||||||
|  |             goto exit; | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         if (-1 != ResolvedFileAttributes) | ||||||
|  |         { | ||||||
|  |             Result = (FILE_ATTRIBUTE_DIRECTORY & ResolvedFileAttributes) ? | ||||||
|  |                 STATUS_SUCCESS : STATUS_UNSUCCESSFUL; | ||||||
|  |             goto exit; | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         P = (PWSTR)(ReparseDataBuf.V.SymbolicLinkReparseBuffer.PathBuffer + | ||||||
|  |             ReparseDataBuf.V.SymbolicLinkReparseBuffer.SubstituteNameOffset / sizeof(WCHAR)); | ||||||
|  |         P[ReparseDataBuf.V.SymbolicLinkReparseBuffer.SubstituteNameLength / sizeof(WCHAR)] = L'\0'; | ||||||
|  |  | ||||||
|  |         Result = FspPosixMapWindowsToPosixPath(P, &PosixResolvedPath); | ||||||
|  |         if (!NT_SUCCESS(Result)) | ||||||
|  |             goto exit; | ||||||
|  |  | ||||||
|  |         memset(&stbuf, 0, sizeof stbuf); | ||||||
|  |         if (0 != f->ops.getattr) | ||||||
|  |             err = f->ops.getattr(PosixResolvedPath, (void *)&stbuf); | ||||||
|  |         else | ||||||
|  |             err = -ENOSYS_(f->env); | ||||||
|  |  | ||||||
|  |         Result = 0 == err && 0040000 == (stbuf.st_mode & 0170000) ? | ||||||
|  |             STATUS_SUCCESS : STATUS_UNSUCCESSFUL; | ||||||
|  |  | ||||||
|  |     exit: | ||||||
|  |         if (0 != PosixResolvedPath) | ||||||
|  |             FspPosixDeletePath(PosixResolvedPath); | ||||||
|  |         if (0 != WindowsPath) | ||||||
|  |             FspPosixDeletePath(WindowsPath); | ||||||
|  |  | ||||||
|  |         return NT_SUCCESS(Result); | ||||||
|  |     } | ||||||
|  | } | ||||||
|  |  | ||||||
| static inline uint32_t fsp_fuse_intf_MapFileAttributesToFlags(UINT32 FileAttributes) | static inline uint32_t fsp_fuse_intf_MapFileAttributesToFlags(UINT32 FileAttributes) | ||||||
| { | { | ||||||
| @@ -367,10 +452,11 @@ static inline UINT32 fsp_fuse_intf_MapFlagsToFileAttributes(uint32_t flags) | |||||||
|  |  | ||||||
| #define FUSE_FILE_INFO(IsDirectory, fi) ((IsDirectory) ? 0 : (fi)) | #define FUSE_FILE_INFO(IsDirectory, fi) ((IsDirectory) ? 0 : (fi)) | ||||||
| #define fsp_fuse_intf_GetFileInfoEx(FileSystem, PosixPath, fi, PUid, PGid, PMode, FileInfo)\ | #define fsp_fuse_intf_GetFileInfoEx(FileSystem, PosixPath, fi, PUid, PGid, PMode, FileInfo)\ | ||||||
|     fsp_fuse_intf_GetFileInfoFunnel(FileSystem, PosixPath, fi, 0, PUid, PGid, PMode, 0, FileInfo) |     fsp_fuse_intf_GetFileInfoFunnel(FileSystem, PosixPath, fi, 0, PUid, PGid, PMode, 0, TRUE, FileInfo) | ||||||
| static NTSTATUS fsp_fuse_intf_GetFileInfoFunnel(FSP_FILE_SYSTEM *FileSystem, | static NTSTATUS fsp_fuse_intf_GetFileInfoFunnel(FSP_FILE_SYSTEM *FileSystem, | ||||||
|     const char *PosixPath, struct fuse_file_info *fi, const void *stbufp, |     const char *PosixPath, struct fuse_file_info *fi, const void *stbufp, | ||||||
|     PUINT32 PUid, PUINT32 PGid, PUINT32 PMode, PUINT32 PDev, |     PUINT32 PUid, PUINT32 PGid, PUINT32 PMode, PUINT32 PDev, | ||||||
|  |     BOOLEAN CheckSymlinkDirectory, | ||||||
|     FSP_FSCTL_FILE_INFO *FileInfo) |     FSP_FSCTL_FILE_INFO *FileInfo) | ||||||
| { | { | ||||||
|     struct fuse *f = FileSystem->UserContext; |     struct fuse *f = FileSystem->UserContext; | ||||||
| @@ -429,7 +515,7 @@ static NTSTATUS fsp_fuse_intf_GetFileInfoFunnel(FSP_FILE_SYSTEM *FileSystem, | |||||||
|         { |         { | ||||||
|             FileInfo->FileAttributes = FILE_ATTRIBUTE_REPARSE_POINT; |             FileInfo->FileAttributes = FILE_ATTRIBUTE_REPARSE_POINT; | ||||||
|             FileInfo->ReparseTag = IO_REPARSE_TAG_SYMLINK; |             FileInfo->ReparseTag = IO_REPARSE_TAG_SYMLINK; | ||||||
|             if (fsp_fuse_intf_CheckSymlinkDirectory(FileSystem, PosixPath)) |             if (CheckSymlinkDirectory && fsp_fuse_intf_CheckSymlinkDirectory(FileSystem, PosixPath)) | ||||||
|                 FileInfo->FileAttributes |= FILE_ATTRIBUTE_DIRECTORY; |                 FileInfo->FileAttributes |= FILE_ATTRIBUTE_DIRECTORY; | ||||||
|             break; |             break; | ||||||
|         } |         } | ||||||
| @@ -572,7 +658,7 @@ exit: | |||||||
|  |  | ||||||
| static NTSTATUS fsp_fuse_intf_GetReparsePointEx(FSP_FILE_SYSTEM *FileSystem, | static NTSTATUS fsp_fuse_intf_GetReparsePointEx(FSP_FILE_SYSTEM *FileSystem, | ||||||
|     const char *PosixPath, struct fuse_file_info *fi, |     const char *PosixPath, struct fuse_file_info *fi, | ||||||
|     PVOID Buffer, PSIZE_T PSize) |     PVOID Buffer, PSIZE_T PSize, PUINT32 PResolvedFileAttributes) | ||||||
| { | { | ||||||
|     struct fuse *f = FileSystem->UserContext; |     struct fuse *f = FileSystem->UserContext; | ||||||
|     UINT32 Uid, Gid, Mode, Dev; |     UINT32 Uid, Gid, Mode, Dev; | ||||||
| @@ -583,12 +669,16 @@ static NTSTATUS fsp_fuse_intf_GetReparsePointEx(FSP_FILE_SYSTEM *FileSystem, | |||||||
|     NTSTATUS Result; |     NTSTATUS Result; | ||||||
|  |  | ||||||
|     Result = fsp_fuse_intf_GetFileInfoFunnel(FileSystem, PosixPath, fi, 0, |     Result = fsp_fuse_intf_GetFileInfoFunnel(FileSystem, PosixPath, fi, 0, | ||||||
|         &Uid, &Gid, &Mode, &Dev, &FileInfo); |         &Uid, &Gid, &Mode, &Dev, FALSE, &FileInfo); | ||||||
|     if (!NT_SUCCESS(Result)) |     if (!NT_SUCCESS(Result)) | ||||||
|         return Result; |         return Result; | ||||||
|  |  | ||||||
|     if (0 == (FILE_ATTRIBUTE_REPARSE_POINT & FileInfo.FileAttributes)) |     if (0 == (FILE_ATTRIBUTE_REPARSE_POINT & FileInfo.FileAttributes)) | ||||||
|  |     { | ||||||
|  |         if (0 != PResolvedFileAttributes) | ||||||
|  |             *PResolvedFileAttributes = FileInfo.FileAttributes; | ||||||
|         return STATUS_NOT_A_REPARSE_POINT; |         return STATUS_NOT_A_REPARSE_POINT; | ||||||
|  |     } | ||||||
|  |  | ||||||
|     if (0 == Buffer) |     if (0 == Buffer) | ||||||
|         return STATUS_SUCCESS; |         return STATUS_SUCCESS; | ||||||
| @@ -688,13 +778,6 @@ static NTSTATUS fsp_fuse_intf_GetReparsePointEx(FSP_FILE_SYSTEM *FileSystem, | |||||||
|     return STATUS_SUCCESS; |     return STATUS_SUCCESS; | ||||||
| } | } | ||||||
|  |  | ||||||
| static NTSTATUS fsp_fuse_intf_GetReparsePointByName( |  | ||||||
|     FSP_FILE_SYSTEM *FileSystem, PVOID Context, |  | ||||||
|     PWSTR FileName, BOOLEAN IsDirectory, PVOID Buffer, PSIZE_T PSize); |  | ||||||
| static NTSTATUS fsp_fuse_intf_SetEaEntry( |  | ||||||
|     FSP_FILE_SYSTEM *FileSystem, PVOID Context, |  | ||||||
|     PFILE_FULL_EA_INFORMATION SingleEa); |  | ||||||
|  |  | ||||||
| static NTSTATUS fsp_fuse_intf_GetVolumeInfo(FSP_FILE_SYSTEM *FileSystem, | static NTSTATUS fsp_fuse_intf_GetVolumeInfo(FSP_FILE_SYSTEM *FileSystem, | ||||||
|     FSP_FSCTL_VOLUME_INFO *VolumeInfo) |     FSP_FSCTL_VOLUME_INFO *VolumeInfo) | ||||||
| { | { | ||||||
| @@ -1031,7 +1114,12 @@ static NTSTATUS fsp_fuse_intf_Open(FSP_FILE_SYSTEM *FileSystem, | |||||||
|         break; |         break; | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     if (FileInfoBuf.FileAttributes & FILE_ATTRIBUTE_DIRECTORY) |     if (FileInfoBuf.FileAttributes & FILE_ATTRIBUTE_REPARSE_POINT) | ||||||
|  |     { | ||||||
|  |         fi.fh = -1; | ||||||
|  |         Result = STATUS_SUCCESS; | ||||||
|  |     } | ||||||
|  |     else if (FileInfoBuf.FileAttributes & FILE_ATTRIBUTE_DIRECTORY) | ||||||
|     { |     { | ||||||
|         if (0 != f->ops.opendir) |         if (0 != f->ops.opendir) | ||||||
|         { |         { | ||||||
| @@ -1044,11 +1132,6 @@ static NTSTATUS fsp_fuse_intf_Open(FSP_FILE_SYSTEM *FileSystem, | |||||||
|             Result = STATUS_SUCCESS; |             Result = STATUS_SUCCESS; | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
|     else if (FileInfoBuf.FileAttributes & FILE_ATTRIBUTE_REPARSE_POINT) |  | ||||||
|     { |  | ||||||
|         fi.fh = -1; |  | ||||||
|         Result = STATUS_SUCCESS; |  | ||||||
|     } |  | ||||||
|     else |     else | ||||||
|     { |     { | ||||||
|         /* |         /* | ||||||
| @@ -1192,15 +1275,15 @@ static VOID fsp_fuse_intf_Close(FSP_FILE_SYSTEM *FileSystem, | |||||||
|     fi.flags = filedesc->OpenFlags; |     fi.flags = filedesc->OpenFlags; | ||||||
|     fi.fh = filedesc->FileHandle; |     fi.fh = filedesc->FileHandle; | ||||||
|  |  | ||||||
|     if (filedesc->IsDirectory) |     if (filedesc->IsReparsePoint) | ||||||
|  |     { | ||||||
|  |         /* reparse points are not opened, nothing to do! */ | ||||||
|  |     } | ||||||
|  |     else if (filedesc->IsDirectory) | ||||||
|     { |     { | ||||||
|         if (0 != f->ops.releasedir) |         if (0 != f->ops.releasedir) | ||||||
|             f->ops.releasedir(filedesc->PosixPath, &fi); |             f->ops.releasedir(filedesc->PosixPath, &fi); | ||||||
|     } |     } | ||||||
|     else if (filedesc->IsReparsePoint) |  | ||||||
|     { |  | ||||||
|         /* reparse points are not opened, nothing to do! */ |  | ||||||
|     } |  | ||||||
|     else |     else | ||||||
|     { |     { | ||||||
|         if (0 != f->ops.flush) |         if (0 != f->ops.flush) | ||||||
| @@ -1332,7 +1415,9 @@ static NTSTATUS fsp_fuse_intf_Flush(FSP_FILE_SYSTEM *FileSystem, | |||||||
|     fi.fh = filedesc->FileHandle; |     fi.fh = filedesc->FileHandle; | ||||||
|  |  | ||||||
|     Result = STATUS_SUCCESS; /* just say success, if fs does not support fsync */ |     Result = STATUS_SUCCESS; /* just say success, if fs does not support fsync */ | ||||||
|     if (filedesc->IsDirectory) |     if (filedesc->IsReparsePoint) | ||||||
|  |         Result = STATUS_ACCESS_DENIED; | ||||||
|  |     else if (filedesc->IsDirectory) | ||||||
|     { |     { | ||||||
|         if (0 != f->ops.fsyncdir) |         if (0 != f->ops.fsyncdir) | ||||||
|         { |         { | ||||||
| @@ -1340,8 +1425,6 @@ static NTSTATUS fsp_fuse_intf_Flush(FSP_FILE_SYSTEM *FileSystem, | |||||||
|             Result = fsp_fuse_ntstatus_from_errno(f->env, err); |             Result = fsp_fuse_ntstatus_from_errno(f->env, err); | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
|     else if (filedesc->IsReparsePoint) |  | ||||||
|         Result = STATUS_ACCESS_DENIED; |  | ||||||
|     else |     else | ||||||
|     { |     { | ||||||
|         if (0 != f->ops.fsync) |         if (0 != f->ops.fsync) | ||||||
| @@ -1854,7 +1937,7 @@ int fsp_fuse_intf_AddDirInfo(void *buf, const char *name, | |||||||
|         NTSTATUS Result0; |         NTSTATUS Result0; | ||||||
|  |  | ||||||
|         Result0 = fsp_fuse_intf_GetFileInfoFunnel(dh->FileSystem, name, 0, stbuf, |         Result0 = fsp_fuse_intf_GetFileInfoFunnel(dh->FileSystem, name, 0, stbuf, | ||||||
|             &Uid, &Gid, &Mode, 0, &DirInfo->FileInfo); |             &Uid, &Gid, &Mode, 0, TRUE, &DirInfo->FileInfo); | ||||||
|         if (NT_SUCCESS(Result0)) |         if (NT_SUCCESS(Result0)) | ||||||
|             DirInfo->Padding[0] = 1; /* HACK: remember that the FileInfo is valid */ |             DirInfo->Padding[0] = 1; /* HACK: remember that the FileInfo is valid */ | ||||||
|     } |     } | ||||||
| @@ -1976,6 +2059,9 @@ static NTSTATUS fsp_fuse_intf_ReadDirectory(FSP_FILE_SYSTEM *FileSystem, | |||||||
|     int err; |     int err; | ||||||
|     NTSTATUS Result; |     NTSTATUS Result; | ||||||
|  |  | ||||||
|  |     if (!filedesc->IsDirectory || filedesc->IsReparsePoint) | ||||||
|  |         return STATUS_ACCESS_DENIED; | ||||||
|  |  | ||||||
|     if (FspFileSystemAcquireDirectoryBuffer(&filedesc->DirBuffer, 0 == Marker, &Result)) |     if (FspFileSystemAcquireDirectoryBuffer(&filedesc->DirBuffer, 0 == Marker, &Result)) | ||||||
|     { |     { | ||||||
|         memset(&dh, 0, sizeof dh); |         memset(&dh, 0, sizeof dh); | ||||||
| @@ -2032,6 +2118,9 @@ static NTSTATUS fsp_fuse_intf_GetDirInfoByName(FSP_FILE_SYSTEM *FileSystem, | |||||||
|     UINT32 Uid, Gid, Mode; |     UINT32 Uid, Gid, Mode; | ||||||
|     NTSTATUS Result; |     NTSTATUS Result; | ||||||
|  |  | ||||||
|  |     if (!filedesc->IsDirectory || filedesc->IsReparsePoint) | ||||||
|  |         return STATUS_ACCESS_DENIED; | ||||||
|  |  | ||||||
|     Result = FspPosixMapWindowsToPosixPath(FileName, &PosixName); |     Result = FspPosixMapWindowsToPosixPath(FileName, &PosixName); | ||||||
|     if (!NT_SUCCESS(Result)) |     if (!NT_SUCCESS(Result)) | ||||||
|     { |     { | ||||||
| @@ -2098,7 +2187,7 @@ static NTSTATUS fsp_fuse_intf_GetReparsePointByName( | |||||||
|     if (!NT_SUCCESS(Result)) |     if (!NT_SUCCESS(Result)) | ||||||
|         goto exit; |         goto exit; | ||||||
|  |  | ||||||
|     Result = fsp_fuse_intf_GetReparsePointEx(FileSystem, PosixPath, 0, Buffer, PSize); |     Result = fsp_fuse_intf_GetReparsePointEx(FileSystem, PosixPath, 0, Buffer, PSize, Context); | ||||||
|  |  | ||||||
| exit: | exit: | ||||||
|     if (0 != PosixPath) |     if (0 != PosixPath) | ||||||
| @@ -2120,7 +2209,7 @@ static NTSTATUS fsp_fuse_intf_GetReparsePoint(FSP_FILE_SYSTEM *FileSystem, | |||||||
|  |  | ||||||
|     return fsp_fuse_intf_GetReparsePointEx(FileSystem, filedesc->PosixPath, |     return fsp_fuse_intf_GetReparsePointEx(FileSystem, filedesc->PosixPath, | ||||||
|         FUSE_FILE_INFO(filedesc->IsDirectory, &fi), |         FUSE_FILE_INFO(filedesc->IsDirectory, &fi), | ||||||
|         Buffer, PSize); |         Buffer, PSize, 0); | ||||||
| } | } | ||||||
|  |  | ||||||
| static NTSTATUS fsp_fuse_intf_SetReparsePoint(FSP_FILE_SYSTEM *FileSystem, | static NTSTATUS fsp_fuse_intf_SetReparsePoint(FSP_FILE_SYSTEM *FileSystem, | ||||||
| @@ -2159,23 +2248,25 @@ static NTSTATUS fsp_fuse_intf_SetReparsePoint(FSP_FILE_SYSTEM *FileSystem, | |||||||
|      * Note that this will also result in a change of the inode number for the reparse point! |      * Note that this will also result in a change of the inode number for the reparse point! | ||||||
|      */ |      */ | ||||||
|  |  | ||||||
|     if (0 == f->ops.rename || 0 == f->ops.unlink) |  | ||||||
|         return STATUS_INVALID_DEVICE_REQUEST; |  | ||||||
|  |  | ||||||
|     ReparseData = (PREPARSE_DATA_BUFFER)Buffer; |     ReparseData = (PREPARSE_DATA_BUFFER)Buffer; | ||||||
|  |  | ||||||
|     if (IO_REPARSE_TAG_SYMLINK == ReparseData->ReparseTag || ( |     if (IO_REPARSE_TAG_SYMLINK == ReparseData->ReparseTag || ( | ||||||
|         IO_REPARSE_TAG_NFS == ReparseData->ReparseTag && |         IO_REPARSE_TAG_NFS == ReparseData->ReparseTag && | ||||||
|         NFS_SPECFILE_LNK == *(PUINT64)ReparseData->GenericReparseBuffer.DataBuffer)) |         NFS_SPECFILE_LNK == *(PUINT64)ReparseData->GenericReparseBuffer.DataBuffer)) | ||||||
|     { |     { | ||||||
|         if (0 == f->ops.symlink) |         if (filedesc->IsDirectory && 0 == f->ops.rmdir) | ||||||
|  |             return STATUS_INVALID_DEVICE_REQUEST; | ||||||
|  |         if (0 == f->ops.symlink || 0 == f->ops.rename || 0 == f->ops.unlink) | ||||||
|             return STATUS_INVALID_DEVICE_REQUEST; |             return STATUS_INVALID_DEVICE_REQUEST; | ||||||
|  |  | ||||||
|         IsSymlink = TRUE; |         IsSymlink = TRUE; | ||||||
|     } |     } | ||||||
|     else if (IO_REPARSE_TAG_NFS == ReparseData->ReparseTag) |     else if (IO_REPARSE_TAG_NFS == ReparseData->ReparseTag) | ||||||
|     { |     { | ||||||
|         if (0 == f->ops.mknod) |         /* FUSE cannot make a directory into an NFS reparse point */ | ||||||
|  |         if (filedesc->IsDirectory) | ||||||
|  |             return STATUS_ACCESS_DENIED; | ||||||
|  |         if (0 == f->ops.mknod || 0 == f->ops.rename || 0 == f->ops.unlink) | ||||||
|             return STATUS_INVALID_DEVICE_REQUEST; |             return STATUS_INVALID_DEVICE_REQUEST; | ||||||
|  |  | ||||||
|         IsSymlink = FALSE; |         IsSymlink = FALSE; | ||||||
| @@ -2183,10 +2274,6 @@ static NTSTATUS fsp_fuse_intf_SetReparsePoint(FSP_FILE_SYSTEM *FileSystem, | |||||||
|     else |     else | ||||||
|         return STATUS_IO_REPARSE_TAG_MISMATCH; |         return STATUS_IO_REPARSE_TAG_MISMATCH; | ||||||
|  |  | ||||||
|     /* FUSE cannot make a directory into a reparse point */ |  | ||||||
|     if (filedesc->IsDirectory) |  | ||||||
|         return STATUS_ACCESS_DENIED; |  | ||||||
|  |  | ||||||
|     memset(&fi, 0, sizeof fi); |     memset(&fi, 0, sizeof fi); | ||||||
|     fi.flags = filedesc->OpenFlags; |     fi.flags = filedesc->OpenFlags; | ||||||
|     fi.fh = filedesc->FileHandle; |     fi.fh = filedesc->FileHandle; | ||||||
| @@ -2297,17 +2384,33 @@ static NTSTATUS fsp_fuse_intf_SetReparsePoint(FSP_FILE_SYSTEM *FileSystem, | |||||||
|         } |         } | ||||||
|     } |     } | ||||||
|  |  | ||||||
|  |     if (filedesc->IsDirectory) | ||||||
|  |     { | ||||||
|  |         err = f->ops.rmdir(filedesc->PosixPath); | ||||||
|  |         if (0 == err) | ||||||
|  |             err = f->ops.rename(PosixHiddenPath, filedesc->PosixPath); | ||||||
|  |     } | ||||||
|  |     else | ||||||
|         err = f->ops.rename(PosixHiddenPath, filedesc->PosixPath); |         err = f->ops.rename(PosixHiddenPath, filedesc->PosixPath); | ||||||
|     if (0 != err) |     if (0 != err) | ||||||
|     { |     { | ||||||
|         /* on failure unlink "hidden" symlink */ |  | ||||||
|         f->ops.unlink(PosixHiddenPath); |         f->ops.unlink(PosixHiddenPath); | ||||||
|  |  | ||||||
|         Result = fsp_fuse_ntstatus_from_errno(f->env, err); |         Result = fsp_fuse_ntstatus_from_errno(f->env, err); | ||||||
|         goto exit; |         goto exit; | ||||||
|     } |     } | ||||||
|  |  | ||||||
|  |     if (filedesc->IsDirectory) | ||||||
|  |     { | ||||||
|  |         if (0 != f->ops.releasedir) | ||||||
|  |             f->ops.releasedir(filedesc->PosixPath, &fi); | ||||||
|  |     } | ||||||
|  |     else | ||||||
|  |     { | ||||||
|  |         if (0 != f->ops.release) | ||||||
|  |             f->ops.release(filedesc->PosixPath, &fi); | ||||||
|  |     } | ||||||
|     filedesc->IsReparsePoint = TRUE; |     filedesc->IsReparsePoint = TRUE; | ||||||
|  |     filedesc->FileHandle = -1; | ||||||
|  |  | ||||||
|     Result = STATUS_SUCCESS; |     Result = STATUS_SUCCESS; | ||||||
|  |  | ||||||
| @@ -2433,14 +2536,18 @@ static NTSTATUS fsp_fuse_intf_SetEaEntry( | |||||||
|     int err; |     int err; | ||||||
|  |  | ||||||
|     if (0 != SingleEa->EaValueLength) |     if (0 != SingleEa->EaValueLength) | ||||||
|         err = f->ops.setxattr(PosixPath, |     { | ||||||
|             SingleEa->EaName, SingleEa->EaName + SingleEa->EaNameLength + 1, SingleEa->EaValueLength, 0); |         err = f->ops.setxattr(PosixPath, SingleEa->EaName, | ||||||
|     else |             SingleEa->EaName + SingleEa->EaNameLength + 1, SingleEa->EaValueLength, 0); | ||||||
|         err = f->ops.removexattr(PosixPath, |  | ||||||
|             SingleEa->EaName); |  | ||||||
|  |  | ||||||
|         return fsp_fuse_ntstatus_from_errno(f->env, err); |         return fsp_fuse_ntstatus_from_errno(f->env, err); | ||||||
|     } |     } | ||||||
|  |     else | ||||||
|  |     { | ||||||
|  |         err = f->ops.removexattr(PosixPath, SingleEa->EaName); | ||||||
|  |             /* ignore errors */ | ||||||
|  |         return STATUS_SUCCESS; | ||||||
|  |     } | ||||||
|  | } | ||||||
|  |  | ||||||
| static NTSTATUS fsp_fuse_intf_SetEa(FSP_FILE_SYSTEM *FileSystem, | static NTSTATUS fsp_fuse_intf_SetEa(FSP_FILE_SYSTEM *FileSystem, | ||||||
|     PVOID FileDesc, |     PVOID FileDesc, | ||||||
|   | |||||||
| @@ -160,6 +160,29 @@ static NTSTATUS fsp_fuse_loop_start(struct fuse *f) | |||||||
|         /* this should always fail with ENOSYS or EINVAL */ |         /* this should always fail with ENOSYS or EINVAL */ | ||||||
|         err = f->ops.readlink("/", buf, sizeof buf); |         err = f->ops.readlink("/", buf, sizeof buf); | ||||||
|         f->has_symlinks = -ENOSYS_(f->env) != err; |         f->has_symlinks = -ENOSYS_(f->env) != err; | ||||||
|  |  | ||||||
|  |         if (f->has_symlinks) | ||||||
|  |         { | ||||||
|  |             /* | ||||||
|  |              * Determine if the file system supports "/." queries. | ||||||
|  |              * | ||||||
|  |              * Symlinks on Windows are differentiated as "file" symlinks or "directory" symlinks. | ||||||
|  |              * When we need to make the distinction we can follow one of two techniques: | ||||||
|  |              * | ||||||
|  |              * - Slashdot technique: We issue a getattr(path + "/.") and check the stat result. | ||||||
|  |              * In general this is not a getattr() query that FUSE file systems are expected | ||||||
|  |              * to handle. For this reason we issue a getattr("/.") below to determine | ||||||
|  |              * if the file system handles this kind of query against the root directory. | ||||||
|  |              * | ||||||
|  |              * - Resolve technique: If the file system cannot handle slashdot queries, we resolve | ||||||
|  |              * the path using readlink on each path component, then issue getattr on the resolved | ||||||
|  |              * path and check the stat result. | ||||||
|  |              */ | ||||||
|  |             struct fuse_stat_ex stbuf; | ||||||
|  |             memset(&stbuf, 0, sizeof stbuf); | ||||||
|  |             err = f->ops.getattr("/.", (void *)&stbuf); | ||||||
|  |             f->has_slashdot = 0 == err && 0040000 == (stbuf.st_mode & 0170000); | ||||||
|  |         } | ||||||
|     } |     } | ||||||
|     if (0 != f->ops.listxattr && 0 != f->ops.getxattr && |     if (0 != f->ops.listxattr && 0 != f->ops.getxattr && | ||||||
|         0 != f->ops.setxattr && 0 != f->ops.removexattr) |         0 != f->ops.setxattr && 0 != f->ops.removexattr) | ||||||
|   | |||||||
| @@ -34,6 +34,7 @@ | |||||||
|     ((struct fuse_context *)((PUINT8)(h) + sizeof(struct fsp_fuse_context_header))) |     ((struct fuse_context *)((PUINT8)(h) + sizeof(struct fsp_fuse_context_header))) | ||||||
|  |  | ||||||
| #define FSP_FUSE_HAS_SYMLINKS(f)        ((f)->has_symlinks) | #define FSP_FUSE_HAS_SYMLINKS(f)        ((f)->has_symlinks) | ||||||
|  | #define FSP_FUSE_HAS_SLASHDOT(f)        ((f)->has_slashdot) | ||||||
|  |  | ||||||
| #define ENOSYS_(env)                    ('C' == (env)->environment ? 88 : 40) | #define ENOSYS_(env)                    ('C' == (env)->environment ? 88 : 40) | ||||||
|  |  | ||||||
| @@ -61,7 +62,7 @@ struct fuse | |||||||
|     void *data; |     void *data; | ||||||
|     unsigned conn_want; |     unsigned conn_want; | ||||||
|     BOOLEAN fsinit; |     BOOLEAN fsinit; | ||||||
|     BOOLEAN has_symlinks; |     BOOLEAN has_symlinks, has_slashdot; | ||||||
|     UINT32 DebugLog; |     UINT32 DebugLog; | ||||||
|     FSP_FILE_SYSTEM_OPERATION_GUARD_STRATEGY OpGuardStrategy; |     FSP_FILE_SYSTEM_OPERATION_GUARD_STRATEGY OpGuardStrategy; | ||||||
|     FSP_FSCTL_VOLUME_PARAMS VolumeParams; |     FSP_FSCTL_VOLUME_PARAMS VolumeParams; | ||||||
|   | |||||||
| @@ -325,6 +325,13 @@ FSP_API NTSTATUS FspAccessCheckEx(FSP_FILE_SYSTEM *FileSystem, | |||||||
|             goto exit; |             goto exit; | ||||||
|         } |         } | ||||||
|  |  | ||||||
|  |         /* | ||||||
|  |          * We allow some file systems (notably FUSE) to open reparse points | ||||||
|  |          * regardless of the FILE_DIRECTORY_FILE / FILE_NON_DIRECTORY_FILE options. | ||||||
|  |          */ | ||||||
|  |         if (0 != (FileAttributes & FILE_ATTRIBUTE_REPARSE_POINT) && FileSystem->UmNoReparsePointsDirCheck) | ||||||
|  |             goto skip_reparse_dir_check; | ||||||
|  |  | ||||||
|         if ((Request->Req.Create.CreateOptions & FILE_DIRECTORY_FILE) && |         if ((Request->Req.Create.CreateOptions & FILE_DIRECTORY_FILE) && | ||||||
|             0 == (FileAttributes & FILE_ATTRIBUTE_DIRECTORY)) |             0 == (FileAttributes & FILE_ATTRIBUTE_DIRECTORY)) | ||||||
|         { |         { | ||||||
| @@ -337,6 +344,9 @@ FSP_API NTSTATUS FspAccessCheckEx(FSP_FILE_SYSTEM *FileSystem, | |||||||
|             Result = STATUS_FILE_IS_A_DIRECTORY; |             Result = STATUS_FILE_IS_A_DIRECTORY; | ||||||
|             goto exit; |             goto exit; | ||||||
|         } |         } | ||||||
|  |  | ||||||
|  |     skip_reparse_dir_check: | ||||||
|  |         ; | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     if (Request->Req.Create.UserMode) |     if (Request->Req.Create.UserMode) | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user