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

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

Issue 12220034: Use a PathBuffer class in dart:io directory lister. (Closed) Base URL: https://dart.googlecode.com/svn/branches/bleeding_edge/dart
Patch Set: Refactor to use a PathBuffer class Created 7 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 class PathBuffer {
17 public:
18 PathBuffer() : length(0) { }
16 19
17 static char* SafeStrNCpy(char* dest, const char* src, size_t n) { 20
18 strncpy(dest, src, n); 21
19 dest[n - 1] = '\0'; 22 char data[PATH_MAX + 1];
20 return dest; 23 int length;
21 } 24
25 bool Add(const char* name) {
26 size_t written = snprintf(data + length,
27 PATH_MAX - length,
28 "%s",
29 name);
30 data[PATH_MAX] = '\0';
31 if (written == strnlen(name, PATH_MAX + 1)) {
32 length += written;
33 return true;
34 } else {
35 return false;
36 }
37 }
38
39 void Reset(int new_length) {
40 length = new_length;
41 data[length] = '\0';
42 }
43 };
44
22 45
23 46
24 // Forward declarations. 47 // Forward declarations.
25 static bool ListRecursively(const char* dir_name, 48 static bool ListRecursively(const char* dir_name,
26 bool recursive, 49 bool recursive,
27 DirectoryListing* listing); 50 DirectoryListing* listing);
28 static bool DeleteRecursively(const char* dir_name); 51 static bool DeleteRecursively(const char* dir_name);
29 52
30 53
31 static bool ComputeFullPath(const char* dir_name, 54 static PathBuffer* ComputeFullPath(const char* dir_name) {
32 char* path, 55 PathBuffer* path = new PathBuffer();
33 int* path_length) {
34 char* abs_path; 56 char* abs_path;
35 do { 57 do {
36 abs_path = realpath(dir_name, path); 58 abs_path = realpath(dir_name, path->data);
37 } while (abs_path == NULL && errno == EINTR); 59 } while (abs_path == NULL && errno == EINTR);
38 if (abs_path == NULL) { 60 if (abs_path == NULL) {
39 return false; 61 delete path;
62 return NULL;
40 } 63 }
41 *path_length = strlen(path); 64 path->length = strnlen(path->data, PATH_MAX);
42 size_t written = snprintf(path + *path_length, 65 if (path->Add(File::PathSeparator())) {
43 PATH_MAX - *path_length, 66 return path;
44 "%s", 67 } else {
45 File::PathSeparator()); 68 delete path;
46 if (written != strlen(File::PathSeparator())) { 69 return NULL;
47 return false;
48 } 70 }
49 *path_length += written; 71 }
50 return true; 72
73 static bool HandleDir(char* dir_name,
74 PathBuffer* path,
75 bool recursive,
76 DirectoryListing *listing) {
77 if (strcmp(dir_name, ".") == 0) return true;
78 if (strcmp(dir_name, "..") == 0) return true;
79 return path->Add(dir_name) &&
80 listing->HandleDirectory(path->data) &&
81 (!recursive || ListRecursively(path->data, recursive, listing));
82 }
83
84 static bool HandleFile(char* file_name,
85 PathBuffer* path,
86 DirectoryListing *listing) {
87 // TODO(sgjesse): Pass flags to indicate whether file responses are
88 // needed.
89 return path->Add(file_name) && listing->HandleFile(path->data);
51 } 90 }
52 91
53 92
54 static bool HandleDir(char* dir_name,
55 char* path,
56 int path_length,
57 bool recursive,
58 DirectoryListing *listing) {
59 if (strcmp(dir_name, ".") != 0 &&
60 strcmp(dir_name, "..") != 0) {
61 size_t written = snprintf(path + path_length,
62 PATH_MAX - path_length,
63 "%s",
64 dir_name);
65 if (written != strlen(dir_name)) {
66 return false;
67 }
68 bool ok = listing->HandleDirectory(path);
69 if (!ok) return ok;
70 if (recursive) {
71 return ListRecursively(path, recursive, listing);
72 }
73 }
74 return true;
75 }
76
77
78 static bool HandleFile(char* file_name,
79 char* path,
80 int path_length,
81 DirectoryListing *listing) {
82 // TODO(sgjesse): Pass flags to indicate whether file responses are
83 // needed.
84 size_t written = snprintf(path + path_length,
85 PATH_MAX - path_length,
86 "%s",
87 file_name);
88 if (written != strlen(file_name)) {
89 return false;
90 }
91 return listing->HandleFile(path);
92 }
93
94
95 static void PostError(DirectoryListing *listing, 93 static void PostError(DirectoryListing *listing,
96 const char* dir_name) { 94 const char* dir_name) {
97 listing->HandleError(dir_name); 95 listing->HandleError(dir_name);
98 } 96 }
99 97
100 98
101 static bool ListRecursively(const char* dir_name, 99 static bool ListRecursively(const char* dir_name,
102 bool recursive, 100 bool recursive,
103 DirectoryListing *listing) { 101 DirectoryListing *listing) {
104 DIR* dir_pointer; 102 DIR* dir_pointer;
105 do { 103 do {
106 dir_pointer = opendir(dir_name); 104 dir_pointer = opendir(dir_name);
107 } while (dir_pointer == NULL && errno == EINTR); 105 } while (dir_pointer == NULL && errno == EINTR);
108 if (dir_pointer == NULL) { 106 if (dir_pointer == NULL) {
109 PostError(listing, dir_name); 107 PostError(listing, dir_name);
110 return false; 108 return false;
111 } 109 }
112 110
113 // Compute full path for the directory currently being listed. The 111 // Compute full path for the directory currently being listed. The
114 // path buffer will be used to construct the current path in the 112 // path buffer will be used to construct the current path in the
115 // recursive traversal. path_length does not always equal 113 // recursive traversal. path_length does not always equal
116 // strlen(path) but indicates the current prefix of path that is the 114 // strlen(path) but indicates the current prefix of path that is the
117 // path of the current directory in the traversal. 115 // path of the current directory in the traversal.
118 char *path = static_cast<char*>(malloc(PATH_MAX)); 116 PathBuffer* path = ComputeFullPath(dir_name);
119 ASSERT(path != NULL); 117 if (path == NULL) {
120 int path_length = 0;
121 bool valid = ComputeFullPath(dir_name, path, &path_length);
122 if (!valid) {
123 free(path);
124 PostError(listing, dir_name); 118 PostError(listing, dir_name);
125 return false; 119 return false;
126 } 120 }
127 121 // Iterate the directory and post the directories and files to the
128 // Iterated the directory and post the directories and files to the
129 // ports. 122 // ports.
130 int read = 0; 123 int path_length = path->length;
124 int status = 0;
131 bool success = true; 125 bool success = true;
132 dirent entry; 126 dirent entry;
133 dirent* result; 127 dirent* result;
134 while ((read = TEMP_FAILURE_RETRY(readdir_r(dir_pointer, 128 while ((status = TEMP_FAILURE_RETRY(readdir_r(dir_pointer,
135 &entry, 129 &entry,
136 &result))) == 0 && 130 &result))) == 0 &&
137 result != NULL) { 131 result != NULL) {
138 switch (entry.d_type) { 132 switch (entry.d_type) {
139 case DT_DIR: 133 case DT_DIR:
140 success = HandleDir(entry.d_name, 134 success = HandleDir(entry.d_name,
141 path, 135 path,
142 path_length,
143 recursive, 136 recursive,
144 listing) && success; 137 listing) && success;
145 break; 138 break;
146 case DT_REG: 139 case DT_REG:
147 success = HandleFile(entry.d_name, 140 success = HandleFile(entry.d_name,
148 path, 141 path,
149 path_length,
150 listing) && success; 142 listing) && success;
151 break; 143 break;
152 case DT_LNK: 144 case DT_LNK:
153 case DT_UNKNOWN: { 145 case DT_UNKNOWN: {
154 // On some file systems the entry type is not determined by 146 // On some file systems the entry type is not determined by
155 // readdir_r. For those and for links we use stat to determine 147 // readdir_r. For those and for links we use stat to determine
156 // the actual entry type. Notice that stat returns the type of 148 // the actual entry type. Notice that stat returns the type of
157 // the file pointed to. 149 // the file pointed to.
158 struct stat entry_info; 150 struct stat entry_info;
159 size_t written = snprintf(path + path_length, 151 if (!path->Add(entry.d_name)) {
160 PATH_MAX - path_length,
161 "%s",
162 entry.d_name);
163 if (written != strlen(entry.d_name)) {
164 success = false; 152 success = false;
165 break; 153 break;
166 } 154 }
167 int stat_success = TEMP_FAILURE_RETRY(stat(path, &entry_info)); 155 int stat_success = TEMP_FAILURE_RETRY(stat(path->data, &entry_info));
168 if (stat_success == -1) { 156 if (stat_success == -1) {
169 success = false; 157 success = false;
170 PostError(listing, path); 158 PostError(listing, path->data);
171 break; 159 break;
172 } 160 }
161 path->Reset(path_length);
173 if (S_ISDIR(entry_info.st_mode)) { 162 if (S_ISDIR(entry_info.st_mode)) {
174 success = HandleDir(entry.d_name, 163 success = HandleDir(entry.d_name,
175 path, 164 path,
176 path_length,
177 recursive, 165 recursive,
178 listing) && success; 166 listing) && success;
179 } else if (S_ISREG(entry_info.st_mode)) { 167 } else if (S_ISREG(entry_info.st_mode)) {
180 success = HandleFile(entry.d_name, 168 success = HandleFile(entry.d_name,
181 path, 169 path,
182 path_length,
183 listing) && success; 170 listing) && success;
184 } 171 }
185 ASSERT(!S_ISLNK(entry_info.st_mode)); 172 ASSERT(!S_ISLNK(entry_info.st_mode));
186 break; 173 break;
187 } 174 }
188 default: 175 default:
189 break; 176 break;
190 } 177 }
178 path->Reset(path_length);
191 } 179 }
192 180
193 if (read != 0) { 181 if (status != 0) {
194 errno = read; 182 errno = status;
195 success = false; 183 success = false;
196 PostError(listing, dir_name); 184 PostError(listing, dir_name);
197 } 185 }
198 186
199 if (closedir(dir_pointer) == -1) { 187 if (closedir(dir_pointer) == -1) {
200 success = false; 188 success = false;
201 PostError(listing, dir_name); 189 PostError(listing, dir_name);
202 } 190 }
203 free(path); 191 delete path;
204 192
205 return success; 193 return success;
206 } 194 }
207 195
208 196
209 static bool DeleteFile(char* file_name, 197 static bool DeleteFile(char* file_name,
210 char* path, 198 PathBuffer* path) {
211 int path_length) { 199 return path->Add(file_name) && remove(path->data) == 0;
212 size_t written = snprintf(path + path_length,
213 PATH_MAX - path_length,
214 "%s",
215 file_name);
216 if (written != strlen(file_name)) {
217 return false;
218 }
219 return (remove(path) == 0);
220 } 200 }
221 201
222 202
223 static bool DeleteDir(char* dir_name, 203 static bool DeleteDir(char* dir_name,
224 char* path, 204 PathBuffer* path) {
225 int path_length) { 205 if (strcmp(dir_name, ".") == 0) return true;
226 if (strcmp(dir_name, ".") != 0 && 206 if (strcmp(dir_name, "..") == 0) return true;
227 strcmp(dir_name, "..") != 0) { 207 return path->Add(dir_name) && DeleteRecursively(path->data);
228 size_t written = snprintf(path + path_length,
229 PATH_MAX - path_length,
230 "%s",
231 dir_name);
232 if (written != strlen(dir_name)) {
233 return false;
234 }
235 return DeleteRecursively(path);
236 }
237 return true;
238 } 208 }
239 209
240 210
241 static bool DeleteRecursively(const char* dir_name) { 211 static bool DeleteRecursively(const char* dir_name) {
242 // Do not recurse into links for deletion. Instead delete the link. 212 // Do not recurse into links for deletion. Instead delete the link.
243 struct stat st; 213 struct stat st;
244 if (TEMP_FAILURE_RETRY(lstat(dir_name, &st)) == -1) { 214 if (TEMP_FAILURE_RETRY(lstat(dir_name, &st)) == -1) {
245 return false; 215 return false;
246 } else if (S_ISLNK(st.st_mode)) { 216 } else if (S_ISLNK(st.st_mode)) {
247 return (remove(dir_name) == 0); 217 return (remove(dir_name) == 0);
248 } 218 }
249 219
250 // Not a link. Attempt to open as a directory and recurse into the 220 // Not a link. Attempt to open as a directory and recurse into the
251 // directory. 221 // directory.
252 DIR* dir_pointer; 222 DIR* dir_pointer;
253 do { 223 do {
254 dir_pointer = opendir(dir_name); 224 dir_pointer = opendir(dir_name);
255 } while (dir_pointer == NULL && errno == EINTR); 225 } while (dir_pointer == NULL && errno == EINTR);
256 226
257 if (dir_pointer == NULL) { 227 if (dir_pointer == NULL) {
258 return false; 228 return false;
259 } 229 }
260 230
261 // Compute full path for the directory currently being deleted. The 231 // Compute full path for the directory currently being deleted. The
262 // path buffer will be used to construct the current path in the 232 // path buffer will be used to construct the current path in the
263 // recursive traversal. path_length does not always equal 233 // recursive traversal.
264 // strlen(path) but indicates the current prefix of path that is the 234 PathBuffer* path = ComputeFullPath(dir_name);
265 // path of the current directory in the traversal. 235 if (path == NULL) return false;
266 char *path = static_cast<char*>(malloc(PATH_MAX));
267 ASSERT(path != NULL);
268 int path_length = 0;
269 bool valid = ComputeFullPath(dir_name, path, &path_length);
270 if (!valid) {
271 free(path);
272 return false;
273 }
274 236
275 // Iterate the directory and delete all files and directories. 237 // Iterate the directory and delete all files and directories.
238 int path_length = path->length;
276 int read = 0; 239 int read = 0;
277 bool success = true; 240 bool success = true;
278 dirent entry; 241 dirent entry;
279 dirent* result; 242 dirent* result;
280 while ((read = TEMP_FAILURE_RETRY(readdir_r(dir_pointer, 243 while ((read = TEMP_FAILURE_RETRY(readdir_r(dir_pointer,
281 &entry, 244 &entry,
282 &result))) == 0 && 245 &result))) == 0 &&
283 result != NULL && 246 result != NULL &&
284 success) { 247 success) {
285 switch (entry.d_type) { 248 switch (entry.d_type) {
286 case DT_DIR: 249 case DT_DIR:
287 success = success && DeleteDir(entry.d_name, path, path_length); 250 success = success && DeleteDir(entry.d_name, path);
288 break; 251 break;
289 case DT_REG: 252 case DT_REG:
290 case DT_LNK: 253 case DT_LNK:
291 // Treat all links as files. This will delete the link which 254 // Treat all links as files. This will delete the link which
292 // is what we want no matter if the link target is a file or a 255 // is what we want no matter if the link target is a file or a
293 // directory. 256 // directory.
294 success = success && DeleteFile(entry.d_name, path, path_length); 257 success = success && DeleteFile(entry.d_name, path);
295 break; 258 break;
296 case DT_UNKNOWN: { 259 case DT_UNKNOWN: {
297 // On some file systems the entry type is not determined by 260 // On some file systems the entry type is not determined by
298 // readdir_r. For those we use lstat to determine the entry 261 // readdir_r. For those we use lstat to determine the entry
299 // type. 262 // type.
300 struct stat entry_info; 263 struct stat entry_info;
301 size_t written = snprintf(path + path_length, 264 if (!path->Add(entry.d_name)) {
302 PATH_MAX - path_length,
303 "%s",
304 entry.d_name);
305 if (written != strlen(entry.d_name)) {
306 success = false; 265 success = false;
307 break; 266 break;
308 } 267 }
309 int lstat_success = TEMP_FAILURE_RETRY(lstat(path, &entry_info)); 268 int lstat_success = TEMP_FAILURE_RETRY(lstat(path->data, &entry_info));
310 if (lstat_success == -1) { 269 if (lstat_success == -1) {
311 success = false; 270 success = false;
312 break; 271 break;
313 } 272 }
273 path->Reset(path_length);
314 if (S_ISDIR(entry_info.st_mode)) { 274 if (S_ISDIR(entry_info.st_mode)) {
315 success = success && DeleteDir(entry.d_name, path, path_length); 275 success = success && DeleteDir(entry.d_name, path);
316 } else if (S_ISREG(entry_info.st_mode) || S_ISLNK(entry_info.st_mode)) { 276 } else if (S_ISREG(entry_info.st_mode) || S_ISLNK(entry_info.st_mode)) {
317 // Treat links as files. This will delete the link which is 277 // Treat links as files. This will delete the link which is
318 // what we want no matter if the link target is a file or a 278 // what we want no matter if the link target is a file or a
319 // directory. 279 // directory.
320 success = success && DeleteFile(entry.d_name, path, path_length); 280 success = success && DeleteFile(entry.d_name, path);
321 } 281 }
322 break; 282 break;
323 } 283 }
324 default: 284 default:
325 break; 285 break;
326 } 286 }
287 path->Reset(path_length);
327 } 288 }
328 289 delete path;
329 free(path);
330 290
331 if ((read != 0) || 291 if ((read != 0) ||
332 (closedir(dir_pointer) == -1) || 292 (closedir(dir_pointer) == -1) ||
333 (remove(dir_name) == -1)) { 293 (remove(dir_name) == -1)) {
334 return false; 294 return false;
335 } 295 }
336 296
337 return success; 297 return success;
338 } 298 }
339 299
(...skipping 50 matching lines...) Expand 10 before | Expand all | Expand 10 after
390 } 350 }
391 return (result == 0); 351 return (result == 0);
392 } 352 }
393 353
394 354
395 char* Directory::CreateTemp(const char* const_template) { 355 char* Directory::CreateTemp(const char* const_template) {
396 // Returns a new, unused directory name, modifying the contents of 356 // Returns a new, unused directory name, modifying the contents of
397 // dir_template. Creates the directory with the permissions specified 357 // dir_template. Creates the directory with the permissions specified
398 // by the process umask. 358 // by the process umask.
399 // The return value must be freed by the caller. 359 // The return value must be freed by the caller.
400 char* path = static_cast<char*>(malloc(PATH_MAX + 1)); 360 PathBuffer* path = new PathBuffer();
401 SafeStrNCpy(path, const_template, PATH_MAX + 1); 361 path->Add(const_template);
402 int path_length = strlen(path); 362 if (path->length == 0) {
403 if (path_length > 0) { 363 path->Add("/tmp/temp_dir1_");
404 if ((path)[path_length - 1] == '/') { 364 } else if ((path->data)[path->length - 1] == '/') {
405 snprintf(path + path_length, PATH_MAX - path_length, "temp_dir_XXXXXX"); 365 path->Add("temp_dir_");
406 } else { 366 }
407 snprintf(path + path_length, PATH_MAX - path_length, "XXXXXX"); 367 if (!path->Add("XXXXXX")) {
408 } 368 // Pattern has overflowed.
409 } else { 369 delete path;
410 snprintf(path, PATH_MAX, "/tmp/temp_dir1_XXXXXX"); 370 return NULL;
411 } 371 }
412 char* result; 372 char* result;
413 do { 373 do {
414 result = mkdtemp(path); 374 result = mkdtemp(path->data);
415 } while (result == NULL && errno == EINTR); 375 } while (result == NULL && errno == EINTR);
416 if (result == NULL) { 376 if (result == NULL) {
417 free(path); 377 delete path;
418 return NULL; 378 return NULL;
419 } 379 }
420 return path; 380 int length = strnlen(path->data, PATH_MAX);
381 result = static_cast<char*>(malloc(length + 1));
382 strncpy(result, path->data, length);
383 result[length] = '\0';
384 delete path;
385 return result;
421 } 386 }
422 387
423 388
424 bool Directory::Delete(const char* dir_name, bool recursive) { 389 bool Directory::Delete(const char* dir_name, bool recursive) {
425 if (!recursive) { 390 if (!recursive) {
426 return (TEMP_FAILURE_RETRY(remove(dir_name)) == 0); 391 return (TEMP_FAILURE_RETRY(remove(dir_name)) == 0);
427 } else { 392 } else {
428 return DeleteRecursively(dir_name); 393 return DeleteRecursively(dir_name);
429 } 394 }
430 } 395 }
431 396
432 397
433 bool Directory::Rename(const char* path, const char* new_path) { 398 bool Directory::Rename(const char* path, const char* new_path) {
434 ExistsResult exists = Exists(path); 399 ExistsResult exists = Exists(path);
435 if (exists != EXISTS) return false; 400 if (exists != EXISTS) return false;
436 return (TEMP_FAILURE_RETRY(rename(path, new_path)) == 0); 401 return (TEMP_FAILURE_RETRY(rename(path, new_path)) == 0);
437 } 402 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698