Originally Posted by
Ducky
Ok i found the solution!
You need to use
statement.
Right, because FindFirstFile grabs the first file, if available. Just be sure to check that it succeeds first, obviously.
Here's a slightly more portable method (not standard, but most systems support the functions used). The general approach here is to encapsulate the traversal logic in a reusable interface that allows you to simply pass callback functions/objects to it that get invoked at key points in the traversing routine, namely before entering a directory, when processing a file, and after exiting the directory. Another feature is that it restores the current working directory to it's original state. It even works with individual file names, so you don't have to incorporate any special logic to detect what type of file-system object you're dealing with.
Code:
#include <dirent.h>
#include <sys/stat.h>
#include <string>
template < typename PreProcessFolder, typename ProcessFile, typename PostProcessFolder >
bool file_system_process
(
std::string const& name,
PreProcessFolder pre_process_folder,
ProcessFile process_file,
PostProcessFolder post_process_folder
);
template < typename ProcessFile, typename PostProcessFolder >
inline bool file_system_process
(
std::string const& name,
ProcessFile process_file,
PostProcessFolder post_process_folder
);
template < typename ProcessFile >
inline bool file_system_process
(
std::string const& name,
ProcessFile process_file
);
namespace impl_ {
struct DIR_cleanup_helper
{
DIR_cleanup_helper( DIR* directory )
: directory( directory )
{ }
~DIR_cleanup_helper( void )
{
closedir( directory );
}
DIR*
directory;
};
template < typename PreProcessFolder, typename ProcessFile, typename PostProcessFolder >
bool file_system_process_
(
std::string const& folder_name,
PreProcessFolder pre_process_folder,
ProcessFile process_file,
PostProcessFolder post_process_folder
)
{
struct stat
attributes;
DIR*
directory = opendir( folder_name.data( ) );
if( directory != 0 )
{
DIR_cleanup_helper
dch( directory );
pre_process_folder( folder_name.data( ) );
chdir( folder_name.data( ) );
dirent*
entry;
while( ( entry = readdir( directory ) ) != 0 )
{
std::string
name = entry->d_name;
if( name == "." || name == ".." )
continue;
if( stat( name.data( ), &attributes ) == 0 )
{
if( ( attributes.st_mode & _S_IFDIR ) == _S_IFDIR )
{
if
(
!file_system_process_
(
name,
pre_process_folder,
process_file,
post_process_folder
)
)
return false;
}
else
process_file( name.data( ) );
}
else
return false;
}
chdir( ".." );
post_process_folder( folder_name.data( ) );
}
else
return false;
return true;
}
void file_system_process_unused_placeholder_( char const* )
{ }
} // ::impl_
template < typename PreProcessFolder, typename ProcessFile, typename PostProcessFolder >
bool file_system_process
(
std::string const& name,
PreProcessFolder pre_process_folder,
ProcessFile process_file,
PostProcessFolder post_process_folder
)
{
std::string
buffer( 32, 0 );
while( !getcwd( &buffer[ 0 ], buffer.size( ) ) )
{
if( errno == ENODEV )
return false;
buffer.resize( buffer.size( ) * 2 );
}
if(
!impl_::file_system_process_
(
name,
pre_process_folder,
process_file,
post_process_folder
)
)
{
struct stat
attributes;
if(
stat( name.data( ), &attributes ) == 0
&&
!( ( attributes.st_mode & _S_IFDIR ) == _S_IFDIR )
)
{
process_file( name.data( ) );
return true;
}
return false;
}
chdir( buffer.data( ) );
return true;
}
template < typename ProcessFile, typename PostProcessFolder >
inline bool file_system_process
(
std::string const& name,
ProcessFile process_file,
PostProcessFolder post_process_folder
)
{
return file_system_process
(
name,
impl_::file_system_process_unused_placeholder_,
process_file,
post_process_folder
);
}
template < typename ProcessFile >
inline bool file_system_process
(
std::string const& name,
ProcessFile process_file
)
{
return file_system_process
(
name,
impl_::file_system_process_unused_placeholder_,
process_file,
impl_::file_system_process_unused_placeholder_
);
}
If the functionality you isn't covered by any of those three variants, just pass "place-holder" functions where appropriate. Here's an example usage, a file/folder-erasing function:
Code:
#include <string>
#include <vector>
#include <fstream>
/*
TODO: make thread-safe
*/
bool file_system_erase( std::string const& name );
namespace impl_ {
static bool
file_system_erase_error_;
void file_system_erase_file_( char const* name )
{
using namespace
std;
static size_t
buffer_size = 1024;
static vector< char >
buffer( buffer_size );
ofstream
out( name );
if( out )
{
struct stat
attributes;
if( stat( name, &attributes ) == 0 )
{
size_t
count = 0;
while
(
out.write( ( char* )&buffer[ 0 ], buffer_size )
&&
count < attributes.st_size
)
{
count += buffer_size;
}
if( count >= attributes.st_size )
{
out.close( );
if( remove( name ) == 0 )
return;
}
}
}
file_system_erase_error_ = true;
}
void file_system_erase_folder_( char const* name )
{
if( rmdir( name ) != 0 )
file_system_erase_error_ = true;
}
} // ::impl_
bool file_system_erase( std::string const& name )
{
impl_::file_system_erase_error_ = false;
return
file_system_process
(
name,
impl_::file_system_erase_file_,
impl_::file_system_erase_folder_
)
&&
!impl_::file_system_erase_error_;
}
And a sample program:
Code:
#include <iostream>
#include <string>
using namespace std;
int main( int argc, char** argv )
{
if( argc < 2 )
{
cerr << "Simple File System Eraser Utility" << endl;
cerr << "Usage: " << *argv << " <files_and_folders>" << endl;
cerr << "Warning: deleted files will NOT be recoverable" << endl;
}
else while( *( ++argv ) )
if( !file_system_erase( *argv ) )
cerr << "Error processing '" << *argv << "'" << endl;
return 0;
}
Anyway, if nothing else, it may be a good starting point for you, in the event that you want a more customized solution.