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

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

Issue 12217086: Change Directory.list to use the input path, and not resolve it to a full path. (Closed) Base URL: https://dart.googlecode.com/svn/branches/bleeding_edge/dart
Patch Set: Add the path separator at the top of the recursive function. 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
« no previous file with comments | « runtime/bin/directory_linux.cc ('k') | tests/standalone/io/file_system_links_test.dart » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
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 <string.h> 9 #include <string.h>
10 #include <sys/param.h> 10 #include <sys/param.h>
11 #include <sys/stat.h> 11 #include <sys/stat.h>
12 #include <unistd.h> 12 #include <unistd.h>
13 13
14 #include "bin/file.h" 14 #include "bin/file.h"
15 #include "bin/platform.h" 15 #include "bin/platform.h"
16 16
17 class PathBuffer { 17 class PathBuffer {
18 public: 18 public:
19 PathBuffer() : length(0) { } 19 PathBuffer() : length(0) {
20 data = new char[PATH_MAX + 1];
21 }
20 22
23 ~PathBuffer() {
24 delete[] data;
25 }
21 26
22 27 char* data;
23 char data[PATH_MAX + 1];
24 int length; 28 int length;
25 29
26 bool Add(const char* name) { 30 bool Add(const char* name) {
27 size_t written = snprintf(data + length, 31 size_t written = snprintf(data + length,
28 PATH_MAX - length, 32 PATH_MAX - length,
29 "%s", 33 "%s",
30 name); 34 name);
31 data[PATH_MAX] = '\0'; 35 data[PATH_MAX] = '\0';
32 if (written == strlen(name)) { 36 if (written == strlen(name)) {
33 length += written; 37 length += written;
34 return true; 38 return true;
35 } else { 39 } else {
36 errno = ENAMETOOLONG; 40 errno = ENAMETOOLONG;
37 return false; 41 return false;
38 } 42 }
39 } 43 }
40 44
41 void Reset(int new_length) { 45 void Reset(int new_length) {
42 length = new_length; 46 length = new_length;
43 data[length] = '\0'; 47 data[length] = '\0';
44 } 48 }
45 }; 49 };
46 50
47 51
48
49 // Forward declarations. 52 // Forward declarations.
50 static bool ListRecursively(const char* dir_name, 53 static bool ListRecursively(PathBuffer* path,
51 bool recursive, 54 bool recursive,
52 DirectoryListing* listing); 55 DirectoryListing* listing);
53 static bool DeleteRecursively(const char* dir_name); 56 static bool DeleteRecursively(PathBuffer* path);
54 57
55 58
56 static void PostError(DirectoryListing *listing, 59 static void PostError(DirectoryListing *listing,
57 const char* dir_name) { 60 const char* dir_name) {
58 listing->HandleError(dir_name); 61 listing->HandleError(dir_name);
59 } 62 }
60 63
61 64
62 static PathBuffer* ComputeFullPath(const char* dir_name) {
63 PathBuffer* path = new PathBuffer();
64 char* abs_path;
65 do {
66 abs_path = realpath(dir_name, path->data);
67 } while (abs_path == NULL && errno == EINTR);
68 if (abs_path == NULL) {
69 delete path;
70 return NULL;
71 }
72 path->length = strlen(path->data);
73 if (path->Add(File::PathSeparator())) {
74 return path;
75 } else {
76 delete path;
77 return NULL;
78 }
79 }
80
81 static bool HandleDir(char* dir_name, 65 static bool HandleDir(char* dir_name,
82 PathBuffer* path, 66 PathBuffer* path,
83 bool recursive, 67 bool recursive,
84 DirectoryListing *listing) { 68 DirectoryListing *listing) {
85 if (strcmp(dir_name, ".") == 0) return true; 69 if (strcmp(dir_name, ".") == 0) return true;
86 if (strcmp(dir_name, "..") == 0) return true; 70 if (strcmp(dir_name, "..") == 0) return true;
87 if (!path->Add(dir_name)) { 71 if (!path->Add(dir_name)) {
88 PostError(listing, path->data); 72 PostError(listing, path->data);
89 return false; 73 return false;
90 } 74 }
91 return listing->HandleDirectory(path->data) && 75 return listing->HandleDirectory(path->data) &&
92 (!recursive || ListRecursively(path->data, recursive, listing)); 76 (!recursive || ListRecursively(path, recursive, listing));
93 } 77 }
94 78
79
95 static bool HandleFile(char* file_name, 80 static bool HandleFile(char* file_name,
96 PathBuffer* path, 81 PathBuffer* path,
97 DirectoryListing *listing) { 82 DirectoryListing *listing) {
98 if (!path->Add(file_name)) { 83 if (!path->Add(file_name)) {
99 PostError(listing, path->data); 84 PostError(listing, path->data);
100 return false; 85 return false;
101 } 86 }
102 return listing->HandleFile(path->data); 87 return listing->HandleFile(path->data);
103 } 88 }
104 89
105 90
106 static bool ListRecursively(const char* dir_name, 91 static bool ListRecursively(PathBuffer* path,
107 bool recursive, 92 bool recursive,
108 DirectoryListing *listing) { 93 DirectoryListing *listing) {
94 if (!path->Add(File::PathSeparator())) {
95 PostError(listing, path->data);
96 return false;
97 }
109 DIR* dir_pointer; 98 DIR* dir_pointer;
110 do { 99 do {
111 dir_pointer = opendir(dir_name); 100 dir_pointer = opendir(path->data);
112 } while (dir_pointer == NULL && errno == EINTR); 101 } while (dir_pointer == NULL && errno == EINTR);
113 if (dir_pointer == NULL) { 102 if (dir_pointer == NULL) {
114 PostError(listing, dir_name); 103 PostError(listing, path->data);
115 return false; 104 return false;
116 } 105 }
117 106
118 // Compute full path for the directory currently being listed. The
119 // path buffer will be used to construct the current path in the
120 // recursive traversal. path_length does not always equal
121 // strlen(path) but indicates the current prefix of path that is the
122 // path of the current directory in the traversal.
123 PathBuffer* path = ComputeFullPath(dir_name);
124 if (path == NULL) {
125 PostError(listing, dir_name);
126 return false;
127 }
128 // Iterate the directory and post the directories and files to the 107 // Iterate the directory and post the directories and files to the
129 // ports. 108 // ports.
130 int path_length = path->length; 109 int path_length = path->length;
131 int status = 0; 110 int status = 0;
132 bool success = true; 111 bool success = true;
133 dirent entry; 112 dirent entry;
134 dirent* result; 113 dirent* result;
135 while ((status = TEMP_FAILURE_RETRY(readdir_r(dir_pointer, 114 while ((status = TEMP_FAILURE_RETRY(readdir_r(dir_pointer,
136 &entry, 115 &entry,
137 &result))) == 0 && 116 &result))) == 0 &&
(...skipping 43 matching lines...) Expand 10 before | Expand all | Expand 10 after
181 } 160 }
182 default: 161 default:
183 break; 162 break;
184 } 163 }
185 path->Reset(path_length); 164 path->Reset(path_length);
186 } 165 }
187 166
188 if (status != 0) { 167 if (status != 0) {
189 errno = status; 168 errno = status;
190 success = false; 169 success = false;
191 PostError(listing, dir_name); 170 PostError(listing, path->data);
192 } 171 }
193 172
194 if (closedir(dir_pointer) == -1) { 173 if (closedir(dir_pointer) == -1) {
195 success = false; 174 success = false;
196 PostError(listing, dir_name); 175 PostError(listing, path->data);
197 } 176 }
198 delete path;
199 177
200 return success; 178 return success;
201 } 179 }
202 180
203 181
204 static bool DeleteFile(char* file_name, 182 static bool DeleteFile(char* file_name,
205 PathBuffer* path) { 183 PathBuffer* path) {
206 return path->Add(file_name) && remove(path->data) == 0; 184 return path->Add(file_name) && remove(path->data) == 0;
207 } 185 }
208 186
209 187
210 static bool DeleteDir(char* dir_name, 188 static bool DeleteDir(char* dir_name,
211 PathBuffer* path) { 189 PathBuffer* path) {
212 if (strcmp(dir_name, ".") == 0) return true; 190 if (strcmp(dir_name, ".") == 0) return true;
213 if (strcmp(dir_name, "..") == 0) return true; 191 if (strcmp(dir_name, "..") == 0) return true;
214 return path->Add(dir_name) && DeleteRecursively(path->data); 192 return path->Add(dir_name) && DeleteRecursively(path);
215 } 193 }
216 194
217 195
218 static bool DeleteRecursively(const char* dir_name) { 196 static bool DeleteRecursively(PathBuffer* path) {
219 // Do not recurse into links for deletion. Instead delete the link. 197 if (!path->Add(File::PathSeparator())) return false;
198 // Do not recurse into links for deletion. Instead delete the link.
220 struct stat st; 199 struct stat st;
221 if (TEMP_FAILURE_RETRY(lstat(dir_name, &st)) == -1) { 200 if (TEMP_FAILURE_RETRY(lstat(path->data, &st)) == -1) {
222 return false; 201 return false;
223 } else if (S_ISLNK(st.st_mode)) { 202 } else if (S_ISLNK(st.st_mode)) {
224 return (remove(dir_name) == 0); 203 return (remove(path->data) == 0);
225 } 204 }
226 205
227 // Not a link. Attempt to open as a directory and recurse into the 206 // Not a link. Attempt to open as a directory and recurse into the
228 // directory. 207 // directory.
229 DIR* dir_pointer; 208 DIR* dir_pointer;
230 do { 209 do {
231 dir_pointer = opendir(dir_name); 210 dir_pointer = opendir(path->data);
232 } while (dir_pointer == NULL && errno == EINTR); 211 } while (dir_pointer == NULL && errno == EINTR);
233 212
234 if (dir_pointer == NULL) { 213 if (dir_pointer == NULL) {
235 return false; 214 return false;
236 } 215 }
237 216
238 // Compute full path for the directory currently being deleted. The
239 // path buffer will be used to construct the current path in the
240 // recursive traversal.
241 PathBuffer* path = ComputeFullPath(dir_name);
242 if (path == NULL) return false;
243
244 // Iterate the directory and delete all files and directories. 217 // Iterate the directory and delete all files and directories.
245 int path_length = path->length; 218 int path_length = path->length;
246 int read = 0; 219 int read = 0;
247 bool success = true; 220 bool success = true;
248 dirent entry; 221 dirent entry;
249 dirent* result; 222 dirent* result;
250 while ((read = TEMP_FAILURE_RETRY(readdir_r(dir_pointer, 223 while ((read = TEMP_FAILURE_RETRY(readdir_r(dir_pointer,
251 &entry, 224 &entry,
252 &result))) == 0 && 225 &result))) == 0 &&
253 result != NULL && 226 result != NULL &&
(...skipping 32 matching lines...) Expand 10 before | Expand all | Expand 10 after
286 // directory. 259 // directory.
287 success = success && DeleteFile(entry.d_name, path); 260 success = success && DeleteFile(entry.d_name, path);
288 } 261 }
289 break; 262 break;
290 } 263 }
291 default: 264 default:
292 break; 265 break;
293 } 266 }
294 path->Reset(path_length); 267 path->Reset(path_length);
295 } 268 }
296 delete path;
297 269
298 if ((read != 0) || 270 if ((read != 0) ||
299 (closedir(dir_pointer) == -1) || 271 (closedir(dir_pointer) == -1) ||
300 (remove(dir_name) == -1)) { 272 (remove(path->data) == -1)) {
301 return false; 273 return false;
302 } 274 }
303
304 return success; 275 return success;
305 } 276 }
306 277
307 278
308 bool Directory::List(const char* dir_name, 279 bool Directory::List(const char* dir_name,
309 bool recursive, 280 bool recursive,
310 DirectoryListing *listing) { 281 DirectoryListing *listing) {
311 bool completed = ListRecursively(dir_name, recursive, listing); 282 PathBuffer path;
312 return completed; 283 if (!path.Add(dir_name)) {
284 PostError(listing, dir_name);
285 return false;
286 }
287 return ListRecursively(&path, recursive, listing);
313 } 288 }
314 289
315 290
316 Directory::ExistsResult Directory::Exists(const char* dir_name) { 291 Directory::ExistsResult Directory::Exists(const char* dir_name) {
317 struct stat entry_info; 292 struct stat entry_info;
318 int success = TEMP_FAILURE_RETRY(stat(dir_name, &entry_info)); 293 int success = TEMP_FAILURE_RETRY(stat(dir_name, &entry_info));
319 if (success == 0) { 294 if (success == 0) {
320 if (S_ISDIR(entry_info.st_mode)) { 295 if (S_ISDIR(entry_info.st_mode)) {
321 return EXISTS; 296 return EXISTS;
322 } else { 297 } else {
(...skipping 34 matching lines...) Expand 10 before | Expand all | Expand 10 after
357 } 332 }
358 return (result == 0); 333 return (result == 0);
359 } 334 }
360 335
361 336
362 char* Directory::CreateTemp(const char* const_template) { 337 char* Directory::CreateTemp(const char* const_template) {
363 // Returns a new, unused directory name, modifying the contents of 338 // Returns a new, unused directory name, modifying the contents of
364 // dir_template. Creates the directory with the permissions specified 339 // dir_template. Creates the directory with the permissions specified
365 // by the process umask. 340 // by the process umask.
366 // The return value must be freed by the caller. 341 // The return value must be freed by the caller.
367 PathBuffer* path = new PathBuffer(); 342 PathBuffer path;
368 path->Add(const_template); 343 path.Add(const_template);
369 if (path->length == 0) { 344 if (path.length == 0) {
370 path->Add("/tmp/temp_dir1_"); 345 path.Add("/tmp/temp_dir1_");
371 } else if ((path->data)[path->length - 1] == '/') { 346 } else if ((path.data)[path.length - 1] == '/') {
372 path->Add("temp_dir_"); 347 path.Add("temp_dir_");
373 } 348 }
374 if (!path->Add("XXXXXX")) { 349 if (!path.Add("XXXXXX")) {
375 // Pattern has overflowed. 350 // Pattern has overflowed.
376 delete path;
377 return NULL; 351 return NULL;
378 } 352 }
379 char* result; 353 char* result;
380 do { 354 do {
381 result = mkdtemp(path->data); 355 result = mkdtemp(path.data);
382 } while (result == NULL && errno == EINTR); 356 } while (result == NULL && errno == EINTR);
383 if (result == NULL) { 357 if (result == NULL) {
384 delete path;
385 return NULL; 358 return NULL;
386 } 359 }
387 int length = strlen(path->data); 360 int length = strlen(path.data);
388 result = static_cast<char*>(malloc(length + 1)); 361 result = static_cast<char*>(malloc(length + 1));
389 strncpy(result, path->data, length); 362 strncpy(result, path.data, length);
390 result[length] = '\0'; 363 result[length] = '\0';
391 delete path;
392 return result; 364 return result;
393 } 365 }
394 366
395 367
396 bool Directory::Delete(const char* dir_name, bool recursive) { 368 bool Directory::Delete(const char* dir_name, bool recursive) {
397 if (!recursive) { 369 if (!recursive) {
398 return (TEMP_FAILURE_RETRY(remove(dir_name)) == 0); 370 return (TEMP_FAILURE_RETRY(remove(dir_name)) == 0);
399 } else { 371 } else {
400 return DeleteRecursively(dir_name); 372 PathBuffer path;
373 if (!path.Add(dir_name)) {
374 return false;
375 }
376 return DeleteRecursively(&path);
401 } 377 }
402 } 378 }
403 379
404 380
405 bool Directory::Rename(const char* path, const char* new_path) { 381 bool Directory::Rename(const char* path, const char* new_path) {
406 ExistsResult exists = Exists(path); 382 ExistsResult exists = Exists(path);
407 if (exists != EXISTS) return false; 383 if (exists != EXISTS) return false;
408 return (TEMP_FAILURE_RETRY(rename(path, new_path)) == 0); 384 return (TEMP_FAILURE_RETRY(rename(path, new_path)) == 0);
409 } 385 }
OLDNEW
« no previous file with comments | « runtime/bin/directory_linux.cc ('k') | tests/standalone/io/file_system_links_test.dart » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698