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_posix.cc

Issue 10309004: Deal with symbolic links for file and directories on Mac and Linux. (Closed) Base URL: https://dart.googlecode.com/svn/branches/bleeding_edge/dart
Patch Set: Created 8 years, 7 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 | « no previous file | runtime/bin/file_linux.cc » ('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 <sys/param.h> 9 #include <sys/param.h>
10 #include <sys/stat.h> 10 #include <sys/stat.h>
(...skipping 132 matching lines...) Expand 10 before | Expand all | Expand 10 after
143 path_length, 143 path_length,
144 recursive, 144 recursive,
145 listing); 145 listing);
146 break; 146 break;
147 case DT_REG: 147 case DT_REG:
148 success = success && HandleFile(entry.d_name, 148 success = success && HandleFile(entry.d_name,
149 path, 149 path,
150 path_length, 150 path_length,
151 listing); 151 listing);
152 break; 152 break;
153 case DT_LNK:
153 case DT_UNKNOWN: { 154 case DT_UNKNOWN: {
154 // On some file systems the entry type is not determined by 155 // On some file systems the entry type is not determined by
155 // readdir_r. For those we use lstat to determine the entry 156 // readdir_r. For those and for links we use stat to determine
156 // type. 157 // the actual entry type. Notice that stat returns the type of
158 // the file pointed to.
157 struct stat entry_info; 159 struct stat entry_info;
158 size_t written = snprintf(path + path_length, 160 size_t written = snprintf(path + path_length,
159 PATH_MAX - path_length, 161 PATH_MAX - path_length,
160 "%s", 162 "%s",
161 entry.d_name); 163 entry.d_name);
162 if (written != strlen(entry.d_name)) { 164 if (written != strlen(entry.d_name)) {
163 success = false; 165 success = false;
164 break; 166 break;
165 } 167 }
166 int lstat_success = TEMP_FAILURE_RETRY(lstat(path, &entry_info)); 168 int stat_success = TEMP_FAILURE_RETRY(stat(path, &entry_info));
167 if (lstat_success == -1) { 169 if (stat_success == -1) {
168 success = false; 170 success = false;
169 PostError(listing, path); 171 PostError(listing, path);
170 break; 172 break;
171 } 173 }
172 if ((entry_info.st_mode & S_IFMT) == S_IFDIR) { 174 if (S_ISDIR(entry_info.st_mode)) {
173 success = success && HandleDir(entry.d_name, 175 success = success && HandleDir(entry.d_name,
174 path, 176 path,
175 path_length, 177 path_length,
176 recursive, 178 recursive,
177 listing); 179 listing);
178 } else if ((entry_info.st_mode & S_IFMT) == S_IFREG) { 180 } else if (S_ISREG(entry_info.st_mode)) {
179 success = success && HandleFile(entry.d_name, 181 success = success && HandleFile(entry.d_name,
180 path, 182 path,
181 path_length, 183 path_length,
182 listing); 184 listing);
183 } 185 }
186 ASSERT(!S_ISLNK(entry_info.st_mode));
184 break; 187 break;
185 } 188 }
186 default: 189 default:
187 break; 190 break;
188 } 191 }
189 } 192 }
190 193
191 if (read != 0) { 194 if (read != 0) {
192 errno = read; 195 errno = read;
193 success = false; 196 success = false;
(...skipping 36 matching lines...) Expand 10 before | Expand all | Expand 10 after
230 if (written != strlen(dir_name)) { 233 if (written != strlen(dir_name)) {
231 return false; 234 return false;
232 } 235 }
233 return DeleteRecursively(path); 236 return DeleteRecursively(path);
234 } 237 }
235 return true; 238 return true;
236 } 239 }
237 240
238 241
239 static bool DeleteRecursively(const char* dir_name) { 242 static bool DeleteRecursively(const char* dir_name) {
243 // Do not recurse into links for deletion. Instead delete the link.
244 struct stat st;
245 if (TEMP_FAILURE_RETRY(lstat(dir_name, &st)) == -1) {
246 return false;
247 } else if (S_ISLNK(st.st_mode)) {
248 return (remove(dir_name) == 0);
249 }
250
251 // Not a link. Attempt to open as a directory and recurse into the
252 // directory.
240 DIR* dir_pointer; 253 DIR* dir_pointer;
241 do { 254 do {
242 dir_pointer = opendir(dir_name); 255 dir_pointer = opendir(dir_name);
243 } while (dir_pointer == NULL && errno == EINTR); 256 } while (dir_pointer == NULL && errno == EINTR);
244 257
245 if (dir_pointer == NULL) { 258 if (dir_pointer == NULL) {
246 return false; 259 return false;
247 } 260 }
248 261
249 // Compute full path for the directory currently being deleted. The 262 // Compute full path for the directory currently being deleted. The
(...skipping 18 matching lines...) Expand all
268 while ((read = TEMP_FAILURE_RETRY(readdir_r(dir_pointer, 281 while ((read = TEMP_FAILURE_RETRY(readdir_r(dir_pointer,
269 &entry, 282 &entry,
270 &result))) == 0 && 283 &result))) == 0 &&
271 result != NULL && 284 result != NULL &&
272 success) { 285 success) {
273 switch (entry.d_type) { 286 switch (entry.d_type) {
274 case DT_DIR: 287 case DT_DIR:
275 success = success && DeleteDir(entry.d_name, path, path_length); 288 success = success && DeleteDir(entry.d_name, path, path_length);
276 break; 289 break;
277 case DT_REG: 290 case DT_REG:
291 case DT_LNK:
292 // Treat all links as files. This will delete the link which
293 // is what we want no matter if the link target is a file or a
294 // directory.
278 success = success && DeleteFile(entry.d_name, path, path_length); 295 success = success && DeleteFile(entry.d_name, path, path_length);
279 break; 296 break;
280 case DT_UNKNOWN: { 297 case DT_UNKNOWN: {
281 // On some file systems the entry type is not determined by 298 // On some file systems the entry type is not determined by
282 // readdir_r. For those we use lstat to determine the entry 299 // readdir_r. For those we use lstat to determine the entry
283 // type. 300 // type.
284 struct stat entry_info; 301 struct stat entry_info;
285 size_t written = snprintf(path + path_length, 302 size_t written = snprintf(path + path_length,
286 PATH_MAX - path_length, 303 PATH_MAX - path_length,
287 "%s", 304 "%s",
288 entry.d_name); 305 entry.d_name);
289 if (written != strlen(entry.d_name)) { 306 if (written != strlen(entry.d_name)) {
290 success = false; 307 success = false;
291 break; 308 break;
292 } 309 }
293 int lstat_success = TEMP_FAILURE_RETRY(lstat(path, &entry_info)); 310 int lstat_success = TEMP_FAILURE_RETRY(lstat(path, &entry_info));
294 if (lstat_success == -1) { 311 if (lstat_success == -1) {
295 success = false; 312 success = false;
296 break; 313 break;
297 } 314 }
298 if ((entry_info.st_mode & S_IFMT) == S_IFDIR) { 315 if (S_ISDIR(entry_info.st_mode)) {
299 success = success && DeleteDir(entry.d_name, path, path_length); 316 success = success && DeleteDir(entry.d_name, path, path_length);
300 } else if ((entry_info.st_mode & S_IFMT) == S_IFREG) { 317 } else if (S_ISREG(entry_info.st_mode) || S_ISLNK(entry_info.st_mode)) {
318 // Treat links as files. This will delete the link which is
319 // what we want no matter if the link target is a file or a
320 // directory.
301 success = success && DeleteFile(entry.d_name, path, path_length); 321 success = success && DeleteFile(entry.d_name, path, path_length);
302 } 322 }
303 break; 323 break;
304 } 324 }
305 default: 325 default:
306 break; 326 break;
307 } 327 }
308 } 328 }
309 329
310 free(path); 330 free(path);
(...skipping 11 matching lines...) Expand all
322 bool Directory::List(const char* dir_name, 342 bool Directory::List(const char* dir_name,
323 bool recursive, 343 bool recursive,
324 DirectoryListing *listing) { 344 DirectoryListing *listing) {
325 bool completed = ListRecursively(dir_name, recursive, listing); 345 bool completed = ListRecursively(dir_name, recursive, listing);
326 return completed; 346 return completed;
327 } 347 }
328 348
329 349
330 Directory::ExistsResult Directory::Exists(const char* dir_name) { 350 Directory::ExistsResult Directory::Exists(const char* dir_name) {
331 struct stat entry_info; 351 struct stat entry_info;
332 int lstat_success = TEMP_FAILURE_RETRY(lstat(dir_name, &entry_info)); 352 int success = TEMP_FAILURE_RETRY(stat(dir_name, &entry_info));
333 if (lstat_success == 0) { 353 if (success == 0) {
334 if ((entry_info.st_mode & S_IFMT) == S_IFDIR) { 354 if (S_ISDIR(entry_info.st_mode)) {
335 return EXISTS; 355 return EXISTS;
336 } else { 356 } else {
337 return DOES_NOT_EXIST; 357 return DOES_NOT_EXIST;
338 } 358 }
339 } else { 359 } else {
340 if (errno == EACCES || 360 if (errno == EACCES ||
341 errno == EBADF || 361 errno == EBADF ||
342 errno == EFAULT || 362 errno == EFAULT ||
343 errno == ENOMEM || 363 errno == ENOMEM ||
344 errno == EOVERFLOW) { 364 errno == EOVERFLOW) {
(...skipping 52 matching lines...) Expand 10 before | Expand all | Expand 10 after
397 } 417 }
398 418
399 419
400 bool Directory::Delete(const char* dir_name, bool recursive) { 420 bool Directory::Delete(const char* dir_name, bool recursive) {
401 if (!recursive) { 421 if (!recursive) {
402 return (TEMP_FAILURE_RETRY(remove(dir_name)) == 0); 422 return (TEMP_FAILURE_RETRY(remove(dir_name)) == 0);
403 } else { 423 } else {
404 return DeleteRecursively(dir_name); 424 return DeleteRecursively(dir_name);
405 } 425 }
406 } 426 }
OLDNEW
« no previous file with comments | « no previous file | runtime/bin/file_linux.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698