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.

608 lines
19 KiB

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