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

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

Issue 249233002: Fix recursive directory deletion, to not leak file descriptors (and pointers). (Closed) Base URL: https://dart.googlecode.com/svn/branches/bleeding_edge/dart
Patch Set: Add check Created 6 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
« no previous file with comments | « runtime/bin/directory_android.cc ('k') | runtime/bin/directory_macos.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 "platform/globals.h" 5 #include "platform/globals.h"
6 #if defined(TARGET_OS_LINUX) 6 #if defined(TARGET_OS_LINUX)
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 227 matching lines...) Expand 10 before | Expand all | Expand 10 after
238 if (NO_RETRY_EXPECTED(lstat64(path->AsString(), &st)) == -1) { 238 if (NO_RETRY_EXPECTED(lstat64(path->AsString(), &st)) == -1) {
239 return false; 239 return false;
240 } else if (S_ISREG(st.st_mode) || S_ISLNK(st.st_mode)) { 240 } else if (S_ISREG(st.st_mode) || S_ISLNK(st.st_mode)) {
241 return (NO_RETRY_EXPECTED(unlink(path->AsString())) == 0); 241 return (NO_RETRY_EXPECTED(unlink(path->AsString())) == 0);
242 } 242 }
243 243
244 if (!path->Add(File::PathSeparator())) return false; 244 if (!path->Add(File::PathSeparator())) return false;
245 245
246 // Not a link. Attempt to open as a directory and recurse into the 246 // Not a link. Attempt to open as a directory and recurse into the
247 // directory. 247 // directory.
248 DIR* dir_pointer; 248 DIR* dir_pointer = opendir(path->AsString());
249 do {
250 dir_pointer = opendir(path->AsString());
251 } while (dir_pointer == NULL && errno == EINTR);
252
253 if (dir_pointer == NULL) { 249 if (dir_pointer == NULL) {
254 return false; 250 return false;
255 } 251 }
256 252
257 // Iterate the directory and delete all files and directories. 253 // Iterate the directory and delete all files and directories.
258 int path_length = path->length(); 254 int path_length = path->length();
259 int read = 0;
260 bool success = true;
261 dirent entry; 255 dirent entry;
262 dirent* result; 256 dirent* result;
263 while ((read = NO_RETRY_EXPECTED( 257 while (NO_RETRY_EXPECTED(readdir_r(dir_pointer, &entry, &result)) == 0) {
264 readdir_r(dir_pointer, &entry, &result))) == 0 && 258 if (result == NULL) {
265 result != NULL && 259 // End of directory.
266 success) { 260 return NO_RETRY_EXPECTED(closedir(dir_pointer)) == 0 &&
261 NO_RETRY_EXPECTED(remove(path->AsString())) == 0;
262 }
263 bool ok = false;
267 switch (entry.d_type) { 264 switch (entry.d_type) {
268 case DT_DIR: 265 case DT_DIR:
269 success = success && DeleteDir(entry.d_name, path); 266 ok = DeleteDir(entry.d_name, path);
270 break; 267 break;
271 case DT_REG: 268 case DT_REG:
272 case DT_LNK: 269 case DT_LNK:
273 // Treat all links as files. This will delete the link which 270 // Treat all links as files. This will delete the link which
274 // is what we want no matter if the link target is a file or a 271 // is what we want no matter if the link target is a file or a
275 // directory. 272 // directory.
276 success = success && DeleteFile(entry.d_name, path); 273 ok = DeleteFile(entry.d_name, path);
277 break; 274 break;
278 case DT_UNKNOWN: { 275 case DT_UNKNOWN: {
279 if (!path->Add(entry.d_name)) { 276 if (!path->Add(entry.d_name)) {
280 success = false;
281 break; 277 break;
282 } 278 }
283 // On some file systems the entry type is not determined by 279 // On some file systems the entry type is not determined by
284 // readdir_r. For those we use lstat to determine the entry 280 // readdir_r. For those we use lstat to determine the entry
285 // type. 281 // type.
286 struct stat64 entry_info; 282 struct stat64 entry_info;
287 int lstat_success = NO_RETRY_EXPECTED( 283 if (NO_RETRY_EXPECTED(lstat64(path->AsString(), &entry_info)) == -1) {
288 lstat64(path->AsString(), &entry_info));
289 if (lstat_success == -1) {
290 success = false;
291 break; 284 break;
292 } 285 }
293 path->Reset(path_length); 286 path->Reset(path_length);
294 if (S_ISDIR(entry_info.st_mode)) { 287 if (S_ISDIR(entry_info.st_mode)) {
295 success = success && DeleteDir(entry.d_name, path); 288 ok = DeleteDir(entry.d_name, path);
296 } else if (S_ISREG(entry_info.st_mode) || S_ISLNK(entry_info.st_mode)) { 289 } else if (S_ISREG(entry_info.st_mode) || S_ISLNK(entry_info.st_mode)) {
297 // Treat links as files. This will delete the link which is 290 // Treat links as files. This will delete the link which is
298 // what we want no matter if the link target is a file or a 291 // what we want no matter if the link target is a file or a
299 // directory. 292 // directory.
300 success = success && DeleteFile(entry.d_name, path); 293 ok = DeleteFile(entry.d_name, path);
301 } 294 }
302 break; 295 break;
303 } 296 }
304 default: 297 default:
305 break; 298 break;
306 } 299 }
300 if (!ok) {
301 break;
302 }
307 path->Reset(path_length); 303 path->Reset(path_length);
308 } 304 }
309 305 // Only happens if an error.
310 if ((read != 0) || 306 ASSERT(errno != 0);
311 (NO_RETRY_EXPECTED(closedir(dir_pointer)) == -1) || 307 int err = errno;
312 (NO_RETRY_EXPECTED(remove(path->AsString())) == -1)) { 308 VOID_NO_RETRY_EXPECTED(closedir(dir_pointer));
313 return false; 309 errno = err;
314 } 310 return false;
315 return success;
316 } 311 }
317 312
318 313
319 Directory::ExistsResult Directory::Exists(const char* dir_name) { 314 Directory::ExistsResult Directory::Exists(const char* dir_name) {
320 struct stat64 entry_info; 315 struct stat64 entry_info;
321 int success = NO_RETRY_EXPECTED(stat64(dir_name, &entry_info)); 316 int success = NO_RETRY_EXPECTED(stat64(dir_name, &entry_info));
322 if (success == 0) { 317 if (success == 0) {
323 if (S_ISDIR(entry_info.st_mode)) { 318 if (S_ISDIR(entry_info.st_mode)) {
324 return EXISTS; 319 return EXISTS;
325 } else { 320 } else {
(...skipping 112 matching lines...) Expand 10 before | Expand all | Expand 10 after
438 bool Directory::Rename(const char* path, const char* new_path) { 433 bool Directory::Rename(const char* path, const char* new_path) {
439 ExistsResult exists = Exists(path); 434 ExistsResult exists = Exists(path);
440 if (exists != EXISTS) return false; 435 if (exists != EXISTS) return false;
441 return NO_RETRY_EXPECTED(rename(path, new_path)) == 0; 436 return NO_RETRY_EXPECTED(rename(path, new_path)) == 0;
442 } 437 }
443 438
444 } // namespace bin 439 } // namespace bin
445 } // namespace dart 440 } // namespace dart
446 441
447 #endif // defined(TARGET_OS_LINUX) 442 #endif // defined(TARGET_OS_LINUX)
OLDNEW
« no previous file with comments | « runtime/bin/directory_android.cc ('k') | runtime/bin/directory_macos.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698