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.

2278 lines
73 KiB

  1. #include "pch.h"
  2. #include "resource.h"
  3. #include "BootCfg.h"
  4. #include "BootCfg64.h"
  5. #include <strsafe.h>
  6. //
  7. // custom macros
  8. //
  9. #define NOT !
  10. #define FORMAT_FILE_PATH L"signature(%s)"
  11. #define FORMAT_FILE_PATH_EX L"signature({%s})"
  12. //
  13. // custom error codes
  14. //
  15. #define ERROR_PARTIAL_SUCCESS 0x40080001
  16. #define ERROR_FAILED 0x40080002
  17. //
  18. // externs
  19. //
  20. extern LIST_ENTRY BootEntries;
  21. extern LIST_ENTRY ActiveUnorderedBootEntries;
  22. extern LIST_ENTRY InactiveUnorderedBootEntries;
  23. //
  24. // parameter / switches index
  25. #define OI_CLONE_MAIN 0
  26. #define OI_CLONE_SOURCE_GUID 1
  27. #define OI_CLONE_TARGET_GUID 2
  28. #define OI_CLONE_FRIENDLY_NAME_REPLACE 3
  29. #define OI_CLONE_FRIENDLY_NAME_APPEND 4
  30. #define OI_CLONE_BOOT_ID 5
  31. #define OI_CLONE_DRIVER_UPDATE 6
  32. #define OI_CLONE_HELP 7
  33. #define OI_CLONE_COUNT 8
  34. // switch names
  35. #define OPTION_CLONE L"clone"
  36. #define OPTION_CLONE_SOURCE_GUID L"sg"
  37. #define OPTION_CLONE_TARGET_GUID L"tg"
  38. #define OPTION_CLONE_FRIENDLY_NAME_REPLACE L"d"
  39. #define OPTION_CLONE_FRIENDLY_NAME_APPEND L"d+"
  40. #define OPTION_CLONE_BOOT_ID L"id"
  41. #define OPTION_CLONE_HELP L"?"
  42. #define OPTION_CLONE_DRIVER_UPDATE L"upddrv"
  43. // default friendly name
  44. #define DEFAULT_FRIENDLY_NAME GetResString2( IDS_CLONE_DEFAULT_FRIENDLY_NAME, 0 )
  45. // resource strings
  46. #define CLONE_ZERO_BOOT_ENTRIES GetResString2( IDS_CLONE_ZERO_BOOT_ENTRIES, 0 )
  47. #define CLONE_RANGE_ZERO_BOOT_ENTRIES GetResString2( IDS_CLONE_RANGE_ZERO_BOOT_ENTRIES, 0 )
  48. #define CLONE_SUCCESS GetResString2( IDS_CLONE_SUCCESS, 0 )
  49. #define CLONE_FAILED GetResString2( IDS_CLONE_FAILED, 0 )
  50. #define CLONE_PARTIAL GetResString2( IDS_CLONE_PARTIAL, 0 )
  51. #define CLONE_INVALID_BOOT_ENTRY GetResString2( IDS_CLONE_INVALID_BOOT_ENTRY, 0 )
  52. #define CLONE_ALREADY_EXISTS GetResString2( IDS_CLONE_ALREADY_EXISTS, 0 )
  53. #define CLONE_BOOT_ENTRY_SUCCESS GetResString2( IDS_CLONE_BOOT_ENTRY_SUCCESS, 0 )
  54. #define CLONE_INVALID_SOURCE_GUID GetResString2( IDS_CLONE_INVALID_SOURCE_GUID, 0 )
  55. #define CLONE_INVALID_TARGET_GUID GetResString2( IDS_CLONE_INVALID_TARGET_GUID, 0 )
  56. #define CLONE_INVALID_DRIVER_ENTRY GetResString2( IDS_CLONE_INVALID_DRIVER_ENTRY, 0 )
  57. #define CLONE_DRIVER_ALREADY_EXISTS GetResString2( IDS_CLONE_DRIVER_ALREADY_EXISTS, 0 )
  58. #define CLONE_ZERO_DRIVER_ENTRIES GetResString2( IDS_CLONE_ZERO_DRIVER_ENTRIES, 0 )
  59. #define CLONE_DRIVER_ENTRY_SUCCESS GetResString2( IDS_CLONE_DRIVER_ENTRY_SUCCESS, 0 )
  60. #define CLONE_DETAILED_TRACE GetResString2( IDS_CLONE_DETAILED_TRACE, 0 )
  61. #define MSG_ERROR_INVALID_USAGE_REQUEST GetResString2( IDS_ERROR_INVALID_USAGE_REQUEST, 0 )
  62. #define MSG_ERROR_INVALID_DESCRIPTION_COMBINATION GetResString2( IDS_ERROR_INVALID_DESCRIPTION_COMBINATION, 0 )
  63. #define MSG_ERROR_INVALID_BOOT_ID_COMBINATION GetResString2( IDS_ERROR_INVALID_BOOT_ID_COMBINATION, 0 )
  64. #define MSG_ERROR_INVALID_UPDDRV_COMBINATION GetResString2( IDS_ERROR_INVALID_UPDDRV_COMBINATION, 0 )
  65. #define MSG_ERROR_NO_SGUID_WITH_UPDDRV GetResString2( IDS_ERROR_NO_SGUID_WITH_UPDDRV, 0 )
  66. //
  67. // internal structure
  68. //
  69. typedef struct __tagCloneParameters
  70. {
  71. BOOL bUsage;
  72. LONG lBootId;
  73. BOOL bVerbose;
  74. BOOL bDriverUpdate;
  75. LPWSTR pwszSourcePath;
  76. LPWSTR pwszTargetPath;
  77. LPWSTR pwszSourceGuid;
  78. LPWSTR pwszTargetGuid;
  79. LPWSTR pwszFriendlyName;
  80. DWORD dwFriendlyNameType;
  81. } TCLONE_PARAMS, *PTCLONE_PARAMS;
  82. //
  83. // enum's
  84. //
  85. enum {
  86. BOOTENTRY_FRIENDLYNAME_NONE = 0,
  87. BOOTENTRY_FRIENDLYNAME_APPEND, BOOTENTRY_FRIENDLYNAME_REPLACE
  88. };
  89. //
  90. // prototypes
  91. //
  92. // parser
  93. DWORD DisplayCloneHelp();
  94. DWORD ProcessOptions( DWORD argc, LPCWSTR argv[], PTCLONE_PARAMS pParams );
  95. // helper functions
  96. DWORD TranslateEFIPathToNTPath( LPCWSTR pwszGUID, LPVOID* pwszPath );
  97. BOOL MatchPath( PFILE_PATH pfpSource, LPCWSTR pwszDevicePath, LPCWSTR pwszFilePath );
  98. DWORD PrepareCompleteEFIPath( PFILE_PATH pfpSource,
  99. LPCWSTR pwszDevicePath,
  100. LPWSTR* pwszEFIPath, DWORD* pdwLength );
  101. // efi driver cloners
  102. DWORD LoadDriverEntries( PEFI_DRIVER_ENTRY_LIST* ppDriverEntries );
  103. LONG FindDriverEntryWithTargetEFI( PEFI_DRIVER_ENTRY_LIST pdeList, DWORD dwSourceIndex,
  104. PEFI_DRIVER_ENTRY pdeSource, LPCWSTR pwszDevicePath );
  105. DWORD DoDriverEntryClone( PEFI_DRIVER_ENTRY_LIST pbeList,
  106. LPCWSTR pwszSourceEFI, LPCWSTR pwszTargetEFI,
  107. LPCWSTR pwszFriendlyName, DWORD dwFriendlyNameType, BOOL bVerbose );
  108. DWORD CloneDriverEntry( PEFI_DRIVER_ENTRY pbeSource, LPCWSTR pwszEFIPath,
  109. LPCWSTR pwszFriendlyName, DWORD dwFriendlyNameType );
  110. // boot entry cloners
  111. DWORD CloneBootEntry( PBOOT_ENTRY pbeSource, LPCWSTR pwszEFIPath,
  112. LPCWSTR pwszFriendlyName, DWORD dwFriendlyNameType );
  113. DWORD DoBootEntryClone( PBOOT_ENTRY_LIST pbeList, LPCWSTR pwszSourceEFI,
  114. LPCWSTR pwszTargetEFI, LONG lIndexFrom, LONG lIndexTo,
  115. LPCWSTR pwszFriendlyName, DWORD dwFriendlyNameType, BOOL bVerbose );
  116. //
  117. // functionality
  118. //
  119. DWORD ProcessCloneSwitch_IA64( IN DWORD argc, IN LPCTSTR argv[] )
  120. {
  121. //
  122. // local variables
  123. NTSTATUS status;
  124. DWORD dwResult = 0;
  125. DWORD dwLength = 0;
  126. DWORD dwExitCode = 0;
  127. TCLONE_PARAMS paramsClone;
  128. BOOLEAN wasEnabled = FALSE;
  129. PEFI_DRIVER_ENTRY_LIST pDriverEntries = NULL;
  130. // init to zero's
  131. ZeroMemory( &paramsClone, sizeof( TCLONE_PARAMS ) );
  132. // process the command line options
  133. dwResult = ProcessOptions( argc, argv, &paramsClone );
  134. if ( dwResult != ERROR_SUCCESS )
  135. {
  136. // display one blank line -- for clarity purpose
  137. ShowMessage( stderr, L"\n" );
  138. // ...
  139. dwExitCode = 1;
  140. ShowLastErrorEx( stderr, SLE_ERROR | SLE_INTERNAL );
  141. goto cleanup;
  142. }
  143. // check if user requested for help
  144. if ( paramsClone.bUsage == TRUE )
  145. {
  146. // display usage for this option
  147. DisplayCloneHelp();
  148. dwExitCode = 0;
  149. goto cleanup;
  150. }
  151. // display one blank line -- for clarity purpose
  152. ShowMessage( stderr, L"\n" );
  153. // initialize the EFI -- only if user specifies the index
  154. if ( paramsClone.bDriverUpdate == FALSE )
  155. {
  156. dwResult = InitializeEFI();
  157. // check the result of load operation
  158. if ( dwResult != ERROR_SUCCESS )
  159. {
  160. // NOTE: message will be displayed in the associated funtions itself
  161. dwExitCode = 1;
  162. goto cleanup;
  163. }
  164. }
  165. else if ( paramsClone.bDriverUpdate == TRUE )
  166. {
  167. //
  168. // load the drivers
  169. // enable the privilege that is necessary to query/set NVRAM.
  170. status = RtlAdjustPrivilege( SE_SYSTEM_ENVIRONMENT_PRIVILEGE, TRUE, FALSE, &wasEnabled );
  171. if ( NOT NT_SUCCESS( status ) )
  172. {
  173. dwExitCode = 1;
  174. dwResult = RtlNtStatusToDosError( status );
  175. SetLastError( dwResult );
  176. ShowLastErrorEx( stderr, SLE_TYPE_ERROR | SLE_SYSTEM );
  177. goto cleanup;
  178. }
  179. // load the drivers now
  180. dwResult = LoadDriverEntries( &pDriverEntries );
  181. if ( dwResult != ERROR_SUCCESS )
  182. {
  183. dwExitCode = 1;
  184. SetLastError( dwResult );
  185. ShowLastErrorEx( stderr, SLE_TYPE_ERROR | SLE_SYSTEM );
  186. goto cleanup;
  187. }
  188. }
  189. // translate the source guid path into NT path - if needed
  190. if ( paramsClone.pwszSourceGuid != NULL )
  191. {
  192. dwResult = TranslateEFIPathToNTPath(
  193. paramsClone.pwszSourceGuid, &paramsClone.pwszSourcePath );
  194. if ( dwResult != ERROR_SUCCESS )
  195. {
  196. dwExitCode = 1;
  197. ShowMessage( stderr, CLONE_INVALID_SOURCE_GUID );
  198. goto cleanup;
  199. }
  200. }
  201. // translate the target guid into NT path
  202. dwResult = TranslateEFIPathToNTPath(
  203. paramsClone.pwszTargetGuid, &paramsClone.pwszTargetPath );
  204. if ( dwResult != ERROR_SUCCESS )
  205. {
  206. dwExitCode = 1;
  207. ShowMessage( stderr, CLONE_INVALID_TARGET_GUID );
  208. goto cleanup;
  209. }
  210. // actual operation ...
  211. if ( paramsClone.bDriverUpdate == FALSE )
  212. {
  213. // by default, if user did not specify the friendly name, we will assume
  214. // that users wants to the append the default string viz. "(clone)"
  215. if ( paramsClone.pwszFriendlyName == NULL )
  216. {
  217. // determine the length of the default friendly name
  218. // and allocate buffer with length
  219. dwLength = StringLength( DEFAULT_FRIENDLY_NAME, 0 ) + 2;
  220. paramsClone.pwszFriendlyName = AllocateMemory( dwLength + 5 );
  221. if ( paramsClone.pwszFriendlyName == NULL )
  222. {
  223. dwExitCode = 1;
  224. SetLastError( ERROR_NOT_ENOUGH_MEMORY );
  225. ShowLastErrorEx( stderr, SLE_TYPE_ERROR | SLE_SYSTEM );
  226. goto cleanup;
  227. }
  228. // copy the default string into this buffer and
  229. // change the friednly name type to append
  230. paramsClone.dwFriendlyNameType = BOOTENTRY_FRIENDLYNAME_APPEND;
  231. StringCopy( paramsClone.pwszFriendlyName, DEFAULT_FRIENDLY_NAME, dwLength );
  232. }
  233. // do the boot entry cloning
  234. dwResult = DoBootEntryClone(
  235. NULL, paramsClone.pwszSourcePath,
  236. paramsClone.pwszTargetPath, paramsClone.lBootId, -1,
  237. paramsClone.pwszFriendlyName, paramsClone.dwFriendlyNameType, paramsClone.bVerbose );
  238. }
  239. else if ( paramsClone.bDriverUpdate == TRUE )
  240. {
  241. // do the driver cloning
  242. dwResult = DoDriverEntryClone(
  243. pDriverEntries, paramsClone.pwszSourcePath, paramsClone.pwszTargetPath,
  244. paramsClone.pwszFriendlyName, paramsClone.dwFriendlyNameType, paramsClone.bVerbose );
  245. }
  246. // determine the exit code based on the error code
  247. switch( dwResult )
  248. {
  249. case ERROR_SUCCESS:
  250. dwExitCode = 0;
  251. break;
  252. case ERROR_FAILED:
  253. dwExitCode = 1;
  254. break;
  255. case ERROR_PARTIAL_SUCCESS:
  256. dwExitCode = 0;
  257. break;
  258. default:
  259. // can never oocur
  260. dwExitCode = 1;
  261. break;
  262. }
  263. cleanup:
  264. // release the memory
  265. FreeMemory( &pDriverEntries );
  266. FreeMemory( &paramsClone.pwszSourcePath );
  267. FreeMemory( &paramsClone.pwszTargetPath );
  268. FreeMemory( &paramsClone.pwszSourceGuid );
  269. FreeMemory( &paramsClone.pwszTargetGuid );
  270. FreeMemory( &paramsClone.pwszFriendlyName );
  271. // return
  272. return dwExitCode;
  273. }
  274. ///////////////////////////////////////////////////////////////////////////////
  275. // boot entries specific implementation
  276. //////////////////////////////////////////////////////////////////////////////
  277. DWORD DoBootEntryClone( PBOOT_ENTRY_LIST pbeList, LPCWSTR pwszSourceEFI,
  278. LPCWSTR pwszTargetEFI, LONG lIndexFrom, LONG lIndexTo,
  279. LPCWSTR pwszFriendlyName, DWORD dwFriendlyNameType, BOOL bVerbose )
  280. {
  281. // local variables
  282. DWORD dwResult = 0;
  283. BOOL bClone = FALSE;
  284. LONG lCurrentIndex = 0;
  285. BOOL bExitFromLoop = FALSE;
  286. PLIST_ENTRY pBootList = NULL;
  287. PBOOT_ENTRY pBootEntry = NULL;
  288. PFILE_PATH pfpBootFilePath = NULL;
  289. PMY_BOOT_ENTRY pMyBootEntry = NULL;
  290. DWORD dwAttempted = 0, dwFailed = 0;
  291. //
  292. // check the input parameter
  293. //
  294. if ( pwszTargetEFI == NULL || (lIndexTo != -1 && lIndexFrom > lIndexTo) ||
  295. (dwFriendlyNameType != BOOTENTRY_FRIENDLYNAME_NONE && pwszFriendlyName == NULL) )
  296. {
  297. dwResult = ERROR_INVALID_PARAMETER;
  298. goto cleanup;
  299. }
  300. // pbeList is a unreferenced parameter
  301. UNREFERENCED_PARAMETER( pbeList );
  302. // if the 'to' index is not specified, then we treat the 'to' index to match
  303. // with the 'from' index
  304. if ( lIndexFrom != -1 && lIndexTo == -1 )
  305. {
  306. lIndexTo = lIndexFrom;
  307. }
  308. // traverse thru the list of boot entries
  309. for( pBootList = BootEntries.Flink; pBootList != &BootEntries; pBootList = pBootList->Flink )
  310. {
  311. // increment the loop counter
  312. bClone = FALSE;
  313. lCurrentIndex = -1;
  314. dwResult = ERROR_SUCCESS;
  315. // get the boot entry
  316. pMyBootEntry = CONTAINING_RECORD( pBootList, MY_BOOT_ENTRY, ListEntry );
  317. if( NOT MBE_IS_NT( pMyBootEntry ) )
  318. {
  319. // this is not a valid boot entry we are looking for skip
  320. continue;
  321. }
  322. // extract the boot id and actual boot entry
  323. lCurrentIndex = pMyBootEntry->myId;
  324. pBootEntry = &pMyBootEntry->NtBootEntry;
  325. // check if the current boot index falls within the index or not
  326. if ( lIndexFrom != -1 )
  327. {
  328. bClone = (lCurrentIndex >= lIndexFrom && lCurrentIndex <= lIndexTo);
  329. }
  330. // extended filtering
  331. if ( pwszSourceEFI != NULL )
  332. {
  333. if ( lIndexFrom == -1 || (lIndexFrom != -1 && bClone == TRUE) )
  334. {
  335. // extract the boot file path
  336. pfpBootFilePath = (PFILE_PATH) ADD_OFFSET( pBootEntry, BootFilePathOffset );
  337. // check whether it matches or not
  338. bClone = MatchPath( pfpBootFilePath, pwszSourceEFI, NULL );
  339. }
  340. }
  341. // clone the boot entry -- only if filtering results in TRUE
  342. bExitFromLoop = FALSE;
  343. if ( bClone == TRUE || (pwszSourceEFI == NULL && lIndexFrom == -1) )
  344. {
  345. // increment the attempted list
  346. dwAttempted++;
  347. // do the operation
  348. dwResult = CloneBootEntry( pBootEntry,
  349. pwszTargetEFI, pwszFriendlyName, dwFriendlyNameType );
  350. // check the result
  351. if ( dwResult != ERROR_SUCCESS )
  352. {
  353. // increment the failures count
  354. dwFailed++;
  355. // check whether this particular instance of operation is target for
  356. // multiple entries or single entry
  357. if ( lIndexFrom == -1 || ((lIndexTo - lIndexFrom + 1) > 1) )
  358. {
  359. // check the severity for the error occured
  360. switch( dwResult )
  361. {
  362. case STG_E_UNKNOWN: // unknown error -- unrecoverable
  363. case ERROR_INVALID_PARAMETER: // code error
  364. case ERROR_NOT_ENOUGH_MEMORY: // unrecovarable case
  365. {
  366. bExitFromLoop = TRUE;
  367. break;
  368. }
  369. case ERROR_ALREADY_EXISTS:
  370. {
  371. // duplicate boot entry
  372. if ( bVerbose == TRUE )
  373. {
  374. ShowMessageEx( stdout, 1, TRUE, CLONE_ALREADY_EXISTS, lCurrentIndex );
  375. }
  376. // ...
  377. dwResult = ERROR_SUCCESS;
  378. break;
  379. }
  380. default:
  381. case ERROR_FILE_NOT_FOUND:
  382. case ERROR_PATH_NOT_FOUND:
  383. {
  384. // dont know how to handle this case
  385. if ( bVerbose == TRUE )
  386. {
  387. SetLastError( dwResult );
  388. SaveLastError();
  389. ShowMessageEx( stdout, 2, TRUE, CLONE_INVALID_BOOT_ENTRY, lCurrentIndex, GetReason() );
  390. }
  391. // ...
  392. dwResult = ERROR_SUCCESS;
  393. break;
  394. }
  395. }
  396. }
  397. else
  398. {
  399. // since this is a single entry clone operation
  400. // break from the loop
  401. bExitFromLoop = TRUE;
  402. }
  403. }
  404. else
  405. {
  406. if ( bVerbose == TRUE )
  407. {
  408. ShowMessageEx( stdout, 1, TRUE, CLONE_BOOT_ENTRY_SUCCESS, lCurrentIndex );
  409. }
  410. }
  411. }
  412. // exit from the loop - if needed
  413. if ( bExitFromLoop == TRUE )
  414. {
  415. break;
  416. }
  417. }
  418. cleanup:
  419. // check the result of the operation
  420. if ( dwResult == ERROR_SUCCESS )
  421. {
  422. if ( dwAttempted == 0 )
  423. {
  424. // no boot entries at all
  425. dwResult = ERROR_FAILED;
  426. if ( lIndexFrom == -1 )
  427. {
  428. ShowMessage( stdout, CLONE_ZERO_BOOT_ENTRIES );
  429. }
  430. else
  431. {
  432. ShowMessage( stdout, CLONE_RANGE_ZERO_BOOT_ENTRIES );
  433. }
  434. }
  435. else
  436. {
  437. // verify whether all requested boot entries are processed or not
  438. if ( lIndexFrom != -1 && dwAttempted != (lIndexTo - lIndexFrom + 1) )
  439. {
  440. // warning - not all boot entries were parsed -- invalid bounds were specified
  441. //
  442. // NOTE: in the current implementation, this can never occur
  443. // this is because, the input parameters for this option does accept
  444. // only the /id which will be treated as 'lIndexStart'
  445. //
  446. }
  447. if ( dwFailed == 0 )
  448. {
  449. // nothing failed -- success
  450. dwResult = ERROR_SUCCESS;
  451. SetLastError( ERROR_SUCCESS );
  452. ShowLastErrorEx( stdout, SLE_TYPE_SUCCESS | SLE_SYSTEM );
  453. }
  454. else if ( dwAttempted == dwFailed )
  455. {
  456. // nothing succeeded -- completely failed
  457. dwResult = ERROR_FAILED;
  458. ShowMessage( stderr, CLONE_FAILED );
  459. // show verbose hint
  460. if ( bVerbose == FALSE )
  461. {
  462. ShowMessage( stderr, CLONE_DETAILED_TRACE );
  463. }
  464. }
  465. else
  466. {
  467. // parital success
  468. dwResult = ERROR_PARTIAL_SUCCESS;
  469. ShowMessage( stderr, CLONE_PARTIAL );
  470. // show verbose hint
  471. if ( bVerbose == FALSE )
  472. {
  473. ShowMessage( stderr, CLONE_DETAILED_TRACE );
  474. }
  475. }
  476. }
  477. }
  478. else
  479. {
  480. // check the reason for failure
  481. switch( dwResult )
  482. {
  483. case STG_E_UNKNOWN: // unknown error -- unrecoverable
  484. case ERROR_INVALID_PARAMETER: // code error
  485. case ERROR_NOT_ENOUGH_MEMORY: // unrecovarable case
  486. {
  487. SetLastError( dwResult );
  488. ShowLastErrorEx( stderr, SLE_TYPE_ERROR | SLE_SYSTEM );
  489. break;
  490. }
  491. case ERROR_ALREADY_EXISTS:
  492. {
  493. ShowMessageEx( stdout, 1, TRUE, CLONE_ALREADY_EXISTS, lIndexFrom );
  494. break;
  495. }
  496. default:
  497. case ERROR_FILE_NOT_FOUND:
  498. case ERROR_PATH_NOT_FOUND:
  499. {
  500. SetLastError( dwResult );
  501. SaveLastError();
  502. ShowMessageEx( stdout, 2, TRUE, CLONE_INVALID_BOOT_ENTRY, lIndexFrom, GetReason() );
  503. break;
  504. }
  505. }
  506. // error code
  507. dwResult = ERROR_FAILED;
  508. }
  509. // return
  510. return dwResult;
  511. }
  512. DWORD CloneBootEntry( PBOOT_ENTRY pbeSource, LPCWSTR pwszEFIPath,
  513. LPCWSTR pwszFriendlyName, DWORD dwFriendlyNameType )
  514. {
  515. //
  516. // local variables
  517. DWORD dwResult = ERROR_SUCCESS;
  518. NTSTATUS status = STATUS_SUCCESS;
  519. // friendly name
  520. DWORD dwFriendlyNameLength = 0;
  521. LPWSTR pwszTargetFriendlyName = NULL;
  522. LPCWSTR pwszSourceFriendlyName = NULL;
  523. // os options
  524. DWORD dwOsOptionsLength = 0;
  525. PWINDOWS_OS_OPTIONS pOsOptions = NULL;
  526. // boot file path
  527. DWORD dwEFIPathLength = 0;
  528. DWORD dwBootFilePathLength = 0;
  529. PFILE_PATH pfpBootFilePath = NULL;
  530. LPWSTR pwszFullEFIPath = NULL;
  531. // boot entry
  532. ULONG ulId = 0;
  533. ULONG ulIdCount = 0;
  534. ULONG* pulIdsArray = NULL;
  535. DWORD dwBootEntryLength = 0;
  536. PBOOT_ENTRY pBootEntry = NULL;
  537. //
  538. // implementation
  539. //
  540. // check the input
  541. if ( pbeSource == NULL || pwszEFIPath == NULL ||
  542. (dwFriendlyNameType != BOOTENTRY_FRIENDLYNAME_NONE && pwszFriendlyName == NULL) )
  543. {
  544. dwResult = ERROR_INVALID_PARAMETER;
  545. goto cleanup;
  546. }
  547. //
  548. // validate the boot file in the source boot entry
  549. //
  550. // extract the boot file path
  551. pfpBootFilePath = (PFILE_PATH) ADD_OFFSET( pbeSource, BootFilePathOffset );
  552. // attempt to translate the file path
  553. status = NtTranslateFilePath( pfpBootFilePath, FILE_PATH_TYPE_NT, NULL, &dwBootFilePathLength );
  554. // reset the pBootFilePath and dwBootFilePathLength variables
  555. pfpBootFilePath = NULL;
  556. dwBootFilePathLength = 0;
  557. // now verify the result of the translation
  558. if ( NOT NT_SUCCESS( status ) )
  559. {
  560. if ( status == STATUS_BUFFER_TOO_SMALL )
  561. {
  562. // source boot entry is a valid one
  563. dwResult = ERROR_SUCCESS;
  564. }
  565. else
  566. {
  567. // error occured -- cannot recover
  568. dwResult = RtlNtStatusToDosError( status );
  569. goto cleanup;
  570. }
  571. }
  572. //
  573. // prepare "friendly name"
  574. //
  575. // determine the source friendly name and its length
  576. dwFriendlyNameLength = 0;
  577. pwszSourceFriendlyName = NULL;
  578. switch( dwFriendlyNameType )
  579. {
  580. case BOOTENTRY_FRIENDLYNAME_NONE:
  581. case BOOTENTRY_FRIENDLYNAME_APPEND:
  582. {
  583. pwszSourceFriendlyName = (LPCWSTR) ADD_OFFSET( pbeSource, FriendlyNameOffset );
  584. dwFriendlyNameLength = StringLengthW( pwszSourceFriendlyName, 0 ) + 1;
  585. break;
  586. }
  587. default:
  588. // do nothing
  589. break;
  590. }
  591. // add the length of the friendly name that needs to be added -- if exists
  592. if ( pwszFriendlyName != NULL )
  593. {
  594. dwFriendlyNameLength += StringLengthW( pwszFriendlyName, 0 ) + 1;
  595. }
  596. // allocate memory for the friendly name
  597. pwszTargetFriendlyName = (LPWSTR) AllocateMemory( (dwFriendlyNameLength + 1) * sizeof( WCHAR ) );
  598. if ( pwszTargetFriendlyName == NULL )
  599. {
  600. dwResult = ERROR_NOT_ENOUGH_MEMORY;
  601. goto cleanup;
  602. }
  603. // prepare the friendly name
  604. StringCopyW( pwszTargetFriendlyName, L"", dwFriendlyNameLength );
  605. // ...
  606. if ( pwszSourceFriendlyName != NULL )
  607. {
  608. StringConcat( pwszTargetFriendlyName, pwszSourceFriendlyName, dwFriendlyNameLength );
  609. }
  610. // ...
  611. if ( pwszFriendlyName != NULL )
  612. {
  613. // add one space b/w the existing and concatenating string
  614. if ( pwszSourceFriendlyName != NULL )
  615. {
  616. StringConcat( pwszTargetFriendlyName, L" ", dwFriendlyNameLength );
  617. }
  618. // ...
  619. StringConcat( pwszTargetFriendlyName, pwszFriendlyName, dwFriendlyNameLength );
  620. }
  621. //
  622. // prepare "OS Options"
  623. //
  624. // NOTE:
  625. // -----
  626. // though the os options are NULL, it will still consume some space (refer the structre of
  627. // BOOT_ENTRY -- that is the reason why the default length of OS OPTIONS is ANYSIZE_ARRAY)
  628. pOsOptions = NULL;
  629. dwOsOptionsLength = ANYSIZE_ARRAY;
  630. if ( pbeSource->OsOptionsLength != 0 )
  631. {
  632. // allocate memory for os options
  633. dwOsOptionsLength = pbeSource->OsOptionsLength;
  634. pOsOptions = (PWINDOWS_OS_OPTIONS) AllocateMemory( dwOsOptionsLength );
  635. if ( pOsOptions == NULL )
  636. {
  637. dwResult = ERROR_NOT_ENOUGH_MEMORY;
  638. goto cleanup;
  639. }
  640. // copy the contents
  641. CopyMemory( pOsOptions, &pbeSource->OsOptions, dwOsOptionsLength );
  642. }
  643. //
  644. // boot file path
  645. //
  646. // the 'FilePath' variable in FILE_PATH variable contains two variables
  647. // each seperated by a NULL terminated character
  648. // the first part designates the DEVICE PATH
  649. // and the second part designated the DIRECTORY / FILE PATH
  650. // we already have the device path (pwszEFIPath) -- but we need to get the
  651. // DIRECTORY / FILE PATH -- this we will get from the source boot entry
  652. pfpBootFilePath = (PFILE_PATH) ADD_OFFSET( pbeSource, BootFilePathOffset );
  653. dwResult = PrepareCompleteEFIPath( pfpBootFilePath, pwszEFIPath, &pwszFullEFIPath, &dwEFIPathLength );
  654. if ( dwResult != ERROR_SUCCESS )
  655. {
  656. // since the memory reference in pBootFilePath is not allocated
  657. // in this function, it is important to reset the pointer to NULL
  658. // this avoids the crash in the program
  659. pfpBootFilePath = NULL;
  660. // ...
  661. goto cleanup;
  662. }
  663. // now determine the memory size that needs to be allocated for FILE_PATH structure
  664. // and align up to the even memory bounday
  665. pfpBootFilePath = NULL;
  666. dwBootFilePathLength = FIELD_OFFSET(FILE_PATH, FilePath) + (dwEFIPathLength * sizeof( WCHAR ));
  667. // allocate memory
  668. pfpBootFilePath = (PFILE_PATH) AllocateMemory( dwBootFilePathLength );
  669. if ( pfpBootFilePath == NULL )
  670. {
  671. dwResult = ERROR_NOT_ENOUGH_MEMORY;
  672. goto cleanup;
  673. }
  674. // initialize the file path structure
  675. ZeroMemory( pfpBootFilePath, dwBootFilePathLength );
  676. pfpBootFilePath->Length = dwBootFilePathLength;
  677. pfpBootFilePath->Type = FILE_PATH_TYPE_NT;
  678. pfpBootFilePath->Version = FILE_PATH_VERSION;
  679. CopyMemory( pfpBootFilePath->FilePath, pwszFullEFIPath, dwEFIPathLength * sizeof( WCHAR ) );
  680. //
  681. // finally, create the boot entry
  682. //
  683. // determine the size for the BOOT_ENTRY structure
  684. dwBootEntryLength = FIELD_OFFSET( BOOT_ENTRY, OsOptions ) +
  685. dwOsOptionsLength +
  686. (dwFriendlyNameLength * sizeof(WCHAR)) +
  687. dwBootFilePathLength +
  688. sizeof(WCHAR) + // align the FriendlyName on WCHAR
  689. sizeof(DWORD); // align the BootFilePath on DWORD
  690. // allocate memory
  691. pBootEntry = (PBOOT_ENTRY) AllocateMemory( dwBootEntryLength );
  692. if ( pBootEntry == NULL )
  693. {
  694. dwResult = ERROR_NOT_ENOUGH_MEMORY;
  695. goto cleanup;
  696. }
  697. // ...
  698. ZeroMemory( pBootEntry, dwBootEntryLength );
  699. pBootEntry->Id = 0L;
  700. pBootEntry->Length = dwBootEntryLength;
  701. pBootEntry->Version = BOOT_ENTRY_VERSION;
  702. pBootEntry->OsOptionsLength = dwOsOptionsLength;
  703. pBootEntry->Attributes = BOOT_ENTRY_ATTRIBUTE_DEFAULT;
  704. // align the friendly name on WCHR boundary
  705. pBootEntry->FriendlyNameOffset =
  706. ALIGN_UP( FIELD_OFFSET(BOOT_ENTRY, OsOptions) + dwOsOptionsLength, WCHAR );
  707. // align the boot file path on DWORD boundary
  708. pBootEntry->BootFilePathOffset =
  709. ALIGN_UP( pBootEntry->FriendlyNameOffset + (dwFriendlyNameLength * sizeof(WCHAR)), DWORD );
  710. // fill the boot entry
  711. CopyMemory( pBootEntry->OsOptions, pOsOptions, dwOsOptionsLength );
  712. CopyMemory( ADD_OFFSET( pBootEntry, BootFilePathOffset ), pfpBootFilePath, dwBootFilePathLength );
  713. CopyMemory(
  714. ADD_OFFSET( pBootEntry, FriendlyNameOffset ),
  715. pwszTargetFriendlyName, (dwFriendlyNameLength * sizeof(WCHAR) ) );
  716. //
  717. // add the prepared boot entry
  718. //
  719. status = NtAddBootEntry( pBootEntry, &ulId );
  720. if ( NOT NT_SUCCESS( status ) )
  721. {
  722. dwResult = RtlNtStatusToDosError( status );
  723. goto cleanup;
  724. }
  725. //
  726. // Add the entry to the boot order.
  727. //
  728. ulIdCount = 32L;
  729. pulIdsArray = (PULONG) AllocateMemory( ulIdCount * sizeof(ULONG) );
  730. if ( pulIdsArray == NULL )
  731. {
  732. dwResult = ERROR_NOT_ENOUGH_MEMORY;
  733. goto cleanup;
  734. }
  735. // query the boot entry order
  736. // NOTE: we will doing error check for this function call bit later
  737. status = NtQueryBootEntryOrder( pulIdsArray, &ulIdCount );
  738. // need room in the buffer for the new entry.
  739. if ( 31L < ulIdCount )
  740. {
  741. // release the current memory allocation for id's
  742. FreeMemory( &pulIdsArray );
  743. // allocate new memory and query again
  744. pulIdsArray = (PULONG) AllocateMemory( (ulIdCount+1) * sizeof(ULONG));
  745. if ( pulIdsArray == NULL )
  746. {
  747. dwResult = ERROR_NOT_ENOUGH_MEMORY;
  748. goto cleanup;
  749. }
  750. // ...
  751. status = NtQueryBootEntryOrder( pulIdsArray, &ulIdCount );
  752. }
  753. // check the result of the boot entries query operation
  754. if ( NOT NT_SUCCESS( status ) )
  755. {
  756. dwResult = RtlNtStatusToDosError( status );
  757. goto cleanup;
  758. }
  759. // set the boot entry order
  760. ulIdCount++;
  761. *(pulIdsArray + (ulIdCount - 1)) = ulId;
  762. status = NtSetBootEntryOrder( pulIdsArray, ulIdCount );
  763. if ( NOT NT_SUCCESS( status ) )
  764. {
  765. dwResult = RtlNtStatusToDosError( status );
  766. goto cleanup;
  767. }
  768. // success
  769. dwResult = ERROR_SUCCESS;
  770. cleanup:
  771. // release the memory allocated
  772. FreeMemory( &pOsOptions );
  773. FreeMemory( &pBootEntry );
  774. FreeMemory( &pulIdsArray );
  775. FreeMemory( &pfpBootFilePath );
  776. FreeMemory( &pwszFullEFIPath );
  777. FreeMemory( &pwszTargetFriendlyName );
  778. // return
  779. return dwResult;
  780. }
  781. ///////////////////////////////////////////////////////////////////////////////
  782. // efi drivers specific implementation
  783. //////////////////////////////////////////////////////////////////////////////
  784. DWORD LoadDriverEntries( PEFI_DRIVER_ENTRY_LIST* ppDriverEntries )
  785. {
  786. //
  787. // local variables
  788. DWORD dwSize = 0;
  789. BOOL bSecondChance = FALSE;
  790. DWORD dwResult = ERROR_SUCCESS;
  791. NTSTATUS status = STATUS_SUCCESS;
  792. const DWORD dwDefaultSize = 1024;
  793. PEFI_DRIVER_ENTRY_LIST pDriverEntries = NULL;
  794. //
  795. // implementation
  796. //
  797. // check the input
  798. if ( ppDriverEntries == NULL )
  799. {
  800. dwResult = ERROR_INVALID_PARAMETER;
  801. goto cleanup;
  802. }
  803. // default size is assumed as 1024 bytes
  804. bSecondChance = FALSE;
  805. dwSize = dwDefaultSize;
  806. try_again:
  807. // allocate memory
  808. pDriverEntries = AllocateMemory( dwSize );
  809. if ( pDriverEntries == NULL )
  810. {
  811. dwResult = ERROR_NOT_ENOUGH_MEMORY;
  812. goto cleanup;
  813. }
  814. // try to get the boot entries
  815. status = NtEnumerateDriverEntries( pDriverEntries, &dwSize );
  816. if ( NOT NT_SUCCESS( status ) )
  817. {
  818. // release the memory that is allocated for target path structure
  819. FreeMemory( &pDriverEntries );
  820. // check the error
  821. if ( status == STATUS_BUFFER_TOO_SMALL && bSecondChance == FALSE )
  822. {
  823. // give a second try
  824. bSecondChance = TRUE;
  825. goto try_again;
  826. }
  827. else
  828. {
  829. // error occured -- cannot recover
  830. dwResult = RtlNtStatusToDosError( status );
  831. goto cleanup;
  832. }
  833. }
  834. // operation is succes
  835. dwResult = ERROR_SUCCESS;
  836. *ppDriverEntries = pDriverEntries;
  837. cleanup:
  838. // need to release memory allocated for Driver entries in this function
  839. // should do this only in case of failure
  840. if ( dwResult != ERROR_SUCCESS )
  841. {
  842. FreeMemory( &pDriverEntries );
  843. }
  844. // return the result
  845. return dwResult;
  846. }
  847. DWORD DoDriverEntryClone( PEFI_DRIVER_ENTRY_LIST pdeList,
  848. LPCWSTR pwszSourceEFI, LPCWSTR pwszTargetEFI,
  849. LPCWSTR pwszFriendlyName, DWORD dwFriendlyNameType, BOOL bVerbose )
  850. {
  851. // local variables
  852. LONG lLoop = 0;
  853. DWORD dwResult = 0;
  854. BOOL bClone = FALSE;
  855. BOOL bExitFromLoop = FALSE;
  856. LPCWSTR pwszDriverName = NULL;
  857. PFILE_PATH pfpDriverFilePath = NULL;
  858. PEFI_DRIVER_ENTRY pDriverEntry = NULL;
  859. PEFI_DRIVER_ENTRY_LIST pdeMasterList = NULL;
  860. DWORD dwAttempted = 0, dwFailed = 0;
  861. //
  862. // check the input parameter
  863. //
  864. if ( pdeList == NULL || pwszSourceEFI == NULL || pwszTargetEFI == NULL ||
  865. (dwFriendlyNameType != BOOTENTRY_FRIENDLYNAME_NONE && pwszFriendlyName == NULL) )
  866. {
  867. dwResult = ERROR_INVALID_PARAMETER;
  868. goto cleanup;
  869. }
  870. // currently, the pwszFriendlyName is not considered -- so it should be NULL
  871. if ( pwszFriendlyName != NULL )
  872. {
  873. dwResult = ERROR_INVALID_PARAMETER;
  874. goto cleanup;
  875. }
  876. // traverse thru the list of driver entries
  877. lLoop = 0;
  878. bExitFromLoop = FALSE;
  879. pdeMasterList = pdeList; // save the pointer the original drivers list
  880. while ( bExitFromLoop == FALSE )
  881. {
  882. // increment the loop counter
  883. lLoop++;
  884. bClone = FALSE;
  885. dwResult = ERROR_SUCCESS;
  886. // get the reference to the current driver entry
  887. pDriverEntry = &pdeList->DriverEntry;
  888. if ( pDriverEntry == NULL )
  889. {
  890. // should never occur
  891. dwResult = (DWORD) STG_E_UNKNOWN;
  892. bExitFromLoop = TRUE;
  893. continue;
  894. }
  895. //
  896. // check whether the current driver's device matches with the requested path
  897. //
  898. // extract the driver file path
  899. pfpDriverFilePath = (PFILE_PATH) ADD_OFFSET( pDriverEntry, DriverFilePathOffset );
  900. // check whether it matches or not
  901. bClone = MatchPath( pfpDriverFilePath, pwszSourceEFI, NULL );
  902. // clone the boot entry -- only if filtering results in TRUE
  903. if ( bClone == TRUE )
  904. {
  905. // updated the attempted count
  906. dwAttempted++;
  907. // get the driver name (it is nothing but the friendly name)
  908. pwszDriverName = (LPCWSTR) ADD_OFFSET( pDriverEntry, FriendlyNameOffset );
  909. // do the operation
  910. // but before proceeding confirm that this particular
  911. // driver entry is not existing
  912. if ( FindDriverEntryWithTargetEFI( pdeMasterList, lLoop,
  913. pDriverEntry, pwszTargetEFI ) == -1 )
  914. {
  915. dwResult = CloneDriverEntry( pDriverEntry,
  916. pwszTargetEFI, pwszFriendlyName, dwFriendlyNameType );
  917. }
  918. else
  919. {
  920. dwResult = ERROR_ALREADY_EXISTS;
  921. }
  922. // check the result
  923. if ( dwResult != ERROR_SUCCESS )
  924. {
  925. // update the failed count
  926. dwFailed++;
  927. // check the severity for the error occured
  928. switch( dwResult )
  929. {
  930. case STG_E_UNKNOWN: // unknown error -- unrecoverable
  931. case ERROR_INVALID_PARAMETER: // code error
  932. case ERROR_NOT_ENOUGH_MEMORY: // unrecovarable case
  933. {
  934. bExitFromLoop = TRUE;
  935. break;
  936. }
  937. case ERROR_ALREADY_EXISTS:
  938. {
  939. // duplicate boot entry
  940. if ( bVerbose == TRUE )
  941. {
  942. ShowMessageEx( stdout, 1, TRUE, CLONE_DRIVER_ALREADY_EXISTS, pwszDriverName );
  943. }
  944. // ...
  945. dwResult = ERROR_SUCCESS;
  946. break;
  947. }
  948. default:
  949. case ERROR_FILE_NOT_FOUND:
  950. case ERROR_PATH_NOT_FOUND:
  951. {
  952. // dont know how to handle this case
  953. if ( bVerbose == TRUE )
  954. {
  955. SetLastError( dwResult );
  956. SaveLastError();
  957. ShowMessageEx( stdout, 2, TRUE, CLONE_INVALID_DRIVER_ENTRY, pwszDriverName, GetReason() );
  958. }
  959. // ...
  960. dwResult = ERROR_SUCCESS;
  961. break;
  962. }
  963. }
  964. }
  965. else
  966. {
  967. if ( bVerbose == TRUE )
  968. {
  969. ShowMessageEx( stdout, 1, TRUE, CLONE_DRIVER_ENTRY_SUCCESS, pwszDriverName );
  970. }
  971. }
  972. }
  973. // fetch the next pointer
  974. // do this only if the error the bExitFromLoop is not set in above blocks
  975. if ( bExitFromLoop == FALSE )
  976. {
  977. bExitFromLoop = (pdeList->NextEntryOffset == 0);
  978. pdeList = (PEFI_DRIVER_ENTRY_LIST) ADD_OFFSET( pdeList, NextEntryOffset );
  979. }
  980. }
  981. cleanup:
  982. // check the result of the operation
  983. if ( dwResult == ERROR_SUCCESS )
  984. {
  985. if ( dwAttempted == 0 )
  986. {
  987. // no driver entries at all
  988. dwResult = ERROR_FAILED;
  989. ShowMessage( stdout, CLONE_ZERO_DRIVER_ENTRIES );
  990. }
  991. else
  992. {
  993. if ( dwFailed == 0 )
  994. {
  995. // nothing failed -- success
  996. dwResult = ERROR_SUCCESS;
  997. SetLastError( ERROR_SUCCESS );
  998. ShowLastErrorEx( stdout, SLE_TYPE_SUCCESS | SLE_SYSTEM );
  999. }
  1000. else if ( dwAttempted == dwFailed )
  1001. {
  1002. // nothing succeeded -- completely failed
  1003. dwResult = ERROR_FAILED;
  1004. ShowMessage( stderr, CLONE_FAILED );
  1005. // show verbose hint
  1006. if ( bVerbose == FALSE )
  1007. {
  1008. ShowMessage( stderr, CLONE_DETAILED_TRACE );
  1009. }
  1010. }
  1011. else
  1012. {
  1013. // parital success
  1014. dwResult = ERROR_PARTIAL_SUCCESS;
  1015. ShowMessage( stderr, CLONE_PARTIAL );
  1016. // show verbose hint
  1017. if ( bVerbose == FALSE )
  1018. {
  1019. ShowMessage( stderr, CLONE_DETAILED_TRACE );
  1020. }
  1021. }
  1022. }
  1023. }
  1024. else
  1025. {
  1026. // check the reason for failure
  1027. switch( dwResult )
  1028. {
  1029. default:
  1030. case STG_E_UNKNOWN: // unknown error -- unrecoverable
  1031. case ERROR_INVALID_PARAMETER: // code error
  1032. case ERROR_NOT_ENOUGH_MEMORY: // unrecovarable case
  1033. {
  1034. SetLastError( dwResult );
  1035. ShowLastErrorEx( stderr, SLE_TYPE_ERROR | SLE_SYSTEM );
  1036. break;
  1037. }
  1038. }
  1039. // error code
  1040. dwResult = ERROR_FAILED;
  1041. }
  1042. // return
  1043. return dwResult;
  1044. }
  1045. DWORD CloneDriverEntry( PEFI_DRIVER_ENTRY pdeSource, LPCWSTR pwszEFIPath,
  1046. LPCWSTR pwszFriendlyName, DWORD dwFriendlyNameType )
  1047. {
  1048. //
  1049. // local variables
  1050. DWORD dwResult = ERROR_SUCCESS;
  1051. NTSTATUS status = STATUS_SUCCESS;
  1052. // friendly name
  1053. DWORD dwFriendlyNameLength = 0;
  1054. LPWSTR pwszTargetFriendlyName = NULL;
  1055. LPCWSTR pwszSourceFriendlyName = NULL;
  1056. // driver file path
  1057. DWORD dwEFIPathLength = 0;
  1058. DWORD dwDriverFilePathLength = 0;
  1059. PFILE_PATH pfpDriverFilePath = NULL;
  1060. LPWSTR pwszFullEFIPath = NULL;
  1061. // driver entry
  1062. ULONG ulId = 0;
  1063. ULONG ulIdCount = 0;
  1064. ULONG* pulIdsArray = NULL;
  1065. DWORD dwDriverEntryLength = 0;
  1066. PEFI_DRIVER_ENTRY pDriverEntry = NULL;
  1067. //
  1068. // implementation
  1069. //
  1070. // check the input
  1071. if ( pdeSource == NULL || pwszEFIPath == NULL ||
  1072. (dwFriendlyNameType != BOOTENTRY_FRIENDLYNAME_NONE && pwszFriendlyName == NULL) )
  1073. {
  1074. dwResult = ERROR_INVALID_PARAMETER;
  1075. goto cleanup;
  1076. }
  1077. //
  1078. // validate the driver file in the source driver entry
  1079. //
  1080. // extract the driver file path
  1081. pfpDriverFilePath = (PFILE_PATH) ADD_OFFSET( pdeSource, DriverFilePathOffset );
  1082. // attempt to translate the file path
  1083. status = NtTranslateFilePath( pfpDriverFilePath, FILE_PATH_TYPE_NT, NULL, &dwDriverFilePathLength );
  1084. // reset the pDriverFilePath and dwDriverFilePathLength variables
  1085. pfpDriverFilePath = NULL;
  1086. dwDriverFilePathLength = 0;
  1087. // now verify the result of the translation
  1088. if ( NOT NT_SUCCESS( status ) )
  1089. {
  1090. if ( status == STATUS_BUFFER_TOO_SMALL )
  1091. {
  1092. // source driver entry is a valid one
  1093. dwResult = ERROR_SUCCESS;
  1094. }
  1095. else
  1096. {
  1097. // error occured -- cannot recover
  1098. dwResult = RtlNtStatusToDosError( status );
  1099. goto cleanup;
  1100. }
  1101. }
  1102. //
  1103. // prepare "friendly name"
  1104. //
  1105. // determine the source friendly name and its length
  1106. dwFriendlyNameLength = 0;
  1107. pwszSourceFriendlyName = NULL;
  1108. switch( dwFriendlyNameType )
  1109. {
  1110. case BOOTENTRY_FRIENDLYNAME_NONE:
  1111. case BOOTENTRY_FRIENDLYNAME_APPEND:
  1112. {
  1113. pwszSourceFriendlyName = (LPCWSTR) ADD_OFFSET( pdeSource, FriendlyNameOffset );
  1114. dwFriendlyNameLength = StringLengthW( pwszSourceFriendlyName, 0 ) + 1;
  1115. break;
  1116. }
  1117. default:
  1118. // do nothing
  1119. break;
  1120. }
  1121. // add the length of the friendly name that needs to be added -- if exists
  1122. if ( pwszFriendlyName != NULL )
  1123. {
  1124. dwFriendlyNameLength += StringLengthW( pwszFriendlyName, 0 ) + 1;
  1125. }
  1126. // allocate memory for the friendly name
  1127. pwszTargetFriendlyName = (LPWSTR) AllocateMemory( (dwFriendlyNameLength + 1) * sizeof( WCHAR ) );
  1128. if ( pwszTargetFriendlyName == NULL )
  1129. {
  1130. dwResult = ERROR_NOT_ENOUGH_MEMORY;
  1131. goto cleanup;
  1132. }
  1133. // prepare the friendly name
  1134. StringCopyW( pwszTargetFriendlyName, L"", dwFriendlyNameLength );
  1135. // ...
  1136. if ( pwszSourceFriendlyName != NULL )
  1137. {
  1138. StringConcat( pwszTargetFriendlyName, pwszSourceFriendlyName, dwFriendlyNameLength );
  1139. }
  1140. // ...
  1141. if ( pwszFriendlyName != NULL )
  1142. {
  1143. // add one space b/w the existing and concatenating string
  1144. if ( pwszSourceFriendlyName != NULL )
  1145. {
  1146. StringConcat( pwszTargetFriendlyName, L" ", dwFriendlyNameLength );
  1147. }
  1148. // ...
  1149. StringConcat( pwszTargetFriendlyName, pwszFriendlyName, dwFriendlyNameLength );
  1150. }
  1151. //
  1152. // driver file path
  1153. //
  1154. // the 'FilePath' variable in FILE_PATH variable contains two variables
  1155. // each seperated by a NULL terminated character
  1156. // the first part designates the DEVICE PATH
  1157. // and the second part designated the DIRECTORY / FILE PATH
  1158. // we already have the device path (pwszEFIPath) -- but we need to get the
  1159. // DIRECTORY / FILE PATH -- this we will get from the source driver entry
  1160. pfpDriverFilePath = (PFILE_PATH) ADD_OFFSET( pdeSource, DriverFilePathOffset );
  1161. dwResult = PrepareCompleteEFIPath( pfpDriverFilePath, pwszEFIPath, &pwszFullEFIPath, &dwEFIPathLength );
  1162. if ( dwResult != ERROR_SUCCESS )
  1163. {
  1164. // since the memory reference in pDriverFilePath is not allocated
  1165. // in this function, it is important to reset the pointer to NULL
  1166. // this avoids the crash in the program
  1167. pfpDriverFilePath = NULL;
  1168. // ...
  1169. goto cleanup;
  1170. }
  1171. // now determine the memory size that needs to be allocated for FILE_PATH structure
  1172. // and align up to the even memory bounday
  1173. pfpDriverFilePath = NULL;
  1174. dwDriverFilePathLength = FIELD_OFFSET(FILE_PATH, FilePath) + (dwEFIPathLength * sizeof( WCHAR ));
  1175. // allocate memory
  1176. pfpDriverFilePath = (PFILE_PATH) AllocateMemory( dwDriverFilePathLength );
  1177. if ( pfpDriverFilePath == NULL )
  1178. {
  1179. dwResult = ERROR_NOT_ENOUGH_MEMORY;
  1180. goto cleanup;
  1181. }
  1182. // initialize the file path structure
  1183. ZeroMemory( pfpDriverFilePath, dwDriverFilePathLength );
  1184. pfpDriverFilePath->Length = dwDriverFilePathLength;
  1185. pfpDriverFilePath->Type = FILE_PATH_TYPE_NT;
  1186. pfpDriverFilePath->Version = FILE_PATH_VERSION;
  1187. CopyMemory( pfpDriverFilePath->FilePath, pwszFullEFIPath, dwEFIPathLength * sizeof( WCHAR ) );
  1188. //
  1189. // finally, create the driver entry
  1190. //
  1191. // determine the size for the EFI_DRIVER_ENTRY structure
  1192. dwDriverEntryLength =
  1193. FIELD_OFFSET( EFI_DRIVER_ENTRY, DriverFilePathOffset ) +
  1194. (dwFriendlyNameLength * sizeof(WCHAR)) +
  1195. dwDriverFilePathLength +
  1196. sizeof(WCHAR) + // align the FriendlyName on WCHAR
  1197. sizeof(DWORD); // align the DriverFilePath on DWORD
  1198. // allocate memory
  1199. pDriverEntry = (PEFI_DRIVER_ENTRY) AllocateMemory( dwDriverEntryLength );
  1200. if ( pDriverEntry == NULL )
  1201. {
  1202. dwResult = ERROR_NOT_ENOUGH_MEMORY;
  1203. goto cleanup;
  1204. }
  1205. // ...
  1206. ZeroMemory( pDriverEntry, dwDriverEntryLength );
  1207. pDriverEntry->Id = 0L;
  1208. pDriverEntry->Length = dwDriverEntryLength;
  1209. pDriverEntry->Version = EFI_DRIVER_ENTRY_VERSION;
  1210. // align the friendly name on WCHR boundary
  1211. pDriverEntry->FriendlyNameOffset = ALIGN_UP( sizeof( EFI_DRIVER_ENTRY ), WCHAR );
  1212. // align the driver file path on DWORD boundary
  1213. pDriverEntry->DriverFilePathOffset =
  1214. ALIGN_UP( pDriverEntry->FriendlyNameOffset + (dwFriendlyNameLength * sizeof(WCHAR)), DWORD );
  1215. // fill the driver entry
  1216. CopyMemory( ADD_OFFSET( pDriverEntry, DriverFilePathOffset ), pfpDriverFilePath, dwDriverFilePathLength );
  1217. CopyMemory(
  1218. ADD_OFFSET( pDriverEntry, FriendlyNameOffset ),
  1219. pwszTargetFriendlyName, (dwFriendlyNameLength * sizeof(WCHAR) ) );
  1220. //
  1221. // add the prepared driver entry
  1222. //
  1223. status = NtAddDriverEntry( pDriverEntry, &ulId );
  1224. if ( NOT NT_SUCCESS( status ) )
  1225. {
  1226. dwResult = RtlNtStatusToDosError( status );
  1227. goto cleanup;
  1228. }
  1229. //
  1230. // ddd the entry to the driver order.
  1231. //
  1232. ulIdCount = 32L;
  1233. pulIdsArray = (PULONG) AllocateMemory( ulIdCount * sizeof(ULONG) );
  1234. if ( pulIdsArray == NULL )
  1235. {
  1236. dwResult = ERROR_NOT_ENOUGH_MEMORY;
  1237. goto cleanup;
  1238. }
  1239. // query the driver entry order
  1240. // NOTE: we will doing error check for this function call bit later
  1241. status = NtQueryDriverEntryOrder( pulIdsArray, &ulIdCount );
  1242. // need room in the buffer for the new entry.
  1243. if ( 31L < ulIdCount )
  1244. {
  1245. // release the current memory allocation for id's
  1246. FreeMemory( &pulIdsArray );
  1247. // allocate new memory and query again
  1248. pulIdsArray = (PULONG) AllocateMemory( (ulIdCount+1) * sizeof(ULONG));
  1249. if ( pulIdsArray == NULL )
  1250. {
  1251. dwResult = ERROR_NOT_ENOUGH_MEMORY;
  1252. goto cleanup;
  1253. }
  1254. // ...
  1255. status = NtQueryDriverEntryOrder( pulIdsArray, &ulIdCount );
  1256. }
  1257. // check the result of the driver entries query operation
  1258. if ( NOT NT_SUCCESS( status ) )
  1259. {
  1260. dwResult = RtlNtStatusToDosError( status );
  1261. goto cleanup;
  1262. }
  1263. // set the boot entry order
  1264. ulIdCount++;
  1265. *(pulIdsArray + (ulIdCount - 1)) = ulId;
  1266. status = NtSetDriverEntryOrder( pulIdsArray, ulIdCount );
  1267. if ( NOT NT_SUCCESS( status ) )
  1268. {
  1269. dwResult = RtlNtStatusToDosError( status );
  1270. goto cleanup;
  1271. }
  1272. // success
  1273. dwResult = ERROR_SUCCESS;
  1274. cleanup:
  1275. // release the memory allocated
  1276. FreeMemory( &pulIdsArray );
  1277. FreeMemory( &pDriverEntry );
  1278. FreeMemory( &pwszFullEFIPath );
  1279. FreeMemory( &pfpDriverFilePath );
  1280. FreeMemory( &pwszTargetFriendlyName );
  1281. // return
  1282. return dwResult;
  1283. }
  1284. LONG FindDriverEntryWithTargetEFI( PEFI_DRIVER_ENTRY_LIST pdeList, DWORD dwSourceIndex,
  1285. PEFI_DRIVER_ENTRY pdeSource, LPCWSTR pwszDevicePath )
  1286. {
  1287. // local variables
  1288. LONG lIndex = 0;
  1289. BOOL bExitFromLoop = FALSE;
  1290. PFILE_PATH pfpFilePath = NULL;
  1291. LPCWSTR pwszFilePath = NULL;
  1292. LPWSTR pwszFullFilePath = NULL;
  1293. PFILE_PATH pfpSourceFilePath = NULL;
  1294. PEFI_DRIVER_ENTRY pDriverEntry = NULL;
  1295. DWORD dw = 0, dwResult = 0, dwLength = 0;
  1296. // check the input parameters
  1297. if ( pdeList == NULL || pdeSource == NULL || pwszDevicePath == NULL )
  1298. {
  1299. dwResult = ERROR_INVALID_PARAMETER;
  1300. goto cleanup;
  1301. }
  1302. // extract the file path from the source driver entry
  1303. pfpSourceFilePath = (PFILE_PATH) ADD_OFFSET( pdeSource, DriverFilePathOffset );
  1304. // preare the efi path from the source path
  1305. // (replacing the source device path with the target device path)
  1306. //
  1307. // the 'FilePath' variable in FILE_PATH variable contains two variables
  1308. // each seperated by a NULL terminated character
  1309. // the first part designates the DEVICE PATH
  1310. // and the second part designated the DIRECTORY / FILE PATH
  1311. // we already have the device path (pwszEFIPath) -- but we need to get the
  1312. // DIRECTORY / FILE PATH -- this we will get from the source driver entry
  1313. //
  1314. dwResult = PrepareCompleteEFIPath( pfpSourceFilePath, pwszDevicePath, &pwszFullFilePath, &dwLength );
  1315. if ( dwResult != ERROR_SUCCESS )
  1316. {
  1317. goto cleanup;
  1318. }
  1319. // since we already the target device path -- we need the file path
  1320. // extract this info more just prepared full file path
  1321. dw = StringLengthW( pwszFullFilePath, 0 ) + 1; // +1 for null character
  1322. if ( dw > dwLength )
  1323. {
  1324. // error case -- this should never occure
  1325. dwResult = (DWORD) STG_E_UNKNOWN;
  1326. goto cleanup;
  1327. }
  1328. // ...
  1329. pwszFilePath = pwszFullFilePath + dw;
  1330. // traverse thru the list of driver entries
  1331. lIndex = 0;
  1332. bExitFromLoop = FALSE;
  1333. dwResult = ERROR_NOT_FOUND;
  1334. while ( bExitFromLoop == FALSE )
  1335. {
  1336. // increment the loop counter
  1337. lIndex++;
  1338. // get the reference to the current driver entry
  1339. pDriverEntry = &pdeList->DriverEntry;
  1340. if ( pDriverEntry == NULL )
  1341. {
  1342. // should never occur
  1343. dwResult = (DWORD) STG_E_UNKNOWN;
  1344. bExitFromLoop = TRUE;
  1345. continue;
  1346. }
  1347. // if the current index doesn't match with the one that we are comparing
  1348. // then only proceed with comparision otherwise skip this
  1349. if ( lIndex != dwSourceIndex )
  1350. {
  1351. // extract the driver file path
  1352. pfpFilePath = (PFILE_PATH) ADD_OFFSET( pDriverEntry, DriverFilePathOffset );
  1353. // compare the file paths
  1354. if ( MatchPath( pfpFilePath, pwszDevicePath, pwszFilePath ) == TRUE )
  1355. {
  1356. bExitFromLoop = TRUE;
  1357. dwResult = ERROR_ALREADY_EXISTS;
  1358. continue;
  1359. }
  1360. }
  1361. // fetch the next pointer
  1362. bExitFromLoop = (pdeList->NextEntryOffset == 0);
  1363. pdeList = (PEFI_DRIVER_ENTRY_LIST) ADD_OFFSET( pdeList, NextEntryOffset );
  1364. }
  1365. cleanup:
  1366. // release memory
  1367. FreeMemory( &pwszFullFilePath );
  1368. // result
  1369. return ((dwResult == ERROR_ALREADY_EXISTS) ? lIndex : -1);
  1370. }
  1371. ///////////////////////////////////////////////////////////////////////////////
  1372. // general helper functions
  1373. ///////////////////////////////////////////////////////////////////////////////
  1374. DWORD TranslateEFIPathToNTPath( LPCWSTR pwszGUID, LPVOID* pwszPath )
  1375. {
  1376. //
  1377. // local variables
  1378. HRESULT hr = S_OK;
  1379. BOOL bSecondChance = FALSE;
  1380. BOOL bExtendedFormat = FALSE;
  1381. DWORD dwResult = ERROR_SUCCESS;
  1382. NTSTATUS status = STATUS_SUCCESS;
  1383. // file path
  1384. DWORD dwFilePathLength = 0;
  1385. LPWSTR pwszFilePath = NULL;
  1386. // source FILE_PATH
  1387. DWORD dwSourceFilePathSize = 0;
  1388. PFILE_PATH pfpSourcePath = NULL;
  1389. // target FILE_PATH
  1390. DWORD dwLength = 0;
  1391. DWORD dwTargetFilePathSize = 0;
  1392. PFILE_PATH pfpTargetPath = NULL;
  1393. //
  1394. // implementation
  1395. //
  1396. // check the parameters
  1397. if ( pwszGUID == NULL || pwszPath == NULL )
  1398. {
  1399. dwResult = ERROR_INVALID_PARAMETER;
  1400. goto cleanup;
  1401. }
  1402. // determine whether we need to choose the extended formatting
  1403. // or normal formatting
  1404. bExtendedFormat = ( (*pwszGUID != L'{') && (*(pwszGUID + StringLengthW( pwszGUID, 0 ) - 1) != L'}') );
  1405. // default length
  1406. dwFilePathLength = MAX_STRING_LENGTH;
  1407. try_alloc:
  1408. //
  1409. // allocate memory for formatting the EFI path
  1410. pwszFilePath = AllocateMemory( (dwFilePathLength + 1) * sizeof( WCHAR ) );
  1411. if ( pwszFilePath == NULL )
  1412. {
  1413. dwResult = ERROR_NOT_ENOUGH_MEMORY;
  1414. goto cleanup;
  1415. }
  1416. // format EFI path
  1417. if ( bExtendedFormat == FALSE )
  1418. {
  1419. hr = StringCchPrintfW( pwszFilePath, dwFilePathLength, FORMAT_FILE_PATH, pwszGUID );
  1420. }
  1421. else
  1422. {
  1423. hr = StringCchPrintfW( pwszFilePath, dwFilePathLength, FORMAT_FILE_PATH_EX, pwszGUID );
  1424. }
  1425. // check the result -- if failed exit
  1426. if ( HRESULT_CODE( hr ) != S_OK )
  1427. {
  1428. // free the currently allocated block
  1429. FreeMemory( &pwszFilePath );
  1430. // increase the memory in blocks for MAX_STRING_LENGTH
  1431. // but do this only 4 times the originally allocated
  1432. if ( dwFilePathLength == (MAX_STRING_LENGTH * 4) )
  1433. {
  1434. // cannot afford to give some more tries -- exit
  1435. dwResult = (DWORD) STG_E_UNKNOWN;
  1436. goto cleanup;
  1437. }
  1438. else
  1439. {
  1440. dwFilePathLength *= MAX_STRING_LENGTH;
  1441. goto try_alloc;
  1442. }
  1443. }
  1444. // determine the actual length of the file path
  1445. dwFilePathLength = StringLengthW( pwszFilePath, 0 ) + 1;
  1446. // now determine the memory size that needs to be allocated for FILE_PATH structure
  1447. // and align up to the even memory bounday
  1448. dwSourceFilePathSize = FIELD_OFFSET( FILE_PATH, FilePath ) + (dwFilePathLength * sizeof(WCHAR));
  1449. // allocate memory for boot file path -- extra one byte is for safe guarding
  1450. pfpSourcePath = AllocateMemory( dwSourceFilePathSize + 1 );
  1451. if ( pfpSourcePath == NULL )
  1452. {
  1453. dwResult = ERROR_NOT_ENOUGH_MEMORY;
  1454. goto cleanup;
  1455. }
  1456. // initialize the source boot path
  1457. ZeroMemory( pfpSourcePath, dwSourceFilePathSize );
  1458. pfpSourcePath->Type = FILE_PATH_TYPE_ARC_SIGNATURE;
  1459. pfpSourcePath->Version = FILE_PATH_VERSION;
  1460. pfpSourcePath->Length = dwSourceFilePathSize;
  1461. CopyMemory( pfpSourcePath->FilePath, pwszFilePath, dwFilePathLength * sizeof(WCHAR) );
  1462. //
  1463. // do the translation
  1464. //
  1465. // default size for the target file path is same as the one for source file path
  1466. //
  1467. bSecondChance = FALSE;
  1468. dwTargetFilePathSize = dwSourceFilePathSize;
  1469. try_translate:
  1470. // allocate memory -- extra one byte is for safe guarding
  1471. pfpTargetPath = AllocateMemory( dwTargetFilePathSize + 1);
  1472. if ( pfpTargetPath == NULL )
  1473. {
  1474. dwResult = ERROR_NOT_ENOUGH_MEMORY;
  1475. goto cleanup;
  1476. }
  1477. // attempt to translate the file path
  1478. status = NtTranslateFilePath( pfpSourcePath,
  1479. FILE_PATH_TYPE_NT, pfpTargetPath, &dwTargetFilePathSize );
  1480. if ( NOT NT_SUCCESS( status ) )
  1481. {
  1482. // release the memory that is allocated for target path structure
  1483. FreeMemory( &pfpTargetPath );
  1484. if ( status == STATUS_BUFFER_TOO_SMALL && bSecondChance == FALSE )
  1485. {
  1486. // give a second try
  1487. bSecondChance = TRUE;
  1488. goto try_translate;
  1489. }
  1490. else
  1491. {
  1492. // error occured -- cannot recover
  1493. dwResult = RtlNtStatusToDosError( status );
  1494. goto cleanup;
  1495. }
  1496. }
  1497. // re-use the memory that is allocated for file path
  1498. // defintely the NT path will be less than the length of ARC Signature
  1499. // NOTE: since we are interested only in the device path, we use StringCopy
  1500. // which stops at the first null character -- otherwise, if we are interestedd in
  1501. // complete path, we need to CopyMemory
  1502. dwLength = StringLengthW( (LPCWSTR) pfpTargetPath->FilePath, 0 );
  1503. if ( dwLength < dwFilePathLength - 1 )
  1504. {
  1505. // copy the string contents
  1506. ZeroMemory( pwszFilePath, (dwFilePathLength - 1) * sizeof( WCHAR ) );
  1507. StringCopyW( pwszFilePath, (LPCWSTR) pfpTargetPath->FilePath, dwFilePathLength );
  1508. }
  1509. else
  1510. {
  1511. // re-allocate memory
  1512. dwLength++;
  1513. if ( ReallocateMemory( (VOID*) &pwszFilePath, (dwLength + 1) * sizeof( WCHAR ) ) == FALSE )
  1514. {
  1515. dwResult = ERROR_NOT_ENOUGH_MEMORY;
  1516. goto cleanup;
  1517. }
  1518. // ...
  1519. ZeroMemory( pwszFilePath, (dwLength + 1) * sizeof( WCHAR ) );
  1520. StringCopyW( pwszFilePath, (LPCWSTR) pfpTargetPath->FilePath, dwLength );
  1521. }
  1522. // translation is success
  1523. // return the translated file path
  1524. dwResult = ERROR_SUCCESS;
  1525. *pwszPath = pwszFilePath;
  1526. cleanup:
  1527. // free memory allocated for target path structure
  1528. FreeMemory( &pfpTargetPath );
  1529. // release the memory allocated for source path structure
  1530. FreeMemory( &pfpSourcePath );
  1531. // release memory allocated for string
  1532. // NOTE: do this only in case of failure
  1533. if ( dwResult != ERROR_SUCCESS )
  1534. {
  1535. // ...
  1536. FreeMemory( &pwszFilePath );
  1537. // re-init the out params to their default values
  1538. *pwszPath = NULL;
  1539. }
  1540. // return the result
  1541. return dwResult;
  1542. }
  1543. DWORD PrepareCompleteEFIPath( PFILE_PATH pfpSource,
  1544. LPCWSTR pwszDevicePath,
  1545. LPWSTR* pwszEFIPath, DWORD* pdwLength )
  1546. {
  1547. //
  1548. // local variables
  1549. DWORD dwLength = 0;
  1550. LPWSTR pwszBuffer = NULL;
  1551. BOOL bSecondChance = FALSE;
  1552. PFILE_PATH pfpFilePath = NULL;
  1553. DWORD dwResult = ERROR_SUCCESS;
  1554. NTSTATUS status = STATUS_SUCCESS;
  1555. LPCWSTR pwszSourceFilePath = NULL;
  1556. LPCWSTR pwszSourceDevicePath = NULL;
  1557. //
  1558. // implementation
  1559. //
  1560. // check the input
  1561. if ( pfpSource == NULL ||
  1562. pwszDevicePath == NULL ||
  1563. pwszEFIPath == NULL || pdwLength == NULL )
  1564. {
  1565. dwResult = ERROR_INVALID_PARAMETER;
  1566. goto cleanup;
  1567. }
  1568. //
  1569. // we need to translate the source file path into NT file path format
  1570. //
  1571. dwLength = 1024;
  1572. try_again:
  1573. // allocate memory for the file path structure
  1574. pfpFilePath = (PFILE_PATH) AllocateMemory( dwLength );
  1575. if ( pfpFilePath == NULL )
  1576. {
  1577. dwResult = ERROR_NOT_ENOUGH_MEMORY;
  1578. goto cleanup;
  1579. }
  1580. // attempt to translate the file path
  1581. status = NtTranslateFilePath( pfpSource, FILE_PATH_TYPE_NT, pfpFilePath, &dwLength );
  1582. if ( NOT NT_SUCCESS( status ) )
  1583. {
  1584. // release the memory that is allocated for target path structure
  1585. FreeMemory( &pfpFilePath );
  1586. if ( status == STATUS_BUFFER_TOO_SMALL && bSecondChance == FALSE )
  1587. {
  1588. // give a second try
  1589. bSecondChance = TRUE;
  1590. goto try_again;
  1591. }
  1592. else
  1593. {
  1594. // error occured -- cannot recover
  1595. dwResult = RtlNtStatusToDosError( status );
  1596. goto cleanup;
  1597. }
  1598. }
  1599. // get the pointer to the source device path
  1600. pwszSourceDevicePath = (LPCWSTR) pfpFilePath->FilePath;
  1601. if ( pwszSourceDevicePath == NULL )
  1602. {
  1603. dwResult = ERROR_INVALID_PARAMETER;
  1604. goto cleanup;
  1605. }
  1606. // check whether the pwszSourceDevicePath and pwszDevicePath that is
  1607. // passed to the fuction are same or different
  1608. if ( StringCompare( pwszSourceDevicePath, pwszDevicePath, TRUE, 0 ) == 0 )
  1609. {
  1610. dwResult = ERROR_ALREADY_EXISTS;
  1611. goto cleanup;
  1612. }
  1613. // get the length of the source device path -- +1 for null character
  1614. dwLength = StringLengthW( pwszSourceDevicePath, 0 ) + 1;
  1615. // check whether the directory path exists or not
  1616. // this can be easily determined based on the length of the device path
  1617. // and total of the structure
  1618. if ( pfpFilePath->Length <= (FIELD_OFFSET( FILE_PATH, FilePath ) + dwLength) )
  1619. {
  1620. // the condition 'less than' will never be true -- but equal might
  1621. // that means there is no directory path associated to this file path
  1622. // so simply return
  1623. //
  1624. // NOTE: this is only for safety sake -- this case will never occur
  1625. //
  1626. dwResult = (DWORD) STG_E_UNKNOWN;
  1627. goto cleanup;
  1628. }
  1629. //
  1630. // file path exists --
  1631. // this is placed very next to device path seperated by '\0' terminator
  1632. pwszSourceFilePath = pwszSourceDevicePath + dwLength;
  1633. // sum the lengths of the device path (passed by the caller) and directory path (got from source file path)
  1634. // NOTE: +3 ==> ( one '\0' character for each path )
  1635. dwLength = StringLengthW( pwszDevicePath, 0 ) + StringLengthW( pwszSourceFilePath, 0 ) + 3;
  1636. // now allocate memory
  1637. // extra one as safety guard
  1638. pwszBuffer = AllocateMemory( (dwLength + 1) * sizeof( WCHAR ) );
  1639. if ( pwszBuffer == NULL )
  1640. {
  1641. dwResult = ERROR_NOT_ENOUGH_MEMORY;
  1642. goto cleanup;
  1643. }
  1644. // copy the new device path (which is passed by the caller) to the newly allocated buffer
  1645. StringCopyW( pwszBuffer, pwszDevicePath, dwLength );
  1646. // increment the pointer leaving one space for UNICODE '\0' character
  1647. StringCopyW( pwszBuffer + (StringLengthW( pwszBuffer, 0 ) + 1),
  1648. pwszSourceFilePath, dwLength - (StringLengthW( pwszBuffer, 0 ) + 1) );
  1649. // success
  1650. dwResult = ERROR_SUCCESS;
  1651. *pwszEFIPath = pwszBuffer;
  1652. *pdwLength = dwLength + 1; // extra one which we allocated as safe guard
  1653. cleanup:
  1654. // free the memory allocated for path translation
  1655. FreeMemory( &pfpFilePath );
  1656. // free memory allocated for buffer space
  1657. // NOTE: release this memory only in case of error
  1658. if ( dwResult != ERROR_SUCCESS )
  1659. {
  1660. // ...
  1661. FreeMemory( &pwszBuffer );
  1662. // also, set the 'out' parameters to their default values
  1663. *pdwLength = 0;
  1664. *pwszEFIPath = NULL;
  1665. }
  1666. // return
  1667. return dwResult;
  1668. }
  1669. BOOL MatchPath( PFILE_PATH pfpSource, LPCWSTR pwszDevicePath, LPCWSTR pwszFilePath )
  1670. {
  1671. //
  1672. // local variables
  1673. DWORD dwLength = 0;
  1674. BOOL bSecondChance = FALSE;
  1675. PFILE_PATH pfpFilePath = NULL;
  1676. DWORD dwResult = ERROR_SUCCESS;
  1677. NTSTATUS status = STATUS_SUCCESS;
  1678. LPCWSTR pwszSourceFilePath = NULL;
  1679. LPCWSTR pwszSourceDevicePath = NULL;
  1680. //
  1681. // implementation
  1682. //
  1683. // check the input
  1684. if ( pfpSource == NULL || (pwszDevicePath == NULL && pwszFilePath == NULL) )
  1685. {
  1686. dwResult = ERROR_INVALID_PARAMETER;
  1687. goto cleanup;
  1688. }
  1689. //
  1690. // we need to translate the source file path into NT file path format
  1691. //
  1692. dwLength = 1024;
  1693. try_again:
  1694. // allocate memory for the file path structure
  1695. pfpFilePath = (PFILE_PATH) AllocateMemory( dwLength );
  1696. if ( pfpFilePath == NULL )
  1697. {
  1698. dwResult = ERROR_NOT_ENOUGH_MEMORY;
  1699. goto cleanup;
  1700. }
  1701. // attempt to translate the file path
  1702. status = NtTranslateFilePath( pfpSource, FILE_PATH_TYPE_NT, pfpFilePath, &dwLength );
  1703. if ( NOT NT_SUCCESS( status ) )
  1704. {
  1705. // release the memory that is allocated for target path structure
  1706. FreeMemory( &pfpFilePath );
  1707. if ( status == STATUS_BUFFER_TOO_SMALL && bSecondChance == FALSE )
  1708. {
  1709. // give a second try
  1710. bSecondChance = TRUE;
  1711. goto try_again;
  1712. }
  1713. else
  1714. {
  1715. // error occured -- cannot recover
  1716. dwResult = RtlNtStatusToDosError( status );
  1717. goto cleanup;
  1718. }
  1719. }
  1720. // get the pointer to the source device path
  1721. pwszSourceDevicePath = (LPCWSTR) pfpFilePath->FilePath;
  1722. if ( pwszSourceDevicePath == NULL )
  1723. {
  1724. dwResult = ERROR_INVALID_PARAMETER;
  1725. goto cleanup;
  1726. }
  1727. // get the length of the source device path -- +1 for null character
  1728. dwLength = StringLengthW( pwszSourceDevicePath, 0 ) + 1;
  1729. // check whether the file path exists or not
  1730. // this can be easily determined based on the length of the device path
  1731. // and total of the structure
  1732. if ( pfpFilePath->Length <= (FIELD_OFFSET( FILE_PATH, FilePath ) + dwLength) )
  1733. {
  1734. // the condition 'less than' will never be true -- but equal might
  1735. // that means there is no file path associated to this file_path
  1736. // so simply return
  1737. //
  1738. // NOTE: this is only for safety sake -- this case will never occur
  1739. //
  1740. dwResult = (DWORD) STG_E_UNKNOWN;
  1741. goto cleanup;
  1742. }
  1743. //
  1744. // file path exists --
  1745. // this is placed very next to device path seperated by '\0' terminator
  1746. pwszSourceFilePath = pwszSourceDevicePath + dwLength;
  1747. // check whether the pwszSourceDevicePath and pwszDevicePath that
  1748. // is passed to the fuction are same or different
  1749. if ( pwszDevicePath != NULL &&
  1750. StringCompare( pwszSourceDevicePath, pwszDevicePath, TRUE, 0 ) != 0 )
  1751. {
  1752. dwResult = ERROR_NOT_FOUND;
  1753. goto cleanup;
  1754. }
  1755. // check whether the pwszSourceFilePath and pwszFilePath that
  1756. // is passed to the fuction are same or different
  1757. if ( pwszFilePath != NULL &&
  1758. StringCompare( pwszSourceFilePath, pwszFilePath, TRUE, 0 ) != 0 )
  1759. {
  1760. dwResult = ERROR_NOT_FOUND;
  1761. goto cleanup;
  1762. }
  1763. // entries matched
  1764. dwResult = ERROR_ALREADY_EXISTS;
  1765. cleanup:
  1766. // free the memory allocated for path translation
  1767. FreeMemory( &pfpFilePath );
  1768. // return
  1769. return (dwResult == ERROR_ALREADY_EXISTS);
  1770. }
  1771. ///////////////////////////////////////////////////////////////////////////////
  1772. // parser
  1773. ///////////////////////////////////////////////////////////////////////////////
  1774. DWORD ProcessOptions( DWORD argc,
  1775. LPCWSTR argv[],
  1776. PTCLONE_PARAMS pParams )
  1777. {
  1778. //
  1779. // local variables
  1780. DWORD dwResult = 0;
  1781. BOOL bClone = FALSE;
  1782. PTCMDPARSER2 pcmdOption = NULL;
  1783. TCMDPARSER2 cmdOptions[ OI_CLONE_COUNT ];
  1784. // check inputs
  1785. if ( argc == 0 || argv == NULL || pParams == NULL )
  1786. {
  1787. dwResult = ERROR_INVALID_PARAMETER;
  1788. goto cleanup;
  1789. }
  1790. // init the entire structure with zero's
  1791. ZeroMemory( cmdOptions, SIZE_OF_ARRAY( cmdOptions )* sizeof( TCMDPARSER2 ) );
  1792. // -clone
  1793. pcmdOption = &cmdOptions[ OI_CLONE_MAIN ];
  1794. pcmdOption->dwCount = 1;
  1795. pcmdOption->pValue = &bClone;
  1796. pcmdOption->dwType = CP_TYPE_BOOLEAN;
  1797. pcmdOption->pwszOptions = OPTION_CLONE;
  1798. StringCopyA( pcmdOption->szSignature, "PARSER2", 8 );
  1799. // -?
  1800. pcmdOption = &cmdOptions[ OI_CLONE_HELP ];
  1801. pcmdOption->dwCount = 1;
  1802. pcmdOption->dwFlags = CP2_USAGE;
  1803. pcmdOption->dwType = CP_TYPE_BOOLEAN;
  1804. pcmdOption->pValue = &pParams->bUsage;
  1805. pcmdOption->pwszOptions = OPTION_CLONE_HELP;
  1806. StringCopyA( pcmdOption->szSignature, "PARSER2", 8 );
  1807. // -sg
  1808. pcmdOption = &cmdOptions[ OI_CLONE_SOURCE_GUID ];
  1809. pcmdOption->dwCount = 1;
  1810. pcmdOption->dwType = CP_TYPE_TEXT;
  1811. pcmdOption->pwszOptions = OPTION_CLONE_SOURCE_GUID;
  1812. StringCopyA( pcmdOption->szSignature, "PARSER2", 8 );
  1813. pcmdOption->dwFlags = CP2_ALLOCMEMORY | CP2_VALUE_TRIMINPUT | CP2_VALUE_NONULL;
  1814. // -tg
  1815. pcmdOption = &cmdOptions[ OI_CLONE_TARGET_GUID ];
  1816. pcmdOption->dwCount = 1;
  1817. pcmdOption->dwType = CP_TYPE_TEXT;
  1818. pcmdOption->pwszOptions = OPTION_CLONE_TARGET_GUID;
  1819. StringCopyA( pcmdOption->szSignature, "PARSER2", 8 );
  1820. pcmdOption->dwFlags = CP2_ALLOCMEMORY | CP2_VALUE_TRIMINPUT | CP2_VALUE_NONULL | CP2_MANDATORY;
  1821. // -d
  1822. pcmdOption = &cmdOptions[ OI_CLONE_FRIENDLY_NAME_REPLACE ];
  1823. pcmdOption->dwCount = 1;
  1824. pcmdOption->dwType = CP_TYPE_TEXT;
  1825. StringCopyA( pcmdOption->szSignature, "PARSER2", 8 );
  1826. pcmdOption->pwszOptions = OPTION_CLONE_FRIENDLY_NAME_REPLACE;
  1827. pcmdOption->dwFlags = CP2_ALLOCMEMORY | CP2_VALUE_TRIMINPUT | CP2_VALUE_NONULL;
  1828. // -d+
  1829. pcmdOption = &cmdOptions[ OI_CLONE_FRIENDLY_NAME_APPEND ];
  1830. pcmdOption->dwCount = 1;
  1831. pcmdOption->dwType = CP_TYPE_TEXT;
  1832. StringCopyA( pcmdOption->szSignature, "PARSER2", 8 );
  1833. pcmdOption->pwszOptions = OPTION_CLONE_FRIENDLY_NAME_APPEND;
  1834. pcmdOption->dwFlags = CP2_ALLOCMEMORY | CP2_VALUE_TRIMINPUT | CP2_VALUE_NONULL;
  1835. // -id
  1836. pcmdOption = &cmdOptions[ OI_CLONE_BOOT_ID ];
  1837. pcmdOption->dwCount = 1;
  1838. pcmdOption->dwType = CP_TYPE_UNUMERIC;
  1839. pcmdOption->pValue = &pParams->lBootId;
  1840. pcmdOption->pwszOptions = OPTION_CLONE_BOOT_ID;
  1841. StringCopyA( pcmdOption->szSignature, "PARSER2", 8 );
  1842. // -upgdrv
  1843. pcmdOption = &cmdOptions[ OI_CLONE_DRIVER_UPDATE ];
  1844. pcmdOption->dwCount = 1;
  1845. pcmdOption->dwType = CP_TYPE_BOOLEAN;
  1846. pcmdOption->pwszOptions = OPTION_CLONE_DRIVER_UPDATE;
  1847. pcmdOption->pValue = &pParams->bDriverUpdate;
  1848. StringCopyA( pcmdOption->szSignature, "PARSER2", 8 );
  1849. //
  1850. // do the parsing
  1851. pParams->bVerbose = TRUE; // default value -- user need not specify "/v" explicitly
  1852. if ( DoParseParam2( argc, argv, OI_CLONE_MAIN, OI_CLONE_COUNT, cmdOptions, 0 ) == FALSE )
  1853. {
  1854. dwResult = GetLastError();
  1855. goto cleanup;
  1856. }
  1857. //
  1858. // validate the input parameters
  1859. //
  1860. // check the usage option
  1861. if ( pParams->bUsage == TRUE )
  1862. {
  1863. if ( argc > 3 )
  1864. {
  1865. // no other options are accepted along with -? option
  1866. dwResult = (DWORD) MK_E_SYNTAX;
  1867. SetReason( MSG_ERROR_INVALID_USAGE_REQUEST );
  1868. goto cleanup;
  1869. }
  1870. else
  1871. {
  1872. // no need of furthur checking of the values
  1873. dwResult = ERROR_SUCCESS;
  1874. goto cleanup;
  1875. }
  1876. }
  1877. // -d and -d+ are mutually exclusive --
  1878. // that is, -d and -d+ cannot be specified at a time --
  1879. // but it is ok even if both are not specified
  1880. if ( cmdOptions[ OI_CLONE_FRIENDLY_NAME_APPEND ].pValue != NULL &&
  1881. cmdOptions[ OI_CLONE_FRIENDLY_NAME_REPLACE ].pValue != NULL )
  1882. {
  1883. dwResult = (DWORD) MK_E_SYNTAX;
  1884. SetReason( MSG_ERROR_INVALID_DESCRIPTION_COMBINATION );
  1885. goto cleanup;
  1886. }
  1887. // get the buffer pointers allocated by command line parser
  1888. pParams->dwFriendlyNameType = BOOTENTRY_FRIENDLYNAME_NONE;
  1889. pParams->pwszSourceGuid = cmdOptions[ OI_CLONE_SOURCE_GUID ].pValue;
  1890. pParams->pwszTargetGuid = cmdOptions[ OI_CLONE_TARGET_GUID ].pValue;
  1891. if ( cmdOptions[ OI_CLONE_FRIENDLY_NAME_APPEND ].pValue != NULL )
  1892. {
  1893. pParams->dwFriendlyNameType = BOOTENTRY_FRIENDLYNAME_APPEND;
  1894. pParams->pwszFriendlyName = cmdOptions[ OI_CLONE_FRIENDLY_NAME_APPEND ].pValue;
  1895. }
  1896. else if ( cmdOptions[ OI_CLONE_FRIENDLY_NAME_REPLACE ].pValue != NULL )
  1897. {
  1898. pParams->dwFriendlyNameType = BOOTENTRY_FRIENDLYNAME_REPLACE;
  1899. pParams->pwszFriendlyName = cmdOptions[ OI_CLONE_FRIENDLY_NAME_REPLACE ].pValue;
  1900. }
  1901. // -id and -sg are mutually exclusive options
  1902. // also, -upddrv also should not be specified when -id is specified
  1903. if ( cmdOptions[ OI_CLONE_BOOT_ID ].dwActuals != 0 )
  1904. {
  1905. if ( pParams->pwszSourceGuid != NULL || pParams->bDriverUpdate == TRUE )
  1906. {
  1907. dwResult = (DWORD) MK_E_SYNTAX;
  1908. SetReason( MSG_ERROR_INVALID_BOOT_ID_COMBINATION );
  1909. goto cleanup;
  1910. }
  1911. }
  1912. else
  1913. {
  1914. // default value
  1915. pParams->lBootId = -1;
  1916. }
  1917. // -d or -d+ should not be specified when -upddrv is specified
  1918. if ( pParams->pwszFriendlyName != NULL && pParams->bDriverUpdate == TRUE )
  1919. {
  1920. dwResult = (DWORD) MK_E_SYNTAX;
  1921. SetReason( MSG_ERROR_INVALID_UPDDRV_COMBINATION );
  1922. goto cleanup;
  1923. }
  1924. // -sg should be specified when -upddrv switch is specified
  1925. if ( pParams->bDriverUpdate == TRUE && pParams->pwszSourceGuid == NULL )
  1926. {
  1927. dwResult = (DWORD) MK_E_SYNTAX;
  1928. SetReason( MSG_ERROR_NO_SGUID_WITH_UPDDRV );
  1929. goto cleanup;
  1930. }
  1931. // success
  1932. dwResult = ERROR_SUCCESS;
  1933. cleanup:
  1934. // return
  1935. return dwResult;
  1936. }
  1937. DWORD DisplayCloneHelp()
  1938. {
  1939. // local variables
  1940. DWORD dwIndex = IDS_CLONE_BEGIN_IA64 ;
  1941. // ...
  1942. for(;dwIndex <=IDS_CLONE_END_IA64;dwIndex++)
  1943. {
  1944. ShowMessage( stdout, GetResString(dwIndex) );
  1945. }
  1946. // return
  1947. return ERROR_SUCCESS;
  1948. }