OLD | NEW |
---|---|
1 // Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file |
2 // for details. All rights reserved. Use of this source code is governed by a | 2 // for details. All rights reserved. Use of this source code is governed by a |
3 // BSD-style license that can be found in the LICENSE file. | 3 // BSD-style license that can be found in the LICENSE file. |
4 | 4 |
5 #include "bin/directory.h" | 5 #include "bin/directory.h" |
6 | 6 |
7 #include <dirent.h> | 7 #include <dirent.h> |
8 #include <errno.h> | 8 #include <errno.h> |
9 #include <sys/param.h> | 9 #include <sys/param.h> |
10 #include <sys/stat.h> | 10 #include <sys/stat.h> |
11 #include <unistd.h> | 11 #include <unistd.h> |
12 | 12 |
13 #include "bin/file.h" | 13 #include "bin/file.h" |
14 #include "bin/platform.h" | 14 #include "bin/platform.h" |
15 | 15 |
16 | 16 |
17 static char* SafeStrNCpy(char* dest, const char* src, size_t n) { | 17 static char* SafeStrNCpy(char* dest, const char* src, size_t n) { |
18 strncpy(dest, src, n); | 18 strncpy(dest, src, n); |
19 dest[n - 1] = '\0'; | 19 dest[n - 1] = '\0'; |
20 return dest; | 20 return dest; |
21 } | 21 } |
22 | 22 |
23 | 23 |
24 static void SetOsErrorMessage(char* os_error_message, | 24 static void SetOsErrorMessage(char* os_error_message, |
25 int os_error_message_len) { | 25 int os_error_message_len) { |
26 SafeStrNCpy(os_error_message, strerror(errno), os_error_message_len); | 26 SafeStrNCpy(os_error_message, strerror(errno), os_error_message_len); |
27 } | 27 } |
28 | 28 |
29 | 29 |
30 // Forward declaration. | 30 // Forward declarations. |
31 static bool ListRecursively(const char* dir_name, | 31 static bool ListRecursively(const char* dir_name, |
32 bool recursive, | 32 bool recursive, |
33 Dart_Port dir_port, | 33 Dart_Port dir_port, |
34 Dart_Port file_port, | 34 Dart_Port file_port, |
35 Dart_Port done_port, | 35 Dart_Port done_port, |
36 Dart_Port error_port); | 36 Dart_Port error_port); |
37 static bool DeleteRecursively(const char* dir_name); | |
37 | 38 |
38 | 39 |
39 static void ComputeFullPath(const char* dir_name, | 40 static void ComputeFullPath(const char* dir_name, |
40 char* path, | 41 char* path, |
41 int* path_length) { | 42 int* path_length) { |
42 char* abs_path; | 43 char* abs_path; |
43 do { | 44 do { |
44 abs_path = realpath(dir_name, path); | 45 abs_path = realpath(dir_name, path); |
45 } while (abs_path == NULL && errno == EINTR); | 46 } while (abs_path == NULL && errno == EINTR); |
46 ASSERT(abs_path != NULL); | 47 ASSERT(abs_path != NULL); |
(...skipping 166 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
213 | 214 |
214 if (closedir(dir_pointer) == -1) { | 215 if (closedir(dir_pointer) == -1) { |
215 PostError(error_port, "Failed to close directory", "", errno); | 216 PostError(error_port, "Failed to close directory", "", errno); |
216 } | 217 } |
217 free(path); | 218 free(path); |
218 | 219 |
219 return !listing_error; | 220 return !listing_error; |
220 } | 221 } |
221 | 222 |
222 | 223 |
224 static bool DeleteFile(char* file_name, | |
Bill Hesse
2012/02/02 17:24:39
Put a comment that strlen(path) may not be path_le
Mads Ager (google)
2012/02/03 11:48:54
This applies to all the methods in this file. I ha
| |
225 char* path, | |
226 int path_length) { | |
227 size_t written = snprintf(path + path_length, | |
228 PATH_MAX - path_length, | |
229 "%s", | |
230 file_name); | |
231 ASSERT(written == strlen(file_name)); | |
232 return (remove(path) == 0); | |
233 } | |
234 | |
235 | |
236 static bool DeleteDir(char* dir_name, | |
237 char* path, | |
238 int path_length) { | |
239 if (strcmp(dir_name, ".") != 0 && | |
240 strcmp(dir_name, "..") != 0) { | |
241 size_t written = snprintf(path + path_length, | |
242 PATH_MAX - path_length, | |
243 "%s", | |
244 dir_name); | |
245 ASSERT(written == strlen(dir_name)); | |
Bill Hesse
2012/02/02 17:24:39
In release mode, could a snprintf turn "long_path/
Mads Ager (google)
2012/02/03 11:48:54
Yes, that is not good. I have changed all the ASSE
| |
246 return DeleteRecursively(path); | |
247 } | |
248 return true; | |
249 } | |
250 | |
251 | |
252 static bool DeleteRecursively(const char* dir_name) { | |
253 DIR* dir_pointer; | |
254 do { | |
255 dir_pointer = opendir(dir_name); | |
256 } while (dir_pointer == NULL && errno == EINTR); | |
257 | |
258 if (dir_pointer == NULL) { | |
259 return false; | |
260 } | |
261 | |
262 // Compute full path for the directory currently being deleted. | |
263 char *path = static_cast<char*>(malloc(PATH_MAX)); | |
264 ASSERT(path != NULL); | |
265 int path_length = 0; | |
266 ComputeFullPath(dir_name, path, &path_length); | |
Bill Hesse
2012/02/02 17:24:39
ASSERT on path_length here?
Mads Ager (google)
2012/02/03 11:48:54
Reworked so ComputeFullPath returns a failure stat
| |
267 | |
268 // Iterated the directory and delete all files and directories. | |
Bill Hesse
2012/02/02 17:24:39
Iterate the directory ...
Mads Ager (google)
2012/02/03 11:48:54
Done.
| |
269 int success = 0; | |
270 bool error = false; | |
271 dirent entry; | |
272 dirent* result; | |
273 while ((success = TEMP_FAILURE_RETRY(readdir_r(dir_pointer, | |
274 &entry, | |
275 &result))) == 0 && | |
276 result != NULL && | |
277 !error) { | |
278 switch (entry.d_type) { | |
279 case DT_DIR: | |
280 error = error || !DeleteDir(entry.d_name, path, path_length); | |
281 break; | |
282 case DT_REG: | |
283 error = error || !DeleteFile(entry.d_name, path, path_length); | |
284 break; | |
285 case DT_UNKNOWN: { | |
286 // On some file systems the entry type is not determined by | |
287 // readdir_r. For those we use lstat to determine the entry | |
288 // type. | |
289 struct stat entry_info; | |
290 size_t written = snprintf(path + path_length, | |
291 PATH_MAX - path_length, | |
292 "%s", | |
293 entry.d_name); | |
294 ASSERT(written == strlen(entry.d_name)); | |
295 int lstat_success = TEMP_FAILURE_RETRY(lstat(path, &entry_info)); | |
296 if (lstat_success == -1) { | |
297 error = true; | |
298 break; | |
299 } | |
300 if ((entry_info.st_mode & S_IFMT) == S_IFDIR) { | |
301 error = error || !DeleteDir(entry.d_name, path, path_length); | |
302 } else if ((entry_info.st_mode & S_IFMT) == S_IFREG) { | |
303 error = error || !DeleteFile(entry.d_name, path, path_length); | |
304 } | |
305 break; | |
306 } | |
307 default: | |
308 break; | |
309 } | |
310 } | |
311 | |
312 free(path); | |
313 | |
314 if ((success != 0) || | |
315 (closedir(dir_pointer) == -1) || | |
316 (remove(dir_name) == -1)) { | |
317 return false; | |
318 } | |
319 | |
320 return !error; | |
Bill Hesse
2012/02/02 17:24:39
Every use of error really wants to use !error inst
Mads Ager (google)
2012/02/03 11:48:54
Good point. Renamed success->read, error->success
| |
321 } | |
322 | |
323 | |
223 void Directory::List(const char* dir_name, | 324 void Directory::List(const char* dir_name, |
224 bool recursive, | 325 bool recursive, |
225 Dart_Port dir_port, | 326 Dart_Port dir_port, |
226 Dart_Port file_port, | 327 Dart_Port file_port, |
227 Dart_Port done_port, | 328 Dart_Port done_port, |
228 Dart_Port error_port) { | 329 Dart_Port error_port) { |
229 bool completed = ListRecursively(dir_name, | 330 bool completed = ListRecursively(dir_name, |
230 recursive, | 331 recursive, |
231 dir_port, | 332 dir_port, |
232 file_port, | 333 file_port, |
(...skipping 69 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
302 if (result == NULL) { | 403 if (result == NULL) { |
303 SetOsErrorMessage(os_error_message, os_error_message_len); | 404 SetOsErrorMessage(os_error_message, os_error_message_len); |
304 free(*path); | 405 free(*path); |
305 *path = NULL; | 406 *path = NULL; |
306 return errno; | 407 return errno; |
307 } | 408 } |
308 return 0; | 409 return 0; |
309 } | 410 } |
310 | 411 |
311 | 412 |
312 bool Directory::Delete(const char* dir_name) { | 413 bool Directory::Delete(const char* dir_name, bool recursive) { |
313 return (TEMP_FAILURE_RETRY(rmdir(dir_name)) == 0); | 414 if (!recursive) { |
415 return (TEMP_FAILURE_RETRY(remove(dir_name)) == 0); | |
416 } else { | |
417 return DeleteRecursively(dir_name); | |
418 } | |
314 } | 419 } |
OLD | NEW |