Source code of Windows XP (NT5)
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.

6394 lines
211 KiB

  1. /*++
  2. Copyright (c) Microsoft Corporation. All rights reserved.
  3. Module Name:
  4. fileq4.c
  5. Abstract:
  6. Setup file queue routines for commit (ie, performing enqueued actions).
  7. Author:
  8. Ted Miller (tedm) 15-Feb-1995
  9. Revision History:
  10. Jamie Hunter (jamiehun) 28-Jan-1997
  11. Added backup queue capabilities
  12. backup on demand capabilities
  13. and unwind capabilities
  14. --*/
  15. #include "precomp.h"
  16. #pragma hdrstop
  17. typedef struct _Q_CAB_CB_DATA {
  18. PSP_FILE_QUEUE Queue;
  19. PSOURCE_MEDIA_INFO SourceMedia;
  20. PSP_FILE_QUEUE_NODE CurrentFirstNode;
  21. PVOID MsgHandler;
  22. PVOID Context;
  23. BOOL IsMsgHandlerNativeCharWidth;
  24. PSETUP_LOG_CONTEXT LogContext;
  25. } Q_CAB_CB_DATA, *PQ_CAB_CB_DATA;
  26. typedef struct _CERT_PROMPT {
  27. LPCTSTR lpszDescription;
  28. LPCTSTR lpszFile;
  29. SetupapiVerifyProblem ProblemType;
  30. ULONG DriverSigningPolicy;
  31. } CERT_PROMPT, *PCERT_PROMPT;
  32. typedef struct _DRIVERBLOCK_PROMPT {
  33. LPCTSTR lpszFile;
  34. SDBENTRYINFO entryinfo;
  35. } DRIVERBLOCK_PROMPT, *PDRIVERBLOCK_PROMPT;
  36. DWORD
  37. pSetupCommitSingleBackup(
  38. IN PSP_FILE_QUEUE Queue,
  39. IN PCTSTR FullTargetPath,
  40. IN LONG TargetRootPath,
  41. IN LONG TargetSubDir,
  42. IN LONG TargetFilename,
  43. IN PVOID MsgHandler,
  44. IN PVOID Context,
  45. IN BOOL IsMsgHandlerNativeCharWidth,
  46. IN BOOL RenameExisting,
  47. OUT PBOOL InUse
  48. );
  49. DWORD
  50. pCommitCopyQueue(
  51. IN PSP_FILE_QUEUE Queue,
  52. IN PVOID MsgHandler,
  53. IN PVOID Context,
  54. IN BOOL IsMsgHandlerNativeCharWidth
  55. );
  56. DWORD
  57. pCommitBackupQueue(
  58. IN PSP_FILE_QUEUE Queue,
  59. IN PVOID MsgHandler,
  60. IN PVOID Context,
  61. IN BOOL IsMsgHandlerNativeCharWidth
  62. );
  63. DWORD
  64. pCommitDeleteQueue(
  65. IN PSP_FILE_QUEUE Queue,
  66. IN PVOID MsgHandler,
  67. IN PVOID Context,
  68. IN BOOL IsMsgHandlerNativeCharWidth
  69. );
  70. DWORD
  71. pCommitRenameQueue(
  72. IN PSP_FILE_QUEUE Queue,
  73. IN PVOID MsgHandler,
  74. IN PVOID Context,
  75. IN BOOL IsMsgHandlerNativeCharWidth
  76. );
  77. UINT
  78. pSetupCabinetQueueCallback(
  79. IN PVOID Context,
  80. IN UINT Notification,
  81. IN UINT_PTR Param1,
  82. IN UINT_PTR Param2
  83. );
  84. DWORD
  85. pSetupCopySingleQueuedFile(
  86. IN PSP_FILE_QUEUE Queue,
  87. IN PSP_FILE_QUEUE_NODE QueueNode,
  88. IN PCTSTR FullSourceName,
  89. IN PVOID MsgHandler,
  90. IN PVOID Context,
  91. OUT PTSTR NewSourcePath,
  92. IN BOOL IsMsgHandlerNativeCharWidth,
  93. IN DWORD CopyStyleFlags
  94. );
  95. DWORD
  96. pSetupCopySingleQueuedFileCabCase(
  97. IN PSP_FILE_QUEUE Queue,
  98. IN PSP_FILE_QUEUE_NODE QueueNode,
  99. IN PCTSTR CabinetName,
  100. IN PCTSTR FullSourceName,
  101. IN PVOID MsgHandler,
  102. IN PVOID Context,
  103. IN BOOL IsMsgHandlerNativeCharWidth
  104. );
  105. VOID
  106. pSetupSetPathOverrides(
  107. IN PVOID StringTable,
  108. IN OUT PTSTR RootPath,
  109. IN OUT PTSTR SubPath,
  110. IN LONG RootPathId,
  111. IN LONG SubPathId,
  112. IN PTSTR NewPath
  113. );
  114. VOID
  115. pSetupBuildSourceForCopy(
  116. IN PCTSTR UserRoot,
  117. IN PCTSTR UserPath,
  118. IN LONG MediaRoot,
  119. IN PSP_FILE_QUEUE Queue,
  120. IN PSP_FILE_QUEUE_NODE QueueNode,
  121. OUT PTSTR FullPath
  122. );
  123. INT_PTR
  124. CALLBACK
  125. CertifyDlgProc(
  126. IN HWND hwnd,
  127. IN UINT msg,
  128. IN WPARAM wParam,
  129. IN LPARAM lParam
  130. );
  131. INT_PTR
  132. CALLBACK
  133. DriverBlockDlgProc(
  134. IN HWND hwnd,
  135. IN UINT msg,
  136. IN WPARAM wParam,
  137. IN LPARAM lParam
  138. );
  139. VOID
  140. RestoreBootReplacedFile(
  141. IN PSP_FILE_QUEUE Queue,
  142. IN PSP_FILE_QUEUE_NODE QueueNode
  143. );
  144. VOID
  145. pSetupExemptFileFromProtection(
  146. IN PCTSTR FileName,
  147. IN DWORD FileChangeFlags,
  148. IN PSETUP_LOG_CONTEXT LogContext, OPTIONAL
  149. OUT PDWORD QueueNodeFlags OPTIONAL
  150. );
  151. VOID
  152. pSetupUninstallNewCatalogNodes(
  153. IN PSP_FILE_QUEUE Queue,
  154. IN PSETUP_LOG_CONTEXT LogContext OPTIONAL
  155. );
  156. BOOL
  157. _SetupCommitFileQueue(
  158. IN HWND Owner, OPTIONAL
  159. IN HSPFILEQ QueueHandle,
  160. IN PVOID MsgHandler,
  161. IN PVOID Context,
  162. IN BOOL IsMsgHandlerNativeCharWidth
  163. )
  164. /*++
  165. Routine Description:
  166. Implementation for SetupCommitFileQueue; handles ANSI and Unicode
  167. callback routines.
  168. Arguments:
  169. Same as for SetupCommitFileQueue().
  170. IsMsgHandlerNativeCharWidth - indicates whether the MsgHandler callback
  171. expects native char width args (or ansi ones, in the unicode build
  172. of this dll).
  173. Return Value:
  174. Boolean value indicating outcome. If FALSE, the GetLastError() indicates
  175. cause of failure.
  176. --*/
  177. {
  178. PSP_FILE_QUEUE Queue;
  179. DWORD rc;
  180. BOOL Success = TRUE;
  181. BOOL ChangedThreadLogContext = FALSE;
  182. PSETUP_LOG_CONTEXT SavedLogContext = NULL;
  183. PSETUP_LOG_CONTEXT LogContext = NULL;
  184. //
  185. // Queue handle is actually a pointer to the queue structure.
  186. //
  187. Queue = (PSP_FILE_QUEUE)QueueHandle;
  188. //
  189. // do a quick handle validation before anything else
  190. //
  191. try {
  192. Success = ((Queue != NULL) && (Queue != INVALID_HANDLE_VALUE) && (Queue->Signature == SP_FILE_QUEUE_SIG));
  193. if (Success) {
  194. LogContext = Queue->LogContext;
  195. }
  196. } except (EXCEPTION_EXECUTE_HANDLER) {
  197. Success = FALSE;
  198. }
  199. if (!Success) {
  200. SetLastError(ERROR_INVALID_HANDLE);
  201. return FALSE;
  202. }
  203. //
  204. // If there's nothing to do, bail now. This prevents an empty
  205. // progress dialog from flashing on the screen. Don't return out
  206. // of the body of the try -- that is bad news performance-wise.
  207. //
  208. try {
  209. Success = (!Queue->DeleteNodeCount && !Queue->RenameNodeCount && !Queue->CopyNodeCount && !Queue->BackupNodeCount);
  210. } except (EXCEPTION_EXECUTE_HANDLER) {
  211. SetLastError(ERROR_INVALID_HANDLE);
  212. return(FALSE);
  213. }
  214. if(Success) {
  215. //
  216. // We are successful in that we had no file operations to do. However,
  217. // we still need to validate the queued catalogs at this time, because
  218. // we always do validation in the context of file copying. If we don't
  219. // do this, we have a hole where a device INF that doesn't copy files
  220. // (e.g., a modem INF) can circumvent driver signing checking.
  221. //
  222. WriteLogEntry(
  223. LogContext,
  224. SETUP_LOG_TIME,
  225. MSG_LOG_BEGIN_VERIFY3_CAT_TIME,
  226. NULL); // text message
  227. rc = _SetupVerifyQueuedCatalogs(Owner,
  228. Queue,
  229. VERCAT_INSTALL_INF_AND_CAT,
  230. NULL,
  231. NULL
  232. );
  233. WriteLogEntry(
  234. LogContext,
  235. SETUP_LOG_TIME,
  236. MSG_LOG_END_VERIFY3_CAT_TIME,
  237. NULL); // text message
  238. if (rc == NO_ERROR) {
  239. //
  240. // If we performed a backup and this is a device install then call
  241. // the pSetupCompleteBackup API to create the Reinstall instance
  242. // subkey and do other device rollback cleanup.
  243. //
  244. if (Queue->Flags & FQF_DEVICE_BACKUP) {
  245. pSetupCompleteBackup(Queue);
  246. }
  247. Queue->Flags |= FQF_QUEUE_ALREADY_COMMITTED;
  248. } else {
  249. //
  250. // Go uninstall any newly-copied INFs/PNFs/CATs.
  251. //
  252. pSetupUninstallNewCatalogNodes(Queue, LogContext);
  253. }
  254. SetLastError(rc);
  255. return(rc == NO_ERROR);
  256. }
  257. ASSERT_HEAP_IS_VALID();
  258. //
  259. // make a note of default logging context for duration of queue processing
  260. // this will catch, eg, INF being opened as part of a callback
  261. //
  262. MYASSERT(!ChangedThreadLogContext);
  263. ChangedThreadLogContext = SetThreadLogContext(LogContext,&SavedLogContext);
  264. if (ChangedThreadLogContext) {
  265. //
  266. // add one more ref to protext log context
  267. //
  268. RefLogContext(LogContext);
  269. }
  270. Success = pSetupCallMsgHandler(
  271. LogContext,
  272. MsgHandler,
  273. IsMsgHandlerNativeCharWidth,
  274. Context,
  275. SPFILENOTIFY_STARTQUEUE,
  276. (UINT_PTR)Owner,
  277. 0
  278. );
  279. if(!Success) {
  280. rc = GetLastError();
  281. if(!rc) {
  282. rc = ERROR_OPERATION_ABORTED;
  283. }
  284. goto final;
  285. }
  286. try {
  287. //
  288. // Verify catalogs/infs.
  289. //
  290. WriteLogEntry(
  291. LogContext,
  292. SETUP_LOG_TIME,
  293. MSG_LOG_BEGIN_VERIFY2_CAT_TIME,
  294. NULL); // text message
  295. rc = _SetupVerifyQueuedCatalogs(Owner,
  296. Queue,
  297. VERCAT_INSTALL_INF_AND_CAT,
  298. NULL,
  299. NULL
  300. );
  301. WriteLogEntry(
  302. LogContext,
  303. SETUP_LOG_TIME,
  304. MSG_LOG_END_VERIFY2_CAT_TIME,
  305. NULL); // text message
  306. Success = (rc == NO_ERROR);
  307. if(rc != NO_ERROR) {
  308. goto Bail;
  309. }
  310. ASSERT_HEAP_IS_VALID();
  311. //
  312. // Handle backup first
  313. // don't commit if there's nothing to do
  314. //
  315. rc = Queue->BackupNodeCount
  316. ? pCommitBackupQueue(Queue,MsgHandler,Context,IsMsgHandlerNativeCharWidth)
  317. : NO_ERROR;
  318. Success = (rc == NO_ERROR);
  319. ASSERT_HEAP_IS_VALID();
  320. if (!Success) {
  321. goto Bail;
  322. }
  323. //
  324. // Handle deletes
  325. // now done after backups, but may incorporate a per-delete backup
  326. // don't commit if there's nothing to do
  327. //
  328. rc = Queue->DeleteNodeCount
  329. ? pCommitDeleteQueue(Queue,MsgHandler,Context,IsMsgHandlerNativeCharWidth)
  330. : NO_ERROR;
  331. Success = (rc == NO_ERROR);
  332. ASSERT_HEAP_IS_VALID();
  333. if (!Success) {
  334. goto Bail;
  335. }
  336. //
  337. // Handle renames next.
  338. // don't commit if there's nothing to do
  339. //
  340. rc = Queue->RenameNodeCount
  341. ? pCommitRenameQueue(Queue,MsgHandler,Context,IsMsgHandlerNativeCharWidth)
  342. : NO_ERROR;
  343. Success = (rc == NO_ERROR);
  344. ASSERT_HEAP_IS_VALID();
  345. if (!Success) {
  346. goto Bail;
  347. }
  348. //
  349. // Handle copies last. Don't bother calling the copy commit routine
  350. // if there are no files to copy.
  351. //
  352. rc = Queue->CopyNodeCount
  353. ? pCommitCopyQueue(Queue,MsgHandler,Context,IsMsgHandlerNativeCharWidth)
  354. : NO_ERROR;
  355. Success = (rc == NO_ERROR);
  356. ASSERT_HEAP_IS_VALID();
  357. if (!Success) {
  358. goto Bail;
  359. }
  360. rc = DoAllDelayedMoves(Queue);
  361. Success = (rc == NO_ERROR);
  362. if(Success) {
  363. //
  364. // Set a flag indicating we've committed the file queue (used to keep
  365. // us from attempting to prune the queue after having committed it).
  366. //
  367. Queue->Flags |= FQF_QUEUE_ALREADY_COMMITTED;
  368. }
  369. //
  370. // If we performed a backup and this is a device install then call
  371. // the pSetupCompleteBackup API to create the Reinstall instance
  372. // subkey and do other device rollback cleanup.
  373. //
  374. if (Queue->Flags & FQF_DEVICE_BACKUP) {
  375. pSetupCompleteBackup(Queue);
  376. }
  377. Bail:
  378. ;
  379. } except(EXCEPTION_EXECUTE_HANDLER) {
  380. Success = FALSE;
  381. rc = ERROR_INVALID_DATA;
  382. }
  383. pSetupCallMsgHandler(
  384. LogContext,
  385. MsgHandler,
  386. IsMsgHandlerNativeCharWidth,
  387. Context,
  388. SPFILENOTIFY_ENDQUEUE,
  389. Success,
  390. 0
  391. );
  392. pSetupUnwindAll(Queue, Success);
  393. final:
  394. //
  395. // If we didn't succeed, then uninstall any new INFs/PNFs/CATs we may have
  396. // installed.
  397. //
  398. if(!Success) {
  399. pSetupUninstallNewCatalogNodes(Queue, LogContext);
  400. }
  401. if (ChangedThreadLogContext) {
  402. //
  403. // restore thread log context
  404. //
  405. SetThreadLogContext(SavedLogContext,NULL);
  406. DeleteLogContext(LogContext); // counter RefLogContext
  407. }
  408. SetLastError(rc);
  409. return(Success);
  410. }
  411. #ifdef UNICODE
  412. //
  413. // ANSI version. Also need undecorated (Unicode) version for compatibility
  414. // with apps that were linked before we had A and W versions.
  415. //
  416. BOOL
  417. SetupCommitFileQueueA(
  418. IN HWND Owner, OPTIONAL
  419. IN HSPFILEQ QueueHandle,
  420. IN PSP_FILE_CALLBACK_A MsgHandler,
  421. IN PVOID Context
  422. )
  423. {
  424. return(_SetupCommitFileQueue(Owner,QueueHandle,MsgHandler,Context,FALSE));
  425. }
  426. #undef SetupCommitFileQueue
  427. SetupCommitFileQueue(
  428. IN HWND Owner, OPTIONAL
  429. IN HSPFILEQ QueueHandle,
  430. IN PSP_FILE_CALLBACK_W MsgHandler,
  431. IN PVOID Context
  432. )
  433. {
  434. return(_SetupCommitFileQueue(Owner,QueueHandle,MsgHandler,Context,TRUE));
  435. }
  436. #else
  437. //
  438. // Unicode stub. Also need undecorated (ANSI) version for compatibility
  439. // with apps that were linked before we had A and W versions.
  440. //
  441. BOOL
  442. SetupCommitFileQueueW(
  443. IN HWND Owner, OPTIONAL
  444. IN HSPFILEQ QueueHandle,
  445. IN PSP_FILE_CALLBACK_W MsgHandler,
  446. IN PVOID Context
  447. )
  448. {
  449. UNREFERENCED_PARAMETER(Owner);
  450. UNREFERENCED_PARAMETER(QueueHandle);
  451. UNREFERENCED_PARAMETER(MsgHandler);
  452. UNREFERENCED_PARAMETER(Context);
  453. SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
  454. return(FALSE);
  455. }
  456. #undef SetupCommitFileQueue
  457. SetupCommitFileQueue(
  458. IN HWND Owner, OPTIONAL
  459. IN HSPFILEQ QueueHandle,
  460. IN PSP_FILE_CALLBACK_A MsgHandler,
  461. IN PVOID Context
  462. )
  463. {
  464. return(_SetupCommitFileQueue(Owner,QueueHandle,MsgHandler,Context,TRUE));
  465. }
  466. #endif
  467. BOOL
  468. #ifdef UNICODE
  469. SetupCommitFileQueueW(
  470. #else
  471. SetupCommitFileQueueA(
  472. #endif
  473. IN HWND Owner, OPTIONAL
  474. IN HSPFILEQ QueueHandle,
  475. IN PSP_FILE_CALLBACK MsgHandler,
  476. IN PVOID Context
  477. )
  478. /*++
  479. Routine Description:
  480. Perform file operations enqueued on a setup file queue.
  481. Arguments:
  482. OwnerWindow - if specified, supplies the window handle of a window
  483. that is to be used as the parent of any progress dialogs.
  484. QueueHandle - supplies a handle to a setup file queue, as returned
  485. by SetupOpenFileQueue.
  486. MsgHandler - Supplies a callback routine to be notified
  487. of various significant events in the queue processing.
  488. Context - Supplies a value that is passed to the MsgHandler
  489. callback function.
  490. Return Value:
  491. Boolean value indicating outcome.
  492. --*/
  493. {
  494. return(_SetupCommitFileQueue(Owner,QueueHandle,MsgHandler,Context,TRUE));
  495. }
  496. DWORD
  497. pCommitBackupQueue(
  498. IN PSP_FILE_QUEUE Queue,
  499. IN PVOID MsgHandler,
  500. IN PVOID Context,
  501. IN BOOL IsMsgHandlerNativeCharWidth
  502. )
  503. /*++
  504. Routine Description:
  505. Process the backup Queue
  506. Backup each file specified in the queue if it exists
  507. File is marked as backup
  508. Location of backup is recorded
  509. Files are not added to unwind queue here
  510. They get added to unwind queue the first time they are potentially modified
  511. See also pCommitDeleteQueue, pCommitRenameQueue and pCommitCopyQueue
  512. Arguments:
  513. Queue - queue that contains the backup sub-queue
  514. MsgHandler - Supplies a callback routine to be notified
  515. of various significant events in the queue processing.
  516. Context - Supplies a value that is passed to the MsgHandler
  517. callback function.
  518. IsMsgHandlerNativeCharWidth - For Unicode/Ansi support
  519. Return Value:
  520. DWORD indicating status or success
  521. --*/
  522. {
  523. PSP_FILE_QUEUE_NODE QueueNode,queueNode;
  524. UINT u;
  525. BOOL b;
  526. DWORD rc;
  527. PCTSTR FullTargetPath,FullBackupPath;
  528. FILEPATHS FilePaths;
  529. BOOL Skipped = FALSE;
  530. DWORD BackupFlags = SP_BACKUP_BACKUPPASS;
  531. MYASSERT(Queue->BackupNodeCount);
  532. b = pSetupCallMsgHandler(
  533. Queue->LogContext,
  534. MsgHandler,
  535. IsMsgHandlerNativeCharWidth,
  536. Context,
  537. SPFILENOTIFY_STARTSUBQUEUE,
  538. FILEOP_BACKUP,
  539. Queue->BackupNodeCount
  540. );
  541. if(!b) {
  542. rc = GetLastError();
  543. if(!rc) {
  544. rc = ERROR_OPERATION_ABORTED;
  545. }
  546. goto clean0;
  547. }
  548. for(QueueNode=Queue->BackupQueue; QueueNode; QueueNode=QueueNode->Next) {
  549. //
  550. // Form the full path of the file to be backed up
  551. //
  552. FullBackupPath = pSetupFormFullPath(
  553. Queue->StringTable,
  554. QueueNode->SourceRootPath,
  555. QueueNode->SourcePath,
  556. QueueNode->SourceFilename
  557. );
  558. if(!FullBackupPath) {
  559. rc = ERROR_NOT_ENOUGH_MEMORY;
  560. goto clean0;
  561. }
  562. FullTargetPath = pSetupFormFullPath(
  563. Queue->StringTable,
  564. QueueNode->TargetDirectory,
  565. QueueNode->TargetFilename,
  566. -1
  567. );
  568. if(!FullTargetPath) {
  569. MyFree(FullBackupPath);
  570. rc = ERROR_NOT_ENOUGH_MEMORY;
  571. goto clean0;
  572. }
  573. FilePaths.Source = FullTargetPath; // copying from
  574. FilePaths.Target = FullBackupPath; // copying to (backup)
  575. FilePaths.Win32Error = NO_ERROR;
  576. FilePaths.Flags = BackupFlags;
  577. Skipped = FALSE;
  578. //
  579. // Inform the callback that we are about to start a backup operation.
  580. //
  581. u = pSetupCallMsgHandler(
  582. Queue->LogContext,
  583. MsgHandler,
  584. IsMsgHandlerNativeCharWidth,
  585. Context,
  586. SPFILENOTIFY_STARTBACKUP,
  587. (UINT_PTR)&FilePaths,
  588. FILEOP_BACKUP
  589. );
  590. if(u == FILEOP_ABORT) {
  591. rc = GetLastError();
  592. if(!rc) {
  593. rc = ERROR_OPERATION_ABORTED;
  594. }
  595. MyFree(FullTargetPath);
  596. MyFree(FullBackupPath);
  597. goto clean0;
  598. }
  599. if(u == FILEOP_DOIT) {
  600. //
  601. // Attempt the backup. If it fails inform the callback,
  602. // which may decide to abort, retry. or skip the file.
  603. //
  604. //SetFileAttributes(FullTargetPath,FILE_ATTRIBUTE_NORMAL);
  605. do {
  606. rc = pSetupBackupFile((HSPFILEQ)Queue,
  607. FullTargetPath,
  608. FullBackupPath,
  609. -1, // TargetID not known
  610. QueueNode->TargetDirectory, // what to backup
  611. -1, // Queue Node's don't maintain this intermediate path
  612. QueueNode->TargetFilename,
  613. QueueNode->SourceRootPath, // backup as...
  614. QueueNode->SourcePath,
  615. QueueNode->SourceFilename,
  616. &b
  617. );
  618. if (rc == NO_ERROR) {
  619. if (b) {
  620. // delayed (in use)
  621. QueueNode->InternalFlags |= INUSE_IN_USE;
  622. //
  623. // Tell the callback.
  624. //
  625. FilePaths.Win32Error = NO_ERROR;
  626. FilePaths.Flags = FILEOP_BACKUP;
  627. pSetupCallMsgHandler(
  628. Queue->LogContext,
  629. MsgHandler,
  630. IsMsgHandlerNativeCharWidth,
  631. Context,
  632. SPFILENOTIFY_FILEOPDELAYED,
  633. (UINT_PTR)&FilePaths,
  634. 0
  635. );
  636. }
  637. } else {
  638. FilePaths.Win32Error = rc;
  639. FilePaths.Flags = BackupFlags;
  640. u = pSetupCallMsgHandler(
  641. Queue->LogContext,
  642. MsgHandler,
  643. IsMsgHandlerNativeCharWidth,
  644. Context,
  645. SPFILENOTIFY_BACKUPERROR,
  646. (UINT_PTR)&FilePaths,
  647. 0
  648. );
  649. if(u == FILEOP_ABORT) {
  650. rc = GetLastError();
  651. if(!rc) {
  652. rc = ERROR_OPERATION_ABORTED;
  653. }
  654. MyFree(FullTargetPath);
  655. MyFree(FullBackupPath);
  656. goto clean0;
  657. }
  658. if(u == FILEOP_SKIP) {
  659. // we skipped the backup
  660. Skipped = TRUE;
  661. break;
  662. }
  663. }
  664. } while(rc != NO_ERROR);
  665. } else {
  666. // we skipped the backup
  667. Skipped = TRUE;
  668. rc = NO_ERROR;
  669. }
  670. FilePaths.Win32Error = rc;
  671. FilePaths.Flags = BackupFlags;
  672. pSetupCallMsgHandler(
  673. Queue->LogContext,
  674. MsgHandler,
  675. IsMsgHandlerNativeCharWidth,
  676. Context,
  677. SPFILENOTIFY_ENDBACKUP,
  678. (UINT_PTR)&FilePaths,
  679. 0
  680. );
  681. MyFree(FullTargetPath);
  682. MyFree(FullBackupPath);
  683. }
  684. pSetupCallMsgHandler(
  685. Queue->LogContext,
  686. MsgHandler,
  687. IsMsgHandlerNativeCharWidth,
  688. Context,
  689. SPFILENOTIFY_ENDSUBQUEUE,
  690. FILEOP_BACKUP,
  691. 0
  692. );
  693. rc = NO_ERROR;
  694. clean0:
  695. SetLastError(rc);
  696. return rc;
  697. }
  698. DWORD
  699. pSetupCommitSingleBackup(
  700. IN PSP_FILE_QUEUE Queue,
  701. IN PCTSTR FullTargetPath,
  702. IN LONG TargetRootPath,
  703. IN LONG TargetSubDir,
  704. IN LONG TargetFilename,
  705. IN PVOID MsgHandler,
  706. IN PVOID Context,
  707. IN BOOL IsMsgHandlerNativeCharWidth,
  708. IN BOOL RenameExisting,
  709. OUT PBOOL InUse
  710. )
  711. /*++
  712. Routine Description:
  713. Check a single file that is potentially about to be modified
  714. If the target file doesn't exist, then this routine does nothing
  715. If the target file hasn't been backed up, back it up
  716. If the target file has been backed up, but is not on unwind queue,
  717. add to unwind queue
  718. The default target location of the backup is used, which is either
  719. into a backup directory tree, or a temporary backup location
  720. Location of backup is recorded
  721. Arguments:
  722. Queue - queue that contains the backup sub-queue
  723. FullTargetPath - String giving target path, or NULL if not formed
  724. TargetRootPath - String ID giving RootPath, or -1 if not specified
  725. TargetSubDir - String ID giving SubDir (relative to RootPath),
  726. or -1 if not specified
  727. TargetFilename - String ID giving Filename, or -1 if not specified
  728. MsgHandler - Supplies a callback routine to be notified
  729. of various significant events in the queue processing.
  730. Context - Supplies a value that is passed to the MsgHandler
  731. callback function.
  732. IsMsgHandlerNativeCharWidth - For Unicode/Ansi support
  733. RenameExisting - Should existing file be renamed?
  734. InUse - if specified, set to indicate if file is in use or not
  735. This should never be the case
  736. Return Value:
  737. DWORD indicating status or success
  738. --*/
  739. {
  740. UINT u;
  741. BOOL b;
  742. DWORD rc;
  743. DWORD rc2;
  744. FILEPATHS FilePaths;
  745. LONG TargetID;
  746. PTSTR TargetPathLocal = NULL;
  747. PSP_UNWIND_NODE UnwindNode = NULL;
  748. SP_TARGET_ENT TargetInfo;
  749. BOOL FileOfSameNameExists;
  750. BOOL DoBackup = TRUE;
  751. BOOL NeedUnwind = FALSE;
  752. BOOL Skipped = FALSE;
  753. WIN32_FILE_ATTRIBUTE_DATA FileAttribData;
  754. UINT OldMode;
  755. BOOL DoRename;
  756. DWORD BackupFlags = SP_BACKUP_DEMANDPASS;
  757. //
  758. // used in this function to init time field
  759. //
  760. static const FILETIME zeroTime = {
  761. 0,0
  762. };
  763. OldMode = SetErrorMode(SEM_FAILCRITICALERRORS); // inhibit unexpected dialog boxes
  764. MYASSERT(Queue);
  765. if (FullTargetPath == NULL) {
  766. TargetPathLocal = pSetupFormFullPath(
  767. Queue->StringTable,
  768. TargetRootPath,
  769. TargetSubDir,
  770. TargetFilename);
  771. if(!TargetPathLocal) {
  772. rc = ERROR_NOT_ENOUGH_MEMORY;
  773. goto clean0;
  774. }
  775. FullTargetPath = TargetPathLocal;
  776. }
  777. FileOfSameNameExists = GetFileAttributesEx(FullTargetPath, GetFileExInfoStandard, &FileAttribData);
  778. if (!FileOfSameNameExists) {
  779. // file doesn't exist, so no need to backup
  780. rc = NO_ERROR;
  781. goto clean0;
  782. }
  783. rc = pSetupBackupGetTargetByPath((HSPFILEQ)Queue,
  784. NULL, // use Queue's string table
  785. FullTargetPath,
  786. TargetRootPath,
  787. TargetSubDir,
  788. TargetFilename,
  789. &TargetID,
  790. &TargetInfo
  791. );
  792. if (rc != NO_ERROR) {
  793. // failed for some strange reason
  794. goto clean0;
  795. }
  796. if (TargetInfo.InternalFlags & SP_TEFLG_INUSE) {
  797. //
  798. // was "inuse'd" before
  799. // we mark as still INUSE
  800. if (InUse != NULL) {
  801. *InUse = TRUE;
  802. }
  803. //
  804. // Don't consider this an error, unless we were supposed to rename the
  805. // existing file.
  806. //
  807. rc = RenameExisting ? ERROR_SHARING_VIOLATION : NO_ERROR;
  808. goto clean0;
  809. }
  810. if (TargetInfo.InternalFlags & SP_TEFLG_SKIPPED) {
  811. //
  812. // was skipped before
  813. // we can't rely on it now
  814. //
  815. rc = NO_ERROR;
  816. goto clean0;
  817. }
  818. //
  819. // If we've been asked to backup the existing file, then make sure the
  820. // SP_TEFLG_RENAMEEXISTING flag is set in the TargetInfo. Also, figure out
  821. // if we've already done the rename.
  822. //
  823. if(RenameExisting &&
  824. !(TargetInfo.InternalFlags & SP_TEFLG_RENAMEEXISTING)) {
  825. //
  826. // We'd better not think we already renamed this file!
  827. //
  828. MYASSERT(!(TargetInfo.InternalFlags & SP_TEFLG_MOVED));
  829. TargetInfo.InternalFlags |= SP_TEFLG_RENAMEEXISTING;
  830. //
  831. // update internal info (this call should never fail)
  832. //
  833. pSetupBackupSetTargetByID((HSPFILEQ)Queue,
  834. TargetID,
  835. &TargetInfo
  836. );
  837. }
  838. //
  839. // Figure out whether we've been asked to rename the existing file to a
  840. // temp name in the same directory, but haven't yet done so.
  841. //
  842. DoRename = ((TargetInfo.InternalFlags & (SP_TEFLG_RENAMEEXISTING | SP_TEFLG_MOVED)) == SP_TEFLG_RENAMEEXISTING);
  843. if(TargetInfo.InternalFlags & SP_TEFLG_SAVED) {
  844. //
  845. // already backed up
  846. //
  847. DoBackup = FALSE;
  848. if((TargetInfo.InternalFlags & SP_TEFLG_UNWIND) && !DoRename) {
  849. //
  850. // already added to unwind queue, and we don't need to do a rename--
  851. // don't need to do anything at all
  852. //
  853. rc = NO_ERROR;
  854. goto clean0;
  855. }
  856. //
  857. // we don't need to backup
  858. // but we still need to add to unwind queue, rename the existing file,
  859. // or both.
  860. //
  861. }
  862. if(DoBackup) {
  863. BackupFlags |= SP_BACKUP_DEMANDPASS;
  864. }
  865. if(DoRename) {
  866. BackupFlags |= SP_BACKUP_BOOTFILE | SP_BACKUP_SPECIAL;
  867. }
  868. FilePaths.Source = FullTargetPath; // what we are backing up
  869. FilePaths.Target = NULL; // indicates an automatic backup
  870. FilePaths.Win32Error = NO_ERROR;
  871. FilePaths.Flags = BackupFlags;
  872. if (DoRename) {
  873. pSetupExemptFileFromProtection(
  874. FullTargetPath,
  875. SFC_ACTION_ADDED | SFC_ACTION_REMOVED | SFC_ACTION_MODIFIED
  876. | SFC_ACTION_RENAMED_OLD_NAME |SFC_ACTION_RENAMED_NEW_NAME,
  877. Queue->LogContext,
  878. NULL
  879. );
  880. }
  881. if (DoBackup && (Queue->Flags & FQF_BACKUP_AWARE)) {
  882. //
  883. // Inform the callback that we are about to start a backup operation.
  884. //
  885. u = pSetupCallMsgHandler(
  886. Queue->LogContext,
  887. MsgHandler,
  888. IsMsgHandlerNativeCharWidth,
  889. Context,
  890. SPFILENOTIFY_STARTBACKUP,
  891. (UINT_PTR)&FilePaths,
  892. FILEOP_BACKUP
  893. );
  894. } else {
  895. //
  896. // no backup, or not backup aware, assume a default
  897. //
  898. u = FILEOP_DOIT;
  899. }
  900. if(u == FILEOP_ABORT) {
  901. rc = GetLastError();
  902. if(!rc) {
  903. rc = ERROR_OPERATION_ABORTED;
  904. }
  905. goto clean0;
  906. }
  907. if((u == FILEOP_DOIT) || (BackupFlags & SP_BACKUP_SPECIAL)) {
  908. //
  909. // Attempt the backup. If it fails inform the callback,
  910. // which may decide to abort, retry. or skip the file.
  911. //
  912. //SetFileAttributes(FullTargetPath,FILE_ATTRIBUTE_NORMAL);
  913. //
  914. // Setup an unwind node, unless we already have one.
  915. //
  916. if(!(TargetInfo.InternalFlags & SP_TEFLG_UNWIND)) {
  917. UnwindNode = MyMalloc(sizeof(SP_UNWIND_NODE));
  918. if (UnwindNode == NULL) {
  919. rc = ERROR_NOT_ENOUGH_MEMORY;
  920. goto clean0;
  921. }
  922. UnwindNode->NextNode = Queue->UnwindQueue;
  923. UnwindNode->TargetID = TargetID;
  924. if (RetreiveFileSecurity( FullTargetPath, &(UnwindNode->SecurityDesc)) != NO_ERROR) {
  925. // failed, but not fatal
  926. UnwindNode->SecurityDesc = NULL;
  927. }
  928. if (GetSetFileTimestamp( FullTargetPath, &(UnwindNode->CreateTime),
  929. &(UnwindNode->AccessTime),
  930. &(UnwindNode->WriteTime),
  931. FALSE) != NO_ERROR) {
  932. // failed, but not fatal
  933. UnwindNode->CreateTime = zeroTime;
  934. UnwindNode->AccessTime = zeroTime;
  935. UnwindNode->WriteTime = zeroTime;
  936. }
  937. }
  938. if (DoBackup || DoRename) {
  939. do {
  940. rc = pSetupBackupFile((HSPFILEQ)Queue,
  941. FullTargetPath, // since we know this, pass it
  942. NULL, // automatic destination
  943. TargetID, // we got this earlier
  944. TargetRootPath, // since we know this, pass it
  945. TargetSubDir,
  946. TargetFilename,
  947. -1, // use the details from TargetID (or temp)
  948. -1,
  949. -1,
  950. &b // in use (should always return FALSE)
  951. );
  952. if (rc == NO_ERROR) {
  953. if (InUse != NULL) {
  954. *InUse = b;
  955. }
  956. if (b) {
  957. //
  958. // if file is in use, callback can decide what to do
  959. //
  960. if (Queue->Flags & FQF_BACKUP_AWARE) {
  961. //
  962. // Tell the callback.
  963. //
  964. FilePaths.Win32Error = ERROR_SHARING_VIOLATION;
  965. FilePaths.Flags = BackupFlags;
  966. if (Queue->Flags & FQF_BACKUP_AWARE) {
  967. u = pSetupCallMsgHandler(
  968. Queue->LogContext,
  969. MsgHandler,
  970. IsMsgHandlerNativeCharWidth,
  971. Context,
  972. SPFILENOTIFY_BACKUPERROR,
  973. (UINT_PTR)&FilePaths,
  974. 0
  975. );
  976. if(u == FILEOP_ABORT) {
  977. rc = GetLastError();
  978. if(!rc) {
  979. rc = ERROR_OPERATION_ABORTED;
  980. }
  981. goto clean0;
  982. }
  983. } else {
  984. rc = ERROR_OPERATION_ABORTED;
  985. goto clean0;
  986. }
  987. }
  988. } else {
  989. //
  990. // success!!!!!
  991. // we would have to unwind this if setup fails
  992. //
  993. NeedUnwind = TRUE;
  994. }
  995. } else {
  996. FilePaths.Win32Error = rc;
  997. FilePaths.Flags = BackupFlags;
  998. if (Queue->Flags & FQF_BACKUP_AWARE) {
  999. //
  1000. // inform about error
  1001. //
  1002. u = pSetupCallMsgHandler(
  1003. Queue->LogContext,
  1004. MsgHandler,
  1005. IsMsgHandlerNativeCharWidth,
  1006. Context,
  1007. SPFILENOTIFY_BACKUPERROR,
  1008. (UINT_PTR)&FilePaths,
  1009. 0
  1010. );
  1011. if(u == FILEOP_ABORT) {
  1012. rc = GetLastError();
  1013. if(!rc) {
  1014. rc = ERROR_OPERATION_ABORTED;
  1015. }
  1016. goto clean0;
  1017. }
  1018. } else {
  1019. //
  1020. // if caller is not backup aware, abort
  1021. //
  1022. rc = ERROR_OPERATION_ABORTED;
  1023. goto clean0;
  1024. }
  1025. if(u == FILEOP_SKIP) {
  1026. //
  1027. // we skipped the backup
  1028. //
  1029. Skipped = TRUE;
  1030. break;
  1031. }
  1032. }
  1033. } while(rc != NO_ERROR);
  1034. } else {
  1035. //
  1036. // didn't need to backup, only need to add to unwind queue
  1037. //
  1038. NeedUnwind = TRUE;
  1039. }
  1040. } else {
  1041. //
  1042. // we skipped the backup
  1043. //
  1044. Skipped = TRUE;
  1045. rc = NO_ERROR;
  1046. }
  1047. if (DoBackup) {
  1048. FilePaths.Win32Error = rc;
  1049. if (Queue->Flags & FQF_BACKUP_AWARE) {
  1050. //
  1051. // report result only if backup aware
  1052. //
  1053. pSetupCallMsgHandler(
  1054. Queue->LogContext,
  1055. MsgHandler,
  1056. IsMsgHandlerNativeCharWidth,
  1057. Context,
  1058. SPFILENOTIFY_ENDBACKUP,
  1059. (UINT_PTR)&FilePaths,
  1060. 0
  1061. );
  1062. }
  1063. }
  1064. if (Skipped) {
  1065. //
  1066. // once we return, file may get overwritten or deleted
  1067. // we have to save the fact it has been skipped once
  1068. // so we always skip this file
  1069. //
  1070. if (pSetupBackupGetTargetByID((HSPFILEQ)Queue, TargetID, &TargetInfo) == NO_ERROR) {
  1071. //
  1072. // flag the file should always be skipped
  1073. //
  1074. TargetInfo.InternalFlags|=SP_TEFLG_SKIPPED;
  1075. pSetupBackupSetTargetByID((HSPFILEQ)Queue, TargetID, &TargetInfo);
  1076. }
  1077. }
  1078. else if (NeedUnwind) {
  1079. //
  1080. // We only want to add this to unwind queue
  1081. //
  1082. if (pSetupBackupGetTargetByID((HSPFILEQ)Queue, TargetID, &TargetInfo) == NO_ERROR) {
  1083. if ((TargetInfo.InternalFlags&SP_TEFLG_UNWIND)==FALSE) {
  1084. //
  1085. // node needs to be added to unwind queue
  1086. // we only ever do this once
  1087. //
  1088. Queue->UnwindQueue = UnwindNode;
  1089. //
  1090. // set to NULL so we don't clean it up later
  1091. //
  1092. UnwindNode = NULL;
  1093. //
  1094. // flag that we've added it to unwind queue
  1095. // so we don't try and do it again later
  1096. //
  1097. TargetInfo.InternalFlags|=SP_TEFLG_UNWIND;
  1098. pSetupBackupSetTargetByID((HSPFILEQ)Queue, TargetID, &TargetInfo);
  1099. }
  1100. }
  1101. }
  1102. rc = NO_ERROR;
  1103. clean0:
  1104. if (UnwindNode != NULL) {
  1105. //
  1106. // we allocated, but didn't use this structure
  1107. //
  1108. if (UnwindNode->SecurityDesc != NULL) {
  1109. MyFree(UnwindNode->SecurityDesc);
  1110. }
  1111. MyFree(UnwindNode);
  1112. }
  1113. if (TargetPathLocal != NULL) {
  1114. MyFree(TargetPathLocal);
  1115. }
  1116. SetErrorMode(OldMode);
  1117. SetLastError(rc);
  1118. return rc;
  1119. }
  1120. DWORD
  1121. pCommitDeleteQueue(
  1122. IN PSP_FILE_QUEUE Queue,
  1123. IN PVOID MsgHandler,
  1124. IN PVOID Context,
  1125. IN BOOL IsMsgHandlerNativeCharWidth
  1126. )
  1127. /*++
  1128. Routine Description:
  1129. Process the delete Queue
  1130. Delete each file specified in the queue
  1131. Files are backed up before they are deleted (if not already backed up)
  1132. See also pCommitBackupQueue, pCommitRenameQueue and pCommitCopyQueue
  1133. Arguments:
  1134. Queue - queue that contains the delete sub-queue
  1135. MsgHandler - Supplies a callback routine to be notified
  1136. of various significant events in the queue processing.
  1137. Context - Supplies a value that is passed to the MsgHandler
  1138. callback function.
  1139. IsMsgHandlerNativeCharWidth - For Unicode/Ansi support
  1140. Return Value:
  1141. DWORD indicating status or success
  1142. --*/
  1143. {
  1144. PSP_FILE_QUEUE_NODE QueueNode,queueNode;
  1145. UINT u;
  1146. BOOL b;
  1147. DWORD rc;
  1148. PCTSTR FullTargetPath;
  1149. FILEPATHS FilePaths;
  1150. BOOL BackupInUse = FALSE;
  1151. BOOL TargetIsProtected;
  1152. MYASSERT(Queue->DeleteNodeCount);
  1153. b = pSetupCallMsgHandler(
  1154. Queue->LogContext,
  1155. MsgHandler,
  1156. IsMsgHandlerNativeCharWidth,
  1157. Context,
  1158. SPFILENOTIFY_STARTSUBQUEUE,
  1159. FILEOP_DELETE,
  1160. Queue->DeleteNodeCount
  1161. );
  1162. if(!b) {
  1163. rc = GetLastError();
  1164. if(!rc) {
  1165. rc = ERROR_OPERATION_ABORTED;
  1166. }
  1167. goto clean0;
  1168. }
  1169. for(QueueNode=Queue->DeleteQueue; QueueNode; QueueNode=QueueNode->Next) {
  1170. //
  1171. // Form the full path of the file to be deleted.
  1172. //
  1173. FullTargetPath = pSetupFormFullPath(
  1174. Queue->StringTable,
  1175. QueueNode->TargetDirectory,
  1176. QueueNode->TargetFilename,
  1177. -1
  1178. );
  1179. if(!FullTargetPath) {
  1180. rc = ERROR_NOT_ENOUGH_MEMORY;
  1181. goto clean0;
  1182. }
  1183. //
  1184. // Backup the file we're about to delete
  1185. //
  1186. if((rc=pSetupDoLastKnownGoodBackup(Queue,
  1187. FullTargetPath,
  1188. LASTGOOD_OPERATION_DELETE,
  1189. NULL)) != NO_ERROR) {
  1190. MyFree(FullTargetPath);
  1191. goto clean0;
  1192. }
  1193. rc = pSetupCommitSingleBackup(Queue,
  1194. FullTargetPath,
  1195. QueueNode->TargetDirectory,
  1196. -1,
  1197. QueueNode->TargetFilename,
  1198. MsgHandler,
  1199. Context,
  1200. IsMsgHandlerNativeCharWidth,
  1201. FALSE,
  1202. &BackupInUse
  1203. );
  1204. if (rc != NO_ERROR) {
  1205. MyFree(FullTargetPath);
  1206. goto clean0;
  1207. }
  1208. FilePaths.Source = NULL;
  1209. FilePaths.Target = FullTargetPath;
  1210. FilePaths.Win32Error = NO_ERROR;
  1211. FilePaths.Flags = 0;
  1212. //
  1213. // Inform the callback that we are about to start a delete operation.
  1214. //
  1215. u = pSetupCallMsgHandler(
  1216. Queue->LogContext,
  1217. MsgHandler,
  1218. IsMsgHandlerNativeCharWidth,
  1219. Context,
  1220. SPFILENOTIFY_STARTDELETE,
  1221. (UINT_PTR)&FilePaths,
  1222. FILEOP_DELETE
  1223. );
  1224. if(u == FILEOP_ABORT) {
  1225. rc = GetLastError();
  1226. if(!rc) {
  1227. rc = ERROR_OPERATION_ABORTED;
  1228. }
  1229. MyFree(FullTargetPath);
  1230. goto clean0;
  1231. }
  1232. if(u == FILEOP_DOIT) {
  1233. //
  1234. // Attempt the delete. If it fails inform the callback,
  1235. // which may decide to abort, retry. or skip the file.
  1236. //
  1237. SetFileAttributes(FullTargetPath,FILE_ATTRIBUTE_NORMAL);
  1238. do {
  1239. if (BackupInUse) {
  1240. rc = ERROR_SHARING_VIOLATION;
  1241. } else {
  1242. rc = DeleteFile(FullTargetPath) ? NO_ERROR : GetLastError();
  1243. }
  1244. if((rc == ERROR_ACCESS_DENIED)
  1245. || (rc == ERROR_SHARING_VIOLATION)
  1246. || (rc == ERROR_USER_MAPPED_FILE)) {
  1247. //
  1248. // The file is probably in use.
  1249. //
  1250. if(QueueNode->InternalFlags & IQF_DELAYED_DELETE_OK) {
  1251. //
  1252. // Inf wanted delete on next reboot. Check to see if
  1253. // we're being asked to delete a protected system file.
  1254. // If so (and all the catalog nodes associated with the
  1255. // queue were OK), then we'll allow this to happen.
  1256. // Otherwise, we'll silently skip the deletion (and log
  1257. // it).
  1258. //
  1259. MYASSERT((Queue->Flags & FQF_DID_CATALOGS_OK) ||
  1260. (Queue->Flags & FQF_DID_CATALOGS_FAILED));
  1261. if(Queue->Flags & FQF_DID_CATALOGS_OK) {
  1262. QueueNode->InternalFlags |= INUSE_IN_USE;
  1263. TargetIsProtected = IsFileProtected(FullTargetPath,
  1264. Queue->LogContext,
  1265. NULL
  1266. );
  1267. if(b = PostDelayedMove(Queue,
  1268. FullTargetPath,
  1269. NULL,
  1270. -1,
  1271. TargetIsProtected)) {
  1272. //
  1273. // Tell the callback.
  1274. //
  1275. FilePaths.Source = NULL;
  1276. FilePaths.Target = FullTargetPath;
  1277. FilePaths.Win32Error = NO_ERROR;
  1278. FilePaths.Flags = FILEOP_DELETE;
  1279. pSetupCallMsgHandler(
  1280. Queue->LogContext,
  1281. MsgHandler,
  1282. IsMsgHandlerNativeCharWidth,
  1283. Context,
  1284. SPFILENOTIFY_FILEOPDELAYED,
  1285. (UINT_PTR)&FilePaths,
  1286. 0
  1287. );
  1288. }
  1289. } else {
  1290. //
  1291. // We're installing an unsigned package. Skip the
  1292. // delayed delete operation, and generate a log
  1293. // entry about this.
  1294. //
  1295. WriteLogEntry(Queue->LogContext,
  1296. SETUP_LOG_ERROR,
  1297. MSG_LOG_DELAYED_DELETE_SKIPPED_FOR_SFC,
  1298. NULL,
  1299. FullTargetPath
  1300. );
  1301. }
  1302. } else {
  1303. //
  1304. // Just skip this file.
  1305. //
  1306. b = TRUE;
  1307. }
  1308. rc = b ? NO_ERROR : GetLastError();
  1309. if(rc) {
  1310. WriteLogEntry(
  1311. Queue->LogContext,
  1312. SETUP_LOG_ERROR | SETUP_LOG_BUFFER,
  1313. MSG_LOG_DELAYDELETE_FILE_ERROR,
  1314. NULL,
  1315. FullTargetPath);
  1316. WriteLogError(Queue->LogContext,SETUP_LOG_ERROR,rc);
  1317. } else {
  1318. WriteLogEntry(
  1319. Queue->LogContext,
  1320. SETUP_LOG_INFO,
  1321. MSG_LOG_DELAYDELETED_FILE,
  1322. NULL,
  1323. FullTargetPath);
  1324. }
  1325. } else if(rc) {
  1326. WriteLogEntry(
  1327. Queue->LogContext,
  1328. DEL_ERR_LOG_LEVEL(rc) | SETUP_LOG_BUFFER,
  1329. MSG_LOG_DELETE_FILE_ERROR,
  1330. NULL,
  1331. FullTargetPath);
  1332. WriteLogError(Queue->LogContext,DEL_ERR_LOG_LEVEL(rc),rc);
  1333. } else {
  1334. WriteLogEntry(
  1335. Queue->LogContext,
  1336. SETUP_LOG_INFO,
  1337. MSG_LOG_DELETED_FILE,
  1338. NULL,
  1339. FullTargetPath);
  1340. }
  1341. #ifdef UNICODE
  1342. if( rc == NO_ERROR )
  1343. {
  1344. rc = pSetupCallSCE(
  1345. ST_SCE_DELETE,
  1346. FullTargetPath,
  1347. NULL,
  1348. NULL,
  1349. -1,
  1350. NULL
  1351. );
  1352. SetLastError( rc );
  1353. }
  1354. #endif
  1355. if(rc != NO_ERROR) {
  1356. FilePaths.Win32Error = rc;
  1357. u = pSetupCallMsgHandler(
  1358. Queue->LogContext,
  1359. MsgHandler,
  1360. IsMsgHandlerNativeCharWidth,
  1361. Context,
  1362. SPFILENOTIFY_DELETEERROR,
  1363. (UINT_PTR)&FilePaths,
  1364. 0
  1365. );
  1366. if(u == FILEOP_ABORT) {
  1367. rc = GetLastError();
  1368. if(!rc) {
  1369. rc = ERROR_OPERATION_ABORTED;
  1370. }
  1371. MyFree(FullTargetPath);
  1372. goto clean0;
  1373. }
  1374. if(u == FILEOP_SKIP) {
  1375. break;
  1376. }
  1377. }
  1378. } while(rc != NO_ERROR);
  1379. } else {
  1380. rc = NO_ERROR;
  1381. }
  1382. FilePaths.Win32Error = rc;
  1383. pSetupCallMsgHandler(
  1384. Queue->LogContext,
  1385. MsgHandler,
  1386. IsMsgHandlerNativeCharWidth,
  1387. Context,
  1388. SPFILENOTIFY_ENDDELETE,
  1389. (UINT_PTR)&FilePaths,
  1390. 0
  1391. );
  1392. MyFree(FullTargetPath);
  1393. }
  1394. pSetupCallMsgHandler(
  1395. Queue->LogContext,
  1396. MsgHandler,
  1397. IsMsgHandlerNativeCharWidth,
  1398. Context,
  1399. SPFILENOTIFY_ENDSUBQUEUE,
  1400. FILEOP_DELETE,
  1401. 0
  1402. );
  1403. rc = NO_ERROR;
  1404. clean0:
  1405. SetLastError(rc);
  1406. return rc;
  1407. }
  1408. DWORD
  1409. pCommitRenameQueue(
  1410. IN PSP_FILE_QUEUE Queue,
  1411. IN PVOID MsgHandler,
  1412. IN PVOID Context,
  1413. IN BOOL IsMsgHandlerNativeCharWidth
  1414. )
  1415. /*++
  1416. Routine Description:
  1417. Process the rename Queue
  1418. Rename each file specified in the queue
  1419. Files are backed up before they are renamed (if not already backed up)
  1420. If the target exists, it is also backed up (if not already backed up)
  1421. Performance: this can get optimized by treating the newly named files
  1422. as a backup
  1423. See also pCommitBackupQueue, pCommitDeleteQueue and pCommitCopyQueue
  1424. Arguments:
  1425. Queue - queue that contains the rename sub-queue
  1426. MsgHandler - Supplies a callback routine to be notified
  1427. of various significant events in the queue processing.
  1428. Context - Supplies a value that is passed to the MsgHandler
  1429. callback function.
  1430. IsMsgHandlerNativeCharWidth - For Unicode/Ansi support
  1431. Return Value:
  1432. DWORD indicating status or success
  1433. --*/
  1434. {
  1435. PSP_FILE_QUEUE_NODE QueueNode,queueNode;
  1436. UINT u;
  1437. BOOL b;
  1438. DWORD rc;
  1439. PCTSTR FullTargetPath;
  1440. PCTSTR FullSourcePath;
  1441. FILEPATHS FilePaths;
  1442. BOOL BackupInUse = FALSE;
  1443. BOOL TargetIsProtected;
  1444. MYASSERT(Queue->RenameNodeCount);
  1445. b = pSetupCallMsgHandler(
  1446. Queue->LogContext,
  1447. MsgHandler,
  1448. IsMsgHandlerNativeCharWidth,
  1449. Context,
  1450. SPFILENOTIFY_STARTSUBQUEUE,
  1451. FILEOP_RENAME,
  1452. Queue->RenameNodeCount
  1453. );
  1454. if(!b) {
  1455. rc = GetLastError();
  1456. if(!rc) {
  1457. rc = ERROR_OPERATION_ABORTED;
  1458. }
  1459. goto clean0;
  1460. }
  1461. for(QueueNode=Queue->RenameQueue; QueueNode; QueueNode=QueueNode->Next) {
  1462. //
  1463. // Form the full source path of the file to be renamed.
  1464. //
  1465. FullSourcePath = pSetupFormFullPath(
  1466. Queue->StringTable,
  1467. QueueNode->SourcePath,
  1468. QueueNode->SourceFilename,
  1469. -1
  1470. );
  1471. if(!FullSourcePath) {
  1472. rc = ERROR_NOT_ENOUGH_MEMORY;
  1473. goto clean0;
  1474. }
  1475. //
  1476. // Form the full target path of the file to be renamed.
  1477. //
  1478. FullTargetPath = pSetupFormFullPath(
  1479. Queue->StringTable,
  1480. QueueNode->TargetDirectory == -1 ? QueueNode->SourcePath : QueueNode->TargetDirectory,
  1481. QueueNode->TargetFilename,
  1482. -1
  1483. );
  1484. if(!FullTargetPath) {
  1485. MyFree(FullSourcePath);
  1486. rc = ERROR_NOT_ENOUGH_MEMORY;
  1487. goto clean0;
  1488. }
  1489. //
  1490. // Backup the file we may be overwriting
  1491. //
  1492. if((rc=pSetupDoLastKnownGoodBackup(Queue,
  1493. FullTargetPath,
  1494. 0,
  1495. NULL)) != NO_ERROR) {
  1496. MyFree(FullSourcePath);
  1497. MyFree(FullTargetPath);
  1498. goto clean0;
  1499. }
  1500. rc = pSetupCommitSingleBackup(Queue,
  1501. FullTargetPath,
  1502. QueueNode->TargetDirectory == -1 ? QueueNode->SourcePath : QueueNode->TargetDirectory,
  1503. -1, // we don't use this
  1504. QueueNode->TargetFilename,
  1505. MsgHandler,
  1506. Context,
  1507. IsMsgHandlerNativeCharWidth,
  1508. FALSE,
  1509. &BackupInUse
  1510. );
  1511. if (rc != NO_ERROR) {
  1512. MyFree(FullSourcePath);
  1513. MyFree(FullTargetPath);
  1514. goto clean0;
  1515. }
  1516. //
  1517. // Backup the file we're about to rename
  1518. //
  1519. if((rc=pSetupDoLastKnownGoodBackup(Queue,
  1520. FullSourcePath,
  1521. LASTGOOD_OPERATION_DELETE,
  1522. NULL)) != NO_ERROR) {
  1523. MyFree(FullSourcePath);
  1524. MyFree(FullTargetPath);
  1525. goto clean0;
  1526. }
  1527. rc = pSetupCommitSingleBackup(Queue,
  1528. FullSourcePath,
  1529. QueueNode->SourcePath,
  1530. -1, // we don't use this????
  1531. QueueNode->SourceFilename,
  1532. MsgHandler,
  1533. Context,
  1534. IsMsgHandlerNativeCharWidth,
  1535. FALSE,
  1536. &b
  1537. );
  1538. if (rc != NO_ERROR) {
  1539. MyFree(FullSourcePath);
  1540. MyFree(FullTargetPath);
  1541. goto clean0;
  1542. }
  1543. if (b) {
  1544. //
  1545. // BackupInUse is the "OR" of the two backup In-Use flags
  1546. //
  1547. BackupInUse = TRUE;
  1548. }
  1549. FilePaths.Source = FullSourcePath;
  1550. FilePaths.Target = FullTargetPath;
  1551. FilePaths.Win32Error = NO_ERROR;
  1552. //
  1553. // Inform the callback that we are about to start a rename operation.
  1554. //
  1555. u = pSetupCallMsgHandler(
  1556. Queue->LogContext,
  1557. MsgHandler,
  1558. IsMsgHandlerNativeCharWidth,
  1559. Context,
  1560. SPFILENOTIFY_STARTRENAME,
  1561. (UINT_PTR)&FilePaths,
  1562. FILEOP_RENAME
  1563. );
  1564. if(u == FILEOP_ABORT) {
  1565. rc = GetLastError();
  1566. if(!rc) {
  1567. rc = ERROR_OPERATION_ABORTED;
  1568. }
  1569. MyFree(FullSourcePath);
  1570. MyFree(FullTargetPath);
  1571. goto clean0;
  1572. }
  1573. if(u == FILEOP_DOIT) {
  1574. //
  1575. // Attempt the rename. If it fails inform the callback,
  1576. // which may decide to abort, retry. or skip the file.
  1577. //
  1578. do {
  1579. if (BackupInUse) {
  1580. //
  1581. // backup is in use, must delay op. Check to see if either
  1582. // the source or target files are protected system files.
  1583. // If so (and all the catalog nodes associated with the
  1584. // queue were OK), then we'll allos this to happen.
  1585. // Otherwise, we'll silently fail the rename (and log it).
  1586. //
  1587. MYASSERT((Queue->Flags & FQF_DID_CATALOGS_OK) ||
  1588. (Queue->Flags & FQF_DID_CATALOGS_FAILED));
  1589. if(Queue->Flags & FQF_DID_CATALOGS_OK) {
  1590. TargetIsProtected = IsFileProtected(FullSourcePath,
  1591. Queue->LogContext,
  1592. NULL
  1593. );
  1594. if(!TargetIsProtected) {
  1595. TargetIsProtected = IsFileProtected(FullTargetPath,
  1596. Queue->LogContext,
  1597. NULL
  1598. );
  1599. }
  1600. if(b = PostDelayedMove(Queue,
  1601. FullSourcePath,
  1602. FullTargetPath,
  1603. -1,
  1604. TargetIsProtected)) {
  1605. rc = NO_ERROR;
  1606. }
  1607. else
  1608. {
  1609. rc = GetLastError();
  1610. }
  1611. if(rc) {
  1612. WriteLogEntry(
  1613. Queue->LogContext,
  1614. DEL_ERR_LOG_LEVEL(rc) | SETUP_LOG_BUFFER,
  1615. MSG_LOG_DELAYRENAME_FILE_ERROR,
  1616. NULL,
  1617. FullSourcePath,
  1618. FullTargetPath);
  1619. WriteLogError(Queue->LogContext,DEL_ERR_LOG_LEVEL(rc),rc);
  1620. } else {
  1621. WriteLogEntry(
  1622. Queue->LogContext,
  1623. SETUP_LOG_INFO,
  1624. MSG_LOG_DELAYRENAMED_FILE,
  1625. NULL,
  1626. FullSourcePath,
  1627. FullTargetPath);
  1628. }
  1629. } else {
  1630. //
  1631. // We're installing an unsigned package. Skip the
  1632. // delayed rename operation, and generate a log
  1633. // entry about this.
  1634. //
  1635. WriteLogEntry(Queue->LogContext,
  1636. SETUP_LOG_ERROR,
  1637. MSG_LOG_DELAYED_MOVE_SKIPPED_FOR_SFC,
  1638. NULL,
  1639. FullTargetPath
  1640. );
  1641. //
  1642. // act as if no error occurred.
  1643. //
  1644. rc = NO_ERROR;
  1645. }
  1646. } else {
  1647. rc = MoveFile(FullSourcePath,FullTargetPath) ? NO_ERROR : GetLastError();
  1648. if(rc) {
  1649. WriteLogEntry(
  1650. Queue->LogContext,
  1651. DEL_ERR_LOG_LEVEL(rc) | SETUP_LOG_BUFFER,
  1652. MSG_LOG_RENAME_FILE_ERROR,
  1653. NULL,
  1654. FullSourcePath,
  1655. FullTargetPath);
  1656. WriteLogError(Queue->LogContext,DEL_ERR_LOG_LEVEL(rc),rc);
  1657. } else {
  1658. WriteLogEntry(
  1659. Queue->LogContext,
  1660. SETUP_LOG_INFO,
  1661. MSG_LOG_RENAMED_FILE,
  1662. NULL,
  1663. FullSourcePath,
  1664. FullTargetPath);
  1665. }
  1666. }
  1667. #ifdef UNICODE
  1668. if( rc == NO_ERROR )
  1669. {
  1670. rc = pSetupCallSCE(
  1671. ST_SCE_RENAME,
  1672. FullSourcePath,
  1673. NULL,
  1674. FullTargetPath,
  1675. -1,
  1676. NULL
  1677. );
  1678. SetLastError( rc );
  1679. }
  1680. #endif
  1681. if((rc == ERROR_FILE_NOT_FOUND) || (rc == ERROR_PATH_NOT_FOUND)) {
  1682. rc = NO_ERROR;
  1683. }
  1684. if(rc != NO_ERROR) {
  1685. FilePaths.Win32Error = rc;
  1686. u = pSetupCallMsgHandler(
  1687. Queue->LogContext,
  1688. MsgHandler,
  1689. IsMsgHandlerNativeCharWidth,
  1690. Context,
  1691. SPFILENOTIFY_RENAMEERROR,
  1692. (UINT_PTR)&FilePaths,
  1693. 0
  1694. );
  1695. if(u == FILEOP_ABORT) {
  1696. rc = GetLastError();
  1697. if(!rc) {
  1698. rc = ERROR_OPERATION_ABORTED;
  1699. }
  1700. MyFree(FullSourcePath);
  1701. MyFree(FullTargetPath);
  1702. goto clean0;
  1703. }
  1704. if(u == FILEOP_SKIP) {
  1705. break;
  1706. }
  1707. }
  1708. } while(rc != NO_ERROR);
  1709. } else {
  1710. rc = NO_ERROR;
  1711. }
  1712. FilePaths.Win32Error = rc;
  1713. pSetupCallMsgHandler(
  1714. Queue->LogContext,
  1715. MsgHandler,
  1716. IsMsgHandlerNativeCharWidth,
  1717. Context,
  1718. SPFILENOTIFY_ENDRENAME,
  1719. (UINT_PTR)&FilePaths,
  1720. 0
  1721. );
  1722. MyFree(FullSourcePath);
  1723. MyFree(FullTargetPath);
  1724. }
  1725. pSetupCallMsgHandler(
  1726. Queue->LogContext,
  1727. MsgHandler,
  1728. IsMsgHandlerNativeCharWidth,
  1729. Context,
  1730. SPFILENOTIFY_ENDSUBQUEUE,
  1731. FILEOP_RENAME,
  1732. 0
  1733. );
  1734. rc = NO_ERROR;
  1735. clean0:
  1736. SetLastError(rc);
  1737. return rc;
  1738. }
  1739. DWORD
  1740. pCommitCopyQueue(
  1741. IN PSP_FILE_QUEUE Queue,
  1742. IN PVOID MsgHandler,
  1743. IN PVOID Context,
  1744. IN BOOL IsMsgHandlerNativeCharWidth
  1745. )
  1746. /*++
  1747. Routine Description:
  1748. Process the copy sub-Queues
  1749. Copy each file specified in the sub-queues
  1750. Files are backed up before they are overwritten (if not already backed up)
  1751. See also pCommitBackupQueue, pCommitDeleteQueue and pCommitRenameQueue
  1752. Arguments:
  1753. Queue - queue that contains the copy sub-queues
  1754. MsgHandler - Supplies a callback routine to be notified
  1755. of various significant events in the queue processing.
  1756. Context - Supplies a value that is passed to the MsgHandler
  1757. callback function.
  1758. IsMsgHandlerNativeCharWidth - For Unicode/Ansi support
  1759. Return Value:
  1760. DWORD indicating status or success
  1761. --*/
  1762. {
  1763. PSOURCE_MEDIA_INFO SourceMediaInfo;
  1764. SOURCE_MEDIA SourceMedia;
  1765. PTCHAR p, temp;
  1766. UINT SourcePathLen;
  1767. UINT u;
  1768. DWORD rc;
  1769. Q_CAB_CB_DATA QData;
  1770. BOOL b;
  1771. BOOL FirstIteration;
  1772. PSP_FILE_QUEUE_NODE QueueNode,queueNode;
  1773. TCHAR UserSourceRoot[MAX_PATH];
  1774. TCHAR UserSourcePath[MAX_PATH];
  1775. TCHAR FullSourcePath[MAX_PATH];
  1776. TCHAR UserOverride[MAX_PATH];
  1777. LPCTSTR RestorePath = NULL;
  1778. UINT DriveType;
  1779. BOOL IsRemovable, AnyProcessed, AnyNotProcessed, SkipMedia;
  1780. BOOL SpecialMedia = FALSE;
  1781. BOOL LocateCab;
  1782. PCTSTR MediaRoot;
  1783. DWORD MediaLogTag;
  1784. LONG Cabfile;
  1785. LONG Tagfile;
  1786. //
  1787. // The caller is supposed to skip calling us if there are no files
  1788. // to be copied.
  1789. //
  1790. MYASSERT(Queue->CopyNodeCount);
  1791. //
  1792. // Inform the callback that we are starting.
  1793. //
  1794. b = pSetupCallMsgHandler(
  1795. Queue->LogContext,
  1796. MsgHandler,
  1797. IsMsgHandlerNativeCharWidth,
  1798. Context,
  1799. SPFILENOTIFY_STARTSUBQUEUE,
  1800. FILEOP_COPY,
  1801. Queue->CopyNodeCount
  1802. );
  1803. if(!b) {
  1804. rc = GetLastError();
  1805. if(!rc) {
  1806. rc = ERROR_OPERATION_ABORTED;
  1807. }
  1808. return(rc);
  1809. }
  1810. if(Queue->RestorePathID != -1) {
  1811. RestorePath = pSetupStringTableStringFromId(Queue->StringTable, Queue->RestorePathID);
  1812. DiskPromptGetDriveType(RestorePath, &DriveType, &IsRemovable);
  1813. if(IsRemovable) {
  1814. //
  1815. // do not allow restore from removable media
  1816. //
  1817. RestorePath = NULL;
  1818. }
  1819. }
  1820. //
  1821. // Initially, no user-specified override path exists.
  1822. //
  1823. UserSourceRoot[0] = TEXT('\0');
  1824. UserSourcePath[0] = TEXT('\0');
  1825. //
  1826. // The outermost loop iterates through all the source media descriptors.
  1827. //
  1828. for(SourceMediaInfo=Queue->SourceMediaList; SourceMediaInfo; SourceMediaInfo=SourceMediaInfo->Next) {
  1829. //
  1830. // If there are no files on this particular media, skip it.
  1831. // Otherwise get pointer to queue node for first file on this media.
  1832. //
  1833. if(!SourceMediaInfo->CopyNodeCount) {
  1834. continue;
  1835. }
  1836. MYASSERT(SourceMediaInfo->CopyQueue);
  1837. //
  1838. // if last media was special media (see long discussion above),
  1839. // then forget about any user override
  1840. //
  1841. if (SpecialMedia) {
  1842. UserSourceRoot[0] = TEXT('\0');
  1843. UserSourcePath[0] = TEXT('\0');
  1844. SpecialMedia = FALSE;
  1845. }
  1846. //
  1847. // see if this media is special media
  1848. //
  1849. if (SourceMediaInfo->Flags & ( SMI_FLAG_USE_SVCPACK_SOURCE_ROOT_PATH |
  1850. SMI_FLAG_USE_LOCAL_SOURCE_CAB ) ) {
  1851. SpecialMedia = TRUE;
  1852. }
  1853. //
  1854. // If we're in restore-mode
  1855. // we've been given a directory to restore from
  1856. // ignore the media root, and use restore-point root
  1857. // restore as many files as we can
  1858. //
  1859. // note, we check for file presence via FileExists
  1860. // rather than trying to determine file name
  1861. // since we'll always backup in uncompressed form
  1862. // with same name as listed in [SourceDisksNames]
  1863. //
  1864. if(RestorePath) {
  1865. //
  1866. // Restore Symantics - prior to prompting for media, see
  1867. // if we can restore backup
  1868. //
  1869. QueueNode = NULL;
  1870. for(queueNode = SourceMediaInfo->CopyQueue;
  1871. queueNode;
  1872. queueNode=queueNode->Next) {
  1873. pSetupBuildSourceForCopy(
  1874. RestorePath,
  1875. NULL,
  1876. SourceMediaInfo->SourceRootPath,
  1877. Queue,
  1878. queueNode,
  1879. FullSourcePath
  1880. );
  1881. //
  1882. // don't allow alternate sourcenames in this case
  1883. //
  1884. if(FileExists(FullSourcePath,NULL)) {
  1885. //
  1886. // backup exists, copy it
  1887. //
  1888. rc = pSetupCopySingleQueuedFile(
  1889. Queue,
  1890. queueNode,
  1891. FullSourcePath,
  1892. MsgHandler,
  1893. Context,
  1894. UserOverride,
  1895. IsMsgHandlerNativeCharWidth,
  1896. SP_COPY_ALREADYDECOMP // backup already decomp'd.
  1897. );
  1898. if(rc == NO_ERROR) {
  1899. //
  1900. // we restored this file through backup
  1901. // carry on to next file
  1902. //
  1903. queueNode->InternalFlags |= IQF_PROCESSED;
  1904. continue;
  1905. }
  1906. //
  1907. // we know backup existed so if this failed
  1908. // consider it major enough to abort restore
  1909. // (eg, file unsigned, user specified abort)
  1910. //
  1911. SetLastError(rc);
  1912. return(rc);
  1913. }
  1914. if(!QueueNode) {
  1915. //
  1916. // first problematic file
  1917. //
  1918. QueueNode = queueNode;
  1919. }
  1920. }
  1921. if(!QueueNode) {
  1922. //
  1923. // we copied all files of this media from backup
  1924. // carry on to next media
  1925. //
  1926. continue;
  1927. }
  1928. } else {
  1929. //
  1930. // not restoring, start at first file
  1931. //
  1932. QueueNode = SourceMediaInfo->CopyQueue;
  1933. }
  1934. //
  1935. // We will need to prompt for media, which requires some preparation.
  1936. // We need to get the first file in the queue for this media, because
  1937. // its path is where we will expect to find it or its cabinet or tag
  1938. // file. If there is no tag file, then we will look for the file
  1939. // itself.
  1940. //
  1941. FirstIteration = TRUE;
  1942. SkipMedia = FALSE;
  1943. LocateCab = FALSE;
  1944. Tagfile = SourceMediaInfo->Tagfile;
  1945. Cabfile = SourceMediaInfo->Cabfile;
  1946. RepromptMedia:
  1947. //
  1948. // The case where we have non-removeable media and the path was
  1949. // previously overridden must be handled specially. For example, we
  1950. // could have files queued on the same source root but different
  1951. // subdirs. If the user changes the network location, for example,
  1952. // we have to be careful or we'll ignore the change in subdirectories
  1953. // as we move among the media.
  1954. //
  1955. // To work around this, we check on non-removable media to see if the
  1956. // queue node we're presently working with is in a subdirectory. If it
  1957. // is, then we reset our UserSourcePath string.
  1958. //
  1959. // (andrewr)...I don't get this comment above. The current code
  1960. // iterates through each source media info structure, which doesn't include
  1961. // subdirectory information, only source root path information. If it
  1962. // does, then the caller is doing something really wierd, since they
  1963. // should be using the SourcePath to define subdirectories from one master
  1964. // root.
  1965. //
  1966. // It appears that the reasoning behind the code below is as follows:
  1967. //
  1968. // The assumption is that if we have removable media and multiple source
  1969. // paths, then we will have to swap media out of the drive. We don't
  1970. // override source root paths if we are dealing with removable media.
  1971. // If the source root path is non removable, then all of the source media
  1972. // is "tied together." If the user overrides the source root path, then
  1973. // we override subsequent fixed media source root paths.
  1974. //
  1975. // In the case of dealing with service pack source media or a local cab-file
  1976. // drivers cache, the source media info for a queue will not be tied together,
  1977. // even though we're dealing with fixed media.
  1978. //
  1979. // To reconcile the comments above and the reasoning it uses with the
  1980. // contradiction that svc pack media imposes, we have 2 options:
  1981. //
  1982. // 1. If we encounter flags that indicate one of our special cases, then don't
  1983. // use any user override for the new source media. (or, put another way,
  1984. // if we know that the last media was actually one of these special media,
  1985. // then don't allow an override of the normal media.
  1986. //
  1987. // 2. Introduce some sort of hueristic that determines if the prior source media
  1988. // and the current source media are similar. If they are, then go ahead and
  1989. // use any user specified override, otherwise use the proper path.
  1990. //
  1991. //
  1992. // For simplicities sake, I use approach 1 above. This is made a little simpler
  1993. // by following the following rule. When adding source media to the media list,
  1994. // insert special media (ie, has flags identifying the media as svc pack media)
  1995. // at the head of the list, insert normal media after that. By following this
  1996. // approach we know that we can just "zero out" the user overrides for the special
  1997. // media and we'll just do the right thing for the regular media.
  1998. //
  1999. // In the case where there is an explicit cab-file to use
  2000. // then we ask the user to point to cab-file instead of source file (first iteration)
  2001. //
  2002. MediaRoot = *UserSourceRoot
  2003. ? UserSourceRoot
  2004. : pSetupStringTableStringFromId(Queue->StringTable, SourceMediaInfo->SourceRootPath);
  2005. DiskPromptGetDriveType(MediaRoot, &DriveType, &IsRemovable);
  2006. if(!IsRemovable && (QueueNode->SourcePath != -1)) {
  2007. *UserSourcePath = TEXT('\0');
  2008. }
  2009. pSetupBuildSourceForCopy(
  2010. UserSourceRoot,
  2011. UserSourcePath,
  2012. SourceMediaInfo->SourceRootPath,
  2013. Queue,
  2014. QueueNode,
  2015. FullSourcePath
  2016. );
  2017. if (FirstIteration
  2018. && (Tagfile != Cabfile)
  2019. && (Cabfile != -1)) {
  2020. MYASSERT(!SkipMedia);
  2021. MYASSERT(!(SourceMediaInfo->Flags & SMI_FLAG_USE_LOCAL_SOURCE_CAB));
  2022. //
  2023. // build location of cab file
  2024. //
  2025. temp = _tcsrchr(FullSourcePath,TEXT('\\'));
  2026. MYASSERT( temp );
  2027. if(temp) {
  2028. *(temp+1) = 0;
  2029. } else {
  2030. FullSourcePath[0] = 0;
  2031. }
  2032. //
  2033. // obtain path of (potential) cab file
  2034. //
  2035. pSetupConcatenatePaths( FullSourcePath, pSetupStringTableStringFromId(Queue->StringTable,Cabfile), MAX_PATH, NULL );
  2036. LocateCab = TRUE;
  2037. } else {
  2038. LocateCab = FALSE;
  2039. }
  2040. if((p = _tcsrchr(FullSourcePath,TEXT('\\')))!=NULL) {
  2041. *p++ = TEXT('\0');
  2042. } else {
  2043. //
  2044. // I'm being pedantic here, this should never happen
  2045. //
  2046. MYASSERT(p);
  2047. p = FullSourcePath;
  2048. }
  2049. //
  2050. // Now FullSourcePath has the path part and p has the file part
  2051. // for the first file in the queue for this media (or explicit cab file)
  2052. // Get the media in the drive by calling the callback function.
  2053. //
  2054. // Although it would be nice to not have to
  2055. // call this callback if we know that we don't have to (there is media
  2056. // where the caller said there should be (local media, media already in, etc.)
  2057. // we do need to call this so that we afford the caller the luxury of
  2058. // changing their mind one last time.
  2059. //
  2060. // the only exception to this rule is if we are using the local driver
  2061. // cache cab-file. In this case, we don't want the user to ever get
  2062. // prompted for this file, so we skip any media prompting. We know that
  2063. // if we have media added that has this flag set, then the cab already exists
  2064. // and we can just use it (otherwise we wouldn't have initialized it in the
  2065. // first place, we'd just use the os source path!)
  2066. //
  2067. SourceMedia.Tagfile = (Tagfile != -1 && FirstIteration)
  2068. ? pSetupStringTableStringFromId(
  2069. Queue->StringTable,
  2070. Tagfile
  2071. )
  2072. : NULL;
  2073. SourceMedia.Description = (SourceMediaInfo->Description != -1)
  2074. ? pSetupStringTableStringFromId(
  2075. Queue->StringTable,
  2076. SourceMediaInfo->DescriptionDisplayName
  2077. )
  2078. : NULL;
  2079. SourceMedia.SourcePath = FullSourcePath;
  2080. SourceMedia.SourceFile = p;
  2081. SourceMedia.Flags = (QueueNode->StyleFlags & (SP_COPY_NOSKIP | SP_COPY_WARNIFSKIP | SP_COPY_NOBROWSE));
  2082. MediaLogTag = AllocLogInfoSlotOrLevel(Queue->LogContext,SETUP_LOG_INFO,FALSE);
  2083. WriteLogEntry(
  2084. Queue->LogContext,
  2085. MediaLogTag,
  2086. MSG_LOG_NEEDMEDIA,
  2087. NULL,
  2088. SourceMedia.Tagfile ? SourceMedia.Tagfile : TEXT(""),
  2089. SourceMedia.Description ? SourceMedia.Description : TEXT(""),
  2090. SourceMedia.SourcePath ? SourceMedia.SourcePath : TEXT(""),
  2091. SourceMedia.SourceFile ? SourceMedia.SourceFile : TEXT(""),
  2092. SourceMedia.Flags
  2093. );
  2094. if( SkipMedia || (FirstIteration && (SourceMediaInfo->Flags & SMI_FLAG_USE_LOCAL_SOURCE_CAB)) ) {
  2095. u = FILEOP_DOIT;
  2096. WriteLogEntry(
  2097. Queue->LogContext,
  2098. SETUP_LOG_VERBOSE,
  2099. MSG_LOG_NEEDMEDIA_AUTOSKIP,
  2100. NULL
  2101. );
  2102. } else {
  2103. u = pSetupCallMsgHandler(
  2104. Queue->LogContext,
  2105. MsgHandler,
  2106. IsMsgHandlerNativeCharWidth,
  2107. Context,
  2108. SPFILENOTIFY_NEEDMEDIA,
  2109. (UINT_PTR)&SourceMedia,
  2110. (UINT_PTR)UserOverride
  2111. );
  2112. }
  2113. if(u == FILEOP_ABORT) {
  2114. rc = GetLastError();
  2115. if(!rc) {
  2116. rc = ERROR_OPERATION_ABORTED;
  2117. }
  2118. WriteLogEntry(
  2119. Queue->LogContext,
  2120. SETUP_LOG_ERROR|SETUP_LOG_BUFFER,
  2121. MSG_LOG_NEEDMEDIA_ABORT,
  2122. NULL);
  2123. WriteLogError(Queue->LogContext,
  2124. SETUP_LOG_ERROR,
  2125. rc
  2126. );
  2127. ReleaseLogInfoSlot(Queue->LogContext,MediaLogTag);
  2128. MediaLogTag = 0;
  2129. SetLastError(rc);
  2130. return(rc);
  2131. }
  2132. if(u == FILEOP_SKIP) {
  2133. //
  2134. // If this file was a bootfile replacement, then we need to restore
  2135. // the original file that was renamed to a temporary filename.
  2136. //
  2137. WriteLogEntry(
  2138. Queue->LogContext,
  2139. SETUP_LOG_WARNING,
  2140. MSG_LOG_NEEDMEDIA_SKIP,
  2141. NULL
  2142. );
  2143. ReleaseLogInfoSlot(Queue->LogContext,MediaLogTag);
  2144. MediaLogTag = 0;
  2145. if(QueueNode->StyleFlags & SP_COPY_REPLACE_BOOT_FILE) {
  2146. RestoreBootReplacedFile(Queue, QueueNode);
  2147. }
  2148. //
  2149. // If there are more files on this media, then try another one.
  2150. // Otherwise we're done with this media.
  2151. //
  2152. QueueNode->InternalFlags |= IQF_PROCESSED;
  2153. for(QueueNode=QueueNode->Next; QueueNode; QueueNode=QueueNode->Next) {
  2154. if(!(QueueNode->InternalFlags & IQF_PROCESSED)) {
  2155. FirstIteration = FALSE;
  2156. goto RepromptMedia;
  2157. }
  2158. }
  2159. continue;
  2160. }
  2161. if(u == FILEOP_NEWPATH) {
  2162. //
  2163. // User gave us a new source path. See which parts of the new path
  2164. // match the existing path/overrides we are using.
  2165. //
  2166. WriteLogEntry(
  2167. Queue->LogContext,
  2168. SETUP_LOG_INFO,
  2169. MSG_LOG_NEEDMEDIA_NEWPATH,
  2170. NULL,
  2171. UserOverride
  2172. );
  2173. ReleaseLogInfoSlot(Queue->LogContext,MediaLogTag);
  2174. MediaLogTag = 0;
  2175. pSetupSetPathOverrides(
  2176. Queue->StringTable,
  2177. UserSourceRoot,
  2178. UserSourcePath,
  2179. SourceMediaInfo->SourceRootPath,
  2180. QueueNode->SourcePath,
  2181. UserOverride
  2182. );
  2183. }
  2184. //
  2185. // logging specific stuff
  2186. //
  2187. if(MediaLogTag!=0) {
  2188. //
  2189. // we explicitly cleared MediaLogTag for each case we handled
  2190. //
  2191. if (u != FILEOP_DOIT) {
  2192. WriteLogEntry(
  2193. Queue->LogContext,
  2194. SETUP_LOG_WARNING,
  2195. MSG_LOG_NEEDMEDIA_BADRESULT,
  2196. NULL,
  2197. u);
  2198. }
  2199. ReleaseLogInfoSlot(Queue->LogContext,MediaLogTag);
  2200. MediaLogTag = 0;
  2201. }
  2202. //
  2203. // If we get here, the media is now accessible.
  2204. // Some or all of the files might be in a cabinet whose name is the tagfile.
  2205. //
  2206. // NOTE: Win95 used the tagfile field to be the cabinet name instead.
  2207. // If present it is used as a tagfile of sorts. The absence of a tagfile
  2208. // means the files are not in cabinets. For NT, we don't bother
  2209. // with all of this but instead try to be a little smarter.
  2210. //
  2211. // Scan the media for all source files we expect to find on it.
  2212. // If we find a file, process it. Later we hit the cabinet and only
  2213. // process the files we didn't already find outside the cabinet.
  2214. //
  2215. // exception to this is "explicit cabinet"
  2216. //
  2217. if(LocateCab) {
  2218. //
  2219. // an explicit cabinet was specified
  2220. // this is first iteration
  2221. // we've gone through NEED_MEDIA to obtain disk for this cabinet
  2222. // don't try to process files outside cabinet
  2223. // we know there is at least one file not processed
  2224. //
  2225. b = TRUE;
  2226. queueNode=QueueNode;
  2227. } else {
  2228. //
  2229. // tagfile may also be a cabfile
  2230. // but process all files outside the cabfile first
  2231. //
  2232. for(queueNode=QueueNode; queueNode; queueNode=queueNode->Next) {
  2233. if(queueNode->InternalFlags & IQF_PROCESSED) {
  2234. //
  2235. // Already processed. Skip to next file.
  2236. //
  2237. continue;
  2238. }
  2239. pSetupBuildSourceForCopy(
  2240. UserSourceRoot,
  2241. UserSourcePath,
  2242. SourceMediaInfo->SourceRootPath,
  2243. Queue,
  2244. queueNode,
  2245. FullSourcePath
  2246. );
  2247. rc = SetupDetermineSourceFileName(FullSourcePath,&b,&p,NULL);
  2248. if(rc == NO_ERROR || SkipMedia) {
  2249. //
  2250. // Found the file outside a cabinet. Process it now.
  2251. //
  2252. if(rc == NO_ERROR) {
  2253. rc = pSetupCopySingleQueuedFile(
  2254. Queue,
  2255. queueNode,
  2256. p,
  2257. MsgHandler,
  2258. Context,
  2259. UserOverride,
  2260. IsMsgHandlerNativeCharWidth,
  2261. 0
  2262. );
  2263. MyFree(p);
  2264. } else {
  2265. //
  2266. // We didn't find the source file, but we're going to try
  2267. // to copy it anyway since we've decided not to skip the
  2268. // prompt for media.
  2269. //
  2270. rc = pSetupCopySingleQueuedFile(
  2271. Queue,
  2272. queueNode,
  2273. FullSourcePath,
  2274. MsgHandler,
  2275. Context,
  2276. UserOverride,
  2277. IsMsgHandlerNativeCharWidth,
  2278. 0
  2279. );
  2280. }
  2281. if(rc != NO_ERROR) {
  2282. return(rc);
  2283. }
  2284. //
  2285. // See if we have a new source path.
  2286. //
  2287. if(UserOverride[0]) {
  2288. pSetupSetPathOverrides(
  2289. Queue->StringTable,
  2290. UserSourceRoot,
  2291. UserSourcePath,
  2292. SourceMediaInfo->SourceRootPath,
  2293. queueNode->SourcePath,
  2294. UserOverride
  2295. );
  2296. }
  2297. }
  2298. }
  2299. //
  2300. // See if any files still need to be processed.
  2301. //
  2302. for(b=FALSE,queueNode=QueueNode; queueNode; queueNode=queueNode->Next) {
  2303. if(!(queueNode->InternalFlags & IQF_PROCESSED)) {
  2304. b = TRUE;
  2305. break;
  2306. }
  2307. }
  2308. }
  2309. //
  2310. // If any files still need to be processed and we have a potential
  2311. // cabinet file, go try to extract them from a cabinet.
  2312. //
  2313. if(b && (Cabfile != -1) && FirstIteration) {
  2314. pSetupBuildSourceForCopy(
  2315. UserSourceRoot,
  2316. UserSourcePath,
  2317. SourceMediaInfo->SourceRootPath,
  2318. Queue,
  2319. queueNode,
  2320. FullSourcePath
  2321. );
  2322. temp = _tcsrchr(FullSourcePath,TEXT('\\'));
  2323. MYASSERT( temp );
  2324. if(temp) {
  2325. *(temp+1) = 0;
  2326. }
  2327. //
  2328. // obtain path of (potential) cab file
  2329. //
  2330. pSetupConcatenatePaths( FullSourcePath, pSetupStringTableStringFromId(Queue->StringTable,Cabfile), MAX_PATH, NULL );
  2331. if(DiamondIsCabinet(FullSourcePath)) {
  2332. QData.Queue = Queue;
  2333. QData.SourceMedia = SourceMediaInfo;
  2334. QData.MsgHandler = MsgHandler;
  2335. QData.IsMsgHandlerNativeCharWidth = IsMsgHandlerNativeCharWidth;
  2336. QData.Context = Context;
  2337. QData.LogContext = Queue->LogContext;
  2338. rc = DiamondProcessCabinet(
  2339. FullSourcePath,
  2340. 0,
  2341. pSetupCabinetQueueCallback,
  2342. &QData,
  2343. TRUE
  2344. );
  2345. if(rc != NO_ERROR) {
  2346. return(rc);
  2347. }
  2348. //
  2349. // Now reset the cabfile to indicate that there is no cabinet.
  2350. // If we don't do this and there are still files that have not
  2351. // been processed, we'll end up in an infinite loop -- the prompt
  2352. // will come back successfully, and we'll just keep going around
  2353. // and around looking through the cabinet, etc.
  2354. //
  2355. Cabfile = -1;
  2356. Tagfile = -1; // for compatability
  2357. }
  2358. }
  2359. //
  2360. // If we get here and files *still* need to be processed,
  2361. // assume the files are in a different directory somewhere
  2362. // and start all over with this media.
  2363. //
  2364. FirstIteration = FALSE;
  2365. DiskPromptGetDriveType(FullSourcePath, &DriveType, &IsRemovable);
  2366. AnyProcessed = FALSE;
  2367. AnyNotProcessed = FALSE;
  2368. for(QueueNode = SourceMediaInfo->CopyQueue;
  2369. QueueNode;
  2370. QueueNode=QueueNode->Next) {
  2371. if(IsRemovable) {
  2372. if(!(QueueNode->InternalFlags & IQF_PROCESSED)) {
  2373. if(Tagfile != -1) {
  2374. SkipMedia = TRUE;
  2375. }
  2376. goto RepromptMedia;
  2377. }
  2378. } else { // Fixed media
  2379. if(QueueNode->InternalFlags & IQF_PROCESSED) {
  2380. AnyProcessed = TRUE;
  2381. } else {
  2382. AnyNotProcessed = TRUE;
  2383. }
  2384. }
  2385. }
  2386. if(!IsRemovable) {
  2387. if(AnyNotProcessed) {
  2388. //
  2389. // If some of the files are present on fixed media, we don't
  2390. // want to look elsewhere.
  2391. //
  2392. if(AnyProcessed) {
  2393. SkipMedia = TRUE;
  2394. }
  2395. //
  2396. // Find the first unprocessed file
  2397. //
  2398. for(QueueNode = SourceMediaInfo->CopyQueue;
  2399. QueueNode;
  2400. QueueNode = QueueNode->Next) {
  2401. if(!(QueueNode->InternalFlags & IQF_PROCESSED)) {
  2402. break;
  2403. }
  2404. }
  2405. MYASSERT(QueueNode);
  2406. goto RepromptMedia;
  2407. }
  2408. }
  2409. } // end for each source media info
  2410. //
  2411. // Tell handler we're done with the copy queue and return.
  2412. //
  2413. pSetupCallMsgHandler(
  2414. Queue->LogContext,
  2415. MsgHandler,
  2416. IsMsgHandlerNativeCharWidth,
  2417. Context,
  2418. SPFILENOTIFY_ENDSUBQUEUE,
  2419. FILEOP_COPY,
  2420. 0
  2421. );
  2422. return(NO_ERROR);
  2423. }
  2424. VOID
  2425. pSetupBuildSourceForCopy(
  2426. IN PCTSTR UserRoot,
  2427. IN PCTSTR UserPath,
  2428. IN LONG MediaRoot,
  2429. IN PSP_FILE_QUEUE Queue,
  2430. IN PSP_FILE_QUEUE_NODE QueueNode,
  2431. OUT PTSTR FullPath
  2432. )
  2433. {
  2434. PCTSTR p;
  2435. //
  2436. // If there is a user-specified override root path, use that instead of
  2437. // the root path specified in the source media descriptor.
  2438. //
  2439. MYASSERT(Queue);
  2440. MYASSERT(QueueNode);
  2441. MYASSERT(FullPath);
  2442. p = (UserRoot && UserRoot[0])
  2443. ? UserRoot
  2444. : pSetupStringTableStringFromId(Queue->StringTable,MediaRoot);
  2445. lstrcpyn(FullPath,p,MAX_PATH);
  2446. //
  2447. // If there is a user-specified override path, use that instead of any
  2448. // path specified in the copy node.
  2449. //
  2450. if(UserPath && UserPath[0]) {
  2451. p = UserPath;
  2452. } else {
  2453. if(QueueNode->SourcePath == -1) {
  2454. p = NULL;
  2455. } else {
  2456. p = pSetupStringTableStringFromId(Queue->StringTable,QueueNode->SourcePath);
  2457. }
  2458. }
  2459. if(p) {
  2460. pSetupConcatenatePaths(FullPath,p,MAX_PATH,NULL);
  2461. }
  2462. //
  2463. // Fetch the filename and append.
  2464. //
  2465. p = pSetupStringTableStringFromId(Queue->StringTable,QueueNode->SourceFilename),
  2466. pSetupConcatenatePaths(FullPath,p,MAX_PATH,NULL);
  2467. }
  2468. VOID
  2469. pSetupSetPathOverrides(
  2470. IN PVOID StringTable,
  2471. IN OUT PTSTR RootPath,
  2472. IN OUT PTSTR SubPath,
  2473. IN LONG RootPathId,
  2474. IN LONG SubPathId,
  2475. IN PTSTR NewPath
  2476. )
  2477. {
  2478. PCTSTR root,path;
  2479. UINT u,l;
  2480. //
  2481. // See if the existing root override or root path is a prefix
  2482. // of the path the user gave us.
  2483. //
  2484. MYASSERT(RootPath);
  2485. MYASSERT(SubPath);
  2486. root = RootPath[0] ? RootPath : pSetupStringTableStringFromId(StringTable,RootPathId);
  2487. u = lstrlen(root);
  2488. path = SubPath[0]
  2489. ? SubPath
  2490. : ((SubPathId == -1) ? NULL : pSetupStringTableStringFromId(StringTable,SubPathId));
  2491. if(path && (*path == TEXT('\\'))) {
  2492. path++;
  2493. }
  2494. if(_tcsnicmp(NewPath,root,u)) {
  2495. //
  2496. // Root path does not match what we're currently using, ie, the user
  2497. // supplied a new path. In this case, we will see if the currently in-use
  2498. // subpath matches the suffix of the new path, and if so, we'll assume
  2499. // that is the override subpath and shorten the override root path.
  2500. //
  2501. lstrcpy(RootPath,NewPath);
  2502. if(path) {
  2503. u = lstrlen(NewPath);
  2504. l = lstrlen(path);
  2505. if((u > l) && (NewPath[(u-l)-1] == TEXT('\\')) && !lstrcmpi(NewPath+u-l,path)) {
  2506. //
  2507. // Subpath tail matches. Truncate the root override and
  2508. // leave the subpath override alone.
  2509. //
  2510. RootPath[(u-l)-1] = 0;
  2511. } else {
  2512. //
  2513. // In this case, we need to indicate an override subpath of the root,
  2514. // or else all subsequent accesses will still try to append the subpath
  2515. // specified in the copy node, which is not what we want.
  2516. //
  2517. SubPath[0] = TEXT('\\');
  2518. SubPath[1] = 0;
  2519. }
  2520. }
  2521. } else {
  2522. //
  2523. // Root path matches what we are currently using.
  2524. //
  2525. // See if the tail of the user-specified path matches the existing
  2526. // subpath. If not, then use the rest of the root path as the subpath
  2527. // override. If the tail matches, then extend the user override root.
  2528. //
  2529. // Examples:
  2530. //
  2531. // File was queued with root = f:\, subpath = \mips
  2532. //
  2533. // User override path is f:\alpha
  2534. //
  2535. // The new status will be leave override root alone;
  2536. // override subpath = \alpha
  2537. //
  2538. // File was queued with root = \\foo\bar, subpath = \i386
  2539. //
  2540. // User override path is \\foo\bar\new\i386
  2541. //
  2542. // The new status will be a root override of \\foo\bar\new;
  2543. // no override subpath.
  2544. //
  2545. NewPath += u;
  2546. if(*NewPath == TEXT('\\')) {
  2547. NewPath++;
  2548. }
  2549. if(path) {
  2550. u = lstrlen(NewPath);
  2551. l = lstrlen(path);
  2552. if((u >= l) && !lstrcmpi(NewPath+u-l,path)) {
  2553. //
  2554. // Change root override and indicate no override subpath.
  2555. //
  2556. SubPath[0] = TEXT('\0');
  2557. NewPath[u-l] = TEXT('\0');
  2558. lstrcpy(RootPath,root);
  2559. pSetupConcatenatePaths(RootPath,NewPath,MAX_PATH,NULL);
  2560. u = lstrlen(RootPath);
  2561. if(u && (*CharPrev(RootPath,RootPath+u) == TEXT('\\'))) {
  2562. RootPath[u-1] = TEXT('\0'); // valid to do if last char is '\'
  2563. }
  2564. } else {
  2565. //
  2566. // Leave override root alone but change subpath.
  2567. //
  2568. lstrcpy(SubPath,NewPath);
  2569. if(!SubPath[0]) {
  2570. SubPath[0] = TEXT('\\');
  2571. SubPath[1] = TEXT('\0');
  2572. }
  2573. }
  2574. } else {
  2575. //
  2576. // File was queued without a subpath. If there's a subpath
  2577. // in what the user gave us, use it as the override.
  2578. //
  2579. if(*NewPath) {
  2580. lstrcpy(SubPath,NewPath);
  2581. }
  2582. }
  2583. }
  2584. }
  2585. UINT
  2586. pSetupCabinetQueueCallback(
  2587. IN PVOID Context,
  2588. IN UINT Notification,
  2589. IN UINT_PTR Param1,
  2590. IN UINT_PTR Param2
  2591. )
  2592. {
  2593. UINT rc;
  2594. PCABINET_INFO CabinetInfo;
  2595. PFILE_IN_CABINET_INFO FileInfo;
  2596. TCHAR TempPath[MAX_PATH];
  2597. PTSTR CabinetFile;
  2598. PTSTR QueuedFile;
  2599. PTSTR FilePart1,FilePart2;
  2600. PTSTR FullTargetPath;
  2601. PFILEPATHS FilePaths;
  2602. PSP_FILE_QUEUE_NODE QueueNode,FirstNode,LastNode;
  2603. PQ_CAB_CB_DATA QData;
  2604. UINT h;
  2605. SOURCE_MEDIA SourceMedia;
  2606. DWORD status;
  2607. QData = (PQ_CAB_CB_DATA)Context;
  2608. switch(Notification) {
  2609. case SPFILENOTIFY_CABINETINFO:
  2610. //
  2611. // We don't do anything with this.
  2612. //
  2613. rc = NO_ERROR;
  2614. break;
  2615. case SPFILENOTIFY_FILEINCABINET:
  2616. //
  2617. // New file within a cabinet.
  2618. //
  2619. // Determine whether we want to copy this file.
  2620. // The context we get has all the stuff we need in it
  2621. // to make this determination.
  2622. //
  2623. // Note that the queue could contain multiple copy operations
  2624. // involving this file, but we only want to extract it once!
  2625. //
  2626. FileInfo = (PFILE_IN_CABINET_INFO)Param1;
  2627. CabinetFile = (PTSTR)Param2;
  2628. if(FilePart1 = _tcsrchr(FileInfo->NameInCabinet,TEXT('\\'))) {
  2629. FilePart1++;
  2630. } else {
  2631. FilePart1 = (PTSTR)FileInfo->NameInCabinet;
  2632. }
  2633. rc = FILEOP_SKIP;
  2634. FileInfo->Win32Error = NO_ERROR;
  2635. FirstNode = NULL;
  2636. //
  2637. // Find ALL instances of this file in the queue and mark them.
  2638. //
  2639. for(QueueNode=QData->SourceMedia->CopyQueue; QueueNode; QueueNode=QueueNode->Next) {
  2640. if(QueueNode->InternalFlags & IQF_PROCESSED) {
  2641. //
  2642. // This file was already processed. Ignore it.
  2643. //
  2644. continue;
  2645. }
  2646. //
  2647. // Check the filename in the cabinet against the file
  2648. // in the media's copy queue.
  2649. //
  2650. QueuedFile = pSetupStringTableStringFromId(
  2651. QData->Queue->StringTable,
  2652. QueueNode->SourceFilename
  2653. );
  2654. if(FilePart2 = _tcsrchr(QueuedFile,TEXT('\\'))) {
  2655. FilePart2++;
  2656. } else {
  2657. FilePart2 = QueuedFile;
  2658. }
  2659. if(!lstrcmpi(FilePart1,FilePart2)) {
  2660. //
  2661. // We want this file.
  2662. //
  2663. rc = FILEOP_DOIT;
  2664. QueueNode->InternalFlags |= IQF_PROCESSED | IQF_MATCH;
  2665. if(!FirstNode) {
  2666. FirstNode = QueueNode;
  2667. }
  2668. LastNode = QueueNode;
  2669. }
  2670. }
  2671. if(rc == FILEOP_DOIT) {
  2672. //
  2673. // We want this file. Tell the caller the full target pathname
  2674. // to be used, which is a temporary file in the directory
  2675. // where the first instance of the file will ultimately go.
  2676. // We do this so we can call SetupInstallFile later (perhaps
  2677. // multiple times), which will handle version checks, etc.
  2678. //
  2679. // Before attempting to create a temp file make sure the path exists.
  2680. //
  2681. lstrcpyn(
  2682. TempPath,
  2683. pSetupStringTableStringFromId(QData->Queue->StringTable,FirstNode->TargetDirectory),
  2684. MAX_PATH
  2685. );
  2686. pSetupConcatenatePaths(TempPath,TEXT("x"),MAX_PATH,NULL); // last component ignored
  2687. status = pSetupMakeSurePathExists(TempPath);
  2688. if(status == NO_ERROR) {
  2689. LastNode->InternalFlags |= IQF_LAST_MATCH;
  2690. if(GetTempFileName(
  2691. pSetupStringTableStringFromId(QData->Queue->StringTable,FirstNode->TargetDirectory),
  2692. TEXT("SETP"),
  2693. 0,
  2694. FileInfo->FullTargetName
  2695. )) {
  2696. QData->CurrentFirstNode = FirstNode;
  2697. } else {
  2698. status = GetLastError();
  2699. if(status == ERROR_ACCESS_DENIED) {
  2700. FileInfo->Win32Error = ERROR_INVALID_TARGET;
  2701. } else {
  2702. FileInfo->Win32Error = status;
  2703. }
  2704. rc = FILEOP_ABORT;
  2705. SetLastError(FileInfo->Win32Error);
  2706. }
  2707. } else {
  2708. if(status == ERROR_ACCESS_DENIED) {
  2709. FileInfo->Win32Error = ERROR_INVALID_TARGET;
  2710. } else {
  2711. FileInfo->Win32Error = status;
  2712. }
  2713. rc = FILEOP_ABORT;
  2714. SetLastError(FileInfo->Win32Error);
  2715. }
  2716. }
  2717. break;
  2718. case SPFILENOTIFY_FILEEXTRACTED:
  2719. FilePaths = (PFILEPATHS)Param1;
  2720. //
  2721. // The current file was extracted. If this was successful,
  2722. // then we need to call SetupInstallFile on it to perform version
  2723. // checks and move it into its final location or locations.
  2724. //
  2725. // The .Source member of FilePaths is the cabinet file.
  2726. //
  2727. // The .Target member is the name of the temporary file, which is
  2728. // very useful, as it is the name if the file to use as the source
  2729. // in copy operations.
  2730. //
  2731. // Process each file in the queue that we care about.
  2732. //
  2733. if((rc = FilePaths->Win32Error) == NO_ERROR) {
  2734. for(QueueNode=QData->CurrentFirstNode; QueueNode && (rc==NO_ERROR); QueueNode=QueueNode->Next) {
  2735. //
  2736. // If we don't care about this file, skip it.
  2737. //
  2738. if(!(QueueNode->InternalFlags & IQF_MATCH)) {
  2739. continue;
  2740. }
  2741. QueueNode->InternalFlags &= ~IQF_MATCH;
  2742. rc = pSetupCopySingleQueuedFileCabCase(
  2743. QData->Queue,
  2744. QueueNode,
  2745. FilePaths->Source,
  2746. FilePaths->Target,
  2747. QData->MsgHandler,
  2748. QData->Context,
  2749. QData->IsMsgHandlerNativeCharWidth
  2750. );
  2751. //
  2752. // If this was the last file that matched, break out.
  2753. //
  2754. if(QueueNode->InternalFlags & IQF_LAST_MATCH) {
  2755. QueueNode->InternalFlags &= ~IQF_LAST_MATCH;
  2756. break;
  2757. }
  2758. }
  2759. }
  2760. //
  2761. // Delete the temporary file we extracted -- we don't need it any more.
  2762. //
  2763. DeleteFile(FilePaths->Target);
  2764. break;
  2765. case SPFILENOTIFY_NEEDNEWCABINET:
  2766. //
  2767. // Need a new cabinet.
  2768. //
  2769. CabinetInfo = (PCABINET_INFO)Param1;
  2770. SourceMedia.Tagfile = NULL;
  2771. SourceMedia.Description = CabinetInfo->DiskName;
  2772. SourceMedia.SourcePath = CabinetInfo->CabinetPath;
  2773. SourceMedia.SourceFile = CabinetInfo->CabinetFile;
  2774. SourceMedia.Flags = SP_FLAG_CABINETCONTINUATION | SP_COPY_NOSKIP;
  2775. h = pSetupCallMsgHandler(
  2776. QData->LogContext,
  2777. QData->MsgHandler,
  2778. QData->IsMsgHandlerNativeCharWidth,
  2779. QData->Context,
  2780. SPFILENOTIFY_NEEDMEDIA,
  2781. (UINT_PTR)&SourceMedia,
  2782. Param2
  2783. );
  2784. switch(h) {
  2785. case FILEOP_NEWPATH:
  2786. case FILEOP_DOIT:
  2787. rc = NO_ERROR;
  2788. break;
  2789. case FILEOP_ABORT:
  2790. rc = GetLastError();
  2791. if(!rc) {
  2792. rc = ERROR_OPERATION_ABORTED;
  2793. }
  2794. break;
  2795. default:
  2796. rc = ERROR_OPERATION_ABORTED;
  2797. break;
  2798. }
  2799. //
  2800. // in this case, rc is a status code
  2801. // but also set it as last error
  2802. //
  2803. SetLastError(rc);
  2804. break;
  2805. default:
  2806. MYASSERT(0);
  2807. rc = 0; // indeterminate
  2808. }
  2809. return(rc);
  2810. }
  2811. DWORD
  2812. pSetupCopySingleQueuedFile(
  2813. IN PSP_FILE_QUEUE Queue,
  2814. IN PSP_FILE_QUEUE_NODE QueueNode,
  2815. IN PCTSTR FullSourceName,
  2816. IN PVOID MsgHandler,
  2817. IN PVOID Context,
  2818. OUT PTSTR NewSourcePath,
  2819. IN BOOL IsMsgHandlerNativeCharWidth,
  2820. IN DWORD CopyStyleFlags
  2821. )
  2822. {
  2823. PTSTR FullTargetName;
  2824. FILEPATHS FilePaths;
  2825. UINT u;
  2826. BOOL InUse;
  2827. TCHAR source[MAX_PATH],PathBuffer[MAX_PATH];
  2828. DWORD rc;
  2829. BOOL b;
  2830. BOOL BackupInUse = FALSE;
  2831. BOOL SignatureVerifyFailed;
  2832. NewSourcePath[0] = 0;
  2833. PathBuffer[0] = 0;
  2834. QueueNode->InternalFlags |= IQF_PROCESSED;
  2835. //
  2836. // Form the full target path of the file.
  2837. //
  2838. FullTargetName = pSetupFormFullPath(
  2839. Queue->StringTable,
  2840. QueueNode->TargetDirectory,
  2841. QueueNode->TargetFilename,
  2842. -1
  2843. );
  2844. if(!FullTargetName) {
  2845. return(ERROR_NOT_ENOUGH_MEMORY);
  2846. }
  2847. lstrcpyn(source,FullSourceName,MAX_PATH);
  2848. //
  2849. // check if we need to backup before we copy
  2850. //
  2851. if((rc=pSetupDoLastKnownGoodBackup(Queue,
  2852. FullTargetName,
  2853. 0,
  2854. NULL)) != NO_ERROR) {
  2855. MyFree(FullTargetName);
  2856. goto clean0;
  2857. }
  2858. rc = pSetupCommitSingleBackup(Queue,
  2859. FullTargetName,
  2860. QueueNode->TargetDirectory,
  2861. -1,
  2862. QueueNode->TargetFilename,
  2863. MsgHandler,
  2864. Context,
  2865. IsMsgHandlerNativeCharWidth,
  2866. (QueueNode->StyleFlags & SP_COPY_REPLACE_BOOT_FILE),
  2867. &BackupInUse
  2868. );
  2869. if (rc != NO_ERROR) {
  2870. MyFree(FullTargetName);
  2871. goto clean0;
  2872. }
  2873. if (BackupInUse) {
  2874. //
  2875. // if we couldn't do backup, force the IN_USE flag
  2876. //
  2877. QueueNode->StyleFlags |= SP_COPY_FORCE_IN_USE;
  2878. }
  2879. do {
  2880. //
  2881. // Form the full source name.
  2882. //
  2883. FilePaths.Source = source;
  2884. FilePaths.Target = FullTargetName;
  2885. FilePaths.Win32Error = NO_ERROR;
  2886. //
  2887. // Also, pass the callback routine the CopyStyle flags we're about to
  2888. // use.
  2889. //
  2890. // Callback flags are read-only.
  2891. //
  2892. FilePaths.Flags = QueueNode->StyleFlags;
  2893. //
  2894. // Notify the callback that the copy is starting.
  2895. //
  2896. u = pSetupCallMsgHandler(
  2897. Queue->LogContext,
  2898. MsgHandler,
  2899. IsMsgHandlerNativeCharWidth,
  2900. Context,
  2901. SPFILENOTIFY_STARTCOPY,
  2902. (UINT_PTR)&FilePaths,
  2903. FILEOP_COPY
  2904. );
  2905. if(u == FILEOP_ABORT) {
  2906. rc = GetLastError();
  2907. if(!rc) {
  2908. rc = ERROR_OPERATION_ABORTED;
  2909. }
  2910. WriteLogEntry(
  2911. Queue->LogContext,
  2912. SETUP_LOG_ERROR|SETUP_LOG_BUFFER,
  2913. MSG_LOG_STARTCOPY_ABORT,
  2914. NULL);
  2915. WriteLogError(Queue->LogContext,
  2916. SETUP_LOG_ERROR,
  2917. rc);
  2918. break;
  2919. }
  2920. if(u == FILEOP_DOIT) {
  2921. //
  2922. // Attempt the copy.
  2923. //
  2924. //
  2925. b = _SetupInstallFileEx(
  2926. Queue,
  2927. QueueNode,
  2928. NULL, // no inf handle
  2929. NULL, // no inf context
  2930. source,
  2931. NULL, // source path root is part of FullSourcePath
  2932. FullTargetName,
  2933. QueueNode->StyleFlags | SP_COPY_SOURCE_ABSOLUTE | CopyStyleFlags,
  2934. MsgHandler,
  2935. Context,
  2936. &InUse,
  2937. IsMsgHandlerNativeCharWidth,
  2938. &SignatureVerifyFailed
  2939. );
  2940. rc = b ? NO_ERROR : GetLastError();
  2941. #ifdef UNICODE
  2942. if(b || (rc == NO_ERROR)) {
  2943. if(!InUse && (QueueNode->SecurityDesc != -1)){
  2944. //
  2945. // Set security on the file
  2946. //
  2947. rc = pSetupCallSCE(ST_SCE_SET,
  2948. FullTargetName,
  2949. Queue,
  2950. NULL,
  2951. QueueNode->SecurityDesc,
  2952. NULL
  2953. );
  2954. }
  2955. }
  2956. #endif
  2957. if(rc == NO_ERROR) {
  2958. //
  2959. // File was copied or not copied, but it if was not copied
  2960. // the callback funtcion was already notified about why
  2961. // (version check failed, etc).
  2962. //
  2963. if(QueueNode->StyleFlags & SP_COPY_REPLACE_BOOT_FILE) {
  2964. //
  2965. // _SetupInstallFileEx is responsible for failing the copy
  2966. // when some yahoo comes and copies over a new file (and
  2967. // locks it) before we get a chance to.
  2968. //
  2969. MYASSERT(!InUse);
  2970. //
  2971. // If the file was copied, we need to set the wants-reboot
  2972. // flag. Otherwise, we need to put back the original file.
  2973. //
  2974. if(b) {
  2975. QueueNode->InternalFlags |= INUSE_INF_WANTS_REBOOT;
  2976. } else {
  2977. RestoreBootReplacedFile(Queue, QueueNode);
  2978. }
  2979. } else {
  2980. if(InUse) {
  2981. QueueNode->InternalFlags |= (QueueNode->StyleFlags & SP_COPY_IN_USE_NEEDS_REBOOT)
  2982. ? INUSE_INF_WANTS_REBOOT
  2983. : INUSE_IN_USE;
  2984. }
  2985. }
  2986. } else {
  2987. DWORD LogTag = 0;
  2988. //
  2989. // File was not copied and a real error occurred.
  2990. // Notify the callback (unless the failure was due to a signature
  2991. // verification problem). Disallow skip if that is specified
  2992. // in the node's flags.
  2993. //
  2994. if(SignatureVerifyFailed) {
  2995. break;
  2996. } else {
  2997. LogTag = AllocLogInfoSlotOrLevel(Queue->LogContext,SETUP_LOG_INFO,FALSE);
  2998. FilePaths.Win32Error = rc;
  2999. FilePaths.Flags = QueueNode->StyleFlags & (SP_COPY_NOSKIP | SP_COPY_WARNIFSKIP | SP_COPY_NOBROWSE);
  3000. WriteLogEntry(
  3001. Queue->LogContext,
  3002. LogTag,
  3003. MSG_LOG_COPYERROR,
  3004. NULL,
  3005. FilePaths.Source,
  3006. FilePaths.Target,
  3007. FilePaths.Flags,
  3008. FilePaths.Win32Error
  3009. );
  3010. u = pSetupCallMsgHandler(
  3011. Queue->LogContext,
  3012. MsgHandler,
  3013. IsMsgHandlerNativeCharWidth,
  3014. Context,
  3015. SPFILENOTIFY_COPYERROR,
  3016. (UINT_PTR)&FilePaths,
  3017. (UINT_PTR)PathBuffer
  3018. );
  3019. if(u == FILEOP_ABORT) {
  3020. rc = GetLastError();
  3021. if(!rc) {
  3022. rc = ERROR_OPERATION_ABORTED;
  3023. }
  3024. }
  3025. }
  3026. if(u == FILEOP_ABORT) {
  3027. WriteLogEntry(
  3028. Queue->LogContext,
  3029. SETUP_LOG_ERROR|SETUP_LOG_BUFFER,
  3030. MSG_LOG_COPYERROR_ABORT,
  3031. NULL
  3032. );
  3033. WriteLogError(Queue->LogContext,
  3034. SETUP_LOG_ERROR,
  3035. rc
  3036. );
  3037. ReleaseLogInfoSlot(Queue->LogContext,LogTag);
  3038. LogTag = 0;
  3039. break;
  3040. } else {
  3041. if(u == FILEOP_SKIP) {
  3042. //
  3043. // If this file was a bootfile replacement, then we need
  3044. // to restore the original file that was renamed to a
  3045. // temporary filename.
  3046. //
  3047. if(QueueNode->StyleFlags & SP_COPY_REPLACE_BOOT_FILE) {
  3048. RestoreBootReplacedFile(Queue, QueueNode);
  3049. }
  3050. WriteLogEntry(
  3051. Queue->LogContext,
  3052. SETUP_LOG_WARNING,
  3053. MSG_LOG_COPYERROR_SKIP,
  3054. NULL
  3055. );
  3056. ReleaseLogInfoSlot(Queue->LogContext,LogTag);
  3057. LogTag = 0;
  3058. //
  3059. // Force termination of processing for this file.
  3060. //
  3061. rc = NO_ERROR;
  3062. break;
  3063. } else {
  3064. if((u == FILEOP_NEWPATH) || ((u == FILEOP_RETRY) && PathBuffer[0])) {
  3065. WriteLogEntry(
  3066. Queue->LogContext,
  3067. SETUP_LOG_WARNING,
  3068. MSG_LOG_COPYERROR_NEWPATH,
  3069. NULL,
  3070. u,
  3071. PathBuffer
  3072. );
  3073. ReleaseLogInfoSlot(Queue->LogContext,LogTag);
  3074. LogTag = 0;
  3075. //
  3076. // Note that rc is already set to something other than
  3077. // NO_ERROR or we wouldn't be here.
  3078. //
  3079. lstrcpyn(NewSourcePath,PathBuffer,MAX_PATH);
  3080. lstrcpyn(source,NewSourcePath,MAX_PATH);
  3081. pSetupConcatenatePaths(
  3082. source,
  3083. pSetupStringTableStringFromId(Queue->StringTable,QueueNode->SourceFilename),
  3084. MAX_PATH,
  3085. NULL
  3086. );
  3087. }
  3088. //
  3089. // Else we don't have a new path.
  3090. // Just keep using the one we had.
  3091. //
  3092. }
  3093. }
  3094. if (LogTag != 0) {
  3095. //
  3096. // haven't done anything regards logging yet, do it now
  3097. //
  3098. WriteLogEntry(
  3099. Queue->LogContext,
  3100. SETUP_LOG_INFO,
  3101. MSG_LOG_COPYERROR_RETRY,
  3102. NULL,
  3103. u
  3104. );
  3105. ReleaseLogInfoSlot(Queue->LogContext,LogTag);
  3106. LogTag = 0;
  3107. }
  3108. }
  3109. } else {
  3110. //
  3111. // skip file
  3112. //
  3113. WriteLogEntry(
  3114. Queue->LogContext,
  3115. SETUP_LOG_INFO, // info level as this would be due to override of callback
  3116. MSG_LOG_STARTCOPY_SKIP,
  3117. NULL,
  3118. u
  3119. );
  3120. rc = NO_ERROR;
  3121. }
  3122. } while(rc != NO_ERROR);
  3123. //
  3124. // Notify the callback that the copy is done.
  3125. //
  3126. FilePaths.Win32Error = rc;
  3127. pSetupCallMsgHandler(
  3128. Queue->LogContext,
  3129. MsgHandler,
  3130. IsMsgHandlerNativeCharWidth,
  3131. Context,
  3132. SPFILENOTIFY_ENDCOPY,
  3133. (UINT_PTR)&FilePaths,
  3134. 0
  3135. );
  3136. MyFree(FullTargetName);
  3137. clean0:
  3138. return(rc);
  3139. }
  3140. DWORD
  3141. pSetupCopySingleQueuedFileCabCase(
  3142. IN PSP_FILE_QUEUE Queue,
  3143. IN PSP_FILE_QUEUE_NODE QueueNode,
  3144. IN PCTSTR CabinetName,
  3145. IN PCTSTR FullSourceName,
  3146. IN PVOID MsgHandler,
  3147. IN PVOID Context,
  3148. IN BOOL IsMsgHandlerNativeCharWidth
  3149. )
  3150. {
  3151. PTSTR FullTargetName;
  3152. FILEPATHS FilePaths;
  3153. UINT u;
  3154. BOOL InUse;
  3155. TCHAR PathBuffer[MAX_PATH];
  3156. DWORD rc;
  3157. BOOL b;
  3158. BOOL BackupInUse = FALSE;
  3159. BOOL SignatureVerifyFailed;
  3160. DWORD LogTag = 0;
  3161. LPCTSTR SourceName;
  3162. //
  3163. // Form the full target path of the file.
  3164. //
  3165. SourceName = pSetupStringTableStringFromId(Queue->StringTable,QueueNode->SourceFilename);
  3166. FullTargetName = pSetupFormFullPath(
  3167. Queue->StringTable,
  3168. QueueNode->TargetDirectory,
  3169. QueueNode->TargetFilename,
  3170. -1
  3171. );
  3172. if(!FullTargetName) {
  3173. return(ERROR_NOT_ENOUGH_MEMORY);
  3174. }
  3175. LogTag = AllocLogInfoSlotOrLevel(Queue->LogContext,SETUP_LOG_INFO,FALSE);
  3176. WriteLogEntry(
  3177. Queue->LogContext,
  3178. LogTag,
  3179. MSG_LOG_COPY_FROM_CAB,
  3180. NULL,
  3181. CabinetName,
  3182. SourceName,
  3183. FullSourceName,
  3184. FullTargetName
  3185. );
  3186. //
  3187. // check if we need to backup before we copy
  3188. //
  3189. if((rc=pSetupDoLastKnownGoodBackup(Queue,
  3190. FullTargetName,
  3191. 0,
  3192. NULL)) != NO_ERROR) {
  3193. MyFree(FullTargetName);
  3194. goto clean0;
  3195. }
  3196. rc = pSetupCommitSingleBackup(Queue,
  3197. FullTargetName,
  3198. QueueNode->TargetDirectory,
  3199. -1,
  3200. QueueNode->TargetFilename,
  3201. MsgHandler,
  3202. Context,
  3203. IsMsgHandlerNativeCharWidth,
  3204. (QueueNode->StyleFlags & SP_COPY_REPLACE_BOOT_FILE),
  3205. &BackupInUse
  3206. );
  3207. if (rc != NO_ERROR) {
  3208. MyFree(FullTargetName);
  3209. goto clean0;
  3210. }
  3211. if (BackupInUse) {
  3212. //
  3213. // if we couldn't do backup, force the IN_USE flag
  3214. //
  3215. QueueNode->StyleFlags |= SP_COPY_FORCE_IN_USE;
  3216. }
  3217. //
  3218. // We use the cabinet name as the source name so the display looks right
  3219. // to the user. Otherwise he sees the name of some temp file in the
  3220. // source field.
  3221. //
  3222. FilePaths.Source = CabinetName;
  3223. FilePaths.Target = FullTargetName;
  3224. FilePaths.Win32Error = NO_ERROR;
  3225. //
  3226. // Also, pass the callback routine the CopyStyle flags we're about to
  3227. // use.
  3228. //
  3229. // Callback flags are read-only.
  3230. //
  3231. FilePaths.Flags = QueueNode->StyleFlags;
  3232. do {
  3233. //
  3234. // Notify the callback that the copy is starting.
  3235. //
  3236. u = pSetupCallMsgHandler(
  3237. Queue->LogContext,
  3238. MsgHandler,
  3239. IsMsgHandlerNativeCharWidth,
  3240. Context,
  3241. SPFILENOTIFY_STARTCOPY,
  3242. (UINT_PTR)&FilePaths,
  3243. FILEOP_COPY
  3244. );
  3245. if(u == FILEOP_ABORT) {
  3246. rc = GetLastError();
  3247. if(!rc) {
  3248. rc = ERROR_OPERATION_ABORTED;
  3249. }
  3250. break;
  3251. }
  3252. if(u == FILEOP_DOIT) {
  3253. //
  3254. // Attempt the copy.
  3255. //
  3256. b = _SetupInstallFileEx(
  3257. Queue,
  3258. QueueNode,
  3259. NULL, // no inf handle
  3260. NULL, // no inf context
  3261. FullSourceName,
  3262. NULL, // source path root is part of FullSourcePath
  3263. FullTargetName,
  3264. QueueNode->StyleFlags | SP_COPY_SOURCE_ABSOLUTE,
  3265. MsgHandler,
  3266. Context,
  3267. &InUse,
  3268. IsMsgHandlerNativeCharWidth,
  3269. &SignatureVerifyFailed
  3270. );
  3271. #ifdef UNICODE
  3272. if(b || ((rc = GetLastError()) == NO_ERROR)) {
  3273. if(!InUse && (QueueNode->SecurityDesc != -1) ){
  3274. // Set security on the file
  3275. rc = pSetupCallSCE(
  3276. ST_SCE_SET,
  3277. FullTargetName,
  3278. Queue,
  3279. NULL,
  3280. QueueNode->SecurityDesc,
  3281. NULL
  3282. );
  3283. SetLastError( rc );
  3284. }
  3285. }
  3286. #endif
  3287. if(b || ((rc = GetLastError()) == NO_ERROR)) {
  3288. //
  3289. // File was copied or not copied, but it if was not copied
  3290. // the callback funtcion was already notified about why
  3291. // (version check failed, etc).
  3292. //
  3293. if(InUse) {
  3294. QueueNode->InternalFlags |= (QueueNode->StyleFlags & SP_COPY_IN_USE_NEEDS_REBOOT)
  3295. ? INUSE_INF_WANTS_REBOOT
  3296. : INUSE_IN_USE;
  3297. }
  3298. rc = NO_ERROR;
  3299. } else {
  3300. //
  3301. // File was not copied and a real error occurred.
  3302. // Break out and return the error.
  3303. //
  3304. break;
  3305. }
  3306. } else {
  3307. //
  3308. // skip file
  3309. //
  3310. rc = NO_ERROR;
  3311. }
  3312. } while(rc != NO_ERROR);
  3313. //
  3314. // Notify the callback that the copy is done.
  3315. //
  3316. FilePaths.Win32Error = rc;
  3317. pSetupCallMsgHandler(
  3318. Queue->LogContext,
  3319. MsgHandler,
  3320. IsMsgHandlerNativeCharWidth,
  3321. Context,
  3322. SPFILENOTIFY_ENDCOPY,
  3323. (UINT_PTR)&FilePaths,
  3324. 0
  3325. );
  3326. MyFree(FullTargetName);
  3327. clean0:
  3328. if(LogTag) {
  3329. ReleaseLogInfoSlot(Queue->LogContext,LogTag);
  3330. }
  3331. return(rc);
  3332. }
  3333. PTSTR
  3334. pSetupFormFullPath(
  3335. IN PVOID StringTable,
  3336. IN LONG PathPart1,
  3337. IN LONG PathPart2, OPTIONAL
  3338. IN LONG PathPart3 OPTIONAL
  3339. )
  3340. /*++
  3341. Routine Description:
  3342. Form a full path based on components whose strings are in a string
  3343. table.
  3344. Arguments:
  3345. StringTable - supplies handle to string table.
  3346. PathPart1 - Supplies first part of path
  3347. PathPart2 - if specified, supplies second part of path
  3348. PathPart3 - if specified, supplies third part of path
  3349. Return Value:
  3350. Pointer to buffer containing full path. Caller can free with MyFree().
  3351. NULL if out of memory.
  3352. --*/
  3353. {
  3354. UINT RequiredSize;
  3355. PCTSTR p1,p2,p3;
  3356. TCHAR Buffer[MAX_PATH];
  3357. p1 = pSetupStringTableStringFromId(StringTable,PathPart1);
  3358. if (!p1) {
  3359. return NULL;
  3360. }
  3361. p2 = (PathPart2 == -1) ? NULL : pSetupStringTableStringFromId(StringTable,PathPart2);
  3362. p3 = (PathPart3 == -1) ? NULL : pSetupStringTableStringFromId(StringTable,PathPart3);
  3363. lstrcpy(Buffer,p1);
  3364. if(!p2 || pSetupConcatenatePaths(Buffer,p2,MAX_PATH,NULL)) {
  3365. if(p3) {
  3366. pSetupConcatenatePaths(Buffer,p3,MAX_PATH,NULL);
  3367. }
  3368. }
  3369. return(DuplicateString(Buffer));
  3370. }
  3371. DWORD
  3372. pSetupVerifyQueuedCatalogs(
  3373. IN HSPFILEQ FileQueue
  3374. )
  3375. /*++
  3376. Routine Description:
  3377. Silently verify all catalog nodes in the specified queue.
  3378. Arguments:
  3379. FileQueue - supplies a handle to the file queue containing catalog nodes
  3380. to be verified.
  3381. Return Value:
  3382. If all catalog nodes are valid, the return value is NO_ERROR. Otherwise,
  3383. it is a Win32 error code indicating the problem.
  3384. --*/
  3385. {
  3386. return _SetupVerifyQueuedCatalogs(NULL, // No UI, thus no HWND needed
  3387. (PSP_FILE_QUEUE)FileQueue,
  3388. VERCAT_NO_PROMPT_ON_ERROR,
  3389. NULL,
  3390. NULL
  3391. );
  3392. }
  3393. DWORD
  3394. _SetupVerifyQueuedCatalogs(
  3395. IN HWND Owner,
  3396. IN PSP_FILE_QUEUE Queue,
  3397. IN DWORD Flags,
  3398. OUT PTSTR DeviceInfFinalName, OPTIONAL
  3399. OUT PBOOL DeviceInfNewlyCopied OPTIONAL
  3400. )
  3401. /*++
  3402. Routine Description:
  3403. This routine verifies catalogs and infs in a given queue by traversing
  3404. the catalog node list associated with the queue and operating on the
  3405. catalog/inf pair described by each one.
  3406. If any catalog/inf fails verification, the user is notified via a dialog,
  3407. depending on current policy.
  3408. ** Behavior for native platform verification (w/o catalog override)
  3409. If an INF is from a system location, we assume that the catalog is
  3410. already installed on the system. Really there is no other option here,
  3411. since we would have no idea where to get the catalog in order to install it
  3412. even if we wanted to try. But the inf might have originally been an
  3413. oem inf which was copied and renamed by the Di stuff at device install
  3414. time. The catalog file knows nothing about the renamed file, so we must
  3415. track mappings from current inf filename to original inf filename.
  3416. In this case, we calculate the inf's hash value and then using that,
  3417. we ask the system for a catalog file that contains signing data
  3418. for that hash value. We then ask the system for info
  3419. about that catalog file. We keep repeating this process until we get
  3420. at the catalog we want (based on name). Finally we can call WinVerifyTrust
  3421. verify the catalog itself and the inf.
  3422. If an INF file is instead from an oem location, we copy the oem inf to a
  3423. unique name in the system inf directory (or create a zero-length placeholder
  3424. there, depending on whether or not the VERCAT_INSTALL_INF_AND_CAT flag is
  3425. set), and add the catalog using a filename based on that unique filename.
  3426. ** Behavior for non-native platform verification (w/o catalog override) **
  3427. We will validate the catalogs and INFs using the alternate platform info
  3428. provided in the file queue. Otherwise, the logic is the same as in the
  3429. native case.
  3430. ** Behavior for verification (w/catalog override) **
  3431. The actual verification will be done using native or non-native parameters
  3432. as discussed above, but INFs without a CatalogFile= entry will be validated
  3433. against the specified overriding catalog. This means that system INFs won't
  3434. get validated globally, and INF in OEM locations can be validated even if
  3435. they don't have a CatalogFile= entry. The overriding catalog file will be
  3436. installed under its current name, thus blowing away any existing catalog
  3437. having that name.
  3438. See the documentation on SetupSetFileQueueAlternatePlatform for more
  3439. details.
  3440. Arguments:
  3441. Owner - supplies window handle of window to own any ui. This HWND is stored
  3442. away in the queue for use later if any individual files fail verification.
  3443. Queue - supplies pointer to queue structure.
  3444. Flags - supplies flags that control behavior of this routine.
  3445. VERCAT_INSTALL_INF_AND_CAT - if this flag is set, any infs from
  3446. oem locations will be installed on the system, along with
  3447. their catalog files.
  3448. VERCAT_NO_PROMPT_ON_ERROR - if this flag is set, the user will _not_ be
  3449. notified about verification failures we encounter. If this flag is
  3450. set, then this was only a 'test', and no user prompting should take
  3451. place (nor should any PSS logging take place). If this flag is set,
  3452. then the VERCAT_INSTALL_INF_AND_CAT _should not_ be specified.
  3453. VERCAT_PRIMARY_DEVICE_INF_FROM_INET - specifies that the primary device
  3454. INF in the queue is from the internet, and should be marked as such
  3455. in the corresponding PNF when installed into the %windir%\Inf
  3456. directory via _SetupCopyOEMInf.
  3457. DeviceInfFinalName - optionally, supplies the address of a character buffer,
  3458. _at least_ MAX_PATH characters long, that upon success receives the
  3459. final name given to the INF under the %windir%\Inf directory (this will
  3460. be different than the INF's original name if it was an OEM INF).
  3461. DeviceInfNewlyCopied - optionally, supplies the address of a boolean
  3462. variable that, upon success, is set to indicate whether the INF name
  3463. returned in DeviceInfFinalName was newly-created. If this parameter is
  3464. supplied, then DeviceInfFinalName must also be specified.
  3465. Return Value:
  3466. If all catalogs/infs were verified and installed, or the user accepted
  3467. the risk if a verification failed, then the return value is NO_ERROR.
  3468. If one or more catalogs/infs were not verified, the return value is a Win32
  3469. error code indicating the cause of the failure. NOTE: This error will
  3470. only be returned if the policy is "block", or it it's "warn" and the
  3471. user decided to abort. In this case, the error returned is for the
  3472. catalog/INF where the error was encountered, and any subsequent catalog
  3473. nodes will not have been verified. An exception to this is when the
  3474. VERCAT_NO_PROMPT_ON_ERROR flag is set. In that case, we'll verify all
  3475. catalogs, even if we encounter improperly-signed ones.
  3476. Remarks:
  3477. There are some system INFs (for which global verification is required) that
  3478. don't live in %windir%\Inf. The OCM INFs are an example of this. Those
  3479. INFs use layout.inf (which _is_ located in %windir%\Inf) for the source
  3480. media information for any files they copy. There are other INFs that don't
  3481. live in %windir%\Inf which are extracted out of a binary as-needed (into a
  3482. temporary filename), processed in order to do registry munging, and then
  3483. deleted. Such INFs do not do file copying (thus their 'package' consists
  3484. of just the INF). To accommodate such INFs, we allow "OEM" INFs (i.e.,
  3485. those INFs not in %windir%\Inf) to be verified globally, but we remember the
  3486. fact that these INFs didn't contain a CatalogFile= entry, and if any files
  3487. are ever queued for copy using such INFs for source media information, then
  3488. we'll fail digital signature verification for such files, since there's no
  3489. way for us to know what catalog should be used for verification.
  3490. --*/
  3491. {
  3492. PSPQ_CATALOG_INFO CatalogNode;
  3493. LPCTSTR InfFullPath;
  3494. LPCTSTR CatName;
  3495. TCHAR PathBuffer[MAX_PATH];
  3496. TCHAR InfNameBuffer[MAX_PATH];
  3497. TCHAR CatalogName[MAX_PATH];
  3498. TCHAR *p;
  3499. DWORD Err, CatalogNodeStatus, ReturnStatus;
  3500. SetupapiVerifyProblem Problem;
  3501. LPCTSTR ProblemFile;
  3502. BOOL DeleteOemInfOnError;
  3503. BOOL OriginalNameDifferent;
  3504. LPCTSTR AltCatalogFile;
  3505. LONG CatStringId;
  3506. ULONG RequiredSize;
  3507. DWORD InfVerifyType;
  3508. DWORD SCOIFlags;
  3509. //
  3510. // Define values used to indicate how validation should be done on the INFs.
  3511. //
  3512. #define VERIFY_INF_AS_OEM 0 // verify solely against the specific
  3513. // catalog referenced by the INF
  3514. #define VERIFY_INF_AS_SYSTEM 1 // verify globally (using all catalogs)
  3515. #define VERIFY_OEM_INF_GLOBALLY 2 // verify OEM INF globally, but remember the
  3516. // original error, in case copy operations
  3517. // are queued using media descriptor info
  3518. // within this INF.
  3519. MYASSERT((Flags & (VERCAT_INSTALL_INF_AND_CAT | VERCAT_NO_PROMPT_ON_ERROR))
  3520. != (VERCAT_INSTALL_INF_AND_CAT | VERCAT_NO_PROMPT_ON_ERROR)
  3521. );
  3522. MYASSERT(!DeviceInfNewlyCopied || DeviceInfFinalName);
  3523. if(Queue->Flags & FQF_DID_CATALOGS_OK) {
  3524. //
  3525. // If the caller wants information about the primary device INF, then
  3526. // find the applicable catalog node.
  3527. //
  3528. if(DeviceInfFinalName) {
  3529. for(CatalogNode=Queue->CatalogList; CatalogNode; CatalogNode=CatalogNode->Next) {
  3530. if(CatalogNode->Flags & CATINFO_FLAG_PRIMARY_DEVICE_INF) {
  3531. MYASSERT(CatalogNode->InfFinalPath != -1);
  3532. InfFullPath = pSetupStringTableStringFromId(Queue->StringTable, CatalogNode->InfFinalPath);
  3533. lstrcpy(DeviceInfFinalName, InfFullPath);
  3534. if(DeviceInfNewlyCopied) {
  3535. *DeviceInfNewlyCopied = (CatalogNode->Flags & CATINFO_FLAG_NEWLY_COPIED);
  3536. }
  3537. }
  3538. }
  3539. }
  3540. return NO_ERROR;
  3541. }
  3542. if(Queue->Flags & FQF_DID_CATALOGS_FAILED) {
  3543. //
  3544. // Scan the catalog nodes until we find the first one that failed
  3545. // verification, and return that failure code.
  3546. //
  3547. for(CatalogNode=Queue->CatalogList; CatalogNode; CatalogNode=CatalogNode->Next) {
  3548. if(CatalogNode->VerificationFailureError != NO_ERROR) {
  3549. return CatalogNode->VerificationFailureError;
  3550. }
  3551. }
  3552. //
  3553. // We didn't find a failed catalog node in our catalog list--something's
  3554. // seriously wrong!
  3555. //
  3556. MYASSERT(0);
  3557. return ERROR_INVALID_DATA;
  3558. }
  3559. //
  3560. // If the queue has an alternate default catalog file associated with it,
  3561. // then retrieve that catalog's name for use later.
  3562. //
  3563. AltCatalogFile = (Queue->AltCatalogFile != -1)
  3564. ? pSetupStringTableStringFromId(Queue->StringTable, Queue->AltCatalogFile)
  3565. : NULL;
  3566. Queue->hWndDriverSigningUi = Owner;
  3567. ReturnStatus = NO_ERROR;
  3568. for(CatalogNode=Queue->CatalogList; CatalogNode; CatalogNode=CatalogNode->Next) {
  3569. //
  3570. // Assume success for verification of this catalog node.
  3571. //
  3572. CatalogNodeStatus = NO_ERROR;
  3573. MYASSERT(CatalogNode->InfFullPath != -1);
  3574. InfFullPath = pStringTableStringFromId(Queue->StringTable, CatalogNode->InfFullPath);
  3575. if(Queue->Flags & FQF_USE_ALT_PLATFORM) {
  3576. //
  3577. // We have an alternate platform override, so use the alternate
  3578. // platform's CatalogFile= entry.
  3579. //
  3580. CatStringId = CatalogNode->AltCatalogFileFromInf;
  3581. } else {
  3582. //
  3583. // We're running native--use the native CatalogFile= entry.
  3584. //
  3585. CatStringId = CatalogNode->CatalogFileFromInf;
  3586. }
  3587. CatName = (CatStringId != -1)
  3588. ? pStringTableStringFromId(Queue->StringTable, CatStringId)
  3589. : NULL;
  3590. InfVerifyType = pSetupInfIsFromOemLocation(InfFullPath, TRUE)
  3591. ? VERIFY_INF_AS_OEM
  3592. : VERIFY_INF_AS_SYSTEM;
  3593. if(InfVerifyType == VERIFY_INF_AS_OEM) {
  3594. //
  3595. // If the caller wants us to, we'll now install the catalog. In
  3596. // addition, if it's a (native platform) device installation, we'll
  3597. // install the INF as well.
  3598. //
  3599. // (Note: we specify the 'no overwrite' switch so that we won't blow
  3600. // away any existing PNF source path information for this INF.
  3601. // We'll only consider an OEM INF to match up with an existing
  3602. // %windir%\Inf\Oem*.INF entry if the catalogs also match up, so
  3603. // we're not going to get into any trouble doing this.
  3604. //
  3605. if(Flags & VERCAT_INSTALL_INF_AND_CAT) {
  3606. //
  3607. // If we're not doing a device install, then we want to suppress
  3608. // popups and error log entries if the INF doesn't reference a
  3609. // catalog. This is because we want to allow such INFs to be
  3610. // validated globally, unless they subsequently try to copy files.
  3611. //
  3612. SCOIFlags = (Queue->Flags & FQF_DEVICE_INSTALL)
  3613. ? 0
  3614. : SCOI_NO_ERRLOG_ON_MISSING_CATALOG;
  3615. //
  3616. // If we're not supposed to generate popups/log entries at all
  3617. // for signature verification failures (e.g., because we've
  3618. // already done so previously), then set that flag as well.
  3619. //
  3620. if(Queue->Flags & FQF_DIGSIG_ERRORS_NOUI) {
  3621. SCOIFlags |= SCOI_NO_UI_ON_SIGFAIL;
  3622. }
  3623. if(Queue->Flags & FQF_KEEP_INF_AND_CAT_ORIGINAL_NAMES) {
  3624. SCOIFlags |= SCOI_KEEP_INF_AND_CAT_ORIGINAL_NAMES;
  3625. }
  3626. if(Queue->Flags & FQF_ABORT_IF_UNSIGNED) {
  3627. SCOIFlags |= SCOI_ABORT_IF_UNSIGNED;
  3628. }
  3629. if(_SetupCopyOEMInf(InfFullPath,
  3630. NULL, // default source location to where INF presently is
  3631. ((Flags & VERCAT_PRIMARY_DEVICE_INF_FROM_INET)
  3632. ? SPOST_URL
  3633. : SPOST_PATH),
  3634. (((Queue->Flags & (FQF_DEVICE_INSTALL | FQF_USE_ALT_PLATFORM)) == FQF_DEVICE_INSTALL)
  3635. ? SP_COPY_NOOVERWRITE
  3636. : SP_COPY_NOOVERWRITE | SP_COPY_OEMINF_CATALOG_ONLY),
  3637. PathBuffer,
  3638. SIZECHARS(PathBuffer),
  3639. NULL,
  3640. &p,
  3641. ((CatalogNode->InfOriginalName != -1)
  3642. ? pStringTableStringFromId(Queue->StringTable,
  3643. CatalogNode->InfOriginalName)
  3644. : pSetupGetFileTitle(InfFullPath)),
  3645. CatName,
  3646. Owner,
  3647. ((Queue->DeviceDescStringId == -1)
  3648. ? NULL
  3649. : pStringTableStringFromId(Queue->StringTable,
  3650. Queue->DeviceDescStringId)),
  3651. Queue->DriverSigningPolicy,
  3652. SCOIFlags,
  3653. AltCatalogFile,
  3654. ((Queue->Flags & FQF_USE_ALT_PLATFORM)
  3655. ? &(Queue->AltPlatformInfo)
  3656. : Queue->ValidationPlatform),
  3657. &Err,
  3658. CatalogNode->CatalogFilenameOnSystem,
  3659. Queue->LogContext,
  3660. &(Queue->hCatAdmin))) {
  3661. //
  3662. // If Err indicates that there was a digital signature
  3663. // problem that the user chose to ignore (or was silently
  3664. // ignored), then set a flag in the queue indicating the
  3665. // user should not be warned about subsequent failures.
  3666. // Don't set this flag if the queue's policy is "Ignore",
  3667. // however, on the chance that the policy might be altered
  3668. // later, and we'd want the user to get informed on any
  3669. // subsequent errors.
  3670. //
  3671. // (Note: if the error was due to the INF not having a
  3672. // CatalogFile= entry, and if we're supposed to ignore such
  3673. // problems, then just set the flag to do global validation
  3674. // later.)
  3675. //
  3676. if((Err == ERROR_NO_CATALOG_FOR_OEM_INF) &&
  3677. (SCOIFlags & SCOI_NO_ERRLOG_ON_MISSING_CATALOG)) {
  3678. InfVerifyType = VERIFY_OEM_INF_GLOBALLY;
  3679. } else if((Err != NO_ERROR) && (Queue->DriverSigningPolicy != DRIVERSIGN_NONE)) {
  3680. Queue->Flags |= FQF_DIGSIG_ERRORS_NOUI;
  3681. }
  3682. if(*PathBuffer) {
  3683. //
  3684. // Store the INF's final path into our catalog node.
  3685. // This will be under %windir%\Inf unless the INF didn't
  3686. // specify a CatalogFile= entry and we did an alternate
  3687. // catalog installation (i.e., because the file queue had
  3688. // an associated alternate catalog).
  3689. //
  3690. CatalogNode->InfFinalPath = pSetupStringTableAddString(
  3691. Queue->StringTable,
  3692. PathBuffer,
  3693. STRTAB_CASE_INSENSITIVE | STRTAB_BUFFER_WRITEABLE
  3694. );
  3695. } else {
  3696. //
  3697. // _SetupCopyOEMInf returned an empty string for the
  3698. // destination INF name, which means that we were doing
  3699. // a catalog-only install, and it didn't find the INF
  3700. // already existing in %windir%\Inf. In this case, just
  3701. // use the INF's original pathname as its final pathname.
  3702. //
  3703. CatalogNode->InfFinalPath = CatalogNode->InfFullPath;
  3704. }
  3705. if(CatalogNode->InfFinalPath == -1) {
  3706. CatalogNodeStatus = ERROR_NOT_ENOUGH_MEMORY;
  3707. if(Err == NO_ERROR) {
  3708. Err = CatalogNodeStatus;
  3709. }
  3710. //
  3711. // Since we couldn't add this filename to the string
  3712. // table, we won't be able to undo this copy later--it
  3713. // must be done here. Delete the INF, PNF, and CAT.
  3714. //
  3715. // NOTE: we should never get here if we did an alternate
  3716. // catalog file-only install, because in that case our
  3717. // new INF name is the same as the INF's original name,
  3718. // thus the string is already in the buffer and there's
  3719. // no way we could run out of memory.
  3720. //
  3721. MYASSERT(lstrcmpi(PathBuffer, InfFullPath));
  3722. pSetupUninstallOEMInf(PathBuffer,
  3723. Queue->LogContext,
  3724. SUOI_FORCEDELETE,
  3725. NULL
  3726. );
  3727. } else {
  3728. //
  3729. // Set a flag in the catalog node indicating that this
  3730. // INF was newly-copied into %windir%\Inf. If the
  3731. // string ID for our INF's original name and that of its
  3732. // new name are equal, then we know we did an alternate
  3733. // catalog installation only, and we don't want to set
  3734. // this flag.
  3735. //
  3736. if(CatalogNode->InfFinalPath != CatalogNode->InfFullPath) {
  3737. CatalogNode->Flags |= CATINFO_FLAG_NEWLY_COPIED;
  3738. }
  3739. //
  3740. // If this is the primary device INF, and the caller
  3741. // requested information about that INF's final
  3742. // pathname, then store that information in the caller-
  3743. // supplied buffer(s) now.
  3744. //
  3745. if(DeviceInfFinalName &&
  3746. (CatalogNode->Flags & CATINFO_FLAG_PRIMARY_DEVICE_INF)) {
  3747. //
  3748. // We'd better not just've done an alternate catalog
  3749. // installation.
  3750. //
  3751. MYASSERT(CatalogNode->InfFinalPath != CatalogNode->InfFullPath);
  3752. lstrcpy(DeviceInfFinalName, PathBuffer);
  3753. if(DeviceInfNewlyCopied) {
  3754. *DeviceInfNewlyCopied = TRUE;
  3755. }
  3756. }
  3757. }
  3758. } else {
  3759. CatalogNodeStatus = GetLastError();
  3760. MYASSERT(CatalogNodeStatus != NO_ERROR);
  3761. if(CatalogNodeStatus == ERROR_FILE_EXISTS) {
  3762. //
  3763. // INF and CAT already there--this isn't a failure.
  3764. //
  3765. // Store the name under which we found this OEM INF into
  3766. // the catalog node's InfFinalPath field.
  3767. //
  3768. CatalogNode->InfFinalPath = pSetupStringTableAddString(
  3769. Queue->StringTable,
  3770. PathBuffer,
  3771. STRTAB_CASE_INSENSITIVE | STRTAB_BUFFER_WRITEABLE
  3772. );
  3773. if(CatalogNode->InfFinalPath == -1) {
  3774. CatalogNodeStatus = ERROR_NOT_ENOUGH_MEMORY;
  3775. } else {
  3776. CatalogNodeStatus = NO_ERROR;
  3777. //
  3778. // If Err indicates that there was a digital signature
  3779. // problem that the user chose to ignore (or was silently
  3780. // ignored), then set a flag in the queue indicating the
  3781. // user should not be warned about subsequent failures.
  3782. // Don't set this flag if the queue's policy is "Ignore",
  3783. // however, on the chance that the policy might be altered
  3784. // later, and we'd want the user to get informed on any
  3785. // subsequent errors.
  3786. //
  3787. if((Err != NO_ERROR) && Queue->DriverSigningPolicy != DRIVERSIGN_NONE) {
  3788. Queue->Flags |= FQF_DIGSIG_ERRORS_NOUI;
  3789. }
  3790. //
  3791. // If this is the primary device INF, and the caller
  3792. // requested information about that INF's final
  3793. // pathname, then store that information in the caller-
  3794. // supplied buffer(s) now.
  3795. //
  3796. if(DeviceInfFinalName &&
  3797. (CatalogNode->Flags & CATINFO_FLAG_PRIMARY_DEVICE_INF)) {
  3798. lstrcpy(DeviceInfFinalName, PathBuffer);
  3799. if(DeviceInfNewlyCopied) {
  3800. *DeviceInfNewlyCopied = FALSE;
  3801. }
  3802. }
  3803. }
  3804. } else if(CatalogNodeStatus == ERROR_SET_SYSTEM_RESTORE_POINT) {
  3805. //
  3806. // We should only get this error if the queue flag is
  3807. // set that causes us to abort unsigned installations.
  3808. //
  3809. MYASSERT(Queue->Flags & FQF_ABORT_IF_UNSIGNED);
  3810. //
  3811. // We don't want the user to see the driver signing
  3812. // UI again when the queue is re-committed...
  3813. //
  3814. if(Queue->DriverSigningPolicy != DRIVERSIGN_NONE) {
  3815. Queue->Flags |= FQF_DIGSIG_ERRORS_NOUI;
  3816. }
  3817. //
  3818. // Make sure that Err is also set to this same
  3819. // "special" error code...
  3820. //
  3821. Err = CatalogNodeStatus;
  3822. }
  3823. //
  3824. // If we had a real failure from _SetupCopyOEMInf (or we're
  3825. // out of memory and couldn't add a string to the string
  3826. // table above), then we need to propagate the value of
  3827. // CatalogNodeStatus to Err, if Err doesn't already have a
  3828. // failure code.
  3829. //
  3830. if((CatalogNodeStatus != NO_ERROR) && (Err == NO_ERROR)) {
  3831. Err = CatalogNodeStatus;
  3832. }
  3833. }
  3834. } else {
  3835. //
  3836. // We were told not to copy any files, but we've encountered an
  3837. // OEM INF that needs to be installed. Hence, we have a failure.
  3838. // Note that we _don't_ look to see if this OEM INF (and its
  3839. // corresponding catalog) might happen to already be properly
  3840. // installed. That isn't necessary, because
  3841. // _SetupDiInstallDevice calls _SetupVerifyQueuedCatalogs with
  3842. // the VERCAT_INSTALL_INF_AND_CAT flag _before_ calling
  3843. // SetupScanFileQueue, thus all INFs/CATs should be present when
  3844. // we're called to do simple verification of the catalog nodes.
  3845. //
  3846. Err = CatalogNodeStatus = ERROR_CANNOT_COPY;
  3847. }
  3848. }
  3849. if(InfVerifyType != VERIFY_INF_AS_OEM) {
  3850. //
  3851. // Inf is in system location (%windir%\Inf), or we're going to try
  3852. // validating an "OEM" INF globally. Figure out the expected name
  3853. // of the catalog file. If the file was originally copied in by the
  3854. // Di stuff, then we need to use a name based on the name Di gave
  3855. // the inf. Otherwise we use the name from the inf's CatalogFile=
  3856. // entry, if present. Finally, if the INF doesn't specify a
  3857. // CatalogFile= entry, we assume it's a system component and
  3858. // attempt to validate against any catalog that we find a hash
  3859. // match in.
  3860. //
  3861. Err = NO_ERROR; // assume success
  3862. if(CatalogNode->InfOriginalName != -1) {
  3863. RequiredSize = SIZECHARS(InfNameBuffer);
  3864. if(pSetupStringTableStringFromIdEx(Queue->StringTable,
  3865. CatalogNode->InfOriginalName,
  3866. InfNameBuffer,
  3867. &RequiredSize)) {
  3868. OriginalNameDifferent = TRUE;
  3869. } else {
  3870. //
  3871. // This should never fail!
  3872. //
  3873. MYASSERT(0);
  3874. Err = ERROR_INVALID_DATA;
  3875. }
  3876. } else {
  3877. OriginalNameDifferent = FALSE;
  3878. }
  3879. if(Err == NO_ERROR) {
  3880. if(CatName) {
  3881. //
  3882. // If there is a catalog name, then we'd better not be
  3883. // doing our "verify OEM INF globally" trick!
  3884. //
  3885. MYASSERT(InfVerifyType == VERIFY_INF_AS_SYSTEM);
  3886. if(OriginalNameDifferent) {
  3887. //
  3888. // If the INF specified a catalog file, then we know we
  3889. // would've installed that catalog file using a name based
  3890. // on the unique name we assigned the INF when copying it
  3891. // into the INF directory.
  3892. //
  3893. lstrcpy(CatalogName, pSetupGetFileTitle(InfFullPath));
  3894. p = _tcsrchr(CatalogName, TEXT('.'));
  3895. if(!p) {
  3896. p = CatalogName + lstrlen(CatalogName);
  3897. }
  3898. lstrcpy(p, pszCatSuffix);
  3899. } else {
  3900. lstrcpy(CatalogName, CatName);
  3901. }
  3902. } else {
  3903. //
  3904. // This system INF didn't specify a CatalogFile= entry. If
  3905. // an alternate catalog is associated with this file queue,
  3906. // then use that catalog for verification.
  3907. //
  3908. if(AltCatalogFile) {
  3909. lstrcpy(CatalogName, AltCatalogFile);
  3910. CatName = pSetupGetFileTitle(CatalogName);
  3911. }
  3912. }
  3913. //
  3914. // (Note: in the call below, we don't want to store the
  3915. // validating catalog filename in our CatalogFilenameOnSystem
  3916. // field if the INF didn't specify a CatalogFile= entry (and
  3917. // there was no alternate catalog specified), because we want
  3918. // any queue nodes that reference this catalog entry to use
  3919. // global validation as well.)
  3920. //
  3921. if(GlobalSetupFlags & PSPGF_MINIMAL_EMBEDDED) {
  3922. //
  3923. // Don't attempt to call _VerifyFile, because we're
  3924. // asking for the validating catalog's name, and that makes
  3925. // no sense in the "minimal embedded" case.
  3926. //
  3927. *(CatalogNode->CatalogFilenameOnSystem) = TEXT('\0');
  3928. //
  3929. // (Err is already set to NO_ERROR.)
  3930. //
  3931. } else {
  3932. if(!CatName) {
  3933. *(CatalogNode->CatalogFilenameOnSystem) = TEXT('\0');
  3934. }
  3935. Err = _VerifyFile(
  3936. Queue->LogContext,
  3937. &(Queue->hCatAdmin),
  3938. NULL,
  3939. (CatName ? CatalogName : NULL),
  3940. NULL,
  3941. 0,
  3942. (OriginalNameDifferent ? InfNameBuffer : pSetupGetFileTitle(InfFullPath)),
  3943. InfFullPath,
  3944. &Problem,
  3945. PathBuffer,
  3946. FALSE,
  3947. ((Queue->Flags & FQF_USE_ALT_PLATFORM)
  3948. ? &(Queue->AltPlatformInfo)
  3949. : Queue->ValidationPlatform),
  3950. (VERIFY_FILE_IGNORE_SELFSIGNED
  3951. | VERIFY_FILE_USE_OEM_CATALOGS
  3952. | VERIFY_FILE_NO_DRIVERBLOCKED_CHECK),
  3953. (CatName ? CatalogNode->CatalogFilenameOnSystem : NULL),
  3954. NULL,
  3955. NULL,
  3956. NULL
  3957. );
  3958. }
  3959. }
  3960. if(Err == NO_ERROR) {
  3961. //
  3962. // INF/CAT was successfully verified--store the INF's final path
  3963. // (which is the same as its current path) into the catalog
  3964. // node.
  3965. //
  3966. CatalogNode->InfFinalPath = CatalogNode->InfFullPath;
  3967. } else {
  3968. if(Problem != SetupapiVerifyCatalogProblem) {
  3969. MYASSERT(Problem != SetupapiVerifyNoProblem);
  3970. //
  3971. // If the problem was not a catalog problem, then it's an
  3972. // INF problem (the _VerifyFile routine doesn't know the
  3973. // file we passed it is an INF).
  3974. //
  3975. Problem = SetupapiVerifyInfProblem;
  3976. }
  3977. ProblemFile = PathBuffer;
  3978. if((Flags & VERCAT_NO_PROMPT_ON_ERROR)
  3979. || (Queue->Flags & FQF_QUEUE_FORCE_BLOCK_POLICY)) {
  3980. //
  3981. // Don't notify the caller or log anything--just remember
  3982. // the error.
  3983. //
  3984. CatalogNodeStatus = Err;
  3985. } else {
  3986. //
  3987. // Notify the caller of the failure (based on policy).
  3988. //
  3989. if(pSetupHandleFailedVerification(
  3990. Owner,
  3991. Problem,
  3992. ProblemFile,
  3993. ((Queue->DeviceDescStringId == -1)
  3994. ? NULL
  3995. : pStringTableStringFromId(Queue->StringTable, Queue->DeviceDescStringId)),
  3996. Queue->DriverSigningPolicy,
  3997. Queue->Flags & FQF_DIGSIG_ERRORS_NOUI,
  3998. Err,
  3999. Queue->LogContext,
  4000. NULL,
  4001. NULL))
  4002. {
  4003. //
  4004. // If the caller wants a chance to set a system restore
  4005. // point prior to doing any unsigned installations,
  4006. // then we abort now with a "special" error code that
  4007. // tells them what to do...
  4008. //
  4009. if(Queue->Flags & FQF_ABORT_IF_UNSIGNED) {
  4010. //
  4011. // We don't want the user to see the driver signing
  4012. // UI again when the queue is re-committed...
  4013. //
  4014. if(Queue->DriverSigningPolicy != DRIVERSIGN_NONE) {
  4015. Queue->Flags |= FQF_DIGSIG_ERRORS_NOUI;
  4016. }
  4017. CatalogNodeStatus = Err = ERROR_SET_SYSTEM_RESTORE_POINT;
  4018. } else {
  4019. //
  4020. // Set a flag in the queue that indicates the user has been
  4021. // informed of a signature problem with this queue, and has
  4022. // elected to go ahead and install anyway. Don't set this
  4023. // flag if the queue's policy is "Ignore", on the chance
  4024. // that the policy might be altered later, and we'd want the
  4025. // user to get informed on any subsequent errors.
  4026. //
  4027. if(Queue->DriverSigningPolicy != DRIVERSIGN_NONE) {
  4028. Queue->Flags |= FQF_DIGSIG_ERRORS_NOUI;
  4029. }
  4030. //
  4031. // Since we're going to use the INF/CAT anyway, in spite of
  4032. // digital signature problems, then we need to set the INF's
  4033. // final path to be the same as its current path.
  4034. //
  4035. CatalogNode->InfFinalPath = CatalogNode->InfFullPath;
  4036. }
  4037. } else {
  4038. //
  4039. // The caller doesn't want to proceed.
  4040. //
  4041. CatalogNodeStatus = Err;
  4042. }
  4043. }
  4044. }
  4045. if(CatalogNodeStatus == NO_ERROR) {
  4046. //
  4047. // If this is the primary device INF, and the caller requested
  4048. // information about that INF's final pathname, then store that
  4049. // information in the caller-supplied buffer(s) now.
  4050. //
  4051. if(DeviceInfFinalName &&
  4052. (CatalogNode->Flags & CATINFO_FLAG_PRIMARY_DEVICE_INF)) {
  4053. lstrcpy(DeviceInfFinalName, InfFullPath);
  4054. if(DeviceInfNewlyCopied) {
  4055. *DeviceInfNewlyCopied = FALSE;
  4056. }
  4057. }
  4058. }
  4059. }
  4060. if(Err == NO_ERROR) {
  4061. //
  4062. // If we successfully validated an "OEM" INF globally, then we want
  4063. // to remember this fact. This will allow us to generate a
  4064. // signature verification failure against any file copy nodes
  4065. // associated with this catalog node.
  4066. //
  4067. if(InfVerifyType == VERIFY_OEM_INF_GLOBALLY) {
  4068. CatalogNode->VerificationFailureError = ERROR_NO_CATALOG_FOR_OEM_INF;
  4069. } else {
  4070. CatalogNode->VerificationFailureError = NO_ERROR;
  4071. }
  4072. } else {
  4073. CatalogNode->VerificationFailureError = Err;
  4074. CatalogNode->CatalogFilenameOnSystem[0] = TEXT('\0');
  4075. }
  4076. if((ReturnStatus == NO_ERROR) && (CatalogNodeStatus != NO_ERROR)) {
  4077. //
  4078. // First critical error we've encountered--propagate the failure
  4079. // for this catalog to our return status that will be returned to
  4080. // the caller once we've finished looking at all the catalogs.
  4081. //
  4082. ReturnStatus = CatalogNodeStatus;
  4083. //
  4084. // Unless the VERCAT_NO_PROMPT_ON_ERROR flag has been set, we
  4085. // should abort right now--there's no since in going any further.
  4086. //
  4087. if(!(Flags & VERCAT_NO_PROMPT_ON_ERROR)) {
  4088. break;
  4089. }
  4090. }
  4091. }
  4092. //
  4093. // If the caller requested no prompting, then we don't want to mark this
  4094. // queue as 'failed', since the user never heard about it. However, if the
  4095. // verification succeeded, then we _do_ want to mark it as successful.
  4096. //
  4097. if(Flags & VERCAT_NO_PROMPT_ON_ERROR) {
  4098. if(ReturnStatus == NO_ERROR) {
  4099. Queue->Flags |= FQF_DID_CATALOGS_OK;
  4100. }
  4101. } else {
  4102. Queue->Flags |= (ReturnStatus == NO_ERROR) ? FQF_DID_CATALOGS_OK
  4103. : FQF_DID_CATALOGS_FAILED;
  4104. }
  4105. return ReturnStatus;
  4106. }
  4107. VOID
  4108. LogFailedVerification(
  4109. IN PSETUP_LOG_CONTEXT LogContext, OPTIONAL
  4110. IN DWORD MessageId,
  4111. IN DWORD Error,
  4112. IN LPCTSTR ProblemFile,
  4113. IN LPCTSTR DeviceDesc OPTIONAL
  4114. )
  4115. /*++
  4116. Routine Description:
  4117. This routine logs when a verification failed but the file was installed
  4118. anyway.
  4119. Arguments:
  4120. LogContext - optionally supplies a pointer to the context for logging.
  4121. If this is not supplied, errors will be logged to the default context.
  4122. MessageId - Message to display
  4123. Error - supplies the code the the error that caused the failure.
  4124. ProblemFile - supplies the file path to the file associated with
  4125. the problem. In some cases this is a full path, in others it's just a
  4126. filename. The caller decides which makes sense in a particular
  4127. scenario. For example, a system catalog is in some funky directory
  4128. and there is no need to tell the user the full path. But in the case
  4129. where a catalog comes from an oem location, there might be some benefit
  4130. to telling the user the full path.
  4131. DeviceDesc - Optionally, supplies the device description to be used in the
  4132. digital signature verification error dialogs that may be popped up.
  4133. Return Value:
  4134. NONE.
  4135. --*/
  4136. {
  4137. PSETUP_LOG_CONTEXT lc = NULL;
  4138. MYASSERT(Error != NO_ERROR);
  4139. MYASSERT(ProblemFile != NULL);
  4140. if (!LogContext) {
  4141. if (CreateLogContext(NULL, TRUE, &lc) == NO_ERROR) {
  4142. //
  4143. // success
  4144. //
  4145. LogContext = lc;
  4146. } else {
  4147. lc = NULL;
  4148. }
  4149. }
  4150. //
  4151. // a device install failed
  4152. //
  4153. WriteLogEntry(
  4154. LogContext,
  4155. SETUP_LOG_ERROR | SETUP_LOG_BUFFER,
  4156. MessageId,
  4157. NULL,
  4158. ProblemFile,
  4159. DeviceDesc);
  4160. WriteLogError(
  4161. LogContext,
  4162. SETUP_LOG_ERROR,
  4163. Error);
  4164. if (lc) {
  4165. DeleteLogContext(lc);
  4166. }
  4167. }
  4168. BOOL
  4169. pSetupHandleFailedVerification(
  4170. IN HWND Owner,
  4171. IN SetupapiVerifyProblem Problem,
  4172. IN LPCTSTR ProblemFile,
  4173. IN LPCTSTR DeviceDesc, OPTIONAL
  4174. IN DWORD DriverSigningPolicy,
  4175. IN BOOL NoUI,
  4176. IN DWORD Error,
  4177. IN PVOID LogContext, OPTIONAL
  4178. OUT PDWORD Flags, OPTIONAL
  4179. IN LPCTSTR TargetFile OPTIONAL
  4180. )
  4181. /*++
  4182. Routine Description:
  4183. This routine deals with a failed verification.
  4184. System policy is checked. If the policy is block, UI is displayed telling
  4185. the user that they're hosed. If the policy is ask-user, then ui is
  4186. displayed requesting the user's decision about whether to ignore the
  4187. verification failure and take the risk. If the policy is ignore, nothing
  4188. is done.
  4189. Arguments:
  4190. Owner - supplies window to own the dialog.
  4191. Problem - supplies a constant indicating what caused the failure. There are
  4192. 5 cases:
  4193. Catalog, meaning that the catalog could not be verified
  4194. CatalogInstall, some other problem occured (e.g., INF directory write-
  4195. protected, thus we couldn't install placeholder INF)
  4196. Inf, meaning that an inf could not be verified or installed, etc.
  4197. File, meaning that some random other file failed verification.
  4198. DriverBlocked, meaning the driver was in the bad driver database.
  4199. ProblemFile - supplies the file path to the file associated with
  4200. the problem. In some cases this is a full path, in others it's just a
  4201. filename. The caller decides which makes sense in a particular
  4202. scenario. For example, a system catalog is in some funky directory
  4203. and there is no need to tell the user the full path. But in the case
  4204. where a catalog comes from an oem location, there might be some benefit
  4205. to telling the user the full path.
  4206. NOTE: if this API is being called because of a blocked driver then a
  4207. full path should always be passed in.
  4208. DeviceDesc - Optionally, supplies the device description to be used in the
  4209. digital signature verification error dialogs that may be popped up.
  4210. DriverSigningPolicy - supplies the driver signing policy currently in
  4211. effect. May be one of the three following values:
  4212. DRIVERSIGN_NONE - silently succeed installation of unsigned/
  4213. incorrectly-signed files. A PSS log entry will
  4214. be generated, however.
  4215. DRIVERSIGN_WARNING - warn the user, but let them choose whether or not
  4216. they still want to install the problematic file.
  4217. If the user elects to proceed with the
  4218. installation, A PSS log entry will be generated
  4219. noting this fact.
  4220. DRIVERSIGN_BLOCKING - do not allow the file to be installed
  4221. NoUI - if TRUE, then a dialog box should not be displayed to the user, even
  4222. if policy is warn or block. This will typically be set to TRUE after
  4223. the user has previously been informed of a digital signature problem
  4224. with the package they're attempting to install, but have elected to
  4225. proceed with the installation anyway. The behavior of the "Yes" button,
  4226. then, is really a "yes to all".
  4227. Error - supplies the code of the error that caused the failure.
  4228. LogContext - optionally supplies a pointer to the context for logging.
  4229. If this is not supplied, errors will be logged to the default context.
  4230. This is declared as a PVOID so external functions don't need to know
  4231. what a SETUP_LOG_CONTEXT is.
  4232. Flags - optionally supplies a pointer to a DWORD that receives one or more
  4233. of the following file queue node flags indicating that we made an
  4234. exemption for installing a protected system file:
  4235. IQF_TARGET_PROTECTED - TargetFile (see below) is a protected system
  4236. file.
  4237. IQF_ALLOW_UNSIGNED - An exception has been granted so that TargetFile
  4238. (see below) may be replaced by an unsigned file.
  4239. TargetFile - optionally supplies a pointer to a string that specifies a
  4240. destination file if one exists. This is only used if we want to exempt
  4241. a file operation on this file. If this parameter is not specified, then
  4242. it is assumed the file will _not_ be replaced (i.e., it may already be
  4243. on the system in its unsigned state), and no SFP exemption will be
  4244. attempted.
  4245. Return Value:
  4246. Boolean value indicating whether the caller should continue.
  4247. If FALSE, then the current operation should be aborted, as the combination
  4248. of system policy and user input indicated that the risk should not
  4249. be taken.
  4250. --*/
  4251. {
  4252. BOOL b;
  4253. INT_PTR iRes;
  4254. CERT_PROMPT CertPrompt;
  4255. HANDLE hDialogEvent = NULL;
  4256. //
  4257. // If we're running non-interactive, then we always silently block,
  4258. // regardless of policy.
  4259. //
  4260. if(GlobalSetupFlags & PSPGF_NONINTERACTIVE) {
  4261. //
  4262. // SPLOG -- log a PSS entry recording this event.
  4263. //
  4264. if (Problem == SetupapiVerifyDriverBlocked) {
  4265. LogFailedVerification(
  4266. (PSETUP_LOG_CONTEXT) LogContext,
  4267. DeviceDesc ? MSG_LOG_DRIVER_BLOCKED_FOR_DEVICE_ERROR_NONINTERACTIVE : MSG_LOG_DRIVER_BLOCKED_ERROR_NONINTERACTIVE,
  4268. Error,
  4269. ProblemFile,
  4270. DeviceDesc);
  4271. } else {
  4272. LogFailedVerification(
  4273. (PSETUP_LOG_CONTEXT) LogContext,
  4274. DeviceDesc ? MSG_LOG_DRIVER_SIGNING_ERROR_NONINTERACTIVE : MSG_LOG_SIGNING_ERROR_NONINTERACTIVE,
  4275. Error,
  4276. ProblemFile,
  4277. DeviceDesc);
  4278. }
  4279. return FALSE;
  4280. }
  4281. if (GuiSetupInProgress) {
  4282. hDialogEvent = CreateEvent(NULL,TRUE,FALSE,SETUP_HAS_OPEN_DIALOG_EVENT);
  4283. }
  4284. #ifdef UNICODE
  4285. if (Problem == SetupapiVerifyDriverBlocked) {
  4286. //
  4287. // Handle a driver block failure.
  4288. // only applicable to UNICODE
  4289. // ANSI won't report this problem code
  4290. //
  4291. HSDB hSDBDrvMain = NULL;
  4292. TAGREF tagref = TAGREF_NULL;
  4293. DRIVERBLOCK_PROMPT DriverBlockPrompt = {0};
  4294. //
  4295. // Never continue if the driver is in the bad driver database!
  4296. //
  4297. b = FALSE;
  4298. LogFailedVerification(
  4299. (PSETUP_LOG_CONTEXT) LogContext,
  4300. DeviceDesc ? MSG_LOG_DRIVER_BLOCKED_FOR_DEVICE_ERROR : MSG_LOG_DRIVER_BLOCKED_ERROR,
  4301. Error,
  4302. ProblemFile,
  4303. DeviceDesc);
  4304. if (!(GlobalSetupFlags & PSPGF_UNATTENDED_SETUP)) {
  4305. //
  4306. // Show the driver blocking UI
  4307. //
  4308. DriverBlockPrompt.lpszFile = (TargetFile != NULL)
  4309. ? TargetFile
  4310. : ProblemFile;
  4311. if ((hSDBDrvMain = SdbInitDatabase(SDB_DATABASE_MAIN_DRIVERS, NULL))) {
  4312. HANDLE hFile = INVALID_HANDLE_VALUE;
  4313. //
  4314. // We are probably dealing with a temp file name at this point,
  4315. // so we need to get a file handle to pass to SdbGetDatabaseMatch
  4316. // along with the final destination file name.
  4317. //
  4318. hFile = CreateFile(ProblemFile,
  4319. GENERIC_READ,
  4320. FILE_SHARE_READ,
  4321. NULL,
  4322. OPEN_EXISTING,
  4323. 0,
  4324. NULL
  4325. );
  4326. if (hFile != INVALID_HANDLE_VALUE) {
  4327. //
  4328. // Pass the TargetFile (the destination filename) to
  4329. // SdbGetDatabaseMatch because that will be what is
  4330. // in the bad driver database.
  4331. //
  4332. tagref = SdbGetDatabaseMatch(hSDBDrvMain,
  4333. (TargetFile != NULL)
  4334. ? pSetupGetFileTitle(TargetFile)
  4335. : ProblemFile,
  4336. hFile,
  4337. NULL,
  4338. 0);
  4339. if (tagref != TAGREF_NULL) {
  4340. SdbReadDriverInformation(hSDBDrvMain,
  4341. tagref,
  4342. &(DriverBlockPrompt.entryinfo));
  4343. }
  4344. CloseHandle(hFile);
  4345. }
  4346. SdbReleaseDatabase(hSDBDrvMain);
  4347. }
  4348. //
  4349. // Always call the dialog code, even if we could access the database.
  4350. //
  4351. iRes = DialogBoxParam(MyDllModuleHandle,
  4352. MAKEINTRESOURCE(IDD_DRIVERBLOCK),
  4353. IsWindow(Owner) ? Owner : NULL,
  4354. DriverBlockDlgProc,
  4355. (LPARAM)&DriverBlockPrompt
  4356. );
  4357. }
  4358. } else
  4359. #endif
  4360. {
  4361. //
  4362. // Handle a digital signature failure.
  4363. //
  4364. // If the policy is block, then the user always gets informed of a problem
  4365. // (i.e., there is no "yes" option, hence no "yes to all" semantics).
  4366. //
  4367. MYASSERT((DriverSigningPolicy != DRIVERSIGN_BLOCKING) || !NoUI);
  4368. CertPrompt.lpszDescription = DeviceDesc;
  4369. CertPrompt.lpszFile = ProblemFile;
  4370. CertPrompt.ProblemType = Problem;
  4371. CertPrompt.DriverSigningPolicy = DriverSigningPolicy;
  4372. switch(DriverSigningPolicy) {
  4373. case DRIVERSIGN_NONE :
  4374. //
  4375. // SPLOG -- log a PSS entry recording this event.
  4376. //
  4377. LogFailedVerification(
  4378. (PSETUP_LOG_CONTEXT) LogContext,
  4379. DeviceDesc ? MSG_LOG_DRIVER_SIGNING_ERROR_POLICY_NONE : MSG_LOG_SIGNING_ERROR_POLICY_NONE,
  4380. Error,
  4381. ProblemFile,
  4382. DeviceDesc);
  4383. //
  4384. // If requested, find out if the file is protected (we may need to
  4385. // skip it if it's being queued up for delayed copy).
  4386. //
  4387. if(Flags && TargetFile) {
  4388. if(IsFileProtected(TargetFile,
  4389. (PSETUP_LOG_CONTEXT)LogContext,
  4390. NULL)) {
  4391. *Flags = IQF_TARGET_PROTECTED;
  4392. }
  4393. }
  4394. b = TRUE;
  4395. goto exit;
  4396. case DRIVERSIGN_WARNING :
  4397. if(NoUI) {
  4398. //
  4399. // SPLOG -- log a PSS entry recording this event.
  4400. //
  4401. LogFailedVerification(
  4402. (PSETUP_LOG_CONTEXT) LogContext,
  4403. DeviceDesc ? MSG_LOG_DRIVER_SIGNING_ERROR_AUTO_YES : MSG_LOG_SIGNING_ERROR_AUTO_YES,
  4404. Error,
  4405. ProblemFile,
  4406. DeviceDesc);
  4407. iRes = IDC_VERIFY_WARN_YES;
  4408. } else if(GlobalSetupFlags & PSPGF_UNATTENDED_SETUP) {
  4409. //
  4410. // SPLOG -- log a PSS entry recording this event.
  4411. //
  4412. LogFailedVerification(
  4413. (PSETUP_LOG_CONTEXT) LogContext,
  4414. DeviceDesc ? MSG_LOG_DRIVER_SIGNING_ERROR_AUTO_NO : MSG_LOG_SIGNING_ERROR_AUTO_NO,
  4415. Error,
  4416. ProblemFile,
  4417. DeviceDesc);
  4418. iRes = IDC_VERIFY_WARN_NO;
  4419. } else {
  4420. if (hDialogEvent) {
  4421. SetEvent(hDialogEvent);
  4422. }
  4423. iRes = DialogBoxParam(MyDllModuleHandle,
  4424. CertPrompt.lpszDescription ?
  4425. MAKEINTRESOURCE(IDD_DEVICE_VERIFY_WARNING) :
  4426. MAKEINTRESOURCE(IDD_SOFTWARE_VERIFY_WARNING),
  4427. IsWindow(Owner) ? Owner : NULL,
  4428. CertifyDlgProc,
  4429. (LPARAM)&CertPrompt
  4430. );
  4431. LogFailedVerification(
  4432. (PSETUP_LOG_CONTEXT) LogContext,
  4433. DeviceDesc
  4434. ?(iRes == IDC_VERIFY_WARN_YES ? MSG_LOG_DRIVER_SIGNING_ERROR_WARN_YES : MSG_LOG_DRIVER_SIGNING_ERROR_WARN_NO)
  4435. :(iRes == IDC_VERIFY_WARN_YES ? MSG_LOG_SIGNING_ERROR_WARN_YES : MSG_LOG_SIGNING_ERROR_WARN_NO),
  4436. Error,
  4437. ProblemFile,
  4438. DeviceDesc);
  4439. }
  4440. break;
  4441. case DRIVERSIGN_BLOCKING :
  4442. if(GlobalSetupFlags & PSPGF_UNATTENDED_SETUP) {
  4443. //
  4444. // During UNATTENDED, we block silently
  4445. //
  4446. LogFailedVerification(
  4447. (PSETUP_LOG_CONTEXT) LogContext,
  4448. DeviceDesc ? MSG_LOG_DRIVER_SIGNING_ERROR_SILENT_BLOCK : MSG_LOG_SIGNING_ERROR_SILENT_BLOCK,
  4449. Error,
  4450. ProblemFile,
  4451. DeviceDesc);
  4452. iRes = IDC_VERIFY_BLOCK_OK;
  4453. } else {
  4454. LogFailedVerification(
  4455. (PSETUP_LOG_CONTEXT) LogContext,
  4456. DeviceDesc ? MSG_LOG_DRIVER_SIGNING_ERROR_POLICY_BLOCK : MSG_LOG_SIGNING_ERROR_POLICY_BLOCK,
  4457. Error,
  4458. ProblemFile,
  4459. DeviceDesc);
  4460. if (hDialogEvent) {
  4461. SetEvent(hDialogEvent);
  4462. }
  4463. iRes = DialogBoxParam(MyDllModuleHandle,
  4464. CertPrompt.lpszDescription ?
  4465. MAKEINTRESOURCE(IDD_DEVICE_VERIFY_BLOCK) :
  4466. MAKEINTRESOURCE(IDD_SOFTWARE_VERIFY_BLOCK),
  4467. IsWindow(Owner) ? Owner : NULL,
  4468. CertifyDlgProc,
  4469. (LPARAM)&CertPrompt
  4470. );
  4471. }
  4472. break;
  4473. default :
  4474. //
  4475. // We don't know about any other policy values!
  4476. //
  4477. MYASSERT(0);
  4478. b = FALSE;
  4479. goto exit;
  4480. }
  4481. switch(iRes) {
  4482. case IDC_VERIFY_WARN_NO:
  4483. case IDC_VERIFY_BLOCK_OK:
  4484. b = FALSE;
  4485. break;
  4486. case IDC_VERIFY_WARN_YES:
  4487. if(TargetFile) {
  4488. pSetupExemptFileFromProtection(TargetFile,
  4489. (DWORD) -1,
  4490. (PSETUP_LOG_CONTEXT)LogContext,
  4491. Flags
  4492. );
  4493. }
  4494. b = TRUE;
  4495. break;
  4496. default:
  4497. //
  4498. // Shouldn't get any other values.
  4499. //
  4500. MYASSERT(0);
  4501. b = FALSE;
  4502. }
  4503. }
  4504. exit:
  4505. if (hDialogEvent) {
  4506. ResetEvent(hDialogEvent);
  4507. CloseHandle(hDialogEvent);
  4508. }
  4509. return b;
  4510. }
  4511. INT_PTR
  4512. CALLBACK
  4513. CertifyDlgProc(
  4514. IN HWND hwnd,
  4515. IN UINT msg,
  4516. IN WPARAM wParam,
  4517. IN LPARAM lParam
  4518. )
  4519. /*++
  4520. Routine Description:
  4521. This is the dialog procedure for the driver signing UI that is presented to
  4522. the user when a verification failure is encountered. This dialog handles
  4523. both the 'warn' and 'block' cases.
  4524. --*/
  4525. {
  4526. UINT MessageLen;
  4527. LOGFONT LogFont;
  4528. HFONT hFontBold = NULL;
  4529. HICON hIcon = NULL;
  4530. PCERT_PROMPT lpCertPrompt;
  4531. lpCertPrompt = (PCERT_PROMPT)GetWindowLongPtr(hwnd, DWLP_USER);
  4532. switch(msg) {
  4533. case WM_INITDIALOG:
  4534. SetWindowLongPtr(hwnd, DWLP_USER, lParam);
  4535. MessageBeep(MB_ICONASTERISK);
  4536. lpCertPrompt = (PCERT_PROMPT)lParam;
  4537. //
  4538. // If lpszDescription is not NULL then this is the device verify
  4539. // warning dialog, otherwise it is the software warning dialog.
  4540. //
  4541. if(lpCertPrompt->lpszDescription != NULL) {
  4542. SetDlgItemText(hwnd, IDC_VERIFY_FILENAME, lpCertPrompt->lpszDescription);
  4543. SetDlgText(hwnd, IDC_VERIFY_BOLD, IDS_DEVICE_VERIFY_MSG1, IDS_DEVICE_VERIFY_MSG2);
  4544. } else {
  4545. SetDlgText(hwnd, IDC_VERIFY_BOLD, IDS_SOFTWARE_VERIFY_MSG1, IDS_SOFTWARE_VERIFY_MSG2);
  4546. }
  4547. //
  4548. // Create the bold font and bold any necessary text.
  4549. //
  4550. hFontBold = (HFONT)SendMessage(GetDlgItem(hwnd, IDC_VERIFY_BOLD),
  4551. WM_GETFONT, 0, 0);
  4552. GetObject(hFontBold, sizeof(LogFont), &LogFont);
  4553. LogFont.lfWeight = FW_BOLD;
  4554. hFontBold = CreateFontIndirect(&LogFont);
  4555. if (hFontBold) {
  4556. SetWindowFont(GetDlgItem(hwnd, IDC_VERIFY_BOLD), hFontBold, TRUE);
  4557. }
  4558. //
  4559. // Set the appropriate warning or error icon.
  4560. //
  4561. hIcon = LoadIcon(NULL,
  4562. (lpCertPrompt->DriverSigningPolicy == DRIVERSIGN_WARNING) ?
  4563. IDI_WARNING :
  4564. IDI_ERROR
  4565. );
  4566. SendDlgItemMessage(hwnd, IDC_VERIFY_ICON, STM_SETICON, (WPARAM)hIcon, 0L);
  4567. //
  4568. // The link won't work in GUI mode setup since help center has not yet
  4569. // been installed, so we will just show the static text instead.
  4570. //
  4571. ShowWindow(GetDlgItem(hwnd, IDC_VERIFY_TESTING_LINK), !GuiSetupInProgress);
  4572. ShowWindow(GetDlgItem(hwnd, IDC_VERIFY_TESTING_TEXT), GuiSetupInProgress);
  4573. //
  4574. // If we are in GUI mode setup then we want to change the text of
  4575. // the buttons to be "Yes" and "No". We also add the following line
  4576. // of text: "Do you want to continue installing the software for
  4577. // this hardware?"
  4578. //
  4579. ShowWindow(GetDlgItem(hwnd, IDC_VERIFY_SETUP_TEXT), GuiSetupInProgress);
  4580. if (GuiSetupInProgress) {
  4581. TCHAR szButtonText[MAX_PATH];
  4582. if (LoadString(MyDllModuleHandle, IDS_YES, szButtonText, SIZECHARS(szButtonText))) {
  4583. SetDlgItemText(hwnd, IDC_VERIFY_WARN_YES, szButtonText);
  4584. }
  4585. if (LoadString(MyDllModuleHandle, IDS_NO, szButtonText, SIZECHARS(szButtonText))) {
  4586. SetDlgItemText(hwnd, IDC_VERIFY_WARN_NO, szButtonText);
  4587. }
  4588. }
  4589. //
  4590. // Make sure this dialog is in the foreground (at least for this
  4591. // process).
  4592. //
  4593. SetForegroundWindow(hwnd);
  4594. if (lpCertPrompt->DriverSigningPolicy == DRIVERSIGN_WARNING) {
  4595. SetFocus(GetDlgItem(hwnd, IDC_VERIFY_WARN_NO));
  4596. }
  4597. return FALSE;
  4598. case WM_DESTROY:
  4599. if (hFontBold) {
  4600. DeleteObject(hFontBold);
  4601. hFontBold = NULL;
  4602. }
  4603. if (hIcon) {
  4604. DestroyIcon(hIcon);
  4605. }
  4606. break;
  4607. case WM_NOTIFY:
  4608. switch (((NMHDR FAR *)lParam)->code) {
  4609. case NM_RETURN:
  4610. case NM_CLICK:
  4611. ShellExecute(hwnd,
  4612. TEXT("open"),
  4613. TEXT("HELPCTR.EXE"),
  4614. TEXT("HELPCTR.EXE -url hcp://services/subsite?node=TopLevelBucket_4/Hardware&topic=MS-ITS%3A%25HELP_LOCATION%25%5Csysdm.chm%3A%3A/logo_testing.htm"),
  4615. NULL,
  4616. SW_SHOWNORMAL
  4617. );
  4618. break;
  4619. }
  4620. break;
  4621. case WM_COMMAND:
  4622. switch(wParam) {
  4623. case IDC_VERIFY_WARN_NO:
  4624. case IDC_VERIFY_WARN_YES:
  4625. case IDC_VERIFY_BLOCK_OK:
  4626. EndDialog(hwnd, (int)wParam);
  4627. break;
  4628. default:
  4629. break;
  4630. }
  4631. break;
  4632. default:
  4633. break;
  4634. }
  4635. return FALSE;
  4636. }
  4637. #ifdef UNICODE
  4638. INT_PTR
  4639. CALLBACK
  4640. DriverBlockDlgProc(
  4641. IN HWND hwnd,
  4642. IN UINT msg,
  4643. IN WPARAM wParam,
  4644. IN LPARAM lParam
  4645. )
  4646. /*++
  4647. Routine Description:
  4648. This is the dialog procedure for the driver blocking UI that is presented to
  4649. the user when a a driver that is about to be installed is found in the bad
  4650. driver database.
  4651. --*/
  4652. {
  4653. UINT MessageLen;
  4654. HICON hIcon = NULL;
  4655. LPTSTR pBuffer = NULL;
  4656. ULONG BufferSize;
  4657. static HAPPHELPINFOCONTEXT hAppHelpInfoContext = NULL;
  4658. static SDBENTRYINFO SdbEntryInfo;
  4659. PDRIVERBLOCK_PROMPT lpDriverBlockPrompt;
  4660. lpDriverBlockPrompt = (PDRIVERBLOCK_PROMPT)GetWindowLongPtr(hwnd, DWLP_USER);
  4661. switch(msg) {
  4662. case WM_INITDIALOG:
  4663. SetWindowLongPtr(hwnd, DWLP_USER, lParam);
  4664. MessageBeep(MB_ICONASTERISK);
  4665. lpDriverBlockPrompt = (PDRIVERBLOCK_PROMPT)lParam;
  4666. hIcon = LoadIcon(MyDllModuleHandle,
  4667. MAKEINTRESOURCE(IDI_DRIVERBLOCK));
  4668. SendDlgItemMessage(hwnd, IDC_DRIVERBLOCK_ICON, STM_SETICON, (WPARAM)hIcon, 0L);
  4669. hAppHelpInfoContext = SdbOpenApphelpInformation(&lpDriverBlockPrompt->entryinfo.guidDB,
  4670. &lpDriverBlockPrompt->entryinfo.guidID);
  4671. if ((hAppHelpInfoContext) &&
  4672. ((BufferSize = SdbQueryApphelpInformation(hAppHelpInfoContext,
  4673. ApphelpAppName,
  4674. NULL,
  4675. 0)) != 0) &&
  4676. (pBuffer = MyMalloc(BufferSize)) &&
  4677. ((BufferSize = SdbQueryApphelpInformation(hAppHelpInfoContext,
  4678. ApphelpAppName,
  4679. pBuffer,
  4680. BufferSize)) != 0)) {
  4681. SetDlgItemText(hwnd, IDC_DRIVERBLOCK_APPNAME, pBuffer);
  4682. MyFree(pBuffer);
  4683. } else if (lpDriverBlockPrompt->lpszFile) {
  4684. SetDlgItemText(hwnd, IDC_DRIVERBLOCK_APPNAME, pSetupGetFileTitle(lpDriverBlockPrompt->lpszFile));
  4685. }
  4686. if ((hAppHelpInfoContext) &&
  4687. ((BufferSize = SdbQueryApphelpInformation(hAppHelpInfoContext,
  4688. ApphelpDetails,
  4689. NULL,
  4690. 0)) != 0) &&
  4691. (pBuffer = MyMalloc(BufferSize)) &&
  4692. ((BufferSize = SdbQueryApphelpInformation(hAppHelpInfoContext,
  4693. ApphelpDetails,
  4694. pBuffer,
  4695. BufferSize)) != 0)) {
  4696. SetDlgItemText(hwnd, IDC_DRIVERBLOCK_SUMMARY, pBuffer);
  4697. MyFree(pBuffer);
  4698. }
  4699. //
  4700. // Make sure this dialog is in the foreground (at least for this
  4701. // process).
  4702. //
  4703. SetForegroundWindow(hwnd);
  4704. return FALSE;
  4705. case WM_DESTROY:
  4706. if (hIcon) {
  4707. DestroyIcon(hIcon);
  4708. }
  4709. if (hAppHelpInfoContext) {
  4710. SdbCloseApphelpInformation(hAppHelpInfoContext);
  4711. }
  4712. break;
  4713. case WM_COMMAND:
  4714. switch(LOWORD(wParam)) {
  4715. case IDCANCEL:
  4716. EndDialog(hwnd, (int)wParam);
  4717. break;
  4718. case IDC_DRIVERBLOCK_DETAILS:
  4719. if (hAppHelpInfoContext) {
  4720. BufferSize = SdbQueryApphelpInformation(hAppHelpInfoContext,
  4721. ApphelpHelpCenterURL,
  4722. NULL,
  4723. 0);
  4724. if (BufferSize && (pBuffer = MyMalloc(BufferSize + (lstrlen(TEXT("HELPCTR.EXE -url ")) * sizeof(TCHAR))))) {
  4725. lstrcpy(pBuffer, TEXT("HELPCTR.EXE -url "));
  4726. BufferSize = SdbQueryApphelpInformation(hAppHelpInfoContext,
  4727. ApphelpHelpCenterURL,
  4728. (PVOID)&pBuffer[lstrlen(TEXT("HELPCTR.EXE -url "))],
  4729. BufferSize);
  4730. if (BufferSize) {
  4731. ShellExecute(hwnd,
  4732. TEXT("open"),
  4733. TEXT("HELPCTR.EXE"),
  4734. pBuffer,
  4735. NULL,
  4736. SW_SHOWNORMAL);
  4737. }
  4738. MyFree(pBuffer);
  4739. }
  4740. }
  4741. break;
  4742. default:
  4743. break;
  4744. }
  4745. break;
  4746. default:
  4747. break;
  4748. }
  4749. return FALSE;
  4750. }
  4751. #endif
  4752. DWORD
  4753. pGetInfOriginalNameAndCatalogFile(
  4754. IN PLOADED_INF Inf, OPTIONAL
  4755. IN LPCTSTR CurrentName, OPTIONAL
  4756. OUT PBOOL DifferentName, OPTIONAL
  4757. OUT LPTSTR OriginalName, OPTIONAL
  4758. IN DWORD OriginalNameSize,
  4759. OUT LPTSTR OriginalCatalogName, OPTIONAL
  4760. IN DWORD OriginalCatalogNameSize,
  4761. IN PSP_ALTPLATFORM_INFO_V2 AltPlatformInfo OPTIONAL
  4762. )
  4763. /*++
  4764. Routine Description:
  4765. This routine determines whether a specified inf once had a different
  4766. original name, such as in the case where the Di stuff copied and renamed a
  4767. device inf.
  4768. (Information about an INF's original name comes from the PNF.)
  4769. This routine can also optionally return the original name of the catalog
  4770. file for this INF.
  4771. Arguments:
  4772. Inf - optionally, supplies a pointer to a LOADED_INF whose original name
  4773. and catalog file are to be queried. If this parameter isn't specified,
  4774. then CurrentName must be specified.
  4775. CurrentName - optionally, supplies the path to the INF whose original name
  4776. is to be queried. If Inf parameter is specified, this parameter is
  4777. ignored.
  4778. DifferentName - optionally, supplies the address of a boolean variable that,
  4779. upon successful return, is set to TRUE if the INF's current name is
  4780. different than its original name.
  4781. OriginalName - if this routine returns successfully, and the DifferentName
  4782. boolean was set to TRUE, then this optional buffer receives
  4783. the INF's original name, which _will not_ be the same as the current
  4784. name.
  4785. OriginalNameSize - supplies size of buffer (bytes for ansi, chars for
  4786. unicode) of OriginalName buffer, or zero if OriginalName is NULL.
  4787. OriginalCatalogName - optionally, supplies a buffer that receives the
  4788. original name of the catalog specified by this INF. If the catalog
  4789. doesn't specify a catalog file, this buffer will be set to an empty
  4790. string.
  4791. OriginalCatalogNameSize - supplies size, in characters, of
  4792. OriginalCatalogName buffer (zero if buffer not supplied).
  4793. AltPlatformInfo - optionally, supplies the address of a structure describing
  4794. the platform parameters that should be used in formulating the decorated
  4795. CatalogFile= entry to be used when searching for the INF's associated
  4796. catalog file.
  4797. Return Value:
  4798. If information is successfully retrieved from the INF, the return value is
  4799. NO_ERROR. Otherwise, it is a Win32 error code indicating the cause of
  4800. failure.
  4801. --*/
  4802. {
  4803. DWORD d;
  4804. HINF hInf = INVALID_HANDLE_VALUE;
  4805. MYASSERT((DifferentName && OriginalName && OriginalNameSize) ||
  4806. !(DifferentName || OriginalName || OriginalNameSize));
  4807. MYASSERT((OriginalCatalogName && OriginalCatalogNameSize) ||
  4808. !(OriginalCatalogName || OriginalCatalogNameSize));
  4809. MYASSERT(Inf || CurrentName);
  4810. if(DifferentName) {
  4811. *DifferentName = FALSE;
  4812. }
  4813. if(!Inf) {
  4814. //
  4815. // Open the INF.
  4816. //
  4817. hInf = SetupOpenInfFile(CurrentName,
  4818. NULL,
  4819. INF_STYLE_OLDNT | INF_STYLE_WIN4,
  4820. NULL
  4821. );
  4822. if(hInf == INVALID_HANDLE_VALUE) {
  4823. return GetLastError();
  4824. }
  4825. //
  4826. // We don't need to lock the INF because it'll never be accessible
  4827. // outside of this routine.
  4828. //
  4829. Inf = (PLOADED_INF)hInf;
  4830. }
  4831. //
  4832. // Enclose in try/except in case we hit an inpage error while using this
  4833. // memory-mapped image.
  4834. //
  4835. d = NO_ERROR;
  4836. try {
  4837. if(DifferentName) {
  4838. if(Inf->OriginalInfName) {
  4839. lstrcpyn(OriginalName, Inf->OriginalInfName, OriginalNameSize);
  4840. *DifferentName = TRUE;
  4841. }
  4842. }
  4843. if(OriginalCatalogName) {
  4844. if(!pSetupGetCatalogFileValue(&(Inf->VersionBlock),
  4845. OriginalCatalogName,
  4846. OriginalCatalogNameSize,
  4847. AltPlatformInfo)) {
  4848. //
  4849. // The INF didn't specify an associated catalog file
  4850. //
  4851. *OriginalCatalogName = TEXT('\0');
  4852. }
  4853. }
  4854. } except(EXCEPTION_EXECUTE_HANDLER) {
  4855. //
  4856. // If we hit an AV, then use invalid parameter error, otherwise, assume
  4857. // an inpage error when dealing with a mapped-in file.
  4858. //
  4859. d = (GetExceptionCode() == EXCEPTION_ACCESS_VIOLATION) ? ERROR_INVALID_PARAMETER : ERROR_READ_FAULT;
  4860. }
  4861. if(hInf != INVALID_HANDLE_VALUE) {
  4862. SetupCloseInfFile(hInf);
  4863. }
  4864. return d;
  4865. }
  4866. #ifdef UNICODE
  4867. PSECURITY_DESCRIPTOR
  4868. pSetupConvertTextToSD(
  4869. IN PCWSTR SDS,
  4870. OUT PULONG SecDescSize
  4871. )
  4872. /*++
  4873. Routine Description:
  4874. Helper for cfgmgr.lib
  4875. Obtains a binary security descriptor from an SDS
  4876. Resulting buffer must be free'd using LocalFree (not MyFree)
  4877. returns NULL if not supported and sets last error
  4878. Arguments:
  4879. SDS - string to obtain security descriptor from
  4880. SecDescSize - filled in with size of security descriptor
  4881. Return Value:
  4882. returns security descriptor (use LocalFree to release)
  4883. or NULL with GetLastError indicating error
  4884. --*/
  4885. {
  4886. SCESTATUS status;
  4887. PSECURITY_DESCRIPTOR pSD = NULL;
  4888. ULONG ulSDSize;
  4889. SECURITY_INFORMATION siSeInfo;
  4890. //
  4891. // If we're in "Disable SCE" mode on embedded, don't do security stuff...
  4892. //
  4893. if(GlobalSetupFlags & PSPGF_NO_SCE_EMBEDDED) {
  4894. SetLastError(ERROR_SCE_DISABLED);
  4895. return NULL;
  4896. }
  4897. try {
  4898. status = SceSvcConvertTextToSD((PWSTR)SDS,&pSD,&ulSDSize,&siSeInfo);
  4899. switch (status ) {
  4900. case SCESTATUS_SUCCESS:
  4901. MYASSERT(pSD);
  4902. MYASSERT(ulSDSize);
  4903. if (SecDescSize) {
  4904. *SecDescSize = ulSDSize;
  4905. }
  4906. SetLastError(NO_ERROR);
  4907. break;
  4908. case SCESTATUS_INVALID_PARAMETER:
  4909. SetLastError(ERROR_INVALID_PARAMETER);
  4910. pSD = NULL;
  4911. break;
  4912. case SCESTATUS_NOT_ENOUGH_RESOURCE:
  4913. SetLastError(ERROR_NOT_ENOUGH_MEMORY);
  4914. pSD = NULL;
  4915. break;
  4916. case SCESTATUS_RECORD_NOT_FOUND:
  4917. default:
  4918. SetLastError(ERROR_INVALID_DATA);
  4919. pSD = NULL;
  4920. }
  4921. } except(EXCEPTION_EXECUTE_HANDLER) {
  4922. //
  4923. // If we hit an AV, then use invalid parameter error, otherwise, assume
  4924. // an inpage error when dealing with a mapped-in file.
  4925. //
  4926. SetLastError(ERROR_INVALID_DATA);
  4927. pSD = NULL;
  4928. }
  4929. return pSD;
  4930. }
  4931. PWSTR
  4932. pSetupConvertSDToText(
  4933. IN PSECURITY_DESCRIPTOR SD,
  4934. OUT PULONG pSDSSize
  4935. )
  4936. /*++
  4937. Routine Description:
  4938. Helper for cfgmgr.lib
  4939. Obtains an SDS from a binary security descriptor
  4940. Resulting buffer must be free'd using LocalFree (not MyFree)
  4941. returns NULL if not supported and sets last error
  4942. Arguments:
  4943. SD - security descriptor to convert to a string
  4944. pSDSSize - return size of string
  4945. Return Value:
  4946. returns security descriptor string (use LocalFree to release)
  4947. or NULL with GetLastError indicating error
  4948. --*/
  4949. {
  4950. HINSTANCE Dll_Handle;
  4951. FARPROC SceFileProc;
  4952. SCESTATUS status;
  4953. DWORD LoadStatus;
  4954. SECURITY_INFORMATION securityInformation = 0;
  4955. PSID sid;
  4956. PACL acl;
  4957. BOOLEAN tmp,present;
  4958. LPWSTR SDS = NULL;
  4959. ULONG ulSSDSize;
  4960. SECURITY_INFORMATION siSeInfo;
  4961. //
  4962. // If we're in "Disable SCE" mode on embedded, don't do security stuff...
  4963. //
  4964. if(GlobalSetupFlags & PSPGF_NO_SCE_EMBEDDED) {
  4965. //
  4966. // Report an empty string
  4967. //
  4968. return LocalAlloc(LPTR, sizeof(WCHAR)); // LPTR zeroes out the char
  4969. }
  4970. try {
  4971. //
  4972. // find out what relevent information is in the descriptor
  4973. // up a securityInformation block to go with it.
  4974. //
  4975. status = RtlGetOwnerSecurityDescriptor(SD, &sid, &tmp);
  4976. if(NT_SUCCESS(status) && (sid != NULL)) {
  4977. securityInformation |= OWNER_SECURITY_INFORMATION;
  4978. }
  4979. status = RtlGetGroupSecurityDescriptor(SD, &sid, &tmp);
  4980. if(NT_SUCCESS(status) && (sid != NULL)) {
  4981. securityInformation |= GROUP_SECURITY_INFORMATION;
  4982. }
  4983. status = RtlGetSaclSecurityDescriptor(SD,
  4984. &present,
  4985. &acl,
  4986. &tmp);
  4987. if(NT_SUCCESS(status) && (present)) {
  4988. securityInformation |= SACL_SECURITY_INFORMATION;
  4989. }
  4990. status = RtlGetDaclSecurityDescriptor(SD,
  4991. &present,
  4992. &acl,
  4993. &tmp);
  4994. if(NT_SUCCESS(status) && (present)) {
  4995. securityInformation |= DACL_SECURITY_INFORMATION;
  4996. }
  4997. //
  4998. // now obtain an SDS
  4999. //
  5000. status = SceSvcConvertSDToText(SD,securityInformation,&SDS,&ulSSDSize);
  5001. switch (status ) {
  5002. case SCESTATUS_SUCCESS:
  5003. MYASSERT(SDS);
  5004. MYASSERT(ulSSDSize);
  5005. if(pSDSSize != NULL) {
  5006. *pSDSSize = ulSSDSize;
  5007. }
  5008. SetLastError(NO_ERROR);
  5009. break;
  5010. case SCESTATUS_INVALID_PARAMETER:
  5011. SetLastError(ERROR_INVALID_PARAMETER);
  5012. SDS = NULL;
  5013. break;
  5014. case SCESTATUS_NOT_ENOUGH_RESOURCE:
  5015. SetLastError(ERROR_NOT_ENOUGH_MEMORY);
  5016. SDS = NULL;
  5017. break;
  5018. case SCESTATUS_RECORD_NOT_FOUND:
  5019. default:
  5020. SetLastError(ERROR_INVALID_DATA);
  5021. SDS = NULL;
  5022. }
  5023. } except(EXCEPTION_EXECUTE_HANDLER) {
  5024. if (SDS) {
  5025. LocalFree(SDS);
  5026. }
  5027. SetLastError(ERROR_INVALID_DATA);
  5028. SDS = NULL;
  5029. }
  5030. return SDS;
  5031. }
  5032. DWORD
  5033. pSetupCallSCE(
  5034. IN DWORD Operation,
  5035. IN PCWSTR FullName,
  5036. IN PSP_FILE_QUEUE Queue,
  5037. IN PCWSTR String1,
  5038. IN DWORD Index1,
  5039. IN PSECURITY_DESCRIPTOR SecDesc OPTIONAL
  5040. )
  5041. /*
  5042. Operation ST_SCE_SET : - Sets security on a File in File Queue and informs SCE database
  5043. FullName : - Filename (Needed)
  5044. Queue : - Pointer to FileQueue (Needed)
  5045. Index : - Index in String Table of Queue (Needed)
  5046. Operation ST_SCE_RENAME : - Sets security on a File in File Queue and informs SCE database to
  5047. record it for the filename mentioned in String1
  5048. FullName : - Filename (Needed)
  5049. Queue : - Pointer to FileQueue (Needed)
  5050. String1 ; - Filename to record in Database (Needed)
  5051. Index : - Index in String Table of Queue (Optional - only if it needs to be set otherwise -1)
  5052. Operation ST_SCE_DELETE : - Removes record of file in SCE database
  5053. FullName : - Filename (Needed)
  5054. Operation ST_SCE_UNWIND : - Used for Backup Unwinds when we reset the security on a dirty file
  5055. FullName : - Filename (Needed)
  5056. SecDesc : - Pointer to Security Descriptor for the original file that we unwind (Needed)
  5057. Operation ST_SCE_SERVICES : - Sets security on a Service and informs SCE database
  5058. FullName : - Service Name (Needed)
  5059. Index : - Service Style (Needed)
  5060. String1 ; - Security Descriptor string
  5061. Operation ST_SCE_SDS_TO_BIN : - Sets security on a Service and informs SCE database
  5062. FullName : - Service Name (Needed)
  5063. Index : - Service Style (Needed)
  5064. String1 ; - Security Descriptor string
  5065. In each case, return value is error or NO_ERROR
  5066. */
  5067. {
  5068. FARPROC SceFileProc;
  5069. PCWSTR SecurityDescriptor;
  5070. HINSTANCE Dll_Handle;
  5071. DWORD ret, LoadStatus;
  5072. //
  5073. // If we're in "Disable SCE" mode on embedded, don't do security stuff...
  5074. //
  5075. if(GlobalSetupFlags & PSPGF_NO_SCE_EMBEDDED) {
  5076. return NO_ERROR;
  5077. }
  5078. try {
  5079. switch (Operation) {
  5080. case ST_SCE_SET:
  5081. //Get the Security descriptor from the String table of the node
  5082. if( Index1 != -1 ){
  5083. SecurityDescriptor = pSetupStringTableStringFromId( Queue->StringTable, Index1 );
  5084. if(!SecurityDescriptor) {
  5085. ret= NO_ERROR;
  5086. break;
  5087. }
  5088. }
  5089. else {
  5090. ret = NO_ERROR;
  5091. break;
  5092. }
  5093. ret = SceSetupUpdateSecurityFile((PWSTR)FullName, 0, (PWSTR)SecurityDescriptor );
  5094. break;
  5095. case ST_SCE_RENAME:
  5096. if( Index1 != -1 ) {
  5097. SecurityDescriptor = pSetupStringTableStringFromId( Queue->StringTable, Index1 );
  5098. } else {
  5099. SecurityDescriptor = NULL;
  5100. }
  5101. ret = SceSetupMoveSecurityFile( (PWSTR)FullName, (PWSTR)String1, (PWSTR)SecurityDescriptor );
  5102. break;
  5103. case ST_SCE_DELETE:
  5104. ret = SceSetupMoveSecurityFile( (PWSTR)FullName, NULL, NULL );
  5105. break;
  5106. case ST_SCE_UNWIND:
  5107. ret = SceSetupUnwindSecurityFile( (PWSTR)FullName, SecDesc );
  5108. break;
  5109. case ST_SCE_SERVICES:
  5110. if( String1 == NULL ){
  5111. ret = NO_ERROR;
  5112. } else {
  5113. ret = SceSetupUpdateSecurityService( (PWSTR)FullName, Index1, (PWSTR)String1 );
  5114. }
  5115. break;
  5116. default:
  5117. MYASSERT(0);
  5118. ret = ERROR_INVALID_DATA;
  5119. }
  5120. } except(EXCEPTION_EXECUTE_HANDLER) {
  5121. ret = ERROR_INVALID_DATA;
  5122. }
  5123. return ret;
  5124. }
  5125. #endif // UNICODE
  5126. VOID
  5127. RestoreBootReplacedFile(
  5128. IN PSP_FILE_QUEUE Queue,
  5129. IN PSP_FILE_QUEUE_NODE QueueNode
  5130. )
  5131. /*++
  5132. Routine Description:
  5133. This routine restores a file that was renamed in preparation for a bootfile
  5134. installation.
  5135. Arguments:
  5136. Queue - queue that contains the bootfile copy operation
  5137. QueueNode - bootfile copy operation being aborted
  5138. Return Value:
  5139. None.
  5140. --*/
  5141. {
  5142. DWORD rc;
  5143. LONG TargetID;
  5144. SP_TARGET_ENT TargetInfo;
  5145. PCTSTR TargetFilename, RenamedFilename;
  5146. BOOL UnPostSucceeded;
  5147. //
  5148. // First, we need to find the corresponding target info node so
  5149. // we can find out what temporary name our file was renamed to.
  5150. //
  5151. rc = pSetupBackupGetTargetByPath((HSPFILEQ)Queue,
  5152. NULL, // use Queue's string table
  5153. NULL,
  5154. QueueNode->TargetDirectory,
  5155. -1,
  5156. QueueNode->TargetFilename,
  5157. &TargetID,
  5158. &TargetInfo
  5159. );
  5160. if(rc == NO_ERROR) {
  5161. //
  5162. // Has the file previously been renamed (and not yet
  5163. // restored)?
  5164. //
  5165. if((TargetInfo.InternalFlags & (SP_TEFLG_MOVED | SP_TEFLG_RESTORED)) == SP_TEFLG_MOVED) {
  5166. TargetFilename = pSetupFormFullPath(
  5167. Queue->StringTable,
  5168. TargetInfo.TargetRoot,
  5169. TargetInfo.TargetSubDir,
  5170. TargetInfo.TargetFilename
  5171. );
  5172. MYASSERT(TargetFilename);
  5173. RenamedFilename = pSetupStringTableStringFromId(
  5174. Queue->StringTable,
  5175. TargetInfo.NewTargetFilename
  5176. );
  5177. MYASSERT(RenamedFilename);
  5178. //
  5179. // Move the renamed file back to its original name.
  5180. //
  5181. RestoreRenamedOrBackedUpFile(TargetFilename,
  5182. RenamedFilename,
  5183. TRUE,
  5184. Queue->LogContext
  5185. );
  5186. //
  5187. // Set the flag indicating that this file has been
  5188. // restored, and save this info.
  5189. //
  5190. TargetInfo.InternalFlags |= SP_TEFLG_RESTORED;
  5191. pSetupBackupSetTargetByID((HSPFILEQ)Queue, TargetID, &TargetInfo);
  5192. //
  5193. // Finally, get rid of the delayed-move node that was to
  5194. // delete the renamed file upon reboot.
  5195. //
  5196. UnPostSucceeded = UnPostDelayedMove(Queue,
  5197. RenamedFilename,
  5198. NULL
  5199. );
  5200. MYASSERT(UnPostSucceeded);
  5201. }
  5202. }
  5203. }
  5204. VOID
  5205. pSetupExemptFileFromProtection(
  5206. IN PCTSTR FileName,
  5207. IN DWORD FileChangeFlags,
  5208. IN PSETUP_LOG_CONTEXT LogContext, OPTIONAL
  5209. OUT PDWORD QueueNodeFlags OPTIONAL
  5210. )
  5211. /*++
  5212. Routine Description:
  5213. This routine checks to see if the specified file is a protected system
  5214. file, and if so, it tells SFC to make a replacement exception for this file.
  5215. Arguments:
  5216. FileName - Supplies the name of the file for which an exception is being
  5217. requested.
  5218. FileChangeFlags - Supplies the flags to be passed to SfcFileException, if
  5219. this file is determined to be under the protection of SFP.
  5220. LogContext - Optionally, supplies the log context to be used when logging
  5221. information resulting from this request.
  5222. QueueNodeFlags - Optionally, supplies the address of a variable that
  5223. receives one or more of the following queue node flags indicating
  5224. whether the specified file is a protected system file, and whether an
  5225. exception was granted for its replacement:
  5226. IQF_TARGET_PROTECTED - File is a protected system file.
  5227. IQF_ALLOW_UNSIGNED - An exception has been granted so that the file
  5228. may be replaced by an unsigned file.
  5229. Return Value:
  5230. None.
  5231. --*/
  5232. {
  5233. #ifdef UNICODE
  5234. HANDLE hSfp;
  5235. PSETUP_LOG_CONTEXT lc = NULL;
  5236. DWORD Result = NO_ERROR;
  5237. if(QueueNodeFlags) {
  5238. *QueueNodeFlags = 0;
  5239. }
  5240. //
  5241. // If the caller didn't supply us with a LogContext, then create our own.
  5242. // We want to do this so that all log entries generated herein will end up
  5243. // in the same section.
  5244. //
  5245. if(!LogContext) {
  5246. if(CreateLogContext(NULL, TRUE, &lc) == NO_ERROR) {
  5247. //
  5248. // success
  5249. //
  5250. LogContext = lc;
  5251. } else {
  5252. lc = NULL;
  5253. }
  5254. }
  5255. if(IsFileProtected(FileName, LogContext, &hSfp)) {
  5256. if(QueueNodeFlags) {
  5257. *QueueNodeFlags = IQF_TARGET_PROTECTED;
  5258. }
  5259. Result = SfcFileException(hSfp,
  5260. (PWSTR)FileName,
  5261. FileChangeFlags
  5262. );
  5263. if(Result == NO_ERROR) {
  5264. WriteLogEntry(
  5265. LogContext,
  5266. SETUP_LOG_ERROR,
  5267. MSG_LOG_SFC_EXEMPT_SUCCESS,
  5268. NULL,
  5269. FileName);
  5270. if(QueueNodeFlags) {
  5271. *QueueNodeFlags |= IQF_ALLOW_UNSIGNED;
  5272. }
  5273. } else {
  5274. WriteLogEntry(
  5275. LogContext,
  5276. SETUP_LOG_ERROR|SETUP_LOG_BUFFER,
  5277. MSG_LOG_SFC_EXEMPT_FAIL,
  5278. NULL,
  5279. FileName);
  5280. WriteLogError(
  5281. LogContext,
  5282. SETUP_LOG_ERROR,
  5283. Result);
  5284. }
  5285. SfcClose(hSfp);
  5286. //
  5287. // If we created our own local LogContext, we can free it now.
  5288. //
  5289. if(lc) {
  5290. DeleteLogContext(lc);
  5291. }
  5292. }
  5293. #else // no file protection on win9x
  5294. if(QueueNodeFlags) {
  5295. *QueueNodeFlags = 0;
  5296. }
  5297. #endif
  5298. }
  5299. BOOL
  5300. pSetupProtectedRenamesFlag(
  5301. BOOL bSet
  5302. )
  5303. {
  5304. HKEY hKey;
  5305. long rslt = ERROR_SUCCESS;
  5306. if (OSVersionInfo.dwPlatformId != VER_PLATFORM_WIN32_NT) {
  5307. return(TRUE);
  5308. }
  5309. rslt = RegOpenKeyEx(
  5310. HKEY_LOCAL_MACHINE,
  5311. TEXT("System\\CurrentControlSet\\Control\\Session Manager"),
  5312. 0,
  5313. KEY_SET_VALUE,
  5314. &hKey);
  5315. if (rslt == ERROR_SUCCESS) {
  5316. DWORD Value = bSet ? 1 : 0;
  5317. rslt = RegSetValueEx(
  5318. hKey,
  5319. TEXT("AllowProtectedRenames"),
  5320. 0,
  5321. REG_DWORD,
  5322. (LPBYTE)&Value,
  5323. sizeof(DWORD));
  5324. RegCloseKey(hKey);
  5325. if (rslt != ERROR_SUCCESS) {
  5326. DebugPrintEx( DPFLTR_ERROR_LEVEL, TEXT("couldn't RegSetValueEx, ec = %d\n"), rslt );
  5327. }
  5328. } else {
  5329. DebugPrintEx( DPFLTR_ERROR_LEVEL, TEXT("couldn't RegOpenKeyEx, ec = %d\n"), rslt );
  5330. }
  5331. return(rslt == ERROR_SUCCESS);
  5332. }
  5333. VOID
  5334. pSetupUninstallNewCatalogNodes(
  5335. IN PSP_FILE_QUEUE Queue,
  5336. IN PSETUP_LOG_CONTEXT LogContext OPTIONAL
  5337. )
  5338. /*++
  5339. Routine Description:
  5340. This routine uninstalls any newly-copied INFs/PNFs/CATs contained in the
  5341. specified linked list of catalog nodes.
  5342. Arguments:
  5343. Queue - Supplies a pointer to the file queue (potentially) containing
  5344. newly-copied catalog nodes to be uninstalled.
  5345. Return Value:
  5346. None.
  5347. --*/
  5348. {
  5349. PSPQ_CATALOG_INFO CatalogNode;
  5350. PTSTR InfToUninstall;
  5351. BOOL Locked = FALSE;
  5352. try {
  5353. if(!_pSpUtilsStringTableLock(Queue->StringTable)) {
  5354. leave;
  5355. }
  5356. Locked = TRUE;
  5357. for(CatalogNode = Queue->CatalogList;
  5358. CatalogNode;
  5359. CatalogNode = CatalogNode->Next) {
  5360. if(CatalogNode->Flags & CATINFO_FLAG_NEWLY_COPIED) {
  5361. InfToUninstall = _pSpUtilsStringTableStringFromId(
  5362. Queue->StringTable,
  5363. CatalogNode->InfFinalPath
  5364. );
  5365. MYASSERT(InfToUninstall);
  5366. if(InfToUninstall) {
  5367. pSetupUninstallOEMInf(InfToUninstall, LogContext, SUOI_FORCEDELETE, NULL);
  5368. }
  5369. }
  5370. }
  5371. } except(EXCEPTION_EXECUTE_HANDLER) {
  5372. //
  5373. // Reference the following variable so the compiler will respect
  5374. // statement ordering w.r.t. its assignment.
  5375. //
  5376. Locked = Locked;
  5377. }
  5378. if(Locked) {
  5379. _pSpUtilsStringTableUnlock(Queue->StringTable);
  5380. }
  5381. }
  5382. BOOL
  5383. WINAPI
  5384. SetupUninstallNewlyCopiedInfs(
  5385. IN HSPFILEQ QueueHandle,
  5386. IN DWORD Flags,
  5387. IN PVOID Reserved
  5388. )
  5389. /*++
  5390. Routine Description:
  5391. This API uninstalls any INFs (and their associated PNFs and CATs) that
  5392. were previously installed during committal of the specified file queue.
  5393. Arguments:
  5394. QueueHandle - Supplies a handle to a committed file queue (potentially)
  5395. containing newly-copied INFs to be uninstalled.
  5396. Flags - Supplies flags that alter the behavior of this API. Presently, no
  5397. flags are defined. This parameter must be zero.
  5398. Reserved - Reserved for future use. This parameter must be NULL.
  5399. Return Value:
  5400. If all the parameters were valid, the return value is non-zero (TRUE). Note
  5401. that this does _not_ necessarily mean that any newly-copied INFs were
  5402. uninstalled.
  5403. If there was a problem with the parameters passed in, the return value is
  5404. FALSE, and GetLastError provides more information on the problem.
  5405. --*/
  5406. {
  5407. PSP_FILE_QUEUE Queue;
  5408. BOOL Success;
  5409. PSETUP_LOG_CONTEXT LogContext;
  5410. if(Flags) {
  5411. SetLastError(ERROR_INVALID_FLAGS);
  5412. return FALSE;
  5413. }
  5414. if(Reserved) {
  5415. SetLastError(ERROR_INVALID_PARAMETER);
  5416. return FALSE;
  5417. }
  5418. //
  5419. // Queue handle is actually a pointer to the queue structure.
  5420. //
  5421. Queue = (PSP_FILE_QUEUE)QueueHandle;
  5422. //
  5423. // do a quick handle validation before anything else
  5424. //
  5425. try {
  5426. Success = ((Queue != NULL) && (Queue != INVALID_HANDLE_VALUE) && (Queue->Signature == SP_FILE_QUEUE_SIG));
  5427. if(Success) {
  5428. LogContext = Queue->LogContext;
  5429. }
  5430. } except(EXCEPTION_EXECUTE_HANDLER) {
  5431. Success = FALSE;
  5432. }
  5433. if(!Success) {
  5434. SetLastError(ERROR_INVALID_HANDLE);
  5435. return FALSE;
  5436. }
  5437. pSetupUninstallNewCatalogNodes(Queue, LogContext);
  5438. return TRUE;
  5439. }