You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
1283 lines
32 KiB
1283 lines
32 KiB
/*++
|
|
|
|
Copyright (c) 1993 Microsoft Corporation
|
|
|
|
Module Name:
|
|
|
|
spfile.c
|
|
|
|
Abstract:
|
|
|
|
File operations for text setup.
|
|
|
|
Author:
|
|
|
|
Ted Miller (tedm) 2-Aug-1993
|
|
|
|
Revision History:
|
|
|
|
Jim Schmidt (jimschm) 10-Apr-1997 Added file attribute routines
|
|
|
|
--*/
|
|
|
|
|
|
#include "spprecmp.h"
|
|
#pragma hdrstop
|
|
|
|
|
|
NTSTATUS
|
|
SpGetFileSize(
|
|
IN HANDLE hFile,
|
|
OUT PULONG Size
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Determine the size of a file. Only the low 32 bits of the size
|
|
are considered.
|
|
|
|
Arguments:
|
|
|
|
hFile - supplies open handle to file whose size is desired.
|
|
|
|
Size - receives size of file.
|
|
|
|
Return Value:
|
|
|
|
--*/
|
|
|
|
{
|
|
NTSTATUS Status;
|
|
IO_STATUS_BLOCK IoStatusBlock;
|
|
FILE_STANDARD_INFORMATION StandardInfo;
|
|
|
|
Status = ZwQueryInformationFile(
|
|
hFile,
|
|
&IoStatusBlock,
|
|
&StandardInfo,
|
|
sizeof(StandardInfo),
|
|
FileStandardInformation
|
|
);
|
|
|
|
if(!NT_SUCCESS(Status)) {
|
|
KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_WARNING_LEVEL, "SETUP: SpGetFileSize: status %lx from ZwQueryInformationFile\n",Status));
|
|
return(Status);
|
|
}
|
|
|
|
*Size = StandardInfo.EndOfFile.LowPart;
|
|
|
|
return(STATUS_SUCCESS);
|
|
}
|
|
|
|
|
|
NTSTATUS
|
|
SpMapEntireFile(
|
|
IN HANDLE hFile,
|
|
OUT PHANDLE Section,
|
|
OUT PVOID *ViewBase,
|
|
IN BOOLEAN WriteAccess
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Map an entire file for read or write access access.
|
|
|
|
Arguments:
|
|
|
|
hFile - supplies handle of open file to be mapped.
|
|
|
|
Section - receives handle for section object created to map file.
|
|
|
|
ViewBase - receives address of the view of the file
|
|
|
|
WriteAccess - if TRUE, map file for read and write access.
|
|
If FALSE, map file for read access.
|
|
|
|
Return Value:
|
|
|
|
--*/
|
|
|
|
{
|
|
NTSTATUS Status;
|
|
LARGE_INTEGER SectionOffset;
|
|
SIZE_T ViewSize = 0;
|
|
|
|
SectionOffset.QuadPart = 0;
|
|
|
|
Status = ZwCreateSection(
|
|
Section,
|
|
STANDARD_RIGHTS_REQUIRED | SECTION_QUERY | SECTION_MAP_READ
|
|
| (WriteAccess ? SECTION_MAP_WRITE : 0),
|
|
NULL,
|
|
NULL, // entire file
|
|
WriteAccess ? PAGE_READWRITE : PAGE_READONLY,
|
|
SEC_COMMIT,
|
|
hFile
|
|
);
|
|
|
|
if(!NT_SUCCESS(Status)) {
|
|
KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_WARNING_LEVEL, "SETUP: Status %lx from ZwCreateSection\n",Status));
|
|
return(Status);
|
|
}
|
|
|
|
*ViewBase = NULL;
|
|
Status = ZwMapViewOfSection(
|
|
*Section,
|
|
NtCurrentProcess(),
|
|
ViewBase,
|
|
0,
|
|
0,
|
|
&SectionOffset,
|
|
&ViewSize,
|
|
ViewShare,
|
|
0,
|
|
WriteAccess ? PAGE_READWRITE : PAGE_READONLY
|
|
);
|
|
|
|
if(!NT_SUCCESS(Status)) {
|
|
|
|
NTSTATUS s;
|
|
|
|
KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_WARNING_LEVEL, "SETUP: SpMapEntireFile: Status %lx from ZwMapViewOfSection\n",Status));
|
|
|
|
s = ZwClose(*Section);
|
|
|
|
if(!NT_SUCCESS(s)) {
|
|
KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_WARNING_LEVEL, "SETUP: SpMapEntireFile: Warning: status %lx from ZwClose on section handle\n",s));
|
|
}
|
|
|
|
return(Status);
|
|
}
|
|
|
|
return(STATUS_SUCCESS);
|
|
}
|
|
|
|
|
|
|
|
BOOLEAN
|
|
SpUnmapFile(
|
|
IN HANDLE Section,
|
|
IN PVOID ViewBase
|
|
)
|
|
{
|
|
NTSTATUS Status;
|
|
BOOLEAN rc = TRUE;
|
|
|
|
Status = ZwUnmapViewOfSection(NtCurrentProcess(),ViewBase);
|
|
if(!NT_SUCCESS(Status)) {
|
|
KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_WARNING_LEVEL, "SETUP: Warning: status %lx from ZwUnmapViewOfSection\n",Status));
|
|
rc = FALSE;
|
|
}
|
|
|
|
Status = ZwClose(Section);
|
|
if(!NT_SUCCESS(Status)) {
|
|
KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_WARNING_LEVEL, "SETUP: Warning: status %lx from ZwClose on section handle\n",Status));
|
|
rc = FALSE;
|
|
}
|
|
|
|
return(rc);
|
|
}
|
|
|
|
|
|
|
|
NTSTATUS
|
|
SpOpenAndMapFile(
|
|
IN PWSTR FileName, OPTIONAL // only needed if no FileHandle
|
|
IN OUT PHANDLE FileHandle,
|
|
OUT PHANDLE SectionHandle,
|
|
OUT PVOID *ViewBase,
|
|
OUT PULONG FileSize,
|
|
IN BOOLEAN WriteAccess
|
|
)
|
|
{
|
|
IO_STATUS_BLOCK IoStatusBlock;
|
|
UNICODE_STRING UnicodeString;
|
|
OBJECT_ATTRIBUTES Obja;
|
|
NTSTATUS Status;
|
|
BOOLEAN MustClose = FALSE;
|
|
|
|
//
|
|
// If necessary, open the file.
|
|
//
|
|
if(!(*FileHandle)) {
|
|
INIT_OBJA(&Obja,&UnicodeString,FileName);
|
|
Status = ZwCreateFile(
|
|
FileHandle,
|
|
FILE_GENERIC_READ | (WriteAccess ? FILE_GENERIC_WRITE : 0),
|
|
&Obja,
|
|
&IoStatusBlock,
|
|
NULL,
|
|
FILE_ATTRIBUTE_NORMAL,
|
|
FILE_SHARE_READ,
|
|
FILE_OPEN,
|
|
0,
|
|
NULL,
|
|
0
|
|
);
|
|
|
|
if(!NT_SUCCESS(Status)) {
|
|
KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_WARNING_LEVEL, "SETUP: SpOpenAndMapFile: Unable to open %ws (%lx)\n",FileName,Status));
|
|
return(Status);
|
|
} else {
|
|
MustClose = TRUE;
|
|
}
|
|
}
|
|
|
|
//
|
|
// Get the size of the file.
|
|
//
|
|
Status = SpGetFileSize(*FileHandle,FileSize);
|
|
if(!NT_SUCCESS(Status)) {
|
|
KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_WARNING_LEVEL, "SETUP: SpOpenAndMapFile: unable to determine size of file %ws(%lx)\n",
|
|
FileName ? FileName : L"(handle)", Status));
|
|
if(MustClose) {
|
|
ZwClose(*FileHandle);
|
|
}
|
|
return(Status);
|
|
}
|
|
|
|
//
|
|
// Map the file.
|
|
//
|
|
Status = SpMapEntireFile(*FileHandle,SectionHandle,ViewBase,WriteAccess);
|
|
if(!NT_SUCCESS(Status)) {
|
|
KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_WARNING_LEVEL, "SETUP: SpOpenAndMapFile: unable to map %ws (%lx)\n",
|
|
FileName ? FileName : L"(handle)", Status));
|
|
if(MustClose) {
|
|
ZwClose(*FileHandle);
|
|
}
|
|
return(Status);
|
|
}
|
|
|
|
return(STATUS_SUCCESS);
|
|
}
|
|
|
|
|
|
NTSTATUS
|
|
SpSetInformationFile(
|
|
IN HANDLE Handle,
|
|
IN FILE_INFORMATION_CLASS FileInformationClass,
|
|
IN ULONG Length,
|
|
IN PVOID FileInformation
|
|
)
|
|
{
|
|
NTSTATUS Status;
|
|
PFILE_OBJECT FileObject;
|
|
OBJECT_HANDLE_INFORMATION HandleInfo;
|
|
|
|
//
|
|
// Reference the object.
|
|
//
|
|
Status = ObReferenceObjectByHandle(
|
|
Handle,
|
|
(ACCESS_MASK)DELETE,
|
|
*IoFileObjectType,
|
|
ExGetPreviousMode(),
|
|
&FileObject,
|
|
&HandleInfo
|
|
);
|
|
|
|
if(!NT_SUCCESS(Status)) {
|
|
KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_WARNING_LEVEL, "SETUP: SpSetInformationFile: ObReferenceObjectByHandle failed (%lx)\n",Status));
|
|
return(Status);
|
|
}
|
|
|
|
//
|
|
// Set the information.
|
|
//
|
|
Status = IoSetInformation(FileObject,FileInformationClass,Length,FileInformation);
|
|
|
|
if(!NT_SUCCESS(Status)) {
|
|
KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_WARNING_LEVEL, "SETUP: IoSetInformation returns %lx\n",Status));
|
|
}
|
|
|
|
//
|
|
// Clean up and return.
|
|
//
|
|
ObDereferenceObject(FileObject);
|
|
return(Status);
|
|
}
|
|
|
|
|
|
NTSTATUS
|
|
SpSetAttributes (
|
|
IN PWSTR SrcNTPath,
|
|
IN ULONG FileAttributes
|
|
)
|
|
{
|
|
UNICODE_STRING UnicodeString;
|
|
NTSTATUS NtStatus;
|
|
|
|
NtStatus = RtlInitUnicodeStringEx(&UnicodeString, SrcNTPath);
|
|
if (!NT_SUCCESS(NtStatus)) {
|
|
goto Exit;
|
|
}
|
|
NtStatus = SpSetAttributes_Ustr(&UnicodeString, FileAttributes);
|
|
Exit:
|
|
return NtStatus;
|
|
}
|
|
|
|
NTSTATUS
|
|
SpSetAttributes_Ustr (
|
|
IN PCUNICODE_STRING SrcNTPath,
|
|
IN ULONG FileAttributes
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Applies FileAttributes to the specified file.
|
|
|
|
Arguments:
|
|
|
|
SrcNTPath - The NT path of the file needing attribute modification
|
|
|
|
FileAttributes - The FILE_ATTRIBUTE_* flags to apply.
|
|
|
|
Return Value:
|
|
|
|
NTSTATUS code.
|
|
|
|
--*/
|
|
|
|
{
|
|
OBJECT_ATTRIBUTES Obja; // for ZwOpenFile
|
|
IO_STATUS_BLOCK IoStatusBlock; // for ZwOpenFile
|
|
NTSTATUS Status; // Return value
|
|
HANDLE FileHandle; // Handle of file to be modified
|
|
FILE_BASIC_INFORMATION BasicInfo; // For attribs modification
|
|
|
|
InitializeObjectAttributes(&Obja, (PUNICODE_STRING)SrcNTPath, OBJ_CASE_INSENSITIVE, NULL, NULL);
|
|
|
|
Status = ZwOpenFile(
|
|
&FileHandle,
|
|
(ACCESS_MASK)(DELETE|FILE_WRITE_ATTRIBUTES),
|
|
&Obja,
|
|
&IoStatusBlock,
|
|
FILE_SHARE_DELETE|FILE_SHARE_READ|FILE_SHARE_WRITE,
|
|
FILE_NON_DIRECTORY_FILE|FILE_OPEN_FOR_BACKUP_INTENT
|
|
);
|
|
|
|
if (!NT_SUCCESS (Status)) {
|
|
Status = ZwOpenFile(
|
|
&FileHandle,
|
|
(ACCESS_MASK)(DELETE|FILE_WRITE_ATTRIBUTES),
|
|
&Obja,
|
|
&IoStatusBlock,
|
|
FILE_SHARE_DELETE|FILE_SHARE_READ|FILE_SHARE_WRITE,
|
|
FILE_DIRECTORY_FILE|FILE_OPEN_FOR_BACKUP_INTENT
|
|
);
|
|
}
|
|
|
|
if(NT_SUCCESS(Status)) {
|
|
|
|
RtlZeroMemory( &BasicInfo, sizeof( FILE_BASIC_INFORMATION ) );
|
|
BasicInfo.FileAttributes = FileAttributes;
|
|
|
|
Status = SpSetInformationFile(
|
|
FileHandle,
|
|
FileBasicInformation,
|
|
sizeof(BasicInfo),
|
|
&BasicInfo
|
|
);
|
|
|
|
ZwClose(FileHandle);
|
|
}
|
|
|
|
if (!NT_SUCCESS(Status)) {
|
|
KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_WARNING_LEVEL, "SETUP: SpSetAttributes failed for %ws, Status=%lx\n", SrcNTPath, Status));
|
|
}
|
|
|
|
return Status;
|
|
}
|
|
|
|
NTSTATUS
|
|
SpGetAttributes (
|
|
IN PWSTR SrcNTPath,
|
|
OUT PULONG FileAttributesPtr
|
|
)
|
|
{
|
|
UNICODE_STRING UnicodeString;
|
|
NTSTATUS NtStatus;
|
|
|
|
NtStatus = RtlInitUnicodeStringEx(&UnicodeString, SrcNTPath);
|
|
if (!NT_SUCCESS(NtStatus)) {
|
|
goto Exit;
|
|
}
|
|
NtStatus = SpGetAttributes_Ustr(&UnicodeString, FileAttributesPtr);
|
|
Exit:
|
|
return NtStatus;
|
|
}
|
|
|
|
NTSTATUS
|
|
SpGetAttributes_Ustr (
|
|
IN PCUNICODE_STRING SrcNTPath,
|
|
OUT PULONG FileAttributesPtr
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Obtains FileAttributes for the specified file.
|
|
|
|
Arguments:
|
|
|
|
SrcNTPath - The NT path of the file to obtain attributes
|
|
|
|
FileAttributesPtr - A poitner to a DWORD that recieves FILE_ATTRIBUTE_*
|
|
flags
|
|
|
|
Return Value:
|
|
|
|
NTSTATUS code. FileAttributePtr is modified only with status is NO_ERROR.
|
|
|
|
--*/
|
|
|
|
{
|
|
OBJECT_ATTRIBUTES Obja; // for ZwOpenFile
|
|
IO_STATUS_BLOCK IoStatusBlock; // for ZwOpenFile
|
|
NTSTATUS Status; // Return value
|
|
HANDLE FileHandle; // Handle of file to be queried
|
|
FILE_BASIC_INFORMATION BasicInfo; // For attribs retrieval
|
|
|
|
InitializeObjectAttributes(&Obja, (PUNICODE_STRING)SrcNTPath, OBJ_CASE_INSENSITIVE, NULL, NULL);
|
|
|
|
Status = ZwOpenFile(
|
|
&FileHandle,
|
|
(ACCESS_MASK)(FILE_TRAVERSE | FILE_READ_ATTRIBUTES),
|
|
&Obja,
|
|
&IoStatusBlock,
|
|
FILE_SHARE_READ,
|
|
FILE_NON_DIRECTORY_FILE
|
|
);
|
|
|
|
if (!NT_SUCCESS (Status)) {
|
|
Status = ZwOpenFile(
|
|
&FileHandle,
|
|
(ACCESS_MASK)(FILE_TRAVERSE | FILE_READ_ATTRIBUTES),
|
|
&Obja,
|
|
&IoStatusBlock,
|
|
FILE_SHARE_READ,
|
|
FILE_DIRECTORY_FILE
|
|
);
|
|
}
|
|
|
|
if(NT_SUCCESS(Status)) {
|
|
Status = ZwQueryInformationFile(
|
|
FileHandle,
|
|
&IoStatusBlock,
|
|
&BasicInfo,
|
|
sizeof(BasicInfo),
|
|
FileBasicInformation
|
|
);
|
|
|
|
ZwClose(FileHandle);
|
|
if (NT_SUCCESS(Status)) {
|
|
*FileAttributesPtr = BasicInfo.FileAttributes;
|
|
}
|
|
}
|
|
|
|
if (!NT_SUCCESS(Status)) {
|
|
KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_WARNING_LEVEL, "SETUP: SpGetAttributes failed for %wZ, Status=%lx\n", SrcNTPath, Status));
|
|
}
|
|
|
|
return Status;
|
|
}
|
|
|
|
NTSTATUS
|
|
SpDeleteFileOrEmptyDirectory(
|
|
IN ULONG Flags,
|
|
IN PCUNICODE_STRING Path
|
|
)
|
|
/*
|
|
This is based on SpMigDeleteFile.
|
|
It does not perform optimally, in terms of limiting the number of NtOpenFile calls.
|
|
*/
|
|
{
|
|
UNICODE_STRING ustr;
|
|
NTSTATUS Status = STATUS_INTERNAL_ERROR;
|
|
const ULONG ValidFlags = SP_DELETE_FILE_OR_EMPTY_DIRECTORY_FLAG_DO_NOT_CLEAR_ATTRIBUTES;
|
|
|
|
if ((Flags & ~ValidFlags) != 0) {
|
|
Status = STATUS_INVALID_PARAMETER;
|
|
goto Exit;
|
|
}
|
|
|
|
if ((Flags & SP_DELETE_FILE_OR_EMPTY_DIRECTORY_FLAG_DO_NOT_CLEAR_ATTRIBUTES) == 0) {
|
|
SpSetAttributes_Ustr (Path, FILE_ATTRIBUTE_NORMAL);
|
|
}
|
|
|
|
if (SpFileExists_Ustr (Path, FALSE)) {
|
|
|
|
//
|
|
// Delete the file
|
|
//
|
|
Status = SpDeleteFile_Ustr (Path, NULL, NULL);
|
|
|
|
} else if (SpFileExists_Ustr (Path, TRUE)) {
|
|
|
|
//
|
|
// Delete the empty directory
|
|
//
|
|
Status = SpDeleteFileEx_Ustr (
|
|
Path,
|
|
NULL,
|
|
NULL,
|
|
FILE_SHARE_DELETE | FILE_SHARE_READ | FILE_SHARE_WRITE,
|
|
FILE_OPEN_FOR_BACKUP_INTENT
|
|
);
|
|
} else {
|
|
Status = STATUS_SUCCESS;
|
|
}
|
|
Exit:
|
|
return Status;
|
|
}
|
|
|
|
NTSTATUS
|
|
SpDeleteFileEx(
|
|
IN PCWSTR Name1,
|
|
IN PCWSTR Name2, OPTIONAL
|
|
IN PCWSTR Name3, OPTIONAL
|
|
IN ULONG ShareFlags, OPTIONAL
|
|
IN ULONG OpenFlags OPTIONAL
|
|
)
|
|
{
|
|
UNICODE_STRING UnicodeString1;
|
|
UNICODE_STRING UnicodeString2;
|
|
UNICODE_STRING UnicodeString3;
|
|
NTSTATUS Status = STATUS_INTERNAL_ERROR;
|
|
|
|
Status = RtlInitUnicodeStringEx(&UnicodeString1, Name1);
|
|
if (!NT_SUCCESS(Status)) {
|
|
goto Exit;
|
|
}
|
|
Status = RtlInitUnicodeStringEx(&UnicodeString2, Name2);
|
|
if (!NT_SUCCESS(Status)) {
|
|
goto Exit;
|
|
}
|
|
Status = RtlInitUnicodeStringEx(&UnicodeString3, Name3);
|
|
if (!NT_SUCCESS(Status)) {
|
|
goto Exit;
|
|
}
|
|
Status = SpDeleteFileEx_Ustr(&UnicodeString1, &UnicodeString2, &UnicodeString3, ShareFlags, OpenFlags);
|
|
Exit:
|
|
return Status;
|
|
}
|
|
|
|
NTSTATUS
|
|
SpDeleteFileEx_Ustr(
|
|
IN PCUNICODE_STRING Name1,
|
|
IN PCUNICODE_STRING Name2, OPTIONAL
|
|
IN PCUNICODE_STRING Name3, OPTIONAL
|
|
IN ULONG ShareFlags, OPTIONAL
|
|
IN ULONG OpenFlags OPTIONAL
|
|
)
|
|
{
|
|
UNICODE_STRING p;
|
|
NTSTATUS Status;
|
|
IO_STATUS_BLOCK IoStatusBlock;
|
|
UNICODE_STRING UnicodeString;
|
|
OBJECT_ATTRIBUTES Obja;
|
|
HANDLE Handle;
|
|
FILE_DISPOSITION_INFORMATION Disposition;
|
|
FILE_BASIC_INFORMATION BasicInfo;
|
|
|
|
//
|
|
// Point to temporary buffer for pathname.
|
|
//
|
|
p = TemporaryBufferUnicodeString;
|
|
|
|
//
|
|
// Build up the full name of the file to delete.
|
|
//
|
|
RtlMoveMemory(p.Buffer, Name1->Buffer, Name1->Length);
|
|
p.Length = Name1->Length;
|
|
if(Name2 != NULL && Name2->Length != 0) {
|
|
SpConcatenatePaths_Ustr(&p,Name2);
|
|
}
|
|
if(Name3 != NULL && Name3->Length != 0) {
|
|
SpConcatenatePaths_Ustr(&p,Name3);
|
|
}
|
|
|
|
//
|
|
// Prepare to open the file.
|
|
//
|
|
InitializeObjectAttributes(&Obja, &p, OBJ_CASE_INSENSITIVE, NULL, NULL);
|
|
|
|
//
|
|
// Attempt to open the file.
|
|
//
|
|
Status = ZwOpenFile(
|
|
&Handle,
|
|
(ACCESS_MASK)(DELETE | FILE_WRITE_ATTRIBUTES),
|
|
&Obja,
|
|
&IoStatusBlock,
|
|
ShareFlags,
|
|
OpenFlags
|
|
);
|
|
|
|
if(!NT_SUCCESS(Status)) {
|
|
if (Status != STATUS_OBJECT_NAME_NOT_FOUND) {
|
|
KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_WARNING_LEVEL, "SETUP: Unable to open %wZ for delete (%lx)\n",p,Status));
|
|
}
|
|
return(Status);
|
|
}
|
|
|
|
//
|
|
// Change the file attribute to normal
|
|
//
|
|
|
|
RtlZeroMemory( &BasicInfo, sizeof( FILE_BASIC_INFORMATION ) );
|
|
BasicInfo.FileAttributes = FILE_ATTRIBUTE_NORMAL;
|
|
|
|
Status = SpSetInformationFile(
|
|
Handle,
|
|
FileBasicInformation,
|
|
sizeof(BasicInfo),
|
|
&BasicInfo
|
|
);
|
|
|
|
if(!NT_SUCCESS(Status)) {
|
|
KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_WARNING_LEVEL, "SETUP: Unable to change attribute of %wZ, Status = (%lx)\n",p,Status));
|
|
return(Status);
|
|
}
|
|
|
|
//
|
|
// Set up for delete and call worker to do it.
|
|
//
|
|
#undef DeleteFile
|
|
Disposition.DeleteFile = TRUE;
|
|
|
|
Status = SpSetInformationFile(
|
|
Handle,
|
|
FileDispositionInformation,
|
|
sizeof(Disposition),
|
|
&Disposition
|
|
);
|
|
|
|
//
|
|
// Clean up and return.
|
|
//
|
|
ZwClose(Handle);
|
|
return(Status);
|
|
}
|
|
|
|
NTSTATUS
|
|
SpDeleteFile(
|
|
IN PCWSTR Name1,
|
|
IN PCWSTR Name2, OPTIONAL
|
|
IN PCWSTR Name3 OPTIONAL
|
|
)
|
|
{
|
|
UNICODE_STRING UnicodeString1;
|
|
UNICODE_STRING UnicodeString2;
|
|
UNICODE_STRING UnicodeString3;
|
|
NTSTATUS Status = STATUS_INTERNAL_ERROR;
|
|
|
|
Status = RtlInitUnicodeStringEx(&UnicodeString1, Name1);
|
|
if (!NT_SUCCESS(Status)) {
|
|
goto Exit;
|
|
}
|
|
Status = RtlInitUnicodeStringEx(&UnicodeString2, Name2);
|
|
if (!NT_SUCCESS(Status)) {
|
|
goto Exit;
|
|
}
|
|
Status = RtlInitUnicodeStringEx(&UnicodeString3, Name3);
|
|
if (!NT_SUCCESS(Status)) {
|
|
goto Exit;
|
|
}
|
|
Status = SpDeleteFile_Ustr(&UnicodeString1, &UnicodeString2, &UnicodeString3);
|
|
Exit:
|
|
return Status;
|
|
}
|
|
|
|
NTSTATUS
|
|
SpDeleteFile_Ustr(
|
|
IN PCUNICODE_STRING Name1,
|
|
IN PCUNICODE_STRING Name2, OPTIONAL
|
|
IN PCUNICODE_STRING Name3 OPTIONAL
|
|
)
|
|
{
|
|
|
|
return( SpDeleteFileEx_Ustr( Name1,
|
|
Name2,
|
|
Name3,
|
|
FILE_SHARE_DELETE | FILE_SHARE_READ | FILE_SHARE_WRITE,
|
|
FILE_NON_DIRECTORY_FILE | FILE_OPEN_FOR_BACKUP_INTENT ) );
|
|
|
|
}
|
|
|
|
BOOLEAN
|
|
SpFileExists(
|
|
IN PCWSTR PathName,
|
|
IN BOOLEAN Directory
|
|
)
|
|
{
|
|
BOOLEAN Result;
|
|
UNICODE_STRING UnicodeString;
|
|
|
|
RtlInitUnicodeString(&UnicodeString, PathName);
|
|
|
|
Result = SpFileExists_Ustr(&UnicodeString, Directory);
|
|
|
|
return Result;
|
|
}
|
|
|
|
BOOLEAN
|
|
SpFileExists_Ustr(
|
|
IN PCUNICODE_STRING PathName,
|
|
IN BOOLEAN Directory
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Determine if a file or directory exists
|
|
|
|
Arguments:
|
|
|
|
PathName - PathName of file or directory to check
|
|
|
|
Directory - Whether PathName refers to a directory or a file
|
|
|
|
Return Value:
|
|
|
|
NT_SUCCESS(NTSTATUS) if file exists.
|
|
|
|
--*/
|
|
|
|
{
|
|
OBJECT_ATTRIBUTES Obja;
|
|
HANDLE Handle;
|
|
IO_STATUS_BLOCK IoStatusBlock;
|
|
NTSTATUS Status;
|
|
|
|
InitializeObjectAttributes(&Obja, (PUNICODE_STRING)PathName, OBJ_CASE_INSENSITIVE, NULL, NULL);
|
|
|
|
Status = ZwCreateFile(
|
|
&Handle,
|
|
FILE_READ_ATTRIBUTES,
|
|
&Obja,
|
|
&IoStatusBlock,
|
|
NULL,
|
|
0,
|
|
FILE_SHARE_READ | FILE_SHARE_WRITE,
|
|
FILE_OPEN,
|
|
Directory ? FILE_DIRECTORY_FILE : FILE_NON_DIRECTORY_FILE,
|
|
NULL,
|
|
0
|
|
);
|
|
|
|
if(NT_SUCCESS(Status)) {
|
|
ZwClose(Handle);
|
|
return(TRUE);
|
|
} else {
|
|
return(FALSE);
|
|
}
|
|
}
|
|
|
|
NTSTATUS
|
|
SpRenameFile(
|
|
IN PCWSTR OldName,
|
|
IN PCWSTR NewName,
|
|
IN BOOLEAN AllowDirectoryRename
|
|
)
|
|
{
|
|
UNICODE_STRING OldUnicodeString;
|
|
UNICODE_STRING NewUnicodeString;
|
|
NTSTATUS Status = STATUS_INTERNAL_ERROR;
|
|
|
|
Status = RtlInitUnicodeStringEx(&OldUnicodeString, OldName);
|
|
if (!NT_SUCCESS(Status)) {
|
|
goto Exit;
|
|
}
|
|
Status = RtlInitUnicodeStringEx(&NewUnicodeString, NewName);
|
|
if (!NT_SUCCESS(Status)) {
|
|
goto Exit;
|
|
}
|
|
Status = SpRenameFile_Ustr(&OldUnicodeString, &NewUnicodeString, AllowDirectoryRename);
|
|
Exit:
|
|
return Status;
|
|
}
|
|
|
|
|
|
NTSTATUS
|
|
SpRenameFile_Ustr(
|
|
IN PCUNICODE_STRING OldName,
|
|
IN PCUNICODE_STRING NewName,
|
|
IN BOOLEAN AllowDirectoryRename
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Rename a file or directory
|
|
|
|
Arguments:
|
|
|
|
OldName - Old name of file
|
|
|
|
NewName - New name of file
|
|
|
|
AllowDirectoryRename - if TRUE, then this routine will rename a directory,
|
|
otherwise directory renames are not allowed.
|
|
|
|
Return Value:
|
|
|
|
NT_SUCCESS(NTSTATUS) if file successfully renamed
|
|
|
|
--*/
|
|
|
|
{
|
|
NTSTATUS Status;
|
|
IO_STATUS_BLOCK IoStatusBlock;
|
|
OBJECT_ATTRIBUTES Obja;
|
|
HANDLE Handle;
|
|
struct {
|
|
FILE_RENAME_INFORMATION NameInfo;
|
|
WCHAR Buffer[ACTUAL_MAX_PATH];
|
|
} Buffer;
|
|
|
|
//
|
|
// Prepare to open the file.
|
|
//
|
|
InitializeObjectAttributes(&Obja, (PUNICODE_STRING)OldName, OBJ_CASE_INSENSITIVE, NULL, NULL);
|
|
|
|
//
|
|
// Attempt to open the file as a file.
|
|
//
|
|
Status = ZwOpenFile(
|
|
&Handle,
|
|
(ACCESS_MASK)(DELETE | SYNCHRONIZE),
|
|
&Obja,
|
|
&IoStatusBlock,
|
|
FILE_SHARE_READ | FILE_SHARE_WRITE,
|
|
FILE_NON_DIRECTORY_FILE | FILE_OPEN_FOR_BACKUP_INTENT
|
|
);
|
|
|
|
if(!NT_SUCCESS(Status) && AllowDirectoryRename) {
|
|
//
|
|
// Attempt to open the file as a directory.
|
|
//
|
|
Status = ZwOpenFile(
|
|
&Handle,
|
|
(ACCESS_MASK)(DELETE | SYNCHRONIZE),
|
|
&Obja,
|
|
&IoStatusBlock,
|
|
FILE_SHARE_READ | FILE_SHARE_WRITE,
|
|
FILE_DIRECTORY_FILE | FILE_OPEN_FOR_BACKUP_INTENT
|
|
);
|
|
}
|
|
|
|
if(!NT_SUCCESS(Status)) {
|
|
KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_WARNING_LEVEL, "SETUP: Unable to open %wZ for rename (%lx)\n",OldName,Status));
|
|
return(Status);
|
|
}
|
|
|
|
//
|
|
// Change the file name
|
|
//
|
|
|
|
RtlZeroMemory(&Buffer, sizeof(Buffer));
|
|
|
|
Buffer.NameInfo.ReplaceIfExists = FALSE;
|
|
Buffer.NameInfo.RootDirectory = NULL;
|
|
Buffer.NameInfo.FileNameLength = NewName->Length;
|
|
RtlCopyMemory( Buffer.NameInfo.FileName, NewName->Buffer, NewName->Length );
|
|
|
|
Status = SpSetInformationFile(
|
|
Handle,
|
|
FileRenameInformation,
|
|
sizeof(Buffer),
|
|
(PVOID)&Buffer
|
|
);
|
|
|
|
if(!NT_SUCCESS(Status)) {
|
|
KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_WARNING_LEVEL, "SETUP: Unable to change name of %wZ to %wZ. Status = (%lx)\n",OldName,NewName,Status));
|
|
}
|
|
|
|
//
|
|
// Clean up and return.
|
|
//
|
|
|
|
ZwClose(Handle);
|
|
return(Status);
|
|
|
|
|
|
}
|
|
|
|
USHORT
|
|
SpChkSum(
|
|
ULONG PartialSum,
|
|
PUSHORT Source,
|
|
ULONG Length
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Compute a partial checksum on a portion of an imagefile.
|
|
|
|
Arguments:
|
|
|
|
PartialSum - Supplies the initial checksum value.
|
|
|
|
Sources - Supplies a pointer to the array of words for which the
|
|
checksum is computed.
|
|
|
|
Length - Supplies the length of the array in words.
|
|
|
|
Return Value:
|
|
|
|
The computed checksum value is returned as the function value.
|
|
|
|
--*/
|
|
|
|
{
|
|
|
|
//
|
|
// Compute the word wise checksum allowing carries to occur into the
|
|
// high order half of the checksum longword.
|
|
//
|
|
|
|
while (Length--) {
|
|
PartialSum += *Source++;
|
|
PartialSum = (PartialSum >> 16) + (PartialSum & 0xffff);
|
|
}
|
|
|
|
//
|
|
// Fold final carry into a single word result and return the resultant
|
|
// value.
|
|
//
|
|
|
|
return (USHORT)(((PartialSum >> 16) + PartialSum) & 0xffff);
|
|
}
|
|
|
|
|
|
PIMAGE_NT_HEADERS
|
|
SpChecksumMappedFile(
|
|
IN PVOID BaseAddress,
|
|
IN ULONG FileSize,
|
|
OUT PULONG HeaderSum,
|
|
OUT PULONG Checksum
|
|
)
|
|
{
|
|
PIMAGE_NT_HEADERS NtHeaders;
|
|
USHORT PartialSum;
|
|
PUSHORT AdjustSum;
|
|
|
|
try {
|
|
|
|
//
|
|
// Compute the checksum of this file and zero the header sum.
|
|
//
|
|
PartialSum = SpChkSum(0,BaseAddress,(FileSize+1) >> 1);
|
|
*HeaderSum = 0;
|
|
|
|
//
|
|
// See whether this is an image.
|
|
//
|
|
if(NtHeaders = RtlImageNtHeader(BaseAddress)) {
|
|
|
|
//
|
|
// The file is an image file -- subtract the two checksum words
|
|
// in the optional header from the computed checksum before adding
|
|
// the file length, and set the value of the header checksum.
|
|
//
|
|
*HeaderSum = NtHeaders->OptionalHeader.CheckSum;
|
|
AdjustSum = (PUSHORT)(&NtHeaders->OptionalHeader.CheckSum);
|
|
PartialSum -= (PartialSum < AdjustSum[0]);
|
|
PartialSum -= AdjustSum[0];
|
|
PartialSum -= (PartialSum < AdjustSum[1]);
|
|
PartialSum -= AdjustSum[1];
|
|
}
|
|
|
|
//
|
|
// Compute the checksum.
|
|
//
|
|
*Checksum = (ULONG)PartialSum + FileSize;
|
|
|
|
} except(EXCEPTION_EXECUTE_HANDLER) {
|
|
NtHeaders = NULL;
|
|
}
|
|
|
|
return(NtHeaders);
|
|
}
|
|
|
|
|
|
NTSTATUS
|
|
SpOpenNameMayBeCompressed(
|
|
IN PWSTR FullPath,
|
|
IN ULONG OpenAccess,
|
|
IN ULONG FileAttributes,
|
|
IN ULONG ShareFlags,
|
|
IN ULONG Disposition,
|
|
IN ULONG OpenFlags,
|
|
OUT PHANDLE Handle,
|
|
OUT PBOOLEAN OpenedCompressedName OPTIONAL
|
|
)
|
|
{
|
|
NTSTATUS Status;
|
|
PWSTR compname;
|
|
PWSTR names[2];
|
|
int compord,uncompord;
|
|
static BOOLEAN PreviousWasCompressed = FALSE;
|
|
BOOLEAN IsComp;
|
|
int i;
|
|
UNICODE_STRING UnicodeString;
|
|
OBJECT_ATTRIBUTES Obja;
|
|
IO_STATUS_BLOCK IoStatusBlock;
|
|
|
|
//
|
|
// Generate compressed name.
|
|
//
|
|
compname = SpGenerateCompressedName(FullPath);
|
|
|
|
//
|
|
// Figure out which name to try to use first. If the last successful
|
|
// call to this routine opened the file using the compressed name, then
|
|
// try to open the compressed name first. Otherwise try to open the
|
|
// uncompressed name first.
|
|
//
|
|
if(PreviousWasCompressed) {
|
|
compord = 0;
|
|
uncompord = 1;
|
|
} else {
|
|
compord = 1;
|
|
uncompord = 0;
|
|
}
|
|
|
|
names[uncompord] = FullPath;
|
|
names[compord] = compname;
|
|
|
|
for(i=0; i<2; i++) {
|
|
|
|
INIT_OBJA(&Obja,&UnicodeString,names[i]);
|
|
|
|
Status = ZwCreateFile(
|
|
Handle,
|
|
OpenAccess,
|
|
&Obja,
|
|
&IoStatusBlock,
|
|
NULL,
|
|
FileAttributes,
|
|
ShareFlags,
|
|
Disposition,
|
|
OpenFlags,
|
|
NULL,
|
|
0
|
|
);
|
|
|
|
if(NT_SUCCESS(Status)) {
|
|
|
|
IsComp = (BOOLEAN)(i == compord);
|
|
|
|
PreviousWasCompressed = IsComp;
|
|
if(OpenedCompressedName) {
|
|
*OpenedCompressedName = IsComp;
|
|
}
|
|
|
|
break;
|
|
}
|
|
}
|
|
|
|
SpMemFree(compname);
|
|
return(Status);
|
|
}
|
|
|
|
NTSTATUS
|
|
SpGetFileSizeByName(
|
|
IN PWSTR DevicePath OPTIONAL,
|
|
IN PWSTR Directory OPTIONAL,
|
|
IN PWSTR FileName,
|
|
OUT PULONG Size
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Determine the size of a file. Only the low 32 bits of the size
|
|
are considered.
|
|
|
|
Arguments:
|
|
|
|
DevicePath - Path to the device that contains the file.
|
|
|
|
Directory - Name of the directory that contains the file.
|
|
|
|
FileName - Name of the file.
|
|
|
|
Size - receives size of file.
|
|
|
|
Return Value:
|
|
|
|
NTSTATUs -
|
|
|
|
--*/
|
|
|
|
{
|
|
PWSTR CompleteFileName;
|
|
HANDLE FileHandle;
|
|
OBJECT_ATTRIBUTES ObjectAttributes;
|
|
IO_STATUS_BLOCK IoStatusBlock;
|
|
NTSTATUS Status;
|
|
UNICODE_STRING UnicodeFileName;
|
|
ULONG FileNameLength;
|
|
|
|
FileNameLength = wcslen( FileName ) + 1;
|
|
if( DevicePath != NULL ) {
|
|
FileNameLength += wcslen( DevicePath ) + 1;
|
|
}
|
|
if( Directory != NULL ) {
|
|
FileNameLength += wcslen( Directory ) + 1;
|
|
}
|
|
|
|
CompleteFileName = SpMemAlloc( FileNameLength*sizeof( WCHAR ) );
|
|
if( CompleteFileName == NULL ) {
|
|
KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_WARNING_LEVEL, "SETUP: Unable to allocate memory on SpGetFileSizeByName \n" ));
|
|
return( STATUS_NO_MEMORY );
|
|
}
|
|
|
|
*CompleteFileName = (WCHAR)'\0';
|
|
if( DevicePath != NULL ) {
|
|
SpConcatenatePaths( CompleteFileName, DevicePath );
|
|
}
|
|
if( Directory != NULL ) {
|
|
SpConcatenatePaths( CompleteFileName, Directory );
|
|
}
|
|
SpConcatenatePaths( CompleteFileName, FileName );
|
|
|
|
RtlInitUnicodeString( &UnicodeFileName,
|
|
CompleteFileName );
|
|
|
|
InitializeObjectAttributes( &ObjectAttributes,
|
|
&UnicodeFileName,
|
|
OBJ_CASE_INSENSITIVE,
|
|
NULL,
|
|
NULL );
|
|
|
|
Status = ZwOpenFile( &FileHandle,
|
|
STANDARD_RIGHTS_READ | FILE_READ_ATTRIBUTES | SYNCHRONIZE,
|
|
&ObjectAttributes,
|
|
&IoStatusBlock,
|
|
0,
|
|
FILE_SYNCHRONOUS_IO_NONALERT );
|
|
|
|
if( !NT_SUCCESS( Status ) ) {
|
|
SpMemFree( CompleteFileName );
|
|
KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_WARNING_LEVEL, "SETUP: ZwOpenFile() failed. File = %ls, Status = %x\n",FileName, Status ) );
|
|
return( Status );
|
|
}
|
|
|
|
Status = SpGetFileSize( FileHandle, Size );
|
|
ZwClose( FileHandle );
|
|
SpMemFree( CompleteFileName );
|
|
|
|
if( !NT_SUCCESS( Status ) ) {
|
|
KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_WARNING_LEVEL, "SETUP: SpGetFileSize() failed. File = %ls, Status = %x\n",FileName, Status ) );
|
|
return( Status );
|
|
}
|
|
return( Status );
|
|
}
|
|
|
|
|
|
VOID
|
|
SpVerifyNoCompression(
|
|
IN PWSTR FileName
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Determine if the file is compressed (via NTFS compression), and if so,
|
|
uncompress it.
|
|
|
|
Arguments:
|
|
|
|
FileName - Name of the file that must be uncompressed.
|
|
|
|
Return Value:
|
|
|
|
none
|
|
|
|
--*/
|
|
|
|
{
|
|
HANDLE FileHandle;
|
|
IO_STATUS_BLOCK IoStatusBlock;
|
|
UNICODE_STRING UnicodeString;
|
|
OBJECT_ATTRIBUTES Obja;
|
|
NTSTATUS Status;
|
|
FILE_BASIC_INFORMATION BasicFileInfo;
|
|
|
|
INIT_OBJA(&Obja, &UnicodeString, FileName);
|
|
Status = ZwCreateFile(
|
|
&FileHandle,
|
|
0,
|
|
&Obja,
|
|
&IoStatusBlock,
|
|
NULL,
|
|
FILE_ATTRIBUTE_NORMAL,
|
|
FILE_SHARE_READ | FILE_SHARE_WRITE,
|
|
FILE_OPEN,
|
|
0,
|
|
NULL,
|
|
0
|
|
);
|
|
|
|
if(!NT_SUCCESS(Status)) {
|
|
//
|
|
// Ignore error.
|
|
//
|
|
KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_WARNING_LEVEL, "SETUP: SpVerifyNoCompression unable to open file %ws (%lx)\n", FileName, Status));
|
|
return;
|
|
}
|
|
|
|
Status = ZwQueryInformationFile(
|
|
FileHandle,
|
|
&IoStatusBlock,
|
|
&BasicFileInfo,
|
|
sizeof(BasicFileInfo),
|
|
FileBasicInformation
|
|
);
|
|
|
|
if(!NT_SUCCESS(Status)) {
|
|
KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_WARNING_LEVEL, "SETUP: SpVerifyNoCompression unable to get basic file info for %ws (%lx)\n", FileName, Status));
|
|
goto ComprVerifyDone;
|
|
}
|
|
|
|
if(BasicFileInfo.FileAttributes & FILE_ATTRIBUTE_COMPRESSED) {
|
|
|
|
USHORT CompressionState = 0;
|
|
|
|
Status = ZwFsControlFile(
|
|
FileHandle,
|
|
NULL,
|
|
NULL,
|
|
NULL,
|
|
&IoStatusBlock,
|
|
FSCTL_SET_COMPRESSION,
|
|
&CompressionState,
|
|
sizeof(CompressionState),
|
|
NULL,
|
|
0
|
|
);
|
|
if(!NT_SUCCESS(Status)) {
|
|
KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_WARNING_LEVEL, "SETUP: SpVerifyNoCompression unable to uncompress %ws (%lx)\n", FileName, Status));
|
|
}
|
|
}
|
|
|
|
ComprVerifyDone:
|
|
ZwClose(FileHandle);
|
|
return;
|
|
}
|