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