diff --git a/headers/private/storage/RemoveEngine.h b/headers/private/storage/RemoveEngine.h new file mode 100644 index 0000000000..1ca78b188c --- /dev/null +++ b/headers/private/storage/RemoveEngine.h @@ -0,0 +1,65 @@ +/* + * Copyright 2013, Haiku, Inc. All Rights Reserved. + * Distributed under the terms of the MIT License. + * + * Authors: + * Ingo Weinhold + */ +#ifndef _REMOVE_ENGINE_H +#define _REMOVE_ENGINE_H + + +#include + +#include + + +namespace BPrivate { + + +class BRemoveEngine : public BEntryOperationEngineBase { +public: + class BController; + +public: + BRemoveEngine(); + ~BRemoveEngine(); + + BController* Controller() const; + void SetController(BController* controller); + + status_t RemoveEntry(const Entry& entry); + +private: + status_t _RemoveEntry(const char* path); + + void _NotifyErrorVarArgs(status_t error, + const char* format, va_list args); + status_t _HandleEntryError(const char* path, + status_t error, const char* format, ...); + +private: + BController* fController; +}; + + +class BRemoveEngine::BController { +public: + BController(); + virtual ~BController(); + + virtual bool EntryStarted(const char* path); + virtual bool EntryFinished(const char* path, status_t error); + + virtual void ErrorOccurred(const char* message, + status_t error); +}; + + +} // namespace BPrivate + + +using ::BPrivate::BRemoveEngine; + + +#endif // _REMOVE_ENGINE_H diff --git a/src/kits/storage/Jamfile b/src/kits/storage/Jamfile index 68c54d8aeb..c57db1a203 100644 --- a/src/kits/storage/Jamfile +++ b/src/kits/storage/Jamfile @@ -42,6 +42,7 @@ for architectureObject in [ MultiArchSubDirSetup ] { PathMonitor.cpp Query.cpp QueryPredicate.cpp + RemoveEngine.cpp ResourceFile.cpp ResourceItem.cpp Resources.cpp diff --git a/src/kits/storage/RemoveEngine.cpp b/src/kits/storage/RemoveEngine.cpp new file mode 100644 index 0000000000..63626be045 --- /dev/null +++ b/src/kits/storage/RemoveEngine.cpp @@ -0,0 +1,199 @@ +/* + * Copyright 2013, Ingo Weinhold, ingo_weinhold@gmx.de. + * Distributed under the terms of the MIT License. + */ + + +#include + +#include +#include +#include + +#include +#include +#include + + +namespace BPrivate { + + +// #pragma mark - BRemoveEngine + + +BRemoveEngine::BRemoveEngine() + : + fController(NULL) +{ +} + + +BRemoveEngine::~BRemoveEngine() +{ +} + + +BRemoveEngine::BController* +BRemoveEngine::Controller() const +{ + return fController; +} + + +void +BRemoveEngine::SetController(BController* controller) +{ + fController = controller; +} + + +status_t +BRemoveEngine::RemoveEntry(const Entry& entry) +{ + BPath pathBuffer; + const char* path; + status_t error = entry.GetPath(pathBuffer, path); + if (error != B_OK) + return error; + + return _RemoveEntry(path); +} + + +status_t +BRemoveEngine::_RemoveEntry(const char* path) +{ + // apply entry filter + if (fController != NULL && !fController->EntryStarted(path)) + return B_OK; + + // stat entry + struct stat st; + if (lstat(path, &st) < 0) { + return _HandleEntryError(path, errno, "Couldn't access \"%s\": %s\n", + path, strerror(errno)); + } + + // recurse, if entry is a directory + if (S_ISDIR(st.st_mode)) { + // open directory + BDirectory directory; + status_t error = directory.SetTo(path); + if (error != B_OK) { + return _HandleEntryError(path, error, + "Failed to open directory \"%s\": %s\n", path, strerror(error)); + } + + char buffer[sizeof(dirent) + B_FILE_NAME_LENGTH]; + dirent *entry = (dirent*)buffer; + while (directory.GetNextDirents(entry, sizeof(buffer), 1) == 1) { + if (strcmp(entry->d_name, ".") == 0 + || strcmp(entry->d_name, "..") == 0) { + continue; + } + + // construct child entry path + BPath childPath; + error = childPath.SetTo(path, entry->d_name); + if (error != B_OK) { + return _HandleEntryError(path, error, + "Failed to construct entry path from dir \"%s\" and name " + "\"%s\": %s\n", path, entry->d_name, strerror(error)); + } + + // remove the entry + error = _RemoveEntry(childPath.Path()); + if (error != B_OK) { + if (fController != NULL + && fController->EntryFinished(path, error)) { + return B_OK; + } + return error; + } + } + } + + // remove entry + if (S_ISDIR(st.st_mode)) { + if (rmdir(path) < 0) { + return _HandleEntryError(path, errno, + "Failed to remove \"%s\": %s\n", path, strerror(errno)); + } + } else { + if (unlink(path) < 0) { + return _HandleEntryError(path, errno, + "Failed to unlink \"%s\": %s\n", path, strerror(errno)); + } + } + + if (fController != NULL) + fController->EntryFinished(path, B_OK); + + return B_OK; +} + + +void +BRemoveEngine::_NotifyErrorVarArgs(status_t error, const char* format, + va_list args) +{ + if (fController != NULL) { + BString message; + message.SetToFormatVarArgs(format, args); + fController->ErrorOccurred(message, error); + } +} + + +status_t +BRemoveEngine::_HandleEntryError(const char* path, status_t error, + const char* format, ...) +{ + if (fController == NULL) + return error; + + va_list args; + va_start(args, format); + _NotifyErrorVarArgs(error, format, args); + va_end(args); + + if (fController->EntryFinished(path, error)) + return B_OK; + return error; +} + + +// #pragma mark - BController + + +BRemoveEngine::BController::BController() +{ +} + + +BRemoveEngine::BController::~BController() +{ +} + + +bool +BRemoveEngine::BController::EntryStarted(const char* path) +{ + return true; +} + + +bool +BRemoveEngine::BController::EntryFinished(const char* path, status_t error) +{ + return error == B_OK; +} + + +void +BRemoveEngine::BController::ErrorOccurred(const char* message, status_t error) +{ +} + + +} // namespace BPrivate