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.
 
 
 
 
 
 

1220 lines
38 KiB

/*++
Copyright (c) Microsoft Corporation. All rights reserved.
Module Name:
fileq1.c
Abstract:
Miscellaneous setup file queue routines.
Author:
Ted Miller (tedm) 15-Feb-1995
Revision History:
--*/
#include "precomp.h"
#pragma hdrstop
HSPFILEQ
WINAPI
SetupOpenFileQueue(
VOID
)
/*++
Routine Description:
Create a setup file queue.
Arguments:
None.
Return Value:
Handle to setup file queue. INVALID_HANDLE_VALUE if error occurs (GetLastError reports the error)
--*/
{
PSP_FILE_QUEUE Queue = NULL;
DWORD rc;
DWORD status = ERROR_INVALID_DATA;
try {
//
// Allocate a queue structure.
//
Queue = MyMalloc(sizeof(SP_FILE_QUEUE));
if(!Queue) {
status = ERROR_NOT_ENOUGH_MEMORY;
leave;
}
ZeroMemory(Queue,sizeof(SP_FILE_QUEUE));
//
// Create a string table for this queue.
//
Queue->StringTable = pSetupStringTableInitialize();
if(!Queue->StringTable) {
status = ERROR_NOT_ENOUGH_MEMORY;
leave;
}
Queue->TargetLookupTable = pSetupStringTableInitializeEx( sizeof(SP_TARGET_ENT), 0 );
if(!Queue->TargetLookupTable) {
status = ERROR_NOT_ENOUGH_MEMORY;
leave;
}
Queue->BackupInfID = -1; // no Backup INF
Queue->BackupInstanceID = -1; // no Backup INF
Queue->RestorePathID = -1; // no Restore directory
Queue->Flags = FQF_TRY_SIS_COPY;
Queue->SisSourceDirectory = NULL;
Queue->SisSourceHandle = INVALID_HANDLE_VALUE;
Queue->Signature = SP_FILE_QUEUE_SIG;
//
// Retrieve the codesigning policy currently in effect (policy in
// effect is for non-driver signing behavior until we are told
// otherwise).
//
Queue->DriverSigningPolicy = pSetupGetCurrentDriverSigningPolicy(FALSE);
//
// If and when we discover that this is a device installation for a
// WHQL-logoable class (or if we discover we're dealing with an
// exception package, or an INF that's replacing system-protected
// files), then we'll clear this bit that allows for Authenticode
// signatures.
//
Queue->DriverSigningPolicy |= DRIVERSIGN_ALLOW_AUTHENTICODE;
//
// Initialize the device description field to the null string id.
//
Queue->DeviceDescStringId = -1;
//
// Initialize the override catalog filename to the null string id.
//
Queue->AltCatalogFile = -1;
//
// Createa a generic log context
//
rc = CreateLogContext(NULL, TRUE, &Queue->LogContext);
if (rc != NO_ERROR) {
status = rc;
leave;
}
status = NO_ERROR;
} except (EXCEPTION_EXECUTE_HANDLER) {
//
// do nothing; this just allows us to catch errors
//
}
if (status == NO_ERROR) {
//
// The address of the queue structure is the queue handle.
//
return(Queue);
}
//
// failure cleanup
//
if (Queue != NULL) {
if (Queue->StringTable) {
pSetupStringTableDestroy(Queue->StringTable);
}
if (Queue->TargetLookupTable) {
pSetupStringTableDestroy(Queue->TargetLookupTable);
}
if(Queue->LogContext) {
DeleteLogContext(Queue->LogContext);
}
MyFree(Queue);
}
//
// return with this on error
//
SetLastError(status);
return (HSPFILEQ)INVALID_HANDLE_VALUE;
}
BOOL
WINAPI
SetupCloseFileQueue(
IN HSPFILEQ QueueHandle
)
/*++
Routine Description:
Destroy a setup file queue. Enqueued operations are not performed.
Arguments:
QueueHandle - supplies handle to setup file queue to be destroyed.
Return Value:
If the function succeeds, the return value is TRUE.
If the function fails, the return value is FALSE. To get extended error
information, call GetLastError. Presently, the only error that can be
encountered is ERROR_INVALID_HANDLE or ERROR_FILEQUEUE_LOCKED, which will occur if someone (typically,
a device installation parameter block) is referencing this queue handle.
--*/
{
PSP_FILE_QUEUE Queue;
PSP_FILE_QUEUE_NODE Node,NextNode;
PSP_DELAYMOVE_NODE DelayMoveNode,NextDelayMoveNode;
PSP_UNWIND_NODE UnwindNode,NextUnwindNode;
PSOURCE_MEDIA_INFO Media,NextMedia;
BOOL b;
PSPQ_CATALOG_INFO Catalog,NextCatalog;
DWORD status = ERROR_INVALID_HANDLE;
if (QueueHandle == NULL || QueueHandle == (HSPFILEQ)INVALID_HANDLE_VALUE) {
SetLastError(ERROR_INVALID_HANDLE);
return FALSE;
}
Queue = (PSP_FILE_QUEUE)QueueHandle;
//
// Primitive queue validation.
//
b = TRUE;
try {
if(Queue->Signature != SP_FILE_QUEUE_SIG) {
b = FALSE;
}
} except(EXCEPTION_EXECUTE_HANDLER) {
b = FALSE;
}
if(!b) {
SetLastError(ERROR_INVALID_HANDLE);
return(FALSE);
}
try {
//
// Don't close the queue if someone is still referencing it.
//
if(Queue->LockRefCount) {
WriteLogEntry(
Queue->LogContext,
SETUP_LOG_ERROR,
MSG_LOG_FILEQUEUE_IN_USE,
NULL); // text message
status = ERROR_FILEQUEUE_LOCKED;
leave;
}
//
// we may have some unwinding to do, but assume we succeeded
// ie, delete temp files and cleanup memory used
//
pSetupUnwindAll(Queue, TRUE);
//
// If the queue wasn't committed and we are backup aware and this is
// a device install then we need to clean up any backup directories and
// registry entries that we created since we have already unwound the
// queue up above.
//
if (!(Queue->Flags & FQF_QUEUE_ALREADY_COMMITTED) &&
(Queue->Flags & FQF_DEVICE_BACKUP)) {
pSetupCleanupBackup(Queue);
}
Queue->Signature = 0;
//
// Free the DelayMove list
//
for(DelayMoveNode = Queue->DelayMoveQueue; DelayMoveNode; DelayMoveNode = NextDelayMoveNode) {
NextDelayMoveNode = DelayMoveNode->NextNode;
MyFree(DelayMoveNode);
}
//
// Free the queue nodes.
//
for(Node=Queue->DeleteQueue; Node; Node=NextNode) {
NextNode = Node->Next;
MyFree(Node);
}
for(Node=Queue->RenameQueue; Node; Node=NextNode) {
NextNode = Node->Next;
MyFree(Node);
}
// Free the backup queue nodes
for(Node=Queue->BackupQueue; Node; Node=NextNode) {
NextNode = Node->Next;
MyFree(Node);
}
// Free the unwind queue nodes
for(UnwindNode=Queue->UnwindQueue; UnwindNode; UnwindNode=NextUnwindNode) {
NextUnwindNode = UnwindNode->NextNode;
MyFree(UnwindNode);
}
//
// Free the media structures and associated copy queues.
//
for(Media=Queue->SourceMediaList; Media; Media=NextMedia) {
for(Node=Media->CopyQueue; Node; Node=NextNode) {
NextNode = Node->Next;
MyFree(Node);
}
NextMedia = Media->Next;
MyFree(Media);
}
//
// Free the catalog nodes.
//
for(Catalog=Queue->CatalogList; Catalog; Catalog=NextCatalog) {
NextCatalog = Catalog->Next;
if(Catalog->hWVTStateData) {
MYASSERT(Catalog->Flags & CATINFO_FLAG_PROMPT_FOR_TRUST);
pSetupCloseWVTStateData(Catalog->hWVTStateData);
}
MyFree(Catalog);
}
//
// Free the validation platform information (if any)
//
if(Queue->ValidationPlatform) {
MyFree(Queue->ValidationPlatform);
}
//
// Free the string table.
//
pSetupStringTableDestroy(Queue->StringTable);
//
// (jamiehun) Free the target lookup table.
//
pSetupStringTableDestroy(Queue->TargetLookupTable);
//
// Free SIS-related fields.
//
if (Queue->SisSourceHandle != INVALID_HANDLE_VALUE) {
CloseHandle(Queue->SisSourceHandle);
}
if (Queue->SisSourceDirectory != NULL) {
MyFree(Queue->SisSourceDirectory);
}
//
// Unreference log context
//
DeleteLogContext(Queue->LogContext);
//
// Free any context handles that may have been allocated during the
// lifetime of this queue.
//
pSetupFreeVerifyContextMembers(&(Queue->VerifyContext));
//
// Free the queue structure itself.
//
MyFree(Queue);
status = NO_ERROR;
} except (EXCEPTION_EXECUTE_HANDLER) {
//
// do nothing; this just allows us to catch errors
//
}
if(status != NO_ERROR) {
SetLastError(status);
return FALSE;
}
return TRUE;
}
#ifdef UNICODE
//
// ANSI version
//
BOOL
WINAPI
SetupSetFileQueueAlternatePlatformA(
IN HSPFILEQ QueueHandle,
IN PSP_ALTPLATFORM_INFO_V2 AlternatePlatformInfo, OPTIONAL
IN PCSTR AlternateDefaultCatalogFile OPTIONAL
)
{
PWSTR UAlternateDefaultCatalogFile;
DWORD Err;
if(AlternateDefaultCatalogFile) {
Err = pSetupCaptureAndConvertAnsiArg(AlternateDefaultCatalogFile,
&UAlternateDefaultCatalogFile
);
if(Err != NO_ERROR) {
SetLastError(Err);
return FALSE;
}
} else {
UAlternateDefaultCatalogFile = NULL;
}
if(SetupSetFileQueueAlternatePlatformW(QueueHandle,
AlternatePlatformInfo,
UAlternateDefaultCatalogFile)) {
Err = NO_ERROR;
} else {
Err = GetLastError();
MYASSERT(Err != NO_ERROR);
}
if(UAlternateDefaultCatalogFile) {
MyFree(UAlternateDefaultCatalogFile);
}
SetLastError(Err);
return (Err == NO_ERROR);
}
#else
//
// Unicode stub
//
BOOL
WINAPI
SetupSetFileQueueAlternatePlatformW(
IN HSPFILEQ QueueHandle,
IN PSP_ALTPLATFORM_INFO_V2 AlternatePlatformInfo, OPTIONAL
IN PCWSTR AlternateDefaultCatalogFile OPTIONAL
)
{
UNREFERENCED_PARAMETER(QueueHandle);
UNREFERENCED_PARAMETER(AlternatePlatformInfo);
UNREFERENCED_PARAMETER(AlternateDefaultCatalogFile);
SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
return(FALSE);
}
#endif
BOOL
WINAPI
SetupSetFileQueueAlternatePlatform(
IN HSPFILEQ QueueHandle,
IN PSP_ALTPLATFORM_INFO_V2 AlternatePlatformInfo, OPTIONAL
IN PCTSTR AlternateDefaultCatalogFile OPTIONAL
)
/*++
Routine Description:
This API associates the specified file queue with an alternate platform in
order to allow for non-native signature verification (e.g., verifying Win98
files on Windows NT, verifying x86 Windows NT files on Amd64, etc.). The
verification is done using the corresponding catalog files specified via
platform-specific CatalogFile= entries in the source media descriptor INFs
(i.e., INFs containing [SourceDisksNames] and [SourceDisksFiles] sections
used when queueing files to be copied).
The caller may also optionally specify a default catalog file, to be used
for verification of files that have no associated catalog, thus would
otherwise be globally validated (e.g., files queued up from the system
layout.inf). A side-effect of this is that INFs with no CatalogFile= entry
are considered valid, even if they exist outside of %windir%\Inf.
If this file queue is subsequently committed, the nonnative catalogs will be
installed into the system catalog database, just as native catalogs would.
Arguments:
QueueHandle - supplies a handle to the file queue with which the alternate
platform is to be associated.
AlternatePlatformInfo - optionally, supplies the address of a structure
containing information regarding the alternate platform that is to be
used for subsequent validation of files contained in the specified file
queue. If this parameter is not supplied, then the queue's association
with an alternate platform is reset, and is reverted back to the default
(i.e., native) environment. This information is also used in
determining the appropriate platform-specific CatalogFile= entry to be
used when finding out which catalog file is applicable for a particular
source media descriptor INF.
(NOTE: caller may actually pass in a V1 struct instead--we detect this
case and convert the V1 struct into a V2 one.)
AlternateDefaultCatalogFile - optionally, supplies the full path to the
catalog file to be used for verification of files contained in the
specified file queue that are not associated with any particular catalog
(hence would normally be globally validated).
If this parameter is NULL, then the file queue will no longer be
associated with any 'override' catalog, and all validation will take
place normally (i.e., using the standard rules for digital signature
verification via system-supplied and 3rd-party provided INFs/CATs).
If this alternate default catalog is still associated with the file
queue at commit time, it will be installed using its present name, and
will overwrite any existing installed catalog file having that name.
Return Value:
If the function succeeds, the return value is TRUE.
If the function fails, the return value is FALSE. To get extended error
information, call GetLastError.
--*/
{
PSP_FILE_QUEUE Queue;
DWORD Err;
TCHAR PathBuffer[MAX_PATH];
DWORD RequiredSize;
PTSTR TempCharPtr;
LONG AltCatalogStringId;
PSPQ_CATALOG_INFO CatalogNode;
LPCTSTR InfFullPath;
SP_ALTPLATFORM_INFO_V2 AltPlatformInfoV2;
Err = NO_ERROR; // assume success
try {
Queue = (PSP_FILE_QUEUE)QueueHandle;
//
// Now validate the AlternatePlatformInfo parameter.
//
if(AlternatePlatformInfo) {
if(AlternatePlatformInfo->cbSize != sizeof(SP_ALTPLATFORM_INFO_V2)) {
//
// The caller may have passed us in a Version 1 struct, or they
// may have passed us in bad data...
//
if(AlternatePlatformInfo->cbSize == sizeof(SP_ALTPLATFORM_INFO_V1)) {
//
// Flags/Reserved field is reserved in V1
//
if(AlternatePlatformInfo->Reserved) {
Err = ERROR_INVALID_PARAMETER;
goto clean0;
}
//
// Convert the caller-supplied data into Version 2 format.
//
ZeroMemory(&AltPlatformInfoV2, sizeof(AltPlatformInfoV2));
AltPlatformInfoV2.cbSize = sizeof(SP_ALTPLATFORM_INFO_V2);
AltPlatformInfoV2.Platform = ((PSP_ALTPLATFORM_INFO_V1)AlternatePlatformInfo)->Platform;
AltPlatformInfoV2.MajorVersion = ((PSP_ALTPLATFORM_INFO_V1)AlternatePlatformInfo)->MajorVersion;
AltPlatformInfoV2.MinorVersion = ((PSP_ALTPLATFORM_INFO_V1)AlternatePlatformInfo)->MinorVersion;
AltPlatformInfoV2.ProcessorArchitecture = ((PSP_ALTPLATFORM_INFO_V1)AlternatePlatformInfo)->ProcessorArchitecture;
AltPlatformInfoV2.Flags = 0;
AlternatePlatformInfo = &AltPlatformInfoV2;
} else {
Err = ERROR_INVALID_USER_BUFFER;
goto clean0;
}
}
//
// Gotta be either Windows or Windows NT
//
if((AlternatePlatformInfo->Platform != VER_PLATFORM_WIN32_WINDOWS) &&
(AlternatePlatformInfo->Platform != VER_PLATFORM_WIN32_NT)) {
Err = ERROR_INVALID_PARAMETER;
goto clean0;
}
//
// Processor had better be either i386, amd64, or ia64.
//
if((AlternatePlatformInfo->ProcessorArchitecture != PROCESSOR_ARCHITECTURE_INTEL) &&
(AlternatePlatformInfo->ProcessorArchitecture != PROCESSOR_ARCHITECTURE_IA64) &&
(AlternatePlatformInfo->ProcessorArchitecture != PROCESSOR_ARCHITECTURE_AMD64)) {
Err = ERROR_INVALID_PARAMETER;
goto clean0;
}
//
// MajorVersion field must be non-zero (MinorVersion field can be
// anything)
//
if(!AlternatePlatformInfo->MajorVersion) {
Err = ERROR_INVALID_PARAMETER;
goto clean0;
}
//
// Validate structure parameter flags (bits indicating what
// parts of the structure are valid).
//
if((AlternatePlatformInfo->Flags & ~ (SP_ALTPLATFORM_FLAGS_VERSION_RANGE)) != 0) {
Err = ERROR_INVALID_PARAMETER;
goto clean0;
}
//
// fill in version validation range if none supplied by caller
//
if((AlternatePlatformInfo->Flags & SP_ALTPLATFORM_FLAGS_VERSION_RANGE) == 0) {
//
// If caller does not know about FirstValidate*Version,
// version upper and lower bounds are equal.
//
AlternatePlatformInfo->FirstValidatedMajorVersion = AlternatePlatformInfo->MajorVersion;
AlternatePlatformInfo->FirstValidatedMinorVersion = AlternatePlatformInfo->MinorVersion;
AlternatePlatformInfo->Flags |= SP_ALTPLATFORM_FLAGS_VERSION_RANGE;
}
}
//
// OK, the platform info structure checks out. Now, associate the
// default catalog (if supplied) with the file queue, otherwise reset
// any existing association with a default catalog.
//
if(AlternateDefaultCatalogFile) {
RequiredSize = GetFullPathName(AlternateDefaultCatalogFile,
SIZECHARS(PathBuffer),
PathBuffer,
&TempCharPtr
);
if(!RequiredSize) {
Err = GetLastError();
goto clean0;
} else if(RequiredSize >= SIZECHARS(PathBuffer)) {
MYASSERT(0);
Err = ERROR_BUFFER_OVERFLOW;
goto clean0;
}
AltCatalogStringId = pSetupStringTableAddString(Queue->StringTable,
PathBuffer,
STRTAB_CASE_INSENSITIVE | STRTAB_BUFFER_WRITEABLE
);
if(AltCatalogStringId == -1) {
Err = ERROR_NOT_ENOUGH_MEMORY;
goto clean0;
}
} else {
//
// Caller has not supplied an alternate default catalog, so reset
// any existing association.
//
AltCatalogStringId = -1;
}
//
// If we've been passed an AltPlatformInfo structure, then we need to
// process each existing catalog node in our file queue and retrieve the
// appropriate platform-specific CatalogFile= entry.
//
if(AlternatePlatformInfo) {
for(CatalogNode = Queue->CatalogList; CatalogNode; CatalogNode = CatalogNode->Next) {
//
// Get the INF name associated with this catalog node.
//
InfFullPath = pSetupStringTableStringFromId(Queue->StringTable,
CatalogNode->InfFullPath
);
Err = pGetInfOriginalNameAndCatalogFile(NULL,
InfFullPath,
NULL,
NULL,
0,
PathBuffer,
SIZECHARS(PathBuffer),
AlternatePlatformInfo
);
if(Err != NO_ERROR) {
goto clean0;
}
if(*PathBuffer) {
//
// We retrieved a CatalogFile= entry that's pertinent for
// the specified platform from the INF.
//
CatalogNode->AltCatalogFileFromInfPending = pSetupStringTableAddString(
Queue->StringTable,
PathBuffer,
STRTAB_CASE_INSENSITIVE | STRTAB_BUFFER_WRITEABLE
);
if(CatalogNode->AltCatalogFileFromInfPending == -1) {
Err = ERROR_NOT_ENOUGH_MEMORY;
goto clean0;
}
} else {
//
// The INF doesn't specify a CatalogFile= entry for this
// platform.
//
CatalogNode->AltCatalogFileFromInfPending = -1;
}
}
//
// OK, if we get to this point, then we've added all the strings to
// the string table we need to, and we're done opening INFs. We
// should encounter no problems from this point forward, so it's
// safe to commit our changes.
//
for(CatalogNode = Queue->CatalogList; CatalogNode; CatalogNode = CatalogNode->Next) {
CatalogNode->AltCatalogFileFromInf = CatalogNode->AltCatalogFileFromInfPending;
}
}
Queue->AltCatalogFile = AltCatalogStringId;
//
// Finally, update (or reset) the AltPlatformInfo structure in the queue
// with the data the caller specified.
//
if(AlternatePlatformInfo) {
CopyMemory(&(Queue->AltPlatformInfo),
AlternatePlatformInfo,
sizeof(SP_ALTPLATFORM_INFO_V2)
);
Queue->Flags |= FQF_USE_ALT_PLATFORM;
} else {
Queue->Flags &= ~FQF_USE_ALT_PLATFORM;
}
//
// Clear the "catalog verifications done" flags in the queue, so that
// we'll redo them the next time _SetupVerifyQueuedCatalogs is called.
// Also, clear the FQF_DIGSIG_ERRORS_NOUI flag so that the next
// verification error we encounter will relayed to the user (based on
// policy).
//
Queue->Flags &= ~(FQF_DID_CATALOGS_OK | FQF_DID_CATALOGS_FAILED | FQF_DID_CATALOGS_PROMPT_FOR_TRUST | FQF_DIGSIG_ERRORS_NOUI);
//
// Additionally, clear the Authenticode flags from any catalog nodes
// that may have had them.
//
for(CatalogNode = Queue->CatalogList; CatalogNode; CatalogNode = CatalogNode->Next) {
CatalogNode->Flags &=
~(CATINFO_FLAG_AUTHENTICODE_SIGNED | CATINFO_FLAG_PROMPT_FOR_TRUST);
if(CatalogNode->hWVTStateData) {
pSetupCloseWVTStateData(CatalogNode->hWVTStateData);
CatalogNode->hWVTStateData = NULL;
}
}
clean0: ; // nothing to do.
} except(EXCEPTION_EXECUTE_HANDLER) {
Err = ERROR_INVALID_PARAMETER;
}
SetLastError(Err);
return (Err == NO_ERROR);
}
BOOL
pSetupSetQueueFlags(
IN HSPFILEQ QueueHandle,
IN DWORD flags
)
{
PSP_FILE_QUEUE Queue;
DWORD Err = NO_ERROR;
try {
Queue = (PSP_FILE_QUEUE)QueueHandle;
Queue->Flags = flags;
if (Queue->Flags & FQF_QUEUE_FORCE_BLOCK_POLICY) {
Queue->DriverSigningPolicy = DRIVERSIGN_BLOCKING;
}
} except(EXCEPTION_EXECUTE_HANDLER) {
Err = GetExceptionCode();
}
SetLastError(Err);
return (Err == NO_ERROR);
}
DWORD
pSetupGetQueueFlags(
IN HSPFILEQ QueueHandle
)
{
PSP_FILE_QUEUE Queue;
try {
Queue = (PSP_FILE_QUEUE)QueueHandle;
return Queue->Flags;
} except(EXCEPTION_EXECUTE_HANDLER) {
}
return 0;
}
WINSETUPAPI
BOOL
WINAPI
SetupGetFileQueueCount(
IN HSPFILEQ FileQueue,
IN UINT SubQueueFileOp,
OUT PUINT NumOperations
)
/*++
Routine Description:
This API obtains a count of a sub-queue in advance of submitting the queue
Arguments:
FileQueue - Queue to query
SubQueueFileOp - operation
FILEOP_COPY FILEOP_DELETE FILEOP_RENAME FILEOP_BACKUP
NumOperations - ptr to hold the return value - number of files in that queue
Return Value:
If the function succeeds, the return value is TRUE.
If the function fails, the return value is FALSE. To get extended error
information, call GetLastError.
--*/
{
PSP_FILE_QUEUE Queue;
BOOL b;
DWORD status = ERROR_INVALID_HANDLE;
if (FileQueue == NULL || FileQueue == (HSPFILEQ)INVALID_HANDLE_VALUE) {
SetLastError(ERROR_INVALID_HANDLE);
return FALSE;
}
Queue = (PSP_FILE_QUEUE)FileQueue;
b = TRUE;
try {
if(Queue->Signature != SP_FILE_QUEUE_SIG) {
b = FALSE;
}
} except(EXCEPTION_EXECUTE_HANDLER) {
b = FALSE;
}
if(!b) {
SetLastError(ERROR_INVALID_HANDLE);
return(FALSE);
}
try {
//
// Invalid/NULL NumOperations ptr will be caught by exception handling
//
switch (SubQueueFileOp) {
case FILEOP_COPY:
*NumOperations=Queue->CopyNodeCount;
status = NO_ERROR;
break;
case FILEOP_RENAME:
*NumOperations=Queue->RenameNodeCount;
status = NO_ERROR;
break;
case FILEOP_DELETE:
*NumOperations=Queue->DeleteNodeCount;
status = NO_ERROR;
break;
case FILEOP_BACKUP:
*NumOperations=Queue->BackupNodeCount;
status = NO_ERROR;
break;
default:
status = ERROR_INVALID_PARAMETER;
}
} except(EXCEPTION_EXECUTE_HANDLER) {
status = ERROR_INVALID_DATA;
}
SetLastError(status);
return (status==NO_ERROR);
}
WINSETUPAPI
BOOL
WINAPI
SetupGetFileQueueFlags(
IN HSPFILEQ FileQueue,
OUT PDWORD Flags
)
/*++
Routine Description:
This API obtains public viewable flags for FileQueue
Arguments:
FileQueue - Queue to query
Flags - ptr to hold the return value - flags, includes:
SPQ_FLAG_BACKUP_AWARE
SPQ_FLAG_ABORT_IF_UNSIGNED
Return Value:
If the function succeeds, the return value is TRUE.
If the function fails, the return value is FALSE. To get extended error
information, call GetLastError.
--*/
{
PSP_FILE_QUEUE Queue;
BOOL b;
DWORD status = ERROR_INVALID_HANDLE;
if (FileQueue == NULL || FileQueue == (HSPFILEQ)INVALID_HANDLE_VALUE) {
SetLastError(ERROR_INVALID_HANDLE);
return FALSE;
}
Queue = (PSP_FILE_QUEUE)FileQueue;
b = TRUE;
try {
if(Queue->Signature != SP_FILE_QUEUE_SIG) {
b = FALSE;
}
} except(EXCEPTION_EXECUTE_HANDLER) {
b = FALSE;
}
if(!b) {
SetLastError(ERROR_INVALID_HANDLE);
return(FALSE);
}
try {
//
// Invalid/NULL Flags ptr will be caught by exception handling
//
*Flags = (((Queue->Flags & FQF_BACKUP_AWARE) ? SPQ_FLAG_BACKUP_AWARE : 0) |
((Queue->Flags & FQF_ABORT_IF_UNSIGNED) ? SPQ_FLAG_ABORT_IF_UNSIGNED : 0) |
((Queue->Flags & FQF_FILES_MODIFIED ) ? SPQ_FLAG_FILES_MODIFIED : 0));
status = NO_ERROR;
} except(EXCEPTION_EXECUTE_HANDLER) {
status = ERROR_INVALID_DATA;
}
SetLastError(status);
return (status==NO_ERROR);
}
VOID
ResetQueueState(
IN PSP_FILE_QUEUE Queue
)
/*++
Routine Description:
This routine resets an aborted filequeue so that it can be committed yet
again. This is used when a client (e.g., newdev) requests that queue
committal be aborted when unsigned files are encountered (i.e., so they can
set a system restore point), then they want to re-commit the file queue
once the restore point has been established.
Arguments:
Queue - supplies a pointer to the file queue to be reset.
Return Value:
none.
--*/
{
PSP_DELAYMOVE_NODE DelayMoveNode, NextDelayMoveNode;
PSP_UNWIND_NODE UnwindNode, NextUnwindNode;
PSP_FILE_QUEUE_NODE QueueNode;
PSOURCE_MEDIA_INFO Media;
SP_TARGET_ENT TargetInfo;
//
// There should be no need to unwind the queue here, as that should've
// already happened when we failed during _SetupCommitFileQueue.
//
//
// Free the DelayMove list
//
for(DelayMoveNode = Queue->DelayMoveQueue; DelayMoveNode; DelayMoveNode = NextDelayMoveNode) {
NextDelayMoveNode = DelayMoveNode->NextNode;
MyFree(DelayMoveNode);
}
Queue->DelayMoveQueue = Queue->DelayMoveQueueTail = NULL;
//
// Free the unwind queue nodes
//
for(UnwindNode = Queue->UnwindQueue; UnwindNode; UnwindNode = NextUnwindNode) {
NextUnwindNode = UnwindNode->NextNode;
MyFree(UnwindNode);
}
Queue->UnwindQueue = NULL;
//
// Clear the "catalog verifications done" flags in the queue, so that we'll
// redo them the next time _SetupVerifyQueuedCatalogs is called.
//
Queue->Flags &= ~(FQF_DID_CATALOGS_OK | FQF_DID_CATALOGS_FAILED);
//
// Clear the flag that indicates we've already committed the file queue.
//
Queue->Flags &= ~FQF_QUEUE_ALREADY_COMMITTED;
//
// Clear the flag that indicates we didn't successfully back-up all files.
// Since we already unwound out of that queue committal, this flag is no
// longer relevant (although we'll quite likely hit this problem again when
// the client re-commits the file queue).
//
Queue->Flags &= ~FQF_BACKUP_INCOMPLETE;
//
// Clear certain internal flags on all the file queue nodes.
//
#define QUEUE_NODE_BITS_TO_RESET ( INUSE_IN_USE \
| INUSE_INF_WANTS_REBOOT \
| IQF_PROCESSED \
| IQF_MATCH \
| IQF_LAST_MATCH )
//
// Note: neither the IQF_ALLOW_UNSIGNED nor IQF_TARGET_PROTECTED flags
// should be set for any queue nodes, because we should only do this if we
// previously committed the queue with the SPQ_FLAG_ABORT_IF_UNSIGNED flag
// was set. In this scenario, we never check to see if a file is protected,
// nor do we request that an exception be granted).
//
for(QueueNode = Queue->BackupQueue; QueueNode; QueueNode = QueueNode->Next) {
QueueNode->InternalFlags &= ~QUEUE_NODE_BITS_TO_RESET;
MYASSERT(!(QueueNode->InternalFlags & (IQF_ALLOW_UNSIGNED | IQF_TARGET_PROTECTED)));
}
for(QueueNode = Queue->DeleteQueue; QueueNode; QueueNode = QueueNode->Next) {
QueueNode->InternalFlags &= ~QUEUE_NODE_BITS_TO_RESET;
MYASSERT(!(QueueNode->InternalFlags & (IQF_ALLOW_UNSIGNED | IQF_TARGET_PROTECTED)));
}
for(QueueNode = Queue->RenameQueue; QueueNode; QueueNode = QueueNode->Next) {
QueueNode->InternalFlags &= ~QUEUE_NODE_BITS_TO_RESET;
MYASSERT(!(QueueNode->InternalFlags & (IQF_ALLOW_UNSIGNED | IQF_TARGET_PROTECTED)));
}
for(Media = Queue->SourceMediaList; Media; Media = Media->Next) {
for(QueueNode = Media->CopyQueue; QueueNode; QueueNode = QueueNode->Next) {
QueueNode->InternalFlags &= ~QUEUE_NODE_BITS_TO_RESET;
MYASSERT(!(QueueNode->InternalFlags & (IQF_ALLOW_UNSIGNED | IQF_TARGET_PROTECTED)));
}
}
//
// Iterate through all the entries in the TargetLookupTable string table,
// and clear some flags in their associated SP_TARGET_ENT data.
//
pSetupStringTableEnum(Queue->TargetLookupTable,
&TargetInfo,
sizeof(TargetInfo),
pSetupResetTarget,
(LPARAM)0
);
}
WINSETUPAPI
BOOL
WINAPI
SetupSetFileQueueFlags(
IN HSPFILEQ FileQueue,
IN DWORD FlagMask,
IN DWORD Flags
)
/*++
Routine Description:
This API modifies public settable flags for FileQueue
Arguments:
FileQueue - Queue in which flags are to be set.
FlagMask - Flags to modify, must not be zero
Flags - New value of flags, must be a subset of FlagMask
FlagMask and Flags include:
SPQ_FLAG_BACKUP_AWARE
SPQ_FLAG_ABORT_IF_UNSIGNED
Return Value:
If the function succeeds, the return value is TRUE.
If the function fails, the return value is FALSE. To get extended error
information, call GetLastError.
--*/
{
PSP_FILE_QUEUE Queue;
BOOL b;
DWORD status = ERROR_INVALID_HANDLE;
DWORD RemapFlags = 0;
DWORD RemapFlagMask = 0;
if (FileQueue == NULL || FileQueue == (HSPFILEQ)INVALID_HANDLE_VALUE) {
SetLastError(ERROR_INVALID_HANDLE);
return FALSE;
}
Queue = (PSP_FILE_QUEUE)FileQueue;
b = TRUE;
try {
if(Queue->Signature != SP_FILE_QUEUE_SIG) {
b = FALSE;
}
} except(EXCEPTION_EXECUTE_HANDLER) {
b = FALSE;
}
if(!b) {
SetLastError(ERROR_INVALID_HANDLE);
return(FALSE);
}
try {
//
// validate FlagMask and Flags
//
if (!FlagMask
|| (FlagMask & ~SPQ_FLAG_VALID)
|| (Flags & ~FlagMask)) {
status = ERROR_INVALID_PARAMETER;
leave;
}
//
// remap SPQ_FLAG_BACKUP_AWARE to FQF_BACKUP_AWARE
//
if (FlagMask & SPQ_FLAG_BACKUP_AWARE) {
RemapFlagMask |= FQF_BACKUP_AWARE;
if (Flags & SPQ_FLAG_BACKUP_AWARE) {
RemapFlags |= FQF_BACKUP_AWARE;
}
}
//
// remap SPQ_FLAG_ABORT_IF_UNSIGNED to FQF_ABORT_IF_UNSIGNED
//
if (FlagMask & SPQ_FLAG_ABORT_IF_UNSIGNED) {
RemapFlagMask |= FQF_ABORT_IF_UNSIGNED;
if (Flags & SPQ_FLAG_ABORT_IF_UNSIGNED) {
RemapFlags |= FQF_ABORT_IF_UNSIGNED;
} else {
//
// If we're clearing this flag, then we also need to go reset
// the queue state so that it can be committed again, just like
// it was the very first time (except that no driver signing UI
// will happen in the subsequent queue committal).
//
if(Queue->Flags & FQF_ABORT_IF_UNSIGNED) {
ResetQueueState(Queue);
}
}
}
//
// remap SPQ_FLAG_FILES_MODIFIED to FQF_FILES_MODIFIED
// allows explicit setting/resetting of this state
// which is informational only
//
if (FlagMask & SPQ_FLAG_FILES_MODIFIED) {
RemapFlagMask |= FQF_FILES_MODIFIED;
if (Flags & SPQ_FLAG_FILES_MODIFIED) {
RemapFlags |= FQF_FILES_MODIFIED;
}
}
//
// now modify real flags
//
Queue->Flags = (Queue->Flags & ~RemapFlagMask) | RemapFlags;
status = NO_ERROR;
} except(EXCEPTION_EXECUTE_HANDLER) {
status = ERROR_INVALID_DATA;
}
SetLastError(status);
return (status==NO_ERROR);
}