| 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(TARGET_OS_LINUX) | 6 #if defined(TARGET_OS_LINUX) |
| 7 | 7 |
| 8 #include "bin/file.h" | 8 #include "bin/file.h" |
| 9 | 9 |
| 10 #include <errno.h> // NOLINT | 10 #include <errno.h> // NOLINT |
| 11 #include <fcntl.h> // NOLINT | 11 #include <fcntl.h> // NOLINT |
| 12 #include <libgen.h> // NOLINT | 12 #include <libgen.h> // NOLINT |
| 13 #include <sys/mman.h> // NOLINT | 13 #include <sys/mman.h> // NOLINT |
| 14 #include <sys/sendfile.h> // NOLINT | 14 #include <sys/sendfile.h> // NOLINT |
| 15 #include <sys/stat.h> // NOLINT | 15 #include <sys/stat.h> // NOLINT |
| 16 #include <sys/types.h> // NOLINT | 16 #include <sys/types.h> // NOLINT |
| 17 #include <unistd.h> // NOLINT | 17 #include <unistd.h> // NOLINT |
| 18 | 18 |
| 19 #include "bin/builtin.h" | 19 #include "bin/builtin.h" |
| 20 #include "bin/log.h" | 20 #include "bin/log.h" |
| 21 #include "platform/signal_blocker.h" | 21 #include "platform/signal_blocker.h" |
| 22 #include "platform/utils.h" | 22 #include "platform/utils.h" |
| 23 | 23 |
| 24 namespace dart { | 24 namespace dart { |
| 25 namespace bin { | 25 namespace bin { |
| 26 | 26 |
| 27 class FileHandle { | 27 class FileHandle { |
| 28 public: | 28 public: |
| 29 explicit FileHandle(int fd) : fd_(fd) { } | 29 explicit FileHandle(int fd) : fd_(fd) {} |
| 30 ~FileHandle() { } | 30 ~FileHandle() {} |
| 31 int fd() const { return fd_; } | 31 int fd() const { return fd_; } |
| 32 void set_fd(int fd) { fd_ = fd; } | 32 void set_fd(int fd) { fd_ = fd; } |
| 33 | 33 |
| 34 private: | 34 private: |
| 35 int fd_; | 35 int fd_; |
| 36 | 36 |
| 37 DISALLOW_COPY_AND_ASSIGN(FileHandle); | 37 DISALLOW_COPY_AND_ASSIGN(FileHandle); |
| 38 }; | 38 }; |
| 39 | 39 |
| 40 | 40 |
| 41 File::~File() { | 41 File::~File() { |
| 42 if (!IsClosed() && | 42 if (!IsClosed() && handle_->fd() != STDOUT_FILENO && |
| 43 handle_->fd() != STDOUT_FILENO && handle_->fd() != STDERR_FILENO) { | 43 handle_->fd() != STDERR_FILENO) { |
| 44 Close(); | 44 Close(); |
| 45 } | 45 } |
| 46 delete handle_; | 46 delete handle_; |
| 47 } | 47 } |
| 48 | 48 |
| 49 | 49 |
| 50 void File::Close() { | 50 void File::Close() { |
| 51 ASSERT(handle_->fd() >= 0); | 51 ASSERT(handle_->fd() >= 0); |
| 52 if (handle_->fd() == STDOUT_FILENO) { | 52 if (handle_->fd() == STDOUT_FILENO) { |
| 53 // If stdout, redirect fd to /dev/null. | 53 // If stdout, redirect fd to /dev/null. |
| (...skipping 29 matching lines...) Expand all Loading... |
| 83 switch (type) { | 83 switch (type) { |
| 84 case kReadOnly: | 84 case kReadOnly: |
| 85 prot = PROT_READ; | 85 prot = PROT_READ; |
| 86 break; | 86 break; |
| 87 case kReadExecute: | 87 case kReadExecute: |
| 88 prot = PROT_READ | PROT_EXEC; | 88 prot = PROT_READ | PROT_EXEC; |
| 89 break; | 89 break; |
| 90 default: | 90 default: |
| 91 return NULL; | 91 return NULL; |
| 92 } | 92 } |
| 93 void* addr = mmap(NULL, length, prot, MAP_PRIVATE, | 93 void* addr = mmap(NULL, length, prot, MAP_PRIVATE, handle_->fd(), position); |
| 94 handle_->fd(), position); | |
| 95 if (addr == MAP_FAILED) { | 94 if (addr == MAP_FAILED) { |
| 96 return NULL; | 95 return NULL; |
| 97 } | 96 } |
| 98 return addr; | 97 return addr; |
| 99 } | 98 } |
| 100 | 99 |
| 101 | 100 |
| 102 int64_t File::Read(void* buffer, int64_t num_bytes) { | 101 int64_t File::Read(void* buffer, int64_t num_bytes) { |
| 103 ASSERT(handle_->fd() >= 0); | 102 ASSERT(handle_->fd() >= 0); |
| 104 return TEMP_FAILURE_RETRY(read(handle_->fd(), buffer, num_bytes)); | 103 return TEMP_FAILURE_RETRY(read(handle_->fd(), buffer, num_bytes)); |
| (...skipping 124 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 229 struct stat64 st; | 228 struct stat64 st; |
| 230 if (TEMP_FAILURE_RETRY(stat64(name, &st)) == 0) { | 229 if (TEMP_FAILURE_RETRY(stat64(name, &st)) == 0) { |
| 231 return S_ISREG(st.st_mode); | 230 return S_ISREG(st.st_mode); |
| 232 } else { | 231 } else { |
| 233 return false; | 232 return false; |
| 234 } | 233 } |
| 235 } | 234 } |
| 236 | 235 |
| 237 | 236 |
| 238 bool File::Create(const char* name) { | 237 bool File::Create(const char* name) { |
| 239 int fd = TEMP_FAILURE_RETRY( | 238 int fd = |
| 240 open64(name, O_RDONLY | O_CREAT | O_CLOEXEC, 0666)); | 239 TEMP_FAILURE_RETRY(open64(name, O_RDONLY | O_CREAT | O_CLOEXEC, 0666)); |
| 241 if (fd < 0) { | 240 if (fd < 0) { |
| 242 return false; | 241 return false; |
| 243 } | 242 } |
| 244 return (TEMP_FAILURE_RETRY(close(fd)) == 0); | 243 return (TEMP_FAILURE_RETRY(close(fd)) == 0); |
| 245 } | 244 } |
| 246 | 245 |
| 247 | 246 |
| 248 bool File::CreateLink(const char* name, const char* target) { | 247 bool File::CreateLink(const char* name, const char* target) { |
| 249 return NO_RETRY_EXPECTED(symlink(target, name)) == 0; | 248 return NO_RETRY_EXPECTED(symlink(target, name)) == 0; |
| 250 } | 249 } |
| (...skipping 62 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 313 int new_fd = TEMP_FAILURE_RETRY( | 312 int new_fd = TEMP_FAILURE_RETRY( |
| 314 open64(new_path, O_WRONLY | O_TRUNC | O_CREAT | O_CLOEXEC, st.st_mode)); | 313 open64(new_path, O_WRONLY | O_TRUNC | O_CREAT | O_CLOEXEC, st.st_mode)); |
| 315 if (new_fd < 0) { | 314 if (new_fd < 0) { |
| 316 VOID_TEMP_FAILURE_RETRY(close(old_fd)); | 315 VOID_TEMP_FAILURE_RETRY(close(old_fd)); |
| 317 return false; | 316 return false; |
| 318 } | 317 } |
| 319 int64_t offset = 0; | 318 int64_t offset = 0; |
| 320 intptr_t result = 1; | 319 intptr_t result = 1; |
| 321 while (result > 0) { | 320 while (result > 0) { |
| 322 // Loop to ensure we copy everything, and not only up to 2GB. | 321 // Loop to ensure we copy everything, and not only up to 2GB. |
| 323 result = NO_RETRY_EXPECTED( | 322 result = |
| 324 sendfile64(new_fd, old_fd, &offset, kMaxUint32)); | 323 NO_RETRY_EXPECTED(sendfile64(new_fd, old_fd, &offset, kMaxUint32)); |
| 325 } | 324 } |
| 326 // From sendfile man pages: | 325 // From sendfile man pages: |
| 327 // Applications may wish to fall back to read(2)/write(2) in the case | 326 // Applications may wish to fall back to read(2)/write(2) in the case |
| 328 // where sendfile() fails with EINVAL or ENOSYS. | 327 // where sendfile() fails with EINVAL or ENOSYS. |
| 329 if ((result < 0) && ((errno == EINVAL) || (errno == ENOSYS))) { | 328 if ((result < 0) && ((errno == EINVAL) || (errno == ENOSYS))) { |
| 330 const intptr_t kBufferSize = 8 * KB; | 329 const intptr_t kBufferSize = 8 * KB; |
| 331 uint8_t buffer[kBufferSize]; | 330 uint8_t buffer[kBufferSize]; |
| 332 while ((result = TEMP_FAILURE_RETRY( | 331 while ((result = TEMP_FAILURE_RETRY(read(old_fd, buffer, kBufferSize))) > |
| 333 read(old_fd, buffer, kBufferSize))) > 0) { | 332 0) { |
| 334 int wrote = TEMP_FAILURE_RETRY(write(new_fd, buffer, result)); | 333 int wrote = TEMP_FAILURE_RETRY(write(new_fd, buffer, result)); |
| 335 if (wrote != result) { | 334 if (wrote != result) { |
| 336 result = -1; | 335 result = -1; |
| 337 break; | 336 break; |
| 338 } | 337 } |
| 339 } | 338 } |
| 340 } | 339 } |
| 341 int e = errno; | 340 int e = errno; |
| 342 VOID_TEMP_FAILURE_RETRY(close(old_fd)); | 341 VOID_TEMP_FAILURE_RETRY(close(old_fd)); |
| 343 VOID_TEMP_FAILURE_RETRY(close(new_fd)); | 342 VOID_TEMP_FAILURE_RETRY(close(new_fd)); |
| (...skipping 16 matching lines...) Expand all Loading... |
| 360 struct stat64 st; | 359 struct stat64 st; |
| 361 if (TEMP_FAILURE_RETRY(stat64(name, &st)) == 0) { | 360 if (TEMP_FAILURE_RETRY(stat64(name, &st)) == 0) { |
| 362 return st.st_size; | 361 return st.st_size; |
| 363 } | 362 } |
| 364 return -1; | 363 return -1; |
| 365 } | 364 } |
| 366 | 365 |
| 367 | 366 |
| 368 static int64_t TimespecToMilliseconds(const struct timespec& t) { | 367 static int64_t TimespecToMilliseconds(const struct timespec& t) { |
| 369 return static_cast<int64_t>(t.tv_sec) * 1000L + | 368 return static_cast<int64_t>(t.tv_sec) * 1000L + |
| 370 static_cast<int64_t>(t.tv_nsec) / 1000000L; | 369 static_cast<int64_t>(t.tv_nsec) / 1000000L; |
| 371 } | 370 } |
| 372 | 371 |
| 373 | 372 |
| 374 void File::Stat(const char* name, int64_t* data) { | 373 void File::Stat(const char* name, int64_t* data) { |
| 375 struct stat64 st; | 374 struct stat64 st; |
| 376 if (TEMP_FAILURE_RETRY(stat64(name, &st)) == 0) { | 375 if (TEMP_FAILURE_RETRY(stat64(name, &st)) == 0) { |
| 377 if (S_ISREG(st.st_mode)) { | 376 if (S_ISREG(st.st_mode)) { |
| 378 data[kType] = kIsFile; | 377 data[kType] = kIsFile; |
| 379 } else if (S_ISDIR(st.st_mode)) { | 378 } else if (S_ISDIR(st.st_mode)) { |
| 380 data[kType] = kIsDirectory; | 379 data[kType] = kIsDirectory; |
| (...skipping 29 matching lines...) Expand all Loading... |
| 410 } | 409 } |
| 411 if (!S_ISLNK(link_stats.st_mode)) { | 410 if (!S_ISLNK(link_stats.st_mode)) { |
| 412 errno = ENOENT; | 411 errno = ENOENT; |
| 413 return NULL; | 412 return NULL; |
| 414 } | 413 } |
| 415 // Don't rely on the link_stats.st_size for the size of the link | 414 // Don't rely on the link_stats.st_size for the size of the link |
| 416 // target. For some filesystems, e.g. procfs, this value is always | 415 // target. For some filesystems, e.g. procfs, this value is always |
| 417 // 0. Also the link might have changed before the readlink call. | 416 // 0. Also the link might have changed before the readlink call. |
| 418 const int kBufferSize = PATH_MAX + 1; | 417 const int kBufferSize = PATH_MAX + 1; |
| 419 char target[kBufferSize]; | 418 char target[kBufferSize]; |
| 420 size_t target_size = TEMP_FAILURE_RETRY( | 419 size_t target_size = |
| 421 readlink(pathname, target, kBufferSize)); | 420 TEMP_FAILURE_RETRY(readlink(pathname, target, kBufferSize)); |
| 422 if (target_size <= 0) { | 421 if (target_size <= 0) { |
| 423 return NULL; | 422 return NULL; |
| 424 } | 423 } |
| 425 char* target_name = DartUtils::ScopedCString(target_size + 1); | 424 char* target_name = DartUtils::ScopedCString(target_size + 1); |
| 426 ASSERT(target_name != NULL); | 425 ASSERT(target_name != NULL); |
| 427 memmove(target_name, target, target_size); | 426 memmove(target_name, target, target_size); |
| 428 target_name[target_size] = '\0'; | 427 target_name[target_size] = '\0'; |
| 429 return target_name; | 428 return target_name; |
| 430 } | 429 } |
| 431 | 430 |
| (...skipping 79 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 511 | 510 |
| 512 | 511 |
| 513 File::Identical File::AreIdentical(const char* file_1, const char* file_2) { | 512 File::Identical File::AreIdentical(const char* file_1, const char* file_2) { |
| 514 struct stat64 file_1_info; | 513 struct stat64 file_1_info; |
| 515 struct stat64 file_2_info; | 514 struct stat64 file_2_info; |
| 516 if ((TEMP_FAILURE_RETRY(lstat64(file_1, &file_1_info)) == -1) || | 515 if ((TEMP_FAILURE_RETRY(lstat64(file_1, &file_1_info)) == -1) || |
| 517 (TEMP_FAILURE_RETRY(lstat64(file_2, &file_2_info)) == -1)) { | 516 (TEMP_FAILURE_RETRY(lstat64(file_2, &file_2_info)) == -1)) { |
| 518 return File::kError; | 517 return File::kError; |
| 519 } | 518 } |
| 520 return ((file_1_info.st_ino == file_2_info.st_ino) && | 519 return ((file_1_info.st_ino == file_2_info.st_ino) && |
| 521 (file_1_info.st_dev == file_2_info.st_dev)) ? | 520 (file_1_info.st_dev == file_2_info.st_dev)) |
| 522 File::kIdentical : | 521 ? File::kIdentical |
| 523 File::kDifferent; | 522 : File::kDifferent; |
| 524 } | 523 } |
| 525 | 524 |
| 526 } // namespace bin | 525 } // namespace bin |
| 527 } // namespace dart | 526 } // namespace dart |
| 528 | 527 |
| 529 #endif // defined(TARGET_OS_LINUX) | 528 #endif // defined(TARGET_OS_LINUX) |
| OLD | NEW |