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.

591 lines
19 KiB

  1. //+------------------------------------------------------------------
  2. //
  3. // Copyright (C) 1995, Microsoft Corporation.
  4. //
  5. // File: FileEnum.cxx
  6. //
  7. // Contents: class encapsulating file enumeration, including a deep option
  8. //
  9. // Classes: CFileEnumeration
  10. //
  11. // History: Nov-93 DaveMont Created.
  12. //
  13. //-------------------------------------------------------------------
  14. #include <t2.hxx>
  15. #include <FileEnum.hxx>
  16. #if DBG
  17. extern ULONG Debug;
  18. #endif
  19. //+---------------------------------------------------------------------------
  20. //
  21. // Member: CFileEnumerate::CFileEnumerate, public
  22. //
  23. // Synopsis: initializes data members, constructor will not throw
  24. //
  25. // Arguments: IN [fdeep] - TRUE = go into sub-directories
  26. //
  27. //----------------------------------------------------------------------------
  28. CFileEnumerate::CFileEnumerate(BOOL fdeep)
  29. : _fdeep(fdeep),
  30. _findeep(FALSE),
  31. _froot(FALSE),
  32. _fcannotaccess(FALSE),
  33. _pcfe(NULL),
  34. _pwfileposition(NULL),
  35. _handle(INVALID_HANDLE_VALUE)
  36. {
  37. ENUMERATE_RETURNS((stderr, "CFileEnumerate ctor\n"))
  38. }
  39. //+---------------------------------------------------------------------------
  40. //
  41. // Member: Dtor, public
  42. //
  43. // Synopsis: closes handles
  44. //
  45. // Arguments: none
  46. //
  47. //----------------------------------------------------------------------------
  48. CFileEnumerate::~CFileEnumerate()
  49. {
  50. if (_handle != INVALID_HANDLE_VALUE)
  51. FindClose(_handle);
  52. ENUMERATE_RETURNS((stderr, "CFileEnumerate dtor (%ws)\n", _wpath))
  53. }
  54. //+---------------------------------------------------------------------------
  55. //
  56. // Member: CFileEnumerate::Init, public
  57. //
  58. // Synopsis: Init must be called before any other methods - this
  59. // is not enforced. converts a ASCII file/path to a UNICODE
  60. // file/path, and gets the first file in the enumeration
  61. //
  62. // Arguments: IN [filename] - the path/file to enumerate
  63. // OUT [wfilename] - first file in the enumeration
  64. // OUT [fdir] - TRUE = returned file is a directory
  65. //
  66. //----------------------------------------------------------------------------
  67. ULONG CFileEnumerate::Init(CHAR *filename, WCHAR **wfilename, BOOL *fdir)
  68. {
  69. // Initialize the file name
  70. if (filename && (strlen(filename) < MAX_PATH))
  71. {
  72. // make it wchar
  73. WCHAR winfilename[MAX_PATH];
  74. if (MultiByteToWideChar(CP_ACP, MB_PRECOMPOSED,
  75. filename, -1,
  76. winfilename, sizeof(winfilename) / sizeof(winfilename[0])) == 0)
  77. return(ERROR_INVALID_NAME);
  78. // finish initialization
  79. return(_ialize(winfilename, wfilename, fdir));
  80. }
  81. ENUMERATE_FAIL((stderr, "Init bad file name: %ld\n",ERROR_INVALID_NAME))
  82. return(ERROR_INVALID_NAME);
  83. }
  84. //+---------------------------------------------------------------------------
  85. //
  86. // Member: CFileEnumerate::Init, public
  87. //
  88. // Synopsis: Same as previous, except takes UNICODE file/path as input
  89. //
  90. // Arguments: IN [filename] - the path/file to enumerate
  91. // OUT [wfilename] - first file in the enumeration
  92. // OUT [fdir] - TRUE = returned file is a directory
  93. //
  94. //----------------------------------------------------------------------------
  95. ULONG CFileEnumerate::Init(WCHAR *filename, WCHAR **wfilename, BOOL *fdir)
  96. {
  97. // Initialize the file name
  98. if (filename && (wcslen(filename) < MAX_PATH))
  99. {
  100. return(_ialize(filename, wfilename, fdir));
  101. }
  102. ENUMERATE_FAIL((stderr, "Init bad file name: %ld\n",ERROR_INVALID_NAME))
  103. return(ERROR_INVALID_NAME);
  104. }
  105. //+---------------------------------------------------------------------------
  106. //
  107. // Member: CFileEnumerate::_ialize, private
  108. //
  109. // Synopsis: finishes initialization and starts search for first file in
  110. // the enumeration
  111. //
  112. // Arguments: OUT [wfilename] - first file in the enumeration
  113. // OUT [fdir] - TRUE = returned file is a directory
  114. //
  115. //----------------------------------------------------------------------------
  116. ULONG CFileEnumerate::_ialize(WCHAR *winfilename, WCHAR **wfilename, BOOL *fdir)
  117. {
  118. ENUMERATE_RETURNS((stderr, "Init start, path = %ws\n", winfilename))
  119. ULONG ret = ERROR_SUCCESS;
  120. ENUMERATE_STAT((stderr, "start path = %ws\n",winfilename))
  121. // save the location of the filename or wildcards
  122. ULONG cwcharcount;
  123. if (!(cwcharcount = GetFullPathName(winfilename,
  124. MAX_PATH,
  125. _wpath,
  126. &_pwfileposition)))
  127. {
  128. return(ERROR_INVALID_NAME);
  129. }
  130. ENUMERATE_STAT((stderr, "got full path name = %ws, filename = (%ws), total chars = %d\n",_wpath, _pwfileposition, cwcharcount))
  131. // if the filepart (_pwfileposition) is NULL, then the name must end in a slash.
  132. // add a *
  133. if (NULL == _pwfileposition)
  134. {
  135. _pwfileposition = (WCHAR *)Add2Ptr(_wpath,wcslen(_wpath)*sizeof(WCHAR));
  136. }
  137. // save the filename/wildcards
  138. wcscpy(_wwildcards, _pwfileposition);
  139. ENUMERATE_EXTRA((stderr, "wild cards = %ws\n",_wwildcards))
  140. // if we are at a root (path ends in :\)
  141. if ( (_wpath[wcslen(_wpath) - 1] == L'\\') &&
  142. (wcslen(_wpath) > 1) &&
  143. (_wpath[wcslen(_wpath) - 2] == L':') )
  144. {
  145. _wfd.dwFileAttributes = FILE_ATTRIBUTE_DIRECTORY;
  146. _wfd.cFileName[0] = L'\0';
  147. *wfilename = _wpath;
  148. *fdir = TRUE;
  149. _froot = TRUE;
  150. } else
  151. {
  152. // check to see if we can iterate through files
  153. if ( (INVALID_HANDLE_VALUE == ( _handle = FindFirstFile(_wpath, &_wfd) ) ) )
  154. {
  155. ret = GetLastError();
  156. _fcannotaccess = (ERROR_ACCESS_DENIED == ret);
  157. ENUMERATE_FAIL((stderr, "find first returned: %ld\n",ret))
  158. }
  159. if (ERROR_SUCCESS == ret)
  160. {
  161. // reject . & .. filenames (go on to next file )
  162. if ( (0 == wcscmp(_wfd.cFileName, L".")) ||
  163. (0 == wcscmp(_wfd.cFileName, L"..")) )
  164. {
  165. ret = _NextLocal(wfilename,fdir);
  166. } else
  167. {
  168. // return the current directory
  169. if (_wfd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
  170. *fdir = TRUE;
  171. else
  172. *fdir = FALSE;
  173. // add the filename to the path so the whole thing is returned
  174. //_pwfileposition is pointer to postion of file in _wpath. _wpath is
  175. //MAX_PATH long. MAX_PATH - (_pwfileposition - _wpath) is the length of
  176. //buffer _pwfileposition
  177. //
  178. HRESULT hr = StringCchCopy((LPWSTR)_pwfileposition,MAX_PATH - (_pwfileposition- _wpath), (LPCWSTR )_wfd.cFileName);
  179. if(FAILED(hr))
  180. {
  181. return HRESULT_CODE(hr);
  182. }
  183. *wfilename = _wpath;
  184. }
  185. }
  186. ENUMERATE_STAT((stderr, "next filename = %ws\n", *wfilename))
  187. }
  188. // if we are going deep and we did not find a file yet:
  189. if ( _fdeep && ( ( ERROR_NO_MORE_FILES == ret ) ||
  190. ( ERROR_FILE_NOT_FOUND == ret ) ) )
  191. {
  192. if (_handle != INVALID_HANDLE_VALUE)
  193. {
  194. FindClose(_handle);
  195. _handle = INVALID_HANDLE_VALUE;
  196. }
  197. ret = _InitDir(wfilename, fdir);
  198. }
  199. ENUMERATE_RETURNS((stderr, "Init returning = %ws(%ld)\n\n", *wfilename, ret))
  200. return(ret);
  201. }
  202. //+---------------------------------------------------------------------------
  203. //
  204. // Member: CFileEnumerate::Next, public
  205. //
  206. // Synopsis: finds the next file in the enumeration
  207. //
  208. // Arguments: OUT [wfilename] - first file in the enumeration
  209. // OUT [fdir] - TRUE = returned file is a directory
  210. //
  211. //----------------------------------------------------------------------------
  212. ULONG CFileEnumerate::Next(WCHAR **wfilename, BOOL *fdir)
  213. {
  214. ENUMERATE_RETURNS((stderr, "Next start, path = %ws\n", _wpath))
  215. ULONG ret = ERROR_NO_MORE_FILES;
  216. // if we failed to initialize with an ERROR_ACCESS_DENIED, then exit
  217. if (_fcannotaccess)
  218. return(ERROR_NO_MORE_FILES);
  219. // if we are not in deep
  220. if (!_findeep)
  221. {
  222. if (!_froot)
  223. ret = _NextLocal(wfilename, fdir);
  224. // if we ran out of files and we are going deep:
  225. if ( _fdeep &&
  226. ( ( ERROR_NO_MORE_FILES == ret ) ||
  227. ( ERROR_FILE_NOT_FOUND == ret ) || _froot ) )
  228. {
  229. if (_handle != INVALID_HANDLE_VALUE)
  230. {
  231. FindClose(_handle);
  232. _handle = INVALID_HANDLE_VALUE;
  233. }
  234. ret = _InitDir(wfilename, fdir);
  235. _froot = FALSE; // (we are past the root now)
  236. }
  237. } else
  238. {
  239. // if we are already down a directory (and in deep)
  240. if (_pcfe)
  241. {
  242. if (ERROR_SUCCESS != (ret = _pcfe->Next(wfilename, fdir)))
  243. {
  244. if (ERROR_ACCESS_DENIED != ret)
  245. {
  246. delete _pcfe;
  247. _pcfe = NULL;
  248. }
  249. }
  250. }
  251. // we need to go to the next directory in the current dir
  252. if (ERROR_NO_MORE_FILES == ret)
  253. {
  254. ret = _NextDir(wfilename, fdir);
  255. }
  256. }
  257. ENUMERATE_RETURNS((stderr, "Next returning = %ws(%ld)\n\n", *wfilename, ret))
  258. return(ret);
  259. }
  260. //+---------------------------------------------------------------------------
  261. //
  262. // Member: CFileEnumerate::_NextLocal, private
  263. //
  264. // Synopsis: searchs for the next file in the current directory
  265. //
  266. // Arguments: OUT [wfilename] - first file in the enumeration
  267. // OUT [fdir] - TRUE = returned file is a directory
  268. //
  269. //----------------------------------------------------------------------------
  270. ULONG CFileEnumerate::_NextLocal(WCHAR **wfilename, BOOL *fdir)
  271. {
  272. ENUMERATE_RETURNS((stderr, "_NextLocal start, path = %ws\n", _wpath))
  273. ULONG ret = ERROR_SUCCESS;
  274. // ensure that we have a valid handle for a findnextfile
  275. if (INVALID_HANDLE_VALUE == _handle)
  276. {
  277. ret = ERROR_INVALID_HANDLE;
  278. } else
  279. {
  280. do
  281. {
  282. if (!FindNextFile(_handle, &_wfd))
  283. {
  284. ret = GetLastError();
  285. ENUMERATE_FAIL((stderr, "find next returned: %ld\n",ret))
  286. } else
  287. ret = ERROR_SUCCESS;
  288. }
  289. while ( (ERROR_SUCCESS == ret) &&
  290. ( (0 == wcscmp(_wfd.cFileName, L".")) ||
  291. (0 == wcscmp(_wfd.cFileName, L"..")) ) );
  292. // if we found a file
  293. if (ERROR_SUCCESS == ret)
  294. {
  295. // return the directory attrib.
  296. if (_wfd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
  297. *fdir = TRUE;
  298. else
  299. *fdir = FALSE;
  300. // add the filename to the path so the whole thing is returned
  301. //_pwfileposition is pointer to postion of file in _wpath. _wpath is
  302. //MAX_PATH long. MAX_PATH - (_pwfileposition - _wpath) is the length of
  303. //buffer _pwfileposition
  304. //
  305. HRESULT hr = StringCchCopy((LPWSTR)_pwfileposition,
  306. MAX_PATH - (_pwfileposition- _wpath),
  307. (const wchar_t*)_wfd.cFileName);
  308. if(FAILED(hr))
  309. {
  310. return HRESULT_CODE(hr);
  311. }
  312. *wfilename = _wpath;
  313. ENUMERATE_STAT((stderr, "next filename = %ws\n", *wfilename))
  314. }
  315. }
  316. ENUMERATE_RETURNS((stderr, "_NextLocal returning = %ws(%ld)\n", *wfilename, ret))
  317. return(ret);
  318. }
  319. //+---------------------------------------------------------------------------
  320. //
  321. // Member: CFileEnumerate::_InitDir, private
  322. //
  323. // Synopsis: (only called if going deep)
  324. // goes down a directory (and thus causing a new CFileEnumerator
  325. // to be created, or re-initializies
  326. //
  327. // Arguments: OUT [wfilename] - first file in the enumeration
  328. // OUT [fdir] - TRUE = returned file is a directory
  329. //
  330. //----------------------------------------------------------------------------
  331. ULONG CFileEnumerate::_InitDir(WCHAR **wfilename, BOOL *fdir)
  332. {
  333. ENUMERATE_RETURNS((stderr, "_InitDir start, path = %ws\n", _wpath))
  334. ULONG ret = ERROR_SUCCESS;
  335. // check and see if a directory was entered as the filename
  336. if ( (0 == _wcsicmp(_wwildcards, _wfd.cFileName)) &&
  337. (_wfd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) )
  338. {
  339. ENUMERATE_EXTRA((stderr, "first file matched directory = %ws\n", _wpath))
  340. _pwfileposition += wcslen(_wfd.cFileName);
  341. //_pwfileposition is pointer to postion of file in _wpath. _wpath is
  342. //MAX_PATH long. MAX_PATH - (_pwfileposition - _wpath) is the length of
  343. //buffer _pwfileposition
  344. //
  345. HRESULT hr = StringCchCopy((LPWSTR)_pwfileposition,
  346. MAX_PATH - (_pwfileposition- _wpath),
  347. L"\\*.*");
  348. if(FAILED(hr))
  349. {
  350. return HRESULT_CODE(hr);
  351. }
  352. _pwfileposition++;
  353. wcscpy(_wwildcards, L"*.*");
  354. ENUMERATE_EXTRA((stderr, " path = %ws\n",_wpath))
  355. ENUMERATE_EXTRA((stderr, "wild cards = %ws\n",_wwildcards))
  356. WCHAR winfilename[MAX_PATH];
  357. hr = StringCchCopy((LPWSTR)winfilename,
  358. MAX_PATH,
  359. _wpath);
  360. if(FAILED(hr))
  361. {
  362. return HRESULT_CODE(hr);
  363. }
  364. ret = _ialize(winfilename, wfilename, fdir);
  365. } else
  366. {
  367. // we are in deep
  368. _findeep = TRUE;
  369. // search thru all directories
  370. //_pwfileposition is pointer to postion of file in _wpath. _wpath is
  371. //MAX_PATH long. MAX_PATH - (_pwfileposition - _wpath) is the length of
  372. //buffer _pwfileposition
  373. //
  374. HRESULT hr = StringCchCopy((LPWSTR)_pwfileposition,
  375. MAX_PATH - (_pwfileposition- _wpath),
  376. L"*.*");
  377. if(FAILED(hr))
  378. {
  379. return HRESULT_CODE(hr);
  380. }
  381. if (INVALID_HANDLE_VALUE == ( _handle = FindFirstFile(_wpath, &_wfd) ))
  382. {
  383. ret = GetLastError();
  384. ENUMERATE_FAIL((stderr, "find first (dir) returned: %ld\n",ret))
  385. } else
  386. {
  387. if ( !(_wfd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) ||
  388. (0 == wcscmp(_wfd.cFileName, L".")) ||
  389. (0 == wcscmp(_wfd.cFileName, L"..")) )
  390. {
  391. ret = _NextDir(wfilename, fdir);
  392. } else
  393. {
  394. // if we have a sub directory, go down it
  395. ret = _DownDir(wfilename, fdir);
  396. // if we found nothing in that first sub directory, go the the next one
  397. if ( (ERROR_NO_MORE_FILES == ret ) ||
  398. (ERROR_FILE_NOT_FOUND == ret ) )
  399. {
  400. ret = _NextDir(wfilename, fdir);
  401. }
  402. }
  403. }
  404. }
  405. ENUMERATE_RETURNS((stderr, "_InitDir returning = %ws(%ld)\n", *wfilename, ret))
  406. return(ret);
  407. }
  408. //+---------------------------------------------------------------------------
  409. //
  410. // Member: CFileEnumerate::_NextDir, private
  411. //
  412. // Synopsis: (only called if going deep)
  413. // finds the next sub-directory from the current directory,
  414. // and then goes down into that directory
  415. //
  416. // Arguments: OUT [wfilename] - first file in the enumeration
  417. // OUT [fdir] - TRUE = returned file is a directory
  418. //
  419. //----------------------------------------------------------------------------
  420. ULONG CFileEnumerate::_NextDir(WCHAR **wfilename, BOOL *fdir)
  421. {
  422. ENUMERATE_RETURNS((stderr, "_NextDir start, path = %ws\n", _wpath))
  423. ULONG ret = ERROR_SUCCESS;
  424. // skip the . & .. & files we cannot access
  425. if (INVALID_HANDLE_VALUE == _handle)
  426. {
  427. ret = ERROR_INVALID_HANDLE;
  428. } else
  429. {
  430. do
  431. {
  432. do
  433. {
  434. if (!FindNextFile(_handle, &_wfd))
  435. {
  436. ret = GetLastError();
  437. ENUMERATE_FAIL((stderr, "find next returned: %ld\n",ret))
  438. } else
  439. ret = ERROR_SUCCESS;
  440. }
  441. while ( (ERROR_SUCCESS == ret) &&
  442. ( !(_wfd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) ||
  443. (0 == wcscmp(_wfd.cFileName, L".")) ||
  444. (0 == wcscmp(_wfd.cFileName, L"..")) ) );
  445. // if we found a directory
  446. if (ERROR_SUCCESS == ret)
  447. {
  448. ret = _DownDir(wfilename, fdir);
  449. } else
  450. {
  451. // out of subdirectories to search, break out of the loop
  452. break;
  453. }
  454. }
  455. while (( ERROR_NO_MORE_FILES == ret) || (ERROR_FILE_NOT_FOUND == ret));
  456. }
  457. ENUMERATE_RETURNS((stderr, "_NextDir returning = %ws(%ld)\n", *wfilename, ret))
  458. return(ret);
  459. }
  460. //+---------------------------------------------------------------------------
  461. //
  462. // Member: CFileEnumerate::_DownDir, private
  463. //
  464. // Synopsis: (only called if going deep)
  465. // creates a new CFileEnumerator for a sub-directory
  466. //
  467. // Arguments: OUT [wfilename] - first file in the enumeration
  468. // OUT [fdir] - TRUE = returned file is a directory
  469. //
  470. //----------------------------------------------------------------------------
  471. ULONG CFileEnumerate::_DownDir(WCHAR **wfilename, BOOL *fdir)
  472. {
  473. ENUMERATE_RETURNS((stderr, "_DownDir start, path = %ws\n", _wpath))
  474. ULONG ret;
  475. // make a new file enumerator class (this one) We should only go down
  476. // 8 directories at most.
  477. _pcfe = new CFileEnumerate(_fdeep);
  478. if (!_pcfe)
  479. return ERROR_NOT_ENOUGH_MEMORY;
  480. // add the wildcards to the end of the directory we are going down
  481. //_pwfileposition is pointer to postion of file in _wpath. _wpath is
  482. //MAX_PATH long. MAX_PATH - (_pwfileposition - _wpath) is the length of
  483. //buffer _pwfileposition
  484. //
  485. HRESULT hr = StringCchCopy((LPWSTR)_pwfileposition,
  486. MAX_PATH - (_pwfileposition- _wpath),
  487. ( const wchar_t *)_wfd.cFileName);
  488. if(FAILED(hr))
  489. {
  490. return HRESULT_CODE(hr);
  491. }
  492. hr = StringCchCat(_wpath,MAX_PATH,L"\\");
  493. if(FAILED(hr))
  494. {
  495. return HRESULT_CODE(hr);
  496. }
  497. hr = StringCchCat(_wpath,MAX_PATH, _wwildcards);
  498. if(FAILED(hr))
  499. {
  500. return HRESULT_CODE(hr);
  501. }
  502. // start it up and see if we find a match
  503. if (ERROR_SUCCESS != (ret = _pcfe->Init(_wpath, wfilename, fdir)))
  504. {
  505. if (ERROR_ACCESS_DENIED != ret)
  506. {
  507. delete _pcfe;
  508. _pcfe = NULL;
  509. }
  510. }
  511. ENUMERATE_RETURNS((stderr, "_DownDir returning = %ws(%ld)\n", *wfilename, ret))
  512. return(ret);
  513. }