mirror of
https://github.com/winfsp/winfsp.git
synced 2025-04-22 08:23:05 -05:00
tst: passthrough: ReadDirectory improvements
This commit is contained in:
parent
2ced698256
commit
a5f8736b1e
@ -38,6 +38,8 @@ typedef struct
|
||||
typedef struct
|
||||
{
|
||||
HANDLE Handle;
|
||||
PVOID DirBuffer;
|
||||
ULONG DirBufferCapacity, DirBufferLength;
|
||||
} PTFS_FILE_CONTEXT;
|
||||
|
||||
static NTSTATUS GetFileInfoInternal(HANDLE Handle, FSP_FSCTL_FILE_INFO *FileInfo)
|
||||
@ -165,6 +167,7 @@ static NTSTATUS Create(FSP_FILE_SYSTEM *FileSystem,
|
||||
FileContext = malloc(sizeof *FileContext);
|
||||
if (0 == FileContext)
|
||||
return STATUS_INSUFFICIENT_RESOURCES;
|
||||
memset(FileContext, 0, sizeof *FileContext);
|
||||
|
||||
SecurityAttributes.nLength = sizeof SecurityAttributes;
|
||||
SecurityAttributes.lpSecurityDescriptor = SecurityDescriptor;
|
||||
@ -220,6 +223,7 @@ static NTSTATUS Open(FSP_FILE_SYSTEM *FileSystem,
|
||||
FileContext = malloc(sizeof *FileContext);
|
||||
if (0 == FileContext)
|
||||
return STATUS_INSUFFICIENT_RESOURCES;
|
||||
memset(FileContext, 0, sizeof *FileContext);
|
||||
|
||||
CreateFlags = FILE_FLAG_BACKUP_SEMANTICS;
|
||||
if (CreateOptions & FILE_DELETE_ON_CLOSE)
|
||||
@ -298,6 +302,7 @@ static VOID Close(FSP_FILE_SYSTEM *FileSystem,
|
||||
|
||||
CloseHandle(Handle);
|
||||
|
||||
free(((PTFS_FILE_CONTEXT *)FileContext)->DirBuffer);
|
||||
free(FileContext);
|
||||
}
|
||||
|
||||
@ -502,12 +507,32 @@ static NTSTATUS SetSecurity(FSP_FILE_SYSTEM *FileSystem,
|
||||
return STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
static BOOLEAN AddDirInfo(PTFS_FILE_CONTEXT *FileContext, FSP_FSCTL_DIR_INFO *DirInfo)
|
||||
{
|
||||
while (!FspFileSystemAddDirInfo(DirInfo,
|
||||
FileContext->DirBuffer, FileContext->DirBufferCapacity, &FileContext->DirBufferLength))
|
||||
{
|
||||
PVOID Buffer;
|
||||
ULONG Capacity = FileContext->DirBufferCapacity ? FileContext->DirBufferCapacity * 2 : 256;
|
||||
|
||||
Buffer = realloc(FileContext->DirBuffer, Capacity);
|
||||
if (0 == Buffer)
|
||||
return FALSE;
|
||||
|
||||
FileContext->DirBuffer = Buffer;
|
||||
FileContext->DirBufferCapacity = Capacity;
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static NTSTATUS ReadDirectory(FSP_FILE_SYSTEM *FileSystem,
|
||||
PVOID FileContext, PVOID Buffer, UINT64 Offset, ULONG BufferLength,
|
||||
PVOID FileContext0, PVOID Buffer, UINT64 Offset, ULONG BufferLength,
|
||||
PWSTR Pattern,
|
||||
PULONG PBytesTransferred)
|
||||
{
|
||||
PTFS *Ptfs = (PTFS *)FileSystem->UserContext;
|
||||
PTFS_FILE_CONTEXT *FileContext = FileContext0;
|
||||
HANDLE Handle = HandleFromContext(FileContext);
|
||||
WCHAR FullPath[FULLPATH_SIZE];
|
||||
ULONG Length, PatternLength;
|
||||
@ -521,87 +546,70 @@ static NTSTATUS ReadDirectory(FSP_FILE_SYSTEM *FileSystem,
|
||||
FSP_FSCTL_DIR_INFO *DirInfo = &DirInfoBuf.D;
|
||||
UINT64 NextOffset = 0;
|
||||
|
||||
if (0 == Pattern)
|
||||
Pattern = L"*";
|
||||
PatternLength = (ULONG)wcslen(Pattern);
|
||||
|
||||
Length = GetFinalPathNameByHandleW(Handle, FullPath, FULLPATH_SIZE - 1, 0);
|
||||
if (0 == Length)
|
||||
return FspNtStatusFromWin32(GetLastError());
|
||||
if (Length + 1 + PatternLength >= FULLPATH_SIZE)
|
||||
return STATUS_OBJECT_NAME_INVALID;
|
||||
|
||||
if (L'\\' != FullPath[Length - 1])
|
||||
FullPath[Length++] = L'\\';
|
||||
memcpy(FullPath + Length, Pattern, PatternLength * sizeof(WCHAR));
|
||||
FullPath[Length + PatternLength] = L'\0';
|
||||
|
||||
FindHandle = FindFirstFileW(FullPath, &FindData);
|
||||
if (INVALID_HANDLE_VALUE == FindHandle)
|
||||
if (0 == Offset)
|
||||
{
|
||||
/* add "End-Of-Listing" marker */
|
||||
FspFileSystemAddDirInfo(0, Buffer, BufferLength, PBytesTransferred);
|
||||
return STATUS_SUCCESS;
|
||||
if (0 == Pattern)
|
||||
Pattern = L"*";
|
||||
PatternLength = (ULONG)wcslen(Pattern);
|
||||
|
||||
Length = GetFinalPathNameByHandleW(Handle, FullPath, FULLPATH_SIZE - 1, 0);
|
||||
if (0 == Length)
|
||||
return FspNtStatusFromWin32(GetLastError());
|
||||
if (Length + 1 + PatternLength >= FULLPATH_SIZE)
|
||||
return STATUS_OBJECT_NAME_INVALID;
|
||||
|
||||
if (L'\\' != FullPath[Length - 1])
|
||||
FullPath[Length++] = L'\\';
|
||||
memcpy(FullPath + Length, Pattern, PatternLength * sizeof(WCHAR));
|
||||
FullPath[Length + PatternLength] = L'\0';
|
||||
|
||||
FindHandle = FindFirstFileW(FullPath, &FindData);
|
||||
if (INVALID_HANDLE_VALUE != FindHandle)
|
||||
{
|
||||
do
|
||||
{
|
||||
memset(DirInfo, 0, sizeof *DirInfo);
|
||||
Length = (ULONG)wcslen(FindData.cFileName);
|
||||
DirInfo->Size = (UINT16)(FIELD_OFFSET(FSP_FSCTL_DIR_INFO, FileNameBuf) + Length * sizeof(WCHAR));
|
||||
DirInfo->FileInfo.FileAttributes = FindData.dwFileAttributes;
|
||||
DirInfo->FileInfo.ReparseTag = 0;
|
||||
DirInfo->FileInfo.FileSize =
|
||||
((UINT64)FindData.nFileSizeHigh << 32) | (UINT64)FindData.nFileSizeLow;
|
||||
DirInfo->FileInfo.AllocationSize = (DirInfo->FileInfo.FileSize + ALLOCATION_UNIT - 1)
|
||||
/ ALLOCATION_UNIT * ALLOCATION_UNIT;
|
||||
DirInfo->FileInfo.CreationTime = ((PLARGE_INTEGER)&FindData.ftCreationTime)->QuadPart;
|
||||
DirInfo->FileInfo.LastAccessTime = ((PLARGE_INTEGER)&FindData.ftLastAccessTime)->QuadPart;
|
||||
DirInfo->FileInfo.LastWriteTime = ((PLARGE_INTEGER)&FindData.ftLastWriteTime)->QuadPart;
|
||||
DirInfo->FileInfo.ChangeTime = DirInfo->FileInfo.LastWriteTime;
|
||||
DirInfo->FileInfo.IndexNumber = 0;
|
||||
DirInfo->FileInfo.HardLinks = 0;
|
||||
DirInfo->NextOffset = (NextOffset += FSP_FSCTL_DEFAULT_ALIGN_UP(DirInfo->Size));
|
||||
memcpy(DirInfo->FileNameBuf, FindData.cFileName, Length * sizeof(WCHAR));
|
||||
|
||||
if (!AddDirInfo(FileContext, DirInfo))
|
||||
break;
|
||||
} while (FindNextFileW(FindHandle, &FindData));
|
||||
|
||||
FindClose(FindHandle);
|
||||
|
||||
if (!AddDirInfo(FileContext, 0))
|
||||
return STATUS_INSUFFICIENT_RESOURCES;
|
||||
}
|
||||
}
|
||||
|
||||
for (;;)
|
||||
if (0 != FileContext->DirBuffer)
|
||||
{
|
||||
/*
|
||||
* NOTE: The root directory does not have the dot (".", "..") entries
|
||||
* under Windows. This sample file system always adds them regardless.
|
||||
*/
|
||||
|
||||
/*
|
||||
* The simple conditional `Offset <= NextOffset++` only works when files
|
||||
* are not created/deleted in the directory while it is being read.
|
||||
* This is perhaps ok for this sample file system, but a "real" file
|
||||
* system would probably have to handle this better.
|
||||
*
|
||||
* The best approach for a file system is to use directory offsets that
|
||||
* do not change when files are created/deleted. If this is not possible
|
||||
* it is also acceptable to have directory offsets that do not change
|
||||
* for as long as the directory remains open.
|
||||
*
|
||||
* The easiest method to achieve this is to buffer all directory contents
|
||||
* in a call to ReadDirectory with Offset == 0 and then return offsets
|
||||
* within the directory content buffer. Subsequent ReadDirectory operations
|
||||
* return directory contents directly from the buffer.
|
||||
*/
|
||||
|
||||
if (Offset <= NextOffset++)
|
||||
for (DirInfo = (PVOID)((PUINT8)FileContext->DirBuffer + Offset);
|
||||
0 != DirInfo->Size;
|
||||
DirInfo = (PVOID)((PUINT8)DirInfo + FSP_FSCTL_DEFAULT_ALIGN_UP(DirInfo->Size)))
|
||||
{
|
||||
memset(DirInfo, 0, sizeof *DirInfo);
|
||||
Length = (ULONG)wcslen(FindData.cFileName);
|
||||
DirInfo->Size = (UINT16)(FIELD_OFFSET(FSP_FSCTL_DIR_INFO, FileNameBuf) + Length * sizeof(WCHAR));
|
||||
DirInfo->FileInfo.FileAttributes = FindData.dwFileAttributes;
|
||||
DirInfo->FileInfo.ReparseTag = 0;
|
||||
DirInfo->FileInfo.FileSize =
|
||||
((UINT64)FindData.nFileSizeHigh << 32) | (UINT64)FindData.nFileSizeLow;
|
||||
DirInfo->FileInfo.AllocationSize = (DirInfo->FileInfo.FileSize + ALLOCATION_UNIT - 1)
|
||||
/ ALLOCATION_UNIT * ALLOCATION_UNIT;
|
||||
DirInfo->FileInfo.CreationTime = ((PLARGE_INTEGER)&FindData.ftCreationTime)->QuadPart;
|
||||
DirInfo->FileInfo.LastAccessTime = ((PLARGE_INTEGER)&FindData.ftLastAccessTime)->QuadPart;
|
||||
DirInfo->FileInfo.LastWriteTime = ((PLARGE_INTEGER)&FindData.ftLastWriteTime)->QuadPart;
|
||||
DirInfo->FileInfo.ChangeTime = DirInfo->FileInfo.LastWriteTime;
|
||||
DirInfo->FileInfo.IndexNumber = 0;
|
||||
DirInfo->FileInfo.HardLinks = 0;
|
||||
DirInfo->NextOffset = NextOffset;
|
||||
memcpy(DirInfo->FileNameBuf, FindData.cFileName, Length * sizeof(WCHAR));
|
||||
|
||||
if (!FspFileSystemAddDirInfo(DirInfo, Buffer, BufferLength, PBytesTransferred))
|
||||
break;
|
||||
}
|
||||
|
||||
if (!FindNextFileW(FindHandle, &FindData))
|
||||
{
|
||||
/* add "End-Of-Listing" marker */
|
||||
FspFileSystemAddDirInfo(0, Buffer, BufferLength, PBytesTransferred);
|
||||
break;
|
||||
return STATUS_SUCCESS;
|
||||
}
|
||||
}
|
||||
|
||||
FindClose(FindHandle);
|
||||
|
||||
/* add "End-Of-Listing" marker */
|
||||
FspFileSystemAddDirInfo(0, Buffer, BufferLength, PBytesTransferred);
|
||||
return STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user