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.

2475 lines
70 KiB

  1. /*++
  2. Copyright (c) Microsoft Corporation. All rights reserved.
  3. Module Name:
  4. infflist.c
  5. Abstract:
  6. Externally exposed routines for manipulating file lists,
  7. disk descriptors, and directory descriptors in INF files.
  8. Author:
  9. Ted Miller (tedm) 3-Feb-1995
  10. Revision History:
  11. --*/
  12. #include "precomp.h"
  13. #pragma hdrstop
  14. #include <winspool.h>
  15. //
  16. // Locations of various fields on lines in a copy section.
  17. // First field is 'target' filename.
  18. // Second field is 'source' filename and is optional for copy sections
  19. // and not used at all in delete sections.
  20. #define COPYSECT_TARGET_FILENAME 1
  21. #define COPYSECT_SOURCE_FILENAME 2
  22. //
  23. // Locations of various fields on lines in a file layout section.
  24. //
  25. #define LAYOUTSECT_FILENAME 0 // key
  26. #define LAYOUTSECT_DISKID 1
  27. #define LAYOUTSECT_SUBDIR 2
  28. #define LAYOUTSECT_SIZE 3
  29. #define LAYOUTSECT_CHECKSUM 4
  30. //
  31. // Locations of various fields on lines in a [DestinationDirs] section.
  32. //
  33. #define DIRSECT_DIRID 1
  34. #define DIRSECT_SUBDIR 2
  35. //
  36. // Names of various sections in an INF.
  37. // (string constants defined in infstr.h)
  38. //
  39. CONST TCHAR pszSourceDisksNames[] = SZ_KEY_SRCDISKNAMES,
  40. pszSourceDisksFiles[] = SZ_KEY_SRCDISKFILES,
  41. pszDestinationDirs[] = SZ_KEY_DESTDIRS,
  42. pszDefaultDestDir[] = SZ_KEY_DEFDESTDIR;
  43. BOOL
  44. _SetupGetSourceFileLocation(
  45. IN HINF InfHandle,
  46. IN PINFCONTEXT InfContext, OPTIONAL
  47. IN PCTSTR FileName, OPTIONAL
  48. IN PSP_ALTPLATFORM_INFO_V2 AltPlatformInfo, OPTIONAL
  49. OUT PUINT SourceId, OPTIONAL
  50. OUT PTSTR ReturnBuffer, OPTIONAL
  51. IN DWORD ReturnBufferSize,
  52. OUT PDWORD RequiredSize, OPTIONAL
  53. OUT PINFCONTEXT LineContext OPTIONAL
  54. )
  55. /*++
  56. Routine Description:
  57. Determine the location of a source file, as listed in an inf file.
  58. Arguments:
  59. InfHandle - supplies the handle to a loaded inf file that contains
  60. file layout information, ie, has [SourceDisksNames] and
  61. [SourceDisksFiles] sections.
  62. InfContext - specifies a line in a copy section of an inf file
  63. for which the full source path is to be retreived. If this
  64. parameter is not specified, then FileName will be searched for
  65. in the [SourceDisksFiles] section of the INF specified by InfHandle.
  66. FileName - supplies the filename (no path) for which to return the
  67. full source location. Must be specified if InfContext is not.
  68. AltPlatformInfo - optionally, supplies alternate platform to be used
  69. when looking for decorated [SourceDisksFiles] section.
  70. SourceId - receives the source id of the source media where the
  71. file is located. This parameter may be NULL if this information
  72. is not desired.
  73. ReturnBuffer - receives the source path (relative to the source LDD).
  74. This path contains neither a drivespec nor the filename itself.
  75. The path never starts or ends with \, so the empty string
  76. means the root.
  77. ReturnBufferSize - specified the size in characters of the buffer
  78. pointed to by ReturnBuffer.
  79. RequiredSize - receives the number of characters required
  80. in ReturnBuffer. If the buffer is too small GetLastError
  81. returns ERROR_INSUFFICIENT_BUFFER.
  82. Return Value:
  83. Boolean value indicating outcome.
  84. --*/
  85. {
  86. PCTSTR fileName, PlatformName;
  87. INFCONTEXT DecContext;
  88. INFCONTEXT UnDecContext;
  89. PINFCONTEXT lineContext;
  90. UINT Length;
  91. PCTSTR SubDir;
  92. TCHAR FileListSectionName[64];
  93. BOOL bDec = FALSE;
  94. BOOL bUnDec = FALSE;
  95. //
  96. // If caller gave a line context, the first field on the line
  97. // is the filename. Retreive it.
  98. //
  99. try {
  100. fileName = InfContext ? pSetupGetField(InfContext,COPYSECT_TARGET_FILENAME) : FileName;
  101. } except(EXCEPTION_EXECUTE_HANDLER) {
  102. //
  103. // InfContext must be a bad pointer
  104. //
  105. fileName = NULL;
  106. }
  107. if(!fileName) {
  108. SetLastError(ERROR_INVALID_PARAMETER);
  109. return(FALSE);
  110. }
  111. //
  112. // Now look for the filename's line in the [SourceDisksFiles] section.
  113. // Look in the platform-specific one first and the platform-independent
  114. // one if not found.
  115. //
  116. if(AltPlatformInfo) {
  117. switch(AltPlatformInfo->ProcessorArchitecture) {
  118. case PROCESSOR_ARCHITECTURE_INTEL :
  119. PlatformName = pszX86SrcDiskSuffix;
  120. break;
  121. case PROCESSOR_ARCHITECTURE_IA64 :
  122. PlatformName = pszIa64SrcDiskSuffix;
  123. break;
  124. case PROCESSOR_ARCHITECTURE_AMD64 :
  125. PlatformName = pszAmd64SrcDiskSuffix;
  126. break;
  127. default :
  128. //
  129. // unknown/unsupported processor architecture.
  130. //
  131. MYASSERT((AltPlatformInfo->ProcessorArchitecture == PROCESSOR_ARCHITECTURE_INTEL) ||
  132. (AltPlatformInfo->ProcessorArchitecture == PROCESSOR_ARCHITECTURE_IA64) ||
  133. (AltPlatformInfo->ProcessorArchitecture == PROCESSOR_ARCHITECTURE_AMD64)
  134. );
  135. SetLastError(ERROR_INVALID_PARAMETER);
  136. return(FALSE);
  137. }
  138. } else {
  139. PlatformName = pszPlatformSrcDiskSuffix;
  140. }
  141. wnsprintf(FileListSectionName,
  142. SIZECHARS(FileListSectionName),
  143. TEXT("%s.%s"),
  144. pszSourceDisksFiles,
  145. PlatformName
  146. );
  147. bDec = SetupFindFirstLine(InfHandle,FileListSectionName,fileName,&DecContext);
  148. if(bDec && (DecContext.CurrentInf == InfHandle)) {
  149. //
  150. // found Decorated section in same INF as source file
  151. //
  152. lineContext = &DecContext;
  153. } else {
  154. //
  155. // didn't find decorated section in expected INF, try undecorated in expected INF
  156. //
  157. bUnDec = SetupFindFirstLine(InfHandle,pszSourceDisksFiles,fileName,&UnDecContext);
  158. if(bUnDec && (UnDecContext.CurrentInf == InfHandle)) {
  159. //
  160. // found in Undecorated section in same INF as source file
  161. //
  162. lineContext = &UnDecContext;
  163. } else if(bDec) {
  164. //
  165. // any decorated section (should only be one)
  166. //
  167. lineContext = &DecContext;
  168. } else if(bUnDec) {
  169. //
  170. // any undecorated section (should only be one)
  171. //
  172. lineContext = &UnDecContext;
  173. } else {
  174. //
  175. // none found
  176. //
  177. SetLastError(ERROR_LINE_NOT_FOUND);
  178. return(FALSE);
  179. }
  180. }
  181. //
  182. // Got the line. If the caller wants it, give it to him.
  183. // We don't guard this with try/except because this routine is internal
  184. // and any fault is a bug in the caller.
  185. //
  186. if(LineContext) {
  187. *LineContext = *lineContext;
  188. }
  189. //
  190. // Get the disk id.
  191. //
  192. if(SourceId) {
  193. if(!SetupGetIntField(lineContext,LAYOUTSECT_DISKID,SourceId)) {
  194. SetLastError(ERROR_INVALID_DATA);
  195. return(FALSE);
  196. }
  197. }
  198. //
  199. // If all the caller was interested in was the disk ID (i.e., they passed in ReturnBuffer
  200. // and RequiredSize both as NULL), then we can save the extra work and return now.
  201. //
  202. if(!(ReturnBuffer || RequiredSize)) {
  203. return TRUE;
  204. }
  205. //
  206. // Now get the path relative to the LDD.
  207. //
  208. SubDir = pSetupGetField(lineContext,LAYOUTSECT_SUBDIR);
  209. if(!SubDir) {
  210. SubDir = TEXT("");
  211. }
  212. Length = lstrlen(SubDir);
  213. //
  214. // Ignore leading path sep if present.
  215. //
  216. if(SubDir[0] == TEXT('\\')) {
  217. Length--;
  218. SubDir++;
  219. }
  220. //
  221. // See if there's a trailing path sep.
  222. //
  223. if(Length && *CharPrev(SubDir,SubDir+Length) == TEXT('\\')) {
  224. Length--;
  225. }
  226. //
  227. // Leave space for the nul
  228. //
  229. if(RequiredSize) {
  230. *RequiredSize = Length+1;
  231. }
  232. //
  233. // Place data in caller's buffer.
  234. // If caller didn't specify a buffer we're done.
  235. //
  236. if(ReturnBuffer) {
  237. if(ReturnBufferSize <= Length) {
  238. SetLastError(ERROR_INSUFFICIENT_BUFFER);
  239. return(FALSE);
  240. }
  241. //
  242. // Don't use lstrcpy, because if we are stripping
  243. // a trailing path sep, lstrcpy could write the nul byte
  244. // past the end of the buffer.
  245. //
  246. CopyMemory(ReturnBuffer,SubDir,Length*sizeof(TCHAR));
  247. ReturnBuffer[Length] = 0;
  248. }
  249. return(TRUE);
  250. }
  251. #ifdef UNICODE
  252. //
  253. // ANSI version
  254. //
  255. BOOL
  256. SetupGetSourceFileLocationA(
  257. IN HINF InfHandle,
  258. IN PINFCONTEXT InfContext, OPTIONAL
  259. IN PCSTR FileName, OPTIONAL
  260. OUT PUINT SourceId,
  261. OUT PSTR ReturnBuffer, OPTIONAL
  262. IN DWORD ReturnBufferSize,
  263. OUT PDWORD RequiredSize OPTIONAL
  264. )
  265. {
  266. WCHAR returnbuffer[MAX_PATH];
  267. DWORD requiredsize;
  268. PCWSTR filename;
  269. UINT sourceid;
  270. DWORD rc;
  271. BOOL b;
  272. PCSTR ansireturn;
  273. rc = NO_ERROR;
  274. if(FileName) {
  275. rc = pSetupCaptureAndConvertAnsiArg(FileName,&filename);
  276. if(rc != NO_ERROR) {
  277. SetLastError(rc);
  278. return(FALSE);
  279. }
  280. } else {
  281. filename = NULL;
  282. }
  283. b = _SetupGetSourceFileLocation(
  284. InfHandle,
  285. InfContext,
  286. filename,
  287. NULL,
  288. &sourceid,
  289. returnbuffer,
  290. MAX_PATH,
  291. &requiredsize,
  292. NULL
  293. );
  294. rc = GetLastError();
  295. if(b) {
  296. rc = NO_ERROR;
  297. if(ansireturn = pSetupUnicodeToAnsi(returnbuffer)) {
  298. requiredsize = lstrlenA(ansireturn)+1;
  299. try {
  300. *SourceId = sourceid;
  301. if(RequiredSize) {
  302. *RequiredSize = requiredsize;
  303. }
  304. } except(EXCEPTION_EXECUTE_HANDLER) {
  305. rc = ERROR_INVALID_PARAMETER;
  306. b = FALSE;
  307. }
  308. if(rc == NO_ERROR) {
  309. if(ReturnBuffer) {
  310. if(requiredsize <= ReturnBufferSize) {
  311. //
  312. // lstrcpy won't generate an exception on NT even if
  313. // ReturnBuffer is invalid, but will return NULL
  314. //
  315. try {
  316. if(!lstrcpyA(ReturnBuffer,ansireturn)) {
  317. b = FALSE;
  318. rc = ERROR_INVALID_PARAMETER;
  319. }
  320. } except(EXCEPTION_EXECUTE_HANDLER) {
  321. b = FALSE;
  322. rc = ERROR_INVALID_PARAMETER;
  323. }
  324. } else {
  325. b = FALSE;
  326. rc = ERROR_INSUFFICIENT_BUFFER;
  327. }
  328. }
  329. }
  330. MyFree(ansireturn);
  331. } else {
  332. b = FALSE;
  333. rc = ERROR_NOT_ENOUGH_MEMORY;
  334. }
  335. }
  336. if(filename) {
  337. MyFree(filename);
  338. }
  339. SetLastError(rc);
  340. return(b);
  341. }
  342. #else
  343. //
  344. // Unicode stub
  345. //
  346. BOOL
  347. SetupGetSourceFileLocationW(
  348. IN HINF InfHandle,
  349. IN PINFCONTEXT InfContext, OPTIONAL
  350. IN PCWSTR FileName, OPTIONAL
  351. OUT PUINT SourceId,
  352. OUT PWSTR ReturnBuffer, OPTIONAL
  353. IN DWORD ReturnBufferSize,
  354. OUT PDWORD RequiredSize OPTIONAL
  355. )
  356. {
  357. UNREFERENCED_PARAMETER(InfHandle);
  358. UNREFERENCED_PARAMETER(InfContext);
  359. UNREFERENCED_PARAMETER(FileName);
  360. UNREFERENCED_PARAMETER(SourceId);
  361. UNREFERENCED_PARAMETER(ReturnBuffer);
  362. UNREFERENCED_PARAMETER(ReturnBufferSize);
  363. UNREFERENCED_PARAMETER(RequiredSize);
  364. SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
  365. return(FALSE);
  366. }
  367. #endif
  368. BOOL
  369. SetupGetSourceFileLocation(
  370. IN HINF InfHandle,
  371. IN PINFCONTEXT InfContext, OPTIONAL
  372. IN PCTSTR FileName, OPTIONAL
  373. OUT PUINT SourceId,
  374. OUT PTSTR ReturnBuffer, OPTIONAL
  375. IN DWORD ReturnBufferSize,
  376. OUT PDWORD RequiredSize OPTIONAL
  377. )
  378. {
  379. TCHAR returnbuffer[MAX_PATH];
  380. DWORD requiredsize;
  381. PCTSTR filename;
  382. UINT sourceid;
  383. DWORD rc;
  384. BOOL b;
  385. rc = NO_ERROR;
  386. if(FileName) {
  387. rc = CaptureStringArg(FileName,&filename);
  388. if(rc != NO_ERROR) {
  389. SetLastError(rc);
  390. return(FALSE);
  391. }
  392. } else {
  393. filename = NULL;
  394. }
  395. b = _SetupGetSourceFileLocation(
  396. InfHandle,
  397. InfContext,
  398. filename,
  399. NULL,
  400. &sourceid,
  401. returnbuffer,
  402. MAX_PATH,
  403. &requiredsize,
  404. NULL
  405. );
  406. rc = GetLastError();
  407. if(b) {
  408. rc = NO_ERROR;
  409. try {
  410. *SourceId = sourceid;
  411. if(RequiredSize) {
  412. *RequiredSize = requiredsize;
  413. }
  414. } except(EXCEPTION_EXECUTE_HANDLER) {
  415. rc = ERROR_INVALID_PARAMETER;
  416. b = FALSE;
  417. }
  418. if(rc == NO_ERROR) {
  419. if(ReturnBuffer) {
  420. if(requiredsize <= ReturnBufferSize) {
  421. //
  422. // lstrcpy won't generate an exception on NT even if
  423. // ReturnBuffer is invalid, but will return NULL
  424. //
  425. try {
  426. if(!lstrcpy(ReturnBuffer,returnbuffer)) {
  427. b = FALSE;
  428. rc = ERROR_INVALID_PARAMETER;
  429. }
  430. } except(EXCEPTION_EXECUTE_HANDLER) {
  431. b = FALSE;
  432. rc = ERROR_INVALID_PARAMETER;
  433. }
  434. } else {
  435. b = FALSE;
  436. rc = ERROR_INSUFFICIENT_BUFFER;
  437. }
  438. }
  439. }
  440. }
  441. if(filename) {
  442. MyFree(filename);
  443. }
  444. SetLastError(rc);
  445. return(b);
  446. }
  447. BOOL
  448. _SetupGetSourceFileSize(
  449. IN HINF InfHandle,
  450. IN PINFCONTEXT InfContext, OPTIONAL
  451. IN PCTSTR FileName, OPTIONAL
  452. IN PCTSTR Section, OPTIONAL
  453. IN PSP_ALTPLATFORM_INFO_V2 AltPlatformInfo, OPTIONAL
  454. OUT PDWORD FileSize,
  455. IN UINT RoundingFactor OPTIONAL
  456. )
  457. /*++
  458. Routine Description:
  459. Determine the (uncompressed) size of a source file,
  460. as listed in an inf file.
  461. Arguments:
  462. InfHandle - supplies the handle to a loaded inf file that contains
  463. file layout information, ie, has [SourceDisksNames] and
  464. optionally [SourceDisksFiles] sections.
  465. InfContext - specifies a line in a the copy section of an inf file
  466. for which the size is to be retreived. If this parameter is
  467. not specified, the FileName parameter is checked next.
  468. FileName - supplies the filename (no path) for which to return the
  469. size. If this parameter is not specified the Section parameter
  470. is used (see below).
  471. Section - specifies the name of a section in the INF file specified
  472. by InfHandle. The total sizes of all files in the section is
  473. computed.
  474. AltPlatformInfo - optionally, supplies alternate platform information
  475. to be used in selecting a decorated [SourceDisksFiles] section.
  476. FileSize - receives the file size(s).
  477. RoundingFactor - If specified, supplies a value for rounding file sizes.
  478. All file sizes will be rounded up to be a multiple of this number
  479. before being added to the total size. This is useful for more
  480. exact determinations of the space a file will occupy on a given volume,
  481. because it allows the caller to have file sizes rounded up to be a
  482. multiple of the cluster size. If not specified no rounding takes place.
  483. Return Value:
  484. Boolean value indicating outcome.
  485. --*/
  486. {
  487. PCTSTR fileName, PlatformName;
  488. INFCONTEXT LayoutSectionContext;
  489. INFCONTEXT CopySectionContext;
  490. BOOL b;
  491. UINT Size;
  492. LONG File,FileCount;
  493. TCHAR FileListSectionName[64];
  494. DWORD rc;
  495. //
  496. // If the rounding factor is not specified, set it to 1 so the math
  497. // below works without special cases.
  498. //
  499. if(!RoundingFactor) {
  500. RoundingFactor = 1;
  501. }
  502. // Establish an inf line context for the line in the copy list section,
  503. // unless the caller passed us an absolute filename.
  504. //
  505. fileName = NULL;
  506. FileCount = 1;
  507. if(InfContext) {
  508. //
  509. // Caller passed INF line context.
  510. // Remember the context in preparation for retreiving the filename
  511. // from the line later.
  512. //
  513. // fileName must be NULL so we look at the line
  514. // and get the correct source name
  515. //
  516. b = TRUE;
  517. try {
  518. CopySectionContext = *InfContext;
  519. } except(EXCEPTION_EXECUTE_HANDLER) {
  520. b = FALSE;
  521. }
  522. if(!b) {
  523. SetLastError(ERROR_INVALID_PARAMETER);
  524. return(FALSE);
  525. }
  526. } else {
  527. if(FileName) {
  528. //
  529. // Caller passed an absolute file name. Remember it.
  530. //
  531. fileName = FileName;
  532. } else {
  533. //
  534. // Caller must have passed a section, the contents of which lists
  535. // a set of files whose sizes are to be totalled. Determine the number
  536. // of lines in the section and establish a context.
  537. //
  538. if(Section) {
  539. FileCount = SetupGetLineCount(InfHandle,Section);
  540. if((FileCount == -1)
  541. || !SetupFindFirstLine(InfHandle,Section,NULL,&CopySectionContext)) {
  542. rc = GetLastError();
  543. pSetupLogSectionError(InfHandle,NULL,NULL,NULL,Section,MSG_LOG_NOSECTION_FILESIZE,rc,NULL);
  544. SetLastError(ERROR_SECTION_NOT_FOUND); // ignoring rc for compatability with older versions of setupAPI
  545. return(FALSE);
  546. }
  547. } else {
  548. SetLastError(ERROR_INVALID_PARAMETER);
  549. return(FALSE);
  550. }
  551. }
  552. }
  553. *FileSize = 0;
  554. for(File=0; File<FileCount; File++) {
  555. if(File) {
  556. //
  557. // This is not the first pass through the loop. We need
  558. // to locate the next line in the copy list section.
  559. //
  560. b = SetupFindNextLine(&CopySectionContext,&CopySectionContext);
  561. if(!b) {
  562. SetLastError(ERROR_INVALID_DATA);
  563. return(FALSE);
  564. }
  565. fileName = pSetupGetField(&CopySectionContext,COPYSECT_SOURCE_FILENAME);
  566. if(fileName == NULL || fileName[0] == 0) {
  567. fileName = pSetupGetField(&CopySectionContext,COPYSECT_TARGET_FILENAME);
  568. }
  569. } else {
  570. //
  571. // First pass through the loop. May need to get a filename.
  572. //
  573. if(!fileName) {
  574. fileName = pSetupGetField(&CopySectionContext,COPYSECT_SOURCE_FILENAME);
  575. if(fileName == NULL || fileName[0] == 0) {
  576. fileName = pSetupGetField(&CopySectionContext,COPYSECT_TARGET_FILENAME);
  577. }
  578. }
  579. }
  580. //
  581. // If we don't have a filename by now, the inf is corrupt.
  582. //
  583. if(!fileName) {
  584. SetLastError(ERROR_INVALID_DATA);
  585. return(FALSE);
  586. }
  587. //
  588. // Locate the line in [SourceDisksFiles] that is for the filename
  589. // we are currently dealing with. Look in the platform-specific
  590. // section first.
  591. //
  592. if(AltPlatformInfo) {
  593. switch(AltPlatformInfo->ProcessorArchitecture) {
  594. case PROCESSOR_ARCHITECTURE_INTEL :
  595. PlatformName = pszX86SrcDiskSuffix;
  596. break;
  597. case PROCESSOR_ARCHITECTURE_IA64 :
  598. PlatformName = pszIa64SrcDiskSuffix;
  599. break;
  600. case PROCESSOR_ARCHITECTURE_AMD64 :
  601. PlatformName = pszAmd64SrcDiskSuffix;
  602. break;
  603. default :
  604. //
  605. // unknown/unsupported processor architecture.
  606. //
  607. MYASSERT((AltPlatformInfo->ProcessorArchitecture == PROCESSOR_ARCHITECTURE_INTEL) ||
  608. (AltPlatformInfo->ProcessorArchitecture == PROCESSOR_ARCHITECTURE_IA64) ||
  609. (AltPlatformInfo->ProcessorArchitecture == PROCESSOR_ARCHITECTURE_AMD64)
  610. );
  611. SetLastError(ERROR_INVALID_PARAMETER);
  612. return(FALSE);
  613. }
  614. } else {
  615. PlatformName = pszPlatformSrcDiskSuffix;
  616. }
  617. wnsprintf(
  618. FileListSectionName,
  619. sizeof(FileListSectionName)/sizeof(FileListSectionName[0]),
  620. TEXT("%s.%s"),
  621. pszSourceDisksFiles,
  622. PlatformName
  623. );
  624. b = SetupFindFirstLine(InfHandle,FileListSectionName,fileName,&LayoutSectionContext);
  625. if(!b) {
  626. b = SetupFindFirstLine(InfHandle,pszSourceDisksFiles,fileName,&LayoutSectionContext);
  627. }
  628. if(!b) {
  629. SetLastError(ERROR_LINE_NOT_FOUND);
  630. return(FALSE);
  631. }
  632. //
  633. // Get the size data for the file.
  634. //
  635. b = SetupGetIntField(&LayoutSectionContext,LAYOUTSECT_SIZE,&Size);
  636. if(!b) {
  637. SetLastError(ERROR_INVALID_DATA);
  638. return(FALSE);
  639. }
  640. //
  641. // Round size up to be an even multiple of the rounding factor
  642. //
  643. if(Size % RoundingFactor) {
  644. Size += RoundingFactor - (Size % RoundingFactor);
  645. }
  646. *FileSize += Size;
  647. }
  648. return(TRUE);
  649. }
  650. #ifdef UNICODE
  651. //
  652. // ANSI version
  653. //
  654. BOOL
  655. SetupGetSourceFileSizeA(
  656. IN HINF InfHandle,
  657. IN PINFCONTEXT InfContext, OPTIONAL
  658. IN PCSTR FileName, OPTIONAL
  659. IN PCSTR Section, OPTIONAL
  660. OUT PDWORD FileSize,
  661. IN UINT RoundingFactor OPTIONAL
  662. )
  663. {
  664. PCWSTR filename,section;
  665. BOOL b;
  666. DWORD rc;
  667. DWORD size;
  668. if(FileName) {
  669. rc = pSetupCaptureAndConvertAnsiArg(FileName,&filename);
  670. if(rc != NO_ERROR) {
  671. SetLastError(rc);
  672. return(FALSE);
  673. }
  674. } else {
  675. filename = NULL;
  676. }
  677. if(Section) {
  678. rc = pSetupCaptureAndConvertAnsiArg(Section,&section);
  679. if(rc != NO_ERROR) {
  680. if(filename) {
  681. MyFree(filename);
  682. }
  683. SetLastError(rc);
  684. return(FALSE);
  685. }
  686. } else {
  687. section = NULL;
  688. }
  689. b = _SetupGetSourceFileSize(InfHandle,
  690. InfContext,
  691. filename,
  692. section,
  693. NULL,
  694. &size,
  695. RoundingFactor
  696. );
  697. rc = GetLastError();
  698. if (b) {
  699. try {
  700. *FileSize = size;
  701. } except(EXCEPTION_EXECUTE_HANDLER) {
  702. b = FALSE;
  703. rc = ERROR_INVALID_PARAMETER;
  704. }
  705. }
  706. if(filename) {
  707. MyFree(filename);
  708. }
  709. if(section) {
  710. MyFree(section);
  711. }
  712. SetLastError(rc);
  713. return(b);
  714. }
  715. #else
  716. //
  717. // Unicode stub
  718. //
  719. BOOL
  720. SetupGetSourceFileSizeW(
  721. IN HINF InfHandle,
  722. IN PINFCONTEXT InfContext, OPTIONAL
  723. IN PCWSTR FileName, OPTIONAL
  724. IN PCWSTR Section, OPTIONAL
  725. OUT PDWORD FileSize,
  726. IN UINT RoundingFactor OPTIONAL
  727. )
  728. {
  729. UNREFERENCED_PARAMETER(InfHandle);
  730. UNREFERENCED_PARAMETER(InfContext);
  731. UNREFERENCED_PARAMETER(FileName);
  732. UNREFERENCED_PARAMETER(Section);
  733. UNREFERENCED_PARAMETER(FileSize);
  734. UNREFERENCED_PARAMETER(RoundingFactor);
  735. SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
  736. return(FALSE);
  737. }
  738. #endif
  739. BOOL
  740. SetupGetSourceFileSize(
  741. IN HINF InfHandle,
  742. IN PINFCONTEXT InfContext, OPTIONAL
  743. IN PCTSTR FileName, OPTIONAL
  744. IN PCTSTR Section, OPTIONAL
  745. OUT PDWORD FileSize,
  746. IN UINT RoundingFactor OPTIONAL
  747. )
  748. {
  749. PCTSTR filename,section;
  750. BOOL b;
  751. DWORD rc;
  752. DWORD size;
  753. if(FileName) {
  754. rc = CaptureStringArg(FileName,&filename);
  755. if(rc != NO_ERROR) {
  756. SetLastError(rc);
  757. return(FALSE);
  758. }
  759. } else {
  760. filename = NULL;
  761. }
  762. if(Section) {
  763. rc = CaptureStringArg(Section,&section);
  764. if(rc != NO_ERROR) {
  765. if(filename) {
  766. MyFree(filename);
  767. }
  768. SetLastError(rc);
  769. return(FALSE);
  770. }
  771. } else {
  772. section = NULL;
  773. }
  774. b = _SetupGetSourceFileSize(InfHandle,
  775. InfContext,
  776. filename,
  777. section,
  778. NULL,
  779. &size,
  780. RoundingFactor
  781. );
  782. rc = GetLastError();
  783. if (b) {
  784. try {
  785. *FileSize = size;
  786. } except(EXCEPTION_EXECUTE_HANDLER) {
  787. b = FALSE;
  788. rc = ERROR_INVALID_PARAMETER;
  789. }
  790. }
  791. if(filename) {
  792. MyFree(filename);
  793. }
  794. if(section) {
  795. MyFree(section);
  796. }
  797. SetLastError(rc);
  798. return(b);
  799. }
  800. BOOL
  801. _SetupGetTargetPath(
  802. IN HINF InfHandle,
  803. IN PINFCONTEXT InfContext, OPTIONAL
  804. IN PCTSTR Section, OPTIONAL
  805. OUT PTSTR ReturnBuffer, OPTIONAL
  806. IN DWORD ReturnBufferSize,
  807. OUT PDWORD RequiredSize OPTIONAL
  808. )
  809. /*++
  810. Routine Description:
  811. Determine the target directory for a given file list section.
  812. A file list section may be for copy, rename, or delete; in any case
  813. all the files in the section are in one directory and that directory
  814. is listed in the [DestinationDirs] section of the inf.
  815. Where InfContext is specified, we will look for [DestinationDirs]
  816. from the current inf in the context first. This will help the scenario
  817. where X.INF includes Y.INF includes LAYOUT.INF, both X&Y have entries
  818. but the section was found in Y. We want to find the section in X last.
  819. Arguments:
  820. InfHandle - supplies the handle to a loaded inf file
  821. that contains a [DestinationDirs] section.
  822. InfContext - specifies a line in a the copy section of an inf file.
  823. The target directory for this section is retreived.
  824. Section - Supplies the section in InfHandle whose destination directory
  825. is to be retreived. Ignored if InfContext is specified.
  826. If neither InfContext nor Section are specified, this function retreives
  827. the default target path.
  828. ReturnBuffer - if specified, receives the full win32 path of the target.
  829. This value is guaranteed not to end with \.
  830. ReturnBufferSize - specifies the size in characters of the buffer pointed
  831. to by ReturnBuffer.
  832. RequiredSize - receives the size in characters of a buffer required to hold
  833. the output data.
  834. Return Value:
  835. Boolean value indicating outcome. GetLastError() returns extended error info.
  836. ERROR_INSUFFICIENT_BUFFER is returned if the function fails because
  837. ReturnBuffer is too small.
  838. --*/
  839. {
  840. PINF_SECTION DestDirsSection = NULL;
  841. UINT LineNumber = 0;
  842. PINF_LINE Line = NULL;
  843. PCTSTR DirId = NULL;
  844. PCTSTR SubDir = NULL;
  845. PCTSTR ActualPath = NULL;
  846. UINT DirIdInt = 0;
  847. PLOADED_INF Inf = NULL;
  848. PLOADED_INF CurInf = NULL;
  849. PLOADED_INF DefaultDestDirInf = NULL;
  850. DWORD TmpRequiredSize = 0;
  851. BOOL DestDirFound = FALSE;
  852. BOOL DefaultDestDirFound = FALSE;
  853. DWORD Err = NO_ERROR;
  854. PINF_LINE DefaultDestDirLine = NULL;
  855. PCTSTR InfSourcePath = NULL;
  856. //
  857. // If an INF context was specified, use it to determine the name
  858. // the section the context describes. If inf context was not specified,
  859. // then a section name must have been.
  860. //
  861. Err = NO_ERROR;
  862. try {
  863. Inf = InfContext ? (PLOADED_INF)InfContext->Inf : (PLOADED_INF)InfHandle;
  864. if(!LockInf(Inf)) {
  865. Err = ERROR_INVALID_HANDLE;
  866. }
  867. } except(EXCEPTION_EXECUTE_HANDLER) {
  868. Err = ERROR_INVALID_PARAMETER;
  869. }
  870. if(Err != NO_ERROR) {
  871. SetLastError(Err);
  872. return(FALSE);
  873. }
  874. //
  875. // If we get here then InfContext is a good pointer if specified;
  876. // if not then Inf is a good pointer.
  877. //
  878. if(InfContext) {
  879. CurInf = (PLOADED_INF)InfContext->CurrentInf;
  880. InfSourcePath = CurInf->InfSourcePath;
  881. Section = pStringTableStringFromId(
  882. CurInf->StringTable,
  883. CurInf->SectionBlock[InfContext->Section].SectionName
  884. );
  885. } else {
  886. InfSourcePath = Inf->InfSourcePath;
  887. if(!Section) {
  888. Section = pszDefaultDestDir;
  889. }
  890. }
  891. //
  892. // Traverse the linked list of INFs, looking for a [DestinationDirs] section
  893. // in each one.
  894. //
  895. DestDirFound = DefaultDestDirFound = FALSE;
  896. Err = NO_ERROR;
  897. if (InfContext) {
  898. //
  899. // first consider the CurrentInf as being Local scope
  900. //
  901. CurInf = InfContext->CurrentInf;
  902. if((DestDirsSection = InfLocateSection(CurInf, pszDestinationDirs, NULL))!=NULL) {
  903. //
  904. // Locate the line in [DestinationDirs] that gives the target path
  905. // for the section. The section name will be the key on the relevant line.
  906. // If that's not there, and we haven't already encountered a DefaultDestDir
  907. // entry, then look for that as well, and remember it if we find one.
  908. //
  909. LineNumber = 0;
  910. if(InfLocateLine(CurInf, DestDirsSection, Section, &LineNumber, &Line)) {
  911. //
  912. // Got the line in [DestinationDirs]. Pull out the directory. The subdir is optional.
  913. //
  914. DirId = InfGetField(CurInf, Line, DIRSECT_DIRID, NULL);
  915. if(!DirId) {
  916. Err = ERROR_INVALID_DATA;
  917. goto clean0;
  918. }
  919. SubDir = InfGetField(CurInf, Line, DIRSECT_SUBDIR, NULL);
  920. DestDirFound = TRUE;
  921. } else if(InfLocateLine(CurInf, DestDirsSection, pszDefaultDestDir, &LineNumber, &Line)) {
  922. DefaultDestDirInf = CurInf;
  923. DefaultDestDirLine = Line;
  924. DefaultDestDirFound = TRUE;
  925. }
  926. }
  927. }
  928. if(!DestDirFound && !DefaultDestDirFound) {
  929. //
  930. // search for any matches at all
  931. //
  932. for(CurInf = Inf; CurInf; CurInf = CurInf->Next) {
  933. if(!(DestDirsSection = InfLocateSection(CurInf, pszDestinationDirs, NULL))) {
  934. continue;
  935. }
  936. //
  937. // Locate the line in [DestinationDirs] that gives the target path
  938. // for the section. The section name will be the key on the relevant line.
  939. // If that's not there, and we haven't already encountered a DefaultDestDir
  940. // entry, then look for that as well, and remember it if we find one.
  941. //
  942. LineNumber = 0;
  943. if(InfLocateLine(CurInf, DestDirsSection, Section, &LineNumber, &Line)) {
  944. //
  945. // Got the line in [DestinationDirs]. Pull out the directory. The subdir is optional.
  946. //
  947. DirId = InfGetField(CurInf, Line, DIRSECT_DIRID, NULL);
  948. if(!DirId) {
  949. Err = ERROR_INVALID_DATA;
  950. goto clean0;
  951. }
  952. SubDir = InfGetField(CurInf, Line, DIRSECT_SUBDIR, NULL);
  953. DestDirFound = TRUE;
  954. break;
  955. }
  956. if(!DefaultDestDirFound &&
  957. InfLocateLine(CurInf, DestDirsSection, pszDefaultDestDir, &LineNumber, &Line)) {
  958. DefaultDestDirInf = CurInf;
  959. DefaultDestDirLine = Line;
  960. DefaultDestDirFound = TRUE;
  961. }
  962. }
  963. }
  964. if(!DestDirFound) {
  965. //
  966. // If we found a DefaultDestDir, then use that, otherwise, use a default.
  967. //
  968. if(DefaultDestDirFound) {
  969. DirId = InfGetField(DefaultDestDirInf, DefaultDestDirLine, DIRSECT_DIRID, NULL);
  970. if(!DirId) {
  971. Err = ERROR_INVALID_DATA;
  972. goto clean0;
  973. }
  974. SubDir = InfGetField(DefaultDestDirInf, DefaultDestDirLine, DIRSECT_SUBDIR, NULL);
  975. CurInf = DefaultDestDirInf;
  976. } else {
  977. SubDir = NULL;
  978. DirId = NULL;
  979. DirIdInt = DIRID_DEFAULT;
  980. CurInf = NULL;
  981. }
  982. }
  983. //
  984. // Translate dirid/subdir to actual path.
  985. //
  986. ActualPath = pSetupDirectoryIdToPath(DirId,
  987. &DirIdInt,
  988. SubDir,
  989. InfSourcePath,
  990. (CurInf && CurInf->OsLoaderPath)
  991. ? &(CurInf->OsLoaderPath)
  992. : NULL
  993. );
  994. if(!ActualPath) {
  995. //
  996. // If the default DIRID lookup failed because DirId is in the
  997. // user-defined range, then GetLastError will return NO_ERROR.
  998. // Otherwise, we should bail now.
  999. //
  1000. if((Err = GetLastError()) != NO_ERROR) {
  1001. goto clean0;
  1002. }
  1003. //
  1004. // Now see if we there's a user-defined DIRID for this.
  1005. //
  1006. if(!(ActualPath = pSetupVolatileDirIdToPath(NULL,
  1007. DirIdInt,
  1008. SubDir,
  1009. Inf))) {
  1010. Err = GetLastError();
  1011. goto clean0;
  1012. }
  1013. }
  1014. //
  1015. // Put actual path in caller's buffer.
  1016. //
  1017. TmpRequiredSize = lstrlen(ActualPath) + 1;
  1018. if(RequiredSize) {
  1019. *RequiredSize = TmpRequiredSize;
  1020. }
  1021. if(ReturnBuffer) {
  1022. if(TmpRequiredSize > ReturnBufferSize) {
  1023. Err = ERROR_INSUFFICIENT_BUFFER;
  1024. } else {
  1025. lstrcpy(ReturnBuffer, ActualPath);
  1026. }
  1027. }
  1028. MyFree(ActualPath);
  1029. clean0:
  1030. UnlockInf(Inf);
  1031. if(Err == NO_ERROR) {
  1032. return TRUE;
  1033. } else {
  1034. SetLastError(Err);
  1035. return FALSE;
  1036. }
  1037. }
  1038. #ifdef UNICODE
  1039. //
  1040. // ANSI version
  1041. //
  1042. BOOL
  1043. SetupGetTargetPathA(
  1044. IN HINF InfHandle,
  1045. IN PINFCONTEXT InfContext, OPTIONAL
  1046. IN PCSTR Section, OPTIONAL
  1047. OUT PSTR ReturnBuffer, OPTIONAL
  1048. IN DWORD ReturnBufferSize,
  1049. OUT PDWORD RequiredSize OPTIONAL
  1050. )
  1051. {
  1052. BOOL b;
  1053. DWORD rc;
  1054. WCHAR returnbuffer[MAX_PATH];
  1055. DWORD requiredsize;
  1056. PCWSTR section;
  1057. PCSTR ansireturn;
  1058. if(Section) {
  1059. rc = pSetupCaptureAndConvertAnsiArg(Section,&section);
  1060. } else {
  1061. section = NULL;
  1062. rc = NO_ERROR;
  1063. }
  1064. if(rc == NO_ERROR) {
  1065. b = _SetupGetTargetPath(InfHandle,InfContext,section,returnbuffer,MAX_PATH,&requiredsize);
  1066. rc = GetLastError();
  1067. } else {
  1068. b = FALSE;
  1069. }
  1070. if(b) {
  1071. if(ansireturn = pSetupUnicodeToAnsi(returnbuffer)) {
  1072. rc = NO_ERROR;
  1073. requiredsize = lstrlenA(ansireturn) + 1;
  1074. if(RequiredSize) {
  1075. try {
  1076. *RequiredSize = requiredsize;
  1077. } except(EXCEPTION_EXECUTE_HANDLER) {
  1078. rc = ERROR_INVALID_PARAMETER;
  1079. b = FALSE;
  1080. }
  1081. }
  1082. if(rc == NO_ERROR) {
  1083. if(ReturnBuffer) {
  1084. if(requiredsize <= ReturnBufferSize) {
  1085. //
  1086. // At least on NT lstrcpy won't fault if an arg is invalid
  1087. // but it will return false.
  1088. //
  1089. if(!lstrcpyA(ReturnBuffer,ansireturn)) {
  1090. rc = ERROR_INVALID_PARAMETER;
  1091. b = FALSE;
  1092. }
  1093. } else {
  1094. rc = ERROR_INSUFFICIENT_BUFFER;
  1095. b = FALSE;
  1096. }
  1097. }
  1098. }
  1099. MyFree(ansireturn);
  1100. } else {
  1101. b = FALSE;
  1102. rc = ERROR_NOT_ENOUGH_MEMORY;
  1103. }
  1104. }
  1105. if(section) {
  1106. MyFree(section);
  1107. }
  1108. SetLastError(rc);
  1109. return(b);
  1110. }
  1111. #else
  1112. //
  1113. // Unicode stub
  1114. //
  1115. BOOL
  1116. SetupGetTargetPathW(
  1117. IN HINF InfHandle,
  1118. IN PINFCONTEXT InfContext, OPTIONAL
  1119. IN PCWSTR Section, OPTIONAL
  1120. OUT PWSTR ReturnBuffer, OPTIONAL
  1121. IN DWORD ReturnBufferSize,
  1122. OUT PDWORD RequiredSize OPTIONAL
  1123. )
  1124. {
  1125. UNREFERENCED_PARAMETER(InfHandle);
  1126. UNREFERENCED_PARAMETER(InfContext);
  1127. UNREFERENCED_PARAMETER(Section);
  1128. UNREFERENCED_PARAMETER(ReturnBuffer);
  1129. UNREFERENCED_PARAMETER(ReturnBufferSize);
  1130. UNREFERENCED_PARAMETER(RequiredSize);
  1131. SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
  1132. return(FALSE);
  1133. }
  1134. #endif
  1135. BOOL
  1136. SetupGetTargetPath(
  1137. IN HINF InfHandle,
  1138. IN PINFCONTEXT InfContext, OPTIONAL
  1139. IN PCTSTR Section, OPTIONAL
  1140. OUT PTSTR ReturnBuffer, OPTIONAL
  1141. IN DWORD ReturnBufferSize,
  1142. OUT PDWORD RequiredSize OPTIONAL
  1143. )
  1144. {
  1145. BOOL b;
  1146. DWORD rc;
  1147. TCHAR returnbuffer[MAX_PATH];
  1148. DWORD requiredsize;
  1149. PCTSTR section;
  1150. if(Section) {
  1151. rc = CaptureStringArg(Section,&section);
  1152. } else {
  1153. section = NULL;
  1154. rc = NO_ERROR;
  1155. }
  1156. if(rc == NO_ERROR) {
  1157. b = _SetupGetTargetPath(InfHandle,InfContext,section,returnbuffer,MAX_PATH,&requiredsize);
  1158. rc = GetLastError();
  1159. } else {
  1160. b = FALSE;
  1161. }
  1162. if(b) {
  1163. rc = NO_ERROR;
  1164. if(RequiredSize) {
  1165. try {
  1166. *RequiredSize = requiredsize;
  1167. } except(EXCEPTION_EXECUTE_HANDLER) {
  1168. rc = ERROR_INVALID_PARAMETER;
  1169. b = FALSE;
  1170. }
  1171. }
  1172. if(rc == NO_ERROR) {
  1173. if(ReturnBuffer) {
  1174. if(requiredsize <= ReturnBufferSize) {
  1175. //
  1176. // At least on NT lstrcpy won't fault if an arg is invalid
  1177. // but it will return false.
  1178. //
  1179. if(!lstrcpy(ReturnBuffer,returnbuffer)) {
  1180. rc = ERROR_INVALID_PARAMETER;
  1181. b = FALSE;
  1182. }
  1183. } else {
  1184. rc = ERROR_INSUFFICIENT_BUFFER;
  1185. b = FALSE;
  1186. }
  1187. }
  1188. }
  1189. }
  1190. if(section) {
  1191. MyFree(section);
  1192. }
  1193. SetLastError(rc);
  1194. return(b);
  1195. }
  1196. PCTSTR
  1197. pSetupDirectoryIdToPath(
  1198. IN PCTSTR DirectoryId, OPTIONAL
  1199. IN OUT PUINT DirectoryIdInt, OPTIONAL
  1200. IN PCTSTR SubDirectory, OPTIONAL
  1201. IN PCTSTR InfSourcePath, OPTIONAL
  1202. IN OUT PCTSTR *OsLoaderPath OPTIONAL
  1203. )
  1204. /*++
  1205. (See pSetupDirectoryIdToPathEx for details.)
  1206. --*/
  1207. {
  1208. return pSetupDirectoryIdToPathEx(DirectoryId,
  1209. DirectoryIdInt,
  1210. SubDirectory,
  1211. InfSourcePath,
  1212. OsLoaderPath,
  1213. NULL
  1214. );
  1215. }
  1216. PCTSTR
  1217. pSetupDirectoryIdToPathEx(
  1218. IN PCTSTR DirectoryId, OPTIONAL
  1219. IN OUT PUINT DirectoryIdInt, OPTIONAL
  1220. IN PCTSTR SubDirectory, OPTIONAL
  1221. IN PCTSTR InfSourcePath, OPTIONAL
  1222. IN OUT PCTSTR *OsLoaderPath, OPTIONAL
  1223. OUT PBOOL VolatileSystemDirId OPTIONAL
  1224. )
  1225. /*++
  1226. Routine Description:
  1227. Translate a directory id/subdirectory pair to an actual path.
  1228. The directory ids are reserved string values that we share with Win9x (and
  1229. then some).
  1230. VOLATILE SYSTEM DIRID PATHS AND USER-DEFINED DIRID PATHS ARE NOT RETURNED
  1231. BY THIS ROUTINE!!!
  1232. Arguments:
  1233. DirectoryId - Optionally, supplies the (base-10) textual representation of
  1234. the directory ID number to use. If this parameter is not specified,
  1235. then DirectoryIdInt must be specified.
  1236. DirectoryIdInt - Optionally, supplies the address of an integer variable
  1237. that specifies, on input, the DIRID to use. This is only used if
  1238. DirectoryID is not specified. On output, if DirectoryId was used,
  1239. then this variable receives the numeric value contained in the
  1240. DirectoryId string.
  1241. SubDirectory - Optionally, supplies a subdirectory string that will be
  1242. appended with the DIRID path.
  1243. InfSourcePath - Optionally, supplies the path to be used if the ID turns
  1244. out to be DIRID_SRCPATH. If this parameter is NULL, and the SourcePath
  1245. DIRID is the one we are to use, then we use the global source path.
  1246. OsLoaderPath - Optionally, supplies the address of a string pointer containing
  1247. the OsLoader path. If the address points to a NULL string pointer, it will
  1248. be filled in with a newly-allocated character buffer containing the OsLoader
  1249. path, as retrieved from the registry. This will only be done if the DirectoryId
  1250. being used is on the system partition.
  1251. VolatileSystemDirId - Optionally, supplies the address of a boolean variable
  1252. that, upon successful return, indicates whether or not the specified
  1253. DIRID was a volatile system DIRID.
  1254. Return Value:
  1255. If successful, the return value is a pointer to a newly-allocated buffer
  1256. containing the directory path matching the specified DIRID.
  1257. THE CALLER IS RESPONSIBLE FOR FREEING THIS BUFFER!
  1258. If failure, the return value is NULL. GetLastError() returns the reason
  1259. for failure. If the failure was because the DIRID was a user-defined one,
  1260. then GetLastError() will return NO_ERROR.
  1261. --*/
  1262. {
  1263. UINT Value;
  1264. PTCHAR End;
  1265. PCTSTR FirstPart;
  1266. PTSTR Path;
  1267. UINT Length;
  1268. TCHAR Buffer[MAX_PATH];
  1269. BOOL b;
  1270. DWORD err;
  1271. if(VolatileSystemDirId) {
  1272. *VolatileSystemDirId = FALSE;
  1273. }
  1274. if(DirectoryId) {
  1275. //
  1276. // We only allow base-10 integer ids for now.
  1277. // Only the terminating nul should cause the conversion to stop.
  1278. // In any other case there were non-digits in the string.
  1279. // Also disallow the empty string.
  1280. //
  1281. Value = _tcstoul(DirectoryId, &End, 10);
  1282. if(*End || (End == DirectoryId)) {
  1283. SetLastError(ERROR_INVALID_DATA);
  1284. return(NULL);
  1285. }
  1286. if(DirectoryIdInt) {
  1287. *DirectoryIdInt = Value;
  1288. }
  1289. } else {
  1290. MYASSERT(DirectoryIdInt);
  1291. Value = *DirectoryIdInt;
  1292. }
  1293. if(!SubDirectory) {
  1294. SubDirectory = TEXT("");
  1295. }
  1296. Path = NULL;
  1297. switch(Value) {
  1298. case DIRID_NULL:
  1299. case DIRID_ABSOLUTE:
  1300. case DIRID_ABSOLUTE_16BIT:
  1301. //
  1302. // Absolute.
  1303. //
  1304. FirstPart = NULL;
  1305. break;
  1306. case DIRID_SRCPATH:
  1307. //
  1308. // If the caller supplied a path, then use it, otherwise, use our global default one.
  1309. //
  1310. if(InfSourcePath) {
  1311. FirstPart = InfSourcePath;
  1312. } else {
  1313. FirstPart = SystemSourcePath;
  1314. }
  1315. break;
  1316. case DIRID_BOOT:
  1317. case DIRID_LOADER:
  1318. //
  1319. // System partition DIRIDS
  1320. //
  1321. if(OsLoaderPath && *OsLoaderPath) {
  1322. lstrcpyn(Buffer, *OsLoaderPath, SIZECHARS(Buffer));
  1323. } else {
  1324. err = pSetupGetOsLoaderDriveAndPath(FALSE, Buffer, SIZECHARS(Buffer), &Length);
  1325. if(err) {
  1326. SetLastError(err);
  1327. return NULL;
  1328. }
  1329. if(OsLoaderPath) {
  1330. //
  1331. // allocate a buffer to return the OsLoaderPath to the caller.
  1332. //
  1333. Length *= sizeof(TCHAR); // need # bytes--not chars
  1334. if(!(*OsLoaderPath = MyMalloc(Length))) {
  1335. SetLastError(ERROR_NOT_ENOUGH_MEMORY);
  1336. return(NULL);
  1337. }
  1338. CopyMemory((PVOID)(*OsLoaderPath), Buffer, Length);
  1339. }
  1340. }
  1341. if(Value == DIRID_BOOT) {
  1342. if(Buffer[0] && Buffer[1] == TEXT(':') && Buffer[2] == TEXT('\\')) {
  1343. //
  1344. // got a simple directory to return
  1345. //
  1346. Buffer[3] = TEXT('\0'); // just want "<drive>:\" part.
  1347. } else {
  1348. //
  1349. // use OsSystemPartitionRoot instead
  1350. //
  1351. lstrcpyn(Buffer,OsSystemPartitionRoot,MAX_PATH);
  1352. }
  1353. }
  1354. FirstPart = Buffer;
  1355. break;
  1356. case DIRID_SHARED:
  1357. //
  1358. // On Win95 there is an installation mode that allows most of
  1359. // the OS to exist on a server. If the system is installed in that mode
  1360. // DIRID_SHARED is the location of the windows dir on the server.
  1361. // Otherwise it just maps to the windows dir. For now just map to
  1362. // sysroot.
  1363. //
  1364. case DIRID_WINDOWS:
  1365. //
  1366. // Windows directory
  1367. //
  1368. FirstPart = WindowsDirectory;
  1369. break;
  1370. case DIRID_SYSTEM:
  1371. //
  1372. // Windows system directory
  1373. //
  1374. FirstPart = SystemDirectory;
  1375. break;
  1376. case DIRID_DRIVERS:
  1377. //
  1378. // io subsys directory (drivers)
  1379. //
  1380. FirstPart = DriversDirectory;
  1381. break;
  1382. case DIRID_INF:
  1383. //
  1384. // inf directory
  1385. //
  1386. FirstPart = InfDirectory;
  1387. break;
  1388. case DIRID_HELP:
  1389. //
  1390. // Help directory
  1391. //
  1392. lstrcpyn(Buffer,WindowsDirectory,MAX_PATH);
  1393. pSetupConcatenatePaths(Buffer,TEXT("help"),MAX_PATH,NULL);
  1394. FirstPart = Buffer;
  1395. break;
  1396. case DIRID_FONTS:
  1397. //
  1398. // Fonts directory
  1399. //
  1400. lstrcpyn(Buffer,WindowsDirectory,MAX_PATH);
  1401. pSetupConcatenatePaths(Buffer,TEXT("fonts"),MAX_PATH,NULL);
  1402. FirstPart = Buffer;
  1403. break;
  1404. case DIRID_VIEWERS:
  1405. //
  1406. // Viewers directory
  1407. //
  1408. lstrcpyn(Buffer,SystemDirectory,MAX_PATH);
  1409. pSetupConcatenatePaths(Buffer,TEXT("viewers"),MAX_PATH,NULL);
  1410. FirstPart = Buffer;
  1411. break;
  1412. case DIRID_COLOR:
  1413. //
  1414. // ICM directory
  1415. //
  1416. lstrcpyn(Buffer, SystemDirectory, MAX_PATH);
  1417. if(OSVersionInfo.dwPlatformId == VER_PLATFORM_WIN32_NT) {
  1418. //
  1419. // On NT, the path is system32\spool\drivers\color
  1420. //
  1421. pSetupConcatenatePaths(Buffer, TEXT("spool\\drivers\\color"), MAX_PATH, NULL);
  1422. } else {
  1423. //
  1424. // On Win9x, the path is system\color
  1425. //
  1426. pSetupConcatenatePaths(Buffer, TEXT("color"), MAX_PATH, NULL);
  1427. }
  1428. FirstPart = Buffer;
  1429. break;
  1430. case DIRID_APPS:
  1431. //
  1432. // Application directory.
  1433. //
  1434. lstrcpyn(Buffer,WindowsDirectory,MAX_PATH);
  1435. Buffer[2] = 0;
  1436. FirstPart = Buffer;
  1437. break;
  1438. case DIRID_SYSTEM16:
  1439. //
  1440. // 16-bit system directory
  1441. //
  1442. FirstPart = System16Directory;
  1443. break;
  1444. case DIRID_SPOOL:
  1445. //
  1446. // spool directory
  1447. //
  1448. lstrcpyn(Buffer,SystemDirectory,MAX_PATH);
  1449. pSetupConcatenatePaths(Buffer,TEXT("spool"),MAX_PATH,NULL);
  1450. FirstPart = Buffer;
  1451. break;
  1452. case DIRID_SPOOLDRIVERS:
  1453. b = GetPrinterDriverDirectory(
  1454. NULL, // local machine
  1455. NULL, // default platform
  1456. 1, // structure level
  1457. (PVOID)Buffer,
  1458. sizeof(Buffer),
  1459. (PDWORD)&Length
  1460. );
  1461. if(!b) {
  1462. return NULL;
  1463. }
  1464. FirstPart = Buffer;
  1465. break;
  1466. case DIRID_PRINTPROCESSOR:
  1467. b = GetPrintProcessorDirectory(
  1468. NULL, // local machine
  1469. NULL, // default platform
  1470. 1, // structure level
  1471. (PVOID)Buffer,
  1472. sizeof(Buffer),
  1473. (PDWORD)&Length
  1474. );
  1475. if(!b) {
  1476. return NULL;
  1477. }
  1478. FirstPart = Buffer;
  1479. break;
  1480. case DIRID_USERPROFILE:
  1481. b = GetEnvironmentVariable (
  1482. TEXT("USERPROFILE"),
  1483. Buffer,
  1484. MAX_PATH
  1485. );
  1486. if(!b) {
  1487. //
  1488. // Can this happen?
  1489. //
  1490. return NULL;
  1491. }
  1492. FirstPart = Buffer;
  1493. break;
  1494. default:
  1495. FirstPart = NULL;
  1496. if((Value >= DIRID_USER) || (Value & VOLATILE_DIRID_FLAG)) {
  1497. //
  1498. // User-defined or volatile dirid--don't do anything with this here
  1499. // except let the caller know if it's a volatile system DIRID (if
  1500. // they requested this information).
  1501. //
  1502. if(Value < DIRID_USER && VolatileSystemDirId) {
  1503. *VolatileSystemDirId = TRUE;
  1504. }
  1505. SetLastError(NO_ERROR);
  1506. return NULL;
  1507. }
  1508. //
  1509. // Default to system32\unknown
  1510. //
  1511. if(!FirstPart) {
  1512. lstrcpyn(Buffer,SystemDirectory,MAX_PATH);
  1513. pSetupConcatenatePaths(Buffer,TEXT("unknown"),MAX_PATH,NULL);
  1514. FirstPart = Buffer;
  1515. }
  1516. break;
  1517. }
  1518. if(FirstPart) {
  1519. pSetupConcatenatePaths((PTSTR)FirstPart,SubDirectory,0,&Length);
  1520. Path = MyMalloc(Length * sizeof(TCHAR));
  1521. if(!Path) {
  1522. SetLastError(ERROR_NOT_ENOUGH_MEMORY);
  1523. return(NULL);
  1524. }
  1525. lstrcpy(Path,FirstPart);
  1526. pSetupConcatenatePaths(Path,SubDirectory,Length,NULL);
  1527. } else {
  1528. //
  1529. // Just use subdirectory.
  1530. //
  1531. Path = DuplicateString(SubDirectory);
  1532. }
  1533. //
  1534. // Make sure the path doesn't end with a \. This could happen if
  1535. // subdirectory is the empty string, etc. Don't do this, however,
  1536. // if it's a root path (e.g., 'A:\').
  1537. //
  1538. if (Path) {
  1539. Length = lstrlen(Path);
  1540. if(Length && *CharPrev(Path,Path+Length) == TEXT('\\')) {
  1541. if((Length != 3) || (Path[1] != TEXT(':'))) {
  1542. Path[Length-1] = 0;
  1543. }
  1544. }
  1545. }
  1546. return(Path);
  1547. }
  1548. PCTSTR
  1549. pGetPathFromDirId(
  1550. IN PCTSTR DirectoryId,
  1551. IN PCTSTR SubDirectory, OPTIONAL
  1552. IN PLOADED_INF pLoadedInf
  1553. )
  1554. /*
  1555. Wrapper function that merges functionality of pSetupDirectoryIdToPathEx
  1556. and pSetupVolatileDirIdToPath to return the DIRID that is needed, be it regular,
  1557. volatile or user defined.
  1558. */
  1559. {
  1560. BOOL IsVolatileDirID=FALSE;
  1561. PCTSTR ReturnPath;
  1562. UINT Value = 0;
  1563. MYASSERT(DirectoryId);
  1564. MYASSERT(pLoadedInf);
  1565. if( ReturnPath = pSetupDirectoryIdToPathEx(DirectoryId,
  1566. &Value,
  1567. SubDirectory,
  1568. pLoadedInf->InfSourcePath,
  1569. NULL,
  1570. &IsVolatileDirID) ){
  1571. return( ReturnPath );
  1572. }
  1573. if( IsVolatileDirID || (Value >= DIRID_USER) ){
  1574. ReturnPath = pSetupVolatileDirIdToPath(DirectoryId,
  1575. 0,
  1576. SubDirectory,
  1577. pLoadedInf);
  1578. return( ReturnPath );
  1579. }
  1580. // Should never happen
  1581. return NULL;
  1582. }
  1583. PCTSTR
  1584. pSetupFilenameFromLine(
  1585. IN PINFCONTEXT Context,
  1586. IN BOOL GetSourceName
  1587. )
  1588. {
  1589. return(pSetupGetField(Context,GetSourceName ? COPYSECT_SOURCE_FILENAME : COPYSECT_TARGET_FILENAME));
  1590. }
  1591. #ifdef UNICODE
  1592. //
  1593. // ANSI version
  1594. //
  1595. BOOL
  1596. SetupSetDirectoryIdExA(
  1597. IN HINF InfHandle,
  1598. IN DWORD Id, OPTIONAL
  1599. IN PCSTR Directory, OPTIONAL
  1600. IN DWORD Flags,
  1601. IN DWORD Reserved1,
  1602. IN PVOID Reserved2
  1603. )
  1604. {
  1605. BOOL b;
  1606. DWORD rc;
  1607. PCWSTR directory;
  1608. if(Directory) {
  1609. rc = pSetupCaptureAndConvertAnsiArg(Directory,&directory);
  1610. } else {
  1611. directory = NULL;
  1612. rc = NO_ERROR;
  1613. }
  1614. if(rc == NO_ERROR) {
  1615. b = SetupSetDirectoryIdExW(InfHandle,Id,directory,Flags,Reserved1,Reserved2);
  1616. rc = GetLastError();
  1617. } else {
  1618. b = FALSE;
  1619. }
  1620. if(directory) {
  1621. MyFree(directory);
  1622. }
  1623. SetLastError(rc);
  1624. return(b);
  1625. }
  1626. #else
  1627. //
  1628. // Unicode stub
  1629. //
  1630. BOOL
  1631. SetupSetDirectoryIdExW(
  1632. IN HINF InfHandle,
  1633. IN DWORD Id, OPTIONAL
  1634. IN PCWSTR Directory, OPTIONAL
  1635. IN DWORD Flags,
  1636. IN DWORD Reserved1,
  1637. IN PVOID Reserved2
  1638. )
  1639. {
  1640. UNREFERENCED_PARAMETER(InfHandle);
  1641. UNREFERENCED_PARAMETER(Id);
  1642. UNREFERENCED_PARAMETER(Directory);
  1643. UNREFERENCED_PARAMETER(Flags);
  1644. UNREFERENCED_PARAMETER(Reserved1);
  1645. UNREFERENCED_PARAMETER(Reserved2);
  1646. SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
  1647. return(FALSE);
  1648. }
  1649. #endif
  1650. BOOL
  1651. SetupSetDirectoryIdEx(
  1652. IN HINF InfHandle,
  1653. IN DWORD Id, OPTIONAL
  1654. IN PCTSTR Directory, OPTIONAL
  1655. IN DWORD Flags,
  1656. IN DWORD Reserved1,
  1657. IN PVOID Reserved2
  1658. )
  1659. /*++
  1660. Routine Description:
  1661. Associate a directory id in the user directory id range with a particular
  1662. directory. The caller can use this function prior to queueing files for
  1663. copy, for getting files copied to a target location known only at runtime.
  1664. After setting the directory ID, this routine traverses all loaded INFs in
  1665. the InfHandle's linked list, and sees if any of them have unresolved string
  1666. substitutions. If so, it attempts to re-apply string substitution to them
  1667. based on the new DIRID mapping. Thus, some INF values may change after calling
  1668. this routine.
  1669. Arguments:
  1670. Id - supplies the directory id to use for the association. This value
  1671. MUST be >= DIRID_USER or the function fails and GetLastError
  1672. returns ERROR_INVALID_PARAMETER. If an association for this id
  1673. already exists it is overwritten. If not specified (ie, 0), then
  1674. Directory is ignored, and the entire current set of user-defined
  1675. directory ids is deleted.
  1676. Directory - if specified, supplies the directory path to associate with
  1677. the given id. If not specified, any directory associated with Id
  1678. is unassociated. No error results if Id is not currently associated
  1679. with any directory.
  1680. Flags - supplies a set of flags controlling operation.
  1681. SETDIRID_NOT_FULL_PATH - indicates that the given Directory is not
  1682. a full path specification but is one or more intermediate
  1683. components in a path. Internally, the routine skips its usual
  1684. call to GetFullPathName() if this flag is set.
  1685. Return Value:
  1686. Boolean value indicating outcome. If FALSE, GetLastError() returns
  1687. extended error information:
  1688. ERROR_NOT_ENOUGH_MEMORY: a memory allocation failed
  1689. ERROR_INVALID_PARAMETER: the Id parameter is not >= DIRID_USER, or
  1690. Directory is not a valid string.
  1691. --*/
  1692. {
  1693. PCTSTR directory;
  1694. DWORD rc;
  1695. PUSERDIRID UserDirId;
  1696. UINT u;
  1697. TCHAR Buffer[MAX_PATH];
  1698. PTSTR p;
  1699. PUSERDIRID_LIST UserDirIdList;
  1700. DWORD RequiredSize;
  1701. //
  1702. // Validate Id parameter.
  1703. // Also as a special case disallow the 16-bit -1 value.
  1704. // Make sure reserved params are 0.
  1705. //
  1706. if((Id && ((Id < DIRID_USER) || (Id == DIRID_ABSOLUTE_16BIT))) || Reserved1 || Reserved2) {
  1707. SetLastError(ERROR_INVALID_PARAMETER);
  1708. return(FALSE);
  1709. }
  1710. //
  1711. // Capture directory, if specified. Ignore if Id is not specified.
  1712. //
  1713. rc = NO_ERROR;
  1714. if(Id && Directory) {
  1715. try {
  1716. directory = DuplicateString(Directory);
  1717. } except(EXCEPTION_EXECUTE_HANDLER) {
  1718. rc = ERROR_INVALID_PARAMETER;
  1719. }
  1720. } else {
  1721. directory = NULL;
  1722. }
  1723. if(rc == NO_ERROR) {
  1724. if(directory) {
  1725. if(Flags & SETDIRID_NOT_FULL_PATH) {
  1726. lstrcpyn(Buffer, directory, MAX_PATH);
  1727. MyFree(directory);
  1728. } else {
  1729. RequiredSize = GetFullPathName(directory,
  1730. SIZECHARS(Buffer),
  1731. Buffer,
  1732. &p
  1733. );
  1734. if(!RequiredSize) {
  1735. rc = GetLastError();
  1736. } else if(RequiredSize >= SIZECHARS(Buffer)) {
  1737. MYASSERT(0);
  1738. rc = ERROR_BUFFER_OVERFLOW;
  1739. }
  1740. MyFree(directory);
  1741. if(rc != NO_ERROR) {
  1742. SetLastError(rc);
  1743. return(FALSE);
  1744. }
  1745. }
  1746. directory = Buffer;
  1747. }
  1748. } else {
  1749. SetLastError(rc);
  1750. return(FALSE);
  1751. }
  1752. try {
  1753. if(!LockInf((PLOADED_INF)InfHandle)) {
  1754. rc = ERROR_INVALID_HANDLE;
  1755. }
  1756. } except(EXCEPTION_EXECUTE_HANDLER) {
  1757. rc = ERROR_INVALID_HANDLE;
  1758. }
  1759. if (rc != NO_ERROR) {
  1760. SetLastError(rc);
  1761. return(FALSE);
  1762. }
  1763. UserDirIdList = &(((PLOADED_INF)InfHandle)->UserDirIdList);
  1764. if(Id) {
  1765. //
  1766. // Got an id to use. Find any existing association for it.
  1767. //
  1768. UserDirId = NULL;
  1769. for(u = 0; u < UserDirIdList->UserDirIdCount; u++) {
  1770. if(UserDirIdList->UserDirIds[u].Id == Id) {
  1771. UserDirId = &(UserDirIdList->UserDirIds[u]);
  1772. break;
  1773. }
  1774. }
  1775. if(directory) {
  1776. if(UserDirId) {
  1777. //
  1778. // Overwrite existing association.
  1779. //
  1780. lstrcpy(UserDirId->Directory, directory);
  1781. } else {
  1782. //
  1783. // Add a new association at the end of the list.
  1784. //
  1785. UserDirId = UserDirIdList->UserDirIds
  1786. ? MyRealloc(UserDirIdList->UserDirIds,
  1787. (UserDirIdList->UserDirIdCount+1)*sizeof(USERDIRID))
  1788. : MyMalloc(sizeof(USERDIRID));
  1789. if(UserDirId) {
  1790. UserDirIdList->UserDirIds = UserDirId;
  1791. lstrcpy(UserDirIdList->UserDirIds[UserDirIdList->UserDirIdCount].Directory, directory);
  1792. UserDirIdList->UserDirIds[UserDirIdList->UserDirIdCount].Id = Id;
  1793. UserDirIdList->UserDirIdCount++;
  1794. } else {
  1795. rc = ERROR_NOT_ENOUGH_MEMORY;
  1796. }
  1797. }
  1798. } else {
  1799. //
  1800. // Need to delete any existing association we found.
  1801. //
  1802. if(UserDirId) {
  1803. //
  1804. // Close up the hole in the array.
  1805. // Note that when we get here u is the index of the
  1806. // array slot where we found the match.
  1807. //
  1808. MoveMemory(
  1809. &(UserDirIdList->UserDirIds[u]),
  1810. &(UserDirIdList->UserDirIds[u+1]),
  1811. ((UserDirIdList->UserDirIdCount-u)-1) * sizeof(USERDIRID)
  1812. );
  1813. //
  1814. // Try to shrink the array -- this really should never fail
  1815. // but we won't fail the call if it does fail for some reason.
  1816. //
  1817. if(UserDirId = MyRealloc(UserDirIdList->UserDirIds,
  1818. (UserDirIdList->UserDirIdCount-1)*sizeof(USERDIRID))) {
  1819. UserDirIdList->UserDirIds = UserDirId;
  1820. }
  1821. UserDirIdList->UserDirIdCount--;
  1822. }
  1823. }
  1824. } else {
  1825. //
  1826. // Id was not specified -- delete any set of associations.
  1827. //
  1828. if(UserDirIdList->UserDirIds) {
  1829. MyFree(UserDirIdList->UserDirIds);
  1830. UserDirIdList->UserDirIds = NULL;
  1831. UserDirIdList->UserDirIdCount = 0;
  1832. }
  1833. MYASSERT(UserDirIdList->UserDirIdCount == 0); // sanity check.
  1834. }
  1835. if(rc == NO_ERROR) {
  1836. //
  1837. // Now apply new DIRID mappings to all unresolved string substitutions
  1838. // in the loaded INFs.
  1839. //
  1840. rc = ApplyNewVolatileDirIdsToInfs((PLOADED_INF)InfHandle, NULL);
  1841. }
  1842. UnlockInf((PLOADED_INF)InfHandle);
  1843. SetLastError(rc);
  1844. return(rc == NO_ERROR);
  1845. }
  1846. BOOL
  1847. SetupSetDirectoryIdA(
  1848. IN HINF InfHandle,
  1849. IN DWORD Id, OPTIONAL
  1850. IN PCSTR Directory OPTIONAL
  1851. )
  1852. {
  1853. return(SetupSetDirectoryIdExA(InfHandle,Id,Directory,0,0,0));
  1854. }
  1855. BOOL
  1856. SetupSetDirectoryIdW(
  1857. IN HINF InfHandle,
  1858. IN DWORD Id, OPTIONAL
  1859. IN PCWSTR Directory OPTIONAL
  1860. )
  1861. {
  1862. return(SetupSetDirectoryIdExW(InfHandle,Id,Directory,0,0,0));
  1863. }
  1864. PCTSTR
  1865. pSetupVolatileDirIdToPath(
  1866. IN PCTSTR DirectoryId, OPTIONAL
  1867. IN UINT DirectoryIdInt, OPTIONAL
  1868. IN PCTSTR SubDirectory, OPTIONAL
  1869. IN PLOADED_INF Inf
  1870. )
  1871. /*++
  1872. Routine Description:
  1873. Translate a volatile system DIRID or user-defined DIRID (along with an
  1874. optional subdirectory) to an actual path.
  1875. THIS ROUTINE DOES NOT DO INF LOCKING--CALLER MUST DO IT!
  1876. Arguments:
  1877. DirectoryId - Optionally, supplies the directory id in string form. If
  1878. this parameter is not specified, then DirectoryIdInt is used directly.
  1879. DirectoryIdInst - Supplies the DIRID to find the path for. This parameter
  1880. is ignored if DirectoryId is supplied.
  1881. SubDirectory - Optionally, supplies a subdirectory to be appended to the
  1882. path specified by the given DIRID.
  1883. Inf - Supplies the address of the loaded INF structure containing the
  1884. user-defined DIRID values to use.
  1885. Return Value:
  1886. If success, a pointer to a path string is returned. The caller is
  1887. responsible for freeing this memory.
  1888. If failure, the return value is NULL, and GetLastError() indicates the
  1889. cause of failure.
  1890. --*/
  1891. {
  1892. UINT Value;
  1893. PTCHAR End;
  1894. PCTSTR FirstPart;
  1895. PTSTR Path;
  1896. UINT Length;
  1897. PUSERDIRID_LIST UserDirIdList;
  1898. TCHAR SpecialFolderPath[MAX_PATH];
  1899. if(DirectoryId) {
  1900. //
  1901. // We only allow base-10 integer ids for now.
  1902. // Only the terminating nul should cause the conversion to stop.
  1903. // In any other case there were non-digits in the string.
  1904. // Also disallow the empty string.
  1905. //
  1906. Value = _tcstoul(DirectoryId, &End, 10);
  1907. if(*End || (End == DirectoryId)) {
  1908. SetLastError(ERROR_INVALID_DATA);
  1909. return(NULL);
  1910. }
  1911. } else {
  1912. Value = DirectoryIdInt;
  1913. }
  1914. if(!SubDirectory) {
  1915. SubDirectory = TEXT("");
  1916. }
  1917. Path = NULL;
  1918. FirstPart = NULL;
  1919. if((Value < DIRID_USER) && (Value & VOLATILE_DIRID_FLAG)) {
  1920. #ifdef ANSI_SETUPAPI
  1921. {
  1922. HRESULT Result;
  1923. LPITEMIDLIST ppidl;
  1924. Result = SHGetSpecialFolderLocation (
  1925. NULL,
  1926. Value ^ VOLATILE_DIRID_FLAG,
  1927. &ppidl
  1928. );
  1929. if (SUCCEEDED (Result)) {
  1930. if (SHGetPathFromIDList (
  1931. ppidl,
  1932. SpecialFolderPath
  1933. )) {
  1934. FirstPart = SpecialFolderPath;
  1935. }
  1936. }
  1937. }
  1938. #else
  1939. //
  1940. // This is a volatile system DIRID. Presently, we only support DIRIDs
  1941. // representing shell special folders, and we chose those DIRID values
  1942. // to make it easy to convert to the CSIDL value necessary to hand into
  1943. // SHGetSpecialFolderPath.
  1944. //
  1945. if(SHGetSpecialFolderPath(NULL,
  1946. SpecialFolderPath,
  1947. (Value ^ VOLATILE_DIRID_FLAG),
  1948. TRUE // does this help?
  1949. )) {
  1950. FirstPart = SpecialFolderPath;
  1951. }
  1952. #endif
  1953. } else {
  1954. //
  1955. // This is a user-defined DIRID--look it up in our list of user DIRIDs
  1956. // presently defined.
  1957. //
  1958. UserDirIdList = &(Inf->UserDirIdList);
  1959. for(Length = 0; Length < UserDirIdList->UserDirIdCount; Length++) {
  1960. if(UserDirIdList->UserDirIds[Length].Id == Value) {
  1961. FirstPart = UserDirIdList->UserDirIds[Length].Directory;
  1962. break;
  1963. }
  1964. }
  1965. }
  1966. if(FirstPart) {
  1967. pSetupConcatenatePaths((PTSTR)FirstPart, SubDirectory, 0, &Length);
  1968. Path = MyMalloc(Length * sizeof(TCHAR));
  1969. if(!Path) {
  1970. SetLastError(ERROR_NOT_ENOUGH_MEMORY);
  1971. return NULL;
  1972. }
  1973. lstrcpy(Path, FirstPart);
  1974. pSetupConcatenatePaths(Path, SubDirectory, Length, NULL);
  1975. } else {
  1976. //
  1977. // Just use subdirectory.
  1978. //
  1979. Path = DuplicateString(SubDirectory);
  1980. }
  1981. //
  1982. // Make sure the path doesn't end with a \. This could happen if
  1983. // subdirectory is the empty string, etc.
  1984. //
  1985. if (Path) {
  1986. Length = lstrlen(Path);
  1987. if(Length && (*CharPrev(Path,Path+Length) == TEXT('\\'))) {
  1988. //
  1989. // Special case when we have a path like "A:\"--we don't want
  1990. // to strip the backslash in that scenario.
  1991. //
  1992. if((Length != 3) || (Path[1] != TEXT(':'))) {
  1993. Path[Length-1] = 0;
  1994. }
  1995. }
  1996. }
  1997. return Path;
  1998. }
  1999. VOID
  2000. InfSourcePathFromFileName(
  2001. IN PCTSTR InfFileName,
  2002. OUT PTSTR *SourcePath, OPTIONAL
  2003. OUT PBOOL TryPnf
  2004. )
  2005. /*++
  2006. Routine Description:
  2007. This routine determines whether the specified INF path is in our INF search path list,
  2008. or in %windir%, %windir%\INF, %windir%\system32, or %windir%\system. If so, then it
  2009. returns NULL. If not, then it returns a copy of our flobal source path (which must be
  2010. freed via MyFree).
  2011. Arguments:
  2012. InfFileName - Supplies the fully-qualified path to the INF.
  2013. SourcePath - Optionally, supplies the address of a variable that receives the address of
  2014. a newly-allocated buffer containing the SourcePath to use, or NULL if the default
  2015. should be used.
  2016. TryPnf - Supplies the address of a variable that is set upon return to indicate whether
  2017. or not this INF was in one of the directories in our INF search path list.
  2018. Return Value:
  2019. None.
  2020. --*/
  2021. {
  2022. TCHAR PathBuffer[MAX_PATH];
  2023. INT TempLen;
  2024. PTSTR s;
  2025. if(SourcePath) {
  2026. *SourcePath = NULL;
  2027. }
  2028. //
  2029. // First, determine if this INF is located somewhere in our search path list. If so,
  2030. // then there's nothing more to do.
  2031. //
  2032. if(!pSetupInfIsFromOemLocation(InfFileName, FALSE)) {
  2033. *TryPnf = TRUE;
  2034. return;
  2035. } else {
  2036. *TryPnf = FALSE;
  2037. if(!SourcePath) {
  2038. //
  2039. // If the caller doesn't care about the source path, then we're done.
  2040. //
  2041. return;
  2042. }
  2043. }
  2044. //
  2045. // We need to use the directory path where this INF came from as our SourcePath.
  2046. //
  2047. lstrcpy(PathBuffer, InfFileName);
  2048. s = (PTSTR)pSetupGetFileTitle(PathBuffer);
  2049. if(((s - PathBuffer) == 3) && (PathBuffer[1] == TEXT(':'))) {
  2050. //
  2051. // This path is a root path (e.g., 'A:\'), so don't strip the trailing backslash.
  2052. //
  2053. *s = TEXT('\0');
  2054. } else {
  2055. //
  2056. // Strip the trailing backslash.
  2057. //
  2058. if((s > PathBuffer) && (*CharPrev(PathBuffer,s) == TEXT('\\'))) {
  2059. s--;
  2060. }
  2061. *s = TEXT('\0');
  2062. }
  2063. //
  2064. // Next, see if this file exists in any of the following locations:
  2065. //
  2066. // %windir%
  2067. // %windir%\INF
  2068. // %windir%\system32
  2069. // %windir%\system
  2070. //
  2071. if (!lstrcmpi(PathBuffer, WindowsDirectory) ||
  2072. !lstrcmpi(PathBuffer, InfDirectory) ||
  2073. !lstrcmpi(PathBuffer, SystemDirectory) ||
  2074. !lstrcmpi(PathBuffer, System16Directory)) {
  2075. //
  2076. // It is one of the above directories--no need to use any source path
  2077. // other than the default.
  2078. //
  2079. return;
  2080. }
  2081. *SourcePath = DuplicateString(PathBuffer);
  2082. }