OLD | NEW |
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(HOST_OS_LINUX) | 6 #if defined(HOST_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 |
11 #include <errno.h> // NOLINT | 11 #include <errno.h> // NOLINT |
12 #include <stdlib.h> // NOLINT | 12 #include <stdlib.h> // NOLINT |
13 #include <string.h> // NOLINT | 13 #include <string.h> // NOLINT |
14 #include <sys/param.h> // NOLINT | 14 #include <sys/param.h> // NOLINT |
15 #include <sys/stat.h> // NOLINT | 15 #include <sys/stat.h> // NOLINT |
16 #include <unistd.h> // NOLINT | 16 #include <unistd.h> // NOLINT |
17 | 17 |
18 #include "bin/dartutils.h" | 18 #include "bin/dartutils.h" |
19 #include "bin/file.h" | 19 #include "bin/file.h" |
20 #include "bin/platform.h" | 20 #include "bin/platform.h" |
21 #include "platform/signal_blocker.h" | 21 #include "platform/signal_blocker.h" |
22 | 22 |
23 namespace dart { | 23 namespace dart { |
24 namespace bin { | 24 namespace bin { |
25 | 25 |
26 PathBuffer::PathBuffer() : length_(0) { | 26 PathBuffer::PathBuffer() : length_(0) { |
27 data_ = calloc(PATH_MAX + 1, sizeof(char)); // NOLINT | 27 data_ = calloc(PATH_MAX + 1, sizeof(char)); // NOLINT |
28 } | 28 } |
29 | 29 |
30 | |
31 PathBuffer::~PathBuffer() { | 30 PathBuffer::~PathBuffer() { |
32 free(data_); | 31 free(data_); |
33 } | 32 } |
34 | 33 |
35 | |
36 bool PathBuffer::AddW(const wchar_t* name) { | 34 bool PathBuffer::AddW(const wchar_t* name) { |
37 UNREACHABLE(); | 35 UNREACHABLE(); |
38 return false; | 36 return false; |
39 } | 37 } |
40 | 38 |
41 | |
42 char* PathBuffer::AsString() const { | 39 char* PathBuffer::AsString() const { |
43 return reinterpret_cast<char*>(data_); | 40 return reinterpret_cast<char*>(data_); |
44 } | 41 } |
45 | 42 |
46 | |
47 wchar_t* PathBuffer::AsStringW() const { | 43 wchar_t* PathBuffer::AsStringW() const { |
48 UNREACHABLE(); | 44 UNREACHABLE(); |
49 return NULL; | 45 return NULL; |
50 } | 46 } |
51 | 47 |
52 | |
53 const char* PathBuffer::AsScopedString() const { | 48 const char* PathBuffer::AsScopedString() const { |
54 return DartUtils::ScopedCopyCString(AsString()); | 49 return DartUtils::ScopedCopyCString(AsString()); |
55 } | 50 } |
56 | 51 |
57 | |
58 bool PathBuffer::Add(const char* name) { | 52 bool PathBuffer::Add(const char* name) { |
59 char* data = AsString(); | 53 char* data = AsString(); |
60 int written = snprintf(data + length_, PATH_MAX - length_, "%s", name); | 54 int written = snprintf(data + length_, PATH_MAX - length_, "%s", name); |
61 data[PATH_MAX] = '\0'; | 55 data[PATH_MAX] = '\0'; |
62 if ((written <= PATH_MAX - length_) && (written >= 0) && | 56 if ((written <= PATH_MAX - length_) && (written >= 0) && |
63 (static_cast<size_t>(written) == strnlen(name, PATH_MAX + 1))) { | 57 (static_cast<size_t>(written) == strnlen(name, PATH_MAX + 1))) { |
64 length_ += written; | 58 length_ += written; |
65 return true; | 59 return true; |
66 } else { | 60 } else { |
67 errno = ENAMETOOLONG; | 61 errno = ENAMETOOLONG; |
68 return false; | 62 return false; |
69 } | 63 } |
70 } | 64 } |
71 | 65 |
72 | |
73 void PathBuffer::Reset(intptr_t new_length) { | 66 void PathBuffer::Reset(intptr_t new_length) { |
74 length_ = new_length; | 67 length_ = new_length; |
75 AsString()[length_] = '\0'; | 68 AsString()[length_] = '\0'; |
76 } | 69 } |
77 | 70 |
78 | |
79 // A linked list of symbolic links, with their unique file system identifiers. | 71 // A linked list of symbolic links, with their unique file system identifiers. |
80 // These are scanned to detect loops while doing a recursive directory listing. | 72 // These are scanned to detect loops while doing a recursive directory listing. |
81 struct LinkList { | 73 struct LinkList { |
82 dev_t dev; | 74 dev_t dev; |
83 ino64_t ino; | 75 ino64_t ino; |
84 LinkList* next; | 76 LinkList* next; |
85 }; | 77 }; |
86 | 78 |
87 | |
88 ListType DirectoryListingEntry::Next(DirectoryListing* listing) { | 79 ListType DirectoryListingEntry::Next(DirectoryListing* listing) { |
89 if (done_) { | 80 if (done_) { |
90 return kListDone; | 81 return kListDone; |
91 } | 82 } |
92 | 83 |
93 if (lister_ == 0) { | 84 if (lister_ == 0) { |
94 do { | 85 do { |
95 lister_ = reinterpret_cast<intptr_t>( | 86 lister_ = reinterpret_cast<intptr_t>( |
96 opendir(listing->path_buffer().AsString())); | 87 opendir(listing->path_buffer().AsString())); |
97 } while ((lister_ == 0) && (errno == EINTR)); | 88 } while ((lister_ == 0) && (errno == EINTR)); |
(...skipping 109 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
207 } | 198 } |
208 done_ = true; | 199 done_ = true; |
209 | 200 |
210 if (errno != 0) { | 201 if (errno != 0) { |
211 return kListError; | 202 return kListError; |
212 } | 203 } |
213 | 204 |
214 return kListDone; | 205 return kListDone; |
215 } | 206 } |
216 | 207 |
217 | |
218 DirectoryListingEntry::~DirectoryListingEntry() { | 208 DirectoryListingEntry::~DirectoryListingEntry() { |
219 ResetLink(); | 209 ResetLink(); |
220 if (lister_ != 0) { | 210 if (lister_ != 0) { |
221 VOID_NO_RETRY_EXPECTED(closedir(reinterpret_cast<DIR*>(lister_))); | 211 VOID_NO_RETRY_EXPECTED(closedir(reinterpret_cast<DIR*>(lister_))); |
222 } | 212 } |
223 } | 213 } |
224 | 214 |
225 | |
226 void DirectoryListingEntry::ResetLink() { | 215 void DirectoryListingEntry::ResetLink() { |
227 if ((link_ != NULL) && ((parent_ == NULL) || (parent_->link_ != link_))) { | 216 if ((link_ != NULL) && ((parent_ == NULL) || (parent_->link_ != link_))) { |
228 delete link_; | 217 delete link_; |
229 link_ = NULL; | 218 link_ = NULL; |
230 } | 219 } |
231 if (parent_ != NULL) { | 220 if (parent_ != NULL) { |
232 link_ = parent_->link_; | 221 link_ = parent_->link_; |
233 } | 222 } |
234 } | 223 } |
235 | 224 |
236 | |
237 static bool DeleteRecursively(PathBuffer* path); | 225 static bool DeleteRecursively(PathBuffer* path); |
238 | 226 |
239 | |
240 static bool DeleteFile(char* file_name, PathBuffer* path) { | 227 static bool DeleteFile(char* file_name, PathBuffer* path) { |
241 return path->Add(file_name) && | 228 return path->Add(file_name) && |
242 (NO_RETRY_EXPECTED(unlink(path->AsString())) == 0); | 229 (NO_RETRY_EXPECTED(unlink(path->AsString())) == 0); |
243 } | 230 } |
244 | 231 |
245 | |
246 static bool DeleteDir(char* dir_name, PathBuffer* path) { | 232 static bool DeleteDir(char* dir_name, PathBuffer* path) { |
247 if ((strcmp(dir_name, ".") == 0) || (strcmp(dir_name, "..") == 0)) { | 233 if ((strcmp(dir_name, ".") == 0) || (strcmp(dir_name, "..") == 0)) { |
248 return true; | 234 return true; |
249 } | 235 } |
250 return path->Add(dir_name) && DeleteRecursively(path); | 236 return path->Add(dir_name) && DeleteRecursively(path); |
251 } | 237 } |
252 | 238 |
253 | |
254 static bool DeleteRecursively(PathBuffer* path) { | 239 static bool DeleteRecursively(PathBuffer* path) { |
255 // Do not recurse into links for deletion. Instead delete the link. | 240 // Do not recurse into links for deletion. Instead delete the link. |
256 // If it's a file, delete it. | 241 // If it's a file, delete it. |
257 struct stat64 st; | 242 struct stat64 st; |
258 if (TEMP_FAILURE_RETRY(lstat64(path->AsString(), &st)) == -1) { | 243 if (TEMP_FAILURE_RETRY(lstat64(path->AsString(), &st)) == -1) { |
259 return false; | 244 return false; |
260 } else if (!S_ISDIR(st.st_mode)) { | 245 } else if (!S_ISDIR(st.st_mode)) { |
261 return (NO_RETRY_EXPECTED(unlink(path->AsString())) == 0); | 246 return (NO_RETRY_EXPECTED(unlink(path->AsString())) == 0); |
262 } | 247 } |
263 | 248 |
(...skipping 81 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
345 path->Reset(path_length); | 330 path->Reset(path_length); |
346 } | 331 } |
347 // Only happens if an error. | 332 // Only happens if an error. |
348 ASSERT(errno != 0); | 333 ASSERT(errno != 0); |
349 int err = errno; | 334 int err = errno; |
350 VOID_NO_RETRY_EXPECTED(closedir(dir_pointer)); | 335 VOID_NO_RETRY_EXPECTED(closedir(dir_pointer)); |
351 errno = err; | 336 errno = err; |
352 return false; | 337 return false; |
353 } | 338 } |
354 | 339 |
355 | |
356 Directory::ExistsResult Directory::Exists(const char* dir_name) { | 340 Directory::ExistsResult Directory::Exists(const char* dir_name) { |
357 struct stat64 entry_info; | 341 struct stat64 entry_info; |
358 int success = TEMP_FAILURE_RETRY(stat64(dir_name, &entry_info)); | 342 int success = TEMP_FAILURE_RETRY(stat64(dir_name, &entry_info)); |
359 if (success == 0) { | 343 if (success == 0) { |
360 if (S_ISDIR(entry_info.st_mode)) { | 344 if (S_ISDIR(entry_info.st_mode)) { |
361 return EXISTS; | 345 return EXISTS; |
362 } else { | 346 } else { |
363 // An OSError may be constructed based on the return value of this | 347 // An OSError may be constructed based on the return value of this |
364 // function, so set errno to something that makes sense. | 348 // function, so set errno to something that makes sense. |
365 errno = ENOTDIR; | 349 errno = ENOTDIR; |
366 return DOES_NOT_EXIST; | 350 return DOES_NOT_EXIST; |
367 } | 351 } |
368 } else { | 352 } else { |
369 if ((errno == EACCES) || (errno == EBADF) || (errno == EFAULT) || | 353 if ((errno == EACCES) || (errno == EBADF) || (errno == EFAULT) || |
370 (errno == ENOMEM) || (errno == EOVERFLOW)) { | 354 (errno == ENOMEM) || (errno == EOVERFLOW)) { |
371 // Search permissions denied for one of the directories in the | 355 // Search permissions denied for one of the directories in the |
372 // path or a low level error occured. We do not know if the | 356 // path or a low level error occured. We do not know if the |
373 // directory exists. | 357 // directory exists. |
374 return UNKNOWN; | 358 return UNKNOWN; |
375 } | 359 } |
376 ASSERT((errno == ELOOP) || (errno == ENAMETOOLONG) || (errno == ENOENT) || | 360 ASSERT((errno == ELOOP) || (errno == ENAMETOOLONG) || (errno == ENOENT) || |
377 (errno == ENOTDIR)); | 361 (errno == ENOTDIR)); |
378 return DOES_NOT_EXIST; | 362 return DOES_NOT_EXIST; |
379 } | 363 } |
380 } | 364 } |
381 | 365 |
382 | |
383 char* Directory::CurrentNoScope() { | 366 char* Directory::CurrentNoScope() { |
384 return getcwd(NULL, 0); | 367 return getcwd(NULL, 0); |
385 } | 368 } |
386 | 369 |
387 | |
388 const char* Directory::Current() { | 370 const char* Directory::Current() { |
389 char buffer[PATH_MAX]; | 371 char buffer[PATH_MAX]; |
390 if (getcwd(buffer, PATH_MAX) == NULL) { | 372 if (getcwd(buffer, PATH_MAX) == NULL) { |
391 return NULL; | 373 return NULL; |
392 } | 374 } |
393 return DartUtils::ScopedCopyCString(buffer); | 375 return DartUtils::ScopedCopyCString(buffer); |
394 } | 376 } |
395 | 377 |
396 | |
397 bool Directory::SetCurrent(const char* path) { | 378 bool Directory::SetCurrent(const char* path) { |
398 return (NO_RETRY_EXPECTED(chdir(path)) == 0); | 379 return (NO_RETRY_EXPECTED(chdir(path)) == 0); |
399 } | 380 } |
400 | 381 |
401 | |
402 bool Directory::Create(const char* dir_name) { | 382 bool Directory::Create(const char* dir_name) { |
403 // Create the directory with the permissions specified by the | 383 // Create the directory with the permissions specified by the |
404 // process umask. | 384 // process umask. |
405 int result = NO_RETRY_EXPECTED(mkdir(dir_name, 0777)); | 385 int result = NO_RETRY_EXPECTED(mkdir(dir_name, 0777)); |
406 // If the directory already exists, treat it as a success. | 386 // If the directory already exists, treat it as a success. |
407 if ((result == -1) && (errno == EEXIST)) { | 387 if ((result == -1) && (errno == EEXIST)) { |
408 return (Exists(dir_name) == EXISTS); | 388 return (Exists(dir_name) == EXISTS); |
409 } | 389 } |
410 return (result == 0); | 390 return (result == 0); |
411 } | 391 } |
412 | 392 |
413 | |
414 const char* Directory::SystemTemp() { | 393 const char* Directory::SystemTemp() { |
415 PathBuffer path; | 394 PathBuffer path; |
416 const char* temp_dir = getenv("TMPDIR"); | 395 const char* temp_dir = getenv("TMPDIR"); |
417 if (temp_dir == NULL) { | 396 if (temp_dir == NULL) { |
418 temp_dir = getenv("TMP"); | 397 temp_dir = getenv("TMP"); |
419 } | 398 } |
420 if (temp_dir == NULL) { | 399 if (temp_dir == NULL) { |
421 temp_dir = "/tmp"; | 400 temp_dir = "/tmp"; |
422 } | 401 } |
423 if (!path.Add(temp_dir)) { | 402 if (!path.Add(temp_dir)) { |
424 return NULL; | 403 return NULL; |
425 } | 404 } |
426 | 405 |
427 // Remove any trailing slash. | 406 // Remove any trailing slash. |
428 char* result = path.AsString(); | 407 char* result = path.AsString(); |
429 int length = strlen(result); | 408 int length = strlen(result); |
430 if ((length > 1) && (result[length - 1] == '/')) { | 409 if ((length > 1) && (result[length - 1] == '/')) { |
431 result[length - 1] = '\0'; | 410 result[length - 1] = '\0'; |
432 } | 411 } |
433 return path.AsScopedString(); | 412 return path.AsScopedString(); |
434 } | 413 } |
435 | 414 |
436 | |
437 const char* Directory::CreateTemp(const char* prefix) { | 415 const char* Directory::CreateTemp(const char* prefix) { |
438 // Returns a new, unused directory name, adding characters to the end | 416 // Returns a new, unused directory name, adding characters to the end |
439 // of prefix. Creates the directory with the permissions specified | 417 // of prefix. Creates the directory with the permissions specified |
440 // by the process umask. | 418 // by the process umask. |
441 // The return value is Dart_ScopeAllocated. | 419 // The return value is Dart_ScopeAllocated. |
442 PathBuffer path; | 420 PathBuffer path; |
443 if (!path.Add(prefix)) { | 421 if (!path.Add(prefix)) { |
444 return NULL; | 422 return NULL; |
445 } | 423 } |
446 if (!path.Add("XXXXXX")) { | 424 if (!path.Add("XXXXXX")) { |
447 // Pattern has overflowed. | 425 // Pattern has overflowed. |
448 return NULL; | 426 return NULL; |
449 } | 427 } |
450 char* result; | 428 char* result; |
451 do { | 429 do { |
452 result = mkdtemp(path.AsString()); | 430 result = mkdtemp(path.AsString()); |
453 } while ((result == NULL) && (errno == EINTR)); | 431 } while ((result == NULL) && (errno == EINTR)); |
454 if (result == NULL) { | 432 if (result == NULL) { |
455 return NULL; | 433 return NULL; |
456 } | 434 } |
457 return path.AsScopedString(); | 435 return path.AsScopedString(); |
458 } | 436 } |
459 | 437 |
460 | |
461 bool Directory::Delete(const char* dir_name, bool recursive) { | 438 bool Directory::Delete(const char* dir_name, bool recursive) { |
462 if (!recursive) { | 439 if (!recursive) { |
463 if ((File::GetType(dir_name, false) == File::kIsLink) && | 440 if ((File::GetType(dir_name, false) == File::kIsLink) && |
464 (File::GetType(dir_name, true) == File::kIsDirectory)) { | 441 (File::GetType(dir_name, true) == File::kIsDirectory)) { |
465 return NO_RETRY_EXPECTED(unlink(dir_name)) == 0; | 442 return NO_RETRY_EXPECTED(unlink(dir_name)) == 0; |
466 } | 443 } |
467 return NO_RETRY_EXPECTED(rmdir(dir_name)) == 0; | 444 return NO_RETRY_EXPECTED(rmdir(dir_name)) == 0; |
468 } else { | 445 } else { |
469 PathBuffer path; | 446 PathBuffer path; |
470 if (!path.Add(dir_name)) { | 447 if (!path.Add(dir_name)) { |
471 return false; | 448 return false; |
472 } | 449 } |
473 return DeleteRecursively(&path); | 450 return DeleteRecursively(&path); |
474 } | 451 } |
475 } | 452 } |
476 | 453 |
477 | |
478 bool Directory::Rename(const char* path, const char* new_path) { | 454 bool Directory::Rename(const char* path, const char* new_path) { |
479 ExistsResult exists = Exists(path); | 455 ExistsResult exists = Exists(path); |
480 if (exists != EXISTS) { | 456 if (exists != EXISTS) { |
481 return false; | 457 return false; |
482 } | 458 } |
483 return (NO_RETRY_EXPECTED(rename(path, new_path)) == 0); | 459 return (NO_RETRY_EXPECTED(rename(path, new_path)) == 0); |
484 } | 460 } |
485 | 461 |
486 } // namespace bin | 462 } // namespace bin |
487 } // namespace dart | 463 } // namespace dart |
488 | 464 |
489 #endif // defined(HOST_OS_LINUX) | 465 #endif // defined(HOST_OS_LINUX) |
OLD | NEW |