1 /* 2 * Copyright 2013, Ingo Weinhold, ingo_weinhold@gmx.de. 3 * Distributed under the terms of the MIT License. 4 */ 5 6 7 #include <RemoveEngine.h> 8 9 #include <errno.h> 10 #include <string.h> 11 #include <unistd.h> 12 13 #include <Directory.h> 14 #include <Entry.h> 15 #include <Path.h> 16 17 18 namespace BPrivate { 19 20 21 // #pragma mark - BRemoveEngine 22 23 24 BRemoveEngine::BRemoveEngine() 25 : 26 fController(NULL) 27 { 28 } 29 30 31 BRemoveEngine::~BRemoveEngine() 32 { 33 } 34 35 36 BRemoveEngine::BController* 37 BRemoveEngine::Controller() const 38 { 39 return fController; 40 } 41 42 43 void 44 BRemoveEngine::SetController(BController* controller) 45 { 46 fController = controller; 47 } 48 49 50 status_t 51 BRemoveEngine::RemoveEntry(const Entry& entry) 52 { 53 BPath pathBuffer; 54 const char* path; 55 status_t error = entry.GetPath(pathBuffer, path); 56 if (error != B_OK) 57 return error; 58 59 return _RemoveEntry(path); 60 } 61 62 63 status_t 64 BRemoveEngine::_RemoveEntry(const char* path) 65 { 66 // apply entry filter 67 if (fController != NULL && !fController->EntryStarted(path)) 68 return B_OK; 69 70 // stat entry 71 struct stat st; 72 if (lstat(path, &st) < 0) { 73 return _HandleEntryError(path, errno, "Couldn't access \"%s\": %s\n", 74 path, strerror(errno)); 75 } 76 77 // recurse, if entry is a directory 78 if (S_ISDIR(st.st_mode)) { 79 // open directory 80 BDirectory directory; 81 status_t error = directory.SetTo(path); 82 if (error != B_OK) { 83 return _HandleEntryError(path, error, 84 "Failed to open directory \"%s\": %s\n", path, strerror(error)); 85 } 86 87 char buffer[offsetof(struct dirent, d_name) + B_FILE_NAME_LENGTH]; 88 dirent *entry = (dirent*)buffer; 89 while (directory.GetNextDirents(entry, sizeof(buffer), 1) == 1) { 90 if (strcmp(entry->d_name, ".") == 0 91 || strcmp(entry->d_name, "..") == 0) { 92 continue; 93 } 94 95 // construct child entry path 96 BPath childPath; 97 error = childPath.SetTo(path, entry->d_name); 98 if (error != B_OK) { 99 return _HandleEntryError(path, error, 100 "Failed to construct entry path from dir \"%s\" and name " 101 "\"%s\": %s\n", path, entry->d_name, strerror(error)); 102 } 103 104 // remove the entry 105 error = _RemoveEntry(childPath.Path()); 106 if (error != B_OK) { 107 if (fController != NULL 108 && fController->EntryFinished(path, error)) { 109 return B_OK; 110 } 111 return error; 112 } 113 } 114 } 115 116 // remove entry 117 if (S_ISDIR(st.st_mode)) { 118 if (rmdir(path) < 0) { 119 return _HandleEntryError(path, errno, 120 "Failed to remove \"%s\": %s\n", path, strerror(errno)); 121 } 122 } else { 123 if (unlink(path) < 0) { 124 return _HandleEntryError(path, errno, 125 "Failed to unlink \"%s\": %s\n", path, strerror(errno)); 126 } 127 } 128 129 if (fController != NULL) 130 fController->EntryFinished(path, B_OK); 131 132 return B_OK; 133 } 134 135 136 void 137 BRemoveEngine::_NotifyErrorVarArgs(status_t error, const char* format, 138 va_list args) 139 { 140 if (fController != NULL) { 141 BString message; 142 message.SetToFormatVarArgs(format, args); 143 fController->ErrorOccurred(message, error); 144 } 145 } 146 147 148 status_t 149 BRemoveEngine::_HandleEntryError(const char* path, status_t error, 150 const char* format, ...) 151 { 152 if (fController == NULL) 153 return error; 154 155 va_list args; 156 va_start(args, format); 157 _NotifyErrorVarArgs(error, format, args); 158 va_end(args); 159 160 if (fController->EntryFinished(path, error)) 161 return B_OK; 162 return error; 163 } 164 165 166 // #pragma mark - BController 167 168 169 BRemoveEngine::BController::BController() 170 { 171 } 172 173 174 BRemoveEngine::BController::~BController() 175 { 176 } 177 178 179 bool 180 BRemoveEngine::BController::EntryStarted(const char* path) 181 { 182 return true; 183 } 184 185 186 bool 187 BRemoveEngine::BController::EntryFinished(const char* path, status_t error) 188 { 189 return error == B_OK; 190 } 191 192 193 void 194 BRemoveEngine::BController::ErrorOccurred(const char* message, status_t error) 195 { 196 } 197 198 199 } // namespace BPrivate 200