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