mirror of
https://github.com/SpartanJ/eepp.git
synced 2026-10-02 03:00:23 +03:00
Fix recursive directory removal across platforms
Add FileSystem::dirRemoveAll() to normalize trailing separators and use the non-throwing std::filesystem::remove_all overload. Migrate ecode and unit-test cleanup call sites to the centralized helper, preventing Haiku from crashing when removing directories with trailing slashes during shutdown.
This commit is contained in:
@@ -81,6 +81,11 @@ class EE_API FileSystem {
|
|||||||
/** Deletes a file from the file system. */
|
/** Deletes a file from the file system. */
|
||||||
static bool fileRemove( const std::string& filepath );
|
static bool fileRemove( const std::string& filepath );
|
||||||
|
|
||||||
|
/** Recursively deletes a directory and all of its contents.
|
||||||
|
* @return True if the directory was removed or did not exist, false on error.
|
||||||
|
*/
|
||||||
|
static bool dirRemoveAll( const std::string& path );
|
||||||
|
|
||||||
/** Moves a file or folder to the destination path
|
/** Moves a file or folder to the destination path
|
||||||
* @param fromPath The path of the file or folder to move
|
* @param fromPath The path of the file or folder to move
|
||||||
* @param toPath The folder / directory destination path
|
* @param toPath The folder / directory destination path
|
||||||
|
|||||||
@@ -202,6 +202,19 @@ bool FileSystem::fileRemove( const std::string& filepath ) {
|
|||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool FileSystem::dirRemoveAll( const std::string& path ) {
|
||||||
|
#if EE_PLATFORM == EE_PLATFORM_WIN
|
||||||
|
std::filesystem::path normalizedPath( String( path ).toWideString() );
|
||||||
|
#else
|
||||||
|
std::filesystem::path normalizedPath( path );
|
||||||
|
#endif
|
||||||
|
if ( normalizedPath.has_relative_path() && !normalizedPath.has_filename() )
|
||||||
|
normalizedPath = normalizedPath.parent_path();
|
||||||
|
std::error_code error;
|
||||||
|
std::filesystem::remove_all( normalizedPath, error );
|
||||||
|
return !error;
|
||||||
|
}
|
||||||
|
|
||||||
bool FileSystem::fileHide( const std::string& filepath ) {
|
bool FileSystem::fileHide( const std::string& filepath ) {
|
||||||
#if EE_PLATFORM == EE_PLATFORM_WIN
|
#if EE_PLATFORM == EE_PLATFORM_WIN
|
||||||
return SetFileAttributesW( (LPCWSTR)String( filepath ).toWideString().c_str(),
|
return SetFileAttributesW( (LPCWSTR)String( filepath ).toWideString().c_str(),
|
||||||
|
|||||||
@@ -26,13 +26,26 @@ struct TempDirectory {
|
|||||||
std::filesystem::create_directories( path );
|
std::filesystem::create_directories( path );
|
||||||
}
|
}
|
||||||
|
|
||||||
~TempDirectory() { std::filesystem::remove_all( path ); }
|
~TempDirectory() { FileSystem::dirRemoveAll( path.string() ); }
|
||||||
|
|
||||||
std::filesystem::path path;
|
std::filesystem::path path;
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace
|
} // namespace
|
||||||
|
|
||||||
|
UTEST( FileSystem, dirRemoveAllHandlesTrailingSlash ) {
|
||||||
|
TempDirectory temp;
|
||||||
|
const std::filesystem::path nested = temp.path / "nested";
|
||||||
|
std::filesystem::create_directories( nested );
|
||||||
|
ASSERT_TRUE( FileSystem::fileWrite( ( nested / "file.txt" ).string(), "contents" ) );
|
||||||
|
|
||||||
|
std::string path( temp.path.string() );
|
||||||
|
FileSystem::dirAddSlashAtEnd( path );
|
||||||
|
EXPECT_TRUE( FileSystem::dirRemoveAll( path ) );
|
||||||
|
EXPECT_FALSE( std::filesystem::exists( temp.path ) );
|
||||||
|
EXPECT_TRUE( FileSystem::dirRemoveAll( path ) );
|
||||||
|
}
|
||||||
|
|
||||||
UTEST( FileInfo, sameInodeUsesDeviceAndRejectsInvalidIdentity ) {
|
UTEST( FileInfo, sameInodeUsesDeviceAndRejectsInvalidIdentity ) {
|
||||||
FileInfoIdentity first;
|
FileInfoIdentity first;
|
||||||
FileInfoIdentity same;
|
FileInfoIdentity same;
|
||||||
|
|||||||
@@ -6,6 +6,7 @@
|
|||||||
#include <filesystem>
|
#include <filesystem>
|
||||||
|
|
||||||
using namespace EE::UI::Models;
|
using namespace EE::UI::Models;
|
||||||
|
using namespace EE::System;
|
||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
|
|
||||||
@@ -131,11 +132,11 @@ struct TempTree {
|
|||||||
static unsigned long long id = 0;
|
static unsigned long long id = 0;
|
||||||
path = std::filesystem::temp_directory_path() /
|
path = std::filesystem::temp_directory_path() /
|
||||||
( "eepp-filesystem-model-move-" + std::to_string( ++id ) );
|
( "eepp-filesystem-model-move-" + std::to_string( ++id ) );
|
||||||
std::filesystem::remove_all( path );
|
FileSystem::dirRemoveAll( path.string() );
|
||||||
std::filesystem::create_directories( path );
|
std::filesystem::create_directories( path );
|
||||||
}
|
}
|
||||||
|
|
||||||
~TempTree() { std::filesystem::remove_all( path ); }
|
~TempTree() { FileSystem::dirRemoveAll( path.string() ); }
|
||||||
|
|
||||||
std::filesystem::path path;
|
std::filesystem::path path;
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -55,10 +55,7 @@ class ScopedTestDirectory {
|
|||||||
public:
|
public:
|
||||||
explicit ScopedTestDirectory( std::filesystem::path path ) : mPath( std::move( path ) ) {}
|
explicit ScopedTestDirectory( std::filesystem::path path ) : mPath( std::move( path ) ) {}
|
||||||
|
|
||||||
~ScopedTestDirectory() {
|
~ScopedTestDirectory() { FileSystem::dirRemoveAll( mPath.string() ); }
|
||||||
std::error_code error;
|
|
||||||
std::filesystem::remove_all( mPath, error );
|
|
||||||
}
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
std::filesystem::path mPath;
|
std::filesystem::path mPath;
|
||||||
|
|||||||
@@ -1046,14 +1046,6 @@ App::App( const size_t& jobs, const std::vector<std::string>& args ) :
|
|||||||
mFontPickerController( std::make_unique<FontPickerController>( this ) ),
|
mFontPickerController( std::make_unique<FontPickerController>( this ) ),
|
||||||
mSettingsActions( std::make_unique<SettingsActions>( this ) ) {}
|
mSettingsActions( std::make_unique<SettingsActions>( this ) ) {}
|
||||||
|
|
||||||
static void fsRemoveAll( const std::string& fpath ) {
|
|
||||||
#if EE_PLATFORM == EE_PLATFORM_WIN
|
|
||||||
fs::remove_all( std::filesystem::path( String( fpath ).toWideString() ) );
|
|
||||||
#else
|
|
||||||
fs::remove_all( fpath );
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
App::~App() {
|
App::~App() {
|
||||||
appInstance = nullptr;
|
appInstance = nullptr;
|
||||||
mDestroyingApp = true;
|
mDestroyingApp = true;
|
||||||
@@ -1082,7 +1074,8 @@ App::~App() {
|
|||||||
}
|
}
|
||||||
mDirTree.reset();
|
mDirTree.reset();
|
||||||
|
|
||||||
fsRemoveAll( mPidPath );
|
if ( !FileSystem::dirRemoveAll( mPidPath ) )
|
||||||
|
Log::warning( "Failed to remove directory \"%s\"", mPidPath );
|
||||||
|
|
||||||
if ( mFirstInstance )
|
if ( mFirstInstance )
|
||||||
FileSystem::fileRemove( firstInstanceIndicatorPath() );
|
FileSystem::fileRemove( firstInstanceIndicatorPath() );
|
||||||
|
|||||||
@@ -1,9 +1,6 @@
|
|||||||
#include "settingsmenu.hpp"
|
#include "settingsmenu.hpp"
|
||||||
#include "uitreeviewfs.hpp"
|
#include "uitreeviewfs.hpp"
|
||||||
|
|
||||||
#include <filesystem>
|
|
||||||
namespace fs = std::filesystem;
|
|
||||||
|
|
||||||
namespace ecode {
|
namespace ecode {
|
||||||
|
|
||||||
String SettingsMenu::i18n( const std::string& key, const String& def ) {
|
String SettingsMenu::i18n( const std::string& key, const String& def ) {
|
||||||
@@ -2866,14 +2863,6 @@ void SettingsMenu::createProjectTreeMenu() {
|
|||||||
showProjectTreeMenu();
|
showProjectTreeMenu();
|
||||||
}
|
}
|
||||||
|
|
||||||
static void fsRemoveAll( const std::string& fpath ) {
|
|
||||||
#if EE_PLATFORM == EE_PLATFORM_WIN
|
|
||||||
fs::remove_all( std::filesystem::path( String( fpath ).toWideString() ) );
|
|
||||||
#else
|
|
||||||
fs::remove_all( fpath );
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
void SettingsMenu::createProjectTreeMenu( const std::vector<FileInfo>& files ) {
|
void SettingsMenu::createProjectTreeMenu( const std::vector<FileInfo>& files ) {
|
||||||
if ( mProjectTreeMenu && mProjectTreeMenu->isVisible() )
|
if ( mProjectTreeMenu && mProjectTreeMenu->isVisible() )
|
||||||
mProjectTreeMenu->close();
|
mProjectTreeMenu->close();
|
||||||
@@ -3152,13 +3141,8 @@ void SettingsMenu::deleteFileDialog( const FileInfo& file ) {
|
|||||||
};
|
};
|
||||||
|
|
||||||
if ( file.isDirectory() ) {
|
if ( file.isDirectory() ) {
|
||||||
try {
|
if ( !FileSystem::dirRemoveAll( file.getFilepath() ) )
|
||||||
std::string fpath( file.getFilepath() );
|
|
||||||
FileSystem::dirRemoveSlashAtEnd( fpath );
|
|
||||||
fsRemoveAll( fpath );
|
|
||||||
} catch ( const fs::filesystem_error& ) {
|
|
||||||
errFn();
|
errFn();
|
||||||
}
|
|
||||||
} else if ( !FileSystem::fileRemove( file.getFilepath() ) ) {
|
} else if ( !FileSystem::fileRemove( file.getFilepath() ) ) {
|
||||||
errFn();
|
errFn();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -8,8 +8,6 @@
|
|||||||
#include <eepp/ui/uimessagebox.hpp>
|
#include <eepp/ui/uimessagebox.hpp>
|
||||||
#include <eepp/window/cursormanager.hpp>
|
#include <eepp/window/cursormanager.hpp>
|
||||||
|
|
||||||
#include <filesystem>
|
|
||||||
|
|
||||||
namespace ecode {
|
namespace ecode {
|
||||||
|
|
||||||
static const std::map<KeyBindings::Shortcut, std::string> getDefaultKeybindings() {
|
static const std::map<KeyBindings::Shortcut, std::string> getDefaultKeybindings() {
|
||||||
@@ -405,14 +403,10 @@ void UITreeViewFS::deleteItems( const std::vector<std::string>& paths ) {
|
|||||||
msgBox->on( Event::OnConfirm, [paths]( const Event* ) {
|
msgBox->on( Event::OnConfirm, [paths]( const Event* ) {
|
||||||
for ( const auto& path : paths ) {
|
for ( const auto& path : paths ) {
|
||||||
FileInfo info( path );
|
FileInfo info( path );
|
||||||
try {
|
if ( info.isDirectory() )
|
||||||
if ( info.isDirectory() ) {
|
FileSystem::dirRemoveAll( path );
|
||||||
std::filesystem::remove_all( std::filesystem::path( path ) );
|
else
|
||||||
} else {
|
FileSystem::fileRemove( path );
|
||||||
FileSystem::fileRemove( path );
|
|
||||||
}
|
|
||||||
} catch ( const std::filesystem::filesystem_error& ) {
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
} );
|
} );
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user