/* * 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[offsetof(struct dirent, d_name) + 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