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.

971 lines
27 KiB

  1. /*++
  2. Copyright (c) 1996 Microsoft Corporation
  3. Module Name:
  4. fileenum.c
  5. Abstract:
  6. The code in this source file traverses a drive tree and calls
  7. an external callback function for each file. An INF can be
  8. provided to exclude files and/or directories from enumeration.
  9. Author:
  10. Jim Schmidt (jimschm) 16-Aug-1996
  11. Revision History:
  12. Marc R. Whitten (marcw) 11-Sep-1997 Tweaked exclusion handling code, removed
  13. obsolete code.
  14. Mike Condra (mikeco) 02-Jun-1996 Add fns to tap into file/path exclusion
  15. Jim Schmidt (jimschm) 20-Dec-1996 Added callback levels and made single
  16. source file for both A and W versions
  17. Jim Schmidt (jimschm) 27-Nov-1996 Added level and filter to EnumTree
  18. --*/
  19. #include "pch.h"
  20. #include "migshared.h"
  21. typedef struct {
  22. FILEENUMPROCA fnEnumCallback;
  23. FILEENUMFAILPROCA fnFailCallback;
  24. DWORD EnumID;
  25. LPVOID pParam;
  26. DWORD Levels;
  27. DWORD CurrentLevel;
  28. DWORD AttributeFilter;
  29. } ENUMSTRUCTA, *PENUMSTRUCTA;
  30. BOOL EnumTreeEngineA (LPCSTR CurrentPath, PENUMSTRUCTA pes);
  31. BOOL IsPathExcludedA (DWORD EnumID, LPCSTR Path);
  32. BOOL IsFileExcludedA (DWORD EnumID, LPCSTR File, BYTE byBitmask[]);
  33. BOOL BuildExclusionsFromInfA (DWORD EnumID, PEXCLUDEINFA ExcludeInfStruct);
  34. void CreateBitmaskA (DWORD EnumID, LPCSTR FindPattern, BYTE byBitmask[]);
  35. typedef struct {
  36. FILEENUMPROCW fnEnumCallback;
  37. FILEENUMFAILPROCW fnFailCallback;
  38. DWORD EnumID;
  39. LPVOID pParam;
  40. DWORD Levels;
  41. DWORD CurrentLevel;
  42. DWORD AttributeFilter;
  43. } ENUMSTRUCTW, *PENUMSTRUCTW;
  44. BOOL EnumTreeEngineW (LPCWSTR CurrentPath, PENUMSTRUCTW pes);
  45. BOOL IsPathExcludedW (DWORD EnumID, LPCWSTR Path);
  46. BOOL IsFileExcludedW (DWORD EnumID, LPCWSTR File, BYTE byBitmask[]);
  47. BOOL BuildExclusionsFromInfW (DWORD EnumID, PEXCLUDEINFW ExcludeInfStruct);
  48. void CreateBitmaskW (DWORD EnumID, LPCWSTR FindPattern, BYTE byBitmask[]);
  49. #ifdef UNICODE
  50. BOOL
  51. WINAPI
  52. FileEnum_Entry (
  53. IN HINSTANCE hinstDLL,
  54. IN DWORD dwReason,
  55. IN LPVOID lpv)
  56. /*++
  57. Routine Description:
  58. FileEnum_Entry is called after the C runtime is initialized, and its purpose
  59. is to initialize the globals for this process. For this LIB, it
  60. does nothing.
  61. Arguments:
  62. hinstDLL - (OS-supplied) Instance handle for the DLL
  63. dwReason - (OS-supplied) Type of initialization or termination
  64. lpv - (OS-supplied) Unused
  65. Return Value:
  66. TRUE because DLL always initializes properly.
  67. --*/
  68. {
  69. switch (dwReason)
  70. {
  71. case DLL_PROCESS_ATTACH:
  72. break;
  73. case DLL_PROCESS_DETACH:
  74. break;
  75. }
  76. return TRUE;
  77. }
  78. /*++
  79. Routine Description:
  80. GenerateEnumID maintains a static that is used to generate unique
  81. enumeration handles for callers. The enumeration handle is guaranteed to
  82. be unique for the first 2^32 calls.
  83. Arguments:
  84. none
  85. Return Value:
  86. A DWORD enumeration handle that may be used to identify an exclusion
  87. list.
  88. --*/
  89. DWORD
  90. GenerateEnumID (
  91. void
  92. )
  93. {
  94. static DWORD s_EnumID = 0;
  95. return ++s_EnumID;
  96. }
  97. #endif
  98. #ifdef UNICODE
  99. #define FILEENUMPROCT FILEENUMPROCW
  100. #define FILEENUMFAILPROCT FILEENUMFAILPROCW
  101. #define PEXCLUDEINFT PEXCLUDEINFW
  102. #define ENUMSTRUCTT ENUMSTRUCTW
  103. #define PENUMSTRUCTT PENUMSTRUCTW
  104. #define EnumerateAllDrivesT EnumerateAllDrivesW
  105. #define EnumerateTreeT EnumerateTreeW
  106. #define EnumTreeEngineT EnumTreeEngineW
  107. #define IsPathExcludedT IsPathExcludedW
  108. #define CreateBitmaskT CreateBitmaskW
  109. #define IsFileExcludedT IsFileExcludedW
  110. #define BuildExclusionsFromInfT BuildExclusionsFromInfW
  111. #define ClearExclusionsT ClearExclusionsW
  112. #define ExcludeFileT ExcludeFileW
  113. #define ExcludePathT ExcludePathW
  114. #else
  115. #define FILEENUMPROCT FILEENUMPROCA
  116. #define FILEENUMFAILPROCT FILEENUMFAILPROCA
  117. #define PEXCLUDEINFT PEXCLUDEINFA
  118. #define ENUMSTRUCTT ENUMSTRUCTA
  119. #define PENUMSTRUCTT PENUMSTRUCTA
  120. #define EnumerateAllDrivesT EnumerateAllDrivesA
  121. #define EnumerateTreeT EnumerateTreeA
  122. #define EnumTreeEngineT EnumTreeEngineA
  123. #define IsPathExcludedT IsPathExcludedA
  124. #define CreateBitmaskT CreateBitmaskA
  125. #define IsFileExcludedT IsFileExcludedA
  126. #define BuildExclusionsFromInfT BuildExclusionsFromInfA
  127. #define ClearExclusionsT ClearExclusionsA
  128. #define ExcludeFileT ExcludeFileA
  129. #define ExcludePathT ExcludePathA
  130. #endif
  131. #define MAX_DRIVES 64
  132. BOOL
  133. EnumerateAllDrivesT (
  134. IN FILEENUMPROCT fnEnumCallback,
  135. IN FILEENUMFAILPROCT fnFailCallback,
  136. IN DWORD EnumID,
  137. IN LPVOID pParam,
  138. IN PEXCLUDEINFT ExcludeInfStruct,
  139. IN DWORD AttributeFilter
  140. )
  141. /*++
  142. Routine Description:
  143. EnumerateAllDrives first builds an exclusion list if an exclusion INF path
  144. is provided, and then enumerates every file on every drive that is not
  145. excluded. The callback function is called once per file. The pParam
  146. parameter is passed to the callback.
  147. Arguments:
  148. fnEnumCallback - A pointer to your callback function
  149. EnumID - A caller-defined value used to identify the exclusion list
  150. pParam - LPVOID passed to callback function
  151. ExcludeInfStruct - Struct containing INF file information for excluding dirs or files
  152. AttributeFilter - FILTER_xxx constants
  153. Return Value:
  154. TRUE if function succeeds. Call GetLastError for error code if return
  155. value is FALSE.
  156. --*/
  157. {
  158. TCHAR LogicalDrives[MAX_DRIVES];
  159. DWORD rc;
  160. PCTSTR p;
  161. UINT driveType;
  162. rc = GetLogicalDriveStrings (
  163. MAX_DRIVES,
  164. LogicalDrives
  165. );
  166. if (!rc || rc > MAX_DRIVES) {
  167. if (rc)
  168. SetLastError (ERROR_OUTOFMEMORY);
  169. return FALSE;
  170. }
  171. for (p = LogicalDrives ; *p ; p = GetEndOfString (p) + 1) {
  172. driveType = GetDriveType(p);
  173. if (driveType == DRIVE_REMOTE || driveType == DRIVE_CDROM) {
  174. continue;
  175. }
  176. if (!EnumerateTreeT (p,
  177. fnEnumCallback,
  178. fnFailCallback,
  179. EnumID,
  180. pParam,
  181. ENUM_ALL_LEVELS,
  182. ExcludeInfStruct,
  183. AttributeFilter
  184. ))
  185. break;
  186. }
  187. return (*p == 0);
  188. }
  189. BOOL
  190. EnumerateTreeT (
  191. IN PCTSTR EnumRoot,
  192. IN FILEENUMPROCT fnEnumCallback,
  193. IN FILEENUMFAILPROCT fnFailCallback, OPTIONAL
  194. IN DWORD EnumID,
  195. IN LPVOID pParam,
  196. IN DWORD Levels,
  197. IN PEXCLUDEINFT ExcludeInfStruct, OPTIONAL
  198. IN DWORD AttributeFilter
  199. )
  200. /*++
  201. Routine Description:
  202. EnumerateTree is similar to EnumerateAllDrives, except it allows you to
  203. enumerate a specific drive, or a specific subdir on a drive. Supply the
  204. drive letter and optional subdirectory in EnumRoot. Before enumerating,
  205. EnumerateTree will first build an exclusion list if an exclusion INF path
  206. is provided. Then every file below EnumRoot is enumerated, and the
  207. callback is called once per file, passing pParam unchanged.
  208. Arguments:
  209. EnumRoot - Drive and optional path to enumerate
  210. fnEnumCallback - A pointer to your callback function
  211. fnFailCallback - A pointer to optional fn that logs enumeration errors
  212. EnumID - A caller-defined value used to identify the exclusion list
  213. pParam - LPVOID passed to callback function
  214. ExcludeInfStruct - Struct containing INF file information for excluding dirs or files
  215. AttributeFilter - FILTER_xxx constants
  216. Return Value:
  217. TRUE if function succeeds. Call GetLastError for error code if return
  218. value is FALSE.
  219. --*/
  220. {
  221. ENUMSTRUCTT es;
  222. BOOL b;
  223. if (ExcludeInfStruct)
  224. if (!BuildExclusionsFromInfT (
  225. EnumID,
  226. ExcludeInfStruct
  227. )) {
  228. DEBUGMSG ((DBG_ERROR, "Error in exclusion file"));
  229. return FALSE;
  230. }
  231. es.fnEnumCallback = fnEnumCallback;
  232. es.fnFailCallback = fnFailCallback;
  233. es.EnumID = EnumID;
  234. es.pParam = pParam;
  235. es.Levels = Levels;
  236. es.CurrentLevel = 1;
  237. es.AttributeFilter = AttributeFilter;
  238. if (!IsPathLengthOk(EnumRoot))
  239. {
  240. if (NULL != fnFailCallback)
  241. {
  242. fnFailCallback(EnumRoot);
  243. return TRUE;
  244. }
  245. }
  246. if (IsPathExcludedT (EnumID, EnumRoot))
  247. return TRUE;
  248. b = EnumTreeEngineT (EnumRoot, &es);
  249. return b;
  250. }
  251. BOOL
  252. EnumTreeEngineT (
  253. PCTSTR CurrentPath,
  254. PENUMSTRUCTT pes
  255. )
  256. {
  257. WIN32_FIND_DATA fd; // A find struct for this subdir
  258. HANDLE hFind; // A find handle for this subdir
  259. PTSTR FullFilePath; // Buffer used to build file path
  260. static TCHAR FindPattern[MAX_TCHAR_PATH * 2]; // Temp buffer used to build pattern
  261. BYTE byBitmask[MAX_PATH]; // Bitmask is used to speed exclusion lookup
  262. static DWORD Attrib; // Temp attribute storage for filter processing
  263. static INT rc; // Callback return value
  264. DWORD PrevLevelCt; // Storage for parent's max depth setting
  265. BOOL RecurseStatus;
  266. DWORD CurrentDirData = 0;
  267. //
  268. // Do nothing when CurrentPath is at the size limit.
  269. //
  270. if (!IsPathLengthOk(CurrentPath))
  271. {
  272. if (NULL != pes->fnFailCallback)
  273. {
  274. pes->fnFailCallback(CurrentPath);
  275. }
  276. return TRUE;
  277. }
  278. PrevLevelCt = pes->Levels;
  279. StringCopy (FindPattern, CurrentPath);
  280. //
  281. // Create a bitmask that tells us when subdirectories match partial
  282. // file patterns.
  283. //
  284. ZeroMemory (byBitmask, sizeof (byBitmask));
  285. CreateBitmaskT (pes->EnumID, FindPattern, byBitmask);
  286. AppendPathWack (FindPattern);
  287. StringCat (FindPattern, TEXT("*"));
  288. hFind = FindFirstFile (FindPattern, &fd);
  289. if (hFind != INVALID_HANDLE_VALUE) {
  290. do {
  291. FullFilePath = JoinPaths (CurrentPath, fd.cFileName);
  292. __try {
  293. //
  294. // Ignore this path if FullFilePath is too long
  295. // this way fd.cFileName will surely be within limits (since it's shorter)
  296. //
  297. if (!IsPathLengthOk (FullFilePath)) {
  298. if (NULL != pes->fnFailCallback) {
  299. pes->fnFailCallback(FullFilePath);
  300. }
  301. __leave;
  302. }
  303. // Filter directories named ".", "..". Set Attrib symbol.
  304. if (fd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) {
  305. if (!StringCompare (fd.cFileName, TEXT(".")) ||
  306. !StringCompare (fd.cFileName, TEXT("..")))
  307. __leave;
  308. Attrib = FILTER_DIRECTORIES;
  309. } else {
  310. Attrib = FILTER_FILES;
  311. }
  312. // Call the callback
  313. if (Attrib & pes->AttributeFilter) {
  314. rc = CALLBACK_CONTINUE;
  315. switch (Attrib) {
  316. case FILTER_DIRECTORIES:
  317. // Ignore excluded paths
  318. if (IsPathExcludedT (pes->EnumID, FullFilePath)) {
  319. break;
  320. }
  321. // Callback for 'directory first'
  322. if (!(pes->AttributeFilter & FILTER_DIRS_LAST)) {
  323. rc = pes->fnEnumCallback (
  324. FullFilePath,
  325. NULL,
  326. &fd,
  327. pes->EnumID,
  328. pes->pParam,
  329. &CurrentDirData
  330. );
  331. }
  332. if (rc >= CALLBACK_CONTINUE && pes->CurrentLevel != pes -> Levels) {
  333. // Recurse on directory
  334. pes->CurrentLevel++;
  335. RecurseStatus = EnumTreeEngineT (FullFilePath, pes);
  336. pes->CurrentLevel--;
  337. if (!RecurseStatus) {
  338. PushError();
  339. FindClose(hFind);
  340. PopError();
  341. #pragma prefast(suppress:242, "try/finally perf not an issue here")
  342. return FALSE;
  343. }
  344. }
  345. // Callback for 'directory last'
  346. if (pes->AttributeFilter & FILTER_DIRS_LAST) {
  347. rc = pes->fnEnumCallback (
  348. FullFilePath,
  349. NULL,
  350. &fd,
  351. pes->EnumID,
  352. pes->pParam,
  353. &CurrentDirData
  354. );
  355. }
  356. break;
  357. case FILTER_FILES:
  358. if (!IsFileExcludedT (pes->EnumID, FullFilePath, byBitmask)) {
  359. rc = pes->fnEnumCallback (FullFilePath,
  360. NULL,
  361. &fd,
  362. pes->EnumID,
  363. pes->pParam,
  364. &CurrentDirData
  365. );
  366. }
  367. break;
  368. }
  369. if (rc == CALLBACK_FAILED) {
  370. PushError();
  371. FindClose (hFind);
  372. PopError();
  373. #pragma prefast(suppress:242, "try/finally perf not an issue here")
  374. return FALSE;
  375. }
  376. else if (rc == CALLBACK_SUBDIR_DONE) {
  377. #pragma prefast(suppress:242, "try/finally perf not an issue here")
  378. break;
  379. }
  380. else if (rc > 0) {
  381. pes->Levels = pes->CurrentLevel + rc;
  382. }
  383. }
  384. else if (Attrib == FILTER_DIRECTORIES && !IsPathExcludedT (pes->EnumID, FullFilePath)) {
  385. // Recurse on directory.
  386. if (pes->CurrentLevel != pes -> Levels) {
  387. pes->CurrentLevel++;
  388. RecurseStatus = EnumTreeEngineT (FullFilePath, pes);
  389. pes->CurrentLevel--;
  390. if (!RecurseStatus) {
  391. PushError();
  392. FindClose(hFind);
  393. PopError();
  394. #pragma prefast(suppress:242, "try/finally perf not an issue here")
  395. return FALSE;
  396. }
  397. }
  398. }
  399. }
  400. __finally {
  401. FreePathString (FullFilePath);
  402. }
  403. } while (FindNextFile (hFind, &fd));
  404. FindClose (hFind);
  405. //
  406. // Test error code returned from FindNextFile
  407. //
  408. if (GetLastError() != ERROR_NO_MORE_FILES && GetLastError() != ERROR_SUCCESS)
  409. {
  410. //
  411. // Caller to handle not-ready message
  412. //
  413. if (GetLastError() != ERROR_NOT_READY)
  414. {
  415. DEBUGMSG((DBG_ERROR,
  416. "EnumTreeEngineT: Error from FindNextFile.\n"
  417. " FindPattern: %s\n"
  418. " Error: %u (%x)",
  419. FindPattern,
  420. GetLastError(),GetLastError()));
  421. }
  422. return FALSE;
  423. }
  424. SetLastError(ERROR_SUCCESS);
  425. }
  426. else {
  427. //
  428. // Test return codes from FindFirstFile
  429. //
  430. if (GetLastError () != ERROR_NO_MORE_FILES)
  431. {
  432. //
  433. // Caller to handle not-ready message
  434. //
  435. if (GetLastError() != ERROR_NOT_READY)
  436. {
  437. DEBUGMSG((DBG_WARNING,
  438. "EnumTreeEngineT: Warning from FindFirstFile.\n"
  439. " FindPattern: %s\n",
  440. FindPattern));
  441. }
  442. // return FALSE;
  443. }
  444. SetLastError (ERROR_SUCCESS);
  445. }
  446. // If a callback returned a positive, non-zero number, the depth
  447. // of the subdirectory search was limited for this level. Now that
  448. // this level is done, we must restore the depth value of our parent.
  449. pes->Levels = PrevLevelCt;
  450. return TRUE;
  451. }
  452. /*++
  453. A bitmask is used in IsFileExcluded for faster relative directory searches.
  454. Instead of looking in the MemDb for each part of the path, IsFileExcluded
  455. skips segments that are known not to match. We create the bitmask here
  456. by looking up each portion of FindPattern. Bit 1 is set if the last
  457. subdirectory exists in the file exclusion list, Bit 2 is set if the last
  458. two subdirectories exist in the file exclusion list, and so on.
  459. For example, assume FindPattern is set to C:\DEV\FOO\BAR. CreateBitmask
  460. first looks in the memory database for BAR\*, and if it is found bit 1 is set.
  461. Then CreateBitmask looks in the memory database for FOO\BAR\*, and sets bit
  462. 2. Again the function looks up DEV\FOO\BAR\* for bit 3 and finally
  463. C:\DEV\FOO\BAR\* for bit 4.
  464. Bit 0 is always set (empty paths always match).
  465. Once this bitmask is set up, IsFileExcluded can test only the patterns that
  466. are known to exist.
  467. --*/
  468. void
  469. CreateBitmaskT (
  470. DWORD EnumID,
  471. PCTSTR FindPattern,
  472. BYTE byBitmask[]
  473. )
  474. {
  475. TCHAR EnumPath[MAX_TCHAR_PATH * 2];
  476. TCHAR ShortPath[MAX_TCHAR_PATH * 2];
  477. PCTSTR p;
  478. PTSTR End;
  479. int nByte;
  480. int nBitVal;
  481. // Always set bit 0
  482. byBitmask[0] |= 1;
  483. // Build full file spec
  484. wsprintf (
  485. EnumPath,
  486. TEXT("%s\\%X\\%s\\"),
  487. MEMDB_CATEGORY_FILEENUM,
  488. EnumID,
  489. MEMDB_FIELD_FE_FILES
  490. );
  491. End = GetEndOfString (EnumPath);
  492. StringCopy (End, FindPattern);
  493. AppendPathWack (End);
  494. StringCat (End, TEXT("*"));
  495. // Start with last subdirectory, and build mask in reverse
  496. p = _tcsrchr (EnumPath, TEXT('\\'));
  497. nByte = 0;
  498. nBitVal = 2;
  499. do {
  500. // Move back to previous backslash
  501. for (p = _tcsdec (EnumPath, p) ;
  502. p >= End && *p != TEXT('\\') ;
  503. p = _tcsdec (EnumPath, p))
  504. {
  505. }
  506. // Check if partial file is in the tree
  507. wsprintf (
  508. ShortPath,
  509. TEXT("%s\\%X\\%s%s"),
  510. MEMDB_CATEGORY_FILEENUM,
  511. EnumID,
  512. MEMDB_FIELD_FE_FILES,
  513. p
  514. );
  515. if (MemDbGetPatternValueWithPattern (ShortPath, NULL))
  516. byBitmask[nByte] |= nBitVal;
  517. // Inc bit pos
  518. nBitVal *= 2;
  519. if (nBitVal == 256) {
  520. nBitVal = 1;
  521. nByte++;
  522. }
  523. } while (p > End);
  524. }
  525. BOOL
  526. IsPathExcludedT (DWORD EnumID, PCTSTR Path)
  527. {
  528. TCHAR EnumPath[MAX_TCHAR_PATH * 2];
  529. TCHAR ShortPath[MAX_TCHAR_PATH * 2];
  530. PCTSTR p;
  531. PTSTR End;
  532. // Try full paths
  533. wsprintf (
  534. EnumPath,
  535. TEXT("%s\\%X\\%s\\"),
  536. MEMDB_CATEGORY_FILEENUM,
  537. EnumID,
  538. MEMDB_FIELD_FE_PATHS
  539. );
  540. End = GetEndOfString (EnumPath);
  541. p = _tcsappend (End, Path);
  542. if (MemDbGetPatternValue (EnumPath, NULL)) {
  543. return TRUE;
  544. }
  545. // Try partial paths
  546. do {
  547. // Move back to previous backslash
  548. for (p = _tcsdec (EnumPath, p) ;
  549. p > End && (*p != TEXT('\\')) ;
  550. p = _tcsdec (EnumPath, p))
  551. {
  552. }
  553. // Check if partial path is in the tree
  554. if (p > End && p[1]) {
  555. wsprintf (
  556. ShortPath,
  557. TEXT("%s\\%X\\%s%s"),
  558. MEMDB_CATEGORY_FILEENUM,
  559. EnumID,
  560. MEMDB_FIELD_FE_PATHS,
  561. p
  562. );
  563. if (MemDbGetPatternValue (ShortPath, NULL)) {
  564. return TRUE;
  565. }
  566. }
  567. } while (p > End);
  568. return FALSE;
  569. }
  570. BOOL
  571. IsFileExcludedT (DWORD EnumID, PCTSTR File, BYTE byBitmask[])
  572. {
  573. TCHAR EnumPath[MAX_TCHAR_PATH * 2];
  574. TCHAR ShortPath[MAX_TCHAR_PATH * 2];
  575. PCTSTR p;
  576. PTSTR End;
  577. int nByte;
  578. int nBit;
  579. // Build full file spec
  580. wsprintf (
  581. EnumPath,
  582. TEXT("%s\\%X\\%s\\"),
  583. MEMDB_CATEGORY_FILEENUM,
  584. EnumID,
  585. MEMDB_FIELD_FE_FILES
  586. );
  587. End = GetEndOfString (EnumPath);
  588. p = _tcsappend (End, File);
  589. //
  590. // Try partial file specs until full spec is reached
  591. //
  592. nByte = 0;
  593. nBit = 1;
  594. do {
  595. //
  596. // Move back to previous backslash in path
  597. // (p starts at NULL of EnumPath, End is in the middle of EnumPath)
  598. //
  599. for (p = _tcsdec (EnumPath, p) ;
  600. p >= End && (*p != TEXT('\\')) ;
  601. p = _tcsdec (EnumPath, p))
  602. {
  603. }
  604. // Bitmask is used to make sure slightly expensive query is necessary
  605. if (byBitmask[nByte] & nBit) {
  606. //
  607. // Check if partial file is in the tree
  608. //
  609. wsprintf (
  610. ShortPath,
  611. TEXT("%s\\%X\\%s%s"),
  612. MEMDB_CATEGORY_FILEENUM,
  613. EnumID,
  614. MEMDB_FIELD_FE_FILES,
  615. p
  616. );
  617. if (MemDbGetPatternValue (ShortPath, NULL)) {
  618. return TRUE;
  619. }
  620. }
  621. nBit *= 2;
  622. if (nBit == 256) {
  623. nBit = 1;
  624. nByte++;
  625. }
  626. } while (p > End);
  627. return FALSE;
  628. }
  629. //
  630. // ClearExclusions removes all enumaration exclusions. It is called
  631. // automatically at the end of enumeration when an exclusion INF file is
  632. // used. Use it when you need to programmatically build an exclusion list
  633. // with ExcludeDrive, ExcludePath, and ExcludeFile.
  634. //
  635. // You can combine programmatic exclusions with an exclusion INF file, but
  636. // beware that the programmatic exclusions will be cleared after
  637. // EnumarteAllDrives or EnumerateTree completes.
  638. //
  639. // If you do not use an INF, the programmatic exclusions will not
  640. // automatically be cleared.
  641. //
  642. // EnumID - Caller-defined value to identify enumeration exclusion list
  643. //
  644. VOID
  645. ClearExclusionsT (
  646. DWORD EnumID
  647. )
  648. {
  649. TCHAR EnumPath[MAX_TCHAR_PATH * 2];
  650. wsprintf (EnumPath, TEXT("%s\\%X"), MEMDB_CATEGORY_FILEENUM, EnumID);
  651. MemDbDeleteTree (EnumPath);
  652. }
  653. /*++
  654. Routine Description:
  655. ExcludePath adds a path name to the exclusion list. There are two
  656. cases:
  657. 1. A full path spec is supplied, including the drive letter or
  658. UNC double-backslash.
  659. 2. The path does not start with a drive letter and is a portion of
  660. a full path.
  661. The dot and double-dot directories are not supported. Any part of
  662. the path may contain wildcard characters, but a wildcard can not
  663. be used in place of a backslash.
  664. Arguments:
  665. EnumID - A caller-defined value that identifies the exclusion list
  666. Path - The path specification as described above
  667. Return Value:
  668. none
  669. --*/
  670. VOID
  671. ExcludePathT (
  672. IN DWORD EnumID,
  673. IN PCTSTR Path
  674. )
  675. {
  676. TCHAR EnumPath[MAX_TCHAR_PATH * 2];
  677. wsprintf (
  678. EnumPath,
  679. TEXT("%s\\%X\\%s\\%s"),
  680. MEMDB_CATEGORY_FILEENUM,
  681. EnumID,
  682. MEMDB_FIELD_FE_PATHS,
  683. Path
  684. );
  685. MemDbSetValue (EnumPath, 0);
  686. }
  687. /*++
  688. Routine Description:
  689. ExcludeFile adds a file spec to the exclusion list. There are two
  690. cases:
  691. 1. A full path spec is supplied, including the drive letter or
  692. UNC double-backslash.
  693. 2. The path does not start with a drive letter and is a portion of
  694. a full path.
  695. The dot and double-dot directories are not supported. Any part of
  696. the path may contain wildcard characters, but a wildcard can not
  697. be used in place of a backslash.
  698. Arguments:
  699. EnumID - A caller-defined value that identifies the exclusion list
  700. File - The file specification as described above
  701. Return Value:
  702. none
  703. --*/
  704. VOID
  705. ExcludeFileT (
  706. IN DWORD EnumID,
  707. IN PCTSTR File
  708. )
  709. {
  710. TCHAR EnumPath[MAX_TCHAR_PATH * 2];
  711. wsprintf (
  712. EnumPath,
  713. TEXT("%s\\%X\\%s\\%s"),
  714. MEMDB_CATEGORY_FILEENUM,
  715. EnumID,
  716. MEMDB_FIELD_FE_FILES,
  717. File
  718. );
  719. MemDbSetValue (EnumPath, 0);
  720. }
  721. BOOL
  722. BuildExclusionsFromInfT (DWORD EnumID,
  723. PEXCLUDEINFT ExcludeInfStruct)
  724. {
  725. HINF hInf;
  726. INFCONTEXT ic;
  727. TCHAR Exclude[MAX_TCHAR_PATH * 2];
  728. // Attempt to open
  729. hInf = SetupOpenInfFile (ExcludeInfStruct->ExclusionInfPath, NULL, INF_STYLE_WIN4, NULL);
  730. if (hInf == INVALID_HANDLE_VALUE)
  731. return FALSE;
  732. // Read in path exclusions
  733. if (ExcludeInfStruct->PathSection) {
  734. if (SetupFindFirstLine (hInf, ExcludeInfStruct->PathSection, NULL, &ic)) {
  735. do {
  736. if (SetupGetStringField (&ic, 1, Exclude, MAX_TCHAR_PATH, NULL)) {
  737. ExcludePathT (EnumID, Exclude);
  738. }
  739. } while (SetupFindNextLine (&ic, &ic));
  740. }
  741. }
  742. // Read in file exclusions
  743. if (ExcludeInfStruct->FileSection) {
  744. if (SetupFindFirstLine (hInf, ExcludeInfStruct->FileSection, NULL, &ic)) {
  745. do {
  746. if (SetupGetStringField (&ic, 1, Exclude, MAX_TCHAR_PATH, NULL)) {
  747. ExcludeFileT (EnumID, Exclude);
  748. }
  749. } while (SetupFindNextLine (&ic, &ic));
  750. }
  751. }
  752. // Clean up
  753. SetupCloseInfFile (hInf);
  754. return TRUE;
  755. }