Leaked source code of windows server 2003
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

/*++
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;
}