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

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

Issue 13818010: dart:io | Ensure that Directory.list terminates even when symbolic links create loops in the file s… (Closed) Base URL: https://dart.googlecode.com/svn/branches/bleeding_edge/dart
Patch Set: Add documentation of new behavior. Created 7 years, 8 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 "platform/globals.h" 5 #include "platform/globals.h"
6 #if defined(TARGET_OS_MACOS) 6 #if defined(TARGET_OS_MACOS)
7 7
8 #include "bin/directory.h" 8 #include "bin/directory.h"
9 9
10 #include <dirent.h> // NOLINT 10 #include <dirent.h> // NOLINT
(...skipping 36 matching lines...) Expand 10 before | Expand all | Expand 10 after
47 } 47 }
48 } 48 }
49 49
50 void Reset(int new_length) { 50 void Reset(int new_length) {
51 length = new_length; 51 length = new_length;
52 data[length] = '\0'; 52 data[length] = '\0';
53 } 53 }
54 }; 54 };
55 55
56 56
57 // A linked list of symbolic links, with their unique file system identifiers.
58 // These are scanned to detect loops while doing a recursive directory listing.
59 struct LinkList {
60 dev_t dev;
61 ino_t ino;
62 LinkList* next;
63 };
64
65
57 // Forward declarations. 66 // Forward declarations.
58 static bool ListRecursively(PathBuffer* path, 67 static bool ListRecursively(PathBuffer* path,
59 bool recursive, 68 bool recursive,
60 bool follow_links, 69 bool follow_links,
70 LinkList* seen,
61 DirectoryListing* listing); 71 DirectoryListing* listing);
62 static bool DeleteRecursively(PathBuffer* path); 72 static bool DeleteRecursively(PathBuffer* path);
63 73
64 74
65 static void PostError(DirectoryListing *listing, 75 static void PostError(DirectoryListing *listing,
66 const char* dir_name) { 76 const char* dir_name) {
67 listing->HandleError(dir_name); 77 listing->HandleError(dir_name);
68 } 78 }
69 79
70 80
71 static bool HandleDir(char* dir_name, 81 static bool HandleDir(char* dir_name,
72 PathBuffer* path, 82 PathBuffer* path,
73 bool recursive, 83 bool recursive,
74 bool follow_links, 84 bool follow_links,
85 LinkList* seen,
75 DirectoryListing *listing) { 86 DirectoryListing *listing) {
76 if (strcmp(dir_name, ".") == 0) return true; 87 if (strcmp(dir_name, ".") == 0) return true;
77 if (strcmp(dir_name, "..") == 0) return true; 88 if (strcmp(dir_name, "..") == 0) return true;
78 if (!path->Add(dir_name)) { 89 if (!path->Add(dir_name)) {
79 PostError(listing, path->data); 90 PostError(listing, path->data);
80 return false; 91 return false;
81 } 92 }
82 return listing->HandleDirectory(path->data) && 93 return listing->HandleDirectory(path->data) &&
83 (!recursive || ListRecursively(path, recursive, follow_links, listing)); 94 (!recursive ||
95 ListRecursively(path, recursive, follow_links, seen, listing));
84 } 96 }
85 97
86 98
87 static bool HandleFile(char* file_name, 99 static bool HandleFile(char* file_name,
88 PathBuffer* path, 100 PathBuffer* path,
89 DirectoryListing *listing) { 101 DirectoryListing *listing) {
90 if (!path->Add(file_name)) { 102 if (!path->Add(file_name)) {
91 PostError(listing, path->data); 103 PostError(listing, path->data);
92 return false; 104 return false;
93 } 105 }
94 return listing->HandleFile(path->data); 106 return listing->HandleFile(path->data);
95 } 107 }
96 108
97 109
98 static bool HandleLink(char* link_name, 110 static bool HandleLink(char* link_name,
99 PathBuffer* path, 111 PathBuffer* path,
100 DirectoryListing *listing) { 112 DirectoryListing *listing) {
101 if (!path->Add(link_name)) { 113 if (!path->Add(link_name)) {
102 PostError(listing, path->data); 114 PostError(listing, path->data);
103 return false; 115 return false;
104 } 116 }
105 return listing->HandleLink(path->data); 117 return listing->HandleLink(path->data);
106 } 118 }
107 119
108 120
109 static bool ListRecursively(PathBuffer* path, 121 static bool ListRecursively(PathBuffer* path,
110 bool recursive, 122 bool recursive,
111 bool follow_links, 123 bool follow_links,
124 LinkList* seen,
112 DirectoryListing *listing) { 125 DirectoryListing *listing) {
113 if (!path->Add(File::PathSeparator())) { 126 if (!path->Add(File::PathSeparator())) {
114 PostError(listing, path->data); 127 PostError(listing, path->data);
115 return false; 128 return false;
116 } 129 }
117 DIR* dir_pointer; 130 DIR* dir_pointer;
118 do { 131 do {
119 dir_pointer = opendir(path->data); 132 dir_pointer = opendir(path->data);
120 } while (dir_pointer == NULL && errno == EINTR); 133 } while (dir_pointer == NULL && errno == EINTR);
121 if (dir_pointer == NULL) { 134 if (dir_pointer == NULL) {
(...skipping 38 matching lines...) Expand 10 before | Expand all | Expand 10 after
160 // On some file systems the entry type is not determined by 173 // On some file systems the entry type is not determined by
161 // readdir_r. For those and for links we use stat to determine 174 // readdir_r. For those and for links we use stat to determine
162 // the actual entry type. Notice that stat returns the type of 175 // the actual entry type. Notice that stat returns the type of
163 // the file pointed to. 176 // the file pointed to.
164 struct stat entry_info; 177 struct stat entry_info;
165 if (!path->Add(entry.d_name)) { 178 if (!path->Add(entry.d_name)) {
166 success = false; 179 success = false;
167 break; 180 break;
168 } 181 }
169 int stat_success; 182 int stat_success;
170 if (follow_links) { 183 stat_success = TEMP_FAILURE_RETRY(lstat(path->data, &entry_info));
171 stat_success = TEMP_FAILURE_RETRY(stat(path->data, &entry_info));
172 if (stat_success == -1) {
173 stat_success = TEMP_FAILURE_RETRY(lstat(path->data, &entry_info));
174 }
175 } else {
176 stat_success = TEMP_FAILURE_RETRY(lstat(path->data, &entry_info));
177 }
178 if (stat_success == -1) { 184 if (stat_success == -1) {
179 success = false; 185 success = false;
180 PostError(listing, path->data); 186 PostError(listing, path->data);
181 break; 187 break;
182 } 188 }
189 if (follow_links && S_ISLNK(entry_info.st_mode)) {
190 // Check to see if we are in a loop created by a symbolic link.
191 LinkList current_link = { entry_info.st_dev,
192 entry_info.st_ino,
193 seen };
194 LinkList* previous = seen;
195 bool looping_link = false;
196 while (previous != NULL) {
197 if (previous->dev == current_link.dev &&
198 previous->ino == current_link.ino) {
199 // Report the looping link as a link, rather than following it.
200 path->Reset(path_length);
201 success = HandleLink(entry.d_name,
202 path,
203 listing) && success;
204 looping_link = true;
205 break;
206 }
207 previous = previous->next;
208 }
209 if (looping_link) break;
210 stat_success = TEMP_FAILURE_RETRY(stat(path->data, &entry_info));
211 if (stat_success == -1) {
212 // Report a broken link as a link, even if follow_links is true.
213 path->Reset(path_length);
214 success = HandleLink(entry.d_name,
215 path,
216 listing) && success;
217 break;
218 }
219 if (S_ISDIR(entry_info.st_mode)) {
220 // Recurse into the subdirectory with current_link added to the
221 // linked list of seen file system links.
222 path->Reset(path_length);
223 success = HandleDir(entry.d_name,
224 path,
225 recursive,
226 follow_links,
227 &current_link,
228 listing) && success;
229 break;
230 }
231 }
183 path->Reset(path_length); 232 path->Reset(path_length);
184 if (S_ISDIR(entry_info.st_mode)) { 233 if (S_ISDIR(entry_info.st_mode)) {
185 success = HandleDir(entry.d_name, 234 success = HandleDir(entry.d_name,
186 path, 235 path,
187 recursive, 236 recursive,
188 follow_links, 237 follow_links,
238 seen,
189 listing) && success; 239 listing) && success;
190 } else if (S_ISREG(entry_info.st_mode)) { 240 } else if (S_ISREG(entry_info.st_mode)) {
191 success = HandleFile(entry.d_name, 241 success = HandleFile(entry.d_name,
192 path, 242 path,
193 listing) && success; 243 listing) && success;
194 } else if (S_ISLNK(entry_info.st_mode)) { 244 } else if (S_ISLNK(entry_info.st_mode)) {
195 success = HandleLink(entry.d_name, 245 success = HandleLink(entry.d_name,
196 path, 246 path,
197 listing) && success; 247 listing) && success;
198 } 248 }
(...skipping 121 matching lines...) Expand 10 before | Expand all | Expand 10 after
320 370
321 bool Directory::List(const char* dir_name, 371 bool Directory::List(const char* dir_name,
322 bool recursive, 372 bool recursive,
323 bool follow_links, 373 bool follow_links,
324 DirectoryListing *listing) { 374 DirectoryListing *listing) {
325 PathBuffer path; 375 PathBuffer path;
326 if (!path.Add(dir_name)) { 376 if (!path.Add(dir_name)) {
327 PostError(listing, dir_name); 377 PostError(listing, dir_name);
328 return false; 378 return false;
329 } 379 }
330 return ListRecursively(&path, recursive, follow_links, listing); 380 return ListRecursively(&path, recursive, follow_links, NULL, listing);
331 } 381 }
332 382
333 383
334 Directory::ExistsResult Directory::Exists(const char* dir_name) { 384 Directory::ExistsResult Directory::Exists(const char* dir_name) {
335 struct stat entry_info; 385 struct stat entry_info;
336 int success = TEMP_FAILURE_RETRY(stat(dir_name, &entry_info)); 386 int success = TEMP_FAILURE_RETRY(stat(dir_name, &entry_info));
337 if (success == 0) { 387 if (success == 0) {
338 if (S_ISDIR(entry_info.st_mode)) { 388 if (S_ISDIR(entry_info.st_mode)) {
339 return EXISTS; 389 return EXISTS;
340 } else { 390 } else {
(...skipping 84 matching lines...) Expand 10 before | Expand all | Expand 10 after
425 } 475 }
426 476
427 477
428 bool Directory::Rename(const char* path, const char* new_path) { 478 bool Directory::Rename(const char* path, const char* new_path) {
429 ExistsResult exists = Exists(path); 479 ExistsResult exists = Exists(path);
430 if (exists != EXISTS) return false; 480 if (exists != EXISTS) return false;
431 return (TEMP_FAILURE_RETRY(rename(path, new_path)) == 0); 481 return (TEMP_FAILURE_RETRY(rename(path, new_path)) == 0);
432 } 482 }
433 483
434 #endif // defined(TARGET_OS_MACOS) 484 #endif // defined(TARGET_OS_MACOS)
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698