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.

1826 lines
48 KiB

  1. /*++
  2. Copyright (c) 1995 Microsoft Corporation
  3. Module Name:
  4. dynupdt.c
  5. Abstract:
  6. Routines to handle dynamic update support during GUI setup phase
  7. Author:
  8. Ovidiu Temereanca (ovidiut) 15-Aug-2000
  9. Revision History:
  10. --*/
  11. #include "setupp.h"
  12. #include "hwdb.h"
  13. #include "newdev.h"
  14. #pragma hdrstop
  15. #define STR_UPDATES_INF TEXT("updates.inf")
  16. #define STR_DEFAULTINSTALL TEXT("DefaultInstall")
  17. #define STR_DEFAULTINSTALLFINAL TEXT("DefaultInstallFinal")
  18. #define STR_DRIVERCACHEINF TEXT("drvindex.inf")
  19. #define STR_VERSION TEXT("Version")
  20. #define STR_CABFILES TEXT("CabFiles")
  21. #define STR_CABS TEXT("Cabs")
  22. #define S_HWCOMP_DAT TEXT("hwcomp.dat")
  23. static TCHAR g_DuShare[MAX_PATH];
  24. BOOL
  25. BuildPath (
  26. OUT PTSTR PathBuffer,
  27. IN DWORD PathBufferSize,
  28. IN PCTSTR Path1,
  29. IN PCTSTR Path2
  30. )
  31. /*++
  32. Routine Description:
  33. This function builds a path given the 2 components, assumed not to contain
  34. trailing or heading wacks
  35. Arguments:
  36. PathBuffer - Receives the full path
  37. PathBuferSize - The size in chars of PathBuffer
  38. Path1 - Specifies the head path
  39. Path2 - Specifies the tail path
  40. Return Value:
  41. TRUE to indicate success; FALSE in case of failure; it means the supplied buffer
  42. was too small to fit the whole new path
  43. --*/
  44. {
  45. if (!PathBuffer || !PathBufferSize || !Path1 || !Path2) {
  46. MYASSERT (FALSE);
  47. SetLastError (ERROR_INVALID_PARAMETER);
  48. return FALSE;
  49. }
  50. if (_sntprintf (PathBuffer, PathBufferSize, TEXT("%s\\%s"), Path1, Path2) < 0) {
  51. PathBuffer[0] = 0;
  52. SetLastError (ERROR_INSUFFICIENT_BUFFER);
  53. return FALSE;
  54. }
  55. return TRUE;
  56. }
  57. BOOL
  58. pDoesFileExist (
  59. IN PCTSTR FilePath
  60. )
  61. {
  62. WIN32_FIND_DATA fd;
  63. return FileExists (FilePath, &fd) && !(fd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY);
  64. }
  65. BOOL
  66. pDoesDirExist (
  67. IN PCTSTR FilePath
  68. )
  69. {
  70. WIN32_FIND_DATA fd;
  71. return FileExists (FilePath, &fd) && (fd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY);
  72. }
  73. DWORD
  74. CreateMultiLevelDirectory (
  75. IN LPCTSTR Directory
  76. )
  77. /*++
  78. Routine Description:
  79. This routine ensures that a multi-level path exists by creating individual
  80. levels one at a time. It can handle either paths of form x:... or \\?\Volume{...
  81. Arguments:
  82. Directory - supplies fully-qualified Win32 pathspec of directory to create
  83. Return Value:
  84. Win32 error code indicating outcome.
  85. --*/
  86. {
  87. TCHAR Buffer[MAX_PATH];
  88. PTSTR p,q;
  89. TCHAR c;
  90. BOOL Done;
  91. DWORD d = ERROR_SUCCESS;
  92. if (FAILED (StringCchCopy (Buffer, ARRAYSIZE(Buffer), Directory))) {
  93. return ERROR_INSUFFICIENT_BUFFER;
  94. }
  95. //
  96. // If it already exists do nothing. (We do this before syntax checking
  97. // to allow for remote paths that already exist. This is needed for
  98. // remote boot machines.)
  99. //
  100. d = GetFileAttributes(Buffer);
  101. if(d != (DWORD)(-1)) {
  102. return((d & FILE_ATTRIBUTE_DIRECTORY) ? NO_ERROR : ERROR_DIRECTORY);
  103. }
  104. //
  105. // Check path format
  106. //
  107. c = (TCHAR)CharUpper((LPTSTR)Buffer[0]);
  108. if (c < TEXT('A') || c > TEXT('Z') || Buffer[1] != TEXT(':')) {
  109. return ERROR_INVALID_PARAMETER;
  110. }
  111. if(Buffer[2] != TEXT('\\')) {
  112. return(Buffer[2] ? ERROR_INVALID_PARAMETER : ERROR_SUCCESS);
  113. }
  114. q = Buffer + 3;
  115. if(*q == 0) {
  116. return(ERROR_SUCCESS);
  117. }
  118. Done = FALSE;
  119. do {
  120. //
  121. // Locate the next path sep char. If there is none then
  122. // this is the deepest level of the path.
  123. //
  124. if(p = _tcschr(q,TEXT('\\'))) {
  125. *p = 0;
  126. } else {
  127. Done = TRUE;
  128. }
  129. //
  130. // Create this portion of the path.
  131. //
  132. if(CreateDirectory(Buffer,NULL)) {
  133. d = ERROR_SUCCESS;
  134. } else {
  135. d = GetLastError();
  136. if(d == ERROR_ALREADY_EXISTS) {
  137. d = ERROR_SUCCESS;
  138. }
  139. }
  140. if(d == ERROR_SUCCESS) {
  141. //
  142. // Put back the path sep and move to the next component.
  143. //
  144. if(!Done) {
  145. *p = TEXT('\\');
  146. q = p+1;
  147. }
  148. } else {
  149. Done = TRUE;
  150. }
  151. } while(!Done);
  152. return(d);
  153. }
  154. DWORD
  155. GetDriverCacheSourcePath (
  156. OUT PTSTR Buffer,
  157. IN DWORD BufChars
  158. )
  159. /*++
  160. Routine Description:
  161. This routine returns the source path to the local driver cache.
  162. This value is retrieved from the following registry location:
  163. \HKLM\Software\Microsoft\Windows\CurrentVersion\Setup
  164. DriverCachePath : REG_EXPAND_SZ :
  165. Arguments:
  166. Buffer - Receives the path.
  167. BufChars - Specifies the size of Buffer, in chars
  168. Return Value:
  169. If the function succeeds, the return value is TRUE
  170. If the function fails, the return value is FALSE.
  171. --*/
  172. {
  173. HKEY hKey;
  174. DWORD rc, DataType, DataSize;
  175. TCHAR Value[MAX_PATH];
  176. rc = RegOpenKeyEx(
  177. HKEY_LOCAL_MACHINE,
  178. REGSTR_PATH_SETUP TEXT("\\Setup"),
  179. 0,
  180. KEY_READ,
  181. &hKey
  182. );
  183. if(rc == ERROR_SUCCESS) {
  184. //
  185. // Attempt to read the "DriverCachePath" value.
  186. //
  187. DataSize = sizeof (Value);
  188. rc = RegQueryValueEx (hKey, REGSTR_VAL_DRIVERCACHEPATH, NULL, &DataType, (PBYTE)Value, &DataSize);
  189. RegCloseKey(hKey);
  190. if(rc == ERROR_SUCCESS) {
  191. ExpandEnvironmentStrings (Value, Buffer, BufChars - 6);
  192. if (Buffer[0]) {
  193. _tcscat (
  194. Buffer,
  195. #if defined(_AMD64_)
  196. TEXT("\\amd64")
  197. #elif defined(_X86_)
  198. IsNEC_98 ? TEXT("\\nec98") : TEXT("\\i386")
  199. #elif defined(_IA64_)
  200. TEXT("\\ia64")
  201. #else
  202. #error "No Target Architecture"
  203. #endif
  204. );
  205. return ERROR_SUCCESS;
  206. } else {
  207. rc = ERROR_INVALID_DATA;
  208. }
  209. }
  210. }
  211. return rc;
  212. }
  213. PCTSTR
  214. FindSubString (
  215. IN PCTSTR String,
  216. IN TCHAR Separator,
  217. IN PCTSTR SubStr,
  218. IN BOOL CaseSensitive
  219. )
  220. /*++
  221. Routine Description:
  222. This function looks for a substring of a given string, only if found
  223. between the specified separator chars
  224. Arguments:
  225. String - Specifies the full string
  226. Separator - Specifies the separator
  227. SubStr - Specifies the sub string to look for
  228. CaseSensitive - Specifies if the comparison should be case sensitive or not
  229. Return Value:
  230. NULL if the substring was not found; a pointer to the SubString inside String
  231. if it was found
  232. --*/
  233. {
  234. SIZE_T len1, len2;
  235. PCTSTR end;
  236. MYASSERT (Separator);
  237. MYASSERT (SubStr);
  238. MYASSERT (!_tcschr (SubStr, Separator));
  239. len1 = lstrlen (SubStr);
  240. MYASSERT (SubStr[len1] == 0);
  241. while (String) {
  242. end = _tcschr (String, Separator);
  243. if (end) {
  244. len2 = end - String;
  245. } else {
  246. len2 = lstrlen (String);
  247. }
  248. if ((len1 == len2) &&
  249. (CaseSensitive ?
  250. !_tcsncmp (String, SubStr, len1) :
  251. !_tcsnicmp (String, SubStr, len1)
  252. )) {
  253. break;
  254. }
  255. if (end) {
  256. String = end + 1;
  257. } else {
  258. String = NULL;
  259. }
  260. }
  261. return String;
  262. }
  263. BOOL
  264. UpdateDrvIndex (
  265. IN PCTSTR InfPath,
  266. IN PCTSTR CabFilename,
  267. IN PCTSTR SourceSifPath
  268. )
  269. /*++
  270. Routine Description:
  271. This function fixes drvindex.inf such that SetupApi
  272. will pick up the file from the right cabinet
  273. Arguments:
  274. InfPath - Specifies the full path to drvindex.inf
  275. CabFilename - Specifies the filename of the
  276. updates cabinet (basically it's "updates.cab")
  277. SourceSifPath - Specifies the full path to the associated
  278. updates.sif containing the list of files in updates.cab
  279. Return Value:
  280. TRUE to indicate success; FALSE in case of failure; use GetLastError()
  281. to find the reason of failure
  282. --*/
  283. {
  284. HANDLE sectFile = INVALID_HANDLE_VALUE;
  285. HANDLE concatFile = INVALID_HANDLE_VALUE;
  286. HANDLE hMap = NULL;
  287. PTSTR section = NULL;
  288. PBYTE base = NULL;
  289. TCHAR tempPath[MAX_PATH];
  290. TCHAR tempFile[MAX_PATH];
  291. TCHAR temp[MAX_PATH];
  292. PTSTR p;
  293. DWORD sectSize;
  294. DWORD concatSize;
  295. DWORD rc;
  296. DWORD bytes;
  297. BOOL b = FALSE;
  298. //
  299. // create a temp file to put the new section in it
  300. //
  301. if (!GetTempPath (ARRAYSIZE(tempPath), tempPath) ||
  302. !GetTempFileName (tempPath, TEXT("STP"), 0, tempFile)
  303. ) {
  304. return FALSE;
  305. }
  306. __try {
  307. if (!CopyFile (InfPath, tempFile, FALSE)) {
  308. __leave;
  309. }
  310. SetFileAttributes (tempFile, FILE_ATTRIBUTE_NORMAL);
  311. section = pSetupDuplicateString (CabFilename);
  312. if (!section) {
  313. __leave;
  314. }
  315. p = _tcsrchr (section, TEXT('.'));
  316. if (p) {
  317. *p = 0;
  318. }
  319. if (GetPrivateProfileString (
  320. STR_CABS,
  321. section,
  322. TEXT(""),
  323. temp,
  324. ARRAYSIZE(temp),
  325. tempFile
  326. )) {
  327. if (lstrcmpi (temp, CabFilename) == 0) {
  328. if (GetPrivateProfileString (
  329. STR_VERSION,
  330. STR_CABFILES,
  331. TEXT(""),
  332. tempPath,
  333. ARRAYSIZE(tempPath),
  334. tempFile
  335. )) {
  336. if (FindSubString (tempPath, TEXT(','), section, FALSE)) {
  337. //
  338. // setup restarted, but drvindex.inf is already patched; nothing to do
  339. //
  340. b = TRUE;
  341. __leave;
  342. }
  343. }
  344. }
  345. }
  346. if (!WritePrivateProfileString (
  347. STR_CABS,
  348. section,
  349. CabFilename,
  350. tempFile
  351. )) {
  352. __leave;
  353. }
  354. if (!GetPrivateProfileString (
  355. STR_VERSION,
  356. STR_CABFILES,
  357. TEXT(""),
  358. tempPath,
  359. ARRAYSIZE(tempPath),
  360. tempFile
  361. )) {
  362. __leave;
  363. }
  364. if (!FindSubString (tempPath, TEXT(','), section, FALSE)) {
  365. wsprintf (temp, TEXT("%s,%s"), section, tempPath);
  366. if (!WritePrivateProfileString (
  367. STR_VERSION,
  368. STR_CABFILES,
  369. temp,
  370. tempFile
  371. )) {
  372. __leave;
  373. }
  374. }
  375. sectFile = CreateFile (
  376. SourceSifPath,
  377. GENERIC_READ,
  378. 0,
  379. NULL,
  380. OPEN_EXISTING,
  381. FILE_ATTRIBUTE_NORMAL,
  382. NULL
  383. );
  384. if (sectFile == INVALID_HANDLE_VALUE) {
  385. __leave;
  386. }
  387. sectSize = GetFileSize (sectFile, NULL);
  388. if (sectSize == INVALID_FILE_SIZE) {
  389. __leave;
  390. }
  391. concatFile = CreateFile (
  392. tempFile,
  393. GENERIC_READ | GENERIC_WRITE,
  394. 0,
  395. NULL,
  396. OPEN_EXISTING,
  397. FILE_ATTRIBUTE_NORMAL,
  398. NULL
  399. );
  400. if (concatFile == INVALID_HANDLE_VALUE) {
  401. __leave;
  402. }
  403. concatSize = GetFileSize (concatFile, NULL);
  404. if (concatSize == INVALID_FILE_SIZE) {
  405. __leave;
  406. }
  407. hMap = CreateFileMapping (concatFile, NULL, PAGE_READWRITE, 0, concatSize + sectSize, NULL);
  408. if (!hMap) {
  409. __leave;
  410. }
  411. base = MapViewOfFile (
  412. hMap,
  413. FILE_MAP_ALL_ACCESS,
  414. 0,
  415. 0,
  416. 0
  417. );
  418. if (!base) {
  419. __leave;
  420. }
  421. //
  422. // make sure concatFile file didn't end in end-of-file
  423. //
  424. if (base[concatSize - 1] == 0x1A) {
  425. base[concatSize - 1] = ' ';
  426. }
  427. //
  428. // now append the other file
  429. //
  430. if (!ReadFile (sectFile, (LPVOID)(base + concatSize), sectSize, &bytes, NULL) || bytes != sectSize) {
  431. __leave;
  432. }
  433. //
  434. // now try to commit changes
  435. //
  436. if (!UnmapViewOfFile (base)) {
  437. __leave;
  438. }
  439. base = NULL;
  440. if (!CloseHandle (hMap)) {
  441. __leave;
  442. }
  443. hMap = NULL;
  444. //
  445. // close the handle to the temporary file and overwrite the real one
  446. //
  447. if (!CloseHandle (concatFile)) {
  448. __leave;
  449. }
  450. concatFile = INVALID_HANDLE_VALUE;
  451. SetFileAttributes (InfPath, FILE_ATTRIBUTE_NORMAL);
  452. b = MoveFileEx (tempFile, InfPath, MOVEFILE_COPY_ALLOWED | MOVEFILE_REPLACE_EXISTING);
  453. }
  454. __finally {
  455. rc = b ? ERROR_SUCCESS : GetLastError ();
  456. DeleteFile (tempFile);
  457. if (base) {
  458. UnmapViewOfFile (base);
  459. }
  460. if (hMap) {
  461. CloseHandle (hMap);
  462. }
  463. if (concatFile != INVALID_HANDLE_VALUE) {
  464. CloseHandle (concatFile);
  465. }
  466. if (sectFile != INVALID_HANDLE_VALUE) {
  467. CloseHandle (sectFile);
  468. }
  469. if (section) {
  470. MyFree (section);
  471. }
  472. SetLastError (rc);
  473. }
  474. return b;
  475. }
  476. UINT
  477. pExpandUpdatesCab (
  478. IN PVOID Context,
  479. IN UINT Code,
  480. IN UINT_PTR Param1,
  481. IN UINT_PTR Param2
  482. )
  483. {
  484. switch (Code) {
  485. case SPFILENOTIFY_FILEINCABINET:
  486. {
  487. PFILE_IN_CABINET_INFO FileInCabInfo = (PFILE_IN_CABINET_INFO)Param1;
  488. //
  489. // extract the file name
  490. //
  491. PCTSTR p = _tcsrchr (FileInCabInfo->NameInCabinet, TEXT('\\'));
  492. if (p) {
  493. p++;
  494. } else {
  495. p = FileInCabInfo->NameInCabinet;
  496. }
  497. lstrcpy (FileInCabInfo->FullTargetName, (PCTSTR)Context);
  498. pSetupConcatenatePaths (
  499. FileInCabInfo->FullTargetName,
  500. p,
  501. SIZECHARS (FileInCabInfo->FullTargetName),
  502. NULL
  503. );
  504. return FILEOP_DOIT;
  505. }
  506. case SPFILENOTIFY_NEEDNEWCABINET:
  507. {
  508. PCABINET_INFO CabInfo = (PCABINET_INFO)Param1;
  509. SetuplogError(
  510. LogSevError,
  511. SETUPLOG_USE_MESSAGEID,
  512. MSG_LOG_SYSSETUP_CAB_MISSING,
  513. CabInfo->CabinetPath,
  514. CabInfo->CabinetFile,
  515. CabInfo->DiskName,
  516. CabInfo->SetId,
  517. CabInfo->CabinetNumber,
  518. NULL,
  519. NULL
  520. );
  521. return ERROR_FILE_NOT_FOUND;
  522. }
  523. }
  524. return NO_ERROR;
  525. }
  526. VOID
  527. pInstallUpdatesInf (
  528. IN PCTSTR SectionToInstall
  529. )
  530. /*++
  531. Routine Description:
  532. This function installs the specified section of STR_UPDATES_INF
  533. if this file is found inside updates.cab
  534. Arguments:
  535. SectionToInstall - Specifies what section to install
  536. Return Value:
  537. none
  538. --*/
  539. {
  540. TCHAR infPath[MAX_PATH];
  541. TCHAR commandLine[MAX_PATH + 30];
  542. /*
  543. STARTUPINFO si;
  544. PROCESS_INFORMATION pi;
  545. */
  546. MYASSERT (!MiniSetup && !OobeSetup);
  547. MYASSERT (g_DuShare[0]);
  548. if (BuildPath (infPath, ARRAYSIZE(infPath), g_DuShare, STR_UPDATES_INF) &&
  549. pDoesFileExist (infPath)) {
  550. //
  551. // install this INF as if the user chose "Install" on the right-click popup menu
  552. //
  553. if (SUCCEEDED (StringCchPrintf (
  554. commandLine,
  555. ARRAYSIZE(commandLine),
  556. TEXT("RUNDLL32.EXE SETUPAPI.DLL,InstallHinfSection %s %u %s"),
  557. SectionToInstall,
  558. 128, // don't reboot
  559. infPath
  560. ))) {
  561. InvokeExternalApplicationEx (NULL, commandLine, NULL, INFINITE, FALSE);
  562. } else {
  563. MYASSERT (FALSE);
  564. }
  565. /*
  566. ZeroMemory (&si, sizeof (si));
  567. si.cb = sizeof (si);
  568. if (CreateProcess (
  569. NULL,
  570. commandLine,
  571. NULL,
  572. NULL,
  573. FALSE,
  574. CREATE_NO_WINDOW | ABOVE_NORMAL_PRIORITY_CLASS,
  575. NULL,
  576. NULL,
  577. &si,
  578. &pi
  579. )) {
  580. CloseHandle (pi.hProcess);
  581. CloseHandle (pi.hThread);
  582. */
  583. } else {
  584. SetuplogError (
  585. LogSevInformation,
  586. TEXT("DUInfo: No %1 to install"),
  587. 0,
  588. STR_UPDATES_INF,
  589. NULL,
  590. NULL
  591. );
  592. }
  593. }
  594. BOOL
  595. DuInitialize (
  596. VOID
  597. )
  598. /*++
  599. Routine Description:
  600. This function initializes DU in GUI setup
  601. Arguments:
  602. none
  603. Return Value:
  604. TRUE to indicate success; FALSE in case of failure; use GetLastError()
  605. to find the reason of failure
  606. --*/
  607. {
  608. PTSTR cabFilename;
  609. TCHAR sourceCabPath[MAX_PATH];
  610. TCHAR workingDir[MAX_PATH];
  611. DWORD rc;
  612. MYASSERT (!MiniSetup && !OobeSetup);
  613. MYASSERT (AnswerFile[0]);
  614. if (!GetPrivateProfileString (
  615. WINNT_SETUPPARAMS,
  616. WINNT_SP_UPDATEDSOURCES,
  617. TEXT(""),
  618. sourceCabPath,
  619. ARRAYSIZE(sourceCabPath),
  620. AnswerFile
  621. )) {
  622. return TRUE;
  623. }
  624. if (!GetPrivateProfileString (
  625. WINNT_SETUPPARAMS,
  626. WINNT_SP_DYNUPDTWORKINGDIR,
  627. TEXT(""),
  628. workingDir,
  629. ARRAYSIZE(workingDir),
  630. AnswerFile
  631. )) {
  632. MYASSERT (FALSE);
  633. if (!GetWindowsDirectory (workingDir, ARRAYSIZE(workingDir))) {
  634. return FALSE;
  635. }
  636. if (!pSetupConcatenatePaths (workingDir, TEXT("setupupd"), ARRAYSIZE(workingDir), NULL)) {
  637. return FALSE;
  638. }
  639. WritePrivateProfileString (
  640. WINNT_SETUPPARAMS,
  641. WINNT_SP_DYNUPDTWORKINGDIR,
  642. workingDir,
  643. AnswerFile
  644. );
  645. }
  646. MYASSERT (workingDir[0]);
  647. if (!pSetupConcatenatePaths (workingDir, TEXT("updates"), ARRAYSIZE(workingDir), NULL) ||
  648. !pSetupConcatenatePaths (
  649. workingDir,
  650. #if defined(_AMD64_)
  651. TEXT("amd64"),
  652. #elif defined(_X86_)
  653. TEXT("i386"),
  654. #elif defined(_IA64_)
  655. TEXT("ia64"),
  656. #else
  657. #error "No Target Architecture"
  658. #endif
  659. ARRAYSIZE(workingDir),
  660. NULL
  661. )) {
  662. return FALSE;
  663. }
  664. if (CreateMultiLevelDirectory (workingDir) != ERROR_SUCCESS) {
  665. rc = GetLastError ();
  666. SetuplogError (
  667. LogSevError,
  668. TEXT("DUError: DuInitialize: failed to create %1 (%2!u!)\r\n"),
  669. 0,
  670. workingDir,
  671. rc,
  672. NULL,
  673. NULL
  674. );
  675. return FALSE;
  676. }
  677. //
  678. // expand updates.cab in this folder
  679. //
  680. if (!SetupIterateCabinet (sourceCabPath, 0, pExpandUpdatesCab, (PVOID)workingDir)) {
  681. rc = GetLastError ();
  682. SetuplogError (
  683. LogSevError,
  684. TEXT("DUError: DuInitialize: failed to expand %1 to %2 (%3!u!)\r\n"),
  685. 0,
  686. sourceCabPath,
  687. workingDir,
  688. rc,
  689. NULL,
  690. NULL
  691. );
  692. return FALSE;
  693. }
  694. //
  695. // OK, everything is set up; go ahead and set the global variable
  696. //
  697. MYASSERT (ARRAYSIZE(g_DuShare) >= ARRAYSIZE(workingDir));
  698. lstrcpy (g_DuShare, workingDir);
  699. return TRUE;
  700. }
  701. DWORD
  702. DuInstallCatalogs (
  703. OUT SetupapiVerifyProblem* Problem,
  704. OUT PTSTR ProblemFile,
  705. IN PCTSTR DescriptionForError OPTIONAL
  706. )
  707. /*++
  708. Routine Description:
  709. This function installs any catalogs found inside updates.cab
  710. Arguments:
  711. same as InstallProductCatalogs
  712. Return Value:
  713. If successful, the return value is ERROR_SUCCESS, otherwise it is a Win32 error
  714. code indicating the cause of the failure.
  715. --*/
  716. {
  717. TCHAR catPath[MAX_PATH];
  718. WIN32_FIND_DATA fd;
  719. HANDLE h;
  720. UINT ErrorMessageId;
  721. DWORD rc = ERROR_SUCCESS;
  722. MYASSERT (!MiniSetup && !OobeSetup);
  723. if (!g_DuShare[0]) {
  724. return ERROR_SUCCESS;
  725. }
  726. if (!BuildPath (catPath, ARRAYSIZE(catPath), g_DuShare, TEXT("*.cat"))) {
  727. return ERROR_INSUFFICIENT_BUFFER;
  728. }
  729. h = FindFirstFile (catPath, &fd);
  730. if (h != INVALID_HANDLE_VALUE) {
  731. do {
  732. if (!(fd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)) {
  733. if (!BuildPath (catPath, ARRAYSIZE(catPath), g_DuShare, fd.cFileName)) {
  734. SetuplogError (
  735. LogSevWarning,
  736. TEXT("DUWarning: ignoring catalog [%1\\%2] - path too long\r\n"),
  737. 0,
  738. g_DuShare,
  739. fd.cFileName,
  740. NULL,
  741. NULL
  742. );
  743. continue;
  744. }
  745. rc = pSetupVerifyCatalogFile (catPath);
  746. if (rc == NO_ERROR) {
  747. rc = pSetupInstallCatalog(catPath, fd.cFileName, NULL);
  748. if(rc != NO_ERROR) {
  749. ErrorMessageId = MSG_LOG_SYSSETUP_CATINSTALL_FAILED;
  750. }
  751. } else {
  752. ErrorMessageId = MSG_LOG_SYSSETUP_VERIFY_FAILED;
  753. }
  754. if(rc != NO_ERROR) {
  755. SetuplogError (
  756. LogSevError,
  757. SETUPLOG_USE_MESSAGEID,
  758. ErrorMessageId,
  759. catPath,
  760. rc,
  761. NULL,
  762. NULL
  763. );
  764. //
  765. // Also, add an entry about this failure to setupapi's PSS
  766. // exception logfile.
  767. //
  768. pSetupHandleFailedVerification (
  769. MainWindowHandle,
  770. SetupapiVerifyCatalogProblem,
  771. catPath,
  772. DescriptionForError,
  773. pSetupGetCurrentDriverSigningPolicy(FALSE),
  774. TRUE, // no UI!
  775. rc,
  776. NULL, // log context
  777. NULL, // optional flags
  778. NULL
  779. );
  780. break;
  781. }
  782. }
  783. } while (FindNextFile (h, &fd));
  784. FindClose (h);
  785. } else {
  786. SetuplogError (
  787. LogSevWarning,
  788. TEXT("DUWarning: no catalogs found in %1\r\n"),
  789. 0,
  790. g_DuShare,
  791. NULL,
  792. NULL
  793. );
  794. }
  795. return rc;
  796. }
  797. DWORD
  798. DuInstallUpdates (
  799. VOID
  800. )
  801. /*++
  802. Routine Description:
  803. This routine updates drvindex.inf to point setupapi to the new binaries.
  804. Arguments:
  805. none
  806. Return Value:
  807. If successful, the return value is ERROR_SUCCESS, otherwise it is a Win32 error
  808. code indicating the cause of the failure.
  809. --*/
  810. {
  811. PTSTR cabFilename;
  812. TCHAR sourceCabPath[MAX_PATH];
  813. TCHAR sourceSifPath[MAX_PATH];
  814. TCHAR cabPath[MAX_PATH];
  815. TCHAR infPath[MAX_PATH];
  816. TCHAR tmpPath[MAX_PATH];
  817. DWORD rc;
  818. MYASSERT (!MiniSetup && !OobeSetup);
  819. if (!g_DuShare[0]) {
  820. return ERROR_SUCCESS;
  821. }
  822. //
  823. // make sure updates.sif is available
  824. //
  825. if (!GetPrivateProfileString (
  826. WINNT_SETUPPARAMS,
  827. WINNT_SP_UPDATEDSOURCES,
  828. TEXT(""),
  829. sourceCabPath,
  830. ARRAYSIZE(sourceCabPath),
  831. AnswerFile
  832. )) {
  833. return GetLastError ();
  834. }
  835. MYASSERT (ARRAYSIZE(sourceSifPath) >= ARRAYSIZE(sourceCabPath));
  836. lstrcpy (sourceSifPath, sourceCabPath);
  837. cabFilename = _tcsrchr (sourceSifPath, TEXT('.'));
  838. if (!cabFilename || _tcschr (cabFilename, TEXT('\\'))) {
  839. SetuplogError (
  840. LogSevError,
  841. SETUPLOG_USE_MESSAGEID,
  842. MSG_LOG_INVALID_UPDATESCAB_NAME,
  843. sourceCabPath,
  844. NULL,
  845. NULL
  846. );
  847. return ERROR_INVALID_DATA;
  848. }
  849. lstrcpyn (cabFilename + 1, TEXT("sif"), (INT)(sourceSifPath + ARRAYSIZE(sourceSifPath) - (cabFilename + 1)));
  850. if (!pDoesFileExist (sourceSifPath)) {
  851. rc = GetLastError ();
  852. SetuplogError (
  853. LogSevError,
  854. SETUPLOG_USE_MESSAGEID,
  855. MSG_LOG_UPDATESSIF_NOT_FOUND,
  856. sourceSifPath,
  857. sourceCabPath,
  858. rc,
  859. NULL,
  860. NULL
  861. );
  862. return rc;
  863. }
  864. //
  865. // copy this where source cabs reside
  866. //
  867. rc = GetDriverCacheSourcePath (cabPath, ARRAYSIZE(cabPath));
  868. if (rc != ERROR_SUCCESS) {
  869. SetuplogError (
  870. LogSevError,
  871. SETUPLOG_USE_MESSAGEID,
  872. MSG_LOG_DRIVER_CACHE_NOT_FOUND,
  873. rc,
  874. NULL,
  875. NULL
  876. );
  877. return rc;
  878. }
  879. cabFilename = _tcsrchr (sourceCabPath, TEXT('\\'));
  880. if (cabFilename) {
  881. cabFilename++;
  882. } else {
  883. cabFilename = cabPath;
  884. }
  885. if (!pSetupConcatenatePaths (cabPath, cabFilename, ARRAYSIZE(cabPath), NULL)) {
  886. return ERROR_INSUFFICIENT_BUFFER;
  887. }
  888. //
  889. // GUI setup should be restartable; copy file, don't move it
  890. //
  891. SetFileAttributes (cabPath, FILE_ATTRIBUTE_NORMAL);
  892. if (!CopyFile (sourceCabPath, cabPath, FALSE)) {
  893. rc = GetLastError ();
  894. SetuplogError (
  895. LogSevError,
  896. SETUPLOG_USE_MESSAGEID,
  897. MSG_LOG_FAILED_TO_COPY_UPDATES,
  898. rc,
  899. NULL,
  900. NULL
  901. );
  902. return rc;
  903. }
  904. //
  905. // now make sure the file attributes are set to RHS to protect it
  906. //
  907. SetFileAttributes (cabPath, FILE_ATTRIBUTE_SYSTEM | FILE_ATTRIBUTE_HIDDEN | FILE_ATTRIBUTE_READONLY);
  908. //
  909. // temp folder for expanded files
  910. //
  911. if (!GetTempPath (ARRAYSIZE(tmpPath), tmpPath)) {
  912. rc = GetLastError ();
  913. return rc;
  914. }
  915. //
  916. // full path to drvindex.inf, assuming the file is in %windir%\inf
  917. //
  918. if (!GetWindowsDirectory (infPath, ARRAYSIZE(infPath))) {
  919. rc = GetLastError ();
  920. return rc;
  921. }
  922. if (FAILED (StringCchCat (infPath, ARRAYSIZE(infPath), TEXT("\\inf\\"))) ||
  923. FAILED (StringCchCat (infPath, ARRAYSIZE(infPath), STR_DRIVERCACHEINF)) ||
  924. GetFileAttributes (infPath) == (DWORD)-1) {
  925. rc = GetLastError ();
  926. SetuplogError (
  927. LogSevError,
  928. TEXT("DUError: %1 not found (rc=%2!u!)\r\n"),
  929. 0,
  930. infPath,
  931. rc,
  932. NULL,
  933. NULL
  934. );
  935. return rc;
  936. }
  937. //
  938. // now patch drvindex.inf
  939. //
  940. if (!UpdateDrvIndex (infPath, cabFilename, sourceSifPath)) {
  941. rc = GetLastError ();
  942. SetuplogError (
  943. LogSevError,
  944. SETUPLOG_USE_MESSAGEID,
  945. MSG_LOG_FAILED_TO_UPDATE_DRVINDEX,
  946. rc,
  947. NULL,
  948. NULL
  949. );
  950. SetFileAttributes (cabPath, FILE_ATTRIBUTE_NORMAL);
  951. DeleteFile (cabPath);
  952. return rc;
  953. }
  954. //
  955. // finally run updates.inf (first part)
  956. //
  957. pInstallUpdatesInf (STR_DEFAULTINSTALL);
  958. return rc;
  959. }
  960. BOOL
  961. DuInstallEndGuiSetupDrivers (
  962. VOID
  963. )
  964. /*++
  965. Routine Description:
  966. This routine installs any WU drivers not approved for the beginning of GUI setup.
  967. Arguments:
  968. none
  969. Return Value:
  970. If successful, the return value is TRUE
  971. --*/
  972. {
  973. DWORD chars;
  974. TCHAR datPath[MAX_PATH];
  975. TCHAR infPath[MAX_PATH];
  976. TCHAR buf[MAX_PATH * 16];
  977. PTSTR source, p, next;
  978. BOOL bRebootRequired;
  979. HWDBINF_ENUM e;
  980. PCTSTR pnpId;
  981. HMODULE hNewDev;
  982. HINF hGuiDrvsInf;
  983. INFCONTEXT ic;
  984. UINT line;
  985. BOOL (WINAPI* pfnUpdateDriver) (
  986. HWND hwndParent,
  987. LPCWSTR HardwareId,
  988. LPCWSTR FullInfPath,
  989. DWORD InstallFlags,
  990. PBOOL bRebootRequired OPTIONAL
  991. );
  992. //
  993. // try to append any additional POST GUI setup drivers
  994. // in the DevicePath
  995. //
  996. if (!SpSetupLoadParameter (
  997. WINNT_SP_DYNUPDTADDITIONALPOSTGUIDRIVERS,
  998. buf,
  999. ARRAYSIZE(buf)
  1000. )) {
  1001. return TRUE;
  1002. }
  1003. chars = lstrlen (buf);
  1004. if (!chars) {
  1005. return TRUE;
  1006. }
  1007. //
  1008. // load the support library newdev.dll
  1009. //
  1010. hNewDev = LoadLibrary (TEXT("newdev.dll"));
  1011. if (!hNewDev) {
  1012. return FALSE;
  1013. }
  1014. (FARPROC)pfnUpdateDriver = GetProcAddress (hNewDev, "UpdateDriverForPlugAndPlayDevicesW");
  1015. if (!pfnUpdateDriver) {
  1016. FreeLibrary (hNewDev);
  1017. return FALSE;
  1018. }
  1019. if (!HwdbInitializeW (NULL)) {
  1020. SetuplogError (
  1021. LogSevWarning,
  1022. TEXT("DUWarning: HwdbInitialize failed (rc=%1!u!); no DU drivers will be installed\r\n"),
  1023. 0,
  1024. GetLastError (),
  1025. NULL,
  1026. NULL
  1027. );
  1028. FreeLibrary (hNewDev);
  1029. return FALSE;
  1030. }
  1031. //
  1032. // look for driver-controlling inf
  1033. //
  1034. hGuiDrvsInf = INVALID_HANDLE_VALUE;
  1035. if (SpSetupLoadParameter (
  1036. WINNT_SP_DYNUPDTDRIVERINFOFILE,
  1037. infPath,
  1038. ARRAYSIZE(infPath)
  1039. )) {
  1040. if (pDoesFileExist (infPath)) {
  1041. hGuiDrvsInf = SetupOpenInfFile (infPath, NULL, INF_STYLE_WIN4, &line);
  1042. if (hGuiDrvsInf == INVALID_HANDLE_VALUE) {
  1043. SetuplogError (
  1044. LogSevWarning,
  1045. TEXT("DUWarning: SetupOpenInfFile(%1) failed (rc=%2!u!); all DU drivers will be installed\r\n"),
  1046. 0,
  1047. infPath,
  1048. GetLastError (),
  1049. NULL,
  1050. NULL
  1051. );
  1052. }
  1053. } else {
  1054. SetuplogError (
  1055. LogSevWarning,
  1056. TEXT("DUWarning: File %1 missing; all DU drivers will be installed\r\n"),
  1057. 0,
  1058. infPath,
  1059. NULL,
  1060. NULL
  1061. );
  1062. }
  1063. } else {
  1064. SetuplogError (
  1065. LogSevInformation,
  1066. TEXT("DUInfo: File %1 missing; all DU drivers will be installed\r\n"),
  1067. 0,
  1068. infPath,
  1069. NULL,
  1070. NULL
  1071. );
  1072. }
  1073. source = buf;
  1074. while (source) {
  1075. next = _tcschr (source, TEXT(','));
  1076. if (next) {
  1077. *next = 0;
  1078. }
  1079. p = source;
  1080. if (*p == TEXT('\"')) {
  1081. p = ++source;
  1082. }
  1083. while (*p && *p != TEXT('\"')) {
  1084. p++;
  1085. }
  1086. *p = 0;
  1087. if (pDoesDirExist (source)) {
  1088. if (BuildPath (datPath, ARRAYSIZE(datPath), source, S_HWCOMP_DAT) &&
  1089. pDoesFileExist (datPath)) {
  1090. //
  1091. // OK, we have the file with hardware info
  1092. //
  1093. if (HwdbEnumFirstInf (&e, datPath)) {
  1094. do {
  1095. if (!BuildPath (infPath, ARRAYSIZE(infPath), source, e.InfFile) ||
  1096. !pDoesFileExist (infPath)) {
  1097. continue;
  1098. }
  1099. //
  1100. // iterate through all PNPIDs in this INF
  1101. //
  1102. for (pnpId = e.PnpIds; *pnpId; pnpId = _tcschr (pnpId, 0) + 1) {
  1103. //
  1104. // excluded PNPID are NOT in hwcomp.dat
  1105. // guidrvs.inf was already processed during winnt32
  1106. //
  1107. if (!pfnUpdateDriver (
  1108. NULL,
  1109. pnpId,
  1110. infPath,
  1111. 0, // BUGBUG - if we specify INSTALLFLAG_NONINTERACTIVE and there is a driver signing problem, the API will fail!
  1112. &bRebootRequired
  1113. )) {
  1114. if (GetLastError() != ERROR_SUCCESS) {
  1115. //
  1116. // well, if the device we wanted to update the driver for
  1117. // doesn't actually exist on this machine, don't log anything
  1118. //
  1119. if (GetLastError() != ERROR_NO_SUCH_DEVINST) {
  1120. SetuplogError (
  1121. LogSevWarning,
  1122. TEXT("DUWarning: UpdateDriverForPlugAndPlayDevices failed (rc=%3!u!) for PNPID=%1 (INF=%2)\r\n"),
  1123. 0,
  1124. pnpId,
  1125. infPath,
  1126. GetLastError (),
  1127. NULL,
  1128. NULL
  1129. );
  1130. }
  1131. } else {
  1132. SetuplogError (
  1133. LogSevInformation,
  1134. TEXT("DUInfo: UpdateDriverForPlugAndPlayDevices did not update the driver for PNPID=%1\r\n"),
  1135. 0,
  1136. pnpId,
  1137. NULL,
  1138. NULL
  1139. );
  1140. }
  1141. continue;
  1142. }
  1143. //
  1144. // SUCCESS! - log this information
  1145. //
  1146. SetuplogError (
  1147. LogSevInformation,
  1148. TEXT("DUInfo: UpdateDriverForPlugAndPlayDevices succeeded for PNPID=%1\r\n"),
  1149. 0,
  1150. pnpId,
  1151. NULL,
  1152. NULL
  1153. );
  1154. //
  1155. // also update the PNF with the info that this is an INTERNET driver
  1156. //
  1157. if (!SetupCopyOEMInf (
  1158. infPath,
  1159. NULL,
  1160. SPOST_URL,
  1161. SP_COPY_REPLACEONLY,
  1162. NULL,
  1163. 0,
  1164. NULL,
  1165. NULL
  1166. )) {
  1167. SetuplogError (
  1168. LogSevInformation,
  1169. TEXT("DUInfo: SetupCopyOEMInf failed to update OEMSourceMediaType for INF=%1\r\n"),
  1170. 0,
  1171. infPath,
  1172. NULL,
  1173. NULL
  1174. );
  1175. }
  1176. }
  1177. } while (HwdbEnumNextInf (&e));
  1178. }
  1179. }
  1180. }
  1181. if (next) {
  1182. source = next + 1;
  1183. } else {
  1184. source = NULL;
  1185. }
  1186. }
  1187. HwdbTerminate ();
  1188. FreeLibrary (hNewDev);
  1189. return TRUE;
  1190. }
  1191. VOID
  1192. DuCleanup (
  1193. VOID
  1194. )
  1195. /*++
  1196. Routine Description:
  1197. This routine performs DU cleanup
  1198. Arguments:
  1199. none
  1200. Return Value:
  1201. none
  1202. --*/
  1203. {
  1204. TCHAR buf[MAX_PATH * 16];
  1205. DWORD chars;
  1206. HKEY key;
  1207. PTSTR devicePath;
  1208. PTSTR p;
  1209. DWORD rc;
  1210. DWORD size;
  1211. DWORD type;
  1212. //
  1213. // cleanup the file system
  1214. //
  1215. MYASSERT (AnswerFile[0]);
  1216. if (GetPrivateProfileString (
  1217. WINNT_SETUPPARAMS,
  1218. WINNT_SP_DYNUPDTWORKINGDIR,
  1219. TEXT(""),
  1220. buf,
  1221. ARRAYSIZE(buf),
  1222. AnswerFile
  1223. )) {
  1224. Delnode (buf);
  1225. }
  1226. //
  1227. // cleanup the registry
  1228. //
  1229. chars = GetPrivateProfileString (
  1230. WINNT_SETUPPARAMS,
  1231. WINNT_SP_DYNUPDTADDITIONALGUIDRIVERS,
  1232. TEXT(""),
  1233. buf,
  1234. ARRAYSIZE(buf),
  1235. AnswerFile
  1236. );
  1237. if (chars > 0) {
  1238. //
  1239. // got it; now remove it from DevicePath
  1240. //
  1241. rc = RegOpenKey (HKEY_LOCAL_MACHINE, REGSTR_PATH_SETUP, &key);
  1242. if (rc == ERROR_SUCCESS) {
  1243. rc = RegQueryValueEx (key, REGSTR_VAL_DEVICEPATH, NULL, NULL, NULL, &size);
  1244. if (rc == ERROR_SUCCESS) {
  1245. devicePath = (PTSTR) MyMalloc (size);
  1246. if (devicePath) {
  1247. rc = RegQueryValueEx (key, REGSTR_VAL_DEVICEPATH, NULL, &type, (LPBYTE)devicePath, &size);
  1248. if (rc == ERROR_SUCCESS && size / sizeof (TCHAR) >= chars + 1) {
  1249. p = _tcsstr (devicePath, buf);
  1250. if (p &&
  1251. (p == devicePath || *(p - 1) == TEXT(';')) &&
  1252. (!p[chars] || p[chars] == TEXT(';'))
  1253. ) {
  1254. if (p == devicePath) {
  1255. _tcscpy (p, p[chars] == TEXT(';') ? p + chars + 1 : p + chars);
  1256. } else {
  1257. _tcscpy (p - 1, p + chars);
  1258. }
  1259. size = (_tcslen (devicePath) + 1) * sizeof (TCHAR);
  1260. rc = RegSetValueEx (key, REGSTR_VAL_DEVICEPATH, 0, type, (PBYTE)devicePath, size);
  1261. }
  1262. }
  1263. MyFree (devicePath);
  1264. }
  1265. }
  1266. RegCloseKey (key);
  1267. }
  1268. }
  1269. g_DuShare[0] = 0;
  1270. }
  1271. BOOL
  1272. DuInstallDuAsms (
  1273. VOID
  1274. )
  1275. /*++
  1276. Routine Description:
  1277. This routine installs additional DU assemblies
  1278. Arguments:
  1279. none
  1280. Return Value:
  1281. TRUE if successful, FALSE otherwise
  1282. --*/
  1283. {
  1284. TCHAR duasmsRoot[MAX_PATH];
  1285. TCHAR duasmsSource[MAX_PATH];
  1286. DWORD chars;
  1287. SIDE_BY_SIDE SideBySide = {0};
  1288. BOOL b1;
  1289. BOOL b2;
  1290. PTSTR p;
  1291. PCTSTR source;
  1292. BOOL fSuccess = TRUE;
  1293. //
  1294. // look for any assemblies root specified in the answer file
  1295. //
  1296. MYASSERT (AnswerFile[0]);
  1297. if (GetPrivateProfileString (
  1298. WINNT_SETUPPARAMS,
  1299. WINNT_SP_UPDATEDDUASMS,
  1300. TEXT(""),
  1301. duasmsRoot,
  1302. ARRAYSIZE(duasmsRoot),
  1303. AnswerFile
  1304. )) {
  1305. //
  1306. // make sure this directory exists; remove any existing quotes first
  1307. //
  1308. p = duasmsRoot;
  1309. if (*p == TEXT('\"')) {
  1310. p++;
  1311. }
  1312. source = p;
  1313. while (*p && *p != TEXT('\"')) {
  1314. p++;
  1315. }
  1316. *p = 0;
  1317. if (pDoesDirExist (source)) {
  1318. //
  1319. // root directory found
  1320. // first copy them in a protected location, then install assemblies from there
  1321. //
  1322. DWORD rc;
  1323. rc = GetDriverCacheSourcePath (duasmsSource, ARRAYSIZE(duasmsSource));
  1324. if (rc != ERROR_SUCCESS) {
  1325. SetuplogError (
  1326. LogSevError,
  1327. SETUPLOG_USE_MESSAGEID,
  1328. MSG_LOG_DRIVER_CACHE_NOT_FOUND,
  1329. rc,
  1330. NULL,
  1331. NULL
  1332. );
  1333. return FALSE;
  1334. }
  1335. if (!pSetupConcatenatePaths (duasmsSource, TEXT("duasms"), ARRAYSIZE(duasmsSource), NULL)) {
  1336. return FALSE;
  1337. }
  1338. //
  1339. // first remove any already existing duasms "backup source" previously downloaded
  1340. //
  1341. Delnode (duasmsSource);
  1342. //
  1343. // now tree copy from the temp location to this "backup source"
  1344. //
  1345. rc = TreeCopy (source, duasmsSource);
  1346. if (rc != ERROR_SUCCESS) {
  1347. SetuplogError(
  1348. LogSevError,
  1349. TEXT("Setup failed to TreeCopy %2 to %3 (TreeCopy failed %1!u!)\r\n"),
  1350. 0,
  1351. rc,
  1352. source,
  1353. duasmsSource,
  1354. NULL,
  1355. NULL
  1356. );
  1357. return FALSE;
  1358. }
  1359. //
  1360. // install duasms from there
  1361. //
  1362. b1 = SideBySidePopulateCopyQueue (&SideBySide, NULL, duasmsSource);
  1363. b2 = SideBySideFinish (&SideBySide, b1);
  1364. if (!b1 || !b2) {
  1365. fSuccess = FALSE;
  1366. SetuplogError (
  1367. LogSevError,
  1368. TEXT("DUError: DuInstallDuAsms failed (rc=%1!u!)\r\n"),
  1369. 0,
  1370. GetLastError (),
  1371. NULL,
  1372. NULL
  1373. );
  1374. }
  1375. } else {
  1376. fSuccess = FALSE;
  1377. SetuplogError (
  1378. LogSevError,
  1379. TEXT("DUError: Invalid directory %1; DuInstallDuAsms failed\r\n"),
  1380. 0,
  1381. source,
  1382. NULL,
  1383. NULL
  1384. );
  1385. }
  1386. }
  1387. return fSuccess;
  1388. }
  1389. BOOL
  1390. BuildPathToInstallationFileEx (
  1391. IN PCTSTR Filename,
  1392. OUT PTSTR PathBuffer,
  1393. IN DWORD PathBufferSize,
  1394. IN BOOL UseDuShare
  1395. )
  1396. /*++
  1397. Routine Description:
  1398. This routine returns the path to the updated DU file, if one exists
  1399. and the caller wanted this. Otherwise it will simply return the path
  1400. to the CD file.
  1401. Arguments:
  1402. Filename - Specifies the filename to look for
  1403. PathBuffer - Receives the full path to the file
  1404. PathBufferSize - Specifies the size in chars of the above buffer
  1405. UseDuShare - Specifies TRUE if the function should check the DU
  1406. location first
  1407. Return Value:
  1408. TRUE if building the path was successful. This does not guarantee the file exist.
  1409. --*/
  1410. {
  1411. if (g_DuShare[0] && UseDuShare) {
  1412. if (BuildPath (PathBuffer, PathBufferSize, g_DuShare, Filename) &&
  1413. pDoesFileExist (PathBuffer)
  1414. ) {
  1415. return TRUE;
  1416. }
  1417. }
  1418. return BuildPath (PathBuffer, PathBufferSize, LegacySourcePath, Filename);
  1419. }
  1420. PCTSTR
  1421. DuGetUpdatesPath (
  1422. VOID
  1423. )
  1424. {
  1425. return g_DuShare[0] ? g_DuShare : NULL;
  1426. }
  1427. BOOL
  1428. DuDoesUpdatedFileExistEx (
  1429. IN PCTSTR Filename,
  1430. OUT PTSTR PathBuffer, OPTIONAL
  1431. IN DWORD PathBufferSize
  1432. )
  1433. /*++
  1434. Routine Description:
  1435. This routine checks if there exists an updated file with the given name.
  1436. Arguments:
  1437. Filename - Specifies the filename to look for
  1438. PathBuffer - Receives the full path to the file; optional
  1439. PathBufferSize - Specifies the size in chars of the above buffer
  1440. Return Value:
  1441. TRUE if a DU file with this name exists, FALSE otherwise
  1442. --*/
  1443. {
  1444. TCHAR path[MAX_PATH];
  1445. if (g_DuShare[0] &&
  1446. BuildPath (path, ARRAYSIZE(path), g_DuShare, Filename) &&
  1447. pDoesFileExist (path)
  1448. ) {
  1449. if (PathBuffer) {
  1450. return SUCCEEDED (StringCchCopy (PathBuffer, PathBufferSize, path));
  1451. }
  1452. return TRUE;
  1453. }
  1454. return FALSE;
  1455. }
  1456. UINT
  1457. DuSetupPromptForDisk (
  1458. HWND hwndParent, // parent window of the dialog box
  1459. PCTSTR DialogTitle, // optional, title of the dialog box
  1460. PCTSTR DiskName, // optional, name of disk to insert
  1461. PCTSTR PathToSource, // optional, expected source path
  1462. PCTSTR FileSought, // name of file needed
  1463. PCTSTR TagFile, // optional, source media tag file
  1464. DWORD DiskPromptStyle, // specifies dialog box behavior
  1465. PTSTR PathBuffer, // receives the source location
  1466. DWORD PathBufferSize, // size of the supplied buffer
  1467. PDWORD PathRequiredSize // optional, buffer size needed
  1468. )
  1469. {
  1470. TCHAR buffer[MAX_PATH];
  1471. DWORD size;
  1472. if ((DiskPromptStyle & IDF_CHECKFIRST) &&
  1473. PathBuffer &&
  1474. PathBufferSize &&
  1475. FileSought &&
  1476. g_DuShare[0]
  1477. ) {
  1478. if (BuildPath (buffer, ARRAYSIZE(buffer), g_DuShare, FileSought) &&
  1479. pDoesFileExist (buffer)
  1480. ) {
  1481. size = lstrlen (buffer) + 1;
  1482. if (size > PathBufferSize) {
  1483. if (PathRequiredSize) {
  1484. *PathRequiredSize = size;
  1485. }
  1486. return DPROMPT_BUFFERTOOSMALL;
  1487. }
  1488. CopyMemory (PathBuffer, buffer, size * sizeof (buffer[0]));
  1489. return DPROMPT_SUCCESS;
  1490. }
  1491. }
  1492. return SetupPromptForDisk (
  1493. hwndParent,
  1494. DialogTitle,
  1495. DiskName,
  1496. PathToSource,
  1497. FileSought,
  1498. TagFile,
  1499. DiskPromptStyle,
  1500. PathBuffer,
  1501. PathBufferSize,
  1502. PathRequiredSize
  1503. );
  1504. }
  1505. VOID
  1506. DuInstallUpdatesInfFinal (
  1507. VOID
  1508. )
  1509. /*++
  1510. Routine Description:
  1511. This function installs the final installation section of STR_UPDATES_INF
  1512. if this file is found inside updates.cab
  1513. Arguments:
  1514. none
  1515. Return Value:
  1516. none
  1517. --*/
  1518. {
  1519. if (!g_DuShare[0]) {
  1520. SetuplogError (
  1521. LogSevInformation,
  1522. TEXT("DUInfo: %1 is disabled"),
  1523. 0,
  1524. TEXT(__FUNCTION__),
  1525. NULL,
  1526. NULL
  1527. );
  1528. return;
  1529. }
  1530. pInstallUpdatesInf (STR_DEFAULTINSTALLFINAL);
  1531. }