Compare commits

..

5 Commits
GPLv3 ... v0.17

11 changed files with 471 additions and 44 deletions

View File

@ -602,9 +602,97 @@ static NTSTATUS FspFileSystemOpCreate_FileOpenTargetDirectory(FSP_FILE_SYSTEM *F
return STATUS_SUCCESS;
}
static NTSTATUS FspFileSystemOpCreate_NotFoundCheck(FSP_FILE_SYSTEM *FileSystem,
FSP_FSCTL_TRANSACT_REQ *Request, FSP_FSCTL_TRANSACT_RSP *Response)
{
/*
* This handles an Open of a named stream done via a symlink. The file system
* has returned STATUS_OBJECT_NAME_NOT_FOUND, but we check to see if the main
* file is a reparse point that can be resolved.
*/
NTSTATUS Result;
UINT32 FileAttributes;
if (0 == FileSystem->Interface->GetSecurityByName ||
0 == FileSystem->Interface->ResolveReparsePoints)
return STATUS_OBJECT_NAME_NOT_FOUND;
if (!Request->Req.Create.NamedStream ||
(Request->Req.Create.CreateOptions & FILE_OPEN_REPARSE_POINT))
return STATUS_OBJECT_NAME_NOT_FOUND;
((PWSTR)Request->Buffer)[Request->Req.Create.NamedStream / sizeof(WCHAR)] = L'\0';
Result = FileSystem->Interface->GetSecurityByName(
FileSystem, (PWSTR)Request->Buffer, &FileAttributes, 0, 0);
((PWSTR)Request->Buffer)[Request->Req.Create.NamedStream / sizeof(WCHAR)] = L':';
if (STATUS_SUCCESS != Result)
return STATUS_OBJECT_NAME_NOT_FOUND;
if (0 == (FileAttributes & FILE_ATTRIBUTE_REPARSE_POINT))
return STATUS_OBJECT_NAME_NOT_FOUND;
FileAttributes = FspPathSuffixIndex((PWSTR)Request->Buffer);
Result = FspFileSystemCallResolveReparsePoints(
FileSystem, Request, Response, FileAttributes);
if (STATUS_REPARSE != Result)
return STATUS_OBJECT_NAME_NOT_FOUND;
return STATUS_REPARSE;
}
static NTSTATUS FspFileSystemOpCreate_CollisionCheck(FSP_FILE_SYSTEM *FileSystem,
FSP_FSCTL_TRANSACT_REQ *Request, FSP_FSCTL_TRANSACT_RSP *Response)
{
/*
* This handles a Create that resulted in STATUS_OBJECT_NAME_COLLISION. We
* handle two separate cases:
*
* 1) A Create colliding with a directory and the FILE_NON_DIRECTORY_FILE
* flag set. We then change the result code to STATUS_FILE_IS_A_DIRECTORY.
*
* 2) A Create colliding with a symlink (reparse point) that can be resolved.
* In this case we resolve the reparse point and return STATUS_REPARSE.
*/
NTSTATUS Result;
UINT32 FileAttributes;
if (0 == FileSystem->Interface->GetSecurityByName)
return STATUS_OBJECT_NAME_COLLISION;
Result = FileSystem->Interface->GetSecurityByName(
FileSystem, (PWSTR)Request->Buffer, &FileAttributes, 0, 0);
if (STATUS_SUCCESS != Result)
return STATUS_OBJECT_NAME_COLLISION;
if ((Request->Req.Create.CreateOptions & FILE_NON_DIRECTORY_FILE) &&
(FileAttributes & FILE_ATTRIBUTE_DIRECTORY))
return STATUS_FILE_IS_A_DIRECTORY;
if (0 == FileSystem->Interface->ResolveReparsePoints)
return STATUS_OBJECT_NAME_COLLISION;
if (Request->Req.Create.CreateOptions & FILE_OPEN_REPARSE_POINT)
return STATUS_OBJECT_NAME_COLLISION;
if (0 == (FileAttributes & FILE_ATTRIBUTE_REPARSE_POINT))
return STATUS_OBJECT_NAME_COLLISION;
FileAttributes = FspPathSuffixIndex((PWSTR)Request->Buffer);
Result = FspFileSystemCallResolveReparsePoints(
FileSystem, Request, Response, FileAttributes);
if (STATUS_REPARSE != Result)
return STATUS_OBJECT_NAME_COLLISION;
return STATUS_REPARSE;
}
FSP_API NTSTATUS FspFileSystemOpCreate(FSP_FILE_SYSTEM *FileSystem,
FSP_FSCTL_TRANSACT_REQ *Request, FSP_FSCTL_TRANSACT_RSP *Response)
{
NTSTATUS Result;
if (0 == FileSystem->Interface->Create ||
0 == FileSystem->Interface->Open ||
0 == FileSystem->Interface->Overwrite)
@ -616,19 +704,32 @@ FSP_API NTSTATUS FspFileSystemOpCreate(FSP_FILE_SYSTEM *FileSystem,
switch ((Request->Req.Create.CreateOptions >> 24) & 0xff)
{
case FILE_CREATE:
return FspFileSystemOpCreate_FileCreate(FileSystem, Request, Response);
Result = FspFileSystemOpCreate_FileCreate(FileSystem, Request, Response);
break;
case FILE_OPEN:
return FspFileSystemOpCreate_FileOpen(FileSystem, Request, Response);
Result = FspFileSystemOpCreate_FileOpen(FileSystem, Request, Response);
break;
case FILE_OPEN_IF:
return FspFileSystemOpCreate_FileOpenIf(FileSystem, Request, Response);
Result = FspFileSystemOpCreate_FileOpenIf(FileSystem, Request, Response);
break;
case FILE_OVERWRITE:
case FILE_SUPERSEDE:
return FspFileSystemOpCreate_FileOverwrite(FileSystem, Request, Response);
Result = FspFileSystemOpCreate_FileOverwrite(FileSystem, Request, Response);
break;
case FILE_OVERWRITE_IF:
return FspFileSystemOpCreate_FileOverwriteIf(FileSystem, Request, Response);
Result = FspFileSystemOpCreate_FileOverwriteIf(FileSystem, Request, Response);
break;
default:
return STATUS_INVALID_PARAMETER;
Result = STATUS_INVALID_PARAMETER;
break;
}
if (STATUS_OBJECT_NAME_NOT_FOUND == Result)
Result = FspFileSystemOpCreate_NotFoundCheck(FileSystem, Request, Response);
else if (STATUS_OBJECT_NAME_COLLISION == Result)
Result = FspFileSystemOpCreate_CollisionCheck(FileSystem, Request, Response);
return Result;
}
FSP_API NTSTATUS FspFileSystemOpOverwrite(FSP_FILE_SYSTEM *FileSystem,
@ -1093,7 +1194,7 @@ FSP_API BOOLEAN FspFileSystemFindReparsePoint(FSP_FILE_SYSTEM *FileSystem,
LastPathComponent = RemainderPath;
while (L'\\' != *RemainderPath)
{
if (L'\0' == *RemainderPath)
if (L'\0' == *RemainderPath || L':' == *RemainderPath)
return FALSE;
RemainderPath++;
}
@ -1161,7 +1262,7 @@ FSP_API NTSTATUS FspFileSystemResolveReparsePointsInternal(FSP_FILE_SYSTEM *File
LastPathComponent = RemainderPath;
while (L'\\' != *RemainderPath)
{
if (L'\0' == *RemainderPath)
if (L'\0' == *RemainderPath || L':' == *RemainderPath)
{
if (!ResolveLastPathComponent)
goto symlink_exit;
@ -1217,16 +1318,18 @@ FSP_API NTSTATUS FspFileSystemResolveReparsePointsInternal(FSP_FILE_SYSTEM *File
RemainderChar = *RemainderPath; *RemainderPath = L'\0';
ReparseDataSize = ReparseDataSize0;
Result = GetReparsePointByName(FileSystem, Context, TargetPath, '\0' != RemainderChar,
Result = GetReparsePointByName(FileSystem, Context, TargetPath, L'\\' == RemainderChar,
ReparseData, &ReparseDataSize);
*RemainderPath = RemainderChar;
if (STATUS_NOT_A_REPARSE_POINT == Result)
/* it was not a reparse point; continue */
continue;
else if (STATUS_OBJECT_NAME_NOT_FOUND == Result && L'\\' != RemainderChar)
goto symlink_exit;
else if (!NT_SUCCESS(Result))
{
if (STATUS_OBJECT_NAME_NOT_FOUND != Result || '\0' != RemainderChar)
if (STATUS_OBJECT_NAME_NOT_FOUND != Result)
Result = STATUS_OBJECT_PATH_NOT_FOUND;
return Result;
}

View File

@ -53,4 +53,17 @@ PWSTR FspDiagIdent(VOID);
BOOL WINAPI FspServiceConsoleCtrlHandler(DWORD CtrlType);
static inline ULONG FspPathSuffixIndex(PWSTR FileName)
{
WCHAR Root[2] = L"\\";
PWSTR Remain, Suffix;
ULONG Result;
FspPathSuffix(FileName, &Remain, &Suffix, Root);
Result = Remain == Root ? 0 : (ULONG)(Suffix - Remain);
FspPathCombine(FileName, Suffix);
return Result;
}
#endif

View File

@ -48,19 +48,6 @@ static NTSTATUS FspGetSecurityByName(FSP_FILE_SYSTEM *FileSystem,
}
}
static inline ULONG FspPathSuffixIndex(PWSTR FileName)
{
WCHAR Root[2] = L"\\";
PWSTR Remain, Suffix;
ULONG Result;
FspPathSuffix(FileName, &Remain, &Suffix, Root);
Result = Remain == Root ? 0 : (ULONG)(Suffix - Remain);
FspPathCombine(FileName, Suffix);
return Result;
}
FSP_API NTSTATUS FspAccessCheckEx(FSP_FILE_SYSTEM *FileSystem,
FSP_FSCTL_TRANSACT_REQ *Request,
BOOLEAN CheckParentOrMain, BOOLEAN AllowTraverseCheck,

View File

@ -47,7 +47,7 @@ NTSTATUS FspFsvolDeviceCopyContextByNameList(PDEVICE_OBJECT DeviceObject,
PVOID **PContexts, PULONG PContextCount);
VOID FspFsvolDeviceDeleteContextByNameList(PVOID *Contexts, ULONG ContextCount);
PVOID FspFsvolDeviceEnumerateContextByName(PDEVICE_OBJECT DeviceObject, PUNICODE_STRING FileName,
BOOLEAN SubpathOnly, PVOID *PRestartKey);
BOOLEAN NextFlag, FSP_DEVICE_CONTEXT_BY_NAME_TABLE_RESTART_KEY *RestartKey);
PVOID FspFsvolDeviceLookupContextByName(PDEVICE_OBJECT DeviceObject, PUNICODE_STRING FileName);
PVOID FspFsvolDeviceInsertContextByName(PDEVICE_OBJECT DeviceObject, PUNICODE_STRING FileName, PVOID Context,
FSP_DEVICE_CONTEXT_BY_NAME_TABLE_ELEMENT *ElementStorage, PBOOLEAN PInserted);
@ -616,20 +616,19 @@ VOID FspFsvolDeviceDeleteContextByNameList(PVOID *Contexts, ULONG ContextCount)
}
PVOID FspFsvolDeviceEnumerateContextByName(PDEVICE_OBJECT DeviceObject, PUNICODE_STRING FileName,
BOOLEAN SubpathOnly, PVOID *PRestartKey)
BOOLEAN NextFlag, FSP_DEVICE_CONTEXT_BY_NAME_TABLE_RESTART_KEY *RestartKey)
{
PAGED_CODE();
FSP_FSVOL_DEVICE_EXTENSION *FsvolDeviceExtension = FspFsvolDeviceExtension(DeviceObject);
BOOLEAN CaseInsensitive = 0 == FsvolDeviceExtension->VolumeParams.CaseSensitiveSearch;
FSP_DEVICE_CONTEXT_BY_NAME_TABLE_ELEMENT_DATA *Result;
ULONG DeleteCount = 0;
if (0 != *PRestartKey)
SubpathOnly = FALSE;
if (0 != RestartKey->RestartKey)
NextFlag = TRUE;
Result = RtlEnumerateGenericTableLikeADirectory(&FsvolDeviceExtension->ContextByNameTable,
0, 0, SubpathOnly, PRestartKey, &DeleteCount, &FileName);
0, 0, NextFlag, &RestartKey->RestartKey, &RestartKey->DeleteCount, &FileName);
if (0 != Result &&
RtlPrefixUnicodeString(FileName, Result->FileName, CaseInsensitive) &&

View File

@ -747,6 +747,11 @@ typedef struct
RTL_BALANCED_LINKS Header;
FSP_DEVICE_CONTEXT_BY_NAME_TABLE_ELEMENT_DATA Data;
} FSP_DEVICE_CONTEXT_BY_NAME_TABLE_ELEMENT;
typedef struct
{
PVOID RestartKey;
ULONG DeleteCount;
} FSP_DEVICE_CONTEXT_BY_NAME_TABLE_RESTART_KEY;
enum
{
FspFsctlDeviceExtensionKind = '\0ltC', /* file system control device (e.g. \Device\WinFsp.Disk) */
@ -823,7 +828,7 @@ NTSTATUS FspFsvolDeviceCopyContextByNameList(PDEVICE_OBJECT DeviceObject,
PVOID **PContexts, PULONG PContextCount);
VOID FspFsvolDeviceDeleteContextByNameList(PVOID *Contexts, ULONG ContextCount);
PVOID FspFsvolDeviceEnumerateContextByName(PDEVICE_OBJECT DeviceObject, PUNICODE_STRING FileName,
BOOLEAN SubpathOnly, PVOID *PRestartKey);
BOOLEAN NextFlag, FSP_DEVICE_CONTEXT_BY_NAME_TABLE_RESTART_KEY *RestartKey);
PVOID FspFsvolDeviceLookupContextByName(PDEVICE_OBJECT DeviceObject, PUNICODE_STRING FileName);
PVOID FspFsvolDeviceInsertContextByName(PDEVICE_OBJECT DeviceObject, PUNICODE_STRING FileName, PVOID Context,
FSP_DEVICE_CONTEXT_BY_NAME_TABLE_ELEMENT *ElementStorage, PBOOLEAN PInserted);

View File

@ -806,23 +806,94 @@ VOID FspFileNodeRename(FSP_FILE_NODE *FileNode, PUNICODE_STRING NewFileName)
PAGED_CODE();
PDEVICE_OBJECT FsvolDeviceObject = FileNode->FsvolDeviceObject;
FSP_FILE_NODE *DescendantFileNode;
FSP_FILE_NODE *DescendantFileNodeArray[16], **DescendantFileNodes;
ULONG DescendantFileNodeCount, DescendantFileNodeIndex;
FSP_DEVICE_CONTEXT_BY_NAME_TABLE_RESTART_KEY RestartKey;
BOOLEAN Deleted, Inserted;
USHORT FileNameLength;
PWSTR ExternalFileName;
FspFsvolDeviceLockContextTable(FsvolDeviceObject);
FspFsvolDeviceDeleteContextByName(FsvolDeviceObject, &FileNode->FileName, &Deleted);
ASSERT(Deleted);
DescendantFileNodes = DescendantFileNodeArray;
DescendantFileNodes[0] = FileNode;
DescendantFileNodeCount = 1;
memset(&RestartKey, 0, sizeof RestartKey);
for (;;)
{
DescendantFileNode = FspFsvolDeviceEnumerateContextByName(FsvolDeviceObject,
&FileNode->FileName, TRUE, &RestartKey);
if (0 == DescendantFileNode)
break;
if (0 != FileNode->ExternalFileName)
FspFree(FileNode->ExternalFileName);
FileNode->FileName = *NewFileName;
FileNode->ExternalFileName = NewFileName->Buffer;
if (ARRAYSIZE(DescendantFileNodeArray) > DescendantFileNodeCount)
DescendantFileNodes[DescendantFileNodeCount] = DescendantFileNode;
DescendantFileNodeCount++;
}
FspFsvolDeviceInsertContextByName(FsvolDeviceObject, &FileNode->FileName, FileNode,
&FileNode->ContextByNameElementStorage, &Inserted);
ASSERT(Inserted);
if (ARRAYSIZE(DescendantFileNodeArray) < DescendantFileNodeCount)
{
DescendantFileNodes = FspAllocMustSucceed(DescendantFileNodeCount * sizeof(FSP_FILE_NODE *));
DescendantFileNodes[0] = FileNode;
DescendantFileNodeIndex = 1;
memset(&RestartKey, 0, sizeof RestartKey);
for (;;)
{
DescendantFileNode = FspFsvolDeviceEnumerateContextByName(FsvolDeviceObject,
&FileNode->FileName, TRUE, &RestartKey);
if (0 == DescendantFileNode)
break;
DescendantFileNodes[DescendantFileNodeIndex] = DescendantFileNode;
DescendantFileNodeIndex++;
ASSERT(DescendantFileNodeCount >= DescendantFileNodeIndex);
}
ASSERT(DescendantFileNodeCount == DescendantFileNodeIndex);
}
FileNameLength = FileNode->FileName.Length;
for (
DescendantFileNodeIndex = 0;
DescendantFileNodeCount > DescendantFileNodeIndex;
DescendantFileNodeIndex++)
{
DescendantFileNode = DescendantFileNodes[DescendantFileNodeIndex];
ASSERT(DescendantFileNode->FileName.Length >= FileNameLength);
FspFsvolDeviceDeleteContextByName(FsvolDeviceObject, &DescendantFileNode->FileName, &Deleted);
ASSERT(Deleted);
ExternalFileName = DescendantFileNode->ExternalFileName;
DescendantFileNode->FileName.MaximumLength =
DescendantFileNode->FileName.Length - FileNameLength + NewFileName->Length;
DescendantFileNode->ExternalFileName = FspAllocMustSucceed(
DescendantFileNode->FileName.MaximumLength);
RtlCopyMemory((PUINT8)DescendantFileNode->ExternalFileName + NewFileName->Length,
(PUINT8)DescendantFileNode->FileName.Buffer + FileNameLength,
DescendantFileNode->FileName.Length - FileNameLength);
RtlCopyMemory(DescendantFileNode->ExternalFileName,
NewFileName->Buffer,
NewFileName->Length);
DescendantFileNode->FileName.Length = DescendantFileNode->FileName.MaximumLength;
DescendantFileNode->FileName.Buffer = DescendantFileNode->ExternalFileName;
if (0 != ExternalFileName)
FspFree(ExternalFileName);
FspFsvolDeviceInsertContextByName(FsvolDeviceObject, &DescendantFileNode->FileName, DescendantFileNode,
&DescendantFileNode->ContextByNameElementStorage, &Inserted);
ASSERT(Inserted);
}
FspFsvolDeviceUnlockContextTable(FsvolDeviceObject);
if (DescendantFileNodeArray != DescendantFileNodes)
FspFree(DescendantFileNodes);
}
BOOLEAN FspFileNodeHasOpenHandles(PDEVICE_OBJECT FsvolDeviceObject,
@ -835,7 +906,7 @@ BOOLEAN FspFileNodeHasOpenHandles(PDEVICE_OBJECT FsvolDeviceObject,
PAGED_CODE();
FSP_FILE_NODE *FileNode;
PVOID RestartKey = 0;
FSP_DEVICE_CONTEXT_BY_NAME_TABLE_RESTART_KEY RestartKey = { 0 };
for (;;)
{

View File

@ -1229,9 +1229,8 @@ static NTSTATUS FspFsvolSetRenameInformationSuccess(
NewFileName.Length = NewFileName.MaximumLength =
Request->Req.SetInformation.Info.Rename.NewFileName.Size - sizeof(WCHAR);
NewFileName.Buffer = FspAllocMustSucceed(NewFileName.Length);
RtlCopyMemory(NewFileName.Buffer, Request->Buffer + Request->FileName.Size, NewFileName.Length);
NewFileName.Buffer = (PVOID)
(Request->Buffer + Request->Req.SetInformation.Info.Rename.NewFileName.Offset);
FspFileNodeRename(FileNode, &NewFileName);
/* fastfat has some really arcane rules on rename notifications; simplify! */

View File

@ -1107,6 +1107,11 @@ static NTSTATUS GetReparsePointByName(
MEMFS *Memfs = (MEMFS *)FileSystem->UserContext;
MEMFS_FILE_NODE *FileNode;
#if defined(MEMFS_NAMED_STREAMS)
/* GetReparsePointByName will never receive a named stream */
assert(0 == wcschr(FileName, L':'));
#endif
FileNode = MemfsFileNodeMapGet(Memfs->FileNodeMap, FileName);
if (0 == FileNode)
return STATUS_OBJECT_NAME_NOT_FOUND;
@ -1133,6 +1138,11 @@ static NTSTATUS GetReparsePoint(FSP_FILE_SYSTEM *FileSystem,
{
MEMFS_FILE_NODE *FileNode = (MEMFS_FILE_NODE *)FileNode0;
#if defined(MEMFS_NAMED_STREAMS)
if (0 != FileNode->MainFileNode)
FileNode = FileNode->MainFileNode;
#endif
if (0 == (FileNode->FileInfo.FileAttributes & FILE_ATTRIBUTE_REPARSE_POINT))
return STATUS_NOT_A_REPARSE_POINT;
@ -1155,6 +1165,11 @@ static NTSTATUS SetReparsePoint(FSP_FILE_SYSTEM *FileSystem,
PVOID ReparseData;
NTSTATUS Result;
#if defined(MEMFS_NAMED_STREAMS)
if (0 != FileNode->MainFileNode)
FileNode = FileNode->MainFileNode;
#endif
if (MemfsFileNodeMapHasChild(Memfs->FileNodeMap, FileNode))
return STATUS_DIRECTORY_NOT_EMPTY;
@ -1189,6 +1204,11 @@ static NTSTATUS DeleteReparsePoint(FSP_FILE_SYSTEM *FileSystem,
MEMFS_FILE_NODE *FileNode = (MEMFS_FILE_NODE *)FileNode0;
NTSTATUS Result;
#if defined(MEMFS_NAMED_STREAMS)
if (0 != FileNode->MainFileNode)
FileNode = FileNode->MainFileNode;
#endif
if (0 != FileNode->ReparseData)
{
Result = FspFileSystemCanReplaceReparsePoint(

View File

@ -462,6 +462,120 @@ void rename_test(void)
}
}
static void rename_flipflop_dotest(ULONG Flags, PWSTR Prefix, ULONG FileInfoTimeout, ULONG NumMappings)
{
void *memfs = memfs_start_ex(Flags, FileInfoTimeout);
HANDLE Handle, Mappings[80];
BOOL Success;
WCHAR FilePath[MAX_PATH];
WCHAR FilePath2[MAX_PATH];
SYSTEM_INFO SystemInfo;
ASSERT(ARRAYSIZE(Mappings) >= NumMappings);
GetSystemInfo(&SystemInfo);
StringCbPrintfW(FilePath, sizeof FilePath, L"%s%s\\short",
Prefix ? L"" : L"\\\\?\\GLOBALROOT", Prefix ? Prefix : memfs_volumename(memfs));
Success = CreateDirectoryW(FilePath, 0);
ASSERT(Success);
StringCbPrintfW(FilePath, sizeof FilePath, L"%s%s\\short\\subdir",
Prefix ? L"" : L"\\\\?\\GLOBALROOT", Prefix ? Prefix : memfs_volumename(memfs));
Success = CreateDirectoryW(FilePath, 0);
ASSERT(Success);
for (ULONG j = 1; NumMappings >= j; j++)
{
if (NumMappings / 2 >= j)
StringCbPrintfW(FilePath, sizeof FilePath, L"%s%s\\short\\%.*s",
Prefix ? L"" : L"\\\\?\\GLOBALROOT", Prefix ? Prefix : memfs_volumename(memfs),
j, L"01234567890123456789012345678901234567890123456789012345678901234567890123456789");
else
StringCbPrintfW(FilePath, sizeof FilePath, L"%s%s\\short\\subdir\\%.*s",
Prefix ? L"" : L"\\\\?\\GLOBALROOT", Prefix ? Prefix : memfs_volumename(memfs),
j, L"01234567890123456789012345678901234567890123456789012345678901234567890123456789");
Handle = CreateFileW(FilePath, GENERIC_ALL, 0, 0, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, 0);
ASSERT(INVALID_HANDLE_VALUE != Handle);
Mappings[j - 1] = CreateFileMappingW(Handle, 0, PAGE_READWRITE,
0, SystemInfo.dwAllocationGranularity, 0);
ASSERT(0 != Mappings[j - 1]);
Success = CloseHandle(Handle);
ASSERT(Success);
}
StringCbPrintfW(FilePath, sizeof FilePath, L"%s%s\\short",
Prefix ? L"" : L"\\\\?\\GLOBALROOT", Prefix ? Prefix : memfs_volumename(memfs));
StringCbPrintfW(FilePath2, sizeof FilePath2, L"%s%s\\longlonglonglonglonglonglonglong",
Prefix ? L"" : L"\\\\?\\GLOBALROOT", Prefix ? Prefix : memfs_volumename(memfs));
for (ULONG i = 0; 10 > i; i++)
{
Success = MoveFileExW(FilePath, FilePath2, 0);
ASSERT(Success);
Success = MoveFileExW(FilePath2, FilePath, 0);
ASSERT(Success);
}
for (ULONG j = 1; NumMappings >= j; j++)
{
Success = CloseHandle(Mappings[j - 1]);
ASSERT(Success);
}
for (ULONG j = 1; NumMappings >= j; j++)
{
if (NumMappings / 2 >= j)
StringCbPrintfW(FilePath, sizeof FilePath, L"%s%s\\short\\%.*s",
Prefix ? L"" : L"\\\\?\\GLOBALROOT", Prefix ? Prefix : memfs_volumename(memfs),
j, L"01234567890123456789012345678901234567890123456789012345678901234567890123456789");
else
StringCbPrintfW(FilePath, sizeof FilePath, L"%s%s\\short\\subdir\\%.*s",
Prefix ? L"" : L"\\\\?\\GLOBALROOT", Prefix ? Prefix : memfs_volumename(memfs),
j, L"01234567890123456789012345678901234567890123456789012345678901234567890123456789");
Success = DeleteFileW(FilePath);
ASSERT(Success);
}
StringCbPrintfW(FilePath, sizeof FilePath, L"%s%s\\short\\subdir",
Prefix ? L"" : L"\\\\?\\GLOBALROOT", Prefix ? Prefix : memfs_volumename(memfs));
Success = RemoveDirectoryW(FilePath);
ASSERT(Success);
StringCbPrintfW(FilePath, sizeof FilePath, L"%s%s\\short",
Prefix ? L"" : L"\\\\?\\GLOBALROOT", Prefix ? Prefix : memfs_volumename(memfs));
Success = RemoveDirectoryW(FilePath);
ASSERT(Success);
memfs_stop(memfs);
}
void rename_flipflop_test(void)
{
if (NtfsTests)
{
WCHAR DirBuf[MAX_PATH] = L"\\\\?\\";
GetCurrentDirectoryW(MAX_PATH - 4, DirBuf + 4);
rename_flipflop_dotest(-1, DirBuf, 0, 10);
}
if (WinFspDiskTests)
{
rename_flipflop_dotest(MemfsDisk, 0, 0, 10);
rename_flipflop_dotest(MemfsDisk, 0, 1000, 10);
rename_flipflop_dotest(MemfsDisk, 0, 0, 40);
rename_flipflop_dotest(MemfsDisk, 0, 1000, 40);
}
if (WinFspNetTests)
{
rename_flipflop_dotest(MemfsNet, L"\\\\memfs\\share", 0, 10);
rename_flipflop_dotest(MemfsNet, L"\\\\memfs\\share", 1000, 10);
rename_flipflop_dotest(MemfsNet, L"\\\\memfs\\share", 0, 40);
rename_flipflop_dotest(MemfsNet, L"\\\\memfs\\share", 1000, 40);
}
}
void getvolinfo_dotest(ULONG Flags, PWSTR Prefix, ULONG FileInfoTimeout)
{
void *memfs = memfs_start_ex(Flags, FileInfoTimeout);
@ -639,6 +753,7 @@ void info_tests(void)
TEST(delete_test);
TEST(delete_access_test);
TEST(rename_test);
TEST(rename_flipflop_test);
TEST(getvolinfo_test);
TEST(setvolinfo_test);
}

View File

@ -1346,6 +1346,120 @@ static void stream_delete_pending_test(void)
}
}
static void stream_rename_flipflop_dotest(ULONG Flags, PWSTR Prefix, ULONG FileInfoTimeout, ULONG NumMappings)
{
void *memfs = memfs_start_ex(Flags, FileInfoTimeout);
HANDLE Handle, Mappings[80];
BOOL Success;
WCHAR FilePath[MAX_PATH];
WCHAR FilePath2[MAX_PATH];
SYSTEM_INFO SystemInfo;
ASSERT(ARRAYSIZE(Mappings) >= NumMappings);
GetSystemInfo(&SystemInfo);
StringCbPrintfW(FilePath, sizeof FilePath, L"%s%s\\short",
Prefix ? L"" : L"\\\\?\\GLOBALROOT", Prefix ? Prefix : memfs_volumename(memfs));
Success = CreateDirectoryW(FilePath, 0);
ASSERT(Success);
StringCbPrintfW(FilePath, sizeof FilePath, L"%s%s\\short\\subdir",
Prefix ? L"" : L"\\\\?\\GLOBALROOT", Prefix ? Prefix : memfs_volumename(memfs));
Success = CreateDirectoryW(FilePath, 0);
ASSERT(Success);
for (ULONG j = 1; NumMappings >= j; j++)
{
if (NumMappings / 2 >= j)
StringCbPrintfW(FilePath, sizeof FilePath, L"%s%s\\short\\%.*s:foo",
Prefix ? L"" : L"\\\\?\\GLOBALROOT", Prefix ? Prefix : memfs_volumename(memfs),
j, L"01234567890123456789012345678901234567890123456789012345678901234567890123456789");
else
StringCbPrintfW(FilePath, sizeof FilePath, L"%s%s\\short\\subdir\\%.*s:bar",
Prefix ? L"" : L"\\\\?\\GLOBALROOT", Prefix ? Prefix : memfs_volumename(memfs),
j, L"01234567890123456789012345678901234567890123456789012345678901234567890123456789");
Handle = CreateFileW(FilePath, GENERIC_ALL, 0, 0, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, 0);
ASSERT(INVALID_HANDLE_VALUE != Handle);
Mappings[j - 1] = CreateFileMappingW(Handle, 0, PAGE_READWRITE,
0, SystemInfo.dwAllocationGranularity, 0);
ASSERT(0 != Mappings[j - 1]);
Success = CloseHandle(Handle);
ASSERT(Success);
}
StringCbPrintfW(FilePath, sizeof FilePath, L"%s%s\\short",
Prefix ? L"" : L"\\\\?\\GLOBALROOT", Prefix ? Prefix : memfs_volumename(memfs));
StringCbPrintfW(FilePath2, sizeof FilePath2, L"%s%s\\longlonglonglonglonglonglonglong",
Prefix ? L"" : L"\\\\?\\GLOBALROOT", Prefix ? Prefix : memfs_volumename(memfs));
for (ULONG i = 0; 10 > i; i++)
{
Success = MoveFileExW(FilePath, FilePath2, 0);
ASSERT(Success);
Success = MoveFileExW(FilePath2, FilePath, 0);
ASSERT(Success);
}
for (ULONG j = 1; NumMappings >= j; j++)
{
Success = CloseHandle(Mappings[j - 1]);
ASSERT(Success);
}
for (ULONG j = 1; NumMappings >= j; j++)
{
if (NumMappings / 2 >= j)
StringCbPrintfW(FilePath, sizeof FilePath, L"%s%s\\short\\%.*s",
Prefix ? L"" : L"\\\\?\\GLOBALROOT", Prefix ? Prefix : memfs_volumename(memfs),
j, L"01234567890123456789012345678901234567890123456789012345678901234567890123456789");
else
StringCbPrintfW(FilePath, sizeof FilePath, L"%s%s\\short\\subdir\\%.*s",
Prefix ? L"" : L"\\\\?\\GLOBALROOT", Prefix ? Prefix : memfs_volumename(memfs),
j, L"01234567890123456789012345678901234567890123456789012345678901234567890123456789");
Success = DeleteFileW(FilePath);
ASSERT(Success);
}
StringCbPrintfW(FilePath, sizeof FilePath, L"%s%s\\short\\subdir",
Prefix ? L"" : L"\\\\?\\GLOBALROOT", Prefix ? Prefix : memfs_volumename(memfs));
Success = RemoveDirectoryW(FilePath);
ASSERT(Success);
StringCbPrintfW(FilePath, sizeof FilePath, L"%s%s\\short",
Prefix ? L"" : L"\\\\?\\GLOBALROOT", Prefix ? Prefix : memfs_volumename(memfs));
Success = RemoveDirectoryW(FilePath);
ASSERT(Success);
memfs_stop(memfs);
}
static void stream_rename_flipflop_test(void)
{
if (NtfsTests)
{
WCHAR DirBuf[MAX_PATH] = L"\\\\?\\";
GetCurrentDirectoryW(MAX_PATH - 4, DirBuf + 4);
stream_rename_flipflop_dotest(-1, DirBuf, 0, 10);
}
if (WinFspDiskTests)
{
stream_rename_flipflop_dotest(MemfsDisk, 0, 0, 10);
stream_rename_flipflop_dotest(MemfsDisk, 0, 1000, 10);
stream_rename_flipflop_dotest(MemfsDisk, 0, 0, 40);
stream_rename_flipflop_dotest(MemfsDisk, 0, 1000, 40);
}
if (WinFspNetTests)
{
stream_rename_flipflop_dotest(MemfsNet, L"\\\\memfs\\share", 0, 10);
stream_rename_flipflop_dotest(MemfsNet, L"\\\\memfs\\share", 1000, 10);
stream_rename_flipflop_dotest(MemfsNet, L"\\\\memfs\\share", 0, 40);
stream_rename_flipflop_dotest(MemfsNet, L"\\\\memfs\\share", 1000, 40);
}
}
static void stream_getsecurity_dotest(ULONG Flags, PWSTR Prefix, ULONG FileInfoTimeout)
{
void *memfs = memfs_start_ex(Flags, FileInfoTimeout);
@ -2010,6 +2124,7 @@ void stream_tests(void)
TEST(stream_setfileinfo_test);
TEST(stream_delete_test);
TEST(stream_delete_pending_test);
TEST(stream_rename_flipflop_test);
TEST(stream_getsecurity_test);
TEST(stream_setsecurity_test);
TEST(stream_getstreaminfo_test);