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.

1988 lines
58 KiB

  1. /*++
  2. Copyright (c) Microsoft Corporation. All Rights Reserved.
  3. Module Name:
  4. msoobci.c
  5. Abstract:
  6. Exception Pack installer helper DLL
  7. Can be used as a co-installer, or called via setup app, or RunDll32 stub
  8. This DLL is for internal distribution of exception packs to update
  9. OS components.
  10. Author:
  11. Jamie Hunter (jamiehun) 2001-11-27
  12. Revision History:
  13. Jamie Hunter (jamiehun) 2001-11-27
  14. Initial Version
  15. --*/
  16. #include "msoobcip.h"
  17. typedef struct _CALLBACKDATA {
  18. PVOID pDefContext; // context for default queue callback
  19. LPCTSTR Media; // where old root was
  20. LPCTSTR Store; // where new root is
  21. BOOL PreCopy; // if using PreCopy section
  22. } CALLBACKDATA;
  23. HRESULT
  24. HandleReboot(
  25. IN DWORD Flags
  26. )
  27. /*++
  28. Routine Description:
  29. Prompt for and execute reboot
  30. Arguments:
  31. Flags - how reboot should be handled
  32. Return Value:
  33. INST_S_REBOOT
  34. INST_S_REBOOTING
  35. --*/
  36. {
  37. if(Flags & COMP_FLAGS_NOPROMPTREBOOT) {
  38. //
  39. // TODO
  40. // if set, reboot unconditionally
  41. //
  42. HANDLE Token;
  43. BOOL b;
  44. TOKEN_PRIVILEGES NewPrivileges;
  45. LUID Luid;
  46. //
  47. // we need to "turn on" reboot privilege
  48. // if any of this fails, try reboot anyway
  49. //
  50. if(!OpenProcessToken(GetCurrentProcess(),TOKEN_ADJUST_PRIVILEGES,&Token)) {
  51. goto try_reboot;
  52. }
  53. if(!LookupPrivilegeValue(NULL,SE_SHUTDOWN_NAME,&Luid)) {
  54. CloseHandle(Token);
  55. goto try_reboot;
  56. }
  57. NewPrivileges.PrivilegeCount = 1;
  58. NewPrivileges.Privileges[0].Luid = Luid;
  59. NewPrivileges.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
  60. AdjustTokenPrivileges(
  61. Token,
  62. FALSE,
  63. &NewPrivileges,
  64. 0,
  65. NULL,
  66. NULL
  67. );
  68. CloseHandle(Token);
  69. try_reboot:
  70. //
  71. // attempt reboot - inform system that this is planned hardware install
  72. //
  73. if(ExitWindowsEx(EWX_REBOOT,
  74. SHTDN_REASON_FLAG_PLANNED
  75. |SHTDN_REASON_MAJOR_SOFTWARE
  76. |SHTDN_REASON_MINOR_INSTALLATION)) {
  77. return INST_S_REBOOTING;
  78. }
  79. } else if(Flags & COMP_FLAGS_PROMPTREBOOT) {
  80. //
  81. // TODO
  82. // if set, prompt for reboot
  83. //
  84. if(IsInteractiveWindowStation()) {
  85. if(SetupPromptReboot(NULL,NULL,FALSE) & SPFILEQ_REBOOT_IN_PROGRESS) {
  86. return INST_S_REBOOTING;
  87. }
  88. }
  89. }
  90. return INST_S_REBOOT;
  91. }
  92. HRESULT
  93. WINAPI
  94. InstallInfSectionW(
  95. IN LPCTSTR InfPath,
  96. IN LPCWSTR SectionName, OPTIONAL
  97. IN DWORD Flags
  98. )
  99. /*++
  100. Routine Description:
  101. Does an install along lines of InstallHinfSection
  102. Arguments:
  103. InfPath - full path to INF file
  104. SectionName - name of section including any decoration
  105. Return Value:
  106. status as hresult
  107. --*/
  108. {
  109. TCHAR SectionNameBuffer[LINE_LEN];
  110. TCHAR ServiceSection[LINE_LEN+32];
  111. HINF hInf = INVALID_HANDLE_VALUE;
  112. HSPFILEQ hFileQueue = INVALID_HANDLE_VALUE;
  113. PVOID QueueContext = NULL;
  114. DWORD Status = NO_ERROR;
  115. BOOL reboot = FALSE;
  116. BOOL needUninstallInf = FALSE;
  117. INT res;
  118. INFCONTEXT InfLine;
  119. DWORD InstFlags;
  120. //
  121. // Some decisions are version based
  122. //
  123. //
  124. // Load the inf file
  125. //
  126. hInf = SetupOpenInfFile(InfPath, NULL, INF_STYLE_WIN4, NULL);
  127. if(hInf == INVALID_HANDLE_VALUE) {
  128. Status = GetLastError();
  129. goto final;
  130. }
  131. if(!SectionName) {
  132. //
  133. // determine section name
  134. //
  135. if(!SetupDiGetActualSectionToInstall(hInf,
  136. KEY_DEFAULTINSTALL,
  137. SectionNameBuffer,
  138. ARRAY_SIZE(SectionNameBuffer),
  139. NULL,
  140. NULL)) {
  141. Status = GetLastError();
  142. goto final;
  143. }
  144. SectionName = SectionNameBuffer;
  145. }
  146. //
  147. // Check to see if the install section has a "Reboot" line.
  148. // or otherwise reboot forced
  149. //
  150. if((Flags & COMP_FLAGS_NEEDSREBOOT)
  151. || (SetupFindFirstLine(hInf, SectionName, KEY_REBOOT, &InfLine))) {
  152. reboot = TRUE;
  153. }
  154. //
  155. // See if UI allowed
  156. //
  157. if(((Flags & COMP_FLAGS_NOUI)==0) && !IsInteractiveWindowStation()) {
  158. Flags |= COMP_FLAGS_NOUI;
  159. }
  160. //
  161. // Load any layout file
  162. //
  163. SetupOpenAppendInfFile(NULL, hInf, NULL);
  164. //
  165. // Create a setup file queue and initialize the default queue callback.
  166. //
  167. hFileQueue = SetupOpenFileQueue();
  168. if(hFileQueue == INVALID_HANDLE_VALUE) {
  169. Status = GetLastError();
  170. goto final;
  171. }
  172. QueueContext = SetupInitDefaultQueueCallbackEx(
  173. NULL,
  174. ((Flags & COMP_FLAGS_NOUI) ? INVALID_HANDLE_VALUE : NULL),
  175. 0,
  176. 0,
  177. 0
  178. );
  179. if(!QueueContext) {
  180. Status = GetLastError();
  181. goto final;
  182. }
  183. if(!SetupInstallFilesFromInfSection(hInf,
  184. NULL,
  185. hFileQueue,
  186. SectionName,
  187. NULL,
  188. 0 // SP_COPY_xxxx
  189. )) {
  190. Status = GetLastError();
  191. goto final;
  192. }
  193. //
  194. // Commit file queue.
  195. //
  196. if(!SetupCommitFileQueue(NULL, hFileQueue, SetupDefaultQueueCallback, QueueContext)) {
  197. Status = GetLastError();
  198. goto final;
  199. }
  200. //
  201. // Note, if the INF contains a (non-NULL) ClassGUID, then it will have
  202. // been installed into %windir%\Inf during the above queue committal.
  203. // We make no effort to subsequently uninstall it (and its associated
  204. // PNF and CAT) if something fails below.
  205. //
  206. needUninstallInf = TRUE;
  207. InstFlags = SPINST_ALL;
  208. if(g_VerInfo.dwMajorVersion < 5) {
  209. InstFlags = 0x1f;
  210. }
  211. if(!SetupInstallFromInfSection(NULL,
  212. hInf,
  213. SectionName,
  214. InstFlags &~ SPINST_FILES,
  215. NULL, // HKEY_xxxx
  216. NULL, // no copying...
  217. 0,
  218. NULL,
  219. NULL,
  220. NULL,
  221. NULL
  222. )) {
  223. Status = GetLastError();
  224. goto final;
  225. }
  226. lstrcpyn(ServiceSection,SectionName,LINE_LEN);
  227. lstrcat(ServiceSection,KEY_DOTSERVICES);
  228. //
  229. // If services section exists, install it
  230. //
  231. if(SetupFindFirstLine(hInf, ServiceSection, NULL, &InfLine)) {
  232. if(!SetupInstallServicesFromInfSection(hInf,ServiceSection,0)) {
  233. Status = GetLastError();
  234. goto final;
  235. }
  236. if(GetLastError() == ERROR_SUCCESS_REBOOT_REQUIRED) {
  237. reboot = TRUE;
  238. }
  239. }
  240. res = SetupPromptReboot(hFileQueue, NULL, TRUE);
  241. if((res!=-1) && (res & SPFILEQ_REBOOT_RECOMMENDED)) {
  242. reboot = TRUE;
  243. }
  244. final:
  245. if(QueueContext) {
  246. SetupTermDefaultQueueCallback(QueueContext);
  247. }
  248. if(hFileQueue != INVALID_HANDLE_VALUE) {
  249. SetupCloseFileQueue(hFileQueue);
  250. }
  251. if(hInf != INVALID_HANDLE_VALUE) {
  252. SetupCloseInfFile(hInf);
  253. }
  254. if(Status == NO_ERROR) {
  255. //
  256. // are we meant to prompt for reboot?
  257. //
  258. if(reboot) {
  259. return HandleReboot(Flags);
  260. } else {
  261. return S_OK;
  262. }
  263. }
  264. if(needUninstallInf) {
  265. //
  266. // call SetupUninstallOEMInf ?
  267. //
  268. }
  269. return HRESULT_FROM_SETUPAPI(Status);
  270. }
  271. HRESULT
  272. WINAPI
  273. InstallInfSectionA(
  274. IN LPCSTR InfPath,
  275. IN LPCSTR SectionName, OPTIONAL
  276. IN DWORD Flags
  277. )
  278. {
  279. TCHAR OutPath[MAX_PATH];
  280. TCHAR OutSection[LINE_LEN]; // as per friendly name
  281. INT sz;
  282. if(InfPath) {
  283. sz = MultiByteToWideChar(CP_ACP,0,InfPath,-1,OutPath,ARRAY_SIZE(OutPath));
  284. if(!sz) {
  285. return E_INVALIDARG;
  286. }
  287. }
  288. if(SectionName) {
  289. sz = MultiByteToWideChar(CP_ACP,0,SectionName,-1,OutSection,ARRAY_SIZE(OutSection));
  290. if(!sz) {
  291. return E_INVALIDARG;
  292. }
  293. }
  294. return InstallInfSection(InfPath ? OutPath : NULL,
  295. SectionName ? OutSection : NULL,
  296. Flags);
  297. }
  298. HRESULT
  299. AttemptStoreCopy(
  300. IN CALLBACKDATA *pCallbackData,
  301. IN LPCTSTR Root, OPTIONAL
  302. IN LPCTSTR Source,
  303. IN LPCTSTR Target OPTIONAL
  304. )
  305. /*++
  306. Routine Description:
  307. Copy from source to target, redirected to the expack store
  308. Arguments:
  309. pCallbackData - as passed to PreCopyQueueCallback
  310. Root - root to source directory
  311. Source - source, relative to Root
  312. Target - target name
  313. Return Value:
  314. status as hresult
  315. --*/
  316. {
  317. TCHAR FullSource[MAX_PATH];
  318. TCHAR FullTarget[MAX_PATH];
  319. LPTSTR SubDir;
  320. LPTSTR BaseName;
  321. LPTSTR DestName;
  322. LPCTSTR p;
  323. DWORD dwStatus;
  324. HRESULT hrStatus;
  325. if(Root) {
  326. lstrcpyn(FullSource,Root,MAX_PATH);
  327. hrStatus = ConcatPath(FullSource,MAX_PATH,Source);
  328. if(!SUCCEEDED(hrStatus)) {
  329. return hrStatus;
  330. }
  331. } else {
  332. lstrcpyn(FullSource,Source,MAX_PATH);
  333. }
  334. //
  335. // we want to determine the source sub-directory
  336. //
  337. SubDir = FullSource;
  338. p = pCallbackData->Media;
  339. while(*p && (*p == *SubDir)) {
  340. p = CharNext(p);
  341. SubDir = CharNext(SubDir);
  342. }
  343. if(*p || ((*SubDir != TEXT('\\')) && (*SubDir != TEXT('/')))) {
  344. //
  345. // not a sub-directory of media
  346. //
  347. DebugPrint(TEXT("Not copying \"%s\" (not subdirectory of \"%s\")"),FullSource,pCallbackData->Media);
  348. return E_FAIL;
  349. }
  350. lstrcpyn(FullTarget,pCallbackData->Store,MAX_PATH);
  351. hrStatus = ConcatPath(FullTarget,MAX_PATH,SubDir);
  352. if(!SUCCEEDED(hrStatus)) {
  353. return hrStatus;
  354. }
  355. if(Target) {
  356. //
  357. // change final name of this
  358. //
  359. BaseName = GetBaseName(Target);
  360. DestName = GetBaseName(FullTarget);
  361. if(((DestName-FullTarget)+lstrlen(BaseName))>=MAX_PATH) {
  362. return HRESULT_FROM_WIN32(ERROR_INSUFFICIENT_BUFFER);
  363. }
  364. lstrcpy(DestName,BaseName);
  365. }
  366. if(GetFileAttributes(FullTarget)!=INVALID_FILE_ATTRIBUTES) {
  367. //
  368. // allow file to be replaced
  369. //
  370. SetFileAttributes(FullTarget,FILE_ATTRIBUTE_NORMAL);
  371. }
  372. MakeSureParentPathExists(FullTarget);
  373. if(CopyFile(FullSource,FullTarget,FALSE)) {
  374. return S_OK;
  375. }
  376. dwStatus = GetLastError();
  377. return HRESULT_FROM_WIN32(dwStatus);
  378. }
  379. UINT
  380. CALLBACK
  381. PreCopyQueueCallback(
  382. IN PVOID Context,
  383. IN UINT Notification,
  384. IN UINT_PTR Param1,
  385. IN UINT_PTR Param2
  386. )
  387. /*++
  388. Routine Description:
  389. Intent is to copy files from existing media to final media
  390. Copy all files
  391. Arguments:
  392. FileName - name of file to scan
  393. Return Value:
  394. status as hresult
  395. --*/
  396. {
  397. CALLBACKDATA * pCallbackData = (CALLBACKDATA *)Context;
  398. switch(Notification) {
  399. case SPFILENOTIFY_NEEDMEDIA:
  400. {
  401. UINT res;
  402. SOURCE_MEDIA *pMedia = (SOURCE_MEDIA *)Param1;
  403. SOURCE_MEDIA MediaCopy = *pMedia;
  404. LPCTSTR Path = NULL;
  405. //
  406. // get the media in place - let default callback do this
  407. // however we can't deal with media location being changed
  408. // so don't allow it
  409. //
  410. MediaCopy.Flags |= SP_COPY_NOSKIP|SP_COPY_NOBROWSE;
  411. res= SetupDefaultQueueCallback(pCallbackData->pDefContext,
  412. Notification,
  413. (UINT_PTR)&MediaCopy,
  414. Param2);
  415. if(res==FILEOP_DOIT) {
  416. //
  417. // typical case
  418. // SourcePath unchanged
  419. //
  420. Path = pMedia->SourcePath;
  421. } else if(res == FILEOP_NEWPATH) {
  422. //
  423. // alternative case
  424. // we said above we don't want this
  425. //
  426. SetLastError(ERROR_CANCELLED);
  427. return FILEOP_ABORT;
  428. } else if(res == FILEOP_SKIP) {
  429. //
  430. // skip
  431. // we said above we don't want this
  432. //
  433. SetLastError(ERROR_CANCELLED);
  434. return FILEOP_ABORT;
  435. } else {
  436. //
  437. // existing failure case
  438. //
  439. return res;
  440. }
  441. //
  442. // if the tag exists at source media, copy it
  443. // if the sourcefile exists at source media, copy it now
  444. // (it might reference a cab file)
  445. //
  446. AttemptStoreCopy(pCallbackData,Path,pMedia->Tagfile,NULL);
  447. AttemptStoreCopy(pCallbackData,Path,pMedia->SourceFile,NULL);
  448. }
  449. return FILEOP_DOIT;
  450. case SPFILENOTIFY_STARTCOPY:
  451. {
  452. UINT res;
  453. FILEPATHS *pPaths = (FILEPATHS*)Param1;
  454. if(pCallbackData->PreCopy) {
  455. //
  456. // we want the target name (PRECOPY case)
  457. //
  458. AttemptStoreCopy(pCallbackData,NULL,pPaths->Source,pPaths->Target);
  459. } else {
  460. //
  461. // we want the source name
  462. //
  463. AttemptStoreCopy(pCallbackData,NULL,pPaths->Source,NULL);
  464. }
  465. }
  466. return FILEOP_SKIP;
  467. case SPFILENOTIFY_STARTDELETE:
  468. return FILEOP_SKIP;
  469. case SPFILENOTIFY_STARTRENAME:
  470. return FILEOP_SKIP;
  471. default:
  472. return SetupDefaultQueueCallback(pCallbackData->pDefContext,
  473. Notification,
  474. Param1,
  475. Param2);
  476. }
  477. }
  478. HRESULT
  479. InstallExceptionPackFromInf(
  480. IN LPCTSTR InfPath,
  481. IN LPCTSTR Media,
  482. IN LPCTSTR Store,
  483. IN DWORD Flags
  484. )
  485. /*++
  486. Routine Description:
  487. Assume INF installed into INF directory
  488. all decisions made
  489. media/store known
  490. Arguments:
  491. InfPath - name of Inf in Media location
  492. Media - InfPath less InfName
  493. Store - expack store
  494. Flags - various flags
  495. Return Value:
  496. status as hresult
  497. --*/
  498. {
  499. TCHAR SectionName[LINE_LEN];
  500. TCHAR PrecopySectionName[LINE_LEN];
  501. HINF hInf;
  502. HSPFILEQ hFileQueue = INVALID_HANDLE_VALUE;
  503. PVOID QueueContext = NULL;
  504. CALLBACKDATA CallbackData;
  505. DWORD Status;
  506. //
  507. // exception packs must be moved to a component-specific store
  508. // run through a file-install to see what files we have to copy
  509. // and use that list to determine source media
  510. //
  511. hInf = SetupOpenInfFile(InfPath, NULL, INF_STYLE_WIN4, NULL);
  512. if(hInf == INVALID_HANDLE_VALUE) {
  513. Status = GetLastError();
  514. goto final;
  515. }
  516. if(!SetupDiGetActualSectionToInstall(hInf,
  517. KEY_DEFAULTINSTALL,
  518. SectionName,
  519. ARRAY_SIZE(SectionName),
  520. NULL,
  521. NULL)) {
  522. Status = GetLastError();
  523. goto final;
  524. }
  525. SetupOpenAppendInfFile(NULL,hInf,NULL);
  526. hFileQueue = SetupOpenFileQueue();
  527. if(hFileQueue == INVALID_HANDLE_VALUE) {
  528. Status = GetLastError();
  529. goto final;
  530. }
  531. if((lstrlen(SectionName)+10)>LINE_LEN) {
  532. Status = ERROR_INSUFFICIENT_BUFFER;
  533. goto final;
  534. }
  535. lstrcpy(PrecopySectionName,SectionName);
  536. lstrcat(PrecopySectionName,KEY_DOTPRECOPY);
  537. QueueContext = SetupInitDefaultQueueCallbackEx(
  538. NULL,
  539. ((Flags & COMP_FLAGS_NOUI) ? INVALID_HANDLE_VALUE : NULL),
  540. 0,
  541. 0,
  542. 0
  543. );
  544. if(!QueueContext) {
  545. Status = GetLastError();
  546. goto final;
  547. }
  548. ZeroMemory(&CallbackData,sizeof(CallbackData));
  549. CallbackData.pDefContext = QueueContext;
  550. CallbackData.Store = Store;
  551. CallbackData.Media = Media;
  552. if(SetupGetLineCount(hInf,PrecopySectionName)>0) {
  553. //
  554. // do the pre-copy install via this section instead
  555. //
  556. CallbackData.PreCopy = TRUE;
  557. if(!SetupInstallFilesFromInfSection(hInf,
  558. NULL,
  559. hFileQueue,
  560. PrecopySectionName,
  561. NULL,
  562. 0 // SP_COPY_xxxx
  563. )) {
  564. Status = GetLastError();
  565. goto final;
  566. }
  567. } else {
  568. CallbackData.PreCopy = FALSE;
  569. if(!SetupInstallFilesFromInfSection(hInf,
  570. NULL,
  571. hFileQueue,
  572. SectionName,
  573. NULL,
  574. 0 // SP_COPY_xxxx
  575. )) {
  576. Status = GetLastError();
  577. goto final;
  578. }
  579. }
  580. //
  581. // Commit file queue, this will get the files to the store
  582. //
  583. if(!SetupCommitFileQueue(NULL, hFileQueue, PreCopyQueueCallback, &CallbackData)) {
  584. Status = GetLastError();
  585. goto final;
  586. }
  587. if(hFileQueue != INVALID_HANDLE_VALUE) {
  588. SetupCloseFileQueue(hFileQueue);
  589. hFileQueue = INVALID_HANDLE_VALUE;
  590. }
  591. if(hInf != INVALID_HANDLE_VALUE) {
  592. SetupCloseInfFile(hInf);
  593. hInf = INVALID_HANDLE_VALUE;
  594. }
  595. //
  596. // now install files from here to final destination
  597. // this should be relatively quick so don't bother with UI
  598. //
  599. if(!(Flags & COMP_FLAGS_NOINSTALL)) {
  600. return InstallInfSection(InfPath,
  601. SectionName,
  602. COMP_FLAGS_NOUI);
  603. }
  604. return S_OK;
  605. //
  606. // TODO - move files to component directory
  607. //
  608. final:
  609. if(QueueContext) {
  610. SetupTermDefaultQueueCallback(QueueContext);
  611. }
  612. if(hFileQueue != INVALID_HANDLE_VALUE) {
  613. SetupCloseFileQueue(hFileQueue);
  614. }
  615. if(hInf != INVALID_HANDLE_VALUE) {
  616. SetupCloseInfFile(hInf);
  617. }
  618. return HRESULT_FROM_SETUPAPI(Status);
  619. }
  620. DWORD
  621. DownlevelQueryInfOriginalFileInformation(
  622. IN HINF hInf,
  623. PSP_INF_INFORMATION InfInformation,
  624. PSP_ORIGINAL_FILE_INFO OriginalFileInfo
  625. )
  626. /*++
  627. Routine Description:
  628. Emulates SetupQueryInfOriginalFileInformation
  629. we need to look in hINF to determine catalog name
  630. only partial implementation enough to support x86
  631. (will degrade on other architectures)
  632. Arguments:
  633. hInf - handle to open INF file
  634. InfInformation - information obtained about original INF
  635. pInfOriginalFileInformation - fill with inf/catalog names
  636. Return Value:
  637. status as DWORD (not HRESULT)
  638. --*/
  639. {
  640. //
  641. // in downlevel case, filename is name of file we opened
  642. // catalog is referenced in the INF
  643. //
  644. // get basename of the INF
  645. // (actually returns full name, but we'll deal with it right)
  646. //
  647. INFCONTEXT InfLine;
  648. SYSTEM_INFO SysInfo;
  649. TCHAR KeyName[LINE_LEN];
  650. if(!SetupQueryInfFileInformation(InfInformation,
  651. 0,
  652. OriginalFileInfo->OriginalInfName,
  653. ARRAY_SIZE(OriginalFileInfo->OriginalInfName),
  654. NULL)) {
  655. return GetLastError();
  656. }
  657. //
  658. // now determine name of catalog
  659. //
  660. GetSystemInfo(&SysInfo);
  661. if(SysInfo.wProcessorArchitecture == PROCESSOR_ARCHITECTURE_INTEL) {
  662. //
  663. // look for .NTx86
  664. // only makes sence for x86
  665. // which is the only architecture we'll migrate Win9x/NT4 to Win2k+
  666. //
  667. lstrcpy(KeyName,INFSTR_KEY_CATALOGFILE);
  668. lstrcat(KeyName,TEXT(".NTx86"));
  669. if(SetupFindFirstLine(hInf,INFSTR_SECT_VERSION,KeyName,&InfLine)) {
  670. if(SetupGetStringField(&InfLine,
  671. 1,
  672. OriginalFileInfo->OriginalCatalogName,
  673. ARRAY_SIZE(OriginalFileInfo->OriginalCatalogName),
  674. NULL)) {
  675. return NO_ERROR;
  676. }
  677. }
  678. }
  679. //
  680. // look for .NT (even on 9x, as the exception pack will be re-parsed
  681. // on NT)
  682. //
  683. lstrcpy(KeyName,INFSTR_KEY_CATALOGFILE);
  684. lstrcat(KeyName,TEXT(".NT"));
  685. if(SetupFindFirstLine(hInf,INFSTR_SECT_VERSION,KeyName,&InfLine)) {
  686. if(SetupGetStringField(&InfLine,
  687. 1,
  688. OriginalFileInfo->OriginalCatalogName,
  689. ARRAY_SIZE(OriginalFileInfo->OriginalCatalogName),
  690. NULL)) {
  691. return NO_ERROR;
  692. }
  693. }
  694. //
  695. // finally look for undecorated
  696. //
  697. if(SetupFindFirstLine(hInf,INFSTR_SECT_VERSION,INFSTR_KEY_CATALOGFILE,&InfLine)) {
  698. if(SetupGetStringField(&InfLine,
  699. 1,
  700. OriginalFileInfo->OriginalCatalogName,
  701. ARRAY_SIZE(OriginalFileInfo->OriginalCatalogName),
  702. NULL)) {
  703. return NO_ERROR;
  704. }
  705. }
  706. //
  707. // no catalog
  708. //
  709. OriginalFileInfo->OriginalCatalogName[0] = TEXT('\0');
  710. return NO_ERROR;
  711. }
  712. HRESULT
  713. GetInfOriginalFileInformation(
  714. IN HINF hInf,
  715. OUT PSP_ORIGINAL_FILE_INFO pInfOriginalFileInformation
  716. )
  717. /*++
  718. Routine Description:
  719. Given a handle to an INF, determine names of inf and catalog files
  720. Arguments:
  721. hInf - handle to open INF file
  722. pInfOriginalFileInformation - inf/catalog names
  723. Return Value:
  724. status as hresult
  725. --*/
  726. {
  727. PSP_INF_INFORMATION pInfInformation = NULL;
  728. DWORD InfInformationSize;
  729. DWORD Status;
  730. InfInformationSize = 8192;
  731. pInfInformation = (PSP_INF_INFORMATION)malloc(InfInformationSize);
  732. if (pInfInformation == NULL) {
  733. return E_OUTOFMEMORY;
  734. }
  735. if(!SetupGetInfInformation(hInf,INFINFO_INF_SPEC_IS_HINF,pInfInformation,InfInformationSize,&InfInformationSize)) {
  736. PVOID TempBuf;
  737. Status = GetLastError();
  738. if(Status != ERROR_INSUFFICIENT_BUFFER) {
  739. free(pInfInformation);
  740. return HRESULT_FROM_SETUPAPI(Status);
  741. }
  742. TempBuf = realloc(pInfInformation,InfInformationSize);
  743. if(!TempBuf) {
  744. free(pInfInformation);
  745. return E_OUTOFMEMORY;
  746. }
  747. }
  748. if(!SetupGetInfInformation(hInf,INFINFO_INF_SPEC_IS_HINF,pInfInformation,InfInformationSize,&InfInformationSize)) {
  749. Status = GetLastError();
  750. free(pInfInformation);
  751. return HRESULT_FROM_SETUPAPI(Status);
  752. }
  753. pInfOriginalFileInformation->cbSize = sizeof(SP_ORIGINAL_FILE_INFO);
  754. if((g_VerInfo.dwPlatformId == VER_PLATFORM_WIN32_NT) && (g_VerInfo.dwMajorVersion >= 5)) {
  755. //
  756. // Win2k+ - have SetupAPI tell us the information (we're querying oem*.inf)
  757. //
  758. if (!QueryInfOriginalFileInformation(pInfInformation,0,NULL,pInfOriginalFileInformation)) {
  759. Status = GetLastError();
  760. free(pInfInformation);
  761. return HRESULT_FROM_SETUPAPI(Status);
  762. }
  763. } else {
  764. //
  765. // <Win2k - querying source INF, get information from there
  766. //
  767. Status = DownlevelQueryInfOriginalFileInformation(hInf,pInfInformation,pInfOriginalFileInformation);
  768. if(Status != NO_ERROR) {
  769. free(pInfInformation);
  770. return HRESULT_FROM_SETUPAPI(Status);
  771. }
  772. }
  773. free(pInfInformation);
  774. return S_OK;
  775. }
  776. HRESULT
  777. DeleteDirectoryRecursive(
  778. IN LPCTSTR Path
  779. )
  780. /*++
  781. Routine Description:
  782. delete specified directory recursively
  783. Arguments:
  784. Path - path of the directory to delete
  785. Return Value:
  786. as HRESULT
  787. S_FALSE if directory doesn't exist
  788. S_OK if directory deleted
  789. other error if, eg, files in use
  790. --*/
  791. {
  792. TCHAR Wildcard[MAX_PATH];
  793. TCHAR Target[MAX_PATH];
  794. HRESULT hrStatus;
  795. DWORD Status;
  796. HRESULT hrFirstError = S_FALSE;
  797. HANDLE hFind;
  798. WIN32_FIND_DATA FindData;
  799. //
  800. // enumerate the directory
  801. //
  802. lstrcpyn(Wildcard,Path,MAX_PATH);
  803. hrStatus = ConcatPath(Wildcard,MAX_PATH,TEXT("\\*.*"));
  804. if(!SUCCEEDED(hrStatus)) {
  805. return hrStatus;
  806. }
  807. hFind = FindFirstFile(Wildcard,&FindData);
  808. if(hFind != INVALID_HANDLE_VALUE) {
  809. hrFirstError = S_OK;
  810. do {
  811. if(lstrcmp(FindData.cFileName,TEXT(".")) == 0) {
  812. continue;
  813. }
  814. if(lstrcmp(FindData.cFileName,TEXT("..")) == 0) {
  815. continue;
  816. }
  817. lstrcpyn(Target,Path,MAX_PATH);
  818. hrStatus = ConcatPath(Target,MAX_PATH,FindData.cFileName);
  819. if(SUCCEEDED(hrStatus)) {
  820. if(FindData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) {
  821. hrStatus = DeleteDirectoryRecursive(Target);
  822. if(SUCCEEDED(hrFirstError) && !SUCCEEDED(hrStatus)) {
  823. hrFirstError = hrStatus;
  824. }
  825. } else {
  826. SetFileAttributes(Target,FILE_ATTRIBUTE_NORMAL);
  827. if(!DeleteFile(Target)) {
  828. Status = GetLastError();
  829. if(SUCCEEDED(hrFirstError)) {
  830. hrFirstError = HRESULT_FROM_WIN32(Status);
  831. }
  832. }
  833. }
  834. } else if(SUCCEEDED(hrFirstError)) {
  835. hrFirstError = hrStatus;
  836. }
  837. } while (FindNextFile(hFind,&FindData));
  838. FindClose(hFind);
  839. }
  840. //
  841. // now delete this directory
  842. //
  843. SetFileAttributes(Path,FILE_ATTRIBUTE_NORMAL);
  844. if(RemoveDirectory(Path) || !SUCCEEDED(hrFirstError)) {
  845. return hrFirstError;
  846. }
  847. Status = GetLastError();
  848. if((Status == ERROR_PATH_NOT_FOUND) || (Status == ERROR_FILE_NOT_FOUND)) {
  849. return hrFirstError;
  850. }
  851. return HRESULT_FROM_WIN32(Status);
  852. }
  853. HRESULT
  854. RevertStore(
  855. IN LPCTSTR BackupDir,
  856. IN LPCTSTR TargetDir
  857. )
  858. /*++
  859. Routine Description:
  860. moves contents from backup back to original location
  861. overwriting files/directories if needed
  862. Arguments:
  863. BackupDir - directory restoring from
  864. TargetDir - directory restoring to
  865. Return Value:
  866. as HRESULT
  867. S_OK if backup created
  868. other error if, eg, files in use
  869. --*/
  870. {
  871. TCHAR Wildcard[MAX_PATH];
  872. TCHAR Source[MAX_PATH];
  873. TCHAR Target[MAX_PATH];
  874. HRESULT hrStatus;
  875. HRESULT hrFirstError = S_FALSE;
  876. DWORD Status;
  877. DWORD dwRes;
  878. HANDLE hFind;
  879. WIN32_FIND_DATA FindData;
  880. lstrcpyn(Wildcard,BackupDir,MAX_PATH);
  881. hrStatus = ConcatPath(Wildcard,MAX_PATH,TEXT("\\*.*"));
  882. if(!SUCCEEDED(hrStatus)) {
  883. return hrStatus;
  884. }
  885. hFind = FindFirstFile(Wildcard,&FindData);
  886. if(hFind != INVALID_HANDLE_VALUE) {
  887. hrFirstError = S_OK;
  888. do {
  889. if(lstrcmp(FindData.cFileName,TEXT(".")) == 0) {
  890. continue;
  891. }
  892. if(lstrcmp(FindData.cFileName,TEXT("..")) == 0) {
  893. continue;
  894. }
  895. lstrcpyn(Source,BackupDir,MAX_PATH);
  896. hrStatus = ConcatPath(Source,MAX_PATH,FindData.cFileName);
  897. if(!SUCCEEDED(hrStatus)) {
  898. if(SUCCEEDED(hrFirstError)) {
  899. hrFirstError = hrStatus;
  900. }
  901. continue;
  902. }
  903. lstrcpyn(Target,TargetDir,MAX_PATH);
  904. hrStatus = ConcatPath(Target,MAX_PATH,FindData.cFileName);
  905. if(!SUCCEEDED(hrStatus)) {
  906. if(SUCCEEDED(hrFirstError)) {
  907. hrFirstError = hrStatus;
  908. }
  909. continue;
  910. }
  911. //
  912. // does target exist?
  913. //
  914. dwRes = GetFileAttributes(Target);
  915. if(dwRes != INVALID_FILE_ATTRIBUTES) {
  916. if(dwRes & FILE_ATTRIBUTE_DIRECTORY) {
  917. //
  918. // revert store recursively
  919. //
  920. hrStatus = RevertStore(Source,Target);
  921. if(!SUCCEEDED(hrStatus)) {
  922. if(SUCCEEDED(hrFirstError)) {
  923. hrFirstError = hrStatus;
  924. }
  925. continue;
  926. }
  927. } else {
  928. SetFileAttributes(Target,FILE_ATTRIBUTE_NORMAL);
  929. if(!DeleteFile(Target)) {
  930. Status = GetLastError();
  931. }
  932. }
  933. }
  934. if(!MoveFile(Source,Target)) {
  935. Status = GetLastError();
  936. hrStatus = HRESULT_FROM_WIN32(Status);
  937. if(SUCCEEDED(hrFirstError)) {
  938. hrFirstError = hrStatus;
  939. }
  940. }
  941. } while (FindNextFile(hFind,&FindData));
  942. FindClose(hFind);
  943. }
  944. //
  945. // now attempt to remove the backup directory
  946. //
  947. if(RemoveDirectory(BackupDir) || !SUCCEEDED(hrFirstError)) {
  948. return hrFirstError;
  949. }
  950. Status = GetLastError();
  951. if((Status == ERROR_PATH_NOT_FOUND) || (Status == ERROR_FILE_NOT_FOUND)) {
  952. return hrFirstError;
  953. }
  954. return HRESULT_FROM_WIN32(Status);
  955. }
  956. HRESULT
  957. BackupStore(
  958. IN LPCTSTR Path,
  959. OUT LPTSTR BackupDir,
  960. OUT DWORD BackupDirLen
  961. )
  962. /*++
  963. Routine Description:
  964. moves contents to new backup, ideally to \\$BACKUP$
  965. returns name of backup
  966. Arguments:
  967. Path - path of the store
  968. BackupDir - filled with directory containing backup
  969. BackupDirLen - containing length of BackupDir
  970. Return Value:
  971. as HRESULT
  972. S_OK if backup created
  973. other error if, eg, files in use
  974. --*/
  975. {
  976. TCHAR Wildcard[MAX_PATH];
  977. TCHAR Source[MAX_PATH];
  978. TCHAR Target[MAX_PATH];
  979. HRESULT hrStatus;
  980. DWORD Status;
  981. HANDLE hFind;
  982. WIN32_FIND_DATA FindData;
  983. int i;
  984. int len;
  985. lstrcpyn(BackupDir,Path,BackupDirLen);
  986. hrStatus = ConcatPath(BackupDir,BackupDirLen,TEXT("\\$BACKUP$"));
  987. if(!SUCCEEDED(hrStatus)) {
  988. //
  989. // obviously path is too big, no point ignoring
  990. // as we'd fail elsewhere
  991. //
  992. return hrStatus;
  993. }
  994. len = lstrlen(BackupDir);
  995. if((BackupDirLen-len)<5) {
  996. return HRESULT_FROM_WIN32(ERROR_INSUFFICIENT_BUFFER);
  997. }
  998. //
  999. // first, if there's a backup, try and delete it
  1000. //
  1001. hrStatus = DeleteDirectoryRecursive(BackupDir);
  1002. if(SUCCEEDED(hrStatus)) {
  1003. hrStatus = MakeSurePathExists(BackupDir);
  1004. }
  1005. if((hrStatus == HRESULT_FROM_WIN32(ERROR_WRITE_PROTECT)) ||
  1006. (hrStatus == HRESULT_FROM_WIN32(ERROR_INVALID_ACCESS))) {
  1007. //
  1008. // no point even trying again
  1009. //
  1010. return hrStatus;
  1011. }
  1012. for(i = 0;!SUCCEEDED(hrStatus) && i<1000;i++) {
  1013. _sntprintf(BackupDir+len,5,TEXT(".%03u"),i);
  1014. hrStatus = DeleteDirectoryRecursive(BackupDir);
  1015. if(SUCCEEDED(hrStatus)) {
  1016. hrStatus = MakeSurePathExists(BackupDir);
  1017. }
  1018. }
  1019. if(!SUCCEEDED(hrStatus)) {
  1020. return hrStatus;
  1021. }
  1022. //
  1023. // now we have a backup directory, move all the files there
  1024. //
  1025. lstrcpyn(Wildcard,Path,MAX_PATH);
  1026. hrStatus = ConcatPath(Wildcard,MAX_PATH,TEXT("\\*.*"));
  1027. if(!SUCCEEDED(hrStatus)) {
  1028. return hrStatus;
  1029. }
  1030. hrStatus = S_FALSE;
  1031. hFind = FindFirstFile(Wildcard,&FindData);
  1032. if(hFind != INVALID_HANDLE_VALUE) {
  1033. do {
  1034. if(lstrcmp(FindData.cFileName,TEXT(".")) == 0) {
  1035. continue;
  1036. }
  1037. if(lstrcmp(FindData.cFileName,TEXT("..")) == 0) {
  1038. continue;
  1039. }
  1040. if(_tcsnicmp(FindData.cFileName,TEXT("$BACKUP$"),8) == 0) {
  1041. //
  1042. // a/the backup directory
  1043. //
  1044. continue;
  1045. }
  1046. lstrcpyn(Source,Path,MAX_PATH);
  1047. hrStatus = ConcatPath(Source,MAX_PATH,FindData.cFileName);
  1048. if(!SUCCEEDED(hrStatus)) {
  1049. break;
  1050. }
  1051. lstrcpyn(Target,BackupDir,MAX_PATH);
  1052. hrStatus = ConcatPath(Target,MAX_PATH,FindData.cFileName);
  1053. if(!SUCCEEDED(hrStatus)) {
  1054. break;
  1055. }
  1056. if(!MoveFile(Source,Target)) {
  1057. Status = GetLastError();
  1058. hrStatus = HRESULT_FROM_WIN32(Status);
  1059. }
  1060. if(!SUCCEEDED(hrStatus)) {
  1061. break;
  1062. }
  1063. hrStatus = S_OK;
  1064. } while (FindNextFile(hFind,&FindData));
  1065. FindClose(hFind);
  1066. }
  1067. if(!SUCCEEDED(hrStatus)) {
  1068. RevertStore(BackupDir,Path);
  1069. }
  1070. return hrStatus;
  1071. }
  1072. HRESULT
  1073. WINAPI
  1074. InstallComponentW(
  1075. IN LPCTSTR InfPath,
  1076. IN DWORD Flags,
  1077. IN const GUID * CompGuid, OPTIONAL
  1078. IN INT VerMajor, OPTIONAL
  1079. IN INT VerMinor, OPTIONAL
  1080. IN INT VerBuild, OPTIONAL
  1081. IN INT VerQFE, OPTIONAL
  1082. IN LPCTSTR Name OPTIONAL
  1083. )
  1084. /*++
  1085. Routine Description:
  1086. exported for call by setup routine
  1087. install a component with a given version assumed
  1088. show progress while pulling files from original location
  1089. Arguments:
  1090. InfPath - path to INF file
  1091. Flags - flags
  1092. COMP_FLAGS_NOINSTALL - place in store, don't install
  1093. COMP_FLAGS_NOUI - don't show any UI
  1094. COMP_FLAGS_NOPROMPTREBOOT - reboot if needed (no prompt)
  1095. COMP_FLAGS_PROMPTREBOOT - prompt for reboot if needed
  1096. COMP_FLAGS_NEEDSREBOOT - assume reboot needed
  1097. CompGuid - if NULL, use GUID specified in INF (ComponentId)
  1098. else verify against GUID specified in INF
  1099. VerMajor/VerMinor/VerBuild/VerQFE
  1100. - if -1, use version specified in INF (ComponentVersion)
  1101. else use this version and verify against version if specified in INF
  1102. Name
  1103. - if NULL, use name specified in INF (ComponentName)
  1104. else use this component name.
  1105. Return Value:
  1106. status as hresult
  1107. --*/
  1108. {
  1109. HINF hInf = INVALID_HANDLE_VALUE;
  1110. INFCONTEXT InfLine;
  1111. TCHAR Buffer[MAX_PATH*3];
  1112. TCHAR FriendlyName[DESC_SIZE];
  1113. TCHAR NewStore[MAX_PATH];
  1114. TCHAR OldStore[MAX_PATH];
  1115. TCHAR MediaRoot[MAX_PATH];
  1116. TCHAR GuidString[64];
  1117. LPTSTR BaseName;
  1118. LPTSTR SubDir;
  1119. DWORD Status = NO_ERROR; // set Status or hrStatus
  1120. DWORD DwRes;
  1121. UINT UiRes;
  1122. HRESULT hrStatus = S_OK;
  1123. GUID InfGuid;
  1124. INT InfVerMajor,InfVerMinor,InfVerBuild,InfVerQFE;
  1125. BOOL PrevReg = FALSE;
  1126. BOOL NeedProxy = FALSE;
  1127. BOOL CanRevert = FALSE;
  1128. BOOL BackedUp = FALSE;
  1129. SETUP_OS_COMPONENT_DATA OsComponentData;
  1130. SETUP_OS_EXCEPTION_DATA OsExceptionData;
  1131. SETUP_OS_COMPONENT_DATA NewOsComponentData;
  1132. SETUP_OS_EXCEPTION_DATA NewOsExceptionData;
  1133. SP_ORIGINAL_FILE_INFO InfOriginalFileInformation;
  1134. //
  1135. // validate args
  1136. //
  1137. if((InfPath == NULL)
  1138. || (VerMajor<-1)
  1139. || (VerMajor>65535)
  1140. || (VerMinor<-1)
  1141. || (VerMinor>65535)
  1142. || (VerBuild<-1)
  1143. || (VerBuild>65535)
  1144. || (VerQFE<-1)
  1145. || (VerQFE>65535)
  1146. || (lstrlen(InfPath)>=MAX_PATH)
  1147. || (Name && (lstrlen(Name)>=ARRAY_SIZE(FriendlyName)))) {
  1148. return E_INVALIDARG;
  1149. }
  1150. //
  1151. // open the INF, we're going to do some information finding
  1152. //
  1153. hInf = SetupOpenInfFile(InfPath,NULL,INF_STYLE_WIN4,NULL);
  1154. if(hInf == INVALID_HANDLE_VALUE) {
  1155. Status = GetLastError();
  1156. goto final;
  1157. }
  1158. //
  1159. // get various information about this exception pack
  1160. // We want to know about the exception pack
  1161. // check classguid is correct
  1162. // get componentid
  1163. // get version if exists, and validate against any passed in
  1164. // get description if exists (overwritten by that passed in)
  1165. //
  1166. //
  1167. // CLASSGUID={F5776D81-AE53-4935-8E84-B0B283D8BCEF}
  1168. //
  1169. if(!SetupFindFirstLine(hInf,INFSTR_SECT_VERSION,INFSTR_KEY_CLASSGUID,&InfLine)) {
  1170. Status = GetLastError();
  1171. goto final;
  1172. }
  1173. if(!SetupGetStringField(&InfLine,1,Buffer,MAX_PATH,NULL)) {
  1174. Status = GetLastError();
  1175. goto final;
  1176. }
  1177. if(_tcsicmp(Buffer,TEXT("{F5776D81-AE53-4935-8E84-B0B283D8BCEF}"))!=0) {
  1178. hrStatus = SPAPI_E_CLASS_MISMATCH;
  1179. goto final;
  1180. }
  1181. //
  1182. // determine what component the INF says
  1183. // ComponentId must exist for exception packs
  1184. //
  1185. if(!SetupFindFirstLine(hInf,INFSTR_SECT_VERSION,KEY_COMPONENTID,&InfLine)) {
  1186. Status = GetLastError();
  1187. goto final;
  1188. }
  1189. if(!SetupGetStringField(&InfLine,1,Buffer,MAX_PATH,NULL)) {
  1190. Status = GetLastError();
  1191. goto final;
  1192. }
  1193. hrStatus = GuidFromString(Buffer,&InfGuid);
  1194. if(SUCCEEDED(hrStatus)) {
  1195. hrStatus = S_OK;
  1196. } else {
  1197. goto final;
  1198. }
  1199. if(CompGuid && !IsEqualGUID(CompGuid,&InfGuid)) {
  1200. //
  1201. // mismatched
  1202. //
  1203. hrStatus = E_INVALIDARG;
  1204. goto final;
  1205. }
  1206. //
  1207. // determine version - optional, just for msoobci
  1208. // but if not specified in INF in DriverVer = <date>,<version>
  1209. // must be passed in
  1210. //
  1211. if(SetupFindFirstLine(hInf,INFSTR_SECT_VERSION,INFSTR_DRIVERVERSION_SECTION,&InfLine)) {
  1212. if(!SetupGetStringField(&InfLine,2,Buffer,MAX_PATH,NULL)) {
  1213. Status = GetLastError();
  1214. goto final;
  1215. }
  1216. hrStatus = VersionFromString(Buffer,&InfVerMajor,&InfVerMinor,&InfVerBuild,&InfVerQFE);
  1217. if(hrStatus == S_FALSE) {
  1218. hrStatus = E_INVALIDARG;
  1219. goto final;
  1220. }
  1221. if(SUCCEEDED(hrStatus)) {
  1222. hrStatus = S_OK;
  1223. } else {
  1224. goto final;
  1225. }
  1226. if(VerMajor>=0) {
  1227. if(VerMajor != InfVerMajor) {
  1228. hrStatus = E_INVALIDARG;
  1229. goto final;
  1230. }
  1231. if(VerMinor>=0) {
  1232. if(VerMinor != InfVerMinor) {
  1233. hrStatus = E_INVALIDARG;
  1234. goto final;
  1235. }
  1236. if(VerBuild>=0) {
  1237. if(VerBuild != InfVerBuild) {
  1238. hrStatus = E_INVALIDARG;
  1239. goto final;
  1240. }
  1241. if(VerQFE>=0) {
  1242. if(VerQFE != InfVerQFE) {
  1243. hrStatus = E_INVALIDARG;
  1244. goto final;
  1245. }
  1246. }
  1247. } else if(VerQFE != -1) {
  1248. //
  1249. // VerQFE must be -1
  1250. //
  1251. hrStatus = E_INVALIDARG;
  1252. goto final;
  1253. }
  1254. } else if((VerBuild != -1) || (VerQFE != -1)) {
  1255. //
  1256. // VerBuild & VerQFE must be -1
  1257. //
  1258. hrStatus = E_INVALIDARG;
  1259. goto final;
  1260. }
  1261. } else if((VerMinor != -1) || (VerBuild != -1) || (VerQFE != -1)) {
  1262. //
  1263. // VerMinor, VerBuild & VerQFE must be -1
  1264. //
  1265. hrStatus = E_INVALIDARG;
  1266. goto final;
  1267. }
  1268. } else {
  1269. //
  1270. // must be specified
  1271. //
  1272. if((VerMajor<0) || (VerMinor<0) || (VerBuild<0) || (VerQFE<0)) {
  1273. hrStatus = E_INVALIDARG;
  1274. goto final;
  1275. }
  1276. InfVerMajor = VerMajor;
  1277. InfVerMinor = VerMinor;
  1278. InfVerBuild = VerBuild;
  1279. InfVerQFE = VerQFE;
  1280. }
  1281. //
  1282. // determine friendly name
  1283. // use Class= entry in INF (must always be specified)
  1284. // if Name not defined, use class name instead
  1285. //
  1286. if(!SetupFindFirstLine(hInf,INFSTR_SECT_VERSION,INFSTR_KEY_CLASS,&InfLine)) {
  1287. Status = GetLastError();
  1288. goto final;
  1289. }
  1290. if(!Name) {
  1291. if(!SetupGetStringField(&InfLine,1,FriendlyName,ARRAY_SIZE(FriendlyName),NULL)) {
  1292. Status = GetLastError();
  1293. goto final;
  1294. }
  1295. Name = FriendlyName;
  1296. }
  1297. //
  1298. // we might not need to update this package after all
  1299. //
  1300. ZeroMemory(&OsComponentData,sizeof(OsComponentData));
  1301. OsComponentData.SizeOfStruct = sizeof(OsComponentData);
  1302. ZeroMemory(&OsExceptionData,sizeof(OsExceptionData));
  1303. OsExceptionData.SizeOfStruct = sizeof(OsExceptionData);
  1304. if(QueryRegisteredOsComponent(&InfGuid,&OsComponentData,&OsExceptionData)) {
  1305. //
  1306. // already registered? see if we supercede
  1307. //
  1308. if(((Flags & COMP_FLAGS_FORCE)==0) && (CompareCompVersion(InfVerMajor,InfVerMinor,InfVerBuild,InfVerQFE,&OsComponentData)<=0)) {
  1309. VerbosePrint(TEXT("Not installing %s, %u.%u.%u.%u <= %u.%u.%u.%u"),
  1310. InfPath,
  1311. InfVerMajor,InfVerMinor,InfVerBuild,InfVerQFE,
  1312. OsComponentData.VersionMajor,
  1313. OsComponentData.VersionMinor,
  1314. OsComponentData.BuildNumber,
  1315. OsComponentData.QFENumber);
  1316. hrStatus = S_FALSE;
  1317. goto final;
  1318. }
  1319. PrevReg = TRUE;
  1320. }
  1321. //
  1322. // determine MediaRoot and INF basename
  1323. //
  1324. DwRes= GetFullPathName(InfPath,MAX_PATH,MediaRoot,&BaseName);
  1325. if(DwRes == 0) {
  1326. Status = GetLastError();
  1327. goto final;
  1328. } else if(DwRes >= MAX_PATH) {
  1329. Status = ERROR_INSUFFICIENT_BUFFER;
  1330. goto final;
  1331. }
  1332. if((BaseName == NULL) || (BaseName == InfPath) || !BaseName[0]) {
  1333. hrStatus = E_INVALIDARG;
  1334. goto final;
  1335. }
  1336. if(BaseName[-1] != TEXT('\\')) {
  1337. hrStatus = E_INVALIDARG;
  1338. goto final;
  1339. }
  1340. //
  1341. // split off MediaRoot and BaseName
  1342. //
  1343. BaseName[-1] = TEXT('\0');
  1344. //
  1345. // get Windows directory
  1346. //
  1347. UiRes = GetRealWindowsDirectory(Buffer,MAX_PATH);
  1348. if(UiRes == 0) {
  1349. Status = GetLastError();
  1350. goto final;
  1351. } else if(UiRes >= MAX_PATH) {
  1352. Status = ERROR_INSUFFICIENT_BUFFER;
  1353. goto final;
  1354. }
  1355. if(!SUCCEEDED(ConcatPath(Buffer,MAX_PATH,TEXT("\\")))) {
  1356. Status = ERROR_INSUFFICIENT_BUFFER;
  1357. goto final;
  1358. }
  1359. SubDir = Buffer+lstrlen(Buffer);
  1360. //
  1361. // c:\windows\
  1362. // ^-buffer ^-subdir
  1363. // we'll do a number of operations using the subdir part of this buffer
  1364. //
  1365. // if PrevReg is TRUE, we most likely have access to previous package
  1366. // so that we can install prev package to revert back to it
  1367. // we expect this package to be in the windows directory as per spec
  1368. // if it's not, then the old package might not still be around
  1369. //
  1370. if(PrevReg && _tcsncmp(OsExceptionData.ExceptionInfName,Buffer,SubDir-Buffer)==0) {
  1371. //
  1372. // it's a sub-directory of %windir%
  1373. // now check for presence of INF and CAT files
  1374. //
  1375. DwRes = GetFileAttributes(OsExceptionData.ExceptionInfName);
  1376. if(DwRes != INVALID_FILE_ATTRIBUTES) {
  1377. DwRes = GetFileAttributes(OsExceptionData.CatalogFileName);
  1378. if(DwRes != INVALID_FILE_ATTRIBUTES) {
  1379. //
  1380. // both present, looks good
  1381. //
  1382. CanRevert = TRUE;
  1383. }
  1384. }
  1385. }
  1386. //
  1387. // determine final path/name of INF and catalog
  1388. // We must place it directly in %windir%\<comp>
  1389. // (WFP relies on this!!!!)
  1390. // we'll backup what's there so that we can restore it later if needed
  1391. //
  1392. hrStatus = StringFromGuid(&InfGuid,GuidString,ARRAY_SIZE(GuidString));
  1393. if(!SUCCEEDED(hrStatus)) {
  1394. goto final;
  1395. }
  1396. hrStatus = S_OK;
  1397. _sntprintf(SubDir,MAX_PATH,TEXT("%s\\%s"),
  1398. TEXT("RegisteredPackages"),
  1399. GuidString
  1400. );
  1401. if((lstrlen(Buffer)+16)>MAX_PATH) {
  1402. Status = ERROR_INSUFFICIENT_BUFFER;
  1403. goto final;
  1404. }
  1405. lstrcpy(NewStore,Buffer);
  1406. if(CanRevert) {
  1407. hrStatus = BackupStore(NewStore,OldStore,ARRAY_SIZE(OldStore));
  1408. if(!SUCCEEDED(hrStatus)) {
  1409. //
  1410. // if we failed backup, that means there's something bad
  1411. // such as files in the store in use
  1412. // probability is that we'll fail later
  1413. // so fail gracefully now instead of badly later
  1414. //
  1415. goto final;
  1416. }
  1417. hrStatus = S_OK;
  1418. }
  1419. //
  1420. // see if %windir%\INF\<BaseName> is there?
  1421. //
  1422. lstrcpy(SubDir,TEXT("INF\\"));
  1423. if(!SUCCEEDED(ConcatPath(Buffer,MAX_PATH,BaseName))) {
  1424. Status = ERROR_INSUFFICIENT_BUFFER;
  1425. goto final;
  1426. }
  1427. DwRes = GetFileAttributes(Buffer);
  1428. if(DwRes != INVALID_FILE_ATTRIBUTES) {
  1429. //
  1430. // replacing an existing INF
  1431. // to work around a cache bug, we'll kick the actuall install
  1432. // off in another process
  1433. //
  1434. NeedProxy = TRUE;
  1435. }
  1436. hrStatus = MakeSurePathExists(NewStore);
  1437. if(!SUCCEEDED(hrStatus)) {
  1438. goto final;
  1439. }
  1440. //
  1441. // install INF into %windir%\INF directory noting location the files
  1442. // should be
  1443. //
  1444. if((g_VerInfo.dwPlatformId == VER_PLATFORM_WIN32_NT) && (g_VerInfo.dwMajorVersion >= 5)) {
  1445. //
  1446. // only do this on Win2k+
  1447. // this will have SetupAPI tell us the original name and the catalog
  1448. // name
  1449. //
  1450. if(CopyOEMInf(InfPath,NewStore,SPOST_PATH,0,NULL,0,NULL,NULL)) {
  1451. //
  1452. // Switch to the INF that's in %windir%\INF directory
  1453. //
  1454. SetupCloseInfFile(hInf);
  1455. hInf = SetupOpenInfFile(Buffer,NULL,INF_STYLE_WIN4,NULL);
  1456. if(hInf == INVALID_HANDLE_VALUE) {
  1457. Status = GetLastError();
  1458. goto final;
  1459. }
  1460. } else {
  1461. Status = GetLastError();
  1462. goto final;
  1463. }
  1464. }
  1465. //
  1466. // now find out what the catalog name would be
  1467. //
  1468. hrStatus = GetInfOriginalFileInformation(hInf,&InfOriginalFileInformation);
  1469. if(!SUCCEEDED(hrStatus)) {
  1470. goto final;
  1471. }
  1472. if((InfOriginalFileInformation.OriginalInfName[0]==TEXT('\0'))
  1473. ||(InfOriginalFileInformation.OriginalCatalogName[0]==TEXT('\0'))) {
  1474. //
  1475. // shouldn't happen
  1476. //
  1477. hrStatus = E_FAIL;
  1478. goto final;
  1479. }
  1480. ZeroMemory(&NewOsExceptionData,sizeof(NewOsExceptionData));
  1481. NewOsExceptionData.SizeOfStruct = sizeof(NewOsExceptionData);
  1482. //
  1483. // INF name
  1484. //
  1485. BaseName = GetBaseName(InfOriginalFileInformation.OriginalInfName);
  1486. lstrcpyn(NewOsExceptionData.ExceptionInfName,NewStore,ARRAY_SIZE(NewOsExceptionData.ExceptionInfName));
  1487. if(!SUCCEEDED(ConcatPath(NewOsExceptionData.ExceptionInfName,ARRAY_SIZE(NewOsExceptionData.ExceptionInfName),BaseName))) {
  1488. Status = ERROR_INSUFFICIENT_BUFFER;
  1489. goto final;
  1490. }
  1491. lstrcpy(Buffer,MediaRoot);
  1492. if(!SUCCEEDED(ConcatPath(Buffer,MAX_PATH,BaseName))) {
  1493. Status = ERROR_INSUFFICIENT_BUFFER;
  1494. goto final;
  1495. }
  1496. if(!CopyFile(Buffer,NewOsExceptionData.ExceptionInfName,FALSE)) {
  1497. Status = GetLastError();
  1498. goto final;
  1499. }
  1500. //
  1501. // CAT name
  1502. //
  1503. BaseName = GetBaseName(InfOriginalFileInformation.OriginalCatalogName);
  1504. lstrcpyn(NewOsExceptionData.CatalogFileName,NewStore,ARRAY_SIZE(NewOsExceptionData.CatalogFileName));
  1505. if(!SUCCEEDED(ConcatPath(NewOsExceptionData.CatalogFileName,ARRAY_SIZE(NewOsExceptionData.CatalogFileName),BaseName))) {
  1506. Status = ERROR_INSUFFICIENT_BUFFER;
  1507. goto final;
  1508. }
  1509. lstrcpy(Buffer,MediaRoot);
  1510. if(!SUCCEEDED(ConcatPath(Buffer,MAX_PATH,BaseName))) {
  1511. Status = ERROR_INSUFFICIENT_BUFFER;
  1512. goto final;
  1513. }
  1514. if(!CopyFile(Buffer,NewOsExceptionData.CatalogFileName,FALSE)) {
  1515. Status = GetLastError();
  1516. goto final;
  1517. }
  1518. //
  1519. // WFP may query exception pack as a source to restore files that are replaced
  1520. // change registration so if WFP does get in loop, it goes to the right place
  1521. //
  1522. if(PrevReg) {
  1523. UnRegisterOsComponent(&InfGuid);
  1524. }
  1525. ZeroMemory(&NewOsComponentData,sizeof(NewOsComponentData));
  1526. NewOsComponentData.SizeOfStruct = sizeof(NewOsComponentData);
  1527. NewOsComponentData.ComponentGuid = InfGuid;
  1528. lstrcpyn(NewOsComponentData.FriendlyName,Name,ARRAY_SIZE(NewOsComponentData.FriendlyName));
  1529. NewOsComponentData.VersionMajor = (WORD)InfVerMajor;
  1530. NewOsComponentData.VersionMinor = (WORD)InfVerMinor;
  1531. NewOsComponentData.BuildNumber = (WORD)InfVerBuild;
  1532. NewOsComponentData.QFENumber = (WORD)InfVerQFE;
  1533. if(!RegisterOsComponent(&NewOsComponentData,&NewOsExceptionData)) {
  1534. Status = GetLastError();
  1535. goto final;
  1536. }
  1537. if(((Flags & COMP_FLAGS_NOUI)==0) && !IsInteractiveWindowStation()) {
  1538. Flags |= COMP_FLAGS_NOUI;
  1539. }
  1540. if(NeedProxy) {
  1541. //
  1542. // A bug in Win2k/XP means that we have problems if replacing an existing
  1543. // exception-pack component
  1544. //
  1545. hrStatus = ProxyInstallExceptionPackFromInf(InfPath,MediaRoot,NewStore,Flags);
  1546. } else {
  1547. hrStatus = InstallExceptionPackFromInf(InfPath,MediaRoot,NewStore,Flags);
  1548. }
  1549. if(!SUCCEEDED(hrStatus)) {
  1550. //
  1551. // not sure best thing to do here, but
  1552. // the component that we had above is definately invalid
  1553. //
  1554. UnRegisterOsComponent(&InfGuid);
  1555. if(PrevReg) {
  1556. RegisterOsComponent(&OsComponentData,&OsExceptionData);
  1557. }
  1558. if(BackedUp) {
  1559. //
  1560. // we got part through and failed. Re-install the old component
  1561. // to revert whatever we did
  1562. //
  1563. RevertStore(OldStore,NewStore);
  1564. BackedUp = FALSE;
  1565. InstallInfSection(OsExceptionData.ExceptionInfName,NULL,COMP_FLAGS_NOUI);
  1566. }
  1567. goto final;
  1568. } else {
  1569. //
  1570. // don't need backup any more
  1571. //
  1572. if(BackedUp) {
  1573. DeleteDirectoryRecursive(OldStore);
  1574. BackedUp = FALSE;
  1575. }
  1576. }
  1577. //
  1578. // succeeded
  1579. //
  1580. Status = NO_ERROR;
  1581. if(hrStatus == INST_S_REBOOT) {
  1582. hrStatus = HandleReboot(Flags);
  1583. } else {
  1584. hrStatus = S_OK;
  1585. }
  1586. final:
  1587. if(hInf != INVALID_HANDLE_VALUE) {
  1588. SetupCloseInfFile(hInf);
  1589. }
  1590. if((hrStatus == S_OK) && Status != NO_ERROR) {
  1591. hrStatus = HRESULT_FROM_SETUPAPI(Status);
  1592. }
  1593. if(BackedUp) {
  1594. //
  1595. // we need to revert the backup
  1596. //
  1597. RevertStore(OldStore,NewStore);
  1598. }
  1599. return hrStatus;
  1600. }
  1601. HRESULT
  1602. WINAPI
  1603. InstallComponentA(
  1604. IN LPCSTR InfPath,
  1605. IN DWORD Flags,
  1606. IN const GUID * CompGuid, OPTIONAL
  1607. IN INT VerMajor, OPTIONAL
  1608. IN INT VerMinor, OPTIONAL
  1609. IN INT VerBuild, OPTIONAL
  1610. IN INT VerQFE, OPTIONAL
  1611. IN LPCSTR Name OPTIONAL
  1612. )
  1613. {
  1614. TCHAR OutPath[MAX_PATH];
  1615. TCHAR OutDesc[DESC_SIZE]; // as per friendly name
  1616. INT sz;
  1617. if(InfPath) {
  1618. sz = MultiByteToWideChar(CP_ACP,0,InfPath,-1,OutPath,ARRAY_SIZE(OutPath));
  1619. if(!sz) {
  1620. return E_INVALIDARG;
  1621. }
  1622. }
  1623. if(Name) {
  1624. sz = MultiByteToWideChar(CP_ACP,0,Name,-1,OutDesc,ARRAY_SIZE(OutDesc));
  1625. if(!sz) {
  1626. return E_INVALIDARG;
  1627. }
  1628. }
  1629. return InstallComponent(InfPath ? OutPath : NULL,
  1630. Flags,
  1631. CompGuid,
  1632. VerMajor,
  1633. VerMinor,
  1634. VerBuild,
  1635. VerQFE,
  1636. Name ? OutDesc : NULL);
  1637. }
  1638. VOID
  1639. WINAPI
  1640. DoInstallW(
  1641. IN HWND Window,
  1642. IN HINSTANCE ModuleHandle,
  1643. IN PCTSTR CommandLine,
  1644. IN INT ShowCommand
  1645. )
  1646. /*++
  1647. Routine Description:
  1648. exported for call by rundll32
  1649. Arguments:
  1650. Window - parent window (not used)
  1651. ModuleHandle - not used
  1652. CommandLine - see below
  1653. ShowCommand - not used
  1654. CommandLine -
  1655. "InfPath;Flags;GUID;High.Low.Build.QFE;Name" (; - CMD_SEP)
  1656. Return Value:
  1657. none
  1658. --*/
  1659. {
  1660. TCHAR InfPath[MAX_PATH];
  1661. TCHAR Desc[DESC_SIZE];
  1662. TCHAR Hold[64];
  1663. INT VerMajor = -1;
  1664. INT VerMinor = -1;
  1665. INT VerBuild = -1;
  1666. INT VerQFE = -1;
  1667. GUID Guid;
  1668. DWORD Flags = 0;
  1669. LPGUID pGuid = NULL;
  1670. LPTSTR pDesc = NULL;
  1671. LPCTSTR pCmd = CommandLine;
  1672. LPCTSTR pEnd;
  1673. HRESULT hResult = S_OK;
  1674. //
  1675. // break CommandLine up into relevent parts
  1676. // First InfPath
  1677. //
  1678. pEnd = _tcschr(pCmd,CMD_SEP);
  1679. if(!pEnd) {
  1680. pEnd = pCmd+lstrlen(pCmd);
  1681. }
  1682. if((pEnd == pCmd) || ((pEnd-pCmd)>=MAX_PATH)) {
  1683. hResult = E_INVALIDARG;
  1684. goto final;
  1685. }
  1686. CopyMemory(InfPath,pCmd,(pEnd-pCmd)*sizeof(TCHAR));
  1687. InfPath[pEnd-pCmd] = TEXT('\0');
  1688. if(*pEnd == CMD_SEP) {
  1689. pCmd = pEnd+1;
  1690. if((*pCmd == CMD_SEP) || (*pCmd == TEXT('\0'))) {
  1691. //
  1692. // skip
  1693. //
  1694. pEnd = pCmd;
  1695. } else {
  1696. //
  1697. // Flags
  1698. //
  1699. Flags = (DWORD)_tcstoul(pCmd,&(LPTSTR)pEnd,0);
  1700. if((*pEnd != CMD_SEP) && (*pEnd != TEXT('\0'))) {
  1701. hResult = E_INVALIDARG;
  1702. goto final;
  1703. }
  1704. }
  1705. }
  1706. if(*pEnd == CMD_SEP) {
  1707. pCmd = pEnd+1;
  1708. if((*pCmd == CMD_SEP) || (*pCmd == TEXT('\0'))) {
  1709. //
  1710. // skip
  1711. //
  1712. pEnd = pCmd;
  1713. } else {
  1714. //
  1715. // Guid
  1716. //
  1717. pEnd = _tcschr(pCmd,CMD_SEP);
  1718. if(!pEnd) {
  1719. pEnd = pCmd+lstrlen(pCmd);
  1720. }
  1721. if((pEnd-pCmd)>=ARRAY_SIZE(Hold)) {
  1722. hResult = E_INVALIDARG;
  1723. goto final;
  1724. }
  1725. CopyMemory(Hold,pCmd,(pEnd-pCmd)*sizeof(TCHAR));
  1726. Hold[pEnd-pCmd] = TEXT('\0');
  1727. hResult = GuidFromString(Hold,&Guid);
  1728. if(!SUCCEEDED(hResult)) {
  1729. goto final;
  1730. }
  1731. pGuid = &Guid;
  1732. }
  1733. }
  1734. if(*pEnd == CMD_SEP) {
  1735. pCmd = pEnd+1;
  1736. if((*pCmd == CMD_SEP) || (*pCmd == TEXT('\0'))) {
  1737. //
  1738. // skip
  1739. //
  1740. pEnd = pCmd;
  1741. } else {
  1742. //
  1743. // Version
  1744. //
  1745. pEnd = _tcschr(pCmd,CMD_SEP);
  1746. if(!pEnd) {
  1747. pEnd = pCmd+lstrlen(pCmd);
  1748. }
  1749. if((pEnd-pCmd)>=ARRAY_SIZE(Hold)) {
  1750. hResult = E_INVALIDARG;
  1751. goto final;
  1752. }
  1753. CopyMemory(Hold,pCmd,(pEnd-pCmd)*sizeof(TCHAR));
  1754. Hold[pEnd-pCmd] = TEXT('\0');
  1755. hResult = VersionFromString(Hold,&VerMajor,&VerMinor,&VerBuild,&VerQFE);
  1756. if(!SUCCEEDED(hResult)) {
  1757. goto final;
  1758. }
  1759. if(hResult == S_FALSE) {
  1760. VerMajor = VerMinor = VerBuild = VerQFE = -1;
  1761. }
  1762. }
  1763. }
  1764. if(*pEnd == CMD_SEP) {
  1765. pCmd = pEnd+1;
  1766. pEnd = pCmd+lstrlen(pCmd);
  1767. if(pEnd != pCmd) {
  1768. if((pEnd-pCmd) >= ARRAY_SIZE(Desc)) {
  1769. hResult = E_INVALIDARG;
  1770. goto final;
  1771. }
  1772. CopyMemory(Desc,pCmd,(pEnd-pCmd)*sizeof(TCHAR));
  1773. Desc[pEnd-pCmd] = TEXT('\0');
  1774. pDesc = Desc;
  1775. }
  1776. }
  1777. hResult = InstallComponent(InfPath,Flags,pGuid,VerMajor,VerMinor,VerBuild,VerQFE,pDesc);
  1778. final:
  1779. if(SUCCEEDED(hResult)) {
  1780. //
  1781. // deal with specific success scenarios
  1782. //
  1783. } else {
  1784. //
  1785. // an error occurred
  1786. //
  1787. DebugPrint(TEXT("DoInstall failed with error: 0x%08x"),hResult);
  1788. }
  1789. }
  1790. VOID
  1791. WINAPI
  1792. DoInstallA(
  1793. IN HWND Window,
  1794. IN HINSTANCE ModuleHandle,
  1795. IN PCSTR CommandLine,
  1796. IN INT ShowCommand
  1797. )
  1798. {
  1799. TCHAR OutLine[MAX_PATH*2];
  1800. INT sz;
  1801. sz = MultiByteToWideChar(CP_ACP,0,CommandLine,-1,OutLine,ARRAY_SIZE(OutLine));
  1802. if(!sz) {
  1803. DebugPrint(TEXT("DoInstallA was passed too big a command line"));
  1804. return;
  1805. }
  1806. DoInstall(Window,ModuleHandle,OutLine,ShowCommand);
  1807. }