Source code of Windows XP (NT5)
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.

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