mirror of
				https://github.com/winfsp/winfsp.git
				synced 2025-10-30 19:48:38 -05:00 
			
		
		
		
	dll: fuse: reimplement ReadDirectory
This commit is contained in:
		| @@ -882,7 +882,6 @@ static NTSTATUS fsp_fuse_intf_Create(FSP_FILE_SYSTEM *FileSystem, | ||||
|     filedesc->OpenFlags = fi.flags; | ||||
|     filedesc->FileHandle = fi.fh; | ||||
|     filedesc->DirBuffer = 0; | ||||
|     filedesc->DirBufferSize = 0; | ||||
|     contexthdr->PosixPath = 0; | ||||
|  | ||||
|     Result = STATUS_SUCCESS; | ||||
| @@ -1000,7 +999,6 @@ static NTSTATUS fsp_fuse_intf_Open(FSP_FILE_SYSTEM *FileSystem, | ||||
|     filedesc->OpenFlags = fi.flags; | ||||
|     filedesc->FileHandle = fi.fh; | ||||
|     filedesc->DirBuffer = 0; | ||||
|     filedesc->DirBufferSize = 0; | ||||
|     contexthdr->PosixPath = 0; | ||||
|  | ||||
|     Result = STATUS_SUCCESS; | ||||
| @@ -1113,7 +1111,7 @@ static VOID fsp_fuse_intf_Close(FSP_FILE_SYSTEM *FileSystem, | ||||
|             f->ops.release(filedesc->PosixPath, &fi); | ||||
|     } | ||||
|  | ||||
|     MemFree(filedesc->DirBuffer); | ||||
|     FspFileSystemDeleteDirectoryBuffer(&filedesc->DirBuffer); | ||||
|     MemFree(filedesc->PosixPath); | ||||
|     MemFree(filedesc); | ||||
| } | ||||
| @@ -1603,102 +1601,157 @@ exit: | ||||
|     return Result; | ||||
| } | ||||
|  | ||||
| int fsp_fuse_intf_AddDirInfo(void *buf, const char *name, | ||||
| static int fsp_fuse_intf_AddDirInfo(void *buf, const char *name, | ||||
|     const struct fuse_stat *stbuf, fuse_off_t off) | ||||
| { | ||||
|     struct fuse_dirhandle *dh = buf; | ||||
|     struct fsp_fuse_dirinfo *di; | ||||
|     ULONG len, xfersize; | ||||
|  | ||||
|     len = lstrlenA(name); | ||||
|     if (len > 255) | ||||
|         len = 255; | ||||
|  | ||||
|     di = (PVOID)((PUINT8)dh->Buffer + dh->BytesTransferred); | ||||
|     xfersize = FSP_FSCTL_DEFAULT_ALIGN_UP(sizeof(struct fsp_fuse_dirinfo) + len + 1); | ||||
|  | ||||
|     if ((PUINT8)di + xfersize > (PUINT8)dh->Buffer + dh->Length) | ||||
|     { | ||||
|         PVOID Buffer; | ||||
|         ULONG Length = dh->Length; | ||||
|  | ||||
|         if (0 == Length) | ||||
|             Length = 16 * 1024; | ||||
|         else if (Length < 16 * 1024 * 1024) | ||||
|             Length *= 2; | ||||
|         else | ||||
|             return 1; | ||||
|  | ||||
|         Buffer = MemAlloc(Length); | ||||
|         if (0 == Buffer) | ||||
|             return 1; | ||||
|  | ||||
|         memcpy(Buffer, dh->Buffer, dh->BytesTransferred); | ||||
|         MemFree(dh->Buffer); | ||||
|  | ||||
|         dh->Buffer = Buffer; | ||||
|         dh->Length = Length; | ||||
|  | ||||
|         di = (PVOID)((PUINT8)dh->Buffer + dh->BytesTransferred); | ||||
|     } | ||||
|  | ||||
|     dh->BytesTransferred += xfersize; | ||||
|     dh->NonZeroOffset = dh->NonZeroOffset || 0 != off; | ||||
|  | ||||
|     di->Size = (UINT16)(sizeof(struct fsp_fuse_dirinfo) + len + 1); | ||||
|     di->FileInfoValid = FALSE; | ||||
|     di->NextOffset = 0 != off ? off : dh->BytesTransferred; | ||||
|     memcpy(di->PosixNameBuf, name, len); | ||||
|     di->PosixNameBuf[len] = '\0'; | ||||
|  | ||||
|     return 0; | ||||
| } | ||||
|  | ||||
| int fsp_fuse_intf_AddDirInfoOld(fuse_dirh_t dh, const char *name, | ||||
|     int type, fuse_ino_t ino) | ||||
| { | ||||
|     return fsp_fuse_intf_AddDirInfo(dh, name, 0, 0) ? -ENOMEM : 0; | ||||
| } | ||||
|  | ||||
| static NTSTATUS fsp_fuse_intf_ReadDirectory(FSP_FILE_SYSTEM *FileSystem, | ||||
|     PVOID FileContext, PWSTR Pattern, PWSTR Marker, | ||||
|     PVOID Buffer, ULONG Length, PULONG PBytesTransferred) | ||||
| { | ||||
|     return STATUS_INVALID_DEVICE_REQUEST; | ||||
| #if 0 | ||||
|     struct fuse *f = FileSystem->UserContext; | ||||
|     struct fsp_fuse_file_desc *filedesc = FileNode; | ||||
|     struct fuse_file_info fi; | ||||
|     struct fuse_dirhandle dh; | ||||
|     struct fsp_fuse_dirinfo *di; | ||||
|     PUINT8 diend; | ||||
|     struct fsp_fuse_file_desc *filedesc = dh->filedesc; | ||||
|     union | ||||
|     { | ||||
|         FSP_FSCTL_DIR_INFO V; | ||||
|         UINT8 B[sizeof(FSP_FSCTL_DIR_INFO) + 255 * sizeof(WCHAR)]; | ||||
|     } DirInfoBuf; | ||||
|     FSP_FSCTL_DIR_INFO *DirInfo = &DirInfoBuf.V; | ||||
|     UINT32 Uid, Gid, Mode; | ||||
|     ULONG SizeA, SizeW; | ||||
|  | ||||
|     if ('/' == filedesc->PosixPath[0] && '\0' == filedesc->PosixPath[1]) | ||||
|     { | ||||
|         /* if this is the root directory do not add the dot entries */ | ||||
|  | ||||
|         if ('.' == name[0] && ('\0' == name[1] || | ||||
|             ('.' == name[1] && '\0' == name[2]))) | ||||
|             return 0; | ||||
|     } | ||||
|  | ||||
|     SizeA = lstrlenA(name); | ||||
|     if (SizeA > 255) | ||||
|         /* ignore bad filenames; should we return error code? */ | ||||
|         return 0; | ||||
|  | ||||
|     SizeW = MultiByteToWideChar(CP_UTF8, 0, name, SizeA, DirInfo->FileNameBuf, 255); | ||||
|     if (0 == SizeW) | ||||
|         /* ignore bad filenames; should we return error code? */ | ||||
|         return 0; | ||||
|  | ||||
|     memset(DirInfo, 0, sizeof *DirInfo); | ||||
|     DirInfo->Size = (UINT16)(sizeof(FSP_FSCTL_DIR_INFO) + SizeW * sizeof(WCHAR)); | ||||
|  | ||||
|     return !FspFileSystemFillDirectoryBuffer(&filedesc->DirBuffer, DirInfo, &dh->Result); | ||||
| } | ||||
|  | ||||
| static int fsp_fuse_intf_AddDirInfoOld(fuse_dirh_t dh, const char *name, | ||||
|     int type, fuse_ino_t ino) | ||||
| { | ||||
|     return fsp_fuse_intf_AddDirInfo(dh, name, 0, 0) ? -ENOMEM : 0; | ||||
| } | ||||
|  | ||||
| static NTSTATUS fsp_fuse_intf_FixDirInfo(FSP_FILE_SYSTEM *FileSystem, | ||||
|     struct fsp_fuse_file_desc *filedesc) | ||||
| { | ||||
|     char *PosixPath = 0, *PosixName, *PosixPathEnd, SavedPathChar; | ||||
|     PWSTR FileName = 0; | ||||
|     ULONG Size; | ||||
|     ULONG SizeA, SizeW; | ||||
|     PUINT8 Buffer; | ||||
|     PULONG Index, IndexEnd; | ||||
|     ULONG Count; | ||||
|     FSP_FSCTL_DIR_INFO *DirInfo; | ||||
|     UINT32 Uid, Gid, Mode; | ||||
|     NTSTATUS Result; | ||||
|  | ||||
|     SizeA = lstrlenA(filedesc->PosixPath); | ||||
|     PosixPath = MemAlloc(SizeA + 1 + 255 + 1); | ||||
|     if (0 == PosixPath) | ||||
|     { | ||||
|         Result = STATUS_INSUFFICIENT_RESOURCES; | ||||
|         goto exit; | ||||
|     } | ||||
|  | ||||
|     memcpy(PosixPath, filedesc->PosixPath, SizeA); | ||||
|     if (1 < SizeA) | ||||
|         /* if not root */ | ||||
|         PosixPath[SizeA++] = '/'; | ||||
|     PosixPath[SizeA] = '\0'; | ||||
|     PosixName = PosixPath + SizeA; | ||||
|  | ||||
|     FspFileSystemPeekInDirectoryBuffer(&filedesc->DirBuffer, &Buffer, &Index, &Count); | ||||
|  | ||||
|     for (IndexEnd = Index + Count; IndexEnd > Index; Index++) | ||||
|     { | ||||
|         DirInfo = (FSP_FSCTL_DIR_INFO *)(Buffer + *Index); | ||||
|         SizeW = (DirInfo->Size - sizeof *DirInfo) / sizeof(WCHAR); | ||||
|  | ||||
|         if (1 == SizeW && L'.' == DirInfo->FileNameBuf[0]) | ||||
|         { | ||||
|             PosixPathEnd = 1 < PosixName - PosixPath ? PosixName - 1 : PosixName; | ||||
|             SavedPathChar = *PosixPathEnd; | ||||
|             *PosixPathEnd = '\0'; | ||||
|         } | ||||
|         else | ||||
|         if (2 == SizeW && L'.' == DirInfo->FileNameBuf[0] && L'.' == DirInfo->FileNameBuf[1]) | ||||
|         { | ||||
|             PosixPathEnd = 1 < PosixName - PosixPath ? PosixName - 2 : PosixName; | ||||
|             while (PosixPath < PosixPathEnd && '/' != *PosixPathEnd) | ||||
|                 PosixPathEnd--; | ||||
|             if (PosixPath == PosixPathEnd) | ||||
|                 PosixPathEnd++; | ||||
|             SavedPathChar = *PosixPathEnd; | ||||
|             *PosixPathEnd = '\0'; | ||||
|         } | ||||
|         else | ||||
|         { | ||||
|             PosixPathEnd = 0; | ||||
|             SizeA = WideCharToMultiByte(CP_UTF8, 0, DirInfo->FileNameBuf, SizeW, PosixName, 255, 0, 0); | ||||
|             if (0 == SizeA) | ||||
|             { | ||||
|                 /* this should never happen because we just converted using MultiByteToWideChar */ | ||||
|                 Result = STATUS_OBJECT_NAME_INVALID; | ||||
|                 goto exit; | ||||
|             } | ||||
|             PosixName[SizeA] = '\0'; | ||||
|         } | ||||
|  | ||||
|         Result = fsp_fuse_intf_GetFileInfoEx(FileSystem, PosixPath, 0, | ||||
|             &Uid, &Gid, &Mode, &DirInfo->FileInfo); | ||||
|         if (!NT_SUCCESS(Result)) | ||||
|             goto exit; | ||||
|  | ||||
|         if (0 != PosixPathEnd) | ||||
|             *PosixPathEnd = SavedPathChar; | ||||
|  | ||||
|         FspPosixDecodeWindowsPath(DirInfo->FileNameBuf, SizeW); | ||||
|     } | ||||
|  | ||||
|     Result = STATUS_SUCCESS; | ||||
|  | ||||
| exit: | ||||
|     MemFree(PosixPath); | ||||
|  | ||||
|     return Result; | ||||
| } | ||||
|  | ||||
| static NTSTATUS fsp_fuse_intf_ReadDirectory(FSP_FILE_SYSTEM *FileSystem, | ||||
|     PVOID FileNode, PWSTR Pattern, PWSTR Marker, | ||||
|     PVOID Buffer, ULONG Length, PULONG PBytesTransferred) | ||||
| { | ||||
|     struct fuse *f = FileSystem->UserContext; | ||||
|     struct fsp_fuse_file_desc *filedesc = FileNode; | ||||
|     struct fuse_dirhandle dh; | ||||
|     struct fuse_file_info fi; | ||||
|     int err; | ||||
|     NTSTATUS Result; | ||||
|  | ||||
|     if (!filedesc->IsDirectory) | ||||
|         return STATUS_ACCESS_DENIED; | ||||
|  | ||||
|     memset(&dh, 0, sizeof dh); | ||||
|  | ||||
|     if (0 == filedesc->DirBuffer) | ||||
|     if (FspFileSystemAcquireDirectoryBuffer(&filedesc->DirBuffer, 0 == Marker, &Result)) | ||||
|     { | ||||
|         memset(&dh, 0, sizeof dh); | ||||
|         dh.filedesc = filedesc; | ||||
|         dh.Result = STATUS_SUCCESS; | ||||
|  | ||||
|         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, Offset, &fi); | ||||
|             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) | ||||
| @@ -1709,143 +1762,23 @@ static NTSTATUS fsp_fuse_intf_ReadDirectory(FSP_FILE_SYSTEM *FileSystem, | ||||
|         else | ||||
|             Result = STATUS_INVALID_DEVICE_REQUEST; | ||||
|  | ||||
|         if (!NT_SUCCESS(Result)) | ||||
|             goto exit; | ||||
|         if (NT_SUCCESS(Result)) | ||||
|         { | ||||
|             Result = dh.Result; | ||||
|             if (NT_SUCCESS(Result)) | ||||
|                 Result = fsp_fuse_intf_FixDirInfo(FileSystem, filedesc); | ||||
|         } | ||||
|  | ||||
|         if (0 == dh.BytesTransferred) | ||||
|         { | ||||
|             /* EOF */ | ||||
|             *PBytesTransferred = 0; | ||||
|             FspFileSystemAddDirInfo(0, Buffer, Length, PBytesTransferred); | ||||
|             goto success; | ||||
|         } | ||||
|         else if (dh.NonZeroOffset) | ||||
|         { | ||||
|             di = (PVOID)((PUINT8)dh.Buffer + 0); | ||||
|             diend = (PUINT8)dh.Buffer + dh.BytesTransferred; | ||||
|         } | ||||
|         else | ||||
|         { | ||||
|             di = (PVOID)((PUINT8)dh.Buffer + Offset); | ||||
|             diend = (PUINT8)dh.Buffer + dh.BytesTransferred; | ||||
|             filedesc->DirBuffer = dh.Buffer; | ||||
|             filedesc->DirBufferSize = dh.BytesTransferred; | ||||
|             dh.Buffer = 0; | ||||
|         } | ||||
|     } | ||||
|     else | ||||
|     { | ||||
|         di = (PVOID)((PUINT8)filedesc->DirBuffer + Offset); | ||||
|         diend = (PUINT8)filedesc->DirBuffer + filedesc->DirBufferSize; | ||||
|         FspFileSystemReleaseDirectoryBuffer(&filedesc->DirBuffer); | ||||
|     } | ||||
|  | ||||
|     for (; | ||||
|         (PUINT8)di + sizeof(di->Size) <= diend; | ||||
|         di = (PVOID)((PUINT8)di + FSP_FSCTL_DEFAULT_ALIGN_UP(di->Size))) | ||||
|     { | ||||
|         if (sizeof(struct fsp_fuse_dirinfo) > di->Size) | ||||
|             break; | ||||
|     if (!NT_SUCCESS(Result)) | ||||
|         return Result; | ||||
|  | ||||
|         if ('/' == filedesc->PosixPath[0] && '\0' == filedesc->PosixPath[1]) | ||||
|         { | ||||
|             /* if this is the root directory do not add the dot entries */ | ||||
|     FspFileSystemReadDirectoryBuffer(&filedesc->DirBuffer, | ||||
|         Marker, Buffer, Length, PBytesTransferred); | ||||
|  | ||||
|             if ('.' == di->PosixNameBuf[0] && ('\0' == di->PosixNameBuf[1] || | ||||
|                 ('.' == di->PosixNameBuf[1] && '\0' == di->PosixNameBuf[2]))) | ||||
|                 continue; | ||||
|         } | ||||
|  | ||||
|         if (!di->FileInfoValid) | ||||
|         { | ||||
|             if (0 == PosixPath) | ||||
|             { | ||||
|                 Size = lstrlenA(filedesc->PosixPath); | ||||
|                 PosixPath = MemAlloc(Size + 1 + 255 + 1); | ||||
|                 if (0 == PosixPath) | ||||
|                 { | ||||
|                     Result = STATUS_INSUFFICIENT_RESOURCES; | ||||
|                     goto exit; | ||||
|                 } | ||||
|  | ||||
|                 memcpy(PosixPath, filedesc->PosixPath, Size); | ||||
|                 if (1 < Size) | ||||
|                     /* if not root */ | ||||
|                     PosixPath[Size++] = '/'; | ||||
|                 PosixPath[Size] = '\0'; | ||||
|                 PosixName = PosixPath + Size; | ||||
|             } | ||||
|  | ||||
|             if ('.' == di->PosixNameBuf[0] && '\0' == di->PosixNameBuf[1]) | ||||
|             { | ||||
|                 PosixPathEnd = 1 < PosixName - PosixPath ? PosixName - 1 : PosixName; | ||||
|                 SavedPathChar = *PosixPathEnd; | ||||
|                 *PosixPathEnd = '\0'; | ||||
|             } | ||||
|             else | ||||
|             if ('.' == di->PosixNameBuf[0] && '.' == di->PosixNameBuf[1] && '\0' == di->PosixNameBuf[2]) | ||||
|             { | ||||
|                 PosixPathEnd = 1 < PosixName - PosixPath ? PosixName - 2 : PosixName; | ||||
|                 while (PosixPath < PosixPathEnd && '/' != *PosixPathEnd) | ||||
|                     PosixPathEnd--; | ||||
|                 if (PosixPath == PosixPathEnd) | ||||
|                     PosixPathEnd++; | ||||
|                 SavedPathChar = *PosixPathEnd; | ||||
|                 *PosixPathEnd = '\0'; | ||||
|             } | ||||
|             else | ||||
|             { | ||||
|                 PosixPathEnd = 0; | ||||
|                 Size = lstrlenA(di->PosixNameBuf); | ||||
|                 if (Size > 255) | ||||
|                     Size = 255; | ||||
|                 memcpy(PosixName, di->PosixNameBuf, Size); | ||||
|                 PosixName[Size] = '\0'; | ||||
|             } | ||||
|  | ||||
|             Result = fsp_fuse_intf_GetFileInfoEx(FileSystem, PosixPath, 0, | ||||
|                 &Uid, &Gid, &Mode, &di->FileInfo); | ||||
|             if (!NT_SUCCESS(Result)) | ||||
|                 goto exit; | ||||
|  | ||||
|             if (0 != PosixPathEnd) | ||||
|                 *PosixPathEnd = SavedPathChar; | ||||
|  | ||||
|             di->FileInfoValid = TRUE; | ||||
|         } | ||||
|         memcpy(&DirInfo->FileInfo, &di->FileInfo, sizeof di->FileInfo); | ||||
|  | ||||
|         Result = FspPosixMapPosixToWindowsPath(di->PosixNameBuf, &FileName); | ||||
|         if (!NT_SUCCESS(Result)) | ||||
|             goto exit; | ||||
|  | ||||
|         Size = lstrlenW(FileName); | ||||
|         if (Size > 255) | ||||
|             Size = 255; | ||||
|         Size *= sizeof(WCHAR); | ||||
|         memcpy(DirInfo->FileNameBuf, FileName, Size); | ||||
|  | ||||
|         FspPosixDeletePath(FileName); | ||||
|  | ||||
|         memset(DirInfo->Padding, 0, sizeof DirInfo->Padding); | ||||
|         DirInfo->Size = (UINT16)(sizeof(FSP_FSCTL_DIR_INFO) + Size); | ||||
|         DirInfo->NextOffset = di->NextOffset; | ||||
|  | ||||
|         if (!FspFileSystemAddDirInfo(DirInfo, Buffer, Length, PBytesTransferred)) | ||||
|             break; | ||||
|     } | ||||
|  | ||||
|     if ((PUINT8)di + sizeof(di->Size) > diend) | ||||
|         FspFileSystemAddDirInfo(0, Buffer, Length, PBytesTransferred); | ||||
|  | ||||
| success: | ||||
|     Result = STATUS_SUCCESS; | ||||
|  | ||||
| exit: | ||||
|     MemFree(PosixPath); | ||||
|     MemFree(dh.Buffer); | ||||
|  | ||||
|     return Result; | ||||
| #endif | ||||
|     return STATUS_SUCCESS; | ||||
| } | ||||
|  | ||||
| static NTSTATUS fsp_fuse_intf_ResolveReparsePoints(FSP_FILE_SYSTEM *FileSystem, | ||||
|   | ||||
| @@ -62,27 +62,15 @@ struct fsp_fuse_file_desc | ||||
|     int OpenFlags; | ||||
|     UINT64 FileHandle; | ||||
|     PVOID DirBuffer; | ||||
|     ULONG DirBufferSize; | ||||
| }; | ||||
|  | ||||
| struct fuse_dirhandle | ||||
| { | ||||
|     PVOID Buffer; | ||||
|     ULONG Length; | ||||
|     ULONG BytesTransferred; | ||||
|     BOOLEAN NonZeroOffset; | ||||
|     struct fsp_fuse_file_desc *filedesc; | ||||
|     NTSTATUS Result; | ||||
|     BOOLEAN DotFiles, HasChild; | ||||
| }; | ||||
|  | ||||
| struct fsp_fuse_dirinfo | ||||
| { | ||||
|     UINT16 Size; | ||||
|     FSP_FSCTL_FILE_INFO FileInfo; | ||||
|     BOOLEAN FileInfoValid; | ||||
|     UINT64 NextOffset; | ||||
|     char PosixNameBuf[];                /* includes term-0 (unlike FSP_FSCTL_DIR_INFO) */ | ||||
| }; | ||||
|  | ||||
| NTSTATUS fsp_fuse_op_enter(FSP_FILE_SYSTEM *FileSystem, | ||||
|     FSP_FSCTL_TRANSACT_REQ *Request, FSP_FSCTL_TRANSACT_RSP *Response); | ||||
| NTSTATUS fsp_fuse_op_leave(FSP_FILE_SYSTEM *FileSystem, | ||||
|   | ||||
		Reference in New Issue
	
	Block a user