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 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 Loading... | |
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 Loading... | |
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 } |
OLD | NEW |