mirror of
				https://github.com/winfsp/winfsp.git
				synced 2025-10-30 19:48:38 -05:00 
			
		
		
		
	dll: fuseintf: ReadDirectory implementation
This commit is contained in:
		| @@ -415,6 +415,8 @@ static NTSTATUS fsp_fuse_intf_Create(FSP_FILE_SYSTEM *FileSystem, | |||||||
|     filedesc->IsDirectory = !!(FileInfoBuf.FileAttributes & FILE_ATTRIBUTE_DIRECTORY); |     filedesc->IsDirectory = !!(FileInfoBuf.FileAttributes & FILE_ATTRIBUTE_DIRECTORY); | ||||||
|     filedesc->OpenFlags = fi.flags; |     filedesc->OpenFlags = fi.flags; | ||||||
|     filedesc->FileHandle = fi.fh; |     filedesc->FileHandle = fi.fh; | ||||||
|  |     filedesc->DirBuffer = 0; | ||||||
|  |     filedesc->DirBufferSize = 0; | ||||||
|     contexthdr->PosixPath = 0; |     contexthdr->PosixPath = 0; | ||||||
|     contexthdr->Response->Rsp.Create.Opened.UserContext2 = (UINT64)(UINT_PTR)filedesc; |     contexthdr->Response->Rsp.Create.Opened.UserContext2 = (UINT64)(UINT_PTR)filedesc; | ||||||
|  |  | ||||||
| @@ -522,6 +524,8 @@ static NTSTATUS fsp_fuse_intf_Open(FSP_FILE_SYSTEM *FileSystem, | |||||||
|     filedesc->IsDirectory = !!(FileInfoBuf.FileAttributes & FILE_ATTRIBUTE_DIRECTORY); |     filedesc->IsDirectory = !!(FileInfoBuf.FileAttributes & FILE_ATTRIBUTE_DIRECTORY); | ||||||
|     filedesc->OpenFlags = fi.flags; |     filedesc->OpenFlags = fi.flags; | ||||||
|     filedesc->FileHandle = fi.fh; |     filedesc->FileHandle = fi.fh; | ||||||
|  |     filedesc->DirBuffer = 0; | ||||||
|  |     filedesc->DirBufferSize = 0; | ||||||
|     contexthdr->PosixPath = 0; |     contexthdr->PosixPath = 0; | ||||||
|     contexthdr->Response->Rsp.Create.Opened.UserContext2 = (UINT64)(UINT_PTR)filedesc; |     contexthdr->Response->Rsp.Create.Opened.UserContext2 = (UINT64)(UINT_PTR)filedesc; | ||||||
|  |  | ||||||
| @@ -547,7 +551,8 @@ static VOID fsp_fuse_intf_Cleanup(FSP_FILE_SYSTEM *FileSystem, | |||||||
|     PVOID FileNode, PWSTR FileName, BOOLEAN Delete) |     PVOID FileNode, PWSTR FileName, BOOLEAN Delete) | ||||||
| { | { | ||||||
|     struct fuse *f = FileSystem->UserContext; |     struct fuse *f = FileSystem->UserContext; | ||||||
|     struct fsp_fuse_file_desc *filedesc = (PVOID)(UINT_PTR)Request->Req.Close.UserContext2; |     struct fsp_fuse_file_desc *filedesc = | ||||||
|  |         (PVOID)(UINT_PTR)Request->Req.Cleanup.UserContext2; | ||||||
|  |  | ||||||
|     /* |     /* | ||||||
|      * In Windows a DeleteFile/RemoveDirectory is the sequence of the following: |      * In Windows a DeleteFile/RemoveDirectory is the sequence of the following: | ||||||
| @@ -584,7 +589,8 @@ static VOID fsp_fuse_intf_Close(FSP_FILE_SYSTEM *FileSystem, | |||||||
|     PVOID FileNode) |     PVOID FileNode) | ||||||
| { | { | ||||||
|     struct fuse *f = FileSystem->UserContext; |     struct fuse *f = FileSystem->UserContext; | ||||||
|     struct fsp_fuse_file_desc *filedesc = (PVOID)(UINT_PTR)Request->Req.Close.UserContext2; |     struct fsp_fuse_file_desc *filedesc = | ||||||
|  |         (PVOID)(UINT_PTR)Request->Req.Close.UserContext2; | ||||||
|     struct fuse_file_info fi; |     struct fuse_file_info fi; | ||||||
|  |  | ||||||
|     memset(&fi, 0, sizeof fi); |     memset(&fi, 0, sizeof fi); | ||||||
| @@ -604,6 +610,7 @@ static VOID fsp_fuse_intf_Close(FSP_FILE_SYSTEM *FileSystem, | |||||||
|             f->ops.release(filedesc->PosixPath, &fi); |             f->ops.release(filedesc->PosixPath, &fi); | ||||||
|     } |     } | ||||||
|  |  | ||||||
|  |     MemFree(filedesc->DirBuffer); | ||||||
|     MemFree(filedesc->PosixPath); |     MemFree(filedesc->PosixPath); | ||||||
|     MemFree(filedesc); |     MemFree(filedesc); | ||||||
| } | } | ||||||
| @@ -638,7 +645,8 @@ static NTSTATUS fsp_fuse_intf_GetFileInfo(FSP_FILE_SYSTEM *FileSystem, | |||||||
|     FSP_FSCTL_FILE_INFO *FileInfo) |     FSP_FSCTL_FILE_INFO *FileInfo) | ||||||
| { | { | ||||||
|     struct fuse *f = FileSystem->UserContext; |     struct fuse *f = FileSystem->UserContext; | ||||||
|     struct fsp_fuse_file_desc *filedesc = (PVOID)(UINT_PTR)Request->Req.Close.UserContext2; |     struct fsp_fuse_file_desc *filedesc = | ||||||
|  |         (PVOID)(UINT_PTR)Request->Req.QueryInformation.UserContext2; | ||||||
|     UINT32 Uid, Gid, Mode; |     UINT32 Uid, Gid, Mode; | ||||||
|     struct fuse_file_info fi; |     struct fuse_file_info fi; | ||||||
|  |  | ||||||
| @@ -712,11 +720,11 @@ struct fuse_dirhandle | |||||||
|     char *PosixPath, *PosixName; |     char *PosixPath, *PosixName; | ||||||
|     PVOID Buffer; |     PVOID Buffer; | ||||||
|     ULONG Length; |     ULONG Length; | ||||||
|     PULONG PBytesTransferred; |     ULONG BytesTransferred; | ||||||
| }; | }; | ||||||
|  |  | ||||||
| int fsp_fuse_intf_AddDirInfo(void *buf, const char *name, | int fsp_fuse_intf_AddDirInfoCommon(void *buf, const char *name, | ||||||
|     const struct fuse_stat *stbuf, fuse_off_t off) |     const struct fuse_stat *stbuf, fuse_off_t off, BOOLEAN GrowBuffer) | ||||||
| { | { | ||||||
|     struct fuse_dirhandle *dh = buf; |     struct fuse_dirhandle *dh = buf; | ||||||
|     UINT32 Uid, Gid, Mode; |     UINT32 Uid, Gid, Mode; | ||||||
| @@ -781,13 +789,43 @@ int fsp_fuse_intf_AddDirInfo(void *buf, const char *name, | |||||||
|     DirInfo->Size = (UINT16)(sizeof(FSP_FSCTL_DIR_INFO) + Size); |     DirInfo->Size = (UINT16)(sizeof(FSP_FSCTL_DIR_INFO) + Size); | ||||||
|     DirInfo->NextOffset = off; |     DirInfo->NextOffset = off; | ||||||
|  |  | ||||||
|     return ! FspFileSystemAddDirInfo(DirInfo, dh->Buffer, dh->Length, dh->PBytesTransferred); |     if (GrowBuffer) | ||||||
|  |     { | ||||||
|  |         DirInfo->NextOffset = dh->BytesTransferred + FSP_FSCTL_DEFAULT_ALIGN_UP(DirInfo->Size); | ||||||
|  |  | ||||||
|  |         if (0 != dh->Buffer && | ||||||
|  |             FspFileSystemAddDirInfo(DirInfo, dh->Buffer, dh->Length, &dh->BytesTransferred)) | ||||||
|  |             return 0; | ||||||
|  |  | ||||||
|  |         if (0 == dh->Length) | ||||||
|  |             dh->Length = 8 * 1024; /* initial alloc: 16 == 8 * 2; see below */ | ||||||
|  |         else if (dh->Length >= 2 * 1024 * 1024) | ||||||
|  |             return 1; | ||||||
|  |  | ||||||
|  |         PVOID Buffer = MemAlloc(dh->Length * 2); | ||||||
|  |         if (0 == Buffer) | ||||||
|  |             return 1; | ||||||
|  |  | ||||||
|  |         memcpy(Buffer, dh->Buffer, dh->BytesTransferred); | ||||||
|  |         MemFree(dh->Buffer); | ||||||
|  |  | ||||||
|  |         dh->Buffer = Buffer; | ||||||
|  |         dh->Length *= 2; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     return ! FspFileSystemAddDirInfo(DirInfo, dh->Buffer, dh->Length, &dh->BytesTransferred); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | int fsp_fuse_intf_AddDirInfo(void *buf, const char *name, | ||||||
|  |     const struct fuse_stat *stbuf, fuse_off_t off) | ||||||
|  | { | ||||||
|  |     return fsp_fuse_intf_AddDirInfoCommon(buf, name, stbuf, off, TRUE); | ||||||
| } | } | ||||||
|  |  | ||||||
| int fsp_fuse_intf_AddDirInfoOld(fuse_dirh_t dh, const char *name, | int fsp_fuse_intf_AddDirInfoOld(fuse_dirh_t dh, const char *name, | ||||||
|     int type, fuse_ino_t ino) |     int type, fuse_ino_t ino) | ||||||
| { | { | ||||||
|     return fsp_fuse_intf_AddDirInfo(dh, name, 0, 0) ? -ENOMEM : 0; |     return fsp_fuse_intf_AddDirInfoCommon(dh, name, 0, 0, TRUE) ? -ENOMEM : 0; | ||||||
| } | } | ||||||
|  |  | ||||||
| static NTSTATUS fsp_fuse_intf_ReadDirectory(FSP_FILE_SYSTEM *FileSystem, | static NTSTATUS fsp_fuse_intf_ReadDirectory(FSP_FILE_SYSTEM *FileSystem, | ||||||
| @@ -797,55 +835,83 @@ static NTSTATUS fsp_fuse_intf_ReadDirectory(FSP_FILE_SYSTEM *FileSystem, | |||||||
|     PULONG PBytesTransferred) |     PULONG PBytesTransferred) | ||||||
| { | { | ||||||
|     struct fuse *f = FileSystem->UserContext; |     struct fuse *f = FileSystem->UserContext; | ||||||
|     struct fsp_fuse_file_desc *filedesc = (PVOID)(UINT_PTR)Request->Req.Close.UserContext2; |     struct fsp_fuse_file_desc *filedesc = | ||||||
|  |         (PVOID)(UINT_PTR)Request->Req.QueryDirectory.UserContext2; | ||||||
|  |     struct fuse_file_info fi; | ||||||
|     struct fuse_dirhandle dh; |     struct fuse_dirhandle dh; | ||||||
|  |     FSP_FSCTL_DIR_INFO *DirInfo; | ||||||
|  |     PUINT8 DirInfoEnd; | ||||||
|     ULONG Size; |     ULONG Size; | ||||||
|     int err; |     int err; | ||||||
|     NTSTATUS Result; |     NTSTATUS Result; | ||||||
|  |  | ||||||
|     memset(&dh, 0, sizeof dh); |     if (0 == filedesc->DirBuffer) | ||||||
|  |  | ||||||
|     Size = lstrlenA(filedesc->PosixPath); |  | ||||||
|     dh.PosixPath = MemAlloc(Size + 1 + 255 + 1); |  | ||||||
|     if (0 == dh.PosixPath) |  | ||||||
|     { |     { | ||||||
|         Result = STATUS_INSUFFICIENT_RESOURCES; |         memset(&dh, 0, sizeof dh); | ||||||
|         goto exit; |  | ||||||
|  |         Size = lstrlenA(filedesc->PosixPath); | ||||||
|  |         dh.PosixPath = MemAlloc(Size + 1 + 255 + 1); | ||||||
|  |         if (0 == dh.PosixPath) | ||||||
|  |         { | ||||||
|  |             Result = STATUS_INSUFFICIENT_RESOURCES; | ||||||
|  |             goto exit; | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         memcpy(dh.PosixPath, filedesc->PosixPath, Size); | ||||||
|  |         if (1 < Size) | ||||||
|  |             /* if not root */ | ||||||
|  |             dh.PosixPath[Size++] = '/'; | ||||||
|  |         dh.PosixName = dh.PosixPath + Size; | ||||||
|  |  | ||||||
|  |         if (0 != f->ops.readdir) | ||||||
|  |         { | ||||||
|  |             memset(&fi, 0, sizeof fi); | ||||||
|  |             fi.flags = filedesc->OpenFlags; | ||||||
|  |             fi.fh = filedesc->FileHandle; | ||||||
|  |  | ||||||
|  |             err = f->ops.readdir(filedesc->PosixPath, &dh, fsp_fuse_intf_AddDirInfo, 0, &fi); | ||||||
|  |             Result = fsp_fuse_ntstatus_from_errno(f->env, err); | ||||||
|  |         } | ||||||
|  |         else if (0 != f->ops.getdir) | ||||||
|  |         { | ||||||
|  |             err = f->ops.getdir(filedesc->PosixPath, &dh, fsp_fuse_intf_AddDirInfoOld); | ||||||
|  |             Result = fsp_fuse_ntstatus_from_errno(f->env, err); | ||||||
|  |         } | ||||||
|  |         else | ||||||
|  |             Result = STATUS_INVALID_DEVICE_REQUEST; | ||||||
|  |  | ||||||
|  |     exit: | ||||||
|  |         MemFree(dh.PosixPath); | ||||||
|  |  | ||||||
|  |         if (NT_SUCCESS(Result)) | ||||||
|  |         { | ||||||
|  |             filedesc->DirBuffer = dh.Buffer; | ||||||
|  |             filedesc->DirBufferSize = dh.BytesTransferred; | ||||||
|  |         } | ||||||
|  |         else | ||||||
|  |         { | ||||||
|  |             MemFree(dh.Buffer); | ||||||
|  |             return Result; | ||||||
|  |         } | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     memcpy(dh.PosixPath, filedesc->PosixPath, Size); |     DirInfo = (PVOID)((PUINT8)filedesc->DirBuffer + Offset); | ||||||
|     if (1 < Size) |     DirInfoEnd = (PUINT8)filedesc->DirBuffer + filedesc->DirBufferSize; | ||||||
|         /* if not root */ |     for (; | ||||||
|         dh.PosixPath[Size++] = '/'; |         (PUINT8)DirInfo + sizeof(DirInfo->Size) <= DirInfoEnd; | ||||||
|     dh.PosixName = dh.PosixPath + Size; |         DirInfo = (PVOID)((PUINT8)DirInfo + FSP_FSCTL_DEFAULT_ALIGN_UP(DirInfo->Size))) | ||||||
|  |  | ||||||
|     dh.Buffer = Buffer; |  | ||||||
|     dh.Length = Length; |  | ||||||
|     dh.PBytesTransferred = PBytesTransferred; |  | ||||||
|  |  | ||||||
|     if (0 != f->ops.readdir) |  | ||||||
|     { |     { | ||||||
|         struct fuse_file_info fi; |         if (sizeof(FSP_FSCTL_DIR_INFO) > DirInfo->Size) | ||||||
|  |             break; | ||||||
|  |  | ||||||
|         memset(&fi, 0, sizeof fi); |         if (!FspFileSystemAddDirInfo(DirInfo, Buffer, Length, PBytesTransferred)) | ||||||
|         fi.flags = filedesc->OpenFlags; |             break; | ||||||
|         fi.fh = filedesc->FileHandle; |  | ||||||
|  |  | ||||||
|         err = f->ops.readdir(filedesc->PosixPath, &dh, fsp_fuse_intf_AddDirInfo, Offset, &fi); |  | ||||||
|         Result = fsp_fuse_ntstatus_from_errno(f->env, err); |  | ||||||
|     } |     } | ||||||
|     else if (0 != f->ops.getdir) |  | ||||||
|     { |  | ||||||
|         err = f->ops.getdir(filedesc->PosixPath, &dh, fsp_fuse_intf_AddDirInfoOld); |  | ||||||
|         Result = fsp_fuse_ntstatus_from_errno(f->env, err); |  | ||||||
|     } |  | ||||||
|     else |  | ||||||
|         Result = STATUS_INVALID_DEVICE_REQUEST; |  | ||||||
|  |  | ||||||
| exit: |     if ((PUINT8)DirInfo + sizeof(DirInfo->Size) > DirInfoEnd) | ||||||
|     MemFree(dh.PosixPath); |         FspFileSystemAddDirInfo(0, Buffer, Length, PBytesTransferred); | ||||||
|  |  | ||||||
|     return Result; |     return STATUS_SUCCESS; | ||||||
| } | } | ||||||
|  |  | ||||||
| FSP_FILE_SYSTEM_INTERFACE fsp_fuse_intf = | FSP_FILE_SYSTEM_INTERFACE fsp_fuse_intf = | ||||||
|   | |||||||
| @@ -51,6 +51,8 @@ struct fsp_fuse_file_desc | |||||||
|     BOOLEAN IsDirectory; |     BOOLEAN IsDirectory; | ||||||
|     int OpenFlags; |     int OpenFlags; | ||||||
|     UINT64 FileHandle; |     UINT64 FileHandle; | ||||||
|  |     PVOID DirBuffer; | ||||||
|  |     ULONG DirBufferSize; | ||||||
| }; | }; | ||||||
|  |  | ||||||
| static inline | static inline | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user