|
|
#include "pch.h"
#include "resource.h"
#include "BootCfg.h"
#include "BootCfg64.h"
#include <strsafe.h>
//
// custom macros
//
#define NOT !
#define FORMAT_FILE_PATH L"signature(%s)"
#define FORMAT_FILE_PATH_EX L"signature({%s})"
//
// custom error codes
//
#define ERROR_PARTIAL_SUCCESS 0x40080001
#define ERROR_FAILED 0x40080002
//
// externs
//
extern LIST_ENTRY BootEntries; extern LIST_ENTRY ActiveUnorderedBootEntries; extern LIST_ENTRY InactiveUnorderedBootEntries;
//
// parameter / switches index
#define OI_CLONE_MAIN 0
#define OI_CLONE_SOURCE_GUID 1
#define OI_CLONE_TARGET_GUID 2
#define OI_CLONE_FRIENDLY_NAME_REPLACE 3
#define OI_CLONE_FRIENDLY_NAME_APPEND 4
#define OI_CLONE_BOOT_ID 5
#define OI_CLONE_DRIVER_UPDATE 6
#define OI_CLONE_HELP 7
#define OI_CLONE_COUNT 8
// switch names
#define OPTION_CLONE L"clone"
#define OPTION_CLONE_SOURCE_GUID L"sg"
#define OPTION_CLONE_TARGET_GUID L"tg"
#define OPTION_CLONE_FRIENDLY_NAME_REPLACE L"d"
#define OPTION_CLONE_FRIENDLY_NAME_APPEND L"d+"
#define OPTION_CLONE_BOOT_ID L"id"
#define OPTION_CLONE_HELP L"?"
#define OPTION_CLONE_DRIVER_UPDATE L"upddrv"
// default friendly name
#define DEFAULT_FRIENDLY_NAME GetResString2( IDS_CLONE_DEFAULT_FRIENDLY_NAME, 0 )
// resource strings
#define CLONE_ZERO_BOOT_ENTRIES GetResString2( IDS_CLONE_ZERO_BOOT_ENTRIES, 0 )
#define CLONE_RANGE_ZERO_BOOT_ENTRIES GetResString2( IDS_CLONE_RANGE_ZERO_BOOT_ENTRIES, 0 )
#define CLONE_SUCCESS GetResString2( IDS_CLONE_SUCCESS, 0 )
#define CLONE_FAILED GetResString2( IDS_CLONE_FAILED, 0 )
#define CLONE_PARTIAL GetResString2( IDS_CLONE_PARTIAL, 0 )
#define CLONE_INVALID_BOOT_ENTRY GetResString2( IDS_CLONE_INVALID_BOOT_ENTRY, 0 )
#define CLONE_ALREADY_EXISTS GetResString2( IDS_CLONE_ALREADY_EXISTS, 0 )
#define CLONE_BOOT_ENTRY_SUCCESS GetResString2( IDS_CLONE_BOOT_ENTRY_SUCCESS, 0 )
#define CLONE_INVALID_SOURCE_GUID GetResString2( IDS_CLONE_INVALID_SOURCE_GUID, 0 )
#define CLONE_INVALID_TARGET_GUID GetResString2( IDS_CLONE_INVALID_TARGET_GUID, 0 )
#define CLONE_INVALID_DRIVER_ENTRY GetResString2( IDS_CLONE_INVALID_DRIVER_ENTRY, 0 )
#define CLONE_DRIVER_ALREADY_EXISTS GetResString2( IDS_CLONE_DRIVER_ALREADY_EXISTS, 0 )
#define CLONE_ZERO_DRIVER_ENTRIES GetResString2( IDS_CLONE_ZERO_DRIVER_ENTRIES, 0 )
#define CLONE_DRIVER_ENTRY_SUCCESS GetResString2( IDS_CLONE_DRIVER_ENTRY_SUCCESS, 0 )
#define CLONE_DETAILED_TRACE GetResString2( IDS_CLONE_DETAILED_TRACE, 0 )
#define MSG_ERROR_INVALID_USAGE_REQUEST GetResString2( IDS_ERROR_INVALID_USAGE_REQUEST, 0 )
#define MSG_ERROR_INVALID_DESCRIPTION_COMBINATION GetResString2( IDS_ERROR_INVALID_DESCRIPTION_COMBINATION, 0 )
#define MSG_ERROR_INVALID_BOOT_ID_COMBINATION GetResString2( IDS_ERROR_INVALID_BOOT_ID_COMBINATION, 0 )
#define MSG_ERROR_INVALID_UPDDRV_COMBINATION GetResString2( IDS_ERROR_INVALID_UPDDRV_COMBINATION, 0 )
#define MSG_ERROR_NO_SGUID_WITH_UPDDRV GetResString2( IDS_ERROR_NO_SGUID_WITH_UPDDRV, 0 )
//
// internal structure
//
typedef struct __tagCloneParameters { BOOL bUsage; LONG lBootId; BOOL bVerbose; BOOL bDriverUpdate; LPWSTR pwszSourcePath; LPWSTR pwszTargetPath; LPWSTR pwszSourceGuid; LPWSTR pwszTargetGuid; LPWSTR pwszFriendlyName; DWORD dwFriendlyNameType; } TCLONE_PARAMS, *PTCLONE_PARAMS;
//
// enum's
//
enum { BOOTENTRY_FRIENDLYNAME_NONE = 0, BOOTENTRY_FRIENDLYNAME_APPEND, BOOTENTRY_FRIENDLYNAME_REPLACE };
//
// prototypes
//
// parser
DWORD DisplayCloneHelp(); DWORD ProcessOptions( DWORD argc, LPCWSTR argv[], PTCLONE_PARAMS pParams );
// helper functions
DWORD TranslateEFIPathToNTPath( LPCWSTR pwszGUID, LPVOID* pwszPath ); BOOL MatchPath( PFILE_PATH pfpSource, LPCWSTR pwszDevicePath, LPCWSTR pwszFilePath ); DWORD PrepareCompleteEFIPath( PFILE_PATH pfpSource, LPCWSTR pwszDevicePath, LPWSTR* pwszEFIPath, DWORD* pdwLength );
// efi driver cloners
DWORD LoadDriverEntries( PEFI_DRIVER_ENTRY_LIST* ppDriverEntries ); LONG FindDriverEntryWithTargetEFI( PEFI_DRIVER_ENTRY_LIST pdeList, DWORD dwSourceIndex, PEFI_DRIVER_ENTRY pdeSource, LPCWSTR pwszDevicePath ); DWORD DoDriverEntryClone( PEFI_DRIVER_ENTRY_LIST pbeList, LPCWSTR pwszSourceEFI, LPCWSTR pwszTargetEFI, LPCWSTR pwszFriendlyName, DWORD dwFriendlyNameType, BOOL bVerbose ); DWORD CloneDriverEntry( PEFI_DRIVER_ENTRY pbeSource, LPCWSTR pwszEFIPath, LPCWSTR pwszFriendlyName, DWORD dwFriendlyNameType );
// boot entry cloners
DWORD CloneBootEntry( PBOOT_ENTRY pbeSource, LPCWSTR pwszEFIPath, LPCWSTR pwszFriendlyName, DWORD dwFriendlyNameType ); DWORD DoBootEntryClone( PBOOT_ENTRY_LIST pbeList, LPCWSTR pwszSourceEFI, LPCWSTR pwszTargetEFI, LONG lIndexFrom, LONG lIndexTo, LPCWSTR pwszFriendlyName, DWORD dwFriendlyNameType, BOOL bVerbose );
//
// functionality
//
DWORD ProcessCloneSwitch_IA64( IN DWORD argc, IN LPCTSTR argv[] ) { //
// local variables
NTSTATUS status; DWORD dwResult = 0; DWORD dwLength = 0; DWORD dwExitCode = 0; TCLONE_PARAMS paramsClone; BOOLEAN wasEnabled = FALSE; PEFI_DRIVER_ENTRY_LIST pDriverEntries = NULL; // init to zero's
ZeroMemory( ¶msClone, sizeof( TCLONE_PARAMS ) );
// process the command line options
dwResult = ProcessOptions( argc, argv, ¶msClone ); if ( dwResult != ERROR_SUCCESS ) { // display one blank line -- for clarity purpose
ShowMessage( stderr, L"\n" );
// ...
dwExitCode = 1; ShowLastErrorEx( stderr, SLE_ERROR | SLE_INTERNAL ); goto cleanup; }
// check if user requested for help
if ( paramsClone.bUsage == TRUE ) { // display usage for this option
DisplayCloneHelp(); dwExitCode = 0; goto cleanup; }
// display one blank line -- for clarity purpose
ShowMessage( stderr, L"\n" );
// initialize the EFI -- only if user specifies the index
if ( paramsClone.bDriverUpdate == FALSE ) { dwResult = InitializeEFI();
// check the result of load operation
if ( dwResult != ERROR_SUCCESS ) { // NOTE: message will be displayed in the associated funtions itself
dwExitCode = 1; goto cleanup; } } else if ( paramsClone.bDriverUpdate == TRUE ) { //
// load the drivers
// enable the privilege that is necessary to query/set NVRAM.
status = RtlAdjustPrivilege( SE_SYSTEM_ENVIRONMENT_PRIVILEGE, TRUE, FALSE, &wasEnabled ); if ( NOT NT_SUCCESS( status ) ) { dwExitCode = 1; dwResult = RtlNtStatusToDosError( status ); SetLastError( dwResult ); ShowLastErrorEx( stderr, SLE_TYPE_ERROR | SLE_SYSTEM ); goto cleanup; }
// load the drivers now
dwResult = LoadDriverEntries( &pDriverEntries ); if ( dwResult != ERROR_SUCCESS ) { dwExitCode = 1; SetLastError( dwResult ); ShowLastErrorEx( stderr, SLE_TYPE_ERROR | SLE_SYSTEM ); goto cleanup; } }
// translate the source guid path into NT path - if needed
if ( paramsClone.pwszSourceGuid != NULL ) { dwResult = TranslateEFIPathToNTPath( paramsClone.pwszSourceGuid, ¶msClone.pwszSourcePath ); if ( dwResult != ERROR_SUCCESS ) { dwExitCode = 1; ShowMessage( stderr, CLONE_INVALID_SOURCE_GUID ); goto cleanup; } }
// translate the target guid into NT path
dwResult = TranslateEFIPathToNTPath( paramsClone.pwszTargetGuid, ¶msClone.pwszTargetPath ); if ( dwResult != ERROR_SUCCESS ) { dwExitCode = 1; ShowMessage( stderr, CLONE_INVALID_TARGET_GUID ); goto cleanup; }
// actual operation ...
if ( paramsClone.bDriverUpdate == FALSE ) { // by default, if user did not specify the friendly name, we will assume
// that users wants to the append the default string viz. "(clone)"
if ( paramsClone.pwszFriendlyName == NULL ) { // determine the length of the default friendly name
// and allocate buffer with length
dwLength = StringLength( DEFAULT_FRIENDLY_NAME, 0 ) + 2; paramsClone.pwszFriendlyName = AllocateMemory( dwLength + 5 ); if ( paramsClone.pwszFriendlyName == NULL ) { dwExitCode = 1; SetLastError( ERROR_NOT_ENOUGH_MEMORY ); ShowLastErrorEx( stderr, SLE_TYPE_ERROR | SLE_SYSTEM ); goto cleanup; }
// copy the default string into this buffer and
// change the friednly name type to append
paramsClone.dwFriendlyNameType = BOOTENTRY_FRIENDLYNAME_APPEND; StringCopy( paramsClone.pwszFriendlyName, DEFAULT_FRIENDLY_NAME, dwLength ); }
// do the boot entry cloning
dwResult = DoBootEntryClone( NULL, paramsClone.pwszSourcePath, paramsClone.pwszTargetPath, paramsClone.lBootId, -1, paramsClone.pwszFriendlyName, paramsClone.dwFriendlyNameType, paramsClone.bVerbose ); } else if ( paramsClone.bDriverUpdate == TRUE ) { // do the driver cloning
dwResult = DoDriverEntryClone( pDriverEntries, paramsClone.pwszSourcePath, paramsClone.pwszTargetPath, paramsClone.pwszFriendlyName, paramsClone.dwFriendlyNameType, paramsClone.bVerbose ); }
// determine the exit code based on the error code
switch( dwResult ) { case ERROR_SUCCESS: dwExitCode = 0; break;
case ERROR_FAILED: dwExitCode = 1; break;
case ERROR_PARTIAL_SUCCESS: dwExitCode = 0; break;
default: // can never oocur
dwExitCode = 1; break; }
cleanup:
// release the memory
FreeMemory( &pDriverEntries ); FreeMemory( ¶msClone.pwszSourcePath ); FreeMemory( ¶msClone.pwszTargetPath ); FreeMemory( ¶msClone.pwszSourceGuid ); FreeMemory( ¶msClone.pwszTargetGuid ); FreeMemory( ¶msClone.pwszFriendlyName );
// return
return dwExitCode; }
///////////////////////////////////////////////////////////////////////////////
// boot entries specific implementation
//////////////////////////////////////////////////////////////////////////////
DWORD DoBootEntryClone( PBOOT_ENTRY_LIST pbeList, LPCWSTR pwszSourceEFI, LPCWSTR pwszTargetEFI, LONG lIndexFrom, LONG lIndexTo, LPCWSTR pwszFriendlyName, DWORD dwFriendlyNameType, BOOL bVerbose ) { // local variables
DWORD dwResult = 0; BOOL bClone = FALSE; LONG lCurrentIndex = 0; BOOL bExitFromLoop = FALSE; PLIST_ENTRY pBootList = NULL; PBOOT_ENTRY pBootEntry = NULL; PFILE_PATH pfpBootFilePath = NULL; PMY_BOOT_ENTRY pMyBootEntry = NULL; DWORD dwAttempted = 0, dwFailed = 0;
//
// check the input parameter
//
if ( pwszTargetEFI == NULL || (lIndexTo != -1 && lIndexFrom > lIndexTo) || (dwFriendlyNameType != BOOTENTRY_FRIENDLYNAME_NONE && pwszFriendlyName == NULL) ) { dwResult = ERROR_INVALID_PARAMETER; goto cleanup; }
// pbeList is a unreferenced parameter
UNREFERENCED_PARAMETER( pbeList );
// if the 'to' index is not specified, then we treat the 'to' index to match
// with the 'from' index
if ( lIndexFrom != -1 && lIndexTo == -1 ) { lIndexTo = lIndexFrom; }
// traverse thru the list of boot entries
for( pBootList = BootEntries.Flink; pBootList != &BootEntries; pBootList = pBootList->Flink ) { // increment the loop counter
bClone = FALSE; lCurrentIndex = -1; dwResult = ERROR_SUCCESS;
// get the boot entry
pMyBootEntry = CONTAINING_RECORD( pBootList, MY_BOOT_ENTRY, ListEntry ); if( NOT MBE_IS_NT( pMyBootEntry ) ) { // this is not a valid boot entry we are looking for skip
continue; }
// extract the boot id and actual boot entry
lCurrentIndex = pMyBootEntry->myId; pBootEntry = &pMyBootEntry->NtBootEntry;
// check if the current boot index falls within the index or not
if ( lIndexFrom != -1 ) { bClone = (lCurrentIndex >= lIndexFrom && lCurrentIndex <= lIndexTo); }
// extended filtering
if ( pwszSourceEFI != NULL ) { if ( lIndexFrom == -1 || (lIndexFrom != -1 && bClone == TRUE) ) { // extract the boot file path
pfpBootFilePath = (PFILE_PATH) ADD_OFFSET( pBootEntry, BootFilePathOffset );
// check whether it matches or not
bClone = MatchPath( pfpBootFilePath, pwszSourceEFI, NULL ); } }
// clone the boot entry -- only if filtering results in TRUE
bExitFromLoop = FALSE; if ( bClone == TRUE || (pwszSourceEFI == NULL && lIndexFrom == -1) ) { // increment the attempted list
dwAttempted++;
// do the operation
dwResult = CloneBootEntry( pBootEntry, pwszTargetEFI, pwszFriendlyName, dwFriendlyNameType );
// check the result
if ( dwResult != ERROR_SUCCESS ) { // increment the failures count
dwFailed++;
// check whether this particular instance of operation is target for
// multiple entries or single entry
if ( lIndexFrom == -1 || ((lIndexTo - lIndexFrom + 1) > 1) ) { // check the severity for the error occured
switch( dwResult ) { case STG_E_UNKNOWN: // unknown error -- unrecoverable
case ERROR_INVALID_PARAMETER: // code error
case ERROR_NOT_ENOUGH_MEMORY: // unrecovarable case
{ bExitFromLoop = TRUE; break; }
case ERROR_ALREADY_EXISTS: { // duplicate boot entry
if ( bVerbose == TRUE ) { ShowMessageEx( stdout, 1, TRUE, CLONE_ALREADY_EXISTS, lCurrentIndex ); }
// ...
dwResult = ERROR_SUCCESS; break; }
default: case ERROR_FILE_NOT_FOUND: case ERROR_PATH_NOT_FOUND: { // dont know how to handle this case
if ( bVerbose == TRUE ) { SetLastError( dwResult ); SaveLastError(); ShowMessageEx( stdout, 2, TRUE, CLONE_INVALID_BOOT_ENTRY, lCurrentIndex, GetReason() ); }
// ...
dwResult = ERROR_SUCCESS; break; } } } else { // since this is a single entry clone operation
// break from the loop
bExitFromLoop = TRUE; } } else { if ( bVerbose == TRUE ) { ShowMessageEx( stdout, 1, TRUE, CLONE_BOOT_ENTRY_SUCCESS, lCurrentIndex ); } } }
// exit from the loop - if needed
if ( bExitFromLoop == TRUE ) { break; } }
cleanup:
// check the result of the operation
if ( dwResult == ERROR_SUCCESS ) { if ( dwAttempted == 0 ) { // no boot entries at all
dwResult = ERROR_FAILED; if ( lIndexFrom == -1 ) { ShowMessage( stdout, CLONE_ZERO_BOOT_ENTRIES ); } else { ShowMessage( stdout, CLONE_RANGE_ZERO_BOOT_ENTRIES ); } } else { // verify whether all requested boot entries are processed or not
if ( lIndexFrom != -1 && dwAttempted != (lIndexTo - lIndexFrom + 1) ) { // warning - not all boot entries were parsed -- invalid bounds were specified
//
// NOTE: in the current implementation, this can never occur
// this is because, the input parameters for this option does accept
// only the /id which will be treated as 'lIndexStart'
//
}
if ( dwFailed == 0 ) { // nothing failed -- success
dwResult = ERROR_SUCCESS; SetLastError( ERROR_SUCCESS ); ShowLastErrorEx( stdout, SLE_TYPE_SUCCESS | SLE_SYSTEM ); } else if ( dwAttempted == dwFailed ) { // nothing succeeded -- completely failed
dwResult = ERROR_FAILED; ShowMessage( stderr, CLONE_FAILED );
// show verbose hint
if ( bVerbose == FALSE ) { ShowMessage( stderr, CLONE_DETAILED_TRACE ); } } else { // parital success
dwResult = ERROR_PARTIAL_SUCCESS; ShowMessage( stderr, CLONE_PARTIAL );
// show verbose hint
if ( bVerbose == FALSE ) { ShowMessage( stderr, CLONE_DETAILED_TRACE ); } } } } else { // check the reason for failure
switch( dwResult ) { case STG_E_UNKNOWN: // unknown error -- unrecoverable
case ERROR_INVALID_PARAMETER: // code error
case ERROR_NOT_ENOUGH_MEMORY: // unrecovarable case
{ SetLastError( dwResult ); ShowLastErrorEx( stderr, SLE_TYPE_ERROR | SLE_SYSTEM ); break; }
case ERROR_ALREADY_EXISTS: { ShowMessageEx( stdout, 1, TRUE, CLONE_ALREADY_EXISTS, lIndexFrom ); break; }
default: case ERROR_FILE_NOT_FOUND: case ERROR_PATH_NOT_FOUND: { SetLastError( dwResult ); SaveLastError(); ShowMessageEx( stdout, 2, TRUE, CLONE_INVALID_BOOT_ENTRY, lIndexFrom, GetReason() ); break; } }
// error code
dwResult = ERROR_FAILED; }
// return
return dwResult; }
DWORD CloneBootEntry( PBOOT_ENTRY pbeSource, LPCWSTR pwszEFIPath, LPCWSTR pwszFriendlyName, DWORD dwFriendlyNameType ) { //
// local variables
DWORD dwResult = ERROR_SUCCESS; NTSTATUS status = STATUS_SUCCESS;
// friendly name
DWORD dwFriendlyNameLength = 0; LPWSTR pwszTargetFriendlyName = NULL; LPCWSTR pwszSourceFriendlyName = NULL;
// os options
DWORD dwOsOptionsLength = 0; PWINDOWS_OS_OPTIONS pOsOptions = NULL;
// boot file path
DWORD dwEFIPathLength = 0; DWORD dwBootFilePathLength = 0; PFILE_PATH pfpBootFilePath = NULL; LPWSTR pwszFullEFIPath = NULL;
// boot entry
ULONG ulId = 0; ULONG ulIdCount = 0; ULONG* pulIdsArray = NULL; DWORD dwBootEntryLength = 0; PBOOT_ENTRY pBootEntry = NULL;
//
// implementation
//
// check the input
if ( pbeSource == NULL || pwszEFIPath == NULL || (dwFriendlyNameType != BOOTENTRY_FRIENDLYNAME_NONE && pwszFriendlyName == NULL) ) { dwResult = ERROR_INVALID_PARAMETER; goto cleanup; }
//
// validate the boot file in the source boot entry
//
// extract the boot file path
pfpBootFilePath = (PFILE_PATH) ADD_OFFSET( pbeSource, BootFilePathOffset );
// attempt to translate the file path
status = NtTranslateFilePath( pfpBootFilePath, FILE_PATH_TYPE_NT, NULL, &dwBootFilePathLength );
// reset the pBootFilePath and dwBootFilePathLength variables
pfpBootFilePath = NULL; dwBootFilePathLength = 0;
// now verify the result of the translation
if ( NOT NT_SUCCESS( status ) ) { if ( status == STATUS_BUFFER_TOO_SMALL ) { // source boot entry is a valid one
dwResult = ERROR_SUCCESS; } else { // error occured -- cannot recover
dwResult = RtlNtStatusToDosError( status ); goto cleanup; } }
//
// prepare "friendly name"
//
// determine the source friendly name and its length
dwFriendlyNameLength = 0; pwszSourceFriendlyName = NULL; switch( dwFriendlyNameType ) { case BOOTENTRY_FRIENDLYNAME_NONE: case BOOTENTRY_FRIENDLYNAME_APPEND: { pwszSourceFriendlyName = (LPCWSTR) ADD_OFFSET( pbeSource, FriendlyNameOffset ); dwFriendlyNameLength = StringLengthW( pwszSourceFriendlyName, 0 ) + 1; break; }
default: // do nothing
break; }
// add the length of the friendly name that needs to be added -- if exists
if ( pwszFriendlyName != NULL ) { dwFriendlyNameLength += StringLengthW( pwszFriendlyName, 0 ) + 1; }
// allocate memory for the friendly name
pwszTargetFriendlyName = (LPWSTR) AllocateMemory( (dwFriendlyNameLength + 1) * sizeof( WCHAR ) ); if ( pwszTargetFriendlyName == NULL ) { dwResult = ERROR_NOT_ENOUGH_MEMORY; goto cleanup; }
// prepare the friendly name
StringCopyW( pwszTargetFriendlyName, L"", dwFriendlyNameLength );
// ...
if ( pwszSourceFriendlyName != NULL ) { StringConcat( pwszTargetFriendlyName, pwszSourceFriendlyName, dwFriendlyNameLength ); }
// ...
if ( pwszFriendlyName != NULL ) { // add one space b/w the existing and concatenating string
if ( pwszSourceFriendlyName != NULL ) { StringConcat( pwszTargetFriendlyName, L" ", dwFriendlyNameLength ); }
// ...
StringConcat( pwszTargetFriendlyName, pwszFriendlyName, dwFriendlyNameLength ); }
//
// prepare "OS Options"
//
// NOTE:
// -----
// though the os options are NULL, it will still consume some space (refer the structre of
// BOOT_ENTRY -- that is the reason why the default length of OS OPTIONS is ANYSIZE_ARRAY)
pOsOptions = NULL; dwOsOptionsLength = ANYSIZE_ARRAY; if ( pbeSource->OsOptionsLength != 0 ) { // allocate memory for os options
dwOsOptionsLength = pbeSource->OsOptionsLength; pOsOptions = (PWINDOWS_OS_OPTIONS) AllocateMemory( dwOsOptionsLength ); if ( pOsOptions == NULL ) { dwResult = ERROR_NOT_ENOUGH_MEMORY; goto cleanup; }
// copy the contents
CopyMemory( pOsOptions, &pbeSource->OsOptions, dwOsOptionsLength ); }
//
// boot file path
//
// the 'FilePath' variable in FILE_PATH variable contains two variables
// each seperated by a NULL terminated character
// the first part designates the DEVICE PATH
// and the second part designated the DIRECTORY / FILE PATH
// we already have the device path (pwszEFIPath) -- but we need to get the
// DIRECTORY / FILE PATH -- this we will get from the source boot entry
pfpBootFilePath = (PFILE_PATH) ADD_OFFSET( pbeSource, BootFilePathOffset ); dwResult = PrepareCompleteEFIPath( pfpBootFilePath, pwszEFIPath, &pwszFullEFIPath, &dwEFIPathLength ); if ( dwResult != ERROR_SUCCESS ) { // since the memory reference in pBootFilePath is not allocated
// in this function, it is important to reset the pointer to NULL
// this avoids the crash in the program
pfpBootFilePath = NULL;
// ...
goto cleanup; }
// now determine the memory size that needs to be allocated for FILE_PATH structure
// and align up to the even memory bounday
pfpBootFilePath = NULL; dwBootFilePathLength = FIELD_OFFSET(FILE_PATH, FilePath) + (dwEFIPathLength * sizeof( WCHAR ));
// allocate memory
pfpBootFilePath = (PFILE_PATH) AllocateMemory( dwBootFilePathLength ); if ( pfpBootFilePath == NULL ) { dwResult = ERROR_NOT_ENOUGH_MEMORY; goto cleanup; }
// initialize the file path structure
ZeroMemory( pfpBootFilePath, dwBootFilePathLength ); pfpBootFilePath->Length = dwBootFilePathLength; pfpBootFilePath->Type = FILE_PATH_TYPE_NT; pfpBootFilePath->Version = FILE_PATH_VERSION; CopyMemory( pfpBootFilePath->FilePath, pwszFullEFIPath, dwEFIPathLength * sizeof( WCHAR ) );
//
// finally, create the boot entry
//
// determine the size for the BOOT_ENTRY structure
dwBootEntryLength = FIELD_OFFSET( BOOT_ENTRY, OsOptions ) + dwOsOptionsLength + (dwFriendlyNameLength * sizeof(WCHAR)) + dwBootFilePathLength + sizeof(WCHAR) + // align the FriendlyName on WCHAR
sizeof(DWORD); // align the BootFilePath on DWORD
// allocate memory
pBootEntry = (PBOOT_ENTRY) AllocateMemory( dwBootEntryLength ); if ( pBootEntry == NULL ) { dwResult = ERROR_NOT_ENOUGH_MEMORY; goto cleanup; }
// ...
ZeroMemory( pBootEntry, dwBootEntryLength ); pBootEntry->Id = 0L; pBootEntry->Length = dwBootEntryLength; pBootEntry->Version = BOOT_ENTRY_VERSION; pBootEntry->OsOptionsLength = dwOsOptionsLength; pBootEntry->Attributes = BOOT_ENTRY_ATTRIBUTE_DEFAULT;
// align the friendly name on WCHR boundary
pBootEntry->FriendlyNameOffset = ALIGN_UP( FIELD_OFFSET(BOOT_ENTRY, OsOptions) + dwOsOptionsLength, WCHAR );
// align the boot file path on DWORD boundary
pBootEntry->BootFilePathOffset = ALIGN_UP( pBootEntry->FriendlyNameOffset + (dwFriendlyNameLength * sizeof(WCHAR)), DWORD );
// fill the boot entry
CopyMemory( pBootEntry->OsOptions, pOsOptions, dwOsOptionsLength ); CopyMemory( ADD_OFFSET( pBootEntry, BootFilePathOffset ), pfpBootFilePath, dwBootFilePathLength ); CopyMemory( ADD_OFFSET( pBootEntry, FriendlyNameOffset ), pwszTargetFriendlyName, (dwFriendlyNameLength * sizeof(WCHAR) ) );
//
// add the prepared boot entry
//
status = NtAddBootEntry( pBootEntry, &ulId ); if ( NOT NT_SUCCESS( status ) ) { dwResult = RtlNtStatusToDosError( status ); goto cleanup; } //
// Add the entry to the boot order.
//
ulIdCount = 32L; pulIdsArray = (PULONG) AllocateMemory( ulIdCount * sizeof(ULONG) ); if ( pulIdsArray == NULL ) { dwResult = ERROR_NOT_ENOUGH_MEMORY; goto cleanup; }
// query the boot entry order
// NOTE: we will doing error check for this function call bit later
status = NtQueryBootEntryOrder( pulIdsArray, &ulIdCount );
// need room in the buffer for the new entry.
if ( 31L < ulIdCount ) { // release the current memory allocation for id's
FreeMemory( &pulIdsArray );
// allocate new memory and query again
pulIdsArray = (PULONG) AllocateMemory( (ulIdCount+1) * sizeof(ULONG)); if ( pulIdsArray == NULL ) { dwResult = ERROR_NOT_ENOUGH_MEMORY; goto cleanup; }
// ...
status = NtQueryBootEntryOrder( pulIdsArray, &ulIdCount ); } // check the result of the boot entries query operation
if ( NOT NT_SUCCESS( status ) ) { dwResult = RtlNtStatusToDosError( status ); goto cleanup; }
// set the boot entry order
ulIdCount++; *(pulIdsArray + (ulIdCount - 1)) = ulId; status = NtSetBootEntryOrder( pulIdsArray, ulIdCount ); if ( NOT NT_SUCCESS( status ) ) { dwResult = RtlNtStatusToDosError( status ); goto cleanup; }
// success
dwResult = ERROR_SUCCESS;
cleanup:
// release the memory allocated
FreeMemory( &pOsOptions ); FreeMemory( &pBootEntry ); FreeMemory( &pulIdsArray ); FreeMemory( &pfpBootFilePath ); FreeMemory( &pwszFullEFIPath ); FreeMemory( &pwszTargetFriendlyName );
// return
return dwResult; }
///////////////////////////////////////////////////////////////////////////////
// efi drivers specific implementation
//////////////////////////////////////////////////////////////////////////////
DWORD LoadDriverEntries( PEFI_DRIVER_ENTRY_LIST* ppDriverEntries ) { //
// local variables
DWORD dwSize = 0; BOOL bSecondChance = FALSE; DWORD dwResult = ERROR_SUCCESS; NTSTATUS status = STATUS_SUCCESS; const DWORD dwDefaultSize = 1024; PEFI_DRIVER_ENTRY_LIST pDriverEntries = NULL;
//
// implementation
//
// check the input
if ( ppDriverEntries == NULL ) { dwResult = ERROR_INVALID_PARAMETER; goto cleanup; }
// default size is assumed as 1024 bytes
bSecondChance = FALSE; dwSize = dwDefaultSize;
try_again:
// allocate memory
pDriverEntries = AllocateMemory( dwSize ); if ( pDriverEntries == NULL ) { dwResult = ERROR_NOT_ENOUGH_MEMORY; goto cleanup; }
// try to get the boot entries
status = NtEnumerateDriverEntries( pDriverEntries, &dwSize ); if ( NOT NT_SUCCESS( status ) ) { // release the memory that is allocated for target path structure
FreeMemory( &pDriverEntries );
// check the error
if ( status == STATUS_BUFFER_TOO_SMALL && bSecondChance == FALSE ) { // give a second try
bSecondChance = TRUE; goto try_again; } else { // error occured -- cannot recover
dwResult = RtlNtStatusToDosError( status ); goto cleanup; } }
// operation is succes
dwResult = ERROR_SUCCESS; *ppDriverEntries = pDriverEntries;
cleanup:
// need to release memory allocated for Driver entries in this function
// should do this only in case of failure
if ( dwResult != ERROR_SUCCESS ) { FreeMemory( &pDriverEntries ); }
// return the result
return dwResult; }
DWORD DoDriverEntryClone( PEFI_DRIVER_ENTRY_LIST pdeList, LPCWSTR pwszSourceEFI, LPCWSTR pwszTargetEFI, LPCWSTR pwszFriendlyName, DWORD dwFriendlyNameType, BOOL bVerbose ) { // local variables
LONG lLoop = 0; DWORD dwResult = 0; BOOL bClone = FALSE; BOOL bExitFromLoop = FALSE; LPCWSTR pwszDriverName = NULL; PFILE_PATH pfpDriverFilePath = NULL; PEFI_DRIVER_ENTRY pDriverEntry = NULL; PEFI_DRIVER_ENTRY_LIST pdeMasterList = NULL; DWORD dwAttempted = 0, dwFailed = 0;
//
// check the input parameter
//
if ( pdeList == NULL || pwszSourceEFI == NULL || pwszTargetEFI == NULL || (dwFriendlyNameType != BOOTENTRY_FRIENDLYNAME_NONE && pwszFriendlyName == NULL) ) { dwResult = ERROR_INVALID_PARAMETER; goto cleanup; }
// currently, the pwszFriendlyName is not considered -- so it should be NULL
if ( pwszFriendlyName != NULL ) { dwResult = ERROR_INVALID_PARAMETER; goto cleanup; }
// traverse thru the list of driver entries
lLoop = 0; bExitFromLoop = FALSE; pdeMasterList = pdeList; // save the pointer the original drivers list
while ( bExitFromLoop == FALSE ) { // increment the loop counter
lLoop++; bClone = FALSE; dwResult = ERROR_SUCCESS;
// get the reference to the current driver entry
pDriverEntry = &pdeList->DriverEntry; if ( pDriverEntry == NULL ) { // should never occur
dwResult = (DWORD) STG_E_UNKNOWN; bExitFromLoop = TRUE; continue; }
//
// check whether the current driver's device matches with the requested path
//
// extract the driver file path
pfpDriverFilePath = (PFILE_PATH) ADD_OFFSET( pDriverEntry, DriverFilePathOffset );
// check whether it matches or not
bClone = MatchPath( pfpDriverFilePath, pwszSourceEFI, NULL );
// clone the boot entry -- only if filtering results in TRUE
if ( bClone == TRUE ) { // updated the attempted count
dwAttempted++;
// get the driver name (it is nothing but the friendly name)
pwszDriverName = (LPCWSTR) ADD_OFFSET( pDriverEntry, FriendlyNameOffset );
// do the operation
// but before proceeding confirm that this particular
// driver entry is not existing
if ( FindDriverEntryWithTargetEFI( pdeMasterList, lLoop, pDriverEntry, pwszTargetEFI ) == -1 ) { dwResult = CloneDriverEntry( pDriverEntry, pwszTargetEFI, pwszFriendlyName, dwFriendlyNameType ); } else { dwResult = ERROR_ALREADY_EXISTS; }
// check the result
if ( dwResult != ERROR_SUCCESS ) { // update the failed count
dwFailed++;
// check the severity for the error occured
switch( dwResult ) { case STG_E_UNKNOWN: // unknown error -- unrecoverable
case ERROR_INVALID_PARAMETER: // code error
case ERROR_NOT_ENOUGH_MEMORY: // unrecovarable case
{ bExitFromLoop = TRUE; break; }
case ERROR_ALREADY_EXISTS: { // duplicate boot entry
if ( bVerbose == TRUE ) { ShowMessageEx( stdout, 1, TRUE, CLONE_DRIVER_ALREADY_EXISTS, pwszDriverName ); }
// ...
dwResult = ERROR_SUCCESS; break; }
default: case ERROR_FILE_NOT_FOUND: case ERROR_PATH_NOT_FOUND: { // dont know how to handle this case
if ( bVerbose == TRUE ) { SetLastError( dwResult ); SaveLastError(); ShowMessageEx( stdout, 2, TRUE, CLONE_INVALID_DRIVER_ENTRY, pwszDriverName, GetReason() ); }
// ...
dwResult = ERROR_SUCCESS; break; } } } else { if ( bVerbose == TRUE ) { ShowMessageEx( stdout, 1, TRUE, CLONE_DRIVER_ENTRY_SUCCESS, pwszDriverName ); } } }
// fetch the next pointer
// do this only if the error the bExitFromLoop is not set in above blocks
if ( bExitFromLoop == FALSE ) { bExitFromLoop = (pdeList->NextEntryOffset == 0); pdeList = (PEFI_DRIVER_ENTRY_LIST) ADD_OFFSET( pdeList, NextEntryOffset ); } }
cleanup:
// check the result of the operation
if ( dwResult == ERROR_SUCCESS ) { if ( dwAttempted == 0 ) { // no driver entries at all
dwResult = ERROR_FAILED; ShowMessage( stdout, CLONE_ZERO_DRIVER_ENTRIES ); } else { if ( dwFailed == 0 ) { // nothing failed -- success
dwResult = ERROR_SUCCESS; SetLastError( ERROR_SUCCESS ); ShowLastErrorEx( stdout, SLE_TYPE_SUCCESS | SLE_SYSTEM ); } else if ( dwAttempted == dwFailed ) { // nothing succeeded -- completely failed
dwResult = ERROR_FAILED; ShowMessage( stderr, CLONE_FAILED );
// show verbose hint
if ( bVerbose == FALSE ) { ShowMessage( stderr, CLONE_DETAILED_TRACE ); } } else { // parital success
dwResult = ERROR_PARTIAL_SUCCESS; ShowMessage( stderr, CLONE_PARTIAL );
// show verbose hint
if ( bVerbose == FALSE ) { ShowMessage( stderr, CLONE_DETAILED_TRACE ); } } } } else { // check the reason for failure
switch( dwResult ) { default: case STG_E_UNKNOWN: // unknown error -- unrecoverable
case ERROR_INVALID_PARAMETER: // code error
case ERROR_NOT_ENOUGH_MEMORY: // unrecovarable case
{ SetLastError( dwResult ); ShowLastErrorEx( stderr, SLE_TYPE_ERROR | SLE_SYSTEM ); break; } }
// error code
dwResult = ERROR_FAILED; }
// return
return dwResult; }
DWORD CloneDriverEntry( PEFI_DRIVER_ENTRY pdeSource, LPCWSTR pwszEFIPath, LPCWSTR pwszFriendlyName, DWORD dwFriendlyNameType ) { //
// local variables
DWORD dwResult = ERROR_SUCCESS; NTSTATUS status = STATUS_SUCCESS;
// friendly name
DWORD dwFriendlyNameLength = 0; LPWSTR pwszTargetFriendlyName = NULL; LPCWSTR pwszSourceFriendlyName = NULL;
// driver file path
DWORD dwEFIPathLength = 0; DWORD dwDriverFilePathLength = 0; PFILE_PATH pfpDriverFilePath = NULL; LPWSTR pwszFullEFIPath = NULL;
// driver entry
ULONG ulId = 0; ULONG ulIdCount = 0; ULONG* pulIdsArray = NULL; DWORD dwDriverEntryLength = 0; PEFI_DRIVER_ENTRY pDriverEntry = NULL;
//
// implementation
//
// check the input
if ( pdeSource == NULL || pwszEFIPath == NULL || (dwFriendlyNameType != BOOTENTRY_FRIENDLYNAME_NONE && pwszFriendlyName == NULL) ) { dwResult = ERROR_INVALID_PARAMETER; goto cleanup; }
//
// validate the driver file in the source driver entry
//
// extract the driver file path
pfpDriverFilePath = (PFILE_PATH) ADD_OFFSET( pdeSource, DriverFilePathOffset );
// attempt to translate the file path
status = NtTranslateFilePath( pfpDriverFilePath, FILE_PATH_TYPE_NT, NULL, &dwDriverFilePathLength );
// reset the pDriverFilePath and dwDriverFilePathLength variables
pfpDriverFilePath = NULL; dwDriverFilePathLength = 0;
// now verify the result of the translation
if ( NOT NT_SUCCESS( status ) ) { if ( status == STATUS_BUFFER_TOO_SMALL ) { // source driver entry is a valid one
dwResult = ERROR_SUCCESS; } else { // error occured -- cannot recover
dwResult = RtlNtStatusToDosError( status ); goto cleanup; } }
//
// prepare "friendly name"
//
// determine the source friendly name and its length
dwFriendlyNameLength = 0; pwszSourceFriendlyName = NULL; switch( dwFriendlyNameType ) { case BOOTENTRY_FRIENDLYNAME_NONE: case BOOTENTRY_FRIENDLYNAME_APPEND: { pwszSourceFriendlyName = (LPCWSTR) ADD_OFFSET( pdeSource, FriendlyNameOffset ); dwFriendlyNameLength = StringLengthW( pwszSourceFriendlyName, 0 ) + 1; break; }
default: // do nothing
break; }
// add the length of the friendly name that needs to be added -- if exists
if ( pwszFriendlyName != NULL ) { dwFriendlyNameLength += StringLengthW( pwszFriendlyName, 0 ) + 1; }
// allocate memory for the friendly name
pwszTargetFriendlyName = (LPWSTR) AllocateMemory( (dwFriendlyNameLength + 1) * sizeof( WCHAR ) ); if ( pwszTargetFriendlyName == NULL ) { dwResult = ERROR_NOT_ENOUGH_MEMORY; goto cleanup; }
// prepare the friendly name
StringCopyW( pwszTargetFriendlyName, L"", dwFriendlyNameLength );
// ...
if ( pwszSourceFriendlyName != NULL ) { StringConcat( pwszTargetFriendlyName, pwszSourceFriendlyName, dwFriendlyNameLength ); }
// ...
if ( pwszFriendlyName != NULL ) { // add one space b/w the existing and concatenating string
if ( pwszSourceFriendlyName != NULL ) { StringConcat( pwszTargetFriendlyName, L" ", dwFriendlyNameLength ); }
// ...
StringConcat( pwszTargetFriendlyName, pwszFriendlyName, dwFriendlyNameLength ); }
//
// driver file path
//
// the 'FilePath' variable in FILE_PATH variable contains two variables
// each seperated by a NULL terminated character
// the first part designates the DEVICE PATH
// and the second part designated the DIRECTORY / FILE PATH
// we already have the device path (pwszEFIPath) -- but we need to get the
// DIRECTORY / FILE PATH -- this we will get from the source driver entry
pfpDriverFilePath = (PFILE_PATH) ADD_OFFSET( pdeSource, DriverFilePathOffset ); dwResult = PrepareCompleteEFIPath( pfpDriverFilePath, pwszEFIPath, &pwszFullEFIPath, &dwEFIPathLength ); if ( dwResult != ERROR_SUCCESS ) { // since the memory reference in pDriverFilePath is not allocated
// in this function, it is important to reset the pointer to NULL
// this avoids the crash in the program
pfpDriverFilePath = NULL;
// ...
goto cleanup; }
// now determine the memory size that needs to be allocated for FILE_PATH structure
// and align up to the even memory bounday
pfpDriverFilePath = NULL; dwDriverFilePathLength = FIELD_OFFSET(FILE_PATH, FilePath) + (dwEFIPathLength * sizeof( WCHAR ));
// allocate memory
pfpDriverFilePath = (PFILE_PATH) AllocateMemory( dwDriverFilePathLength ); if ( pfpDriverFilePath == NULL ) { dwResult = ERROR_NOT_ENOUGH_MEMORY; goto cleanup; }
// initialize the file path structure
ZeroMemory( pfpDriverFilePath, dwDriverFilePathLength ); pfpDriverFilePath->Length = dwDriverFilePathLength; pfpDriverFilePath->Type = FILE_PATH_TYPE_NT; pfpDriverFilePath->Version = FILE_PATH_VERSION; CopyMemory( pfpDriverFilePath->FilePath, pwszFullEFIPath, dwEFIPathLength * sizeof( WCHAR ) );
//
// finally, create the driver entry
//
// determine the size for the EFI_DRIVER_ENTRY structure
dwDriverEntryLength = FIELD_OFFSET( EFI_DRIVER_ENTRY, DriverFilePathOffset ) + (dwFriendlyNameLength * sizeof(WCHAR)) + dwDriverFilePathLength + sizeof(WCHAR) + // align the FriendlyName on WCHAR
sizeof(DWORD); // align the DriverFilePath on DWORD
// allocate memory
pDriverEntry = (PEFI_DRIVER_ENTRY) AllocateMemory( dwDriverEntryLength ); if ( pDriverEntry == NULL ) { dwResult = ERROR_NOT_ENOUGH_MEMORY; goto cleanup; }
// ...
ZeroMemory( pDriverEntry, dwDriverEntryLength ); pDriverEntry->Id = 0L; pDriverEntry->Length = dwDriverEntryLength; pDriverEntry->Version = EFI_DRIVER_ENTRY_VERSION;
// align the friendly name on WCHR boundary
pDriverEntry->FriendlyNameOffset = ALIGN_UP( sizeof( EFI_DRIVER_ENTRY ), WCHAR );
// align the driver file path on DWORD boundary
pDriverEntry->DriverFilePathOffset = ALIGN_UP( pDriverEntry->FriendlyNameOffset + (dwFriendlyNameLength * sizeof(WCHAR)), DWORD );
// fill the driver entry
CopyMemory( ADD_OFFSET( pDriverEntry, DriverFilePathOffset ), pfpDriverFilePath, dwDriverFilePathLength ); CopyMemory( ADD_OFFSET( pDriverEntry, FriendlyNameOffset ), pwszTargetFriendlyName, (dwFriendlyNameLength * sizeof(WCHAR) ) );
//
// add the prepared driver entry
//
status = NtAddDriverEntry( pDriverEntry, &ulId ); if ( NOT NT_SUCCESS( status ) ) { dwResult = RtlNtStatusToDosError( status ); goto cleanup; } //
// ddd the entry to the driver order.
//
ulIdCount = 32L; pulIdsArray = (PULONG) AllocateMemory( ulIdCount * sizeof(ULONG) ); if ( pulIdsArray == NULL ) { dwResult = ERROR_NOT_ENOUGH_MEMORY; goto cleanup; }
// query the driver entry order
// NOTE: we will doing error check for this function call bit later
status = NtQueryDriverEntryOrder( pulIdsArray, &ulIdCount );
// need room in the buffer for the new entry.
if ( 31L < ulIdCount ) { // release the current memory allocation for id's
FreeMemory( &pulIdsArray );
// allocate new memory and query again
pulIdsArray = (PULONG) AllocateMemory( (ulIdCount+1) * sizeof(ULONG)); if ( pulIdsArray == NULL ) { dwResult = ERROR_NOT_ENOUGH_MEMORY; goto cleanup; }
// ...
status = NtQueryDriverEntryOrder( pulIdsArray, &ulIdCount ); } // check the result of the driver entries query operation
if ( NOT NT_SUCCESS( status ) ) { dwResult = RtlNtStatusToDosError( status ); goto cleanup; }
// set the boot entry order
ulIdCount++; *(pulIdsArray + (ulIdCount - 1)) = ulId; status = NtSetDriverEntryOrder( pulIdsArray, ulIdCount ); if ( NOT NT_SUCCESS( status ) ) { dwResult = RtlNtStatusToDosError( status ); goto cleanup; }
// success
dwResult = ERROR_SUCCESS;
cleanup:
// release the memory allocated
FreeMemory( &pulIdsArray ); FreeMemory( &pDriverEntry ); FreeMemory( &pwszFullEFIPath ); FreeMemory( &pfpDriverFilePath ); FreeMemory( &pwszTargetFriendlyName );
// return
return dwResult; }
LONG FindDriverEntryWithTargetEFI( PEFI_DRIVER_ENTRY_LIST pdeList, DWORD dwSourceIndex, PEFI_DRIVER_ENTRY pdeSource, LPCWSTR pwszDevicePath ) { // local variables
LONG lIndex = 0; BOOL bExitFromLoop = FALSE; PFILE_PATH pfpFilePath = NULL; LPCWSTR pwszFilePath = NULL; LPWSTR pwszFullFilePath = NULL; PFILE_PATH pfpSourceFilePath = NULL; PEFI_DRIVER_ENTRY pDriverEntry = NULL; DWORD dw = 0, dwResult = 0, dwLength = 0;
// check the input parameters
if ( pdeList == NULL || pdeSource == NULL || pwszDevicePath == NULL ) { dwResult = ERROR_INVALID_PARAMETER; goto cleanup; }
// extract the file path from the source driver entry
pfpSourceFilePath = (PFILE_PATH) ADD_OFFSET( pdeSource, DriverFilePathOffset );
// preare the efi path from the source path
// (replacing the source device path with the target device path)
//
// the 'FilePath' variable in FILE_PATH variable contains two variables
// each seperated by a NULL terminated character
// the first part designates the DEVICE PATH
// and the second part designated the DIRECTORY / FILE PATH
// we already have the device path (pwszEFIPath) -- but we need to get the
// DIRECTORY / FILE PATH -- this we will get from the source driver entry
//
dwResult = PrepareCompleteEFIPath( pfpSourceFilePath, pwszDevicePath, &pwszFullFilePath, &dwLength ); if ( dwResult != ERROR_SUCCESS ) { goto cleanup; }
// since we already the target device path -- we need the file path
// extract this info more just prepared full file path
dw = StringLengthW( pwszFullFilePath, 0 ) + 1; // +1 for null character
if ( dw > dwLength ) { // error case -- this should never occure
dwResult = (DWORD) STG_E_UNKNOWN; goto cleanup; }
// ...
pwszFilePath = pwszFullFilePath + dw;
// traverse thru the list of driver entries
lIndex = 0; bExitFromLoop = FALSE; dwResult = ERROR_NOT_FOUND; while ( bExitFromLoop == FALSE ) { // increment the loop counter
lIndex++;
// get the reference to the current driver entry
pDriverEntry = &pdeList->DriverEntry; if ( pDriverEntry == NULL ) { // should never occur
dwResult = (DWORD) STG_E_UNKNOWN; bExitFromLoop = TRUE; continue; }
// if the current index doesn't match with the one that we are comparing
// then only proceed with comparision otherwise skip this
if ( lIndex != dwSourceIndex ) { // extract the driver file path
pfpFilePath = (PFILE_PATH) ADD_OFFSET( pDriverEntry, DriverFilePathOffset );
// compare the file paths
if ( MatchPath( pfpFilePath, pwszDevicePath, pwszFilePath ) == TRUE ) { bExitFromLoop = TRUE; dwResult = ERROR_ALREADY_EXISTS; continue; } }
// fetch the next pointer
bExitFromLoop = (pdeList->NextEntryOffset == 0); pdeList = (PEFI_DRIVER_ENTRY_LIST) ADD_OFFSET( pdeList, NextEntryOffset ); }
cleanup:
// release memory
FreeMemory( &pwszFullFilePath );
// result
return ((dwResult == ERROR_ALREADY_EXISTS) ? lIndex : -1); }
///////////////////////////////////////////////////////////////////////////////
// general helper functions
///////////////////////////////////////////////////////////////////////////////
DWORD TranslateEFIPathToNTPath( LPCWSTR pwszGUID, LPVOID* pwszPath ) { //
// local variables
HRESULT hr = S_OK; BOOL bSecondChance = FALSE; BOOL bExtendedFormat = FALSE; DWORD dwResult = ERROR_SUCCESS; NTSTATUS status = STATUS_SUCCESS;
// file path
DWORD dwFilePathLength = 0; LPWSTR pwszFilePath = NULL;
// source FILE_PATH
DWORD dwSourceFilePathSize = 0; PFILE_PATH pfpSourcePath = NULL;
// target FILE_PATH
DWORD dwLength = 0; DWORD dwTargetFilePathSize = 0; PFILE_PATH pfpTargetPath = NULL;
//
// implementation
//
// check the parameters
if ( pwszGUID == NULL || pwszPath == NULL ) { dwResult = ERROR_INVALID_PARAMETER; goto cleanup; }
// determine whether we need to choose the extended formatting
// or normal formatting
bExtendedFormat = ( (*pwszGUID != L'{') && (*(pwszGUID + StringLengthW( pwszGUID, 0 ) - 1) != L'}') );
// default length
dwFilePathLength = MAX_STRING_LENGTH;
try_alloc:
//
// allocate memory for formatting the EFI path
pwszFilePath = AllocateMemory( (dwFilePathLength + 1) * sizeof( WCHAR ) ); if ( pwszFilePath == NULL ) { dwResult = ERROR_NOT_ENOUGH_MEMORY; goto cleanup; }
// format EFI path
if ( bExtendedFormat == FALSE ) { hr = StringCchPrintfW( pwszFilePath, dwFilePathLength, FORMAT_FILE_PATH, pwszGUID ); } else { hr = StringCchPrintfW( pwszFilePath, dwFilePathLength, FORMAT_FILE_PATH_EX, pwszGUID ); }
// check the result -- if failed exit
if ( HRESULT_CODE( hr ) != S_OK ) { // free the currently allocated block
FreeMemory( &pwszFilePath );
// increase the memory in blocks for MAX_STRING_LENGTH
// but do this only 4 times the originally allocated
if ( dwFilePathLength == (MAX_STRING_LENGTH * 4) ) { // cannot afford to give some more tries -- exit
dwResult = (DWORD) STG_E_UNKNOWN; goto cleanup; } else { dwFilePathLength *= MAX_STRING_LENGTH; goto try_alloc; } }
// determine the actual length of the file path
dwFilePathLength = StringLengthW( pwszFilePath, 0 ) + 1;
// now determine the memory size that needs to be allocated for FILE_PATH structure
// and align up to the even memory bounday
dwSourceFilePathSize = FIELD_OFFSET( FILE_PATH, FilePath ) + (dwFilePathLength * sizeof(WCHAR));
// allocate memory for boot file path -- extra one byte is for safe guarding
pfpSourcePath = AllocateMemory( dwSourceFilePathSize + 1 ); if ( pfpSourcePath == NULL ) { dwResult = ERROR_NOT_ENOUGH_MEMORY; goto cleanup; }
// initialize the source boot path
ZeroMemory( pfpSourcePath, dwSourceFilePathSize ); pfpSourcePath->Type = FILE_PATH_TYPE_ARC_SIGNATURE; pfpSourcePath->Version = FILE_PATH_VERSION; pfpSourcePath->Length = dwSourceFilePathSize; CopyMemory( pfpSourcePath->FilePath, pwszFilePath, dwFilePathLength * sizeof(WCHAR) );
//
// do the translation
//
// default size for the target file path is same as the one for source file path
//
bSecondChance = FALSE; dwTargetFilePathSize = dwSourceFilePathSize;
try_translate:
// allocate memory -- extra one byte is for safe guarding
pfpTargetPath = AllocateMemory( dwTargetFilePathSize + 1); if ( pfpTargetPath == NULL ) { dwResult = ERROR_NOT_ENOUGH_MEMORY; goto cleanup; } // attempt to translate the file path
status = NtTranslateFilePath( pfpSourcePath, FILE_PATH_TYPE_NT, pfpTargetPath, &dwTargetFilePathSize ); if ( NOT NT_SUCCESS( status ) ) { // release the memory that is allocated for target path structure
FreeMemory( &pfpTargetPath );
if ( status == STATUS_BUFFER_TOO_SMALL && bSecondChance == FALSE ) { // give a second try
bSecondChance = TRUE; goto try_translate; } else { // error occured -- cannot recover
dwResult = RtlNtStatusToDosError( status ); goto cleanup; } }
// re-use the memory that is allocated for file path
// defintely the NT path will be less than the length of ARC Signature
// NOTE: since we are interested only in the device path, we use StringCopy
// which stops at the first null character -- otherwise, if we are interestedd in
// complete path, we need to CopyMemory
dwLength = StringLengthW( (LPCWSTR) pfpTargetPath->FilePath, 0 ); if ( dwLength < dwFilePathLength - 1 ) { // copy the string contents
ZeroMemory( pwszFilePath, (dwFilePathLength - 1) * sizeof( WCHAR ) ); StringCopyW( pwszFilePath, (LPCWSTR) pfpTargetPath->FilePath, dwFilePathLength ); } else { // re-allocate memory
dwLength++; if ( ReallocateMemory( (VOID*) &pwszFilePath, (dwLength + 1) * sizeof( WCHAR ) ) == FALSE ) { dwResult = ERROR_NOT_ENOUGH_MEMORY; goto cleanup; }
// ...
ZeroMemory( pwszFilePath, (dwLength + 1) * sizeof( WCHAR ) ); StringCopyW( pwszFilePath, (LPCWSTR) pfpTargetPath->FilePath, dwLength ); }
// translation is success
// return the translated file path
dwResult = ERROR_SUCCESS; *pwszPath = pwszFilePath;
cleanup: // free memory allocated for target path structure
FreeMemory( &pfpTargetPath );
// release the memory allocated for source path structure
FreeMemory( &pfpSourcePath );
// release memory allocated for string
// NOTE: do this only in case of failure
if ( dwResult != ERROR_SUCCESS ) { // ...
FreeMemory( &pwszFilePath );
// re-init the out params to their default values
*pwszPath = NULL; }
// return the result
return dwResult; }
DWORD PrepareCompleteEFIPath( PFILE_PATH pfpSource, LPCWSTR pwszDevicePath, LPWSTR* pwszEFIPath, DWORD* pdwLength ) { //
// local variables
DWORD dwLength = 0; LPWSTR pwszBuffer = NULL; BOOL bSecondChance = FALSE; PFILE_PATH pfpFilePath = NULL; DWORD dwResult = ERROR_SUCCESS; NTSTATUS status = STATUS_SUCCESS; LPCWSTR pwszSourceFilePath = NULL; LPCWSTR pwszSourceDevicePath = NULL;
//
// implementation
//
// check the input
if ( pfpSource == NULL || pwszDevicePath == NULL || pwszEFIPath == NULL || pdwLength == NULL ) { dwResult = ERROR_INVALID_PARAMETER; goto cleanup; }
//
// we need to translate the source file path into NT file path format
//
dwLength = 1024;
try_again:
// allocate memory for the file path structure
pfpFilePath = (PFILE_PATH) AllocateMemory( dwLength ); if ( pfpFilePath == NULL ) { dwResult = ERROR_NOT_ENOUGH_MEMORY; goto cleanup; }
// attempt to translate the file path
status = NtTranslateFilePath( pfpSource, FILE_PATH_TYPE_NT, pfpFilePath, &dwLength ); if ( NOT NT_SUCCESS( status ) ) { // release the memory that is allocated for target path structure
FreeMemory( &pfpFilePath );
if ( status == STATUS_BUFFER_TOO_SMALL && bSecondChance == FALSE ) { // give a second try
bSecondChance = TRUE; goto try_again; } else { // error occured -- cannot recover
dwResult = RtlNtStatusToDosError( status ); goto cleanup; } }
// get the pointer to the source device path
pwszSourceDevicePath = (LPCWSTR) pfpFilePath->FilePath; if ( pwszSourceDevicePath == NULL ) { dwResult = ERROR_INVALID_PARAMETER; goto cleanup; }
// check whether the pwszSourceDevicePath and pwszDevicePath that is
// passed to the fuction are same or different
if ( StringCompare( pwszSourceDevicePath, pwszDevicePath, TRUE, 0 ) == 0 ) { dwResult = ERROR_ALREADY_EXISTS; goto cleanup; }
// get the length of the source device path -- +1 for null character
dwLength = StringLengthW( pwszSourceDevicePath, 0 ) + 1;
// check whether the directory path exists or not
// this can be easily determined based on the length of the device path
// and total of the structure
if ( pfpFilePath->Length <= (FIELD_OFFSET( FILE_PATH, FilePath ) + dwLength) ) { // the condition 'less than' will never be true -- but equal might
// that means there is no directory path associated to this file path
// so simply return
//
// NOTE: this is only for safety sake -- this case will never occur
//
dwResult = (DWORD) STG_E_UNKNOWN; goto cleanup; }
//
// file path exists --
// this is placed very next to device path seperated by '\0' terminator
pwszSourceFilePath = pwszSourceDevicePath + dwLength;
// sum the lengths of the device path (passed by the caller) and directory path (got from source file path)
// NOTE: +3 ==> ( one '\0' character for each path )
dwLength = StringLengthW( pwszDevicePath, 0 ) + StringLengthW( pwszSourceFilePath, 0 ) + 3;
// now allocate memory
// extra one as safety guard
pwszBuffer = AllocateMemory( (dwLength + 1) * sizeof( WCHAR ) ); if ( pwszBuffer == NULL ) { dwResult = ERROR_NOT_ENOUGH_MEMORY; goto cleanup; }
// copy the new device path (which is passed by the caller) to the newly allocated buffer
StringCopyW( pwszBuffer, pwszDevicePath, dwLength );
// increment the pointer leaving one space for UNICODE '\0' character
StringCopyW( pwszBuffer + (StringLengthW( pwszBuffer, 0 ) + 1), pwszSourceFilePath, dwLength - (StringLengthW( pwszBuffer, 0 ) + 1) );
// success
dwResult = ERROR_SUCCESS; *pwszEFIPath = pwszBuffer; *pdwLength = dwLength + 1; // extra one which we allocated as safe guard
cleanup:
// free the memory allocated for path translation
FreeMemory( &pfpFilePath );
// free memory allocated for buffer space
// NOTE: release this memory only in case of error
if ( dwResult != ERROR_SUCCESS ) { // ...
FreeMemory( &pwszBuffer );
// also, set the 'out' parameters to their default values
*pdwLength = 0; *pwszEFIPath = NULL; }
// return
return dwResult; }
BOOL MatchPath( PFILE_PATH pfpSource, LPCWSTR pwszDevicePath, LPCWSTR pwszFilePath ) { //
// local variables
DWORD dwLength = 0; BOOL bSecondChance = FALSE; PFILE_PATH pfpFilePath = NULL; DWORD dwResult = ERROR_SUCCESS; NTSTATUS status = STATUS_SUCCESS; LPCWSTR pwszSourceFilePath = NULL; LPCWSTR pwszSourceDevicePath = NULL;
//
// implementation
//
// check the input
if ( pfpSource == NULL || (pwszDevicePath == NULL && pwszFilePath == NULL) ) { dwResult = ERROR_INVALID_PARAMETER; goto cleanup; }
//
// we need to translate the source file path into NT file path format
//
dwLength = 1024;
try_again:
// allocate memory for the file path structure
pfpFilePath = (PFILE_PATH) AllocateMemory( dwLength ); if ( pfpFilePath == NULL ) { dwResult = ERROR_NOT_ENOUGH_MEMORY; goto cleanup; }
// attempt to translate the file path
status = NtTranslateFilePath( pfpSource, FILE_PATH_TYPE_NT, pfpFilePath, &dwLength ); if ( NOT NT_SUCCESS( status ) ) { // release the memory that is allocated for target path structure
FreeMemory( &pfpFilePath );
if ( status == STATUS_BUFFER_TOO_SMALL && bSecondChance == FALSE ) { // give a second try
bSecondChance = TRUE; goto try_again; } else { // error occured -- cannot recover
dwResult = RtlNtStatusToDosError( status ); goto cleanup; } }
// get the pointer to the source device path
pwszSourceDevicePath = (LPCWSTR) pfpFilePath->FilePath; if ( pwszSourceDevicePath == NULL ) { dwResult = ERROR_INVALID_PARAMETER; goto cleanup; }
// get the length of the source device path -- +1 for null character
dwLength = StringLengthW( pwszSourceDevicePath, 0 ) + 1;
// check whether the file path exists or not
// this can be easily determined based on the length of the device path
// and total of the structure
if ( pfpFilePath->Length <= (FIELD_OFFSET( FILE_PATH, FilePath ) + dwLength) ) { // the condition 'less than' will never be true -- but equal might
// that means there is no file path associated to this file_path
// so simply return
//
// NOTE: this is only for safety sake -- this case will never occur
//
dwResult = (DWORD) STG_E_UNKNOWN; goto cleanup; }
//
// file path exists --
// this is placed very next to device path seperated by '\0' terminator
pwszSourceFilePath = pwszSourceDevicePath + dwLength;
// check whether the pwszSourceDevicePath and pwszDevicePath that
// is passed to the fuction are same or different
if ( pwszDevicePath != NULL && StringCompare( pwszSourceDevicePath, pwszDevicePath, TRUE, 0 ) != 0 ) { dwResult = ERROR_NOT_FOUND; goto cleanup; }
// check whether the pwszSourceFilePath and pwszFilePath that
// is passed to the fuction are same or different
if ( pwszFilePath != NULL && StringCompare( pwszSourceFilePath, pwszFilePath, TRUE, 0 ) != 0 ) { dwResult = ERROR_NOT_FOUND; goto cleanup; }
// entries matched
dwResult = ERROR_ALREADY_EXISTS;
cleanup:
// free the memory allocated for path translation
FreeMemory( &pfpFilePath );
// return
return (dwResult == ERROR_ALREADY_EXISTS); }
///////////////////////////////////////////////////////////////////////////////
// parser
///////////////////////////////////////////////////////////////////////////////
DWORD ProcessOptions( DWORD argc, LPCWSTR argv[], PTCLONE_PARAMS pParams ) { //
// local variables
DWORD dwResult = 0; BOOL bClone = FALSE; PTCMDPARSER2 pcmdOption = NULL; TCMDPARSER2 cmdOptions[ OI_CLONE_COUNT ]; // check inputs
if ( argc == 0 || argv == NULL || pParams == NULL ) { dwResult = ERROR_INVALID_PARAMETER; goto cleanup; }
// init the entire structure with zero's
ZeroMemory( cmdOptions, SIZE_OF_ARRAY( cmdOptions )* sizeof( TCMDPARSER2 ) );
// -clone
pcmdOption = &cmdOptions[ OI_CLONE_MAIN ]; pcmdOption->dwCount = 1; pcmdOption->pValue = &bClone; pcmdOption->dwType = CP_TYPE_BOOLEAN; pcmdOption->pwszOptions = OPTION_CLONE; StringCopyA( pcmdOption->szSignature, "PARSER2", 8 );
// -?
pcmdOption = &cmdOptions[ OI_CLONE_HELP ]; pcmdOption->dwCount = 1; pcmdOption->dwFlags = CP2_USAGE; pcmdOption->dwType = CP_TYPE_BOOLEAN; pcmdOption->pValue = &pParams->bUsage; pcmdOption->pwszOptions = OPTION_CLONE_HELP; StringCopyA( pcmdOption->szSignature, "PARSER2", 8 );
// -sg
pcmdOption = &cmdOptions[ OI_CLONE_SOURCE_GUID ]; pcmdOption->dwCount = 1; pcmdOption->dwType = CP_TYPE_TEXT; pcmdOption->pwszOptions = OPTION_CLONE_SOURCE_GUID; StringCopyA( pcmdOption->szSignature, "PARSER2", 8 ); pcmdOption->dwFlags = CP2_ALLOCMEMORY | CP2_VALUE_TRIMINPUT | CP2_VALUE_NONULL;
// -tg
pcmdOption = &cmdOptions[ OI_CLONE_TARGET_GUID ]; pcmdOption->dwCount = 1; pcmdOption->dwType = CP_TYPE_TEXT; pcmdOption->pwszOptions = OPTION_CLONE_TARGET_GUID; StringCopyA( pcmdOption->szSignature, "PARSER2", 8 ); pcmdOption->dwFlags = CP2_ALLOCMEMORY | CP2_VALUE_TRIMINPUT | CP2_VALUE_NONULL | CP2_MANDATORY;
// -d
pcmdOption = &cmdOptions[ OI_CLONE_FRIENDLY_NAME_REPLACE ]; pcmdOption->dwCount = 1; pcmdOption->dwType = CP_TYPE_TEXT; StringCopyA( pcmdOption->szSignature, "PARSER2", 8 ); pcmdOption->pwszOptions = OPTION_CLONE_FRIENDLY_NAME_REPLACE; pcmdOption->dwFlags = CP2_ALLOCMEMORY | CP2_VALUE_TRIMINPUT | CP2_VALUE_NONULL;
// -d+
pcmdOption = &cmdOptions[ OI_CLONE_FRIENDLY_NAME_APPEND ]; pcmdOption->dwCount = 1; pcmdOption->dwType = CP_TYPE_TEXT; StringCopyA( pcmdOption->szSignature, "PARSER2", 8 ); pcmdOption->pwszOptions = OPTION_CLONE_FRIENDLY_NAME_APPEND; pcmdOption->dwFlags = CP2_ALLOCMEMORY | CP2_VALUE_TRIMINPUT | CP2_VALUE_NONULL;
// -id
pcmdOption = &cmdOptions[ OI_CLONE_BOOT_ID ]; pcmdOption->dwCount = 1; pcmdOption->dwType = CP_TYPE_UNUMERIC; pcmdOption->pValue = &pParams->lBootId; pcmdOption->pwszOptions = OPTION_CLONE_BOOT_ID; StringCopyA( pcmdOption->szSignature, "PARSER2", 8 );
// -upgdrv
pcmdOption = &cmdOptions[ OI_CLONE_DRIVER_UPDATE ]; pcmdOption->dwCount = 1; pcmdOption->dwType = CP_TYPE_BOOLEAN; pcmdOption->pwszOptions = OPTION_CLONE_DRIVER_UPDATE; pcmdOption->pValue = &pParams->bDriverUpdate; StringCopyA( pcmdOption->szSignature, "PARSER2", 8 );
//
// do the parsing
pParams->bVerbose = TRUE; // default value -- user need not specify "/v" explicitly
if ( DoParseParam2( argc, argv, OI_CLONE_MAIN, OI_CLONE_COUNT, cmdOptions, 0 ) == FALSE ) { dwResult = GetLastError(); goto cleanup; }
//
// validate the input parameters
//
// check the usage option
if ( pParams->bUsage == TRUE ) { if ( argc > 3 ) { // no other options are accepted along with -? option
dwResult = (DWORD) MK_E_SYNTAX; SetReason( MSG_ERROR_INVALID_USAGE_REQUEST ); goto cleanup; } else { // no need of furthur checking of the values
dwResult = ERROR_SUCCESS; goto cleanup; } }
// -d and -d+ are mutually exclusive --
// that is, -d and -d+ cannot be specified at a time --
// but it is ok even if both are not specified
if ( cmdOptions[ OI_CLONE_FRIENDLY_NAME_APPEND ].pValue != NULL && cmdOptions[ OI_CLONE_FRIENDLY_NAME_REPLACE ].pValue != NULL ) { dwResult = (DWORD) MK_E_SYNTAX; SetReason( MSG_ERROR_INVALID_DESCRIPTION_COMBINATION ); goto cleanup; }
// get the buffer pointers allocated by command line parser
pParams->dwFriendlyNameType = BOOTENTRY_FRIENDLYNAME_NONE; pParams->pwszSourceGuid = cmdOptions[ OI_CLONE_SOURCE_GUID ].pValue; pParams->pwszTargetGuid = cmdOptions[ OI_CLONE_TARGET_GUID ].pValue; if ( cmdOptions[ OI_CLONE_FRIENDLY_NAME_APPEND ].pValue != NULL ) { pParams->dwFriendlyNameType = BOOTENTRY_FRIENDLYNAME_APPEND; pParams->pwszFriendlyName = cmdOptions[ OI_CLONE_FRIENDLY_NAME_APPEND ].pValue; } else if ( cmdOptions[ OI_CLONE_FRIENDLY_NAME_REPLACE ].pValue != NULL ) { pParams->dwFriendlyNameType = BOOTENTRY_FRIENDLYNAME_REPLACE; pParams->pwszFriendlyName = cmdOptions[ OI_CLONE_FRIENDLY_NAME_REPLACE ].pValue; }
// -id and -sg are mutually exclusive options
// also, -upddrv also should not be specified when -id is specified
if ( cmdOptions[ OI_CLONE_BOOT_ID ].dwActuals != 0 ) { if ( pParams->pwszSourceGuid != NULL || pParams->bDriverUpdate == TRUE ) { dwResult = (DWORD) MK_E_SYNTAX; SetReason( MSG_ERROR_INVALID_BOOT_ID_COMBINATION ); goto cleanup; } } else { // default value
pParams->lBootId = -1; }
// -d or -d+ should not be specified when -upddrv is specified
if ( pParams->pwszFriendlyName != NULL && pParams->bDriverUpdate == TRUE ) { dwResult = (DWORD) MK_E_SYNTAX; SetReason( MSG_ERROR_INVALID_UPDDRV_COMBINATION ); goto cleanup; }
// -sg should be specified when -upddrv switch is specified
if ( pParams->bDriverUpdate == TRUE && pParams->pwszSourceGuid == NULL ) { dwResult = (DWORD) MK_E_SYNTAX; SetReason( MSG_ERROR_NO_SGUID_WITH_UPDDRV ); goto cleanup; }
// success
dwResult = ERROR_SUCCESS;
cleanup:
// return
return dwResult; }
DWORD DisplayCloneHelp() { // local variables
DWORD dwIndex = IDS_CLONE_BEGIN_IA64 ;
// ...
for(;dwIndex <=IDS_CLONE_END_IA64;dwIndex++) { ShowMessage( stdout, GetResString(dwIndex) ); }
// return
return ERROR_SUCCESS; }
|