mirror of
https://github.com/winfsp/winfsp.git
synced 2025-04-22 08:23:05 -05:00
sys, dll: implement POSIX semantics for Rename
This commit is contained in:
parent
76bfa395a8
commit
bb3e92df6c
@ -426,6 +426,12 @@ typedef struct
|
||||
FSP_FSCTL_TRANSACT_BUF NewFileName;
|
||||
UINT64 AccessToken; /* request access token (PID,HANDLE) */
|
||||
} Rename;
|
||||
struct
|
||||
{
|
||||
FSP_FSCTL_TRANSACT_BUF NewFileName;
|
||||
UINT64 AccessToken; /* request access token (PID,HANDLE) */
|
||||
UINT32 Flags;
|
||||
} RenameEx;
|
||||
} Info;
|
||||
} SetInformation;
|
||||
struct
|
||||
|
@ -1459,7 +1459,8 @@ UINT32 FspFileSystemOperationProcessId(VOID)
|
||||
case FspFsctlTransactCreateKind:
|
||||
return FSP_FSCTL_TRANSACT_REQ_TOKEN_PID(Request->Req.Create.AccessToken);
|
||||
case FspFsctlTransactSetInformationKind:
|
||||
if (10/*FileRenameInformation*/ == Request->Req.SetInformation.FileInformationClass)
|
||||
if (10/*FileRenameInformation*/ == Request->Req.SetInformation.FileInformationClass ||
|
||||
65/*FileRenameInformationEx*/ == Request->Req.SetInformation.FileInformationClass)
|
||||
return FSP_FSCTL_TRANSACT_REQ_TOKEN_PID(Request->Req.SetInformation.Info.Rename.AccessToken);
|
||||
/* fall through! */
|
||||
default:
|
||||
|
@ -383,7 +383,10 @@ NTSTATUS FspFileSystemRenameCheck(FSP_FILE_SYSTEM *FileSystem,
|
||||
Request->Req.SetInformation.Info.Rename.NewFileName.Size;
|
||||
CreateRequest->Kind = FspFsctlTransactCreateKind;
|
||||
CreateRequest->Req.Create.CreateOptions =
|
||||
FILE_DELETE_ON_CLOSE | /* force read-only check! */
|
||||
(65/*FileRenameInformationEx*/ == Request->Req.SetInformation.FileInformationClass &&
|
||||
0 != (0x40/*IGNORE_READONLY_ATTRIBUTE*/ & Request->Req.SetInformation.Info.RenameEx.Flags) ?
|
||||
0 :
|
||||
FILE_DELETE_ON_CLOSE) | /* force read-only check! */
|
||||
FILE_OPEN_REPARSE_POINT; /* allow rename over reparse point */
|
||||
CreateRequest->Req.Create.AccessToken = Request->Req.SetInformation.Info.Rename.AccessToken;
|
||||
CreateRequest->Req.Create.UserMode = TRUE;
|
||||
|
@ -141,7 +141,8 @@ NTSTATUS fsp_fuse_op_enter(FSP_FILE_SYSTEM *FileSystem,
|
||||
AccessToken = Request->Req.Create.AccessToken;
|
||||
}
|
||||
else if (FspFsctlTransactSetInformationKind == Request->Kind &&
|
||||
10/*FileRenameInformation*/ == Request->Req.SetInformation.FileInformationClass)
|
||||
(10/*FileRenameInformation*/ == Request->Req.SetInformation.FileInformationClass ||
|
||||
65/*FileRenameInformationEx*/ == Request->Req.SetInformation.FileInformationClass))
|
||||
{
|
||||
FileName = (PWSTR)(Request->Buffer + Request->Req.SetInformation.Info.Rename.NewFileName.Offset);
|
||||
AccessToken = Request->Req.SetInformation.Info.Rename.AccessToken;
|
||||
|
@ -1577,7 +1577,8 @@ NTSTATUS FspFileNodeCheckBatchOplocksOnAllStreams(
|
||||
PUNICODE_STRING StreamFileName);
|
||||
NTSTATUS FspFileNodeRenameCheck(PDEVICE_OBJECT FsvolDeviceObject, PIRP OplockIrp,
|
||||
FSP_FILE_NODE *FileNode, ULONG AcquireFlags,
|
||||
PUNICODE_STRING FileName, BOOLEAN CheckingOldName);
|
||||
PUNICODE_STRING FileName, BOOLEAN CheckingOldName,
|
||||
BOOLEAN PosixRename);
|
||||
VOID FspFileNodeRename(FSP_FILE_NODE *FileNode, PUNICODE_STRING NewFileName);
|
||||
VOID FspFileNodeGetFileInfo(FSP_FILE_NODE *FileNode, FSP_FSCTL_FILE_INFO *FileInfo);
|
||||
BOOLEAN FspFileNodeTryGetFileInfo(FSP_FILE_NODE *FileNode, FSP_FSCTL_FILE_INFO *FileInfo);
|
||||
|
@ -58,7 +58,8 @@ NTSTATUS FspFileNodeCheckBatchOplocksOnAllStreams(
|
||||
PUNICODE_STRING StreamFileName);
|
||||
NTSTATUS FspFileNodeRenameCheck(PDEVICE_OBJECT FsvolDeviceObject, PIRP OplockIrp,
|
||||
FSP_FILE_NODE *FileNode, ULONG AcquireFlags,
|
||||
PUNICODE_STRING FileName, BOOLEAN CheckingOldName);
|
||||
PUNICODE_STRING FileName, BOOLEAN CheckingOldName,
|
||||
BOOLEAN PosixRename);
|
||||
VOID FspFileNodeRename(FSP_FILE_NODE *FileNode, PUNICODE_STRING NewFileName);
|
||||
VOID FspFileNodeGetFileInfo(FSP_FILE_NODE *FileNode, FSP_FSCTL_FILE_INFO *FileInfo);
|
||||
BOOLEAN FspFileNodeTryGetFileInfo(FSP_FILE_NODE *FileNode, FSP_FSCTL_FILE_INFO *FileInfo);
|
||||
@ -1355,7 +1356,8 @@ NTSTATUS FspFileNodeCheckBatchOplocksOnAllStreams(
|
||||
|
||||
NTSTATUS FspFileNodeRenameCheck(PDEVICE_OBJECT FsvolDeviceObject, PIRP OplockIrp,
|
||||
FSP_FILE_NODE *FileNode, ULONG AcquireFlags,
|
||||
PUNICODE_STRING FileName, BOOLEAN CheckingOldName)
|
||||
PUNICODE_STRING FileName, BOOLEAN CheckingOldName,
|
||||
BOOLEAN PosixRename)
|
||||
{
|
||||
PAGED_CODE();
|
||||
|
||||
@ -1389,7 +1391,7 @@ NTSTATUS FspFileNodeRenameCheck(PDEVICE_OBJECT FsvolDeviceObject, PIRP OplockIrp
|
||||
* "rename" resource exclusively, which disallows new Opens.
|
||||
*/
|
||||
|
||||
if (!CheckingOldName)
|
||||
if (!PosixRename && !CheckingOldName)
|
||||
{
|
||||
/* replaced file cannot be a directory or mapped as an image */
|
||||
for (
|
||||
@ -1568,11 +1570,32 @@ NTSTATUS FspFileNodeRenameCheck(PDEVICE_OBJECT FsvolDeviceObject, PIRP OplockIrp
|
||||
|
||||
if (DescendantFileNode != FileNode && 0 < DescendantFileNode->HandleCount)
|
||||
{
|
||||
/*
|
||||
* If we are doing a POSIX rename, then it is ok if we have open handles,
|
||||
* provided that we do not have sharing violations.
|
||||
*
|
||||
* Check our share access:
|
||||
*
|
||||
* - If all openers are allowing FILE_SHARE_DELETE.
|
||||
* - And all named streams openers are allowing FILE_SHARE_DELETE.
|
||||
*
|
||||
* Then we are good to go.
|
||||
*
|
||||
* (WinFsp cannot rename streams and there is no need to check MainFileDenyDeleteCount).
|
||||
*
|
||||
* NOTE: These are derived rules. AFAIK there is no documentation on how NTFS
|
||||
* does this in the case of POSIX rename.
|
||||
*/
|
||||
if (PosixRename &&
|
||||
DescendantFileNode->ShareAccess.OpenCount == DescendantFileNode->ShareAccess.SharedDelete &&
|
||||
0 == DescendantFileNode->StreamDenyDeleteCount)
|
||||
continue;
|
||||
|
||||
/* release the FileNode and rename lock in case of failure! */
|
||||
FspFileNodeReleaseF(FileNode, AcquireFlags);
|
||||
FspFsvolDeviceFileRenameRelease(FsvolDeviceObject);
|
||||
|
||||
Result = STATUS_ACCESS_DENIED;
|
||||
Result = PosixRename ? STATUS_SHARING_VIOLATION : STATUS_ACCESS_DENIED;
|
||||
break;
|
||||
}
|
||||
}
|
||||
@ -1661,14 +1684,14 @@ VOID FspFileNodeRename(FSP_FILE_NODE *FileNode, PUNICODE_STRING NewFileName)
|
||||
if (!Inserted)
|
||||
{
|
||||
/*
|
||||
* Handle files that have been Cleanup'ed but not Close'd.
|
||||
* Handle files that have been replaced after a Rename.
|
||||
* For example, this can happen when the user has mapped and closed a file
|
||||
* or immediately after breaking a Batch oplock.
|
||||
* or immediately after breaking a Batch oplock or
|
||||
* when doing a POSIX rename.
|
||||
*/
|
||||
|
||||
ASSERT(FspFileNodeIsValid(InsertedFileNode));
|
||||
ASSERT(DescendantFileNode != InsertedFileNode);
|
||||
ASSERT(0 == InsertedFileNode->HandleCount);
|
||||
ASSERT(0 != InsertedFileNode->OpenCount);
|
||||
|
||||
InsertedFileNode->OpenCount = 0;
|
||||
|
@ -1639,7 +1639,9 @@ static NTSTATUS FspFsvolSetRenameInformation(
|
||||
FSP_FSVOL_DEVICE_EXTENSION *FsvolDeviceExtension = FspFsvolDeviceExtension(FsvolDeviceObject);
|
||||
PFILE_OBJECT FileObject = IrpSp->FileObject;
|
||||
PFILE_OBJECT TargetFileObject = IrpSp->Parameters.SetFile.FileObject;
|
||||
FILE_INFORMATION_CLASS FileInformationClass = IrpSp->Parameters.SetFile.FileInformationClass;
|
||||
BOOLEAN ReplaceIfExists = IrpSp->Parameters.SetFile.ReplaceIfExists;
|
||||
UINT32 RenameFlags = !!ReplaceIfExists;
|
||||
PFILE_RENAME_INFORMATION Info = (PFILE_RENAME_INFORMATION)Irp->AssociatedIrp.SystemBuffer;
|
||||
ULONG Length = IrpSp->Parameters.SetFile.Length;
|
||||
FSP_FILE_NODE *FileNode = FileObject->FsContext;
|
||||
@ -1654,11 +1656,21 @@ static NTSTATUS FspFsvolSetRenameInformation(
|
||||
PSECURITY_SUBJECT_CONTEXT SecuritySubjectContext = 0;
|
||||
|
||||
ASSERT(FileNode == FileDesc->FileNode);
|
||||
ASSERT(
|
||||
FileRenameInformation == FileInformationClass ||
|
||||
FileRenameInformationEx == FileInformationClass);
|
||||
|
||||
if (sizeof(FILE_RENAME_INFORMATION) > Length)
|
||||
return STATUS_INVALID_PARAMETER;
|
||||
if (sizeof(WCHAR) > Info->FileNameLength)
|
||||
return STATUS_INVALID_PARAMETER;
|
||||
if (FileRenameInformationEx == FileInformationClass)
|
||||
{
|
||||
if (!FspFsvolDeviceExtension(FsvolDeviceObject)->VolumeParams.SupportsPosixUnlinkRename)
|
||||
return STATUS_INVALID_PARAMETER;
|
||||
RenameFlags |= Info->Flags &
|
||||
(FILE_RENAME_POSIX_SEMANTICS | FILE_RENAME_IGNORE_READONLY_ATTRIBUTE);
|
||||
}
|
||||
if (FileNode->IsRootDirectory)
|
||||
/* cannot rename root directory */
|
||||
return STATUS_INVALID_PARAMETER;
|
||||
@ -1736,13 +1748,14 @@ retry:
|
||||
Request->Kind = FspFsctlTransactSetInformationKind;
|
||||
Request->Req.SetInformation.UserContext = FileNode->UserContext;
|
||||
Request->Req.SetInformation.UserContext2 = FileDesc->UserContext2;
|
||||
Request->Req.SetInformation.FileInformationClass = FileRenameInformation;
|
||||
Request->Req.SetInformation.FileInformationClass = FileInformationClass;
|
||||
Request->Req.SetInformation.Info.Rename.NewFileName.Offset = Request->FileName.Size;
|
||||
Request->Req.SetInformation.Info.Rename.NewFileName.Size = NewFileName.Length + sizeof(WCHAR);
|
||||
Request->Req.SetInformation.Info.RenameEx.Flags = RenameFlags;
|
||||
}
|
||||
|
||||
/*
|
||||
* Special rules for renaming open files:
|
||||
* Special rules for renaming open files without POSIX semantics:
|
||||
* - A file cannot be renamed if it has any open handles,
|
||||
* unless it is only open because of a batch opportunistic lock (oplock)
|
||||
* and the batch oplock can be broken immediately.
|
||||
@ -1754,13 +1767,15 @@ retry:
|
||||
|
||||
Result = FspFileNodeRenameCheck(FsvolDeviceObject, Irp,
|
||||
FileNode, FspFileNodeAcquireFull,
|
||||
&FileNode->FileName, TRUE);
|
||||
&FileNode->FileName, TRUE,
|
||||
0 != (FILE_RENAME_POSIX_SEMANTICS & RenameFlags));
|
||||
/* FspFileNodeRenameCheck releases FileNode and rename lock on failure */
|
||||
if (STATUS_OPLOCK_BREAK_IN_PROGRESS == Result)
|
||||
goto retry;
|
||||
if (!NT_SUCCESS(Result))
|
||||
{
|
||||
Result = STATUS_ACCESS_DENIED;
|
||||
if (STATUS_SHARING_VIOLATION != Result)
|
||||
Result = STATUS_ACCESS_DENIED;
|
||||
goto exit;
|
||||
}
|
||||
|
||||
@ -1768,13 +1783,15 @@ retry:
|
||||
{
|
||||
Result = FspFileNodeRenameCheck(FsvolDeviceObject, Irp,
|
||||
FileNode, FspFileNodeAcquireFull,
|
||||
&NewFileName, FALSE);
|
||||
&NewFileName, FALSE,
|
||||
0 != (FILE_RENAME_POSIX_SEMANTICS & RenameFlags));
|
||||
/* FspFileNodeRenameCheck releases FileNode and rename lock on failure */
|
||||
if (STATUS_OPLOCK_BREAK_IN_PROGRESS == Result)
|
||||
goto retry;
|
||||
if (!NT_SUCCESS(Result))
|
||||
{
|
||||
Result = STATUS_ACCESS_DENIED;
|
||||
if (STATUS_SHARING_VIOLATION != Result)
|
||||
Result = STATUS_ACCESS_DENIED;
|
||||
goto exit;
|
||||
}
|
||||
}
|
||||
@ -1881,7 +1898,7 @@ static NTSTATUS FspFsvolSetInformation(
|
||||
case FileDispositionInformationEx:
|
||||
return FspFsvolSetDispositionInformation(FsvolDeviceObject, Irp, IrpSp);
|
||||
case FileRenameInformation:
|
||||
//case FileRenameInformationEx:
|
||||
case FileRenameInformationEx:
|
||||
return FspFsvolSetRenameInformation(FsvolDeviceObject, Irp, IrpSp);
|
||||
}
|
||||
|
||||
@ -2008,8 +2025,10 @@ NTSTATUS FspFsvolSetInformationPrepare(
|
||||
PAGED_CODE();
|
||||
|
||||
PIO_STACK_LOCATION IrpSp = IoGetCurrentIrpStackLocation(Irp);
|
||||
FILE_INFORMATION_CLASS FileInformationClass = IrpSp->Parameters.SetFile.FileInformationClass;
|
||||
|
||||
if (FileRenameInformation != IrpSp->Parameters.SetFile.FileInformationClass ||
|
||||
if ((FileRenameInformation != FileInformationClass &&
|
||||
FileRenameInformationEx != FileInformationClass) ||
|
||||
0 == FspIopRequestContext(Request, RequestSubjectContextOrAccessToken))
|
||||
return STATUS_SUCCESS;
|
||||
|
||||
@ -2087,7 +2106,7 @@ NTSTATUS FspFsvolSetInformationComplete(
|
||||
case FileDispositionInformationEx:
|
||||
FSP_RETURN(Result = FspFsvolSetDispositionInformationSuccess(Irp, Response));
|
||||
case FileRenameInformation:
|
||||
//case FileRenameInformationEx:
|
||||
case FileRenameInformationEx:
|
||||
FSP_RETURN(Result = FspFsvolSetRenameInformationSuccess(Irp, Response));
|
||||
}
|
||||
|
||||
|
@ -1784,6 +1784,179 @@ void rename_pid_dotest(ULONG Flags, PWSTR Prefix)
|
||||
ASSERT(0 < rename_pid_Pass);// && 0 == rename_pid_Fail);
|
||||
}
|
||||
|
||||
static void rename_ex_dotest(ULONG Flags, PWSTR VolPrefix, PWSTR Prefix, ULONG FileInfoTimeout)
|
||||
{
|
||||
BOOLEAN Success;
|
||||
DWORD FileSystemFlags;
|
||||
|
||||
Success = GetVolumeInformationW(L"C:\\",
|
||||
0, 0,
|
||||
0, 0, &FileSystemFlags,
|
||||
0, 0);
|
||||
if (!Success || 0 == (FileSystemFlags & FILE_SUPPORTS_POSIX_UNLINK_RENAME))
|
||||
/* skip this test if the system lacks FILE_SUPPORTS_POSIX_UNLINK_RENAME capability */
|
||||
return;
|
||||
|
||||
void *memfs = memfs_start_ex(Flags, FileInfoTimeout);
|
||||
|
||||
NTSYSCALLAPI NTSTATUS NTAPI
|
||||
NtSetInformationFile(
|
||||
HANDLE FileHandle,
|
||||
PIO_STATUS_BLOCK IoStatusBlock,
|
||||
PVOID FileInformation,
|
||||
ULONG Length,
|
||||
FILE_INFORMATION_CLASS FileInformationClass);
|
||||
typedef struct
|
||||
{
|
||||
ULONG Flags;
|
||||
HANDLE RootDirectory;
|
||||
ULONG FileNameLength;
|
||||
WCHAR FileName[1];
|
||||
} FILE_RENAME_INFORMATION, *PFILE_RENAME_INFORMATION;
|
||||
|
||||
HANDLE Handle0, Handle1, Handle2;
|
||||
WCHAR File0Path[MAX_PATH];
|
||||
WCHAR File2Path[MAX_PATH];
|
||||
union
|
||||
{
|
||||
FILE_RENAME_INFORMATION I;
|
||||
UINT8 B[sizeof(FILE_RENAME_INFORMATION) + MAX_PATH * sizeof(WCHAR)];
|
||||
} RenameInfo;
|
||||
IO_STATUS_BLOCK IoStatus;
|
||||
|
||||
StringCbPrintfW(File0Path, sizeof File0Path, L"%s%s\\",
|
||||
VolPrefix ? L"" : L"\\\\?\\GLOBALROOT", VolPrefix ? VolPrefix : memfs_volumename(memfs));
|
||||
|
||||
Success = GetVolumeInformationW(File0Path,
|
||||
0, 0,
|
||||
0, 0, &FileSystemFlags,
|
||||
0, 0);
|
||||
ASSERT(Success);
|
||||
if (0 != (FileSystemFlags & FILE_SUPPORTS_POSIX_UNLINK_RENAME))
|
||||
{
|
||||
StringCbPrintfW(File0Path, sizeof File0Path, L"%s%s\\file0",
|
||||
Prefix ? L"" : L"\\\\?\\GLOBALROOT", Prefix ? Prefix : memfs_volumename(memfs));
|
||||
|
||||
StringCbPrintfW(File2Path, sizeof File2Path, L"%s%s\\file2",
|
||||
Prefix ? L"" : L"\\\\?\\GLOBALROOT", Prefix ? Prefix : memfs_volumename(memfs));
|
||||
|
||||
Handle0 = CreateFileW(File0Path,
|
||||
GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, 0,
|
||||
CREATE_NEW, FILE_ATTRIBUTE_NORMAL, 0);
|
||||
ASSERT(INVALID_HANDLE_VALUE != Handle0);
|
||||
CloseHandle(Handle0);
|
||||
|
||||
Handle0 = CreateFileW(File0Path,
|
||||
DELETE, 0, 0,
|
||||
OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0);
|
||||
ASSERT(INVALID_HANDLE_VALUE != Handle0);
|
||||
|
||||
Handle1 = CreateFileW(File0Path,
|
||||
FILE_READ_ATTRIBUTES, 0, 0,
|
||||
OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0);
|
||||
ASSERT(INVALID_HANDLE_VALUE != Handle1);
|
||||
|
||||
memset(&RenameInfo.I, 0, sizeof RenameInfo.I);
|
||||
RenameInfo.I.Flags = 2/*FILE_RENAME_POSIX_SEMANTICS*/;
|
||||
RenameInfo.I.FileNameLength = (ULONG)(wcslen(L"file2") * sizeof(WCHAR));
|
||||
memcpy(RenameInfo.I.FileName, L"file2", RenameInfo.I.FileNameLength);
|
||||
IoStatus.Status = NtSetInformationFile(
|
||||
Handle0, &IoStatus,
|
||||
&RenameInfo.I, FIELD_OFFSET(FILE_RENAME_INFORMATION, FileName) + RenameInfo.I.FileNameLength,
|
||||
65/*FileRenameInformationEx*/);
|
||||
ASSERT(0 == IoStatus.Status);
|
||||
|
||||
Handle2 = CreateFileW(File2Path,
|
||||
FILE_READ_ATTRIBUTES, 0, 0,
|
||||
OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0);
|
||||
ASSERT(INVALID_HANDLE_VALUE != Handle2);
|
||||
|
||||
CloseHandle(Handle2);
|
||||
CloseHandle(Handle1);
|
||||
CloseHandle(Handle0);
|
||||
|
||||
Handle0 = CreateFileW(File0Path,
|
||||
GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, 0,
|
||||
CREATE_NEW, FILE_ATTRIBUTE_NORMAL, 0);
|
||||
ASSERT(INVALID_HANDLE_VALUE != Handle0);
|
||||
CloseHandle(Handle0);
|
||||
|
||||
Handle1 = CreateFileW(File0Path,
|
||||
GENERIC_READ | GENERIC_WRITE, 0, 0,
|
||||
OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0);
|
||||
ASSERT(INVALID_HANDLE_VALUE != Handle1);
|
||||
|
||||
Handle2 = CreateFileW(File2Path,
|
||||
DELETE, 0, 0,
|
||||
OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0);
|
||||
ASSERT(INVALID_HANDLE_VALUE != Handle0);
|
||||
|
||||
memset(&RenameInfo.I, 0, sizeof RenameInfo.I);
|
||||
RenameInfo.I.Flags = 3/*FILE_RENAME_REPLACE_IF_EXISTS|FILE_RENAME_POSIX_SEMANTICS*/;
|
||||
RenameInfo.I.FileNameLength = (ULONG)(wcslen(L"file0") * sizeof(WCHAR));
|
||||
memcpy(RenameInfo.I.FileName, L"file0", RenameInfo.I.FileNameLength);
|
||||
IoStatus.Status = NtSetInformationFile(
|
||||
Handle2, &IoStatus,
|
||||
&RenameInfo.I, FIELD_OFFSET(FILE_RENAME_INFORMATION, FileName) + RenameInfo.I.FileNameLength,
|
||||
65/*FileRenameInformationEx*/);
|
||||
ASSERT(STATUS_SHARING_VIOLATION == IoStatus.Status);
|
||||
|
||||
CloseHandle(Handle2);
|
||||
CloseHandle(Handle1);
|
||||
|
||||
Handle1 = CreateFileW(File0Path,
|
||||
FILE_READ_ATTRIBUTES, 0, 0,
|
||||
OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0);
|
||||
ASSERT(INVALID_HANDLE_VALUE != Handle1);
|
||||
|
||||
Handle2 = CreateFileW(File2Path,
|
||||
DELETE, 0, 0,
|
||||
OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0);
|
||||
ASSERT(INVALID_HANDLE_VALUE != Handle0);
|
||||
|
||||
memset(&RenameInfo.I, 0, sizeof RenameInfo.I);
|
||||
RenameInfo.I.Flags = 3/*FILE_RENAME_REPLACE_IF_EXISTS|FILE_RENAME_POSIX_SEMANTICS*/;
|
||||
RenameInfo.I.FileNameLength = (ULONG)(wcslen(L"file0") * sizeof(WCHAR));
|
||||
memcpy(RenameInfo.I.FileName, L"file0", RenameInfo.I.FileNameLength);
|
||||
IoStatus.Status = NtSetInformationFile(
|
||||
Handle2, &IoStatus,
|
||||
&RenameInfo.I, FIELD_OFFSET(FILE_RENAME_INFORMATION, FileName) + RenameInfo.I.FileNameLength,
|
||||
65/*FileRenameInformationEx*/);
|
||||
ASSERT(0 == IoStatus.Status);
|
||||
|
||||
CloseHandle(Handle2);
|
||||
CloseHandle(Handle1);
|
||||
|
||||
Success = DeleteFileW(File0Path);
|
||||
ASSERT(Success);
|
||||
}
|
||||
|
||||
memfs_stop(memfs);
|
||||
}
|
||||
|
||||
void rename_ex_test(void)
|
||||
{
|
||||
if (OptLegacyUnlinkRename)
|
||||
return;
|
||||
|
||||
if (NtfsTests)
|
||||
{
|
||||
WCHAR DirBuf[MAX_PATH], DriveBuf[3];
|
||||
GetTestDirectoryAndDrive(DirBuf, DriveBuf);
|
||||
rename_ex_dotest(-1, DriveBuf, DirBuf, 0);
|
||||
}
|
||||
if (WinFspDiskTests)
|
||||
{
|
||||
rename_ex_dotest(MemfsDisk, 0, 0, 0);
|
||||
rename_ex_dotest(MemfsDisk, 0, 0, 1000);
|
||||
}
|
||||
if (WinFspNetTests)
|
||||
{
|
||||
rename_ex_dotest(MemfsNet, L"\\\\memfs\\share", L"\\\\memfs\\share", 0);
|
||||
rename_ex_dotest(MemfsNet, L"\\\\memfs\\share", L"\\\\memfs\\share", 1000);
|
||||
}
|
||||
}
|
||||
|
||||
void rename_pid_test(void)
|
||||
{
|
||||
if (NtfsTests)
|
||||
@ -2060,6 +2233,8 @@ void info_tests(void)
|
||||
if (!OptShareName)
|
||||
TEST(rename_mmap_test);
|
||||
TEST(rename_standby_test);
|
||||
if (!OptLegacyUnlinkRename)
|
||||
TEST(rename_ex_test);
|
||||
if (!NtfsTests)
|
||||
TEST(rename_pid_test);
|
||||
TEST(getvolinfo_test);
|
||||
|
Loading…
x
Reference in New Issue
Block a user