home *** CD-ROM | disk | FTP | other *** search
/ Tricks of the Windows Gam…ming Gurus (2nd Edition) / Disc2.iso / msdn_vcb / samples / vc98 / sdk / sdktools / winnt / cacls / fileenum.cxx < prev    next >
C/C++ Source or Header  |  1997-04-24  |  17KB  |  523 lines

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