diff --git a/include/ebcl/Filesystem.hh b/include/ebcl/Filesystem.hh index 8c456d9..4ad4366 100644 --- a/include/ebcl/Filesystem.hh +++ b/include/ebcl/Filesystem.hh @@ -201,6 +201,15 @@ M_LSHIFT_OP( T_StringBuilder , T_FSPath const& ); /*= FILESYSTEM ===============================================================*/ +// Type of entries +enum class E_FSEntryType { + NONE , // Filesystem entry does not exist + FILE , // Filesystem entry refers to a file + DIRECTORY , // Filesystem entry refers to a directory + OTHER // Filesystem entry exists but refers to something else + // entirely (e.g. symlinks) and is therefore off-limits +}; + class Filesystem final { Filesystem( ) = delete; @@ -208,6 +217,29 @@ class Filesystem final // Return the absolute path to the current working directory static T_FSPath Cwd( ) noexcept; + // Get the type of an entry + static E_FSEntryType TypeOf( T_FSPath const& path ) noexcept; + + // List a directory's contents + static bool List( T_FSPath const& path , + T_Array< T_String >& output ) noexcept; + + // Create a new directory + static bool MkDir( T_FSPath const& path ) noexcept; + + // Create a new directory, including parent directories if + // they do not exist + static bool MkDirFull( T_FSPath const& path ) noexcept; + + // Delete a directory + static bool RmDir( T_FSPath const& path ) noexcept; + + // Delete a file + static bool Rm( T_FSPath const& path ) noexcept; + + // Move or rename a file + static bool Move( T_FSPath const& from , + T_FSPath const& to ) noexcept; }; diff --git a/src/Filesystem.cc b/src/Filesystem.cc index c57fce5..460346a 100644 --- a/src/Filesystem.cc +++ b/src/Filesystem.cc @@ -3,15 +3,13 @@ /******************************************************************************/ #include -using namespace ebcl; - - -#ifdef _WIN32 -# define M_PATHSEP_ '\\' -#else -# define M_PATHSEP_ '/' +#ifndef _WIN32 +# include +# include # include #endif +using namespace ebcl; + /*= T_FSPathStyle ============================================================*/ @@ -390,6 +388,101 @@ T_FSPath T_FSPath::canonical( ) const noexcept } +/*= T_DirLister_ =============================================================*/ + +namespace { + +class T_DirLister_ +{ + private: + T_Buffer< char > path_; +#ifdef _WIN32 + HANDLE handle_; + WIN32_FIND_DATAW output_; +#else + DIR* dir_; + struct dirent* output_; +#endif + + public: + explicit T_DirLister_( T_Buffer< char > path ) noexcept; + ~T_DirLister_( ); + + bool start( ) noexcept; + void next( ) noexcept; + bool hasValue( ) const noexcept; + T_String getName( ) const noexcept; +}; + + +} // namespace + +/*----------------------------------------------------------------------------*/ + +inline T_DirLister_::T_DirLister_( T_Buffer< char > path ) noexcept + : path_( std::move( path ) ) +{ +#ifdef _WIN32 +# error "Not implemented" +#else + dir_ = nullptr; + output_ = nullptr; +#endif +} + +T_DirLister_::~T_DirLister_( ) +{ +#ifdef _WIN32 +# error "Not implemented" +#else + if ( dir_ != nullptr ) { + closedir( dir_ ); + } +#endif +} + +inline bool T_DirLister_::start( ) noexcept +{ +#ifdef _WIN32 +# error "Not implemented" +#else + dir_ = opendir( &path_[ 0 ] ); + if ( dir_ == nullptr ) { + return false; + } + output_ = readdir( dir_ ); + return true; +#endif +} + +inline void T_DirLister_::next( ) noexcept +{ +#ifdef _WIN32 +# error "Not implemented" +#else + output_ = readdir( dir_ ); +#endif +} + +inline bool T_DirLister_::hasValue( ) const noexcept +{ +#ifdef _WIN32 +# error "Not implemented" +#else + return output_ != nullptr; +#endif +} + +inline T_String T_DirLister_::getName( ) const noexcept +{ +#ifdef _WIN32 +# error "Not implemented" +#else + return T_String( output_->d_name ); +#endif +} + + /*= Filesystem ===============================================================*/ T_FSPath Filesystem::Cwd( ) noexcept @@ -414,3 +507,159 @@ T_FSPath Filesystem::Cwd( ) noexcept assert( path.isValid( ) ); return path; } + +E_FSEntryType Filesystem::TypeOf( + T_FSPath const& path ) noexcept +{ + assert( path.style( ) == T_FSPathStyle::System( ) ); + if ( !path.isValid( ) ) { + return E_FSEntryType::NONE; + } + + const auto chars{ path.toString( ).toOSString( ) }; + +#ifdef _WIN32 + + uint32_t fa( GetFileAttributesW( (wchar_t const*) & chars[ 0 ] ) ); + if ( fa == INVALID_FILE_ATTRIBUTES ) { + return E_FSEntryType::NONE; + } else if ( ( fa & FILE_ATTRIBUTE_DIRECTORY ) != 0 ) { + return E_FSEntryType::DIRECTORY; + } else if ( ( fa & FILE_ATTRIBUTE_NORMAL ) != 0 ) { + return E_FSEntryType::FILE; + } else { + return E_FSEntryType::OTHER; + } + +#else + + struct stat fa; + if ( stat( ( char const* ) &chars[ 0 ] , &fa ) ) { + return E_FSEntryType::NONE; + } + + const auto masked( fa.st_mode & S_IFMT ); + switch ( masked ) { + case S_IFREG: + return E_FSEntryType::FILE; + + case S_IFDIR: + return E_FSEntryType::DIRECTORY; + + default: + return E_FSEntryType::OTHER; + } + +#endif +} + +bool Filesystem::List( + T_FSPath const& path , + T_Array< T_String >& output ) noexcept +{ + assert( path.style( ) == T_FSPathStyle::System( ) ); + if ( !path.isValid( ) ) { + return false; + } + + T_DirLister_ dl{ path.toString( ).toOSString( ) }; + if ( !dl.start( ) ) { + return false; + } + while ( dl.hasValue( ) ) { + output.add( dl.getName( ) ); + dl.next( ); + } + return true; +} + +bool Filesystem::MkDir( + T_FSPath const& path ) noexcept +{ + assert( path.style( ) == T_FSPathStyle::System( ) ); + if ( !path.isValid( ) ) { + return false; + } + const auto chars{ path.toString( ).toOSString( ) }; + +#ifdef _WIN32 + return CreateDirectoryW( ( wchar_t const* ) &chars[ 0 ] , nullptr ); +#else + return mkdir( ( char const* ) &chars[ 0 ] , 0755 ) == 0; +#endif +} + +bool Filesystem::MkDirFull( + T_FSPath const& path ) noexcept +{ + assert( path.style( ) == T_FSPathStyle::System( ) ); + if ( !path.isValid( ) ) { + return false; + } + + const T_FSPath full{ path.canonical( ) }; + T_FSPath current{ full.root( ) }; + for ( auto const& cmp : full.components( ) ) { + current = current.child( cmp ); + const auto t{ TypeOf( current ) }; + if ( t == E_FSEntryType::NONE ) { + if ( !MkDir( current ) ) { + return false; + } + } else if ( t != E_FSEntryType::DIRECTORY ) { + return false; + } + } + + return true; +} + +bool Filesystem::RmDir( + T_FSPath const& path ) noexcept +{ + assert( path.style( ) == T_FSPathStyle::System( ) ); + if ( !path.isValid( ) ) { + return false; + } + + const auto chars{ path.toString( ).toOSString( ) }; +#ifdef _WIN32 + return RemoveDirectoryW( ( wchar_t const* ) &chars[ 0 ] ); +#else + return rmdir( ( char const* ) &chars[ 0 ] ) == 0; +#endif +} + +bool Filesystem::Rm( + T_FSPath const& path ) noexcept +{ + assert( path.style( ) == T_FSPathStyle::System( ) ); + if ( !path.isValid( ) ) { + return false; + } + + const auto chars{ path.toString( ).toOSString( ) }; +#ifdef _WIN32 + return DeleteFileW( ( wchar_t const* ) &chars[ 0 ] ); +#else + return unlink( ( char const* ) &chars[ 0 ] ) == 0; +#endif +} + +bool Filesystem::Move( + T_FSPath const& from , + T_FSPath const& to ) noexcept +{ + assert( from.style( ) == T_FSPathStyle::System( ) ); + assert( to.style( ) == T_FSPathStyle::System( ) ); + + const auto charsFrom{ from.toString( ).toOSString( ) }; + const auto charsTo{ to.toString( ).toOSString( ) }; +#ifdef _WIN32 + return MoveFileW( ( wchar_t const* ) &charsFrom[ 0 ] , + ( wchar_t const* ) &charsTo[ 0 ] ); +#else + return rename( ( char const* ) &charsFrom[ 0 ] , + ( char const* ) &charsTo[ 0 ] ) == 0; +#endif +}