xref: /haiku/src/kits/storage/RemoveEngine.cpp (revision 4c8e85b316c35a9161f5a1c50ad70bc91c83a76f)
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