windows-nt/Source/XPSP1/NT/admin/pchealth/sr/kernel/lookup.c

981 lines
24 KiB
C
Raw Permalink Normal View History

2020-09-26 03:20:57 -05:00
/*++
Copyright (c) 1998-1999 Microsoft Corporation
Module Name:
lookup.c
Abstract:
this is the sr lookup functionlity implementation
Author:
Kanwaljit Marok (kmarok) 01-May-2000
Revision History:
--*/
#include "precomp.h"
//
// Include hlist.c to use the inline funtions
//
#include "hlist.c"
#include "ptree.c"
//
// Internal helper APIs
//
static
NTSTATUS
SrOpenLookupBlob(
IN PUNICODE_STRING pFileName,
IN PDEVICE_OBJECT pTargetDevice,
OUT PBLOB_INFO pBlobInfo
);
//
// linker commands
//
#ifdef ALLOC_PRAGMA
#pragma alloc_text( PAGE, SrOpenLookupBlob )
#pragma alloc_text( PAGE, SrLoadLookupBlob )
#pragma alloc_text( PAGE, SrReloadLookupBlob )
#pragma alloc_text( PAGE, SrFreeLookupBlob )
#pragma alloc_text( PAGE, SrIsExtInteresting )
#pragma alloc_text( PAGE, SrIsPathInteresting )
#endif // ALLOC_PRAGMA
//++
// Function:
// SrOpenLookupBlob
//
// Description:
// This function loads the lookup blob in memory and
// sets the appropriate pointers for lookup.
//
// Arguments:
//
// Return Value:
// This function returns STATUS_XXX
//--
static
NTSTATUS
SrOpenLookupBlob(
IN PUNICODE_STRING pFileName,
IN PDEVICE_OBJECT pTargetDevice,
OUT PBLOB_INFO pBlobInfo
)
{
NTSTATUS Status;
OBJECT_ATTRIBUTES oa;
IO_STATUS_BLOCK IoStatusBlock;
HANDLE Handle = NULL;
PLIST_ENTRY pListEntry;
PSR_DEVICE_EXTENSION pExtension;
static char blobFailureMessage[] = "sr!System Restore's BLOB file \"%wZ\" is invalid.\n";
PAGED_CODE();
ASSERT(pFileName);
ASSERT(pBlobInfo);
ASSERT( IS_BLOB_LOCK_ACQUIRED() );
try
{
//
// Zero out the pointers that get initialized when the
// blob is successfully read into the memory from disk
//
pBlobInfo->LookupBlob = NULL;
pBlobInfo->LookupTree = NULL;
pBlobInfo->LookupList = NULL;
pBlobInfo->DefaultType= NODE_TYPE_UNKNOWN;
//
// open and read the file
//
InitializeObjectAttributes( &oa,
pFileName,
OBJ_KERNEL_HANDLE,
NULL,
NULL );
Status = SrIoCreateFile(
&Handle,
GENERIC_READ | SYNCHRONIZE,
&oa,
&IoStatusBlock,
0,
FILE_ATTRIBUTE_NORMAL,
FILE_SHARE_READ,
FILE_OPEN,
FILE_SYNCHRONOUS_IO_NONALERT,
NULL,
0,
0,
pTargetDevice );
if (NT_SUCCESS(Status))
{
DWORD dwBytesRead = 0, dwBytes = 0;
LARGE_INTEGER nOffset;
BlobHeader blobHeader;
//
// Read the blob header
//
nOffset.QuadPart = 0;
dwBytes = sizeof(blobHeader);
Status = ZwReadFile(
Handle,
NULL,
NULL,
NULL,
&IoStatusBlock,
&blobHeader,
dwBytes,
&nOffset,
NULL
);
if (NT_SUCCESS(Status))
{
//
// need to do some sanity check on the header
//
if ( !VERIFY_BLOB_VERSION(&blobHeader) ||
!VERIFY_BLOB_MAGIC (&blobHeader) )
{
SrTrace( BLOB_VERIFICATION, (blobFailureMessage, pFileName) );
Status = STATUS_FILE_CORRUPT_ERROR;
leave;
}
pBlobInfo->LookupBlob = SR_ALLOCATE_POOL(
NonPagedPool,
blobHeader.m_dwMaxSize,
SR_LOOKUP_TABLE_TAG );
if( pBlobInfo->LookupBlob )
{
//
// Read the entire file now
//
nOffset.QuadPart = 0;
dwBytes = blobHeader.m_dwMaxSize;
Status = ZwReadFile(
Handle,
NULL,
NULL,
NULL,
&IoStatusBlock,
pBlobInfo->LookupBlob,
dwBytes,
&nOffset,
NULL
);
if (NT_SUCCESS(Status))
{
//
// TODO: verify that size of the file matched the
// size from the header
//
//
// Setup the lookup pointers properly in blobinfo
//
pBlobInfo->LookupTree = pBlobInfo->LookupBlob +
sizeof(blobHeader);
pBlobInfo->LookupList = pBlobInfo->LookupTree +
BLOB_MAXSIZE((pBlobInfo->LookupTree));
pBlobInfo->DefaultType = TREE_HEADER((pBlobInfo->LookupTree))->m_dwDefault;
//
// Verify the individual blobs
//
if (!SrVerifyBlob(pBlobInfo->LookupBlob)) {
SrTrace( BLOB_VERIFICATION,
(blobFailureMessage,pFileName) );
Status = STATUS_FILE_CORRUPT_ERROR;
leave;
}
}
}
else
{
Status = STATUS_INSUFFICIENT_RESOURCES;
}
}
}
else
{
SrTrace( VERBOSE_ERRORS,
("sr!SrOpenLookupBlob: Cannot Open Blob file \"%wZ\"\n",
pFileName) );
}
//
// The new blob was loaded successfully, perge all contexts on all
// volumes since what is interesting and what is not interesting
// may have changed.
//
ASSERT(!IS_DEVICE_EXTENSION_LIST_LOCK_ACQUIRED());
try
{
SrAcquireDeviceExtensionListLockShared();
for (pListEntry = _globals.DeviceExtensionListHead.Flink;
pListEntry != &_globals.DeviceExtensionListHead;
pListEntry = pListEntry->Flink)
{
pExtension = CONTAINING_RECORD( pListEntry,
SR_DEVICE_EXTENSION,
ListEntry );
ASSERT(IS_VALID_SR_DEVICE_EXTENSION(pExtension));
//
// Skip Control Device Objects.
//
if (!FlagOn(pExtension->FsType,SrFsControlDeviceObject))
{
SrDeleteAllContexts( pExtension );
}
}
}
finally
{
SrReleaseDeviceExtensionListLock();
}
}
finally
{
Status = FinallyUnwind(SrOpenLookupBlob, Status);
//
// close the blob file handle
//
if (Handle)
{
ZwClose( Handle );
}
//
// incase of a failure free up the resources
//
if (!NT_SUCCESS(Status))
{
if( pBlobInfo->LookupBlob )
{
SR_FREE_POOL( pBlobInfo->LookupBlob, SR_LOOKUP_TABLE_TAG );
}
pBlobInfo->LookupBlob = NULL;
pBlobInfo->LookupTree = NULL;
pBlobInfo->LookupList = NULL;
pBlobInfo->DefaultType= NODE_TYPE_UNKNOWN;
}
}
RETURN(Status);
}
//
// Public APIs called by the filer
//
//++
// Function:
// SrLoadLookupBlob
//
// Description:
// This function loads the lookup blob in memory and
// sets the appropriate pointers for lookup.
//
// Arguments:
//
// Return Value:
// This function returns STATUS_XXX
//--
NTSTATUS
SrLoadLookupBlob(
IN PUNICODE_STRING pFileName,
IN PDEVICE_OBJECT pTargetDevice,
OUT PBLOB_INFO pBlobInfo
)
{
NTSTATUS Status;
PAGED_CODE();
ASSERT( pFileName );
ASSERT( pBlobInfo );
try
{
SrAcquireBlobLockExclusive();
//
// if somebody else did it, bail out
//
if (global->BlobInfoLoaded)
{
Status = STATUS_SUCCESS;
leave;
}
//
// initialize return information
//
RtlZeroMemory( pBlobInfo, sizeof( BLOB_INFO ) );
//
// Try and open the lookup blob
//
Status = SrOpenLookupBlob( pFileName,
pTargetDevice,
pBlobInfo );
//
// If we failed to read the file for some reason,
// reinitlialize the return info
//
if ( NT_SUCCESS( Status ) )
{
SrTrace(LOOKUP, ("Loaded lookup blob :%wZ\n", pFileName) );
global->BlobInfoLoaded = TRUE;
}
else
{
SrFreeLookupBlob( pBlobInfo );
}
}
finally
{
SrReleaseBlobLock();
}
RETURN(Status);
}
//++
// Function:
// SrReloadLookupBlob
//
// Description:
// This function loads the lookup blob in memory and
// sets the appropriate pointers for lookup.
//
// Arguments:
// Pointer to LookupBlob
// Pointer to BlobInfo structure
//
// Return Value:
// This function returns STATUS_XXX
//--
NTSTATUS
SrReloadLookupBlob(
IN PUNICODE_STRING pFileName,
IN PDEVICE_OBJECT pTargetDevice,
OUT PBLOB_INFO pBlobInfo
)
{
NTSTATUS Status = STATUS_UNSUCCESSFUL;
BLOB_INFO OldBlobInfo;
PAGED_CODE();
ASSERT( pFileName != NULL );
ASSERT( pBlobInfo != NULL );
ASSERT( !IS_BLOB_LOCK_ACQUIRED() );
try
{
SrAcquireBlobLockExclusive();
if (global->BlobInfoLoaded == 0)
{
Status = SrLoadLookupBlob( pFileName,
pTargetDevice,
pBlobInfo );
leave;
}
//
// Save the current blob info
//
RtlCopyMemory( &OldBlobInfo, pBlobInfo, sizeof( BLOB_INFO ) );
//
// Open the new blob file
//
Status = SrOpenLookupBlob( pFileName,
pTargetDevice,
pBlobInfo );
if(NT_SUCCESS(Status))
{
//
// Free up the memory taken up by the old blob
//
if (OldBlobInfo.LookupBlob)
{
SR_FREE_POOL( OldBlobInfo.LookupBlob, SR_LOOKUP_TABLE_TAG );
}
SrTrace(LOOKUP, ("Reloaded lookup blob :%wZ\n", pFileName) );
}
else
{
//
// Copy the old information back in the original context
//
RtlCopyMemory( pBlobInfo, &OldBlobInfo, sizeof( BLOB_INFO ) );
SrTrace(LOOKUP, (" Cannot reload blob :%wZ\n", pFileName) );
}
}
finally
{
if (NT_SUCCESS_NO_DBGBREAK( Status ))
{
//
// The blob has been reload successfully, so make sure that the
// global BlobError flag is cleared.
//
// We do this here because we are still holding the blob lock.
//
_globals.HitErrorLoadingBlob = FALSE;
}
SrReleaseBlobLock();
}
RETURN(Status);
}
//++
// Function:
// SrFreeLookupBlob
//
// Description:
// This function Frees the lookup blob in memory
//
// Arguments:
// Pointer to BlobInfo structure
//
// Return Value:
// This function returns STATUS_XXX
//--
NTSTATUS
SrFreeLookupBlob(
IN PBLOB_INFO pBlobInfo
)
{
NTSTATUS Status = STATUS_SUCCESS;
PAGED_CODE();
ASSERT( pBlobInfo );
try
{
SrAcquireBlobLockExclusive();
if (_globals.BlobInfoLoaded == 0)
{
//
// Reset our error flag here.
//
_globals.HitErrorLoadingBlob = FALSE;
leave;
}
if( pBlobInfo->LookupBlob )
{
SR_FREE_POOL( pBlobInfo->LookupBlob, SR_LOOKUP_TABLE_TAG );
pBlobInfo->LookupBlob = NULL;
}
RtlZeroMemory( pBlobInfo, sizeof(BLOB_INFO) );
pBlobInfo->DefaultType = NODE_TYPE_UNKNOWN;
SrTrace(LOOKUP, ("Freed lookup blob\n") );
global->BlobInfoLoaded = 0;
}
finally
{
SrReleaseBlobLock();
}
RETURN(Status);
}
//++
// Function:
// SrIsExtInteresting
//
// Description:
// This function checks the file extension in the blob to
// see if we care about it
//
// Arguments:
// Pointer to BlobInfo structure
// Pointer to Path
// Pointer to boolean return value
//
// Return Value:
// This function returns TRUE/FALSE
//--
NTSTATUS
SrIsExtInteresting(
IN PUNICODE_STRING pFileName,
OUT PBOOLEAN pInteresting
)
{
BOOL fRet = FALSE;
NTSTATUS Status = STATUS_SUCCESS;
INT iType = 0;
BOOL fPathHasExt = FALSE;
BOOL fMatch = FALSE;
PAGED_CODE();
//
// check parameters and lookup info
//
ASSERT(pFileName);
ASSERT(pInteresting);
//
// Lookup code is enclosed in an exception handler to protect against
// bad memroy accesses generated by corrupt lookup data
//
try
{
*pInteresting = FALSE;
//
// CODEWORK : put some blob verification code,
// magicnum, type etc
//
//
// Take the blob lock so that other threads won't change
// the blob while we are looking up. Note that the blob
// can be gone after we get the lock.
//
SrAcquireBlobLockShared();
if ( !global->BlobInfoLoaded ||
!global->BlobInfo.LookupList )
{
Status = SR_STATUS_VOLUME_DISABLED;
leave;
}
//
// parse the filename for lookup in the mem blob
//
fMatch = MatchExtension(
global->BlobInfo.LookupList,
pFileName,
&iType,
&fPathHasExt );
if ( !fMatch )
{
//
// Extension didn't match, so setting to default type
//
iType = global->BlobInfo.DefaultType;
}
if ( !fPathHasExt )
{
//
// If the path didn't contain an extension then we should
// treat it as an exclude
//
iType = NODE_TYPE_EXCLUDE;
}
//
// If type is still unknown then set the type to the default.
//
if ( NODE_TYPE_UNKNOWN == iType )
{
iType = global->BlobInfo.DefaultType;
}
*pInteresting = (iType != NODE_TYPE_EXCLUDE);
// SrTrace(LOOKUP, ("Extention Interest:%d\n", *pInteresting) );
}
finally
{
Status = FinallyUnwind(SrIsExtInteresting, Status);
SrReleaseBlobLock();
if (!NT_SUCCESS(Status))
{
*pInteresting = FALSE;
}
}
RETURN(Status);
}
//++
// Function:
// SrIsPathInteresting
//
// Description:
// This function checks the file name in the blob to
// see if we care about it
//
// Arguments:
// Pointer to BlobInfo structure
// Pointer to Full Path
// Pointer to Volume Prefix
// Boolean to indicate if this path is a directory
// Pointer to boolean return value
//
// Return Value:
// This function returns TRUE/FALSE
//--
NTSTATUS
SrIsPathInteresting(
IN PUNICODE_STRING pFullPath,
IN PUNICODE_STRING pVolPrefix,
IN BOOLEAN IsDirectory,
OUT PBOOLEAN pInteresting
)
{
BOOL fRet = FALSE;
NTSTATUS Status = STATUS_UNSUCCESSFUL;
PBYTE pFileName = NULL;
WORD FileNameSize = 0;
UNICODE_STRING localName;
PAGED_CODE();
//
// check parameters and lookup info
//
ASSERT(pFullPath);
ASSERT(pVolPrefix);
ASSERT(pFullPath->Length >= pVolPrefix->Length);
ASSERT(pInteresting);
try
{
*pInteresting = FALSE;
//
// Take the blob lock so that other threads won't change
//
SrAcquireBlobLockShared();
if ( !global->BlobInfoLoaded ||
!global->BlobInfo.LookupList ||
!global->BlobInfo.LookupTree )
{
Status = SR_STATUS_VOLUME_DISABLED;
leave;
}
ASSERT(global->BlobInfo.DefaultType != NODE_TYPE_UNKNOWN );
//
// allocate space for a parsed path
//
FileNameSize = CALC_PPATH_SIZE( pFullPath->Length/sizeof(WCHAR) );
pFileName = ExAllocatePoolWithTag( PagedPool,
FileNameSize,
SR_FILENAME_BUFFER_TAG );
if (NULL == pFileName)
{
Status = STATUS_INSUFFICIENT_RESOURCES;
leave;
}
//
// parse the filename for lookup in the mem blob
//
fRet = ConvertToParsedPath(
pFullPath->Buffer,
pFullPath->Length/sizeof(WCHAR),
pFileName,
FileNameSize );
if(fRet)
{
INT iNode = -1;
INT iType = 0;
INT iLevel = 0;
BOOL fExactMatch = FALSE;
BOOL fMatch = FALSE;
//
// Lookup the parsed path in the tree blob
//
fMatch = MatchPrefix(
global->BlobInfo.LookupTree,
TREE_ROOT_NODE,
((path_t)pFileName)->pp_elements,
&iNode,
&iLevel,
&iType,
NULL,
&fExactMatch);
if (fMatch)
{
SrTrace(LOOKUP,
("Found match in pathtree N: %d L:%d T:%d\n",
iNode, iLevel, iType));
}
//
// Lookup in __ALLVOLUMES__ to see is there is a match
//
if ( NODE_TYPE_UNKNOWN == iType ||
(!fExactMatch && NODE_TYPE_EXCLUDE != iType )
)
{
PBYTE pRelFileName = NULL;
INT RelFileNameLen = 0;
//
// Lookup only volume relative filename
//
RelFileNameLen = sizeof(L'\\' ) +
sizeof(ALLVOLUMES_PATH_W) +
(pFullPath->Length - pVolPrefix->Length);
pRelFileName = ExAllocatePoolWithTag( PagedPool,
RelFileNameLen,
SR_FILENAME_BUFFER_TAG );
if (NULL == pRelFileName)
{
Status = STATUS_INSUFFICIENT_RESOURCES;
leave;
}
localName.Buffer = &pFullPath->Buffer[pVolPrefix->Length/sizeof(WCHAR)];
localName.Length = pFullPath->Length - pVolPrefix->Length;
localName.MaximumLength = localName.Length;
RelFileNameLen = swprintf(
(LPWSTR)pRelFileName,
L"\\%s%wZ",
ALLVOLUMES_PATH_W,
&localName );
fRet = ConvertToParsedPath(
(LPWSTR)pRelFileName,
(USHORT)RelFileNameLen,
pFileName,
FileNameSize );
if(fRet)
{
//
// Lookup the parsed path in the appropriate protion of
// the tree blob NTROOT\\__ALLVOLUMES__
//
fMatch = MatchPrefix(
global->BlobInfo.LookupTree,
TREE_ROOT_NODE,
((path_t)pFileName)->pp_elements,
&iNode,
&iLevel,
&iType,
NULL,
&fExactMatch);
if (fMatch)
{
SrTrace(LOOKUP,
("Found match in pathtree N: %d L:%d T:%d\n",
iNode, iLevel, iType));
}
}
else
{
CHECK_STATUS( Status );
}
ExFreePoolWithTag( pRelFileName, SR_FILENAME_BUFFER_TAG );
NULLPTR( pRelFileName );
}
if ( !IsDirectory )
{
//
// If path didn't match or matched partially, we need to
// lookup the extension list also
//
if ( NODE_TYPE_UNKNOWN == iType ||
(!fExactMatch && NODE_TYPE_EXCLUDE != iType )
)
{
BOOL fPathHasExt = FALSE;
fMatch = MatchExtension(
global->BlobInfo.LookupList,
pFullPath,
&iType,
&fPathHasExt );
if ( !fMatch )
{
//
// Extension didn't match, setting to default type
//
iType = global->BlobInfo.DefaultType;
}
if ( !fPathHasExt )
{
//
// If path didn't contain an extension then
// treat it as an exclude
//
iType = NODE_TYPE_EXCLUDE;
}
}
//
// If still type is unknown then set type to the default.
//
if ( NODE_TYPE_UNKNOWN == iType )
{
iType = global->BlobInfo.DefaultType;
}
}
else
{
//
// If this is directory operation and no match found in
// tree then treat is as include.
//
if ( NODE_TYPE_UNKNOWN == iType )
{
iType = NODE_TYPE_INCLUDE;
}
}
*pInteresting = (iType != NODE_TYPE_EXCLUDE);
Status = STATUS_SUCCESS;
}
else
{
SrTrace( LOOKUP,
( "ConvertToParsedPath Failed : %wZ\n", pFullPath )
);
CHECK_STATUS( Status );
}
// SrTrace(LOOKUP, ("Path Interest:%d\n", *pInteresting) );
}
finally
{
Status = FinallyUnwind(SrIsPathInteresting, Status);
SrReleaseBlobLock();
if (pFileName != NULL)
{
ExFreePoolWithTag( pFileName, SR_FILENAME_BUFFER_TAG );
NULLPTR( pFileName );;
}
if (!NT_SUCCESS(Status))
{
*pInteresting = FALSE;
}
}
RETURN(Status);
}