Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(6)

Side by Side Diff: runtime/bin/directory_posix.cc

Issue 9316066: Implement recursive directory deletion. (Closed) Base URL: https://dart.googlecode.com/svn/branches/bleeding_edge/dart
Patch Set: Address comments. Created 8 years, 10 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
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 bool 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 if (abs_path == NULL) {
48 return false;
49 }
47 *path_length = strlen(path); 50 *path_length = strlen(path);
48 size_t written = snprintf(path + *path_length, 51 size_t written = snprintf(path + *path_length,
Bill Hesse 2012/02/03 12:17:51 I would consider moving the addition of PathSepara
Mads Ager (google) 2012/02/03 12:37:12 I would like to keep this as is. That way the code
49 PATH_MAX - *path_length, 52 PATH_MAX - *path_length,
50 "%s", 53 "%s",
51 File::PathSeparator()); 54 File::PathSeparator());
52 ASSERT(written == strlen(File::PathSeparator())); 55 if (written != strlen(File::PathSeparator())) {
56 return false;
57 }
53 *path_length += written; 58 *path_length += written;
59 return true;
54 } 60 }
55 61
56 62
57 static bool HandleDir(char* dir_name, 63 static bool HandleDir(char* dir_name,
58 char* path, 64 char* path,
59 int path_length, 65 int path_length,
60 bool recursive, 66 bool recursive,
61 Dart_Port dir_port, 67 Dart_Port dir_port,
62 Dart_Port file_port, 68 Dart_Port file_port,
63 Dart_Port done_port, 69 Dart_Port done_port,
64 Dart_Port error_port) { 70 Dart_Port error_port) {
65 if (strcmp(dir_name, ".") != 0 && 71 if (strcmp(dir_name, ".") != 0 &&
66 strcmp(dir_name, "..") != 0) { 72 strcmp(dir_name, "..") != 0) {
67 size_t written = snprintf(path + path_length, 73 size_t written = snprintf(path + path_length,
68 PATH_MAX - path_length, 74 PATH_MAX - path_length,
69 "%s", 75 "%s",
70 dir_name); 76 dir_name);
71 ASSERT(written == strlen(dir_name)); 77 if (written != strlen(dir_name)) {
78 return false;
79 }
72 if (dir_port != 0) { 80 if (dir_port != 0) {
73 Dart_Handle name = Dart_NewString(path); 81 Dart_Handle name = Dart_NewString(path);
74 Dart_Post(dir_port, name); 82 Dart_Post(dir_port, name);
75 } 83 }
76 if (recursive) { 84 if (recursive) {
77 return ListRecursively(path, 85 return ListRecursively(path,
78 recursive, 86 recursive,
79 dir_port, 87 dir_port,
80 file_port, 88 file_port,
81 done_port, 89 done_port,
82 error_port); 90 error_port);
83 } 91 }
84 } 92 }
85 return true; 93 return true;
86 } 94 }
87 95
88 96
89 static void HandleFile(char* file_name, 97 static bool HandleFile(char* file_name,
90 char* path, 98 char* path,
91 int path_length, 99 int path_length,
92 Dart_Port file_port) { 100 Dart_Port file_port) {
93 if (file_port != 0) { 101 if (file_port != 0) {
94 size_t written = snprintf(path + path_length, 102 size_t written = snprintf(path + path_length,
95 PATH_MAX - path_length, 103 PATH_MAX - path_length,
96 "%s", 104 "%s",
97 file_name); 105 file_name);
98 ASSERT(written == strlen(file_name)); 106 if (written != strlen(file_name)) {
107 return false;
108 }
99 Dart_Handle name = Dart_NewString(path); 109 Dart_Handle name = Dart_NewString(path);
100 Dart_Post(file_port, name); 110 Dart_Post(file_port, name);
101 } 111 }
112 return true;
102 } 113 }
103 114
104 115
105 static void PostError(Dart_Port error_port, 116 static void PostError(Dart_Port error_port,
106 const char* prefix, 117 const char* prefix,
107 const char* suffix, 118 const char* suffix,
108 int error_code) { 119 int error_code) {
109 if (error_port != 0) { 120 if (error_port != 0) {
110 char* error_str = Platform::StrError(error_code); 121 char* error_str = Platform::StrError(error_code);
111 int error_message_size = 122 int error_message_size =
(...skipping 21 matching lines...) Expand all
133 Dart_Port error_port) { 144 Dart_Port error_port) {
134 DIR* dir_pointer; 145 DIR* dir_pointer;
135 do { 146 do {
136 dir_pointer = opendir(dir_name); 147 dir_pointer = opendir(dir_name);
137 } while (dir_pointer == NULL && errno == EINTR); 148 } while (dir_pointer == NULL && errno == EINTR);
138 if (dir_pointer == NULL) { 149 if (dir_pointer == NULL) {
139 PostError(error_port, "Directory listing failed for: ", dir_name, errno); 150 PostError(error_port, "Directory listing failed for: ", dir_name, errno);
140 return false; 151 return false;
141 } 152 }
142 153
143 // Compute full path for the directory currently being listed. 154 // Compute full path for the directory currently being listed. The
155 // path buffer will be used to construct the current path in the
156 // recursive traversal. path_length does not always equal
157 // strlen(path) but indicates the current prefix of path that is the
158 // path of the current directory in the traversal.
144 char *path = static_cast<char*>(malloc(PATH_MAX)); 159 char *path = static_cast<char*>(malloc(PATH_MAX));
145 ASSERT(path != NULL); 160 ASSERT(path != NULL);
146 int path_length = 0; 161 int path_length = 0;
147 ComputeFullPath(dir_name, path, &path_length); 162 bool valid = ComputeFullPath(dir_name, path, &path_length);
163 if (!valid) {
164 free(path);
165 PostError(error_port, "Directory listing failed for: ", dir_name, errno);
166 return false;
167 }
148 168
149 // Iterated the directory and post the directories and files to the 169 // Iterated the directory and post the directories and files to the
150 // ports. 170 // ports.
151 int success = 0; 171 int read = 0;
152 bool listing_error = false; 172 bool success = true;
153 dirent entry; 173 dirent entry;
154 dirent* result; 174 dirent* result;
155 while ((success = TEMP_FAILURE_RETRY(readdir_r(dir_pointer, 175 while ((read = TEMP_FAILURE_RETRY(readdir_r(dir_pointer,
156 &entry, 176 &entry,
157 &result))) == 0 && 177 &result))) == 0 &&
158 result != NULL && 178 result != NULL &&
159 !listing_error) { 179 success) {
160 switch (entry.d_type) { 180 switch (entry.d_type) {
161 case DT_DIR: 181 case DT_DIR:
162 listing_error = listing_error || !HandleDir(entry.d_name, 182 success = success && HandleDir(entry.d_name,
163 path, 183 path,
164 path_length, 184 path_length,
165 recursive, 185 recursive,
166 dir_port, 186 dir_port,
167 file_port, 187 file_port,
168 done_port, 188 done_port,
169 error_port); 189 error_port);
170 break; 190 break;
171 case DT_REG: 191 case DT_REG:
172 HandleFile(entry.d_name, path, path_length, file_port); 192 success = success && HandleFile(entry.d_name,
193 path,
194 path_length,
195 file_port);
173 break; 196 break;
174 case DT_UNKNOWN: { 197 case DT_UNKNOWN: {
175 // On some file systems the entry type is not determined by 198 // On some file systems the entry type is not determined by
176 // readdir_r. For those we use lstat to determine the entry 199 // readdir_r. For those we use lstat to determine the entry
177 // type. 200 // type.
178 struct stat entry_info; 201 struct stat entry_info;
179 size_t written = snprintf(path + path_length, 202 size_t written = snprintf(path + path_length,
180 PATH_MAX - path_length, 203 PATH_MAX - path_length,
181 "%s", 204 "%s",
182 entry.d_name); 205 entry.d_name);
183 ASSERT(written == strlen(entry.d_name)); 206 if (written != strlen(entry.d_name)) {
207 success = false;
208 break;
209 }
184 int lstat_success = TEMP_FAILURE_RETRY(lstat(path, &entry_info)); 210 int lstat_success = TEMP_FAILURE_RETRY(lstat(path, &entry_info));
185 if (lstat_success == -1) { 211 if (lstat_success == -1) {
186 listing_error = true; 212 success = false;
187 PostError(error_port, "Directory listing failed for: ", path, errno); 213 PostError(error_port, "Directory listing failed for: ", path, errno);
188 break; 214 break;
189 } 215 }
190 if ((entry_info.st_mode & S_IFMT) == S_IFDIR) { 216 if ((entry_info.st_mode & S_IFMT) == S_IFDIR) {
191 listing_error = listing_error || !HandleDir(entry.d_name, 217 success = success && HandleDir(entry.d_name,
192 path, 218 path,
193 path_length, 219 path_length,
194 recursive, 220 recursive,
195 dir_port, 221 dir_port,
196 file_port, 222 file_port,
197 done_port, 223 done_port,
198 error_port); 224 error_port);
199 } else if ((entry_info.st_mode & S_IFMT) == S_IFREG) { 225 } else if ((entry_info.st_mode & S_IFMT) == S_IFREG) {
200 HandleFile(entry.d_name, path, path_length, file_port); 226 success = success && HandleFile(entry.d_name,
227 path,
228 path_length,
229 file_port);
201 } 230 }
202 break; 231 break;
203 } 232 }
204 default: 233 default:
205 break; 234 break;
206 } 235 }
207 } 236 }
208 237
209 if (success != 0) { 238 if (read != 0) {
210 listing_error = true; 239 success = false;
211 PostError(error_port, "Directory listing failed", "", success); 240 PostError(error_port, "Directory listing failed", "", read);
212 } 241 }
213 242
214 if (closedir(dir_pointer) == -1) { 243 if (closedir(dir_pointer) == -1) {
215 PostError(error_port, "Failed to close directory", "", errno); 244 PostError(error_port, "Failed to close directory", "", errno);
216 } 245 }
217 free(path); 246 free(path);
218 247
219 return !listing_error; 248 return success;
220 } 249 }
221 250
222 251
252 static bool DeleteFile(char* file_name,
253 char* path,
254 int path_length) {
255 size_t written = snprintf(path + path_length,
256 PATH_MAX - path_length,
257 "%s",
258 file_name);
259 if (written != strlen(file_name)) {
260 return false;
261 }
262 return (remove(path) == 0);
263 }
264
265
266 static bool DeleteDir(char* dir_name,
267 char* path,
268 int path_length) {
269 if (strcmp(dir_name, ".") != 0 &&
270 strcmp(dir_name, "..") != 0) {
271 size_t written = snprintf(path + path_length,
272 PATH_MAX - path_length,
273 "%s",
274 dir_name);
275 if (written != strlen(dir_name)) {
276 return false;
277 }
278 return DeleteRecursively(path);
279 }
280 return true;
281 }
282
283
284 static bool DeleteRecursively(const char* dir_name) {
285 DIR* dir_pointer;
286 do {
287 dir_pointer = opendir(dir_name);
288 } while (dir_pointer == NULL && errno == EINTR);
289
290 if (dir_pointer == NULL) {
291 return false;
292 }
293
294 // Compute full path for the directory currently being deleted. The
295 // path buffer will be used to construct the current path in the
296 // recursive traversal. path_length does not always equal
297 // strlen(path) but indicates the current prefix of path that is the
298 // path of the current directory in the traversal.
299 char *path = static_cast<char*>(malloc(PATH_MAX));
300 ASSERT(path != NULL);
301 int path_length = 0;
302 bool valid = ComputeFullPath(dir_name, path, &path_length);
303 if (!valid) {
304 free(path);
305 return false;
306 }
307
308 // Iterate the directory and delete all files and directories.
309 int read = 0;
310 bool success = true;
311 dirent entry;
312 dirent* result;
313 while ((read = TEMP_FAILURE_RETRY(readdir_r(dir_pointer,
314 &entry,
315 &result))) == 0 &&
316 result != NULL &&
317 success) {
318 switch (entry.d_type) {
319 case DT_DIR:
320 success = success && DeleteDir(entry.d_name, path, path_length);
321 break;
322 case DT_REG:
323 success = success && DeleteFile(entry.d_name, path, path_length);
324 break;
325 case DT_UNKNOWN: {
326 // On some file systems the entry type is not determined by
327 // readdir_r. For those we use lstat to determine the entry
328 // type.
329 struct stat entry_info;
330 size_t written = snprintf(path + path_length,
331 PATH_MAX - path_length,
332 "%s",
333 entry.d_name);
334 if (written != strlen(entry.d_name)) {
335 success = false;
336 break;
337 }
338 int lstat_success = TEMP_FAILURE_RETRY(lstat(path, &entry_info));
339 if (lstat_success == -1) {
340 success = false;
341 break;
342 }
343 if ((entry_info.st_mode & S_IFMT) == S_IFDIR) {
344 success = success && DeleteDir(entry.d_name, path, path_length);
345 } else if ((entry_info.st_mode & S_IFMT) == S_IFREG) {
346 success = success && DeleteFile(entry.d_name, path, path_length);
347 }
348 break;
349 }
350 default:
351 break;
352 }
353 }
354
355 free(path);
356
357 if ((read != 0) ||
358 (closedir(dir_pointer) == -1) ||
359 (remove(dir_name) == -1)) {
360 return false;
361 }
362
363 return success;
364 }
365
366
223 void Directory::List(const char* dir_name, 367 void Directory::List(const char* dir_name,
224 bool recursive, 368 bool recursive,
225 Dart_Port dir_port, 369 Dart_Port dir_port,
226 Dart_Port file_port, 370 Dart_Port file_port,
227 Dart_Port done_port, 371 Dart_Port done_port,
228 Dart_Port error_port) { 372 Dart_Port error_port) {
229 bool completed = ListRecursively(dir_name, 373 bool completed = ListRecursively(dir_name,
230 recursive, 374 recursive,
231 dir_port, 375 dir_port,
232 file_port, 376 file_port,
(...skipping 69 matching lines...) Expand 10 before | Expand all | Expand 10 after
302 if (result == NULL) { 446 if (result == NULL) {
303 SetOsErrorMessage(os_error_message, os_error_message_len); 447 SetOsErrorMessage(os_error_message, os_error_message_len);
304 free(*path); 448 free(*path);
305 *path = NULL; 449 *path = NULL;
306 return errno; 450 return errno;
307 } 451 }
308 return 0; 452 return 0;
309 } 453 }
310 454
311 455
312 bool Directory::Delete(const char* dir_name) { 456 bool Directory::Delete(const char* dir_name, bool recursive) {
313 return (TEMP_FAILURE_RETRY(rmdir(dir_name)) == 0); 457 if (!recursive) {
458 return (TEMP_FAILURE_RETRY(remove(dir_name)) == 0);
459 } else {
460 return DeleteRecursively(dir_name);
461 }
314 } 462 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698