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.

1646 lines
43 KiB

  1. /*++
  2. Copyright (c) Microsoft Corporation. All rights reserved.
  3. Module Name:
  4. mru.c
  5. Abstract:
  6. Implementation of source list handling routines.
  7. Author:
  8. Ted Miller (tedm) 30-Aug-1995
  9. Revision History:
  10. --*/
  11. #include "precomp.h"
  12. #pragma hdrstop
  13. #define MAX_SOURCELIST_SIZE 0x10000
  14. //
  15. // Location in registry where per-system MRU list is stored
  16. // (relative to HKEY_LOCAL_MACHINE).
  17. //
  18. PCTSTR pszPerSystemKey = TEXT("SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Setup");
  19. PCTSTR pszPerSystemVal = TEXT("Installation Sources");
  20. //
  21. // Location in registry where per-user MRU list is stored.
  22. // (relative to HKEY_CURRENT_USER).
  23. //
  24. PCTSTR pszPerUserKey = TEXT("SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Setup");
  25. PCTSTR pszPerUserVal = TEXT("Installation Sources");
  26. typedef PTSTR *APTSTR;
  27. //
  28. // Platform strings we recognize.
  29. //
  30. PCTSTR PlatformPathComponents[] = { TEXT("\\i386"),
  31. TEXT("\\x86"),
  32. TEXT("\\amd64"),
  33. TEXT("\\ia64"),
  34. NULL
  35. };
  36. //
  37. // These are guarded by MruCritSect.
  38. //
  39. PTSTR *TemporarySourceList;
  40. UINT TemporarySourceCount;
  41. BOOL MruNoBrowse;
  42. VOID
  43. pSetupStripTrailingPlatformComponent(
  44. IN OUT PTSTR *Paths,
  45. IN OUT PDWORD NumPaths
  46. );
  47. BOOL LockMruCritSect()
  48. {
  49. BOOL locked = FALSE;
  50. try {
  51. EnterCriticalSection(&MruCritSect);
  52. locked = TRUE;
  53. } except (EXCEPTION_EXECUTE_HANDLER) {
  54. }
  55. if(!locked) {
  56. SetLastError(ERROR_NOT_ENOUGH_MEMORY);
  57. }
  58. return locked;
  59. }
  60. BOOL
  61. _SetupSetSourceList(
  62. IN DWORD Flags,
  63. IN PCTSTR *SourceList,
  64. IN UINT SourceCount
  65. )
  66. /*++
  67. Routine Description:
  68. This routine allows the caller to set the list of installation
  69. sources for either the current user or the system (common to
  70. all users).
  71. Arguments:
  72. Flags - a combination of the following values:
  73. SRCLIST_SYSTEM - specify that the list is to become the
  74. per-system list. The caller must be administrator.
  75. SRCLIST_USER - specify that the list is to become the per-user
  76. list.
  77. SRCLIST_TEMPORARY - specify that the list is to become the
  78. entire list for the duration of the current process,
  79. or until this routine is called again to change the behavior.
  80. Exactly one of SRCLIST_SYSTEM, SRCLIST_USER, and SRCLIST_TEMPORARY
  81. must be specified.
  82. SRCLIST_NOBROWSE - specify that the user is not allowed to add
  83. or change sources when the SetupPromptForDisk API is used.
  84. Typically used in combination with SRCLIST_TEMPORARY.
  85. SourceList - supplies array of strings that are to become the
  86. source list, as described by the Flags parameter.
  87. SourceCount - specifies number of elements in the SourceList array.
  88. Return Value:
  89. --*/
  90. {
  91. DWORD flags;
  92. DWORD d;
  93. UINT u,v;
  94. //
  95. // Check flags. Only one of system, user, or temporary may be set.
  96. //
  97. flags = Flags & (SRCLIST_SYSTEM | SRCLIST_USER | SRCLIST_TEMPORARY);
  98. if((flags != SRCLIST_SYSTEM) && (flags != SRCLIST_USER) && (flags != SRCLIST_TEMPORARY)) {
  99. SetLastError(ERROR_INVALID_PARAMETER);
  100. return(FALSE);
  101. }
  102. if(SourceCount >= MAX_SOURCELIST_SIZE) {
  103. SetLastError(ERROR_INVALID_PARAMETER);
  104. return(FALSE);
  105. }
  106. //
  107. // User must be admin for system flag to work.
  108. //
  109. if((flags == SRCLIST_SYSTEM) && !pSetupIsUserAdmin()) {
  110. SetLastError(ERROR_ACCESS_DENIED);
  111. return(FALSE);
  112. }
  113. //
  114. // Only allow one thread at a time in this process to access
  115. // the temporary source list.
  116. //
  117. if(!LockMruCritSect()) {
  118. return FALSE;
  119. }
  120. if(Flags & SRCLIST_NOBROWSE) {
  121. MruNoBrowse = TRUE;
  122. }
  123. d = NO_ERROR;
  124. if(flags == SRCLIST_TEMPORARY) {
  125. if(TemporarySourceList) {
  126. SetupFreeSourceList(&TemporarySourceList,TemporarySourceCount);
  127. }
  128. //
  129. // Duplicate the list the caller passed in.
  130. //
  131. if(TemporarySourceList = MyMalloc(SourceCount * sizeof(PTSTR))) {
  132. TemporarySourceCount = SourceCount;
  133. for(u=0; u<SourceCount; u++) {
  134. TemporarySourceList[u] = DuplicateString(SourceList[u]);
  135. if(!TemporarySourceList[u]) {
  136. for(v=0; v<u; v++) {
  137. MyFree(TemporarySourceList[v]);
  138. }
  139. MyFree(TemporarySourceList);
  140. TemporarySourceList = NULL;
  141. TemporarySourceCount = 0;
  142. d = ERROR_NOT_ENOUGH_MEMORY;
  143. break;
  144. }
  145. }
  146. } else {
  147. d = ERROR_NOT_ENOUGH_MEMORY;
  148. }
  149. } else {
  150. //
  151. // User or system.
  152. //
  153. d = pSetupSetArrayToMultiSzValue(
  154. (flags == SRCLIST_SYSTEM) ? HKEY_LOCAL_MACHINE : HKEY_CURRENT_USER,
  155. (flags == SRCLIST_SYSTEM) ? pszPerSystemKey : pszPerUserKey,
  156. (flags == SRCLIST_SYSTEM) ? pszPerSystemVal : pszPerUserVal,
  157. (PTSTR *)SourceList,
  158. SourceCount
  159. );
  160. }
  161. //
  162. // Done with protected resource
  163. //
  164. LeaveCriticalSection(&MruCritSect);
  165. SetLastError(d);
  166. return(d == NO_ERROR);
  167. }
  168. //
  169. // ANSI version
  170. //
  171. BOOL
  172. SetupSetSourceListA(
  173. IN DWORD Flags,
  174. IN PCSTR *SourceList,
  175. IN UINT SourceCount
  176. )
  177. {
  178. PCWSTR *sourceList;
  179. UINT u;
  180. DWORD rc;
  181. BOOL b;
  182. if(SourceCount >= MAX_SOURCELIST_SIZE) {
  183. SetLastError(ERROR_INVALID_PARAMETER);
  184. return(FALSE);
  185. }
  186. sourceList = MyMalloc(SourceCount*sizeof(PCWSTR));
  187. if(!sourceList) {
  188. SetLastError(ERROR_NOT_ENOUGH_MEMORY);
  189. return(FALSE);
  190. }
  191. ZeroMemory((PVOID)sourceList,SourceCount*sizeof(PCWSTR));
  192. rc = NO_ERROR;
  193. for(u=0; (rc==NO_ERROR) && (u<SourceCount); u++) {
  194. //
  195. // Try/except guards access to SourceList[u] in case
  196. // SourceList is a bad pointer
  197. //
  198. try {
  199. rc = pSetupCaptureAndConvertAnsiArg(SourceList[u],&sourceList[u]);
  200. } except(EXCEPTION_EXECUTE_HANDLER) {
  201. rc = ERROR_INVALID_PARAMETER;
  202. }
  203. }
  204. if(rc == NO_ERROR) {
  205. b = _SetupSetSourceList(Flags,sourceList,SourceCount);
  206. rc = GetLastError();
  207. } else {
  208. b = FALSE;
  209. }
  210. for(u=0; u<SourceCount; u++) {
  211. if(sourceList[u]) {
  212. MyFree(sourceList[u]);
  213. }
  214. }
  215. MyFree(sourceList);
  216. SetLastError(rc);
  217. return(b);
  218. }
  219. BOOL
  220. SetupSetSourceList(
  221. IN DWORD Flags,
  222. IN PCTSTR *SourceList,
  223. IN UINT SourceCount
  224. )
  225. {
  226. PCTSTR *sourceList;
  227. UINT u;
  228. DWORD rc;
  229. BOOL b;
  230. sourceList = MyMalloc(SourceCount*sizeof(PCTSTR));
  231. if(!sourceList) {
  232. SetLastError(ERROR_NOT_ENOUGH_MEMORY);
  233. return(FALSE);
  234. }
  235. ZeroMemory((PVOID)sourceList,SourceCount*sizeof(PCTSTR));
  236. rc = NO_ERROR;
  237. for(u=0; (rc==NO_ERROR) && (u<SourceCount); u++) {
  238. //
  239. // Try/except guards access to SourceList[u] in case
  240. // SourceList is a bad pointer
  241. //
  242. try {
  243. rc = CaptureStringArg(SourceList[u],&sourceList[u]);
  244. } except(EXCEPTION_EXECUTE_HANDLER) {
  245. rc = ERROR_INVALID_PARAMETER;
  246. }
  247. }
  248. if(rc == NO_ERROR) {
  249. b = _SetupSetSourceList(Flags,sourceList,SourceCount);
  250. rc = GetLastError();
  251. } else {
  252. b = FALSE;
  253. }
  254. for(u=0; u<SourceCount; u++) {
  255. if(sourceList[u]) {
  256. MyFree(sourceList[u]);
  257. }
  258. }
  259. MyFree(sourceList);
  260. SetLastError(rc);
  261. return(b);
  262. }
  263. BOOL
  264. SetupCancelTemporarySourceList(
  265. VOID
  266. )
  267. /*++
  268. Routine Description:
  269. This routine cancels any temporary list and no-browse behavior
  270. and reverts to standard list behavior.
  271. Arguments:
  272. None.
  273. Return Value:
  274. TRUE if a temporary list was in effect; FALSE if otherwise.
  275. --*/
  276. {
  277. BOOL b;
  278. if(!LockMruCritSect()) {
  279. return FALSE;
  280. }
  281. MruNoBrowse = FALSE;
  282. if(TemporarySourceList) {
  283. //
  284. // SetupFreeSourceList zeros out the pointer for us.
  285. //
  286. SetupFreeSourceList(&TemporarySourceList,TemporarySourceCount);
  287. TemporarySourceCount = 0;
  288. b = TRUE;
  289. } else {
  290. b = FALSE;
  291. }
  292. LeaveCriticalSection(&MruCritSect);
  293. return(b);
  294. }
  295. BOOL
  296. _SetupAddToSourceList(
  297. IN DWORD Flags,
  298. IN PCTSTR Source
  299. )
  300. /*++
  301. Routine Description:
  302. This routine allows the caller to append a value to the list
  303. of installation sources for either the current user or the system.
  304. If the value already exists it is removed first.
  305. Arguments:
  306. Flags - a combination of the following values:
  307. SRCLIST_SYSTEM - specify that the source is to added to the
  308. per-system list. The caller must be administrator.
  309. SRCLIST_USER - specify that the list is to be added to the per-user
  310. list.
  311. SRCLIST_SYSIFADMIN - specifies that if the caller is administrator,
  312. then the source is added to the system list; if the caller
  313. is not administrator then the source is added to the per-user
  314. list for the current user.
  315. If a temporary list is currently in use (see SetupSetSourceList),
  316. these 3 flags are ignored and the source is added to the temporary list.
  317. SRCLIST_APPEND - specify that the source is to be added to the end
  318. of the given list. Otherwise it is added to the beginning.
  319. Source - specifies the source to be added to the list.
  320. Return Value:
  321. --*/
  322. {
  323. APTSTR Lists[2];
  324. UINT Counts[2];
  325. UINT NumberOfLists;
  326. DWORD d;
  327. UINT u;
  328. PTSTR p;
  329. PVOID pTmp;
  330. HKEY RootKeys[2];
  331. PCTSTR SubKeys[2];
  332. PCTSTR Vals[2];
  333. BOOL NeedToFree[2];
  334. if(!LockMruCritSect()) {
  335. return FALSE;
  336. }
  337. //
  338. // Remove first, if present. This makes things easier for us later.
  339. // Do this inside the locks to ensure atomicity for the add call as
  340. // a whole.
  341. //
  342. if(!SetupRemoveFromSourceList(Flags,Source)) {
  343. d = GetLastError();
  344. LeaveCriticalSection(&MruCritSect);
  345. SetLastError(d);
  346. return(FALSE);
  347. }
  348. //
  349. // Check Temporary list first.
  350. //
  351. d = NO_ERROR;
  352. if(TemporarySourceList) {
  353. Lists[0] = TemporarySourceList;
  354. Counts[0] = TemporarySourceCount;
  355. NumberOfLists = 1;
  356. NeedToFree[0] = FALSE;
  357. } else {
  358. //
  359. // Check sysifadmin flag and turn on appropriate flag.
  360. //
  361. if(Flags & SRCLIST_SYSIFADMIN) {
  362. Flags |= pSetupIsUserAdmin() ? SRCLIST_SYSTEM : SRCLIST_USER;
  363. }
  364. NumberOfLists = 0;
  365. if(Flags & SRCLIST_SYSTEM) {
  366. if(pSetupIsUserAdmin()) {
  367. d = pSetupQueryMultiSzValueToArray(
  368. HKEY_LOCAL_MACHINE,
  369. pszPerSystemKey,
  370. pszPerSystemVal,
  371. &Lists[0],
  372. &Counts[0],
  373. FALSE
  374. );
  375. if(d == NO_ERROR) {
  376. NumberOfLists = 1;
  377. RootKeys[0] = HKEY_LOCAL_MACHINE;
  378. SubKeys[0] = pszPerSystemKey;
  379. Vals[0] = pszPerSystemVal;
  380. NeedToFree[0] = TRUE;
  381. } else {
  382. Lists[0] = NULL;
  383. }
  384. } else {
  385. d = ERROR_ACCESS_DENIED;
  386. }
  387. }
  388. if((Flags & SRCLIST_USER) && (d == NO_ERROR)) {
  389. d = pSetupQueryMultiSzValueToArray(
  390. HKEY_CURRENT_USER,
  391. pszPerSystemKey,
  392. pszPerSystemVal,
  393. &Lists[NumberOfLists],
  394. &Counts[NumberOfLists],
  395. FALSE
  396. );
  397. if(d == NO_ERROR) {
  398. RootKeys[NumberOfLists] = HKEY_CURRENT_USER;
  399. SubKeys[NumberOfLists] = pszPerUserKey;
  400. Vals[NumberOfLists] = pszPerUserVal;
  401. NeedToFree[NumberOfLists] = TRUE;
  402. NumberOfLists++;
  403. } else {
  404. Lists[NumberOfLists] = NULL;
  405. }
  406. }
  407. }
  408. if(d == NO_ERROR) {
  409. //
  410. // Do each list.
  411. //
  412. for(u=0; (d==NO_ERROR) && (u<NumberOfLists); u++) {
  413. if(p = DuplicateString(Source)) {
  414. if(pTmp = MyRealloc(Lists[u],(Counts[u]+1)*sizeof(PTSTR))) {
  415. Lists[u] = pTmp;
  416. if(Flags & SRCLIST_APPEND) {
  417. Lists[u][Counts[u]] = p;
  418. } else {
  419. MoveMemory(&Lists[u][1],Lists[u],Counts[u] * sizeof(PTSTR));
  420. Lists[u][0] = p;
  421. }
  422. Counts[u]++;
  423. //
  424. // Put back in registry if necessary.
  425. //
  426. if(TemporarySourceList) {
  427. TemporarySourceList = Lists[u];
  428. TemporarySourceCount = Counts[0];
  429. } else {
  430. d = pSetupSetArrayToMultiSzValue(
  431. RootKeys[u],
  432. SubKeys[u],
  433. Vals[u],
  434. Lists[u],
  435. Counts[u]
  436. );
  437. if(NeedToFree[u]) {
  438. SetupFreeSourceList(&Lists[u],Counts[u]);
  439. }
  440. }
  441. } else {
  442. d = ERROR_NOT_ENOUGH_MEMORY;
  443. }
  444. } else {
  445. d = ERROR_NOT_ENOUGH_MEMORY;
  446. }
  447. }
  448. }
  449. //
  450. // Done looking at temporary list.
  451. //
  452. //
  453. LeaveCriticalSection(&MruCritSect);
  454. SetLastError(d);
  455. return(d == NO_ERROR);
  456. }
  457. //
  458. // ANSI version
  459. //
  460. BOOL
  461. SetupAddToSourceListA(
  462. IN DWORD Flags,
  463. IN PCSTR Source
  464. )
  465. {
  466. BOOL b;
  467. DWORD rc;
  468. PCWSTR source;
  469. rc = pSetupCaptureAndConvertAnsiArg(Source,&source);
  470. if(rc == NO_ERROR) {
  471. b = _SetupAddToSourceList(Flags,source);
  472. rc = GetLastError();
  473. MyFree(source);
  474. } else {
  475. b = FALSE;
  476. }
  477. SetLastError(rc);
  478. return(b);
  479. }
  480. BOOL
  481. SetupAddToSourceList(
  482. IN DWORD Flags,
  483. IN PCTSTR Source
  484. )
  485. {
  486. BOOL b;
  487. DWORD rc;
  488. PCTSTR source;
  489. rc = CaptureStringArg(Source,&source);
  490. if(rc == NO_ERROR) {
  491. b = _SetupAddToSourceList(Flags,source);
  492. rc = GetLastError();
  493. MyFree(source);
  494. } else {
  495. b = FALSE;
  496. }
  497. SetLastError(rc);
  498. return(b);
  499. }
  500. BOOL
  501. _SetupRemoveFromSourceList(
  502. IN DWORD Flags,
  503. IN PCTSTR Source
  504. )
  505. /*++
  506. Routine Description:
  507. This routine allows the caller to remove a value from the list
  508. of installation sources for either the current user or the system.
  509. The system and user lists are merged at run time.
  510. Arguments:
  511. Flags - a combination of the following values:
  512. SRCLIST_SYSTEM - specify that the source is to removed from the
  513. per-system list. The caller must be administrator.
  514. SRCLIST_USER - specify that the list is to be removed from the
  515. per-user list.
  516. SRCLIST_SYSIFADMIN - specifies that if the caller is administrator,
  517. then the source is removed from the system list; if the caller
  518. is not administrator then the source is removed from the per-user
  519. list for the current user.
  520. Any combination of these flags may be specified on a single call.
  521. If a temporary list is currently in use (see SetupSetSourceList),
  522. these 3 flags are ignored and the source is removed from the temporary list.
  523. SRCLIST_SUBDIRS - specify that all subdirectories of Source are also
  524. to be removed. The determination of subdirectories is done based on
  525. a simple prefix scan.
  526. Source - specifies the source to be removed from the list.
  527. Return Value:
  528. --*/
  529. {
  530. APTSTR Lists[2];
  531. UINT Counts[2];
  532. UINT NumberOfLists;
  533. DWORD d;
  534. BOOL NeedToFree;
  535. UINT u,v;
  536. PTSTR p;
  537. BOOL Match;
  538. UINT Len;
  539. PVOID pTmp;
  540. p = DuplicateString(Source);
  541. if(!p) {
  542. SetLastError(ERROR_NOT_ENOUGH_MEMORY);
  543. return(FALSE);
  544. }
  545. CharUpper(p);
  546. Len = lstrlen(p);
  547. if(!LockMruCritSect()) {
  548. MyFree(p);
  549. return FALSE;
  550. }
  551. //
  552. // Check Temporary list first.
  553. //
  554. d = NO_ERROR;
  555. if(TemporarySourceList) {
  556. Lists[0] = TemporarySourceList;
  557. Counts[0] = TemporarySourceCount;
  558. NumberOfLists = 1;
  559. NeedToFree = FALSE;
  560. } else {
  561. //
  562. // Check sysifadmin flag and turn on appropriate flag.
  563. //
  564. if(Flags & SRCLIST_SYSIFADMIN) {
  565. Flags |= pSetupIsUserAdmin() ? SRCLIST_SYSTEM : SRCLIST_USER;
  566. }
  567. NeedToFree = TRUE;
  568. NumberOfLists = 0;
  569. if(Flags & SRCLIST_SYSTEM) {
  570. if(pSetupIsUserAdmin()) {
  571. d = pSetupQueryMultiSzValueToArray(
  572. HKEY_LOCAL_MACHINE,
  573. pszPerSystemKey,
  574. pszPerSystemVal,
  575. &Lists[0],
  576. &Counts[0],
  577. FALSE
  578. );
  579. if(d == NO_ERROR) {
  580. NumberOfLists = 1;
  581. } else {
  582. Lists[0] = NULL;
  583. }
  584. } else {
  585. d = ERROR_ACCESS_DENIED;
  586. }
  587. }
  588. if((Flags & SRCLIST_USER) && (d == NO_ERROR)) {
  589. d = pSetupQueryMultiSzValueToArray(
  590. HKEY_CURRENT_USER,
  591. pszPerSystemKey,
  592. pszPerSystemVal,
  593. &Lists[NumberOfLists],
  594. &Counts[NumberOfLists],
  595. FALSE
  596. );
  597. if(d == NO_ERROR) {
  598. NumberOfLists++;
  599. } else {
  600. Lists[NumberOfLists] = NULL;
  601. }
  602. }
  603. }
  604. if(d == NO_ERROR) {
  605. //
  606. // Go through each list.
  607. //
  608. for(u=0; u<NumberOfLists; u++) {
  609. //
  610. // Go though each item in the current list.
  611. //
  612. for(v=0; v<Counts[u]; v++) {
  613. CharUpper(Lists[u][v]);
  614. //
  615. // See if this item matches the one being deleted.
  616. //
  617. Match = FALSE;
  618. if(Flags & SRCLIST_SUBDIRS) {
  619. //
  620. // See if the source the caller passed in is
  621. // a prefix of the source in the list.
  622. //
  623. Match = (_tcsncmp(Lists[u][v],p,Len) == 0);
  624. } else {
  625. Match = (lstrcmp(Lists[u][v],p) == 0);
  626. }
  627. if(Match) {
  628. //
  629. // Need to remove this item.
  630. //
  631. MyFree(Lists[u][v]);
  632. MoveMemory(
  633. &Lists[u][v],
  634. &Lists[u][v+1],
  635. (Counts[u] - (v+1)) * sizeof(PTSTR)
  636. );
  637. Counts[u]--;
  638. v--;
  639. }
  640. }
  641. }
  642. if(TemporarySourceList) {
  643. //
  644. // Shrink temporary source list down to new size.
  645. // Since we're shrinking we don't expect the realloc to fail
  646. // but it's not an error if it does.
  647. //
  648. if(pTmp = MyRealloc(Lists[0],Counts[0]*sizeof(PTSTR))) {
  649. TemporarySourceList = pTmp;
  650. }
  651. TemporarySourceCount = Counts[0];
  652. } else {
  653. //
  654. // Need to put stuff back in registry.
  655. //
  656. u=0;
  657. if(Flags & SRCLIST_SYSTEM) {
  658. d = pSetupSetArrayToMultiSzValue(
  659. HKEY_LOCAL_MACHINE,
  660. pszPerSystemKey,
  661. pszPerSystemVal,
  662. Lists[0],
  663. Counts[0]
  664. );
  665. u++;
  666. }
  667. if((d == NO_ERROR) && (Flags & SRCLIST_USER)) {
  668. d = pSetupSetArrayToMultiSzValue(
  669. HKEY_CURRENT_USER,
  670. pszPerUserKey,
  671. pszPerUserVal,
  672. Lists[u],
  673. Counts[u]
  674. );
  675. u++;
  676. }
  677. }
  678. }
  679. //
  680. // Done looking at temporary list.
  681. //
  682. //
  683. LeaveCriticalSection(&MruCritSect);
  684. if(NeedToFree) {
  685. for(u=0; u<NumberOfLists; u++) {
  686. if(Lists[u]) {
  687. SetupFreeSourceList(&Lists[u],Counts[u]);
  688. }
  689. }
  690. }
  691. MyFree(p);
  692. SetLastError(d);
  693. return(d == NO_ERROR);
  694. }
  695. //
  696. // ANSI version
  697. //
  698. BOOL
  699. SetupRemoveFromSourceListA(
  700. IN DWORD Flags,
  701. IN PCSTR Source
  702. )
  703. {
  704. PCWSTR source;
  705. BOOL b;
  706. DWORD rc;
  707. rc = pSetupCaptureAndConvertAnsiArg(Source,&source);
  708. if(rc == NO_ERROR) {
  709. b = _SetupRemoveFromSourceList(Flags,source);
  710. rc = GetLastError();
  711. MyFree(source);
  712. } else {
  713. b = FALSE;
  714. }
  715. SetLastError(rc);
  716. return(b);
  717. }
  718. BOOL
  719. SetupRemoveFromSourceList(
  720. IN DWORD Flags,
  721. IN PCTSTR Source
  722. )
  723. {
  724. PCTSTR source;
  725. BOOL b;
  726. DWORD rc;
  727. rc = CaptureStringArg(Source,&source);
  728. if(rc == NO_ERROR) {
  729. b = _SetupRemoveFromSourceList(Flags,source);
  730. rc = GetLastError();
  731. MyFree(source);
  732. } else {
  733. b = FALSE;
  734. }
  735. SetLastError(rc);
  736. return(b);
  737. }
  738. //
  739. // ANSI version
  740. //
  741. BOOL
  742. SetupQuerySourceListA(
  743. IN DWORD Flags,
  744. OUT PCSTR **List,
  745. OUT PUINT Count
  746. )
  747. {
  748. PCWSTR *list;
  749. UINT count;
  750. BOOL b;
  751. DWORD d;
  752. PSTR *ansilist;
  753. UINT i;
  754. b = SetupQuerySourceListW(Flags,&list,&count);
  755. d = GetLastError();
  756. if(b) {
  757. if(ansilist = MyMalloc(count * sizeof(PCSTR))) {
  758. ZeroMemory(ansilist,count*sizeof(PCSTR));
  759. for(i=0; i<count; i++) {
  760. ansilist[i] = pSetupUnicodeToAnsi(list[i]);
  761. if(!ansilist[i]) {
  762. SetupFreeSourceListA(&ansilist,count);
  763. d = ERROR_NOT_ENOUGH_MEMORY;
  764. b = FALSE;
  765. break;
  766. }
  767. }
  768. if(b) {
  769. //
  770. // Everything's ok, set up caller's out params.
  771. //
  772. try {
  773. *Count = count;
  774. *List = ansilist;
  775. } except(EXCEPTION_EXECUTE_HANDLER) {
  776. SetupFreeSourceListA(&ansilist,count);
  777. d = ERROR_INVALID_PARAMETER;
  778. b = FALSE;
  779. }
  780. }
  781. } else {
  782. d = ERROR_NOT_ENOUGH_MEMORY;
  783. b = FALSE;
  784. }
  785. SetupFreeSourceListW(&list,count);
  786. }
  787. SetLastError(d);
  788. return(b);
  789. }
  790. BOOL
  791. SetupQuerySourceList(
  792. IN DWORD Flags,
  793. OUT PCTSTR **List,
  794. OUT PUINT Count
  795. )
  796. /*++
  797. Routine Description:
  798. This routine allows the caller to query the current list of installation
  799. sources. The list is built from the system and user-specific lists,
  800. potentially overridden by a temporary list (see SetupSetSourceList).
  801. Arguments:
  802. Flags - a combination of the following values:
  803. SRCLIST_SYSTEM - specify that only the system list is desired.
  804. SRCLIST_USER - specify that only the per-user list is desired.
  805. SRCLIST_SYSIFADMIN - Same as SRCLIST_SYSTEM. Accepted only for
  806. compatibility.
  807. If none of these flags is specified then the current (merged) list is
  808. returned in its entirety.
  809. SRCLIST_NOSTRIPPLATFORM - Normally, all paths are stripped of a platform-
  810. specific component if that component is the final one. IE, a path
  811. stored in the registry as f:\mips will come back as f:\. If this flag
  812. is specified, this behavior is turned off.
  813. List - receives a pointer to an array of sources. The caller must free this
  814. with SetupFreeSourceList.
  815. Count - receives the number of sources.
  816. Return Value:
  817. --*/
  818. {
  819. DWORD d;
  820. PTSTR *Values1 = NULL;
  821. UINT NumVals1 = 0;
  822. PTSTR *Values2 = NULL;
  823. UINT NumVals2 = 0;
  824. UINT TotalVals;
  825. UINT u,v;
  826. BOOL Found;
  827. PTSTR *p;
  828. BOOL StripPlatform;
  829. //
  830. // Either caller wants sysifadmin, or he wants some combination of
  831. // system and user lists.
  832. //
  833. if((Flags & SRCLIST_SYSIFADMIN) && (Flags & (SRCLIST_SYSTEM | SRCLIST_USER))) {
  834. SetLastError(ERROR_INVALID_PARAMETER);
  835. return(FALSE);
  836. }
  837. if(!LockMruCritSect()) {
  838. return FALSE;
  839. }
  840. //
  841. // If sysifadmin, figure out which list to get.
  842. //
  843. if(Flags & SRCLIST_SYSIFADMIN) {
  844. //
  845. // Changed behavior to basically ignore this flag,
  846. // since setup doesn't record the system source in the per-user
  847. // mru list any more since this gets messy for upgrades.
  848. //
  849. //Flags = pSetupIsUserAdmin() ? SRCLIST_SYSTEM : SRCLIST_USER;
  850. Flags = SRCLIST_SYSTEM;
  851. } else {
  852. //
  853. // if no flags are specified, turn on system and user unless
  854. // there's a temporary list.
  855. //
  856. if(!Flags && !TemporarySourceList) {
  857. Flags = SRCLIST_SYSTEM | SRCLIST_USER;
  858. }
  859. }
  860. StripPlatform = ((Flags & SRCLIST_NOSTRIPPLATFORM) == 0);
  861. if(!Flags) {
  862. //
  863. // Temporary list in use.
  864. //
  865. d = NO_ERROR;
  866. if(Values1 = MyMalloc(TemporarySourceCount * sizeof(PTSTR))) {
  867. for(u=0; u<TemporarySourceCount; u++) {
  868. Values1[u] = DuplicateString(TemporarySourceList[u]);
  869. if(!Values1[u]) {
  870. d = ERROR_NOT_ENOUGH_MEMORY;
  871. for(v=0; v<u; v++) {
  872. MyFree(Values1[v]);
  873. }
  874. MyFree(Values1);
  875. break;
  876. }
  877. }
  878. if(d == NO_ERROR) {
  879. try {
  880. *List = Values1;
  881. *Count = TemporarySourceCount;
  882. } except(EXCEPTION_EXECUTE_HANDLER) {
  883. d = ERROR_INVALID_PARAMETER;
  884. }
  885. }
  886. } else {
  887. d = ERROR_NOT_ENOUGH_MEMORY;
  888. }
  889. } else {
  890. //
  891. // Fetch system list if desired.
  892. //
  893. if(Flags & SRCLIST_SYSTEM) {
  894. d = pSetupQueryMultiSzValueToArray(
  895. HKEY_LOCAL_MACHINE,
  896. pszPerSystemKey,
  897. pszPerSystemVal,
  898. &Values1,
  899. &NumVals1,
  900. FALSE
  901. );
  902. //
  903. // If we are supposed to, strip out platform-specific
  904. // trailing components.
  905. //
  906. if((d == NO_ERROR) && StripPlatform) {
  907. pSetupStripTrailingPlatformComponent(Values1,&NumVals1);
  908. } else if (d != NO_ERROR) {
  909. //
  910. // Create dummy array.
  911. //
  912. NumVals1 = 0;
  913. if(Values1 = MyMalloc(0)) {
  914. d = NO_ERROR;
  915. } else {
  916. d = ERROR_NOT_ENOUGH_MEMORY;
  917. }
  918. }
  919. } else {
  920. //
  921. // Create dummy array.
  922. //
  923. NumVals1 = 0;
  924. if(Values1 = MyMalloc(0)) {
  925. d = NO_ERROR;
  926. } else {
  927. d = ERROR_NOT_ENOUGH_MEMORY;
  928. }
  929. }
  930. //
  931. // Fetch user list if desired.
  932. //
  933. if((d == NO_ERROR) && (Flags & SRCLIST_USER)) {
  934. d = pSetupQueryMultiSzValueToArray(
  935. HKEY_CURRENT_USER,
  936. pszPerUserKey,
  937. pszPerUserVal,
  938. &Values2,
  939. &NumVals2,
  940. FALSE
  941. );
  942. if((d == NO_ERROR) && StripPlatform) {
  943. pSetupStripTrailingPlatformComponent(Values2,&NumVals2);
  944. }
  945. } else if(Values1) {
  946. //
  947. // Create dummy array.
  948. //
  949. NumVals2 = 0;
  950. if(Values2 = MyMalloc(0)) {
  951. d = NO_ERROR;
  952. } else {
  953. d = ERROR_NOT_ENOUGH_MEMORY;
  954. }
  955. } else {
  956. NumVals2 = 0;
  957. Values2 = NULL;
  958. d = ERROR_NOT_ENOUGH_MEMORY;
  959. }
  960. TotalVals = NumVals1;
  961. if(d == NO_ERROR) {
  962. //
  963. // Merge lists. Favor the system list.
  964. // We iterate through the user list. For each item in the user list,
  965. // we look for it in the system list. If not found, we append to the system list.
  966. // The system list becomes the final list.
  967. //
  968. for(u=0; (d == NO_ERROR) && (u<NumVals2); u++) {
  969. //
  970. // Look for the current per-user path in the per-system
  971. // list. If not found, append to end of system list.
  972. //
  973. Found = FALSE;
  974. for(v=0; v<NumVals1; v++) {
  975. if(!lstrcmpi(Values1[v],Values2[u])) {
  976. Found = TRUE;
  977. break;
  978. }
  979. }
  980. if(!Found) {
  981. if(p = MyRealloc(Values1,(TotalVals+1)*sizeof(PTSTR))) {
  982. Values1 = p;
  983. if(Values1[TotalVals] = DuplicateString(Values2[u])) {
  984. TotalVals++;
  985. } else {
  986. d = ERROR_NOT_ENOUGH_MEMORY;
  987. }
  988. } else {
  989. d = ERROR_NOT_ENOUGH_MEMORY;
  990. }
  991. }
  992. }
  993. if(d == NO_ERROR) {
  994. //
  995. // Ensure that there's at least one item in the list.
  996. //
  997. if(TotalVals) {
  998. try {
  999. *List = Values1;
  1000. *Count = TotalVals;
  1001. Values1 = NULL; // no longer ours to free
  1002. } except(EXCEPTION_EXECUTE_HANDLER) {
  1003. d = ERROR_INVALID_PARAMETER;
  1004. }
  1005. } else {
  1006. try {
  1007. if(*List = MyMalloc(sizeof(PTSTR))) {
  1008. if(**List = DuplicateString(TEXT("A:\\"))) {
  1009. *Count = 1;
  1010. } else {
  1011. MyFree(*List);
  1012. d = ERROR_NOT_ENOUGH_MEMORY;
  1013. }
  1014. } else {
  1015. d = ERROR_NOT_ENOUGH_MEMORY;
  1016. }
  1017. } except(EXCEPTION_EXECUTE_HANDLER) {
  1018. //
  1019. // Note there is a tiny window for a memory leak here,
  1020. // if List pointer went bad between the MyMalloc
  1021. // and the DuplicateString. Oh well.
  1022. //
  1023. d = ERROR_INVALID_PARAMETER;
  1024. }
  1025. }
  1026. }
  1027. }
  1028. if (Values1) {
  1029. for(u=0; u<TotalVals; u++) {
  1030. if(Values1[u]) {
  1031. MyFree(Values1[u]);
  1032. }
  1033. }
  1034. MyFree(Values1);
  1035. }
  1036. if (Values2) {
  1037. for(u=0; u<NumVals2; u++) {
  1038. MyFree(Values2[u]);
  1039. }
  1040. MyFree(Values2);
  1041. }
  1042. }
  1043. LeaveCriticalSection(&MruCritSect);
  1044. SetLastError(d);
  1045. return(d == NO_ERROR);
  1046. }
  1047. BOOL
  1048. SetupFreeSourceListA(
  1049. IN OUT PCSTR **List,
  1050. IN UINT Count
  1051. )
  1052. {
  1053. //
  1054. // Not really ansi/unicode specific
  1055. //
  1056. return(SetupFreeSourceListW((PCWSTR **)List,Count));
  1057. }
  1058. BOOL
  1059. SetupFreeSourceListW(
  1060. IN OUT PCWSTR **List,
  1061. IN UINT Count
  1062. )
  1063. /*++
  1064. Routine Description:
  1065. This routine frees a source list as returned by SetupQuerySourceList.
  1066. Arguments:
  1067. Return Value:
  1068. --*/
  1069. {
  1070. UINT u;
  1071. BOOL b;
  1072. PCWSTR *list;
  1073. b = TRUE;
  1074. try {
  1075. list = *List;
  1076. for(u=0; u<Count; u++) {
  1077. if(list[u]) {
  1078. MyFree(list[u]);
  1079. }
  1080. }
  1081. MyFree(list);
  1082. *List = NULL;
  1083. } except(EXCEPTION_EXECUTE_HANDLER) {
  1084. b = FALSE;
  1085. }
  1086. return(b);
  1087. }
  1088. DWORD
  1089. pSetupGetList(
  1090. IN DWORD Flags,
  1091. OUT PCTSTR **List,
  1092. OUT PUINT Count,
  1093. OUT PBOOL NoBrowse
  1094. )
  1095. {
  1096. DWORD d;
  1097. if(!LockMruCritSect()) {
  1098. return ERROR_NOT_ENOUGH_MEMORY;
  1099. }
  1100. *NoBrowse = MruNoBrowse;
  1101. d = SetupQuerySourceList(Flags,List,Count) ? NO_ERROR : GetLastError();
  1102. LeaveCriticalSection(&MruCritSect);
  1103. return(d);
  1104. }
  1105. PTSTR
  1106. pSetupGetDefaultSourcePath(
  1107. IN HINF InfHandle,
  1108. IN DWORD Flags,
  1109. OUT PDWORD InfSourceMediaType
  1110. )
  1111. /*++
  1112. Routine Description:
  1113. This routine returns the default path string to be used for the
  1114. specified INF. It also returns the type of path, either a normal
  1115. file path or a URL.
  1116. The caller must free the string returned (if any) via MyFree.
  1117. Arguments:
  1118. InfHandle - Supplies a handle to the INF whose default source path
  1119. is to be retrieved.
  1120. Flags
  1121. - if SRCPATH_USEINFLOCATION bit is set, then return the directory
  1122. where the INF is located (with a source media type of SPOST_PATH)
  1123. in the case where either (a) the PNF has no source media information,
  1124. or (b) the PNF has SPOST_URL information.
  1125. - if SRCPATH_USEPNFINFORMATION bit is set, then the actual PNF
  1126. information (whether path or URL) is returned, and if the PNF
  1127. has no source media information, then the system source path is
  1128. returned.
  1129. InfSourceMediaType - Supplies the address of a variable that receives
  1130. the type of path returned. May be one of the following values:
  1131. SPOST_PATH - Standard file path
  1132. SPOST_URL - Internet path
  1133. Return Value:
  1134. If InfSourceMediaType is returned as SPOST_PATH, then a path will
  1135. always be returned, unless we're out of memory (or, if
  1136. DefaultPathIsInfLocation is TRUE, another possibility is that we hit an
  1137. exception). GetLastError() may be used in this case to indicate the cause of
  1138. failure).
  1139. If InfSourceMediaType is returned as SPOST_URL, then the return value
  1140. will be NULL if the default Code Download Manager URL is used (or if we ran
  1141. out of memory), otherwise it will be the specific URL to be used.
  1142. In either case, GetLastError() may be called to determine the cause of
  1143. failure (in the case of SPOST_URL for a NULL InfSourceMediaType,
  1144. GetLastError() will return NO_ERROR if we didn't fail (i.e., we meant to
  1145. return NULL because the INF came from the CDM website).
  1146. --*/
  1147. {
  1148. PTSTR InfSourcePath = NULL, p;
  1149. DWORD Err;
  1150. *InfSourceMediaType = SPOST_PATH;
  1151. Err = NO_ERROR;
  1152. //
  1153. // Lock the INF, so that we can get it's 'InfSourcePath' value, if present.
  1154. //
  1155. if(LockInf((PLOADED_INF)InfHandle)) {
  1156. try {
  1157. if(((PLOADED_INF)InfHandle)->InfSourcePath) {
  1158. InfSourcePath = DuplicateString(((PLOADED_INF)InfHandle)->InfSourcePath);
  1159. if(!InfSourcePath) {
  1160. Err = ERROR_NOT_ENOUGH_MEMORY;
  1161. goto clean0;
  1162. }
  1163. }
  1164. *InfSourceMediaType = ((PLOADED_INF)InfHandle)->InfSourceMediaType;
  1165. if(Flags & SRCPATH_USEINFLOCATION) {
  1166. //
  1167. // Caller has requested that we default to the INF's source
  1168. // location when there's no SPOST_PATH info.
  1169. //
  1170. if(*InfSourceMediaType != SPOST_PATH) {
  1171. if(InfSourcePath) {
  1172. MyFree(InfSourcePath);
  1173. InfSourcePath = NULL;
  1174. }
  1175. *InfSourceMediaType = SPOST_PATH;
  1176. }
  1177. if(!InfSourcePath) {
  1178. //
  1179. // Don't have an INF source path--use the INF's present
  1180. // location.
  1181. //
  1182. InfSourcePath = DuplicateString(((PLOADED_INF)InfHandle)->VersionBlock.Filename);
  1183. if(InfSourcePath) {
  1184. //
  1185. // OK, we duplicated the INF's full pathname, now
  1186. // truncate it to just the path part.
  1187. //
  1188. p = (PTSTR)pSetupGetFileTitle(InfSourcePath);
  1189. *p = TEXT('\0');
  1190. if(((p - InfSourcePath) != 3) ||
  1191. _tcscmp(CharNext(InfSourcePath), TEXT(":\\"))) {
  1192. //
  1193. // The path is not an "A:\" type path, so truncate
  1194. //
  1195. p = CharPrev(InfSourcePath, p);
  1196. MYASSERT(*p == TEXT('\\'));
  1197. if(p > InfSourcePath) {
  1198. *p = TEXT('\0');
  1199. }
  1200. }
  1201. } else {
  1202. Err = ERROR_NOT_ENOUGH_MEMORY;
  1203. goto clean0;
  1204. }
  1205. }
  1206. }
  1207. clean0: ; // nothing to do.
  1208. } except(EXCEPTION_EXECUTE_HANDLER) {
  1209. if(InfSourcePath) {
  1210. MyFree(InfSourcePath);
  1211. InfSourcePath = NULL;
  1212. }
  1213. Err = ERROR_INVALID_PARAMETER;
  1214. }
  1215. UnlockInf((PLOADED_INF)InfHandle);
  1216. }
  1217. if((Flags & SRCPATH_USEINFLOCATION) && !InfSourcePath) {
  1218. //
  1219. // We either hit out of memory or an exception--make sure media type
  1220. // specifies SPOST_PATH before returning failure.
  1221. //
  1222. *InfSourceMediaType = SPOST_PATH;
  1223. MYASSERT(Err != NO_ERROR);
  1224. SetLastError(Err);
  1225. return NULL;
  1226. }
  1227. if(!InfSourcePath && (*InfSourceMediaType == SPOST_PATH) && (Flags & SRCPATH_USEPNFINFORMATION)) {
  1228. //
  1229. // There's not an oem location associated with this INF, so use our default
  1230. // source path.
  1231. //
  1232. InfSourcePath = DuplicateString(SystemSourcePath);
  1233. if(!InfSourcePath) {
  1234. Err = ERROR_NOT_ENOUGH_MEMORY;
  1235. }
  1236. }
  1237. SetLastError(Err);
  1238. return InfSourcePath;
  1239. }
  1240. VOID
  1241. pSetupStripTrailingPlatformComponent(
  1242. IN OUT PTSTR *Paths,
  1243. IN OUT PDWORD NumPaths
  1244. )
  1245. {
  1246. PTSTR Path;
  1247. DWORD PathCount;
  1248. DWORD NewPathCount;
  1249. DWORD PathIndex;
  1250. DWORD DupIndex;
  1251. DWORD FirstIndex;
  1252. DWORD HoleCount;
  1253. PCTSTR Component;
  1254. UINT ComponentLength;
  1255. UINT PathLength;
  1256. int ComponentOffset;
  1257. UINT ComponentIndex;
  1258. //
  1259. // Do this for all paths in the array passed in by the caller.
  1260. //
  1261. PathCount = *NumPaths;
  1262. for(PathIndex=0; PathIndex<PathCount; PathIndex++) {
  1263. Path = Paths[PathIndex];
  1264. if(!Path) {
  1265. //
  1266. // skip holes
  1267. //
  1268. continue;
  1269. }
  1270. //
  1271. // See if the final path component matches one of the ones
  1272. // we care about.
  1273. //
  1274. PathLength = lstrlen(Path);
  1275. for(ComponentIndex=0; PlatformPathComponents[ComponentIndex]; ComponentIndex++) {
  1276. Component = PlatformPathComponents[ComponentIndex];
  1277. ComponentLength = lstrlen(Component);
  1278. ComponentOffset = PathLength - ComponentLength;
  1279. if((ComponentOffset > 0) && (lstrcmpi(Path+ComponentOffset,Component)==0)) {
  1280. //
  1281. // Got a match. Strip off the final component.
  1282. // Leave a trailing backslash if we're dealing with the root.
  1283. //
  1284. Path[ComponentOffset] = TEXT('\0');
  1285. if((Path[1] == TEXT(':')) && !Path[2]) {
  1286. Path[2] = TEXT('\\');
  1287. Path[3] = 0;
  1288. }
  1289. //
  1290. // Remove duplicate, preserving the first instance
  1291. //
  1292. for(FirstIndex=0 ; FirstIndex<PathIndex ; FirstIndex++) {
  1293. if(lstrcmpi(Paths[FirstIndex],Path) == 0) {
  1294. //
  1295. // we've found first instance
  1296. // and it's earlier than PathIndex
  1297. // so we'll end up deleting entry at PathIndex
  1298. Path = Paths[FirstIndex];
  1299. break;
  1300. }
  1301. }
  1302. for(DupIndex = FirstIndex+1;DupIndex<PathCount;DupIndex++) {
  1303. if(lstrcmpi(Paths[DupIndex],Path) == 0) {
  1304. //
  1305. // eliminate duplicate
  1306. //
  1307. MyFree(Paths[DupIndex]);
  1308. Paths[DupIndex] = NULL; // new hole - handle holes later
  1309. }
  1310. }
  1311. //
  1312. // only strip one component
  1313. //
  1314. break;
  1315. }
  1316. }
  1317. }
  1318. //
  1319. // now fix up 'holes' preserving order
  1320. //
  1321. HoleCount = 0;
  1322. for(PathIndex=0; PathIndex<PathCount; PathIndex++) {
  1323. if(!Paths[PathIndex]) {
  1324. //
  1325. // count holes
  1326. //
  1327. HoleCount++;
  1328. } else if(HoleCount) {
  1329. //
  1330. // shift down by number of holes found
  1331. //
  1332. Paths[PathIndex-HoleCount] = Paths[PathIndex];
  1333. }
  1334. }
  1335. NewPathCount = PathCount-HoleCount;
  1336. for(PathIndex = PathCount; PathIndex < NewPathCount; PathIndex++) {
  1337. Paths[PathIndex] = NULL;
  1338. }
  1339. *NumPaths = NewPathCount;
  1340. }