Curious … here is a simple test code I cobbled together to look at the
behaviour … it is supposed to be doing …
NtCreateFile Blah -> Handle1
NtCreateFile Blah [DeleteOnClose] -> Handle2
NtQueryInformationFile FileStandardInformaiton Handle1
NtQueryInformationFile FileStandardInformaiton Handle2
NtSetInformationFile FileDispositionInformation [FALSE] Handle2
NtClose Handle2
NtQueryInformationFile FileStandardInformaiton Handle1
NtClose Handle1
The first two NtQueryInformationFile return DeletePending FALSE and the
third returns DeletePending TRUE. The file Blah is delete after the second
NtClose. This is for NTFS and FAT on W2K3 SP1 and XP SP2.
I wonder have I goofed the code or just misunderstood the method to clear
the DeleteOnClose?
By the way, if replace the “NtSetInformationFile Handle2” *before* “NtClose
Handle2” with a NtSetInformatyionFile Handle1 *after* NtCloseHandle Handle2
then all three NtQueryInformationFile return DeletePending FALSE and the
file is not delete after the second NtClose.
int Bladder(int argc, WCHAR * argv)
{
WCHAR FileName[1024];
NTSTATUS NtStatus;
UNICODE_STRING UnicodeString;
OBJECT_ATTRIBUTES ObjectAttributes;
HANDLE FileHandle1, FileHandle2;
IO_STATUS_BLOCK IoStatusBlock;
FILE_DISPOSITION_INFORMATION FileDispositionInformationData;
FILE_STANDARD_INFORMATION FileStandardInformationData;
if (argc != (1 + 1))
{
fwprintf(stderr, L"Usage: %s filename\n", argv[0]);
exit(1);
}
wcscpy(FileName, L"\??\“);
wcscat(FileName, argv[1]);
fwprintf(stdout, L"FileName %s\n”, FileName);
fwprintf(stdout, L"Opening file (1) …\n");
RtlInitUnicodeString(&UnicodeString, FileName);
InitializeObjectAttributes(&ObjectAttributes,
&UnicodeString,
OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE,
NULL,
NULL);
NtStatus = NtCreateFile(&FileHandle1,
SYNCHRONIZE | DELETE,
&ObjectAttributes,
&IoStatusBlock,
0,
FILE_ATTRIBUTE_NORMAL,
FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
FILE_OPEN_IF,
FILE_SYNCHRONOUS_IO_NONALERT,
NULL,
0);
if (!NT_SUCCESS(NtStatus))
{
fwprintf(stderr, L"NtCreateFile returns %X\n", NtStatus);
exit(1);
}
if (! NT_SUCCESS(IoStatusBlock.Status))
{
fwprintf(stderr, L"NtCreateFile IoStatusBlock.Status %X\n",
IoStatusBlock.Status);
exit(1);
}
fwprintf(stdout, L"Opening file (2) with delete on close …\n");
RtlInitUnicodeString(&UnicodeString, FileName);
InitializeObjectAttributes(&ObjectAttributes,
&UnicodeString,
OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE,
NULL,
NULL);
NtStatus = NtCreateFile(&FileHandle2,
SYNCHRONIZE | DELETE,
&ObjectAttributes,
&IoStatusBlock,
0,
FILE_ATTRIBUTE_NORMAL,
FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
FILE_OPEN,
FILE_SYNCHRONOUS_IO_NONALERT | FILE_DELETE_ON_CLOSE,
NULL,
0);
if (!NT_SUCCESS(NtStatus))
{
fwprintf(stderr, L"NtCreateFile returns %X\n", NtStatus);
exit(1);
}
if (! NT_SUCCESS(IoStatusBlock.Status))
{
fwprintf(stderr, L"NtCreateFile IoStatusBlock.Status %X\n",
IoStatusBlock.Status);
exit(1);
}
fwprintf(stdout, L"Querying disposition (1) …\n");
NtStatus = NtQueryInformationFile(FileHandle1,
&IoStatusBlock,
&FileStandardInformationData,
sizeof(FILE_STANDARD_INFORMATION),
FileStandardInformation);
if (!NT_SUCCESS(NtStatus))
{
fwprintf(stderr, L"NtQueryInformationFile returns %X\n", NtStatus);
exit(1);
}
if (! NT_SUCCESS(IoStatusBlock.Status))
{
fwprintf(stderr, L"NtQueryInformationFile IoStatusBlock.Status %X\n",
IoStatusBlock.Status);
exit(1);
}
fwprintf(stdout, L"Disposition (1) is %d\n",
FileStandardInformationData.DeletePending);
fwprintf(stdout, L"Querying disposition (2) …\n");
NtStatus = NtQueryInformationFile(FileHandle2,
&IoStatusBlock,
&FileStandardInformationData,
sizeof(FILE_STANDARD_INFORMATION),
FileStandardInformation);
if (!NT_SUCCESS(NtStatus))
{
fwprintf(stderr, L"NtQueryInformationFile returns %X\n", NtStatus);
exit(1);
}
if (! NT_SUCCESS(IoStatusBlock.Status))
{
fwprintf(stderr, L"NtQueryInformationFile IoStatusBlock.Status %X\n",
IoStatusBlock.Status);
exit(1);
}
fwprintf(stdout, L"Disposition (2) is %d\n",
FileStandardInformationData.DeletePending);
fwprintf(stdout, L"Setting file (2) delete file false …\n");
FileDispositionInformationData.DeleteFile = FALSE;
NtStatus = NtSetInformationFile(FileHandle2,
&IoStatusBlock,
&FileDispositionInformationData,
sizeof(FILE_DISPOSITION_INFORMATION),
FileDispositionInformation);
if (!NT_SUCCESS(NtStatus))
{
fwprintf(stderr, L"NtSetInformationFile returns %X\n", NtStatus);
exit(1);
}
if (! NT_SUCCESS(IoStatusBlock.Status))
{
fwprintf(stderr, L"NtSetInformationFile IoStatusBlock.Status %X\n",
IoStatusBlock.Status);
exit(1);
}
fwprintf(stdout, L"Closing file (2) …\n");
NtStatus = NtClose(FileHandle2);
if (!NT_SUCCESS(NtStatus))
{
fwprintf(stderr, L"NtCloseFile returns %X\n", NtStatus);
exit(1);
}
if (! NT_SUCCESS(IoStatusBlock.Status))
{
fwprintf(stderr, L"NtCloseFile IoStatusBlock.Status %X\n",
IoStatusBlock.Status);
exit(1);
}
fwprintf(stdout, L"Querying disposition (1) …\n");
NtStatus = NtQueryInformationFile(FileHandle1,
&IoStatusBlock,
&FileStandardInformationData,
sizeof(FILE_STANDARD_INFORMATION),
FileStandardInformation);
if (!NT_SUCCESS(NtStatus))
{
fwprintf(stderr, L"NtQueryInformationFile returns %X\n", NtStatus);
exit(1);
}
if (! NT_SUCCESS(IoStatusBlock.Status))
{
fwprintf(stderr, L"NtQueryInformationFile IoStatusBlock.Status %X\n",
IoStatusBlock.Status);
exit(1);
}
fwprintf(stdout, L"Disposition (1) is %d\n",
FileStandardInformationData.DeletePending);
fwprintf(stdout, L"Closing file (1) …\n");
NtStatus = NtClose(FileHandle1);
if (!NT_SUCCESS(NtStatus))
{
fwprintf(stderr, L"NtCloseFile returns %X\n", NtStatus);
exit(1);
}
if (! NT_SUCCESS(IoStatusBlock.Status))
{
fwprintf(stderr, L"NtCloseFile IoStatusBlock.Status %X\n",
IoStatusBlock.Status);
exit(1);
}
return 0;
}
“Tony Mason” wrote in message news:xxxxx@ntfsd…
Note that due to the peculiarities of implementation, delete-on-close
cannot be cleared for FAT, but it can be for NTFS, although I did log a
bug against this and thus it might have been fixed for Vista.
Tony
Tony Mason
Consulting Partner
OSR Open Systems Resources, Inc.
http://www.osr.com