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.

1442 lines
57 KiB

  1. /*++
  2. Copyright (c) Microsoft Corporation. All rights reserved.
  3. Module Name:
  4. fileq6.c
  5. Abstract:
  6. Copy list scanning functions.
  7. Author:
  8. Ted Miller (tedm) 24-Feb-1995
  9. Revision History:
  10. --*/
  11. #include "precomp.h"
  12. #pragma hdrstop
  13. //
  14. // Define mask that isolates the action to be performed on the file queue.
  15. //
  16. #define SPQ_ACTION_MASK (SPQ_SCAN_FILE_PRESENCE | SPQ_SCAN_FILE_VALIDITY | SPQ_SCAN_USE_CALLBACK | SPQ_SCAN_USE_CALLBACKEX | SPQ_SCAN_USE_CALLBACK_SIGNERINFO)
  17. #define SPQ_SCAN_USE_CALLBACKEX_PRESENCE (SPQ_SCAN_FILE_PRESENCE|SPQ_SCAN_USE_CALLBACKEX)
  18. BOOL
  19. _SetupMarkFileNodeTargetFlags(
  20. IN PSP_FILE_QUEUE FileQueue,
  21. IN LONG RootID,
  22. IN LONG DirID,
  23. IN LONG FileID,
  24. IN DWORD MaskFlags,
  25. IN DWORD Flags,
  26. OUT PDWORD PriorFlags
  27. )
  28. {
  29. SP_TARGET_ENT TargetInfo;
  30. LONG TargetID;
  31. DWORD rc;
  32. DWORD OldFlags;
  33. MYASSERT(Flags == (MaskFlags&Flags));
  34. rc = pSetupBackupGetTargetByPath((HSPFILEQ)FileQueue,
  35. NULL, // use Queue's string table
  36. NULL,
  37. RootID,
  38. DirID,
  39. FileID,
  40. &TargetID,
  41. &TargetInfo
  42. );
  43. if (rc != NO_ERROR) {
  44. SetLastError(rc);
  45. return FALSE;
  46. }
  47. OldFlags = TargetInfo.InternalFlags;
  48. TargetInfo.InternalFlags = (TargetInfo.InternalFlags&~MaskFlags)|Flags;
  49. if(OldFlags != TargetInfo.InternalFlags) {
  50. rc = pSetupBackupSetTargetByID((HSPFILEQ)FileQueue,
  51. TargetID,
  52. &TargetInfo
  53. );
  54. }
  55. if(PriorFlags) {
  56. *PriorFlags = OldFlags;
  57. }
  58. if (rc != NO_ERROR) {
  59. SetLastError(rc);
  60. return FALSE;
  61. }
  62. return TRUE;
  63. }
  64. BOOL
  65. _SetupScanFileQueue(
  66. IN HSPFILEQ FileQueue,
  67. IN DWORD Flags,
  68. IN HWND Window, OPTIONAL
  69. IN PVOID CallbackRoutine, OPTIONAL
  70. IN PVOID CallbackContext, OPTIONAL
  71. OUT PDWORD Result,
  72. IN BOOL IsNativeCharWidth
  73. )
  74. /*++
  75. Routine Description:
  76. Implementation for SetupScanFileQueue, handles ANSI and Unicode
  77. callback functions.
  78. Arguments:
  79. Same as SetupScanFileQueue().
  80. IsNativeCharWidth - supplies flag indicating whether callback routine is
  81. expecting unicode params. Meaningful only in UNICODE version of DLL.
  82. Return Value:
  83. Same as SetupScanFileQueue().
  84. --*/
  85. {
  86. DWORD Action;
  87. PSP_FILE_QUEUE Queue;
  88. PSP_FILE_QUEUE_NODE QueueNode, TempNode, NextNode;
  89. PSP_FILE_QUEUE_NODE CheckNode;
  90. PSOURCE_MEDIA_INFO SourceMedia;
  91. BOOL Continue;
  92. TCHAR TargetPath[MAX_PATH];
  93. BOOL Err;
  94. int i;
  95. PTSTR Message;
  96. DWORD flags;
  97. DWORD Win32Error;
  98. SetupapiVerifyProblem Problem;
  99. TCHAR TempCharBuffer[MAX_PATH];
  100. TCHAR SourcePath[MAX_PATH];
  101. TCHAR DigitalSigner[MAX_PATH];
  102. TCHAR SignerVersion[MAX_PATH];
  103. TCHAR CatalogFile[MAX_PATH];
  104. DWORD rc;
  105. UINT Notification;
  106. UINT_PTR CallbackParam1;
  107. FILEPATHS FilePaths;
  108. FILEPATHS_SIGNERINFO FilePathsSignerInfo;
  109. BOOL DoPruning, PruneNode;
  110. PSPQ_CATALOG_INFO CatalogNode;
  111. PSETUP_LOG_CONTEXT lc = NULL;
  112. DWORD slot_fileop = 0;
  113. HANDLE hWVTStateData;
  114. PCRYPT_PROVIDER_DATA ProviderData;
  115. PCRYPT_PROVIDER_SGNR ProviderSigner;
  116. PCRYPT_PROVIDER_CERT ProviderCert;
  117. Queue = (PSP_FILE_QUEUE)FileQueue;
  118. rc = NO_ERROR;
  119. try {
  120. if (Queue->Signature != SP_FILE_QUEUE_SIG) {
  121. rc = ERROR_INVALID_HANDLE;
  122. }
  123. } except(EXCEPTION_EXECUTE_HANDLER) {
  124. rc = ERROR_INVALID_HANDLE;
  125. }
  126. if(rc != NO_ERROR) {
  127. SetLastError(rc);
  128. return(FALSE);
  129. }
  130. lc = Queue->LogContext;
  131. //
  132. // Validate arguments. Exactly one action flag must be specified.
  133. //
  134. if(Result) {
  135. *Result = 0;
  136. } else {
  137. SetLastError(ERROR_INVALID_PARAMETER);
  138. return(FALSE);
  139. }
  140. Action = (Flags & SPQ_ACTION_MASK);
  141. switch(Action) {
  142. case SPQ_SCAN_FILE_PRESENCE:
  143. case SPQ_SCAN_FILE_VALIDITY:
  144. break;
  145. case SPQ_SCAN_USE_CALLBACK:
  146. case SPQ_SCAN_USE_CALLBACKEX:
  147. case SPQ_SCAN_USE_CALLBACKEX_PRESENCE:
  148. case SPQ_SCAN_USE_CALLBACK_SIGNERINFO:
  149. if(CallbackRoutine) {
  150. break;
  151. }
  152. // else fall through to invalid arg case
  153. default:
  154. SetLastError(ERROR_INVALID_PARAMETER);
  155. return(FALSE);
  156. }
  157. DoPruning = Flags & SPQ_SCAN_PRUNE_COPY_QUEUE;
  158. if(DoPruning) {
  159. if(Queue->Flags & FQF_QUEUE_ALREADY_COMMITTED) {
  160. //
  161. // If we've been asked to prune the copy queue, then make sure the queue
  162. // hasn't been committed yet.
  163. //
  164. SetLastError(ERROR_NO_MORE_ITEMS);
  165. return FALSE;
  166. }
  167. if((Action == SPQ_SCAN_USE_CALLBACK)
  168. || (Action == SPQ_SCAN_USE_CALLBACKEX)
  169. || (Action == SPQ_SCAN_USE_CALLBACKEX_PRESENCE)
  170. || (Action == SPQ_SCAN_USE_CALLBACK_SIGNERINFO)
  171. || (Flags & SPQ_SCAN_INFORM_USER)) {
  172. //
  173. // Presently, pruning the queue is not supported when using a callback.
  174. // Also, SPQ_SCAN_INFORM_USER and SPQ_SCAN_PRUNE_COPY_QUEUE don't play well
  175. // together...
  176. //
  177. SetLastError(ERROR_INVALID_FLAGS);
  178. return FALSE;
  179. }
  180. }
  181. //
  182. // If the caller asked for UI, make sure we're running interactively.
  183. //
  184. if((Flags & SPQ_SCAN_INFORM_USER) && (GlobalSetupFlags & (PSPGF_NONINTERACTIVE|PSPGF_UNATTENDED_SETUP))) {
  185. SetLastError(ERROR_REQUIRES_INTERACTIVE_WINDOWSTATION);
  186. return FALSE;
  187. }
  188. //
  189. // If we're verifying the digital signatures of the files, then first make
  190. // sure that we've processed the catalog nodes for this queue. However, we
  191. // don't want any copying to take place if there are OEM INFs in the list.
  192. //
  193. if((Action == SPQ_SCAN_FILE_VALIDITY) ||
  194. (Action == SPQ_SCAN_USE_CALLBACKEX) ||
  195. (Action == SPQ_SCAN_USE_CALLBACK_SIGNERINFO)) {
  196. WriteLogEntry(
  197. lc,
  198. SETUP_LOG_TIME,
  199. MSG_LOG_BEGIN_VERIFY4_CAT_TIME,
  200. NULL); // text message
  201. rc = _SetupVerifyQueuedCatalogs(Window,
  202. Queue,
  203. VERCAT_NO_PROMPT_ON_ERROR,
  204. NULL,
  205. NULL
  206. );
  207. WriteLogEntry(
  208. lc,
  209. SETUP_LOG_TIME,
  210. MSG_LOG_END_VERIFY4_CAT_TIME,
  211. NULL); // text message
  212. if((Action == SPQ_SCAN_FILE_VALIDITY) && (rc != NO_ERROR)) {
  213. WriteLogEntry(
  214. lc,
  215. (rc == ERROR_CANNOT_COPY ? SETUP_LOG_VVERBOSE : SETUP_LOG_WARNING) | SETUP_LOG_BUFFER,
  216. MSG_LOG_SCANQUEUE_VERIFY_FAILED,
  217. NULL);
  218. WriteLogError(
  219. lc,
  220. (rc == ERROR_CANNOT_COPY ? SETUP_LOG_VVERBOSE : SETUP_LOG_WARNING),
  221. rc);
  222. //
  223. // Result output param has already been initialized to zero
  224. // above.
  225. //
  226. return TRUE;
  227. }
  228. } else {
  229. rc = NO_ERROR;
  230. }
  231. //
  232. // Regardless of whether or not the catalog validation succeeded
  233. // above, we still want to call the callback for each file. The
  234. // failed catalog verifications will be reflected in the failed
  235. // file verifications that the caller gets informed of via the
  236. // Win32Error field of the FILEPATHS struct we give the callback.
  237. //
  238. // Initialize the static fields of that structure here so we don't
  239. // have to each pass through the loop below.
  240. //
  241. FilePaths.Target = TargetPath;
  242. FilePaths.Source = SourcePath;
  243. FilePathsSignerInfo.Target = TargetPath;
  244. FilePathsSignerInfo.Source = SourcePath;
  245. //
  246. // markup delete/rename usage
  247. // we don't need to do this if we have SPQ_SCAN_PRUNE_DELREN set
  248. //
  249. if(!(Flags & SPQ_SCAN_PRUNE_DELREN)) {
  250. for(TempNode=Queue->DeleteQueue; TempNode; TempNode=TempNode->Next) {
  251. if(!_SetupMarkFileNodeTargetFlags(Queue,
  252. TempNode->TargetDirectory,
  253. -1,
  254. TempNode->TargetFilename,
  255. SP_TEFLG_PRUNE_DEL,SP_TEFLG_PRUNE_DEL,
  256. NULL)) {
  257. //
  258. // this would indicate an out-of-memory condition
  259. // last error is set
  260. //
  261. return FALSE;
  262. }
  263. }
  264. for(TempNode=Queue->RenameQueue; TempNode; TempNode=TempNode->Next) {
  265. if(!_SetupMarkFileNodeTargetFlags(Queue,
  266. TempNode->SourcePath,
  267. -1,
  268. TempNode->SourceFilename,
  269. SP_TEFLG_PRUNE_RENSRC,SP_TEFLG_PRUNE_RENSRC,
  270. NULL)) {
  271. //
  272. // this would indicate an out-of-memory condition
  273. // last error is set
  274. //
  275. return FALSE;
  276. }
  277. if(!_SetupMarkFileNodeTargetFlags(Queue,
  278. TempNode->TargetDirectory == -1 ? TempNode->SourcePath : TempNode->TargetDirectory,
  279. -1,
  280. TempNode->TargetFilename,
  281. SP_TEFLG_PRUNE_RENTARG,SP_TEFLG_PRUNE_RENTARG,
  282. NULL)) {
  283. //
  284. // this would indicate an out-of-memory condition
  285. // last error is set
  286. //
  287. return FALSE;
  288. }
  289. }
  290. }
  291. //
  292. // Process all nodes in the copy queue.
  293. //
  294. Err = FALSE;
  295. Continue = TRUE;
  296. for(SourceMedia=Queue->SourceMediaList; Continue && SourceMedia; SourceMedia=SourceMedia->Next) {
  297. TempNode = NULL;
  298. QueueNode = SourceMedia->CopyQueue;
  299. while(Continue && QueueNode) {
  300. DWORD PrevNodeFlags;
  301. //
  302. // markup copy usage
  303. //
  304. if(!_SetupMarkFileNodeTargetFlags(Queue,
  305. QueueNode->TargetDirectory,
  306. -1,
  307. QueueNode->TargetFilename,
  308. SP_TEFLG_PRUNE_COPY,SP_TEFLG_PRUNE_COPY,
  309. &PrevNodeFlags)) {
  310. //
  311. // this would indicate an out-of-memory condition
  312. // last error is set
  313. //
  314. rc = GetLastError();
  315. Err = TRUE;
  316. Continue = FALSE;
  317. break;
  318. }
  319. //
  320. // Form target path.
  321. //
  322. lstrcpyn(
  323. TargetPath,
  324. pSetupStringTableStringFromId(Queue->StringTable,QueueNode->TargetDirectory),
  325. MAX_PATH
  326. );
  327. pSetupConcatenatePaths(
  328. TargetPath,
  329. pSetupStringTableStringFromId(Queue->StringTable,QueueNode->TargetFilename),
  330. MAX_PATH,
  331. NULL
  332. );
  333. if((PrevNodeFlags & (SP_TEFLG_PRUNE_DEL|SP_TEFLG_PRUNE_RENSRC|SP_TEFLG_PRUNE_RENTARG))
  334. && !((Flags & SPQ_SCAN_PRUNE_DELREN) || (QueueNode->StyleFlags & SP_COPY_NOPRUNE))) {
  335. DWORD msg;
  336. //
  337. // this file is touched in source/target
  338. // but the INF author forgot to mark it as SP_COPY_NOPRUNE
  339. // this typically indicates a mistake on the author's part
  340. // so we try and handle it best as we can
  341. // if SPQ_SCAN_PRUNE_DELREN is set, we'll kill the delete/rename entries
  342. // if it's not set, we enforce the SP_COPY_NOPRUNE
  343. //
  344. QueueNode->StyleFlags |= SP_COPY_NOPRUNE;
  345. if(PrevNodeFlags & SP_TEFLG_PRUNE_DEL) {
  346. msg = MSG_LOG_CHANGEPRUNE_DEL;
  347. } else if(PrevNodeFlags & SP_TEFLG_PRUNE_RENSRC) {
  348. msg = MSG_LOG_CHANGEPRUNE_RENSRC;
  349. } else {
  350. msg = MSG_LOG_CHANGEPRUNE_RENTARG;
  351. }
  352. WriteLogEntry(
  353. lc,
  354. SETUP_LOG_WARNING,
  355. msg,
  356. NULL,
  357. TargetPath);
  358. }
  359. //
  360. // Perform check on file.
  361. //
  362. PruneNode = FALSE;
  363. switch(Action) {
  364. case SPQ_SCAN_FILE_PRESENCE:
  365. Continue = FileExists(TargetPath,NULL);
  366. if(DoPruning) {
  367. //
  368. // File's presence should result in this copy node's removal
  369. // from the queue--it's absence should be ignored.
  370. //
  371. if(Continue) {
  372. PruneNode = TRUE;
  373. } else {
  374. //
  375. // Leave copy node alone.
  376. //
  377. PruneNode = FALSE;
  378. Continue = TRUE;
  379. }
  380. } else {
  381. if (Continue) {
  382. //
  383. // we should not continue if the copy node is marked as a "no prune" node
  384. //
  385. if (QueueNode->StyleFlags & SP_COPY_NOPRUNE) {
  386. Continue = FALSE;
  387. }
  388. }
  389. }
  390. break;
  391. case SPQ_SCAN_FILE_VALIDITY:
  392. //
  393. // If we are going to prune the copy queue then:
  394. //
  395. // (a) only validate the file against the system catalogs (not
  396. // against any OEM catalogs), and
  397. // (b) don't validate self-signed files.
  398. //
  399. // (Note: we will never consider an INF in %windir%\Inf to be
  400. // signed, since it is invalid to copy an INF there via a file
  401. // queue. SetupCopyOEMInf must be used instead.)
  402. //
  403. if(GlobalSetupFlags & PSPGF_MINIMAL_EMBEDDED) {
  404. //
  405. // If we're pruning, then we don't want to consider any
  406. // existing files as valid, otherwise we'd never copy
  407. // anything!
  408. //
  409. Continue = !DoPruning;
  410. //
  411. // We want to prune the queue node if the target exists and
  412. // the source doesn't
  413. //
  414. if(DoPruning && FileExists(TargetPath, NULL)) {
  415. //
  416. // The target exists! Now build the path the source
  417. // file...
  418. //
  419. lstrcpyn(SourcePath,
  420. pSetupStringTableStringFromId(Queue->StringTable,
  421. QueueNode->SourceRootPath),
  422. SIZECHARS(SourcePath)
  423. );
  424. if(QueueNode->SourcePath != -1) {
  425. pSetupConcatenatePaths(SourcePath,
  426. pSetupStringTableStringFromId(
  427. Queue->StringTable,
  428. QueueNode->SourcePath),
  429. SIZECHARS(SourcePath),
  430. NULL
  431. );
  432. }
  433. pSetupConcatenatePaths(SourcePath,
  434. pSetupStringTableStringFromId(
  435. Queue->StringTable,
  436. QueueNode->SourceFilename),
  437. SIZECHARS(SourcePath),
  438. NULL
  439. );
  440. //
  441. // If there's no source file to copy, prune this node
  442. //
  443. Continue = !FileExists(SourcePath, NULL);
  444. }
  445. } else {
  446. if(QueueNode->CatalogInfo &&
  447. ((QueueNode->CatalogInfo->Flags & CATINFO_FLAG_AUTHENTICODE_SIGNED) ||
  448. (QueueNode->CatalogInfo->Flags & CATINFO_FLAG_PROMPT_FOR_TRUST))) {
  449. //
  450. // Validate using Authenticode policy. At this point,
  451. // we've already established that the user trusts the
  452. // publisher.
  453. //
  454. Win32Error = VerifySourceFile(lc,
  455. Queue,
  456. QueueNode,
  457. pSetupGetFileTitle(TargetPath),
  458. TargetPath,
  459. NULL,
  460. ((Queue->Flags & FQF_USE_ALT_PLATFORM)
  461. ? &(Queue->AltPlatformInfo)
  462. : Queue->ValidationPlatform),
  463. (VERIFY_FILE_IGNORE_SELFSIGNED
  464. | VERIFY_FILE_USE_AUTHENTICODE_CATALOG),
  465. &Problem,
  466. TempCharBuffer,
  467. NULL,
  468. NULL,
  469. NULL,
  470. NULL
  471. );
  472. if((Win32Error == ERROR_AUTHENTICODE_TRUSTED_PUBLISHER) ||
  473. (Win32Error == ERROR_AUTHENTICODE_TRUST_NOT_ESTABLISHED)) {
  474. Continue = TRUE;
  475. } else {
  476. Continue = FALSE;
  477. }
  478. } else {
  479. //
  480. // Validate using normal driver signing policy.
  481. //
  482. Continue = (NO_ERROR == VerifySourceFile(lc,
  483. Queue,
  484. QueueNode,
  485. pSetupGetFileTitle(TargetPath),
  486. TargetPath,
  487. NULL,
  488. ((Queue->Flags & FQF_USE_ALT_PLATFORM)
  489. ? &(Queue->AltPlatformInfo)
  490. : Queue->ValidationPlatform),
  491. (DoPruning ? VERIFY_FILE_IGNORE_SELFSIGNED
  492. : 0),
  493. &Problem,
  494. TempCharBuffer,
  495. NULL,
  496. NULL,
  497. NULL,
  498. NULL
  499. ));
  500. }
  501. }
  502. if(DoPruning) {
  503. //
  504. // File's validity should result in this copy node's removal
  505. // from the queue--it's invalidity should be ignored.
  506. //
  507. if(Continue) {
  508. PruneNode = TRUE;
  509. } else {
  510. //
  511. // Leave copy node alone.
  512. //
  513. PruneNode = FALSE;
  514. Continue = TRUE;
  515. }
  516. } else {
  517. if (Continue) {
  518. //
  519. // we should not continue if the copy node is marked as a "no prune" node
  520. //
  521. if (QueueNode->StyleFlags & SP_COPY_NOPRUNE) {
  522. Continue = FALSE;
  523. }
  524. }
  525. }
  526. break;
  527. case SPQ_SCAN_USE_CALLBACK:
  528. case SPQ_SCAN_USE_CALLBACKEX:
  529. case SPQ_SCAN_USE_CALLBACKEX_PRESENCE:
  530. case SPQ_SCAN_USE_CALLBACK_SIGNERINFO:
  531. flags = (QueueNode->InternalFlags & (INUSE_INF_WANTS_REBOOT | INUSE_IN_USE))
  532. ? SPQ_DELAYED_COPY
  533. : 0;
  534. if((Action == SPQ_SCAN_USE_CALLBACKEX) ||
  535. (Action == SPQ_SCAN_USE_CALLBACKEX_PRESENCE) ||
  536. (Action == SPQ_SCAN_USE_CALLBACK_SIGNERINFO)) {
  537. //
  538. // The caller requested the extended version of the queue
  539. // scan callback--we need to build the source file path.
  540. //
  541. lstrcpyn(SourcePath,
  542. pSetupStringTableStringFromId(Queue->StringTable, QueueNode->SourceRootPath),
  543. SIZECHARS(SourcePath)
  544. );
  545. if(QueueNode->SourcePath != -1) {
  546. pSetupConcatenatePaths(SourcePath,
  547. pSetupStringTableStringFromId(Queue->StringTable, QueueNode->SourcePath),
  548. SIZECHARS(SourcePath),
  549. NULL
  550. );
  551. }
  552. pSetupConcatenatePaths(SourcePath,
  553. pSetupStringTableStringFromId(Queue->StringTable, QueueNode->SourceFilename),
  554. SIZECHARS(SourcePath),
  555. NULL
  556. );
  557. if((Action == SPQ_SCAN_USE_CALLBACKEX_PRESENCE)) {
  558. Win32Error = NO_ERROR;
  559. } else {
  560. CatalogFile[0] = TEXT('\0');
  561. DigitalSigner[0] = TEXT('\0');
  562. SignerVersion[0] = TEXT('\0');
  563. if(GlobalSetupFlags & PSPGF_MINIMAL_EMBEDDED) {
  564. //
  565. // We can't call our internal VerifySourceFile
  566. // routine, because it doesn't expect to be asked
  567. // for signer info when in "minimal embedded" mode
  568. // (plus, it doesn't make sense to ask for such
  569. // info anyway, since we have no idea who signed
  570. // the file, or even if it was signed).
  571. //
  572. Win32Error = NO_ERROR;
  573. } else {
  574. if(QueueNode->CatalogInfo &&
  575. ((QueueNode->CatalogInfo->Flags & CATINFO_FLAG_AUTHENTICODE_SIGNED) ||
  576. (QueueNode->CatalogInfo->Flags & CATINFO_FLAG_PROMPT_FOR_TRUST))) {
  577. Win32Error = VerifySourceFile(
  578. lc,
  579. Queue,
  580. QueueNode,
  581. pSetupGetFileTitle(TargetPath),
  582. TargetPath,
  583. NULL,
  584. ((Queue->Flags & FQF_USE_ALT_PLATFORM)
  585. ? &(Queue->AltPlatformInfo)
  586. : Queue->ValidationPlatform),
  587. VERIFY_FILE_USE_AUTHENTICODE_CATALOG,
  588. &Problem,
  589. TempCharBuffer,
  590. ((Action == SPQ_SCAN_USE_CALLBACK_SIGNERINFO)
  591. ? CatalogFile
  592. : NULL),
  593. NULL,
  594. NULL,
  595. &hWVTStateData
  596. );
  597. if((Win32Error == ERROR_AUTHENTICODE_TRUSTED_PUBLISHER) ||
  598. (Win32Error == ERROR_AUTHENTICODE_TRUST_NOT_ESTABLISHED)) {
  599. ProviderData = WTHelperProvDataFromStateData(hWVTStateData);
  600. MYASSERT(ProviderData);
  601. if (ProviderData) {
  602. ProviderSigner = WTHelperGetProvSignerFromChain(ProviderData,
  603. 0,
  604. FALSE,
  605. 0);
  606. MYASSERT(ProviderSigner);
  607. if (ProviderSigner) {
  608. ProviderCert = WTHelperGetProvCertFromChain(ProviderSigner,
  609. 0);
  610. MYASSERT(ProviderCert);
  611. if (ProviderCert) {
  612. //
  613. // Get the publisher and add this
  614. // as the DigitalSigner.
  615. //
  616. CertGetNameString(ProviderCert->pCert,
  617. CERT_NAME_SIMPLE_DISPLAY_TYPE,
  618. 0,
  619. NULL,
  620. DigitalSigner,
  621. SIZECHARS(DigitalSigner));
  622. }
  623. }
  624. }
  625. MYASSERT(hWVTStateData);
  626. pSetupCloseWVTStateData(hWVTStateData);
  627. hWVTStateData = NULL;
  628. }
  629. } else {
  630. //
  631. // Validate using normal driver signing policy.
  632. //
  633. Win32Error = VerifySourceFile(
  634. lc,
  635. Queue,
  636. QueueNode,
  637. pSetupGetFileTitle(TargetPath),
  638. TargetPath,
  639. NULL,
  640. ((Queue->Flags & FQF_USE_ALT_PLATFORM)
  641. ? &(Queue->AltPlatformInfo)
  642. : Queue->ValidationPlatform),
  643. 0,
  644. &Problem,
  645. TempCharBuffer,
  646. ((Action == SPQ_SCAN_USE_CALLBACK_SIGNERINFO)
  647. ? CatalogFile
  648. : NULL),
  649. ((Action == SPQ_SCAN_USE_CALLBACK_SIGNERINFO)
  650. ? DigitalSigner
  651. : NULL),
  652. ((Action == SPQ_SCAN_USE_CALLBACK_SIGNERINFO)
  653. ? SignerVersion
  654. : NULL),
  655. NULL
  656. );
  657. }
  658. }
  659. }
  660. if ((Action == SPQ_SCAN_USE_CALLBACKEX) ||
  661. (Action == SPQ_SCAN_USE_CALLBACKEX_PRESENCE)) {
  662. FilePaths.Win32Error = Win32Error;
  663. FilePaths.Flags = QueueNode->StyleFlags;
  664. CallbackParam1 = (UINT_PTR)(&FilePaths);
  665. Notification = SPFILENOTIFY_QUEUESCAN_EX;
  666. } else {
  667. FilePathsSignerInfo.Win32Error = Win32Error;
  668. FilePathsSignerInfo.Flags = QueueNode->StyleFlags;
  669. FilePathsSignerInfo.DigitalSigner = (DigitalSigner[0] != TEXT('\0'))
  670. ? DigitalSigner
  671. : NULL;
  672. FilePathsSignerInfo.Version = (SignerVersion[0] != TEXT('\0'))
  673. ? SignerVersion
  674. : NULL;
  675. FilePathsSignerInfo.CatalogFile = (CatalogFile[0] != TEXT('\0'))
  676. ? CatalogFile
  677. : NULL;
  678. CallbackParam1 = (UINT_PTR)(&FilePathsSignerInfo);
  679. Notification = SPFILENOTIFY_QUEUESCAN_SIGNERINFO;
  680. }
  681. } else {
  682. CallbackParam1 = (UINT_PTR)TargetPath;
  683. Notification = SPFILENOTIFY_QUEUESCAN;
  684. }
  685. rc = (DWORD)pSetupCallMsgHandler(
  686. lc,
  687. CallbackRoutine,
  688. IsNativeCharWidth,
  689. CallbackContext,
  690. Notification,
  691. CallbackParam1,
  692. flags
  693. );
  694. *Result = rc;
  695. Err = (rc != NO_ERROR);
  696. Continue = !Err;
  697. break;
  698. }
  699. if(DoPruning && PruneNode) {
  700. BOOL ReallyPrune = TRUE;
  701. MYASSERT(Continue == TRUE);
  702. //
  703. // before we remove the item from the queue, we must check if the copy item
  704. // also exists in the rename or delete queues. if it does, then we cannot
  705. // prune the item from the copy queue
  706. //
  707. if (QueueNode->StyleFlags & SP_COPY_NOPRUNE) {
  708. ReallyPrune = FALSE;
  709. TempNode = QueueNode;
  710. QueueNode = QueueNode->Next;
  711. }
  712. if (ReallyPrune) {
  713. WriteLogEntry(
  714. lc,
  715. SETUP_LOG_VERBOSE,
  716. MSG_LOG_PRUNE,
  717. NULL,
  718. TargetPath);
  719. NextNode = QueueNode->Next;
  720. if(TempNode) {
  721. TempNode->Next = NextNode;
  722. } else {
  723. SourceMedia->CopyQueue = NextNode;
  724. }
  725. MyFree(QueueNode);
  726. QueueNode = NextNode;
  727. //
  728. // Adjust the queue node counts.
  729. //
  730. Queue->CopyNodeCount--;
  731. SourceMedia->CopyNodeCount--;
  732. }
  733. } else {
  734. TempNode = QueueNode;
  735. QueueNode = QueueNode->Next;
  736. }
  737. }
  738. }
  739. if(Flags & SPQ_SCAN_PRUNE_DELREN) {
  740. //
  741. // flag tells us to rip out of Delete/Rename queues
  742. // files that are (or was) in the copy queue.
  743. // we'll only be asked to do this in limited cases
  744. // (eg, GUI setup)
  745. //
  746. TempNode = NULL;
  747. QueueNode = Queue->DeleteQueue;
  748. while(QueueNode) {
  749. DWORD PrevFlags;
  750. NextNode = QueueNode->Next;
  751. if(_SetupMarkFileNodeTargetFlags(Queue,
  752. QueueNode->TargetDirectory,
  753. -1,
  754. QueueNode->TargetFilename,
  755. 0,0,
  756. &PrevFlags)) {
  757. if(PrevFlags & SP_TEFLG_PRUNE_COPY) {
  758. //
  759. // warn about this
  760. //
  761. lstrcpyn(
  762. TargetPath,
  763. pSetupStringTableStringFromId(Queue->StringTable,QueueNode->TargetDirectory),
  764. MAX_PATH
  765. );
  766. pSetupConcatenatePaths(
  767. TargetPath,
  768. pSetupStringTableStringFromId(Queue->StringTable,QueueNode->TargetFilename),
  769. MAX_PATH,
  770. NULL
  771. );
  772. WriteLogEntry(
  773. lc,
  774. SETUP_LOG_WARNING,
  775. MSG_LOG_PRUNE_DEL,
  776. NULL,
  777. TargetPath);
  778. if(TempNode) {
  779. TempNode->Next = NextNode;
  780. } else {
  781. Queue->DeleteQueue = NextNode;
  782. }
  783. MyFree(QueueNode);
  784. Queue->DeleteNodeCount--;
  785. QueueNode = NextNode;
  786. continue;
  787. }
  788. }
  789. TempNode = QueueNode;
  790. QueueNode = NextNode;
  791. }
  792. TempNode = NULL;
  793. QueueNode = Queue->RenameQueue;
  794. while(QueueNode) {
  795. DWORD PrevFlags;
  796. NextNode = QueueNode->Next;
  797. if(_SetupMarkFileNodeTargetFlags(Queue,
  798. QueueNode->SourcePath,
  799. -1,
  800. QueueNode->SourceFilename,
  801. 0,0,
  802. &PrevFlags)) {
  803. if(PrevFlags & SP_TEFLG_PRUNE_COPY) {
  804. //
  805. // warn about this
  806. //
  807. lstrcpyn(
  808. TargetPath,
  809. pSetupStringTableStringFromId(Queue->StringTable,QueueNode->SourcePath),
  810. MAX_PATH
  811. );
  812. pSetupConcatenatePaths(
  813. TargetPath,
  814. pSetupStringTableStringFromId(Queue->StringTable,QueueNode->SourceFilename),
  815. MAX_PATH,
  816. NULL
  817. );
  818. WriteLogEntry(
  819. lc,
  820. SETUP_LOG_WARNING,
  821. MSG_LOG_PRUNE_RENSRC,
  822. NULL,
  823. TargetPath);
  824. if(TempNode) {
  825. TempNode->Next = NextNode;
  826. } else {
  827. Queue->RenameQueue = NextNode;
  828. }
  829. MyFree(QueueNode);
  830. Queue->RenameNodeCount--;
  831. QueueNode = NextNode;
  832. continue;
  833. }
  834. }
  835. if(_SetupMarkFileNodeTargetFlags(Queue,
  836. QueueNode->TargetDirectory == -1 ? QueueNode->SourcePath : QueueNode->TargetDirectory,
  837. -1,
  838. QueueNode->TargetFilename,
  839. 0,0,
  840. &PrevFlags)) {
  841. if(PrevFlags & SP_TEFLG_PRUNE_COPY) {
  842. //
  843. // warn about this
  844. //
  845. lstrcpyn(
  846. TargetPath,
  847. pSetupStringTableStringFromId(Queue->StringTable,QueueNode->TargetDirectory == -1 ? QueueNode->SourcePath : QueueNode->TargetDirectory),
  848. MAX_PATH
  849. );
  850. pSetupConcatenatePaths(
  851. TargetPath,
  852. pSetupStringTableStringFromId(Queue->StringTable,QueueNode->TargetFilename),
  853. MAX_PATH,
  854. NULL
  855. );
  856. WriteLogEntry(
  857. lc,
  858. SETUP_LOG_WARNING,
  859. MSG_LOG_PRUNE_RENTARG,
  860. NULL,
  861. TargetPath);
  862. if(TempNode) {
  863. TempNode->Next = NextNode;
  864. } else {
  865. Queue->RenameQueue = NextNode;
  866. }
  867. MyFree(QueueNode);
  868. Queue->RenameNodeCount--;
  869. QueueNode = NextNode;
  870. continue;
  871. }
  872. }
  873. TempNode = QueueNode;
  874. QueueNode = NextNode;
  875. }
  876. }
  877. //
  878. // If the case of SPQ_SCAN_USE_CALLBACK(EX), *Result is already set up
  879. // when we get here. If Continue is TRUE then we visited all nodes
  880. // and the presence/validity check passed on all of them. Note that
  881. // if Continue is TRUE then Err must be FALSE.
  882. //
  883. if((Action == SPQ_SCAN_FILE_PRESENCE) || (Action == SPQ_SCAN_FILE_VALIDITY)) {
  884. if(DoPruning) {
  885. //
  886. // Set result based on whether any of the queues have nodes in them.
  887. //
  888. if(Queue->CopyNodeCount) {
  889. *Result = 0;
  890. } else {
  891. *Result = (Queue->DeleteNodeCount || Queue->RenameNodeCount || Queue->BackupNodeCount) ? 2 : 1;
  892. }
  893. } else {
  894. //
  895. // If we weren't doing pruning, then we know that the Continue
  896. // variable indicates whether or not we bailed partway through.
  897. //
  898. if(Continue) {
  899. //
  900. // Need to set up Result.
  901. //
  902. if((Flags & SPQ_SCAN_INFORM_USER) && Queue->CopyNodeCount
  903. && (Message = RetreiveAndFormatMessage(MSG_NO_NEED_TO_COPY))) {
  904. //
  905. // Overload TargetPath for use as the caption string.
  906. //
  907. GetWindowText(Window,TargetPath,sizeof(TargetPath)/sizeof(TargetPath[0]));
  908. i = MessageBox(
  909. Window,
  910. Message,
  911. TargetPath,
  912. MB_APPLMODAL | MB_YESNO | MB_ICONINFORMATION
  913. );
  914. MyFree(Message);
  915. if(i == IDYES) {
  916. //
  917. // User wants to skip copying.
  918. //
  919. *Result = (Queue->DeleteNodeCount || Queue->RenameNodeCount || Queue->BackupNodeCount) ? 2 : 1;
  920. } else {
  921. //
  922. // User wants to perform copy.
  923. //
  924. *Result = 0;
  925. }
  926. } else {
  927. //
  928. // Don't want to ask user. Set up Result based on whether
  929. // there are items in the delete, rename or backup queues.
  930. //
  931. *Result = (Queue->DeleteNodeCount || Queue->RenameNodeCount || Queue->BackupNodeCount) ? 2 : 1;
  932. }
  933. } else {
  934. //
  935. // Presence/validity check failed.
  936. //
  937. *Result = 0;
  938. }
  939. //
  940. // Empty the copy queue if necessary.
  941. //
  942. if(*Result) {
  943. for(SourceMedia=Queue->SourceMediaList; Continue && SourceMedia; SourceMedia=SourceMedia->Next) {
  944. for(QueueNode=SourceMedia->CopyQueue; QueueNode; QueueNode=TempNode) {
  945. TempNode = QueueNode->Next;
  946. MyFree(QueueNode);
  947. }
  948. Queue->CopyNodeCount -= SourceMedia->CopyNodeCount;
  949. SourceMedia->CopyQueue = NULL;
  950. SourceMedia->CopyNodeCount = 0;
  951. }
  952. //
  953. // We think we just removed all files in all copy queues.
  954. // The 2 counts we maintain should be in sync -- meaning that
  955. // the total copy node count should now be 0.
  956. //
  957. MYASSERT(Queue->CopyNodeCount == 0);
  958. }
  959. }
  960. }
  961. SetLastError(rc);
  962. return(!Err);
  963. }
  964. #ifdef UNICODE
  965. //
  966. // ANSI version for UNICODE
  967. //
  968. BOOL
  969. SetupScanFileQueueA(
  970. IN HSPFILEQ FileQueue,
  971. IN DWORD Flags,
  972. IN HWND Window, OPTIONAL
  973. IN PSP_FILE_CALLBACK_A CallbackRoutine, OPTIONAL
  974. IN PVOID CallbackContext, OPTIONAL
  975. OUT PDWORD Result
  976. )
  977. {
  978. BOOL b;
  979. try {
  980. b = _SetupScanFileQueue(
  981. FileQueue,
  982. Flags,
  983. Window,
  984. CallbackRoutine,
  985. CallbackContext,
  986. Result,
  987. FALSE
  988. );
  989. } except(EXCEPTION_EXECUTE_HANDLER) {
  990. b = FALSE;
  991. SetLastError(ERROR_INVALID_DATA);
  992. }
  993. return(b);
  994. }
  995. #else
  996. //
  997. // UNICODE version for Win9x
  998. //
  999. BOOL
  1000. SetupScanFileQueueW(
  1001. IN HSPFILEQ FileQueue,
  1002. IN DWORD Flags,
  1003. IN HWND Window, OPTIONAL
  1004. IN PSP_FILE_CALLBACK_W CallbackRoutine, OPTIONAL
  1005. IN PVOID CallbackContext, OPTIONAL
  1006. OUT PDWORD Result
  1007. )
  1008. {
  1009. UNREFERENCED_PARAMETER(FileQueue);
  1010. UNREFERENCED_PARAMETER(Flags);
  1011. UNREFERENCED_PARAMETER(Window);
  1012. UNREFERENCED_PARAMETER(CallbackRoutine);
  1013. UNREFERENCED_PARAMETER(CallbackContext);
  1014. UNREFERENCED_PARAMETER(Result);
  1015. SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
  1016. return(FALSE);
  1017. }
  1018. #endif
  1019. BOOL
  1020. SetupScanFileQueue(
  1021. IN HSPFILEQ FileQueue,
  1022. IN DWORD Flags,
  1023. IN HWND Window, OPTIONAL
  1024. IN PSP_FILE_CALLBACK CallbackRoutine, OPTIONAL
  1025. IN PVOID CallbackContext, OPTIONAL
  1026. OUT PDWORD Result
  1027. )
  1028. /*++
  1029. Routine Description:
  1030. This routine scans a setup file queue, performing an operation on each
  1031. node in its copy list. The operation is specified by a set of flags.
  1032. A caller can use this API to determine whether all files that have been
  1033. enqueued for copy already exist on the target, and if so, to inform the
  1034. user, who may elect to skip the file copying. This can spare the user from
  1035. having to furnish Setup media in many cases.
  1036. Arguments:
  1037. FileQueue - supplies handle to Setup file queue whose copy list is to
  1038. be scanned/iterated.
  1039. Flags - supplies a set of values that control operation of the API. A
  1040. combination of the following values:
  1041. SPQ_SCAN_FILE_PRESENCE - determine whether all target files in the
  1042. copy queue are already present on the target.
  1043. SPQ_SCAN_FILE_VALIDITY - determine whether all target files in the
  1044. copy queue are already present on the target, and verify their
  1045. digital signatures.
  1046. SPQ_SCAN_USE_CALLBACK - for each node in the queue, call the
  1047. callback routine with SPFILENOTIFY_QUEUESCAN. If the callback
  1048. routine returns non-0 then queue processing is stopped and this
  1049. routine returns FALSE immediately.
  1050. SPQ_SCAN_USE_CALLBACKEX - same as SPQ_SCAN_USE_CALLBACK except that
  1051. SPFILENOTIFY_QUEUESCAN_EX is used instead. This supplies a pointer
  1052. to a FILEPATHS structure in Param1, thus you get both source and
  1053. destination info. You also get the results of the file presence
  1054. check (and if present, of its digital signature verification) in
  1055. the Win32Error field, and the CopyStyle flags in effect for that
  1056. copy queue node in the Flags field.
  1057. SPQ_SCAN_USE_CALLBACK_SIGNERINFO - same as SPQ_SCAN_USE_CALLBACK except
  1058. that SPFILENOTIFY_QUEUESCAN_SIGNERINFO is used instead. This
  1059. supplies a pointer to a FILEPATHS_SIGNERINFO structure in Param1,
  1060. thus you get both source and destination info. You also get the
  1061. results of the file presence check (and if present, of its digital
  1062. signature verification) in the Win32Error field, and the CopyStyle
  1063. flags in effect for that copy queue node in the Flags field. In
  1064. addition you get who digitaly signed the file in the DigitalSigner
  1065. field and the SHA1 key in the SignerId field.
  1066. Exactly one of SPQ_SCAN_FILE_PRESENCE, SPQ_SCAN_FILE_VALIDITY,
  1067. SPQ_SCAN_USE_CALLBACK, SPQ_SCAN_USE_CALLBACKEX, or
  1068. SPQ_SCAN_USE_CALLBACK_SIGNERINFO must be specified.
  1069. SPQ_SCAN_INFORM_USER - if specified and all files in the queue
  1070. pass the presence/validity check, then this routine will inform
  1071. the user that the operation he is attempting requires files but
  1072. that we believe all files are already present. Ignored if
  1073. SPQ_SCAN_FILE_PRESENCE or SPQ_SCAN_FILE_VALIDITY is not specified.
  1074. Not valid if specified in combination with SPQ_SCAN_PRUNE_COPY_QUEUE.
  1075. SPQ_SCAN_PRUNE_COPY_QUEUE - if specified, the copy queue will be pruned
  1076. of any nodes that are deemed unnecessary. This determination is
  1077. made based on the type of queue scan being performed:
  1078. If SPQ_SCAN_FILE_PRESENCE, then the presence of a file having the
  1079. destination filename is sufficient to consider this copy operation
  1080. unnecessary.
  1081. If SPQ_SCAN_FILE_VALIDITY, then the destination file must not only
  1082. be present, but also valid in order for the copy operation to be
  1083. considered unnecessary.
  1084. If SPQ_SCAN_USE_CALLBACK, SPQ_SCAN_USE_CALLBACKEX or
  1085. SPQ_SCAN_USE_CALLBACK_SIGNERINFO, then the queue callback routine
  1086. should return zero to mark the copy node as unnecessary, or non-zero
  1087. to leave the node in the copy queue.
  1088. NOTE: This flag may only be specified _before_ the queue has been
  1089. committed. This means that the flags contained in Param2 will
  1090. always be zero. If SetupScanFileQueue is called with
  1091. SPQ_SCAN_PRUNE_COPY_QUEUE after committing the queue, the API will
  1092. fail and GetLastError() will return
  1093. ERROR_NO_MORE_ITEMS.
  1094. This flag is not valid if specified in combination with
  1095. SPQ_SCAN_INFORM_USER.
  1096. Window - specifies the window to own any dialogs, etc, that may be
  1097. presented. Unused if Flags does not contain one of
  1098. SPQ_SCAN_FILE_PRESENCE or SPQ_SCAN_FILE_VALIDITY, or if Flags does not
  1099. contain SPQ_SCAN_INFORM_USER.
  1100. CallbackRoutine - required if Flags includes SPQ_SCAN_USE_CALLBACK.
  1101. Specifies a callback function to be called on each node in
  1102. the copy queue. The notification code passed to the callback is
  1103. SPFILENOTIFY_QUEUESCAN.
  1104. CallbackContext - caller-defined data to be passed to CallbackRoutine.
  1105. Result - receives result of routine. See below.
  1106. Return Value:
  1107. If FALSE, then an error occurred or the callback function returned non-0.
  1108. Check Result -- if it is non-0, then it is the value returned by
  1109. the callback function which stopped queue processing.
  1110. If Result is 0, then extended error information is available from
  1111. GetLastError().
  1112. If TRUE, then all nodes were processed. Result is 0 if a callback was
  1113. specified. If SPQ_SCAN_USE_CALLBACK(EX) or SPQ_SCAN_USE_CALLBACK_SIGNERINFO
  1114. was not specified, then Result indicates whether the queue passed the
  1115. presence/validity check:
  1116. Result = 0: queue failed the check, or the queue passed the
  1117. check but SPQ_SCAN_INFORM_USER was specified and the user indicated
  1118. that he wants new copies of the files. There are still nodes in the
  1119. copy queue, although if SPQ_SCAN_PRUNE_COPY_QUEUE is specified, then
  1120. any nodes that were validated have been pruned.
  1121. Result = 1: queue passed the check, and, if SPQ_SCAN_INFORM_USER was
  1122. specified, the user indicated that no copying is required. If Result is
  1123. 1, the copy queue has been emptied, and there are no elements on the
  1124. delete or rename queues, so the caller may skip queue commit.
  1125. Result = 2: queue passed the check, and, if SPQ_SCAN_INFORM_USER was
  1126. specified, the user indicated that no copying is required. In this case,
  1127. the copy queue has been emptied, however there are elements on the
  1128. delete or rename queues, so the caller may not skip queue commit.
  1129. --*/
  1130. {
  1131. BOOL b;
  1132. try {
  1133. b = _SetupScanFileQueue(
  1134. FileQueue,
  1135. Flags,
  1136. Window,
  1137. CallbackRoutine,
  1138. CallbackContext,
  1139. Result,
  1140. TRUE
  1141. );
  1142. } except(EXCEPTION_EXECUTE_HANDLER) {
  1143. b = FALSE;
  1144. SetLastError(ERROR_INVALID_DATA);
  1145. }
  1146. return(b);
  1147. }
  1148. INT
  1149. SetupPromptReboot(
  1150. IN HSPFILEQ FileQueue, OPTIONAL
  1151. IN HWND Owner,
  1152. IN BOOL ScanOnly
  1153. )
  1154. /*++
  1155. Routine Description:
  1156. This routine asks the user whether he wants to reboot the system,
  1157. optionally dependent on whether any files in a committed file queue
  1158. were in use (and are thus now pending operations via MoveFileEx()).
  1159. A reboot is also required if any files were installed as boot files
  1160. (e.g., marked as COPYFLG_REPLACE_BOOT_FILE in the INF).
  1161. If the user answers yes to the prompt, shutdown is initiated
  1162. before this routine returns.
  1163. Arguments:
  1164. FileQueue - if specified, supplies a file queue upon which
  1165. to base the decision about whether shutdown is necessary.
  1166. If not specified, then this routine assumes shutdown is
  1167. necessary and asks the user what to do.
  1168. Owner - supplies window handle for parent window to own windows
  1169. created by this routine.
  1170. ScanOnly - if TRUE, then the user is never asked whether he wants
  1171. to reboot and no shutdown is initiated. In this case FileQueue
  1172. must be specified. If FALSE then this routine functions as
  1173. described above.
  1174. This flags is used when the caller wants to determine whether
  1175. shutdown is necessary separately from actually performing
  1176. the shutdown.
  1177. Return Value:
  1178. A combination of the following flags or -1 if an error occured:
  1179. SPFILEQ_FILE_IN_USE: at least one file was in use and thus there are
  1180. delayed file operations pending. This flag will never be set
  1181. when FileQueue is not specified.
  1182. SPFILEQ_REBOOT_RECOMMENDED: it is recommended that the system
  1183. be rebooted. Depending on other flags and user response to
  1184. the shutdown query, shutdown may already be happening.
  1185. SPFILEQ_REBOOT_IN_PROGRESS: shutdown is in progress.
  1186. --*/
  1187. {
  1188. PSP_FILE_QUEUE Queue;
  1189. PSP_FILE_QUEUE_NODE QueueNode;
  1190. PSOURCE_MEDIA_INFO SourceMedia;
  1191. INT Flags;
  1192. int i;
  1193. DWORD Reason = REASON_PLANNED_FLAG;
  1194. //
  1195. // If only scanning, there must be a FileQueue to scan!
  1196. //
  1197. if(ScanOnly && !FileQueue) {
  1198. SetLastError(ERROR_INVALID_PARAMETER);
  1199. return -1;
  1200. }
  1201. //
  1202. // If we're not just scanning (i.e., we're potentially going to popup UI,
  1203. // then we'd better be interactive.
  1204. //
  1205. if(!ScanOnly && (GlobalSetupFlags & (PSPGF_NONINTERACTIVE|PSPGF_UNATTENDED_SETUP))) {
  1206. SetLastError(ERROR_REQUIRES_INTERACTIVE_WINDOWSTATION);
  1207. return -1;
  1208. }
  1209. Queue = (PSP_FILE_QUEUE)FileQueue;
  1210. Flags = 0;
  1211. //
  1212. // Scan file queue if the caller so desires.
  1213. //
  1214. if(FileQueue) {
  1215. try {
  1216. if(Queue->Flags & FQF_DEVICE_INSTALL) {
  1217. Reason |= REASON_HWINSTALL;
  1218. }
  1219. //
  1220. // Check delete queue for in-use files.
  1221. //
  1222. for(QueueNode=Queue->DeleteQueue; QueueNode; QueueNode=QueueNode->Next) {
  1223. if(QueueNode->InternalFlags & INUSE_INF_WANTS_REBOOT) {
  1224. Flags |= SPFILEQ_REBOOT_RECOMMENDED;
  1225. }
  1226. if(QueueNode->InternalFlags & INUSE_IN_USE) {
  1227. Flags |= SPFILEQ_FILE_IN_USE;
  1228. }
  1229. }
  1230. //
  1231. // Check copy queues for in-use files.
  1232. //
  1233. for(SourceMedia=Queue->SourceMediaList; SourceMedia; SourceMedia=SourceMedia->Next) {
  1234. for(QueueNode=SourceMedia->CopyQueue; QueueNode; QueueNode=QueueNode->Next) {
  1235. if(QueueNode->InternalFlags & INUSE_INF_WANTS_REBOOT) {
  1236. Flags |= SPFILEQ_REBOOT_RECOMMENDED;
  1237. }
  1238. if(QueueNode->InternalFlags & INUSE_IN_USE) {
  1239. Flags |= SPFILEQ_FILE_IN_USE;
  1240. }
  1241. }
  1242. }
  1243. } except(EXCEPTION_EXECUTE_HANDLER) {
  1244. SetLastError(ERROR_INVALID_PARAMETER);
  1245. Flags = -1;
  1246. }
  1247. } else {
  1248. Flags = SPFILEQ_REBOOT_RECOMMENDED;
  1249. }
  1250. //
  1251. // Ask the user if he wants to shut down, if necessary.
  1252. //
  1253. if(!ScanOnly &&
  1254. (Flags & (SPFILEQ_REBOOT_RECOMMENDED | SPFILEQ_FILE_IN_USE)) &&
  1255. (Flags != -1)) {
  1256. if(RestartDialogEx(Owner,NULL,EWX_REBOOT,Reason) == IDYES) {
  1257. Flags |= SPFILEQ_REBOOT_IN_PROGRESS;
  1258. }
  1259. }
  1260. return(Flags);
  1261. }