Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

2414 lines
84 KiB

  1. /*++
  2. Copyright (c) 1998 Microsoft Corporation
  3. Module Name:
  4. restore.c
  5. Abstract:
  6. Implementation of file restoration code.
  7. Author:
  8. Andrew Ritz (andrewr) 30-Jul-1999
  9. Revision History:
  10. Andrew Ritz (andrewr) 30-Jul-1999 : moved code from fileio.c and validate.c
  11. --*/
  12. #include "sfcp.h"
  13. #pragma hdrstop
  14. #include <dbt.h>
  15. #include <initguid.h>
  16. #include <devguid.h>
  17. #define STRSAFE_NO_DEPRECATE
  18. #include <strsafe.h>
  19. //
  20. // DEVICE_CHANGE is a private stucture used to indicate how to check for a file
  21. // (either from a device change notification or from the user clicking "retry"
  22. // on the prompt dialog.
  23. //
  24. typedef struct _DEVICE_CHANGE {
  25. DWORD Mask;
  26. DWORD Flags;
  27. } DEVICE_CHANGE, *PDEVICE_CHANGE;
  28. DWORD
  29. pSfcRestoreFromMediaWorkerThread(
  30. IN PRESTORE_QUEUE RestoreQueue
  31. );
  32. DWORD
  33. SfcGetCabTagFile(
  34. IN PSOURCE_INFO psi,
  35. OUT PWSTR* ppFile
  36. );
  37. PVOID
  38. pSfcRegisterForDevChange(
  39. HWND hDlg
  40. )
  41. /*++
  42. Routine Description:
  43. Routine registers for PNP device notification messages so we know when the
  44. user has inserted the CD-ROM.
  45. Arguments:
  46. hDlg - dialog to post device change notification to.
  47. Return Value:
  48. A device change handle for success, otherwise NULL. If this function
  49. succeeds, the hDlg will receive WM_DEVICECHANGE notification messages
  50. --*/
  51. {
  52. PVOID hNotifyDevNode;
  53. DEV_BROADCAST_DEVICEINTERFACE FilterData;
  54. ASSERT(IsWindow(hDlg));
  55. //
  56. // register for cdrom change notifications
  57. //
  58. FilterData.dbcc_size = sizeof(DEV_BROADCAST_DEVICEINTERFACE);
  59. FilterData.dbcc_devicetype = DBT_DEVTYP_DEVICEINTERFACE;
  60. FilterData.dbcc_classguid = GUID_DEVCLASS_CDROM;
  61. hNotifyDevNode = RegisterDeviceNotification( hDlg, &FilterData, DEVICE_NOTIFY_WINDOW_HANDLE );
  62. if (hNotifyDevNode == NULL) {
  63. DebugPrint1( LVL_VERBOSE, L"RegisterDeviceNotification failed, ec=%d", GetLastError() );
  64. }
  65. return hNotifyDevNode;
  66. }
  67. INT_PTR
  68. CALLBACK
  69. pSfcPromptForMediaDialogProc(
  70. HWND hwndDlg,
  71. UINT uMsg,
  72. WPARAM wParam,
  73. LPARAM lParam
  74. )
  75. /*++
  76. Routine Description:
  77. Routine is the dialog procedure for prompting the user to put in media.
  78. We use the same dialog procedure for IDD_SFC_NETWORK_PROMPT and
  79. IDD_SFC_CD_PROMPT.
  80. We register for a device notification so we know when the user puts the
  81. media into the drive. So we don't even need an "OK" button in this dialog,
  82. just a cancel dialog in case the user cannot find the media, etc.
  83. Arguments:
  84. standard dialog proc arguments
  85. Return Value:
  86. standard dialog proc return code
  87. --*/
  88. {
  89. #define WM_TRYAGAIN (WM_APP + 1)
  90. DEV_BROADCAST_VOLUME *dbv;
  91. static UINT QueryCancelAutoPlay = 0;
  92. static PVOID hNotifyDevNode = NULL;
  93. static PPROMPT_INFO pi;
  94. WCHAR buf1[128];
  95. WCHAR buf2[128];
  96. WCHAR conn[128];
  97. PWSTR s;
  98. PDEVICE_CHANGE DeviceChangeStruct;
  99. DWORD Mask, Flags, i;
  100. DWORD rcid;
  101. static CancelId;
  102. WCHAR Path[16];
  103. WCHAR SourcePath[MAX_PATH];
  104. static PSFC_WINDOW_DATA WindowData;
  105. static bInModalLoop = FALSE;
  106. switch (uMsg) {
  107. case WM_INITDIALOG:
  108. pi = (PPROMPT_INFO) lParam;
  109. ASSERT(NULL != pi);
  110. //
  111. // register for cdrom notification.
  112. //
  113. hNotifyDevNode = pSfcRegisterForDevChange( hwndDlg );
  114. //
  115. // try to turn off the autorun junk that the shell creates
  116. //
  117. QueryCancelAutoPlay = RegisterWindowMessage( L"QueryCancelAutoPlay" );
  118. //
  119. // center the dialog and try to put it in the user's face
  120. //
  121. CenterDialog( hwndDlg );
  122. SetForegroundWindow( hwndDlg );
  123. GetDlgItemText( hwndDlg, IDC_MEDIA_NAME, buf1, UnicodeChars(buf1) );
  124. swprintf( buf2, buf1, pi->si->Description );
  125. SetDlgItemText( hwndDlg, IDC_MEDIA_NAME, buf2 );
  126. //
  127. // if we're a network connection, put in the actual source path.
  128. //
  129. if (pi->NetPrompt) {
  130. ASSERT( pi->SourcePath != NULL );
  131. GetDlgItemText( hwndDlg, IDC_NET_NAME, buf1, UnicodeChars(buf1) );
  132. if(!SfcGetConnectionName( pi->SourcePath, conn, UnicodeChars(conn), NULL, 0, FALSE, NULL )) {
  133. conn[0] = 0;
  134. }
  135. (void) StringCchPrintf( buf2, UnicodeChars(buf2), buf1, conn );
  136. SetDlgItemText( hwndDlg, IDC_NET_NAME, buf2 );
  137. } else {
  138. NOTHING;
  139. //HideWindow( GetDlgItem( hwndDlg, IDC_RETRY ) );
  140. //HideWindow( GetDlgItem( hwndDlg, IDC_INFO ) );
  141. //SetFocus( GetDlgItem( hwndDlg, IDCANCEL ) );
  142. }
  143. //
  144. // set the appropriate text based on what sort of prompt we are for
  145. //
  146. if (pi->Flags & PI_FLAG_COPY_TO_CACHE) {
  147. rcid = IDS_CACHE_TEXT;
  148. CancelId = IDS_CANCEL_CONFIRM_CACHE;
  149. } else if (pi->Flags & PI_FLAG_INSTALL_PROTECTED) {
  150. rcid = IDS_INSTALL_PROTECTED_TEXT;
  151. CancelId = IDS_CANCEL_CONFIRM_INSTALL;
  152. } else {
  153. ASSERT(pi->Flags & PI_FLAG_RESTORE_FILE);
  154. rcid = IDS_RESTORE_TEXT;
  155. CancelId = IDS_CANCEL_CONFIRM;
  156. }
  157. LoadString(SfcInstanceHandle,rcid,SourcePath,UnicodeChars(SourcePath));
  158. SetDlgItemText( hwndDlg, IDC_PROMPT_TEXT, SourcePath );
  159. //
  160. // remember our window handle so we can close it if we have to.
  161. //
  162. WindowData = pSfcCreateWindowDataEntry( hwndDlg );
  163. break;
  164. case WM_COMMAND:
  165. switch (LOWORD(wParam)) {
  166. case IDC_RETRY:
  167. PostMessage(hwndDlg, WM_TRYAGAIN, 0, (LPARAM)NULL);
  168. break;
  169. case IDC_INFO:
  170. bInModalLoop = TRUE;
  171. MyMessageBox(
  172. NULL,
  173. pi->NetPrompt ? IDS_MORE_INFORMATION_NET : IDS_MORE_INFORMATION_CD,
  174. MB_ICONINFORMATION | MB_SERVICE_NOTIFICATION);
  175. bInModalLoop = FALSE;
  176. break;
  177. case IDCANCEL:
  178. //
  179. // the user clicked cancel. Ask them if they really mean it and exit
  180. //
  181. ASSERT(CancelId != 0);
  182. bInModalLoop = TRUE;
  183. if (MyMessageBox(
  184. hwndDlg,
  185. CancelId,
  186. MB_APPLMODAL | MB_YESNO | MB_DEFBUTTON2 | MB_ICONWARNING ) == IDYES) {
  187. UnregisterDeviceNotification( hNotifyDevNode );
  188. pSfcRemoveWindowDataEntry( WindowData );
  189. EndDialog( hwndDlg, 0 );
  190. }
  191. bInModalLoop = FALSE;
  192. break;
  193. default:
  194. NOTHING;
  195. }
  196. break;
  197. case WM_WFPENDDIALOG:
  198. DebugPrint(
  199. LVL_VERBOSE,
  200. L"Received WM_WFPENDDIALOG message, terminating dialog" );
  201. SetWindowLongPtr( hwndDlg, DWLP_MSGRESULT, ERROR_SUCCESS );
  202. //
  203. // returning 2 indicates that we are being force-terminated so we
  204. // don't need to bother removing our SFC_WINDOW_DATA member
  205. //
  206. EndDialog( hwndDlg, 2 );
  207. break;
  208. case WM_TRYAGAIN:
  209. DeviceChangeStruct = (PDEVICE_CHANGE) lParam;
  210. if (DeviceChangeStruct) {
  211. Mask = DeviceChangeStruct->Mask;
  212. Flags = DeviceChangeStruct->Flags;
  213. MemFree(DeviceChangeStruct);
  214. DeviceChangeStruct = NULL;
  215. } else {
  216. Flags = DBTF_MEDIA;
  217. Mask = (DWORD)-1;
  218. }
  219. if (pi->NetPrompt) {
  220. EstablishConnection( hwndDlg, pi->SourcePath, !SFCNoPopUps );
  221. if (TAGFILE(pi->si)) {
  222. s = wcsrchr( TAGFILE(pi->si), L'.' );
  223. if (s && _wcsicmp( s, L".cab" ) == 0) {
  224. //
  225. // yep, the tagfile is a cabfile
  226. // look for that file on disk
  227. // and if it is, use it.
  228. //
  229. BuildPathForFile(
  230. pi->SourcePath,
  231. pi->si->SourcePath,
  232. TAGFILE(pi->si),
  233. SFC_INCLUDE_SUBDIRECTORY,
  234. SFC_INCLUDE_ARCHSUBDIR,
  235. SourcePath,
  236. UnicodeChars(SourcePath) );
  237. if (SfcIsFileOnMedia( SourcePath )) {
  238. s = wcsrchr( SourcePath, L'\\' );
  239. *s = L'\0';
  240. wcscpy( pi->NewPath, SourcePath );
  241. UnregisterDeviceNotification( hNotifyDevNode );
  242. pSfcRemoveWindowDataEntry( WindowData );
  243. EndDialog( hwndDlg, 1 );
  244. return FALSE;
  245. }
  246. //
  247. // try without the subdir
  248. //
  249. BuildPathForFile(
  250. pi->SourcePath,
  251. pi->si->SourcePath,
  252. TAGFILE(pi->si),
  253. SFC_INCLUDE_SUBDIRECTORY,
  254. (!SFC_INCLUDE_ARCHSUBDIR),
  255. SourcePath,
  256. UnicodeChars(SourcePath) );
  257. if (SfcIsFileOnMedia( SourcePath )) {
  258. s = wcsrchr( SourcePath, L'\\' );
  259. *s = L'\0';
  260. wcscpy( pi->NewPath, SourcePath );
  261. UnregisterDeviceNotification( hNotifyDevNode );
  262. pSfcRemoveWindowDataEntry( WindowData );
  263. EndDialog( hwndDlg, 1 );
  264. return FALSE;
  265. } else {
  266. DebugPrint1( LVL_VERBOSE, L"pSfcPromptForMediaDialogProc: cab file is missing from cd, [%ws]", SourcePath );
  267. }
  268. } else {
  269. DebugPrint1( LVL_VERBOSE,
  270. L"pSfcPromptForMediaDialogProc: the tag file [%ws] is not a cab file",
  271. TAGFILE(pi->si) );
  272. }
  273. }
  274. //
  275. // no cab file. look for the actual
  276. // file on the media
  277. //
  278. BuildPathForFile(
  279. pi->SourcePath,
  280. pi->si->SourcePath,
  281. pi->SourceFileName,
  282. SFC_INCLUDE_SUBDIRECTORY,
  283. SFC_INCLUDE_ARCHSUBDIR,
  284. SourcePath,
  285. UnicodeChars(SourcePath) );
  286. if (SfcIsFileOnMedia( SourcePath )) {
  287. s = wcsrchr( SourcePath, L'\\' );
  288. *s = L'\0';
  289. wcscpy( pi->NewPath, SourcePath );
  290. UnregisterDeviceNotification( hNotifyDevNode );
  291. pSfcRemoveWindowDataEntry( WindowData );
  292. EndDialog( hwndDlg, 1 );
  293. return FALSE;
  294. }
  295. //
  296. // try again without the subdir
  297. //
  298. BuildPathForFile(
  299. pi->SourcePath,
  300. pi->si->SourcePath,
  301. pi->SourceFileName,
  302. SFC_INCLUDE_SUBDIRECTORY,
  303. (!SFC_INCLUDE_ARCHSUBDIR),
  304. SourcePath,
  305. UnicodeChars(SourcePath) );
  306. if (SfcIsFileOnMedia( SourcePath )) {
  307. s = wcsrchr( SourcePath, L'\\' );
  308. *s = L'\0';
  309. wcscpy( pi->NewPath, SourcePath );
  310. UnregisterDeviceNotification( hNotifyDevNode );
  311. pSfcRemoveWindowDataEntry( WindowData );
  312. EndDialog( hwndDlg, 1 );
  313. return FALSE;
  314. }
  315. }
  316. Path[0] = L'?';
  317. Path[1] = L':';
  318. Path[2] = L'\\';
  319. Path[3] = 0;
  320. Path[4] = 0;
  321. //
  322. // cycle through all drive letters A-Z looking for the file
  323. //
  324. for (i=0; i<26; i++) {
  325. if (Mask&1) {
  326. Path[0] = (WCHAR)(L'A' + i);
  327. Path[3] = 0;
  328. //
  329. // is media present in the CD-ROM?
  330. //
  331. if (Flags == DBTF_MEDIA) {
  332. if (GetDriveType( Path ) == DRIVE_CDROM) {
  333. //
  334. // look for the tag file so we're sure that the cd that
  335. // was inserted is the correct one
  336. //
  337. DebugPrint1( LVL_VERBOSE, L"pSfcPromptForMediaDialogProc: found cdrom drive on [%ws]", Path );
  338. if (TAGFILE(pi->si)) {
  339. wcscpy( SourcePath, Path );
  340. s = wcsrchr( TAGFILE(pi->si), L'.' );
  341. if (s && _wcsicmp( s, L".cab" ) == 0) {
  342. PWSTR szTagfile;
  343. //
  344. // get the cab's tagfile
  345. //
  346. if (SfcGetCabTagFile(pi->si, &szTagfile) == ERROR_SUCCESS) {
  347. pSetupConcatenatePaths( SourcePath, szTagfile, UnicodeChars(SourcePath), NULL );
  348. MemFree(szTagfile);
  349. } else {
  350. DebugPrint1(LVL_VERBOSE, L"SfcGetCabTagFile failed with error %d", GetLastError());
  351. }
  352. }else{
  353. pSetupConcatenatePaths( SourcePath, TAGFILE(pi->si),UnicodeChars(SourcePath), NULL );
  354. }
  355. if (GetFileAttributes( SourcePath ) != (DWORD)-1) {
  356. //
  357. // the user has the correct cd inserted
  358. // so now look to see if the file is on
  359. // the cd
  360. //
  361. //
  362. // first we have to look for the tagfile
  363. // for the actual file because the tag-
  364. // file may actually be a cabfile that
  365. // the file is embedded in
  366. //
  367. if (TAGFILE(pi->si)) {
  368. s = wcsrchr( TAGFILE(pi->si), L'.' );
  369. if (s && _wcsicmp( s, L".cab" ) == 0) {
  370. //
  371. // yep, the tagfile is a cabfile
  372. // look for that file on disk
  373. // and if it is, use it.
  374. //
  375. BuildPathForFile(
  376. Path,
  377. pi->si->SourcePath,
  378. TAGFILE(pi->si),
  379. SFC_INCLUDE_SUBDIRECTORY,
  380. SFC_INCLUDE_ARCHSUBDIR,
  381. SourcePath,
  382. UnicodeChars(SourcePath) );
  383. if (SfcIsFileOnMedia( SourcePath )) {
  384. s = wcsrchr( SourcePath, L'\\' );
  385. *s = L'\0';
  386. wcscpy( pi->NewPath, SourcePath );
  387. UnregisterDeviceNotification( hNotifyDevNode );
  388. pSfcRemoveWindowDataEntry( WindowData );
  389. EndDialog( hwndDlg, 1 );
  390. return FALSE;
  391. } else {
  392. DebugPrint1( LVL_VERBOSE, L"pSfcPromptForMediaDialogProc: cab file is missing from cd, [%ws]", SourcePath );
  393. }
  394. } else {
  395. DebugPrint1( LVL_VERBOSE,
  396. L"pSfcPromptForMediaDialogProc: the tag file [%ws] is not a cab file",
  397. TAGFILE(pi->si) );
  398. }
  399. }
  400. //
  401. // no cab file. look for the actual
  402. // file on the media
  403. //
  404. BuildPathForFile(
  405. Path,
  406. pi->si->SourcePath,
  407. pi->SourceFileName,
  408. SFC_INCLUDE_SUBDIRECTORY,
  409. SFC_INCLUDE_ARCHSUBDIR,
  410. SourcePath,
  411. UnicodeChars(SourcePath) );
  412. if (SfcIsFileOnMedia( SourcePath )) {
  413. s = wcsrchr( SourcePath, L'\\' );
  414. *s = L'\0';
  415. wcscpy( pi->NewPath, SourcePath );
  416. UnregisterDeviceNotification( hNotifyDevNode );
  417. pSfcRemoveWindowDataEntry( WindowData );
  418. EndDialog( hwndDlg, 1 );
  419. return FALSE;
  420. } else {
  421. DebugPrint1( LVL_VERBOSE, L"pSfcPromptForMediaDialogProc: source file is missing [%ws]", SourcePath );
  422. }
  423. } else {
  424. DebugPrint1( LVL_VERBOSE, L"pSfcPromptForMediaDialogProc: media tag file [%ws] is missing, wrong CD", SourcePath );
  425. }
  426. } else {
  427. DebugPrint1( LVL_VERBOSE, L"pSfcPromptForMediaDialogProc: could not get source information for layout.inf, ec=%d", GetLastError() );
  428. }
  429. }
  430. } else if (Flags == DBTF_NET) {
  431. //
  432. // network share has changed... get the UNC
  433. // pathname and check for the file
  434. //
  435. if (SfcGetConnectionName( Path, SourcePath, UnicodeChars(SourcePath), NULL, 0, FALSE, NULL)) {
  436. //
  437. // first we have to look for the tagfile
  438. // for the actual file because the tag-
  439. // file may actually be a cabfile that
  440. // the file is embedded in
  441. //
  442. if (TAGFILE(pi->si)) {
  443. s = wcsrchr( TAGFILE(pi->si), L'.' );
  444. if (s && _wcsicmp( s, L".cab" ) == 0) {
  445. //
  446. // yep, the tagfile is a cabfile
  447. // look for that file on disk
  448. // and if it is, use it.
  449. //
  450. BuildPathForFile(
  451. Path,
  452. pi->si->SourcePath,
  453. TAGFILE(pi->si),
  454. SFC_INCLUDE_SUBDIRECTORY,
  455. SFC_INCLUDE_ARCHSUBDIR,
  456. SourcePath,
  457. UnicodeChars(SourcePath) );
  458. if (SfcIsFileOnMedia( SourcePath )) {
  459. s = wcsrchr( SourcePath, L'\\' );
  460. *s = L'\0';
  461. wcscpy( pi->NewPath, SourcePath );
  462. UnregisterDeviceNotification( hNotifyDevNode );
  463. pSfcRemoveWindowDataEntry( WindowData );
  464. EndDialog( hwndDlg, 1 );
  465. return FALSE;
  466. } else {
  467. DebugPrint1( LVL_VERBOSE, L"pSfcPromptForMediaDialogProc: cab file is missing from cd, [%ws]", SourcePath );
  468. }
  469. } else {
  470. DebugPrint1( LVL_VERBOSE,
  471. L"pSfcPromptForMediaDialogProc: the tag file [%ws] is not a cab file",
  472. TAGFILE(pi->si) );
  473. }
  474. }
  475. BuildPathForFile(
  476. SourcePath,
  477. pi->si->SourcePath,
  478. pi->SourceFileName,
  479. SFC_INCLUDE_SUBDIRECTORY,
  480. SFC_INCLUDE_ARCHSUBDIR,
  481. SourcePath,
  482. UnicodeChars(SourcePath) );
  483. if (SfcIsFileOnMedia( SourcePath )) {
  484. s = wcsrchr( SourcePath, L'\\' );
  485. *s = L'\0';
  486. wcscpy( pi->NewPath, SourcePath );
  487. UnregisterDeviceNotification( hNotifyDevNode );
  488. pSfcRemoveWindowDataEntry( WindowData );
  489. EndDialog( hwndDlg, 1 );
  490. }
  491. }
  492. }
  493. }
  494. Mask = Mask >> 1;
  495. }
  496. //
  497. // ok user made a mistake
  498. // he put in a cd but it is either the wrong cd
  499. // or it is damaged/corrupted.
  500. //
  501. bInModalLoop = TRUE;
  502. MyMessageBox(
  503. hwndDlg,
  504. pi->NetPrompt
  505. ? IDS_WRONG_NETCD
  506. : IDS_WRONG_CD,
  507. MB_OK,
  508. pi->si->Description );
  509. bInModalLoop = FALSE;
  510. //
  511. // Received a volume change notification but we didn't find what
  512. // we're looking for.
  513. //
  514. DebugPrint( LVL_VERBOSE, L"pSfcPromptForMediaDialogProc: didn't find file" );
  515. break;
  516. case WM_DEVICECHANGE:
  517. //
  518. // Don't process this while in a modal loop (i.e. displaying a message box)
  519. //
  520. if(bInModalLoop) {
  521. break;
  522. }
  523. if (wParam == DBT_DEVICEARRIVAL) {
  524. dbv = (DEV_BROADCAST_VOLUME*)lParam;
  525. if (dbv->dbcv_devicetype == DBT_DEVTYP_VOLUME) {
  526. //
  527. // only care about volume type change notifications
  528. //
  529. DebugPrint( LVL_VERBOSE, L"pSfcPromptForMediaDialogProc: received a volume change notification" );
  530. DeviceChangeStruct = MemAlloc( sizeof( DEVICE_CHANGE ) );
  531. if (DeviceChangeStruct) {
  532. DeviceChangeStruct->Mask = dbv->dbcv_unitmask;
  533. DeviceChangeStruct->Flags = dbv->dbcv_flags;
  534. if (!PostMessage(hwndDlg, WM_TRYAGAIN, 0, (LPARAM)DeviceChangeStruct)) {
  535. DebugPrint1( LVL_MINIMAL ,
  536. L"pSfcPromptForMediaDialogProc: PostMessage failed, ec = 0x%0xd",
  537. GetLastError() );
  538. MemFree(DeviceChangeStruct);
  539. }
  540. } else {
  541. PostMessage(hwndDlg, WM_TRYAGAIN, 0, (LPARAM)NULL);
  542. }
  543. }
  544. }
  545. break;
  546. default:
  547. if (uMsg == QueryCancelAutoPlay) {
  548. //
  549. // disable autorun because it confuses the user
  550. //
  551. SetWindowLongPtr( hwndDlg, DWLP_MSGRESULT, 1 );
  552. return 1;
  553. }
  554. } // end switch
  555. return FALSE;
  556. }
  557. UINT
  558. SfcQueueCallback(
  559. IN PFILE_COPY_INFO fci,
  560. IN UINT Notification,
  561. IN UINT_PTR Param1,
  562. IN UINT_PTR Param2
  563. )
  564. /*++
  565. Routine Description:
  566. Routine is a setupapi queue callback routine. We override some of the
  567. setupapi functions because we want to provide our own UI (or rather
  568. disallow the setupapi UI).
  569. Arguments:
  570. fci - our context structure which setupapi passes to us for each
  571. callback
  572. Notification - SPFILENOTIFY_* code
  573. Param1 - depends on notification
  574. Param2 - depends on notification
  575. Return Value:
  576. depends on notification.
  577. --*/
  578. {
  579. PSOURCE_MEDIA sm = (PSOURCE_MEDIA)Param1;
  580. WCHAR fname[MAX_PATH*2];
  581. WCHAR buf[MAX_PATH];
  582. DWORD rVal;
  583. INT_PTR rv;
  584. DWORD RcId;
  585. PFILEPATHS fp;
  586. PFILEINSTALL_STATUS cs;
  587. NTSTATUS Status;
  588. HANDLE FileHandle;
  589. PNAME_NODE Node;
  590. PSFC_REGISTRY_VALUE RegVal;
  591. DWORD FileSizeHigh;
  592. DWORD FileSizeLow;
  593. DWORD PathType;
  594. PROMPT_INFO pi;
  595. PSOURCE_INFO SourceInfo;
  596. PVALIDATION_REQUEST_DATA vrd;
  597. HCATADMIN hCatAdmin;
  598. switch (Notification) {
  599. case SPFILENOTIFY_ENDQUEUE:
  600. //
  601. // We might have impersonated the logged-on user in EstablishConnection during SPFILENOTIFY_NEEDMEDIA
  602. //
  603. RevertToSelf();
  604. break;
  605. //
  606. // we had a copy error, record this and move onto the next file.
  607. //
  608. case SPFILENOTIFY_COPYERROR:
  609. fp = (PFILEPATHS)Param1;
  610. DebugPrint2(
  611. LVL_MINIMAL,
  612. L"Failed to copy file %ws, ec = 0x%08x...",
  613. fp->Target,
  614. fp->Win32Error );
  615. //
  616. // fall through
  617. //
  618. case SPFILENOTIFY_ENDCOPY:
  619. //
  620. // end copy means the file copy just completed
  621. //
  622. fp = (PFILEPATHS)Param1;
  623. DebugPrint3( LVL_VERBOSE,
  624. L"SfcQueueCallback: copy file %ws --> %ws, ec = 0x%08x",
  625. fp->Source,
  626. fp->Target,
  627. fp->Win32Error );
  628. //
  629. // if the copy succeeded, clear any read-only or hidden attributes
  630. // that may have been set by copying off of a cd, etc.
  631. //
  632. if (fp->Win32Error == ERROR_SUCCESS) {
  633. SetFileAttributes( fp->Target,
  634. GetFileAttributes(fp->Target) & (~(FILE_ATTRIBUTE_READONLY | FILE_ATTRIBUTE_HIDDEN)) );
  635. }
  636. //
  637. // in the case that we're copying files due to an InstallProtectedFiles
  638. // call, cs will be initialized, and we can loop throught the list of
  639. // files, updating a status structure for each of these files
  640. //
  641. cs = fci->CopyStatus;
  642. while (cs && cs->FileName) {
  643. //
  644. // cycle through the list of files we want to be copied
  645. // and if the file was copied successfully, then get the
  646. // filesize so we can post it to the caller's dialog
  647. //
  648. // also remember the version for returning to the caller
  649. //
  650. if ( (_wcsicmp(cs->FileName,fp->Target) == 0)
  651. && cs->Win32Error == ERROR_SUCCESS) {
  652. cs->Win32Error = fp->Win32Error;
  653. if (cs->Win32Error == ERROR_SUCCESS) {
  654. Node = SfcFindProtectedFile( cs->FileName, UnicodeLen(cs->FileName) );
  655. if (Node) {
  656. RegVal = (PSFC_REGISTRY_VALUE)Node->Context;
  657. Status = SfcOpenFile( &RegVal->FileName, RegVal->DirHandle, SHARE_ALL, &FileHandle );
  658. if (NT_SUCCESS(Status)) {
  659. if (fci->hWnd) {
  660. FileSizeLow = GetFileSize( FileHandle, &FileSizeHigh );
  661. PostMessage( fci->hWnd, WM_SFC_NOTIFY, (WPARAM)FileSizeLow, (LPARAM)FileSizeHigh );
  662. }
  663. SfcGetFileVersion( FileHandle, &cs->Version, NULL, fname );
  664. NtClose( FileHandle );
  665. }
  666. }
  667. } else {
  668. DebugPrint2( LVL_MINIMAL, L"Failed to copy file %ws, ec = 0x%08x", fp->Target, fp->Win32Error );
  669. }
  670. break;
  671. }
  672. cs += 1;
  673. }
  674. if (fci->si) {
  675. vrd = pSfcGetValidationRequestFromFilePaths( fci->si, fci->FileCount, fp );
  676. if (vrd && vrd->Win32Error == ERROR_SUCCESS) {
  677. vrd->Win32Error = fp->Win32Error;
  678. if (fp->Win32Error == ERROR_SUCCESS) {
  679. vrd->CopyCompleted = TRUE;
  680. if (!CryptCATAdminAcquireContext(&hCatAdmin, &DriverVerifyGuid, 0)) {
  681. DebugPrint1( LVL_MINIMAL, L"CCAAC() failed, ec=%d", GetLastError() );
  682. goto next;
  683. }
  684. //
  685. // make sure the file is now valid
  686. //
  687. if (!SfcGetValidationData( &vrd->RegVal->FileName,
  688. &vrd->RegVal->FullPathName,
  689. vrd->RegVal->DirHandle,
  690. hCatAdmin,
  691. &vrd->ImageValData.New )) {
  692. DebugPrint1( LVL_MINIMAL, L"SfcGetValidationData() failed, ec=%d", GetLastError() );
  693. goto next;
  694. }
  695. if (vrd->ImageValData.New.SignatureValid == FALSE) {
  696. vrd->ImageValData.New.DllVersion = 0;
  697. } else {
  698. //
  699. // Cause a validation request. This should get us
  700. // to sync the file in the cache.
  701. //
  702. SfcQueueValidationRequest(vrd->RegVal, SFC_ACTION_MODIFIED );
  703. }
  704. CryptCATAdminReleaseContext(hCatAdmin,0);
  705. vrd->ImageValData.EventLog = MSG_DLL_CHANGE;
  706. } else {
  707. vrd->ImageValData.EventLog = MSG_RESTORE_FAILURE;
  708. }
  709. }
  710. }
  711. return (Notification == SPFILENOTIFY_COPYERROR)
  712. ? FILEOP_SKIP
  713. : FILEOP_DOIT;
  714. break;
  715. //
  716. // This means that we're copying something from a new piece of media.
  717. // Before we mess around with putting up a prompt for the file, let's just
  718. // check for the file at the specified location and if it's there, we
  719. // assume that the media is already present and we should just use it.
  720. //
  721. case SPFILENOTIFY_NEEDMEDIA:
  722. DebugPrint3( LVL_MINIMAL, L"SfcQueueCallback: %ws - %ws, %ws", sm->SourcePath, sm->SourceFile, sm->Tagfile );
  723. wcscpy( fname, sm->SourcePath );
  724. pSetupConcatenatePaths( fname, sm->SourceFile, UnicodeChars(fname), NULL );
  725. SourceInfo = pSfcGetSourceInfoFromSourceName( fci->si, fci->FileCount, sm );
  726. ASSERT(ShuttingDown ? SourceInfo != NULL : TRUE);
  727. //
  728. // if we're in the process of shutting down, then abort the queue.
  729. //
  730. if (ShuttingDown) {
  731. return(FILEOP_ABORT);
  732. }
  733. //
  734. // if we didn't find the SOURCE_INFO for this file, we can't go on
  735. // since we need that information to know where the proper location
  736. // to retrieve the file is. we do make one last-ditch effort to
  737. // see if the file is just where we said it would be earlier, however.
  738. if (!SourceInfo) {
  739. if (SfcIsFileOnMedia( fname )) {
  740. return FILEOP_DOIT;
  741. }
  742. SetLastError(ERROR_CANCELLED);
  743. return (FILEOP_ABORT);
  744. }
  745. //
  746. // if this is a network share we try to establish a connection
  747. // to the server before looking for the file. this may bring up
  748. // UI
  749. //
  750. PathType = SfcGetPathType( (PWSTR)sm->SourcePath, buf,UnicodeChars(buf) );
  751. if (PathType == PATH_NETWORK || PathType == PATH_UNC) {
  752. EstablishConnection( NULL, sm->SourcePath, (fci->AllowUI && !SFCNoPopUps) );
  753. }
  754. rVal = SfcQueueLookForFile( sm, SourceInfo, fname, (PWSTR)Param2 );
  755. if (SFCNoPopUps) {
  756. if (rVal == FILEOP_ABORT) {
  757. //
  758. // media is necessary to copy the files but the user has
  759. // configured wfp to not put up any ui. we make this look
  760. // like a cancel
  761. //
  762. SetLastError(ERROR_CANCELLED);
  763. }
  764. return (rVal);
  765. }
  766. if (rVal != FILEOP_ABORT) {
  767. //
  768. // we have found the file so start copying
  769. //
  770. return (rVal);
  771. }
  772. //
  773. // if we're not supposed to put up any dialogs, just abort copying
  774. // this media and goto the next media.
  775. //
  776. // Note: it would be good to skip instead of aborting, since
  777. // there might some set of files which we can restore from another
  778. // media. In order to do this we really need to be able to know
  779. // what files are on this media and set an error code for these
  780. // files so that we know they weren't copied.
  781. //
  782. if (!fci->AllowUI) {
  783. return (FILEOP_ABORT);
  784. }
  785. //
  786. // otherwise let's just record that we're putting up media
  787. // and then do just that.
  788. //
  789. fci->UIShown = TRUE;
  790. //
  791. // Note: make sure not to use this source media structure after the
  792. // media has changed
  793. //
  794. switch (PathType) {
  795. case PATH_LOCAL:
  796. RcId = IDD_SFC_CD_PROMPT;
  797. break;
  798. case PATH_NETWORK:
  799. case PATH_UNC:
  800. RcId = IDD_SFC_NETWORK_PROMPT;
  801. break;
  802. case PATH_CDROM:
  803. RcId = IDD_SFC_CD_PROMPT;
  804. break;
  805. default:
  806. RcId = 0;
  807. ASSERT( FALSE && "Unexpected PathType" );
  808. break;
  809. }
  810. ASSERT((sm->SourceFile) && (sm->SourcePath) && (RcId != 0) );
  811. pi.si = SourceInfo;
  812. pi.SourceFileName = (PWSTR)sm->SourceFile;
  813. pi.NewPath = buf;
  814. pi.SourcePath = (PWSTR)sm->SourcePath;
  815. pi.NetPrompt = (RcId == IDD_SFC_NETWORK_PROMPT);
  816. pi.Flags = fci->Flags;
  817. rv = MyDialogBoxParam(
  818. RcId,
  819. pSfcPromptForMediaDialogProc,
  820. (LPARAM)&pi
  821. );
  822. if (rv == 1) {
  823. //
  824. // we're done. if we got a new path, pass that back to
  825. // setup API else just copy the file from the current
  826. // location
  827. //
  828. if (_wcsicmp( pi.NewPath, sm->SourcePath )) {
  829. wcscpy( (PWSTR)Param2, pi.NewPath );
  830. return ( FILEOP_NEWPATH );
  831. }
  832. return FILEOP_DOIT;
  833. } else if (rv == 2) {
  834. //
  835. // we were forcefully aborted by receiving WM_WFPENDDIALOG
  836. //
  837. return FILEOP_ABORT;
  838. } else {
  839. ASSERT(rv == 0);
  840. SetLastError(ERROR_CANCELLED);
  841. return FILEOP_ABORT;
  842. }
  843. ASSERT(FALSE && "should not get here");
  844. break;
  845. default:
  846. NOTHING;
  847. }
  848. next:
  849. //
  850. // just to the default for the rest of the callbacks
  851. //
  852. return SetupDefaultQueueCallback( fci->MsgHandlerContext, Notification, Param1, Param2 );
  853. }
  854. BOOL
  855. SfcAddFileToQueue(
  856. IN const HSPFILEQ hFileQ,
  857. IN PCWSTR FileName,
  858. IN PCWSTR TargetFileName,
  859. IN PCWSTR TargetDirectory,
  860. IN PCWSTR SourceFileName, OPTIONAL
  861. IN PCWSTR SourceRootPath, OPTIONAL
  862. IN PCWSTR InfName,
  863. IN BOOL ExcepPackFile,
  864. IN OUT PSOURCE_INFO SourceInfo OPTIONAL
  865. )
  866. /*++
  867. Routine Description:
  868. Routine adds the specified file to a file queue for copying.
  869. Arguments:
  870. hFileQ - contains a file queue handle that we are inserting this
  871. copy node into
  872. FileName - specifies the filename to be copied
  873. TargetFileName - target filename
  874. TargetDirectory - target destination directory
  875. SourceFileName - source filename if it's different than the target
  876. filename. if this is NULL, we assume the source filename
  877. is the same as the target
  878. SourceRootPath - the root path where we can find this file
  879. InfName - the layout inf name
  880. SourceInfo - SOURCE_INFO structure which gets set with additional
  881. information about the file (like relative source
  882. path, etc.) If this is supplied, it is assumed that
  883. the structure was already initialized with a call to
  884. SfcGetSourceInformation
  885. Return Value:
  886. TRUE if the file was successfully added to the file queue.
  887. --*/
  888. {
  889. BOOL b = FALSE;
  890. SOURCE_INFO sibuf;
  891. SP_FILE_COPY_PARAMS fcp;
  892. RtlZeroMemory(&fcp, sizeof(fcp));
  893. fcp.cbSize = sizeof(fcp);
  894. fcp.LayoutInf = INVALID_HANDLE_VALUE;
  895. //
  896. // get the source information
  897. //
  898. if (SourceInfo == NULL) {
  899. SourceInfo = &sibuf;
  900. ZeroMemory( SourceInfo, sizeof(SOURCE_INFO) );
  901. if (!SfcGetSourceInformation( SourceFileName == NULL ? FileName : SourceFileName, InfName, ExcepPackFile, SourceInfo )) {
  902. goto exit;
  903. }
  904. }
  905. ASSERT(SourceInfo != NULL);
  906. //
  907. // Open layout.inf
  908. //
  909. fcp.LayoutInf = SfcOpenInf(NULL, FALSE);
  910. if(INVALID_HANDLE_VALUE == fcp.LayoutInf) {
  911. goto exit;
  912. }
  913. fcp.QueueHandle = hFileQ;
  914. fcp.SourceRootPath = SourceRootPath ? SourceRootPath : SourceInfo->SourceRootPath;
  915. fcp.SourcePath = SourceInfo->SourcePath;
  916. fcp.SourceFilename = SourceFileName == NULL ? FileName : SourceFileName;
  917. fcp.SourceDescription = SourceInfo->Description;
  918. fcp.SourceTagfile = TAGFILE(SourceInfo);
  919. fcp.TargetDirectory = TargetDirectory;
  920. fcp.TargetFilename = TargetFileName;
  921. fcp.CopyStyle = SP_COPY_REPLACE_BOOT_FILE | PSP_COPY_USE_SPCACHE;
  922. //
  923. // add the file to the file queue
  924. //
  925. b = SetupQueueCopyIndirect(&fcp);
  926. if (!b) {
  927. DebugPrint1( LVL_VERBOSE, L"SetupQueueCopy failed, ec=%d", GetLastError() );
  928. goto exit;
  929. }
  930. exit:
  931. //
  932. // cleanup and exit
  933. //
  934. if(fcp.LayoutInf != INVALID_HANDLE_VALUE) {
  935. SetupCloseInfFile(fcp.LayoutInf);
  936. }
  937. return b;
  938. }
  939. BOOL
  940. SfcRestoreFileFromInstallMedia(
  941. IN PVALIDATION_REQUEST_DATA vrd,
  942. IN PCWSTR FileName,
  943. IN PCWSTR TargetFileName,
  944. IN PCWSTR TargetDirectory,
  945. IN PCWSTR SourceFileName,
  946. IN PCWSTR InfName,
  947. IN BOOL ExcepPackFile,
  948. IN BOOL TargetIsCache,
  949. IN BOOL AllowUI,
  950. OUT PDWORD UIShown
  951. )
  952. /*++
  953. Routine Description:
  954. Routine restores the file specified from media. This routine only
  955. handles one file at a time, and it is only used when populating the
  956. DLLCache.
  957. Arguments:
  958. vrd
  959. FileName
  960. TargetFileName
  961. TargetDirectory
  962. SourceFileName
  963. InfName
  964. AllowUI
  965. UIShown
  966. Return Value:
  967. If TRUE, the file was successfully restored from media.
  968. --*/
  969. {
  970. HSPFILEQ hFileQ = INVALID_HANDLE_VALUE;
  971. PVOID MsgHandlerContext = NULL;
  972. BOOL b = FALSE;
  973. DWORD LastError = ERROR_SUCCESS;
  974. struct _info
  975. {
  976. FILE_COPY_INFO fci;
  977. SOURCE_INFO si;
  978. }* pinfo = NULL;
  979. PSOURCE_INFO psi;
  980. ASSERT(FileName != NULL);
  981. //
  982. // allocate SOURCE_INFO and FILE_COPY_INFO in the heap to minimize stack use
  983. // note that the memory is zeroed by MemAlloc
  984. //
  985. pinfo = (struct _info*) MemAlloc(sizeof(*pinfo));
  986. if(NULL == pinfo)
  987. {
  988. LastError = ERROR_NOT_ENOUGH_MEMORY;
  989. DebugPrint( LVL_MINIMAL, L"Not enough memory in function SfcRestoreFileFromInstallMedia" );
  990. goto exit;
  991. }
  992. //
  993. // get the source information for the first file
  994. //
  995. if (!SfcGetSourceInformation( SourceFileName == NULL ? FileName : SourceFileName, InfName, ExcepPackFile, &pinfo->si )) {
  996. goto exit;
  997. }
  998. //
  999. // create a file queue
  1000. //
  1001. hFileQ = SetupOpenFileQueue();
  1002. if (hFileQ == INVALID_HANDLE_VALUE) {
  1003. LastError = GetLastError();
  1004. DebugPrint1( LVL_MINIMAL, L"SetupOpenFileQueue failed, ec=%d", LastError );
  1005. b = FALSE;
  1006. goto exit;
  1007. }
  1008. //
  1009. // add the file(s) to the queue
  1010. //
  1011. // at this time we know where to copy the files from and the media is
  1012. // present and available, but more files may have been queued up while
  1013. // we performed this effort and possibly spent a long time prompting
  1014. // the user for media. because of this we need to examine the queue and
  1015. // queue up all file copies so the user only gets one prompt.
  1016. //
  1017. // Old note:
  1018. // there may be a problem with this because we could have a situation
  1019. // where there are multiple file copies from different media. this
  1020. // could happen in the case of a service pack or a winpack.
  1021. //
  1022. // New note: (andrewr) setupapi is smart enough to copy one media's worth of files
  1023. // before copying the other media's files, so the prior concern isn't valid
  1024. //
  1025. b = SfcAddFileToQueue(
  1026. hFileQ,
  1027. FileName,
  1028. TargetFileName,
  1029. TargetDirectory,
  1030. SourceFileName,
  1031. NULL,
  1032. InfName,
  1033. ExcepPackFile,
  1034. &pinfo->si
  1035. );
  1036. if (!b) {
  1037. goto exit;
  1038. }
  1039. //
  1040. // setup the default queue callback with the popups disabled
  1041. //
  1042. MsgHandlerContext = SetupInitDefaultQueueCallbackEx( NULL, INVALID_HANDLE_VALUE, 0, 0, 0 );
  1043. if (MsgHandlerContext == NULL) {
  1044. LastError = GetLastError();
  1045. DebugPrint1( LVL_MINIMAL, L"SetupInitDefaultQueueCallbackEx failed, ec=%d", LastError );
  1046. goto exit;
  1047. }
  1048. //
  1049. // Note: There can be more than one SOURCE_INFO for the entire queue, so
  1050. // this code is not strictly correct. But this is really only a problem
  1051. // in the case that we have to prompt the user for media. This will
  1052. // really work itself out in the NEED_MEDIA callback when we are actually
  1053. // trying to copy the file.
  1054. //
  1055. pinfo->fci.MsgHandlerContext = MsgHandlerContext;
  1056. pinfo->fci.si = &psi;
  1057. pinfo->fci.FileCount = 1;
  1058. psi = &pinfo->si;
  1059. pinfo->si.ValidationRequestData = vrd;
  1060. pinfo->fci.AllowUI = AllowUI;
  1061. pinfo->fci.Flags |= TargetIsCache
  1062. ? FCI_FLAG_COPY_TO_CACHE
  1063. : FCI_FLAG_RESTORE_FILE;
  1064. //
  1065. // force the file queue to require all files be signed
  1066. //
  1067. pSetupSetQueueFlags( hFileQ, pSetupGetQueueFlags( hFileQ ) | FQF_QUEUE_FORCE_BLOCK_POLICY );
  1068. //
  1069. // commit the file queue
  1070. //
  1071. b = SetupCommitFileQueue(
  1072. NULL,
  1073. hFileQ,
  1074. SfcQueueCallback,
  1075. &pinfo->fci
  1076. );
  1077. if (!b) {
  1078. LastError = GetLastError();
  1079. DebugPrint1( LVL_MINIMAL, L"SetupCommitFileQueue failed, ec=0x%08x", LastError );
  1080. }
  1081. if (UIShown) {
  1082. *UIShown = pinfo->fci.UIShown;
  1083. }
  1084. exit:
  1085. //
  1086. // cleanup and exit
  1087. //
  1088. if (MsgHandlerContext) {
  1089. SetupTermDefaultQueueCallback( MsgHandlerContext );
  1090. }
  1091. if (hFileQ != INVALID_HANDLE_VALUE) {
  1092. SetupCloseFileQueue( hFileQ );
  1093. }
  1094. if(pinfo != NULL)
  1095. {
  1096. MemFree(pinfo);
  1097. }
  1098. SetLastError( LastError );
  1099. return b;
  1100. }
  1101. BOOL
  1102. SfcRestoreFromCache(
  1103. IN PVALIDATION_REQUEST_DATA vrd,
  1104. IN HCATADMIN hCatAdmin
  1105. )
  1106. /*++
  1107. Routine Description:
  1108. Routine takes a validated file and attempts to restore it from the cache.
  1109. The routine also does some extra book-keeping tasks, like syncing up the
  1110. copy of the dllcache file with that on disk
  1111. Arguments:
  1112. vrd - pointer to VALIDATION_REQUEST_DATA structure describing the file to
  1113. be restored.
  1114. hCatAdmin - crypto context handle to be used in checking file
  1115. Return Value:
  1116. always TRUE (indicates we successfully validated the DLL as good or bad)
  1117. --*/
  1118. {
  1119. NTSTATUS Status = STATUS_SUCCESS;
  1120. PSFC_REGISTRY_VALUE RegVal = vrd->RegVal;
  1121. PCOMPLETE_VALIDATION_DATA ImageValData = &vrd->ImageValData;
  1122. UNICODE_STRING ActualFileName;
  1123. PWSTR FileName;
  1124. //
  1125. // if the original file isn't present, then we should try to restore it
  1126. // from cache
  1127. //
  1128. if (!ImageValData->Original.SignatureValid) {
  1129. //
  1130. // bad signature
  1131. //
  1132. DebugPrint1( LVL_MINIMAL,
  1133. L"%wZ signature is BAD, try to restore file from cache",
  1134. &RegVal->FileName );
  1135. //
  1136. // we always try to restore from cache first, even if there isn't a
  1137. // file in the cache
  1138. //
  1139. ImageValData->RestoreFromCache = TRUE;
  1140. ImageValData->NotifyUser = TRUE;
  1141. if (!vrd->SyncOnly) {
  1142. ImageValData->EventLog = MSG_DLL_CHANGE;
  1143. }
  1144. } else {
  1145. //
  1146. // good signature, let's do some book-keeping here to sync up the
  1147. // file in the dllcache with that on disk
  1148. //
  1149. if (ImageValData->Original.FilePresent == TRUE && ImageValData->Cache.FilePresent == FALSE) {
  1150. //
  1151. // the file is missing from the cache but the original file has
  1152. // a valid signature...
  1153. // so we put the original file into the cache
  1154. //
  1155. //
  1156. // Note that this doesn't really consider the SFCQuota policy, but
  1157. // it's only one file, so we assume that we won't blow the cache
  1158. // quota.
  1159. //
  1160. DebugPrint1( LVL_MINIMAL, L"Cache file doesn't exist; restoring from real - %wZ", &RegVal->FileName );
  1161. ImageValData->RestoreFromReal = TRUE;
  1162. ImageValData->NotifyUser = FALSE;
  1163. ImageValData->EventLog = 0;
  1164. vrd->SyncOnly = TRUE;
  1165. } else {
  1166. //
  1167. // it looks like both files are present and are valid,
  1168. // but we want to resynch the cach copy because someone
  1169. // may have replaced the real file with a new, valid signed
  1170. // file and now the cached copy doesn't match.
  1171. //
  1172. DebugPrint1( LVL_MINIMAL, L"Real file and cache are both present and valid, replace cache with newer - %wZ", &RegVal->FileName );
  1173. ImageValData->RestoreFromReal = TRUE;
  1174. ImageValData->NotifyUser = FALSE;
  1175. ImageValData->EventLog = 0;
  1176. vrd->SyncOnly = TRUE;
  1177. }
  1178. }
  1179. if (ImageValData->RestoreFromCache || ImageValData->RestoreFromReal) {
  1180. if (ImageValData->RestoreFromReal) {
  1181. //
  1182. // put the real file back in the cache
  1183. //
  1184. FileName = FileNameOnMedia( RegVal );
  1185. RtlInitUnicodeString( &ActualFileName, FileName );
  1186. ASSERT(FileName != NULL);
  1187. ASSERT(RegVal->DirHandle != NULL);
  1188. ASSERT(SfcProtectedDllFileDirectory != NULL);
  1189. Status = SfcCopyFile(
  1190. RegVal->DirHandle,
  1191. RegVal->DirName.Buffer,
  1192. SfcProtectedDllFileDirectory,
  1193. NULL,
  1194. &ActualFileName,
  1195. &RegVal->FileName
  1196. );
  1197. if (NT_SUCCESS(Status)) {
  1198. SfcGetValidationData( &RegVal->FileName,
  1199. &RegVal->FullPathName,
  1200. RegVal->DirHandle,
  1201. hCatAdmin,
  1202. &ImageValData->New );
  1203. if (ImageValData->New.SignatureValid == FALSE) {
  1204. ImageValData->New.DllVersion = 0;
  1205. }
  1206. if ((SFCDisable != SFC_DISABLE_SETUP) && (vrd->SyncOnly == FALSE)) {
  1207. SfcReportEvent( ImageValData->EventLog, RegVal->FullPathName.Buffer, ImageValData, 0 );
  1208. }
  1209. vrd->CopyCompleted = TRUE;
  1210. } else {
  1211. SfcReportEvent( MSG_CACHE_COPY_ERROR, RegVal->FullPathName.Buffer, ImageValData, GetLastError() );
  1212. }
  1213. } else { // restorefromcache == TRUE
  1214. //
  1215. // we need to put the cache copy back
  1216. // but only if the cache version is valid
  1217. //
  1218. if (ImageValData->Cache.FilePresent && ImageValData->Cache.SignatureValid) {
  1219. FileName = FileNameOnMedia( RegVal );
  1220. RtlInitUnicodeString( &ActualFileName, FileName );
  1221. ASSERT(FileName != NULL);
  1222. ASSERT(SfcProtectedDllFileDirectory != NULL);
  1223. ASSERT(RegVal->DirHandle != NULL);
  1224. Status = SfcCopyFile(
  1225. SfcProtectedDllFileDirectory,
  1226. SfcProtectedDllPath.Buffer,
  1227. RegVal->DirHandle,
  1228. RegVal->DirName.Buffer,
  1229. &RegVal->FileName,
  1230. &ActualFileName
  1231. );
  1232. if (NT_SUCCESS(Status)) {
  1233. vrd->CopyCompleted = TRUE;
  1234. ImageValData->NotifyUser = TRUE;
  1235. if (!vrd->SyncOnly) {
  1236. ImageValData->EventLog = MSG_DLL_CHANGE;
  1237. }
  1238. SfcGetValidationData(
  1239. &RegVal->FileName,
  1240. &RegVal->FullPathName,
  1241. RegVal->DirHandle,
  1242. hCatAdmin,
  1243. &ImageValData->New );
  1244. if (ImageValData->New.SignatureValid == FALSE) {
  1245. ImageValData->New.DllVersion = 0;
  1246. }
  1247. if (vrd->SyncOnly == FALSE) {
  1248. SfcReportEvent(
  1249. ImageValData->EventLog,
  1250. RegVal->FullPathName.Buffer,
  1251. ImageValData,
  1252. 0 );
  1253. }
  1254. } else {
  1255. //
  1256. // we failed to copy the file from the cache so we have
  1257. // to restore from media
  1258. //
  1259. ImageValData->RestoreFromMedia = TRUE;
  1260. ImageValData->NotifyUser = TRUE;
  1261. if (!vrd->SyncOnly) {
  1262. ImageValData->EventLog = MSG_DLL_CHANGE;
  1263. }
  1264. }
  1265. } else {
  1266. //
  1267. // need to restore from cache but the cache copy is missing
  1268. // or invalid. Clear the crud out of the cache
  1269. //
  1270. FileName = FileNameOnMedia( RegVal );
  1271. RtlInitUnicodeString( &ActualFileName, FileName );
  1272. DebugPrint2( LVL_MINIMAL,
  1273. L"Cannot restore file from the cache because the "
  1274. L"cache file [%wZ] is invalid - %wZ ",
  1275. &ActualFileName,
  1276. &RegVal->FileName );
  1277. ImageValData->BadCacheEntry = TRUE;
  1278. ImageValData->NotifyUser = TRUE;
  1279. if (!vrd->SyncOnly) {
  1280. ImageValData->EventLog = MSG_DLL_CHANGE;
  1281. }
  1282. ImageValData->RestoreFromMedia = TRUE;
  1283. SfcDeleteFile(
  1284. SfcProtectedDllFileDirectory,
  1285. &ActualFileName );
  1286. SfcReportEvent(
  1287. ImageValData->EventLog,
  1288. RegVal->FullPathName.Buffer,
  1289. ImageValData,
  1290. 0 );
  1291. }
  1292. }
  1293. if (!NT_SUCCESS(Status)) {
  1294. DebugPrint1( LVL_MINIMAL,
  1295. L"Failed to restore a file from the cache - %wZ",
  1296. &RegVal->FileName );
  1297. }
  1298. }
  1299. return TRUE;
  1300. }
  1301. BOOL
  1302. SfcSyncCache(
  1303. IN PVALIDATION_REQUEST_DATA vrd,
  1304. IN HCATADMIN hCatAdmin
  1305. )
  1306. /*++
  1307. Routine Description:
  1308. Routine takes a validated file and attempts to sync a copy of the file in
  1309. the cache.
  1310. Arguments:
  1311. vrd - pointer to VALIDATION_REQUEST_DATA structure describing the file to
  1312. be synced.
  1313. hCatAdmin - crypto context handle to be used in checking file
  1314. Return Value:
  1315. TRUE indicates we successfully sunc a copy in the dllcache
  1316. --*/
  1317. {
  1318. NTSTATUS Status = STATUS_SUCCESS;
  1319. PSFC_REGISTRY_VALUE RegVal = vrd->RegVal;
  1320. PCOMPLETE_VALIDATION_DATA ImageValData = &vrd->ImageValData;
  1321. UNICODE_STRING ActualFileName;
  1322. PWSTR FileName;
  1323. //
  1324. // caller should ensure that the signature is valid before proceeding
  1325. //
  1326. ASSERT(ImageValData->Original.SignatureValid == TRUE);
  1327. //
  1328. // if there is a copy in the dllcache already, let's assume that there is
  1329. // enough space to sync the new copy of the file. Otherwise we have to
  1330. // ensure that there is reasonable space before proceeding.
  1331. //
  1332. //
  1333. if (vrd->ImageValData.Cache.FilePresent == TRUE) {
  1334. ImageValData->RestoreFromReal = TRUE;
  1335. ImageValData->NotifyUser = FALSE;
  1336. ImageValData->EventLog = 0;
  1337. vrd->SyncOnly = TRUE;
  1338. } else {
  1339. ULONGLONG RequiredFreeSpace;
  1340. ULARGE_INTEGER FreeBytesAvailableToCaller;
  1341. ULARGE_INTEGER TotalNumberOfBytes;
  1342. ULARGE_INTEGER TotalNumberOfFreeBytes;
  1343. //
  1344. // The file is not in the cache.
  1345. //
  1346. RequiredFreeSpace = (GetPageFileSize() + SFC_REQUIRED_FREE_SPACE)* ONE_MEG;
  1347. //
  1348. // see
  1349. // a) how much space we have left
  1350. // b) compare against our free space buffer
  1351. // c) how much space the cache is using
  1352. // d) compare against our cache quota
  1353. //
  1354. // if these all succeed, then we're allowed to copy the file into
  1355. // the cache
  1356. //
  1357. if (GetDiskFreeSpaceEx(
  1358. SfcProtectedDllPath.Buffer,
  1359. &FreeBytesAvailableToCaller,
  1360. &TotalNumberOfBytes,
  1361. &TotalNumberOfFreeBytes)
  1362. && TotalNumberOfFreeBytes.QuadPart > RequiredFreeSpace) {
  1363. if (TotalNumberOfBytes.QuadPart <= SFCQuota) {
  1364. ImageValData->RestoreFromReal = TRUE;
  1365. ImageValData->NotifyUser = FALSE;
  1366. ImageValData->EventLog = 0;
  1367. vrd->SyncOnly = TRUE;
  1368. }else {
  1369. DebugPrint1( LVL_MINIMAL,
  1370. L"quota is exceeded (%I64d), can't copy new files",
  1371. TotalNumberOfBytes);
  1372. Status = STATUS_QUOTA_EXCEEDED;
  1373. }
  1374. } else {
  1375. DebugPrint1( LVL_MINIMAL,
  1376. L"Not enough free space on disk (%I64d), can't copy new files",
  1377. TotalNumberOfBytes.QuadPart);
  1378. Status = STATUS_QUOTA_EXCEEDED;
  1379. }
  1380. }
  1381. //
  1382. // if we were told to copy the file above, then do it.
  1383. //
  1384. if (ImageValData->RestoreFromReal) {
  1385. //
  1386. // put the real file back in the cache
  1387. //
  1388. FileName = FileNameOnMedia( RegVal );
  1389. RtlInitUnicodeString( &ActualFileName, FileName );
  1390. ASSERT(FileName != NULL);
  1391. ASSERT(RegVal->DirHandle != NULL);
  1392. ASSERT(SfcProtectedDllFileDirectory != NULL);
  1393. Status = SfcCopyFile(
  1394. RegVal->DirHandle,
  1395. RegVal->DirName.Buffer,
  1396. SfcProtectedDllFileDirectory,
  1397. SfcProtectedDllPath.Buffer,
  1398. &ActualFileName,
  1399. &RegVal->FileName
  1400. );
  1401. if (NT_SUCCESS(Status)) {
  1402. WCHAR FullPathToFile[MAX_PATH];
  1403. UNICODE_STRING FullPathToCacheFile;
  1404. wcscpy(FullPathToFile,SfcProtectedDllPath.Buffer);
  1405. pSetupConcatenatePaths(
  1406. FullPathToFile,
  1407. ActualFileName.Buffer,
  1408. UnicodeChars(FullPathToFile), NULL );
  1409. RtlInitUnicodeString( &FullPathToCacheFile, FullPathToFile );
  1410. SfcGetValidationData( &ActualFileName,
  1411. &FullPathToCacheFile,
  1412. SfcProtectedDllFileDirectory,
  1413. hCatAdmin,
  1414. &ImageValData->New );
  1415. //
  1416. // since we started with a valid file, we had better end up with
  1417. // a valid file installed
  1418. //
  1419. if(ImageValData->New.SignatureValid == TRUE) {
  1420. vrd->CopyCompleted = TRUE;
  1421. } else {
  1422. ImageValData->New.DllVersion = 0;
  1423. SfcReportEvent( MSG_CACHE_COPY_ERROR, RegVal->FullPathName.Buffer, ImageValData, GetLastError() );
  1424. Status = STATUS_UNSUCCESSFUL;
  1425. }
  1426. } else {
  1427. SfcReportEvent( MSG_CACHE_COPY_ERROR, RegVal->FullPathName.Buffer, ImageValData, GetLastError() );
  1428. }
  1429. }
  1430. return (NT_SUCCESS(Status));
  1431. }
  1432. PSOURCE_INFO
  1433. pSfcGetSourceInfoFromSourceName(
  1434. const PSOURCE_INFO *SourceInfoList,
  1435. DWORD SourceInfoCount,
  1436. const PSOURCE_MEDIA SourceMediaInfo
  1437. )
  1438. {
  1439. DWORD i;
  1440. PSOURCE_INFO SourceInfo;
  1441. ASSERT( SourceInfoList != NULL );
  1442. ASSERT( SourceInfoCount > 0 );
  1443. ASSERT( SourceMediaInfo != NULL );
  1444. if (ShuttingDown) {
  1445. return NULL;
  1446. }
  1447. i = 0;
  1448. while (i < SourceInfoCount) {
  1449. SourceInfo = SourceInfoList[i];
  1450. ASSERT(SourceInfo != NULL);
  1451. if (_wcsicmp(
  1452. SourceInfo->SourceFileName,
  1453. SourceMediaInfo->SourceFile) == 0) {
  1454. return (SourceInfo);
  1455. }
  1456. i += 1;
  1457. }
  1458. return (NULL);
  1459. }
  1460. PVALIDATION_REQUEST_DATA
  1461. pSfcGetValidationRequestFromFilePaths(
  1462. const PSOURCE_INFO *SourceInfoList,
  1463. DWORD SourceInfoCount,
  1464. const PFILEPATHS FilePaths
  1465. )
  1466. {
  1467. DWORD i;
  1468. PSOURCE_INFO SourceInfo;
  1469. PCWSTR p;
  1470. ASSERT( SourceInfoList != NULL );
  1471. ASSERT( SourceInfoCount > 0 );
  1472. ASSERT( FilePaths != NULL );
  1473. if (ShuttingDown) {
  1474. return NULL;
  1475. }
  1476. i = 0;
  1477. while (i < SourceInfoCount) {
  1478. SourceInfo = SourceInfoList[i];
  1479. ASSERT(SourceInfo != NULL);
  1480. if (SourceInfo->ValidationRequestData) {
  1481. p = SourceInfo->ValidationRequestData->RegVal->FullPathName.Buffer;
  1482. if (_wcsicmp(
  1483. p,
  1484. FilePaths->Target) == 0) {
  1485. return (SourceInfo->ValidationRequestData);
  1486. }
  1487. }
  1488. i += 1;
  1489. }
  1490. return (NULL);
  1491. }
  1492. BOOL
  1493. SfcQueueAddFileToRestoreQueue(
  1494. IN BOOL RequiresUI,
  1495. IN PSFC_REGISTRY_VALUE RegVal,
  1496. IN PCWSTR InfFileName,
  1497. IN BOOL ExcepPackFile,
  1498. IN OUT PSOURCE_INFO SourceInfo,
  1499. IN PCWSTR ActualFileNameOnMedia
  1500. )
  1501. /*++
  1502. Routine Description:
  1503. This routine tries to add a file to the appropriate global file queue.
  1504. If the queue is being commited, then this routine fails.
  1505. If the file queue does not yet exist, the queue is created.
  1506. Arguments:
  1507. RequiresUI - if TRUE, the file will require UI in order to be
  1508. installed
  1509. RegVal - pointer to SFC_REGISTRY_VALUE that describes file
  1510. to be restored
  1511. SourceInfo - pointer to SOURCE_INFO structure describing where
  1512. the source file is to be restored from
  1513. ActualFileNameOnMedia - the real filename of the file on the source media
  1514. Return Value:
  1515. TRUE if the file was added to the queue, else FALSE.
  1516. --*/
  1517. {
  1518. PRESTORE_QUEUE RestoreQueue;
  1519. BOOL RetVal = FALSE;
  1520. PVOID Ptr;
  1521. ASSERT( SourceInfo != NULL );
  1522. ASSERT( SourceInfo->SourceFileName[0] != (TCHAR)'\0' );
  1523. //
  1524. // point to the proper global queue
  1525. //
  1526. RestoreQueue = RequiresUI
  1527. ? &UIRestoreQueue
  1528. : &SilentRestoreQueue;
  1529. //
  1530. // must protect all of this in a critical section
  1531. //
  1532. RtlEnterCriticalSection( &RestoreQueue->CriticalSection );
  1533. //
  1534. // if the queue is in progress, we can't do anything
  1535. //
  1536. if (!RestoreQueue->RestoreInProgress) {
  1537. //
  1538. // create the queue if it doesn't already exist
  1539. //
  1540. if (RestoreQueue->FileQueue == INVALID_HANDLE_VALUE) {
  1541. RestoreQueue->FileQueue = SetupOpenFileQueue();
  1542. if (RestoreQueue->FileQueue == INVALID_HANDLE_VALUE) {
  1543. DebugPrint1(
  1544. LVL_MINIMAL,
  1545. L"SetupOpenFileQueue() failed, ec=%d",
  1546. GetLastError() );
  1547. goto exit;
  1548. }
  1549. //
  1550. // also preallocate nothing to make re-allocating easy
  1551. //
  1552. ASSERT(RestoreQueue->FileCopyInfo.si == NULL);
  1553. RestoreQueue->FileCopyInfo.si = MemAlloc( 0 );
  1554. }
  1555. ASSERT(RestoreQueue->FileQueue != INVALID_HANDLE_VALUE);
  1556. //
  1557. // now make more room in our array of PSOURCE_INFO pointers
  1558. // for the new entry in our queue and assign that entry.
  1559. //
  1560. Ptr = MemReAlloc(
  1561. ((RestoreQueue->QueueCount + 1) * sizeof(PSOURCE_INFO)),
  1562. RestoreQueue->FileCopyInfo.si );
  1563. if (Ptr) {
  1564. RestoreQueue->FileCopyInfo.si = (PSOURCE_INFO *)Ptr;
  1565. RestoreQueue->FileCopyInfo.si[RestoreQueue->QueueCount] = SourceInfo;
  1566. } else {
  1567. MemFree( (PVOID) RestoreQueue->FileCopyInfo.si );
  1568. goto exit;
  1569. }
  1570. //
  1571. // add the file to the queue
  1572. //
  1573. RetVal = SfcAddFileToQueue(
  1574. RestoreQueue->FileQueue,
  1575. RegVal->FileName.Buffer,
  1576. RegVal->FileName.Buffer,
  1577. RegVal->DirName.Buffer,
  1578. ActualFileNameOnMedia,
  1579. NULL,
  1580. InfFileName,
  1581. ExcepPackFile,
  1582. SourceInfo
  1583. );
  1584. if (!RetVal) {
  1585. DebugPrint2(
  1586. LVL_MINIMAL,
  1587. L"SfcAddFileToQueue failed [%ws], ec = %d",
  1588. RegVal->FileName.Buffer,
  1589. GetLastError() );
  1590. } else {
  1591. RestoreQueue->QueueCount += 1;
  1592. //
  1593. // remember something about adding this entry so that
  1594. // when we commit the file we how to treat it
  1595. //
  1596. SourceInfo->Flags |= SI_FLAG_USERESTORE_QUEUE
  1597. | (RequiresUI ? 0 : SI_FLAG_SILENT_QUEUE) ;
  1598. DebugPrint2(
  1599. LVL_MINIMAL,
  1600. L"Added file [%ws] to %ws queue for restoration",
  1601. RegVal->FileName.Buffer,
  1602. RequiresUI ? L"UIRestoreQueue" : L"SilentRestoreQueue" );
  1603. }
  1604. }
  1605. exit:
  1606. RtlLeaveCriticalSection( &RestoreQueue->CriticalSection );
  1607. return RetVal;
  1608. }
  1609. BOOL
  1610. SfcQueueResetQueue(
  1611. IN BOOL RequiresUI
  1612. )
  1613. /*++
  1614. Routine Description:
  1615. This routine is called after we've successfully committed the file queue.
  1616. The routine removes all of the associated validation requests from our
  1617. queue, logging entries for each of these requests. It also cleans up the
  1618. global file queue to be processed again.
  1619. If the queue has not been commited, then this routine fails.
  1620. Arguments:
  1621. RequiresUI - if TRUE, the file will require UI in order to be
  1622. installed
  1623. Return Value:
  1624. TRUE if the routine succeeded, else FALSE.
  1625. --*/
  1626. {
  1627. PRESTORE_QUEUE RestoreQueue;
  1628. BOOL RetVal = FALSE;
  1629. DWORD Count;
  1630. PLIST_ENTRY Current;
  1631. PVALIDATION_REQUEST_DATA vrd;
  1632. DWORD Mask;
  1633. BOOL DoReset = FALSE;
  1634. DWORD Msg, ErrorCode;
  1635. //
  1636. // point to the proper global queue
  1637. //
  1638. RestoreQueue = RequiresUI
  1639. ? &UIRestoreQueue
  1640. : &SilentRestoreQueue;
  1641. Mask = (VRD_FLAG_REQUEST_PROCESSED | VRD_FLAG_REQUEST_QUEUED)
  1642. | (RequiresUI ? VRD_FLAG_REQUIRE_UI : 0);
  1643. //
  1644. // must protect all of this in a critical section
  1645. //
  1646. RtlEnterCriticalSection( &RestoreQueue->CriticalSection );
  1647. if ((RestoreQueue->RestoreInProgress == TRUE) &&
  1648. (RestoreQueue->RestoreComplete == TRUE)) {
  1649. DoReset = TRUE;
  1650. }
  1651. if (DoReset) {
  1652. RtlEnterCriticalSection( &ErrorCs );
  1653. Current = SfcErrorQueue.Flink;
  1654. Count = 0;
  1655. //
  1656. // cycle through our queue, logging and removing requests as we go.
  1657. //
  1658. while (Current != &SfcErrorQueue) {
  1659. vrd = CONTAINING_RECORD( Current, VALIDATION_REQUEST_DATA, Entry );
  1660. Current = vrd->Entry.Flink;
  1661. //
  1662. // check if we have a valid entry
  1663. //
  1664. if (vrd->Flags == Mask) {
  1665. Count += 1;
  1666. #if 0
  1667. //
  1668. // if the file was copied successfully, then we'd better make
  1669. // sure that the signature of the file is valid
  1670. //
  1671. // if the file failed to be copied, then we'd better have a
  1672. // reason why it failed to be copied
  1673. //
  1674. ASSERT(vrd->CopyCompleted
  1675. ? (vrd->ImageValData.New.SignatureValid == TRUE)
  1676. && (vrd->ImageValData.EventLog == MSG_DLL_CHANGE)
  1677. : (RestoreQueue->LastErrorCode == ERROR_SUCCESS)
  1678. ? ((vrd->ImageValData.EventLog == MSG_RESTORE_FAILURE)
  1679. && (vrd->Win32Error != ERROR_SUCCESS))
  1680. : TRUE );
  1681. #endif
  1682. if (vrd->CopyCompleted && vrd->ImageValData.New.SignatureValid == FALSE) {
  1683. vrd->ImageValData.New.DllVersion = 0;
  1684. }
  1685. DebugPrint2(
  1686. LVL_MINIMAL,
  1687. L"File [%ws] %ws restored successfully.",
  1688. vrd->RegVal->FullPathName.Buffer,
  1689. vrd->CopyCompleted ? L"was" : L"was NOT"
  1690. );
  1691. //
  1692. // log an event
  1693. //
  1694. // first determine if we need to tweak the error code if the
  1695. // user cancelled, then log the event
  1696. //
  1697. ErrorCode = vrd->Win32Error;
  1698. Msg = vrd->ImageValData.EventLog;
  1699. if (RestoreQueue->LastErrorCode != ERROR_SUCCESS) {
  1700. if (RestoreQueue->LastErrorCode == ERROR_CANCELLED) {
  1701. if ((vrd->Win32Error == ERROR_SUCCESS)
  1702. && (vrd->CopyCompleted == FALSE) ) {
  1703. ErrorCode = ERROR_CANCELLED;
  1704. Msg = SFCNoPopUps ? MSG_COPY_CANCEL_NOUI : MSG_COPY_CANCEL;
  1705. }
  1706. } else {
  1707. if ((vrd->Win32Error == ERROR_SUCCESS)
  1708. && (vrd->CopyCompleted == FALSE) ) {
  1709. ErrorCode = RestoreQueue->LastErrorCode;
  1710. Msg = MSG_RESTORE_FAILURE;
  1711. } else if (Msg == 0) {
  1712. Msg = MSG_RESTORE_FAILURE;
  1713. }
  1714. }
  1715. }
  1716. ASSERT(Msg != 0);
  1717. if (Msg == 0) {
  1718. Msg = MSG_RESTORE_FAILURE;
  1719. }
  1720. //
  1721. // log the event
  1722. //
  1723. SfcReportEvent(
  1724. Msg,
  1725. vrd->RegVal->FileName.Buffer,
  1726. &vrd->ImageValData,
  1727. ErrorCode );
  1728. //
  1729. // remove the entry
  1730. //
  1731. RemoveEntryList( &vrd->Entry );
  1732. ErrorQueueCount -= 1;
  1733. MemFree( vrd );
  1734. }
  1735. }
  1736. RtlLeaveCriticalSection( &ErrorCs );
  1737. ASSERT( Count == RestoreQueue->QueueCount );
  1738. CloseHandle( RestoreQueue->WorkerThreadHandle );
  1739. RestoreQueue->WorkerThreadHandle = NULL;
  1740. RestoreQueue->RestoreComplete = FALSE;
  1741. RestoreQueue->QueueCount = 0;
  1742. SetupCloseFileQueue( RestoreQueue->FileQueue );
  1743. RestoreQueue->FileQueue = INVALID_HANDLE_VALUE;
  1744. RestoreQueue->RestoreInProgress = FALSE;
  1745. RestoreQueue->RestoreStatus = FALSE;
  1746. RestoreQueue->LastErrorCode = ERROR_SUCCESS;
  1747. SetupTermDefaultQueueCallback( RestoreQueue->FileCopyInfo.MsgHandlerContext );
  1748. MemFree((PVOID)RestoreQueue->FileCopyInfo.si);
  1749. ZeroMemory( &RestoreQueue->FileCopyInfo, sizeof(FILE_COPY_INFO) );
  1750. }
  1751. RtlLeaveCriticalSection( &RestoreQueue->CriticalSection );
  1752. return ( RetVal );
  1753. }
  1754. BOOL
  1755. SfcQueueCommitRestoreQueue(
  1756. IN BOOL RequiresUI
  1757. )
  1758. /*++
  1759. Routine Description:
  1760. This routine tries to add a file to the appropriate global file queue.
  1761. If the queue is being commited, then this routine fails.
  1762. If the file queue does not yet exist, the queue is created.
  1763. Arguments:
  1764. RequiresUI - if TRUE, the file will require UI in order to be
  1765. installed
  1766. RegVal - pointer to SFC_REGISTRY_VALUE that describes file
  1767. to be restored
  1768. SourceInfo - pointer to SOURCE_INFO structure describing where
  1769. the source file is to be restored from
  1770. ActualFileNameOnMedia - the real filename of the file on the source media
  1771. Return Value:
  1772. TRUE if the file was added to the queue, else FALSE.
  1773. --*/
  1774. {
  1775. PRESTORE_QUEUE RestoreQueue;
  1776. BOOL RetVal = FALSE;
  1777. BOOL DoCommit = FALSE;
  1778. //
  1779. // point to the proper global queue
  1780. //
  1781. RestoreQueue = RequiresUI
  1782. ? &UIRestoreQueue
  1783. : &SilentRestoreQueue;
  1784. //
  1785. // we must protect our restore queue access in a critical section
  1786. //
  1787. RtlEnterCriticalSection( &RestoreQueue->CriticalSection );
  1788. //
  1789. // see if we should commit the queue
  1790. //
  1791. if ( (RestoreQueue->RestoreInProgress == FALSE)
  1792. && (RestoreQueue->RestoreComplete == FALSE)
  1793. && (RestoreQueue->QueueCount > 0)) {
  1794. ASSERT(RestoreQueue->FileQueue != INVALID_HANDLE_VALUE );
  1795. RestoreQueue->RestoreInProgress = TRUE;
  1796. DoCommit = TRUE;
  1797. }
  1798. if (DoCommit) {
  1799. DebugPrint1( LVL_MINIMAL,
  1800. L"Creating pSfcRestoreFromMediaWorkerThread for %ws queue",
  1801. RequiresUI ? L"UIRestoreQueue" : L"SilentRestoreQueue" );
  1802. RestoreQueue->WorkerThreadHandle = CreateThread(
  1803. NULL,
  1804. 0,
  1805. (LPTHREAD_START_ROUTINE)pSfcRestoreFromMediaWorkerThread,
  1806. RestoreQueue,
  1807. 0,
  1808. NULL
  1809. );
  1810. if (!RestoreQueue->WorkerThreadHandle) {
  1811. DebugPrint1( LVL_MINIMAL,
  1812. L"Couldn't create pSfcRestoreFromMediaWorkerThread, ec = 0x%08x",
  1813. GetLastError() );
  1814. RestoreQueue->RestoreInProgress = FALSE;
  1815. }
  1816. }
  1817. RtlLeaveCriticalSection( &RestoreQueue->CriticalSection );
  1818. return ( RetVal );
  1819. }
  1820. DWORD
  1821. pSfcRestoreFromMediaWorkerThread(
  1822. IN PRESTORE_QUEUE RestoreQueue
  1823. )
  1824. /*++
  1825. Routine Description:
  1826. Routine takes a media queue that is ready for committal and commits
  1827. that queue to disk.
  1828. We require another thread to do the actual queue commital for 2
  1829. reasons:
  1830. a) we want to keep servicing change requests as they come in (for example,
  1831. if we have to prompt for UI for some requests and not for others, we can
  1832. commit the requests which do not require UI while we wait for media to
  1833. become present to commit the files which require UI
  1834. b) it makes terminating our valiation thread much easier if we know that we
  1835. will never have popups on the screen as a result of that thread. We can
  1836. simply signal an event for that thread to go away, which can then signal
  1837. these worker threads to go away.
  1838. Arguments:
  1839. RestoreQueue - pointer to a RESTORE_QUEUE structure which describes the
  1840. queue to be committed.
  1841. Return Value:
  1842. N/A.
  1843. --*/
  1844. {
  1845. BOOL RetVal;
  1846. PVOID MsgHandlerContext = NULL;
  1847. BOOL RequiresUI;
  1848. RequiresUI = (RestoreQueue == &UIRestoreQueue);
  1849. ASSERT(RestoreQueue != NULL);
  1850. #if 1
  1851. if (RequiresUI) {
  1852. SetThreadDesktop( hUserDesktop );
  1853. }
  1854. #endif
  1855. DebugPrint1( LVL_MINIMAL,
  1856. L"entering pSfcRestoreFromMediaWorkerThread for %ws queue",
  1857. RequiresUI ? L"UIRestoreQueue" : L"SilentRestoreQueue" );
  1858. //
  1859. // setup the default queue callback with the popups disabled
  1860. //
  1861. MsgHandlerContext = SetupInitDefaultQueueCallbackEx( NULL, INVALID_HANDLE_VALUE, 0, 0, 0 );
  1862. if (MsgHandlerContext == NULL) {
  1863. DebugPrint1( LVL_VERBOSE, L"SetupInitDefaultQueueCallbackEx failed, ec=%d", GetLastError() );
  1864. RetVal = FALSE;
  1865. goto exit;
  1866. }
  1867. //
  1868. // build up a structure which we use in committing the queue.
  1869. //
  1870. RtlEnterCriticalSection( &RestoreQueue->CriticalSection );
  1871. RestoreQueue->FileCopyInfo.MsgHandlerContext = MsgHandlerContext;
  1872. ASSERT( RestoreQueue->FileCopyInfo.si != NULL);
  1873. RestoreQueue->FileCopyInfo.FileCount = RestoreQueue->QueueCount;
  1874. RestoreQueue->FileCopyInfo.AllowUI = RequiresUI;
  1875. //
  1876. // remember that this is a restoration queue.
  1877. // When we commit the queue we will use this fact to mark each file in
  1878. // our queue as processed so that we can log it and remember the
  1879. // file signature, etc.
  1880. //
  1881. RestoreQueue->FileCopyInfo.Flags |= FCI_FLAG_RESTORE_FILE;
  1882. RestoreQueue->FileCopyInfo.Flags |= FCI_FLAG_USERESTORE_QUEUE
  1883. | (RequiresUI ? 0 : FCI_FLAG_SILENT_QUEUE) ;
  1884. //
  1885. // force the file queue to require all files be signed
  1886. //
  1887. pSetupSetQueueFlags( RestoreQueue->FileQueue, pSetupGetQueueFlags( RestoreQueue->FileQueue ) | FQF_QUEUE_FORCE_BLOCK_POLICY );
  1888. RtlLeaveCriticalSection( &RestoreQueue->CriticalSection );
  1889. //
  1890. // commit the file queue
  1891. //
  1892. RetVal = SetupCommitFileQueue(
  1893. NULL,
  1894. RestoreQueue->FileQueue,
  1895. SfcQueueCallback,
  1896. &RestoreQueue->FileCopyInfo
  1897. );
  1898. if (!RetVal) {
  1899. DebugPrint1( LVL_VERBOSE, L"SetupCommitFileQueue failed, ec=0x%08x", GetLastError() );
  1900. }
  1901. //
  1902. // if we succeeded commiting the queue, mark the queue
  1903. //
  1904. RtlEnterCriticalSection( &RestoreQueue->CriticalSection );
  1905. ASSERT(RestoreQueue->RestoreInProgress == TRUE);
  1906. RestoreQueue->RestoreStatus = RetVal;
  1907. RestoreQueue->LastErrorCode = RetVal ? ERROR_SUCCESS : GetLastError();
  1908. RestoreQueue->RestoreComplete = TRUE;
  1909. RtlLeaveCriticalSection( &RestoreQueue->CriticalSection );
  1910. //
  1911. // set an event to wake up the validation thread so it can clean things up
  1912. //
  1913. SetEvent( ErrorQueueEvent );
  1914. exit:
  1915. DebugPrint2( LVL_MINIMAL,
  1916. L"Leaving pSfcRestoreFromMediaWorkerThread for %ws queue, retval = %d",
  1917. RequiresUI ? L"UIRestoreQueue" : L"SilentRestoreQueue",
  1918. RetVal
  1919. );
  1920. return (RetVal);
  1921. }
  1922. DWORD
  1923. SfcGetCabTagFile(
  1924. IN PSOURCE_INFO psi,
  1925. OUT PWSTR* ppFile
  1926. )
  1927. /*++
  1928. Routine Description:
  1929. This function gets the tagfile of a cabfile. It is called when the tagfile for a protected file is a cabfile.
  1930. Allocates the output buffer.
  1931. Arguments:
  1932. psi - the protected file source info
  1933. ppFile - receives the tagfile
  1934. Return value:
  1935. Win32 error code
  1936. --*/
  1937. {
  1938. DWORD dwError = ERROR_SUCCESS;
  1939. BOOL bExcepFile = FALSE;
  1940. HINF hInf = INVALID_HANDLE_VALUE;
  1941. UINT uiInfo = SRCINFO_TAGFILE;
  1942. ASSERT(psi != NULL && ppFile != NULL);
  1943. ASSERT(psi->ValidationRequestData != NULL && psi->ValidationRequestData->RegVal != NULL);
  1944. *ppFile = (PWSTR) MemAlloc(MAX_PATH * sizeof(WCHAR));
  1945. if(NULL == *ppFile) {
  1946. dwError = ERROR_NOT_ENOUGH_MEMORY;
  1947. goto exit;
  1948. }
  1949. //
  1950. // if there is a second tagfile, then we have to use the file's inf instead of layout.inf
  1951. //
  1952. if((psi->SetupAPIFlags & SRC_FLAGS_CABFILE) != 0) {
  1953. uiInfo = SRCINFO_TAGFILE2;
  1954. if(psi->ValidationRequestData != NULL && psi->ValidationRequestData->RegVal != NULL) {
  1955. bExcepFile = SfcGetInfName(psi->ValidationRequestData->RegVal, *ppFile);
  1956. }
  1957. }
  1958. hInf = SfcOpenInf(*ppFile, bExcepFile);
  1959. if(INVALID_HANDLE_VALUE == hInf) {
  1960. dwError = GetLastError();
  1961. goto exit;
  1962. }
  1963. if(!SetupGetSourceInfo(hInf, psi->SourceId, uiInfo, *ppFile, MAX_PATH, NULL)) {
  1964. dwError = GetLastError();
  1965. goto exit;
  1966. }
  1967. exit:
  1968. if(dwError != ERROR_SUCCESS)
  1969. {
  1970. MemFree(*ppFile);
  1971. *ppFile = NULL;
  1972. }
  1973. if(hInf != INVALID_HANDLE_VALUE) {
  1974. SetupCloseInfFile(hInf);
  1975. }
  1976. return dwError;
  1977. }