| 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 <sys/stat.h> // NOLINT | 12 #include <sys/stat.h> // NOLINT |
| 13 #include <sys/types.h> // NOLINT | 13 #include <sys/types.h> // NOLINT |
| 14 #include <sys/sendfile.h> // NOLINT | 14 #include <sys/sendfile.h> // NOLINT |
| 15 #include <unistd.h> // NOLINT | 15 #include <unistd.h> // NOLINT |
| 16 #include <libgen.h> // NOLINT | 16 #include <libgen.h> // NOLINT |
| 17 | 17 |
| 18 #include "bin/builtin.h" | 18 #include "bin/builtin.h" |
| 19 #include "bin/log.h" | 19 #include "bin/log.h" |
| 20 #include "platform/signal_blocker.h" | 20 #include "platform/signal_blocker.h" |
| 21 #include "platform/utils.h" | 21 #include "platform/utils.h" |
| 22 | 22 |
| 23 | |
| 24 namespace dart { | 23 namespace dart { |
| 25 namespace bin { | 24 namespace bin { |
| 26 | 25 |
| 27 class FileHandle { | 26 class FileHandle { |
| 28 public: | 27 public: |
| 29 explicit FileHandle(int fd) : fd_(fd) { } | 28 explicit FileHandle(int fd) : fd_(fd) { } |
| 30 ~FileHandle() { } | 29 ~FileHandle() { } |
| 31 int fd() const { return fd_; } | 30 int fd() const { return fd_; } |
| 32 void set_fd(int fd) { fd_ = fd; } | 31 void set_fd(int fd) { fd_ = fd; } |
| 33 | 32 |
| (...skipping 71 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 105 | 104 |
| 106 | 105 |
| 107 bool File::Flush() { | 106 bool File::Flush() { |
| 108 ASSERT(handle_->fd() >= 0); | 107 ASSERT(handle_->fd() >= 0); |
| 109 return NO_RETRY_EXPECTED(fsync(handle_->fd())) != -1; | 108 return NO_RETRY_EXPECTED(fsync(handle_->fd())) != -1; |
| 110 } | 109 } |
| 111 | 110 |
| 112 | 111 |
| 113 bool File::Lock(File::LockType lock, int64_t start, int64_t end) { | 112 bool File::Lock(File::LockType lock, int64_t start, int64_t end) { |
| 114 ASSERT(handle_->fd() >= 0); | 113 ASSERT(handle_->fd() >= 0); |
| 115 ASSERT(end == -1 || end > start); | 114 ASSERT((end == -1) || (end > start)); |
| 116 struct flock fl; | 115 struct flock fl; |
| 117 switch (lock) { | 116 switch (lock) { |
| 118 case File::kLockUnlock: | 117 case File::kLockUnlock: |
| 119 fl.l_type = F_UNLCK; | 118 fl.l_type = F_UNLCK; |
| 120 break; | 119 break; |
| 121 case File::kLockShared: | 120 case File::kLockShared: |
| 122 fl.l_type = F_RDLCK; | 121 fl.l_type = F_RDLCK; |
| 123 break; | 122 break; |
| 124 case File::kLockExclusive: | 123 case File::kLockExclusive: |
| 125 fl.l_type = F_WRLCK; | 124 fl.l_type = F_WRLCK; |
| (...skipping 13 matching lines...) Expand all Loading... |
| 139 int64_t File::Length() { | 138 int64_t File::Length() { |
| 140 ASSERT(handle_->fd() >= 0); | 139 ASSERT(handle_->fd() >= 0); |
| 141 struct stat64 st; | 140 struct stat64 st; |
| 142 if (TEMP_FAILURE_RETRY(fstat64(handle_->fd(), &st)) == 0) { | 141 if (TEMP_FAILURE_RETRY(fstat64(handle_->fd(), &st)) == 0) { |
| 143 return st.st_size; | 142 return st.st_size; |
| 144 } | 143 } |
| 145 return -1; | 144 return -1; |
| 146 } | 145 } |
| 147 | 146 |
| 148 | 147 |
| 149 File* File::Open(const char* name, FileOpenMode mode) { | 148 File* File::FileOpenW(const wchar_t* system_name, FileOpenMode mode) { |
| 149 UNREACHABLE(); |
| 150 return NULL; |
| 151 } |
| 152 |
| 153 |
| 154 File* File::ScopedOpen(const char* name, FileOpenMode mode) { |
| 150 // Report errors for non-regular files. | 155 // Report errors for non-regular files. |
| 151 struct stat64 st; | 156 struct stat64 st; |
| 152 if (TEMP_FAILURE_RETRY(stat64(name, &st)) == 0) { | 157 if (TEMP_FAILURE_RETRY(stat64(name, &st)) == 0) { |
| 153 // Only accept regular files and character devices. | 158 // Only accept regular files and character devices. |
| 154 if (!S_ISREG(st.st_mode) && !S_ISCHR(st.st_mode)) { | 159 if (!S_ISREG(st.st_mode) && !S_ISCHR(st.st_mode)) { |
| 155 errno = (S_ISDIR(st.st_mode)) ? EISDIR : ENOENT; | 160 errno = (S_ISDIR(st.st_mode)) ? EISDIR : ENOENT; |
| 156 return NULL; | 161 return NULL; |
| 157 } | 162 } |
| 158 } | 163 } |
| 159 int flags = O_RDONLY; | 164 int flags = O_RDONLY; |
| (...skipping 17 matching lines...) Expand all Loading... |
| 177 (((mode & kWriteOnly) != 0) && ((mode & kTruncate) == 0))) { | 182 (((mode & kWriteOnly) != 0) && ((mode & kTruncate) == 0))) { |
| 178 int64_t position = NO_RETRY_EXPECTED(lseek64(fd, 0, SEEK_END)); | 183 int64_t position = NO_RETRY_EXPECTED(lseek64(fd, 0, SEEK_END)); |
| 179 if (position < 0) { | 184 if (position < 0) { |
| 180 return NULL; | 185 return NULL; |
| 181 } | 186 } |
| 182 } | 187 } |
| 183 return new File(new FileHandle(fd)); | 188 return new File(new FileHandle(fd)); |
| 184 } | 189 } |
| 185 | 190 |
| 186 | 191 |
| 192 File* File::Open(const char* path, FileOpenMode mode) { |
| 193 // ScopedOpen doesn't actually need a scope. |
| 194 return ScopedOpen(path, mode); |
| 195 } |
| 196 |
| 197 |
| 187 File* File::OpenStdio(int fd) { | 198 File* File::OpenStdio(int fd) { |
| 188 if (fd < 0 || 2 < fd) return NULL; | 199 if ((fd < 0) || (2 < fd)) { |
| 200 return NULL; |
| 201 } |
| 189 return new File(new FileHandle(fd)); | 202 return new File(new FileHandle(fd)); |
| 190 } | 203 } |
| 191 | 204 |
| 192 | 205 |
| 193 bool File::Exists(const char* name) { | 206 bool File::Exists(const char* name) { |
| 194 struct stat64 st; | 207 struct stat64 st; |
| 195 if (TEMP_FAILURE_RETRY(stat64(name, &st)) == 0) { | 208 if (TEMP_FAILURE_RETRY(stat64(name, &st)) == 0) { |
| 196 return S_ISREG(st.st_mode); | 209 return S_ISREG(st.st_mode); |
| 197 } else { | 210 } else { |
| 198 return false; | 211 return false; |
| (...skipping 85 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 284 int64_t offset = 0; | 297 int64_t offset = 0; |
| 285 intptr_t result = 1; | 298 intptr_t result = 1; |
| 286 while (result > 0) { | 299 while (result > 0) { |
| 287 // Loop to ensure we copy everything, and not only up to 2GB. | 300 // Loop to ensure we copy everything, and not only up to 2GB. |
| 288 result = NO_RETRY_EXPECTED( | 301 result = NO_RETRY_EXPECTED( |
| 289 sendfile64(new_fd, old_fd, &offset, kMaxUint32)); | 302 sendfile64(new_fd, old_fd, &offset, kMaxUint32)); |
| 290 } | 303 } |
| 291 // From sendfile man pages: | 304 // From sendfile man pages: |
| 292 // Applications may wish to fall back to read(2)/write(2) in the case | 305 // Applications may wish to fall back to read(2)/write(2) in the case |
| 293 // where sendfile() fails with EINVAL or ENOSYS. | 306 // where sendfile() fails with EINVAL or ENOSYS. |
| 294 if (result < 0 && (errno == EINVAL || errno == ENOSYS)) { | 307 if ((result < 0) && ((errno == EINVAL) || (errno == ENOSYS))) { |
| 295 const intptr_t kBufferSize = 8 * KB; | 308 const intptr_t kBufferSize = 8 * KB; |
| 296 uint8_t buffer[kBufferSize]; | 309 uint8_t buffer[kBufferSize]; |
| 297 while ((result = TEMP_FAILURE_RETRY( | 310 while ((result = TEMP_FAILURE_RETRY( |
| 298 read(old_fd, buffer, kBufferSize))) > 0) { | 311 read(old_fd, buffer, kBufferSize))) > 0) { |
| 299 int wrote = TEMP_FAILURE_RETRY(write(new_fd, buffer, result)); | 312 int wrote = TEMP_FAILURE_RETRY(write(new_fd, buffer, result)); |
| 300 if (wrote != result) { | 313 if (wrote != result) { |
| 301 result = -1; | 314 result = -1; |
| 302 break; | 315 break; |
| 303 } | 316 } |
| 304 } | 317 } |
| (...skipping 56 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 361 | 374 |
| 362 time_t File::LastModified(const char* name) { | 375 time_t File::LastModified(const char* name) { |
| 363 struct stat64 st; | 376 struct stat64 st; |
| 364 if (TEMP_FAILURE_RETRY(stat64(name, &st)) == 0) { | 377 if (TEMP_FAILURE_RETRY(stat64(name, &st)) == 0) { |
| 365 return st.st_mtime; | 378 return st.st_mtime; |
| 366 } | 379 } |
| 367 return -1; | 380 return -1; |
| 368 } | 381 } |
| 369 | 382 |
| 370 | 383 |
| 371 char* File::LinkTarget(const char* pathname) { | 384 const char* File::LinkTarget(const char* pathname) { |
| 372 struct stat64 link_stats; | 385 struct stat64 link_stats; |
| 373 if (TEMP_FAILURE_RETRY(lstat64(pathname, &link_stats)) != 0) return NULL; | 386 if (TEMP_FAILURE_RETRY(lstat64(pathname, &link_stats)) != 0) { |
| 387 return NULL; |
| 388 } |
| 374 if (!S_ISLNK(link_stats.st_mode)) { | 389 if (!S_ISLNK(link_stats.st_mode)) { |
| 375 errno = ENOENT; | 390 errno = ENOENT; |
| 376 return NULL; | 391 return NULL; |
| 377 } | 392 } |
| 378 // Don't rely on the link_stats.st_size for the size of the link | 393 // Don't rely on the link_stats.st_size for the size of the link |
| 379 // target. For some filesystems, e.g. procfs, this value is always | 394 // target. For some filesystems, e.g. procfs, this value is always |
| 380 // 0. Also the link might have changed before the readlink call. | 395 // 0. Also the link might have changed before the readlink call. |
| 381 const int kBufferSize = PATH_MAX + 1; | 396 const int kBufferSize = PATH_MAX + 1; |
| 382 char target[kBufferSize]; | 397 char target[kBufferSize]; |
| 383 size_t target_size = TEMP_FAILURE_RETRY( | 398 size_t target_size = TEMP_FAILURE_RETRY( |
| 384 readlink(pathname, target, kBufferSize)); | 399 readlink(pathname, target, kBufferSize)); |
| 385 if (target_size <= 0) { | 400 if (target_size <= 0) { |
| 386 return NULL; | 401 return NULL; |
| 387 } | 402 } |
| 388 char* target_name = reinterpret_cast<char*>(malloc(target_size + 1)); | 403 char* target_name = DartUtils::ScopedCString(target_size + 1); |
| 389 if (target_name == NULL) { | 404 ASSERT(target_name != NULL); |
| 390 return NULL; | |
| 391 } | |
| 392 memmove(target_name, target, target_size); | 405 memmove(target_name, target, target_size); |
| 393 target_name[target_size] = '\0'; | 406 target_name[target_size] = '\0'; |
| 394 return target_name; | 407 return target_name; |
| 395 } | 408 } |
| 396 | 409 |
| 397 | 410 |
| 398 bool File::IsAbsolutePath(const char* pathname) { | 411 bool File::IsAbsolutePath(const char* pathname) { |
| 399 return (pathname != NULL && pathname[0] == '/'); | 412 return (pathname != NULL && pathname[0] == '/'); |
| 400 } | 413 } |
| 401 | 414 |
| 402 | 415 |
| 403 char* File::GetCanonicalPath(const char* pathname) { | 416 const char* File::GetCanonicalPath(const char* pathname) { |
| 404 char* abs_path = NULL; | 417 char* abs_path = NULL; |
| 405 if (pathname != NULL) { | 418 if (pathname != NULL) { |
| 419 char* resolved_path = DartUtils::ScopedCString(PATH_MAX + 1); |
| 420 ASSERT(resolved_path != NULL); |
| 406 do { | 421 do { |
| 407 abs_path = realpath(pathname, NULL); | 422 abs_path = realpath(pathname, resolved_path); |
| 408 } while (abs_path == NULL && errno == EINTR); | 423 } while (abs_path == NULL && errno == EINTR); |
| 409 ASSERT(abs_path == NULL || IsAbsolutePath(abs_path)); | 424 ASSERT(abs_path == NULL || IsAbsolutePath(abs_path)); |
| 425 ASSERT(abs_path == NULL || (abs_path == resolved_path)); |
| 410 } | 426 } |
| 411 return abs_path; | 427 return abs_path; |
| 412 } | 428 } |
| 413 | 429 |
| 414 | 430 |
| 415 const char* File::PathSeparator() { | 431 const char* File::PathSeparator() { |
| 416 return "/"; | 432 return "/"; |
| 417 } | 433 } |
| 418 | 434 |
| 419 | 435 |
| 420 const char* File::StringEscapedPathSeparator() { | 436 const char* File::StringEscapedPathSeparator() { |
| 421 return "/"; | 437 return "/"; |
| 422 } | 438 } |
| 423 | 439 |
| 424 | 440 |
| 425 File::StdioHandleType File::GetStdioHandleType(int fd) { | 441 File::StdioHandleType File::GetStdioHandleType(int fd) { |
| 426 ASSERT(0 <= fd && fd <= 2); | 442 ASSERT((0 <= fd) && (fd <= 2)); |
| 427 struct stat64 buf; | 443 struct stat64 buf; |
| 428 int result = TEMP_FAILURE_RETRY(fstat64(fd, &buf)); | 444 int result = TEMP_FAILURE_RETRY(fstat64(fd, &buf)); |
| 429 if (result == -1) { | 445 if (result == -1) { |
| 430 const int kBufferSize = 1024; | 446 const int kBufferSize = 1024; |
| 431 char error_buf[kBufferSize]; | 447 char error_buf[kBufferSize]; |
| 432 FATAL2("Failed stat on file descriptor %d: %s", fd, | 448 FATAL2("Failed stat on file descriptor %d: %s", fd, |
| 433 Utils::StrError(errno, error_buf, kBufferSize)); | 449 Utils::StrError(errno, error_buf, kBufferSize)); |
| 434 } | 450 } |
| 435 if (S_ISCHR(buf.st_mode)) return kTerminal; | 451 if (S_ISCHR(buf.st_mode)) { |
| 436 if (S_ISFIFO(buf.st_mode)) return kPipe; | 452 return kTerminal; |
| 437 if (S_ISSOCK(buf.st_mode)) return kSocket; | 453 } |
| 438 if (S_ISREG(buf.st_mode)) return kFile; | 454 if (S_ISFIFO(buf.st_mode)) { |
| 455 return kPipe; |
| 456 } |
| 457 if (S_ISSOCK(buf.st_mode)) { |
| 458 return kSocket; |
| 459 } |
| 460 if (S_ISREG(buf.st_mode)) { |
| 461 return kFile; |
| 462 } |
| 439 return kOther; | 463 return kOther; |
| 440 } | 464 } |
| 441 | 465 |
| 442 | 466 |
| 443 File::Type File::GetType(const char* pathname, bool follow_links) { | 467 File::Type File::GetType(const char* pathname, bool follow_links) { |
| 444 struct stat64 entry_info; | 468 struct stat64 entry_info; |
| 445 int stat_success; | 469 int stat_success; |
| 446 if (follow_links) { | 470 if (follow_links) { |
| 447 stat_success = TEMP_FAILURE_RETRY(stat64(pathname, &entry_info)); | 471 stat_success = TEMP_FAILURE_RETRY(stat64(pathname, &entry_info)); |
| 448 } else { | 472 } else { |
| 449 stat_success = TEMP_FAILURE_RETRY(lstat64(pathname, &entry_info)); | 473 stat_success = TEMP_FAILURE_RETRY(lstat64(pathname, &entry_info)); |
| 450 } | 474 } |
| 451 if (stat_success == -1) return File::kDoesNotExist; | 475 if (stat_success == -1) { |
| 452 if (S_ISDIR(entry_info.st_mode)) return File::kIsDirectory; | 476 return File::kDoesNotExist; |
| 453 if (S_ISREG(entry_info.st_mode)) return File::kIsFile; | 477 } |
| 454 if (S_ISLNK(entry_info.st_mode)) return File::kIsLink; | 478 if (S_ISDIR(entry_info.st_mode)) { |
| 479 return File::kIsDirectory; |
| 480 } |
| 481 if (S_ISREG(entry_info.st_mode)) { |
| 482 return File::kIsFile; |
| 483 } |
| 484 if (S_ISLNK(entry_info.st_mode)) { |
| 485 return File::kIsLink; |
| 486 } |
| 455 return File::kDoesNotExist; | 487 return File::kDoesNotExist; |
| 456 } | 488 } |
| 457 | 489 |
| 458 | 490 |
| 459 File::Identical File::AreIdentical(const char* file_1, const char* file_2) { | 491 File::Identical File::AreIdentical(const char* file_1, const char* file_2) { |
| 460 struct stat64 file_1_info; | 492 struct stat64 file_1_info; |
| 461 struct stat64 file_2_info; | 493 struct stat64 file_2_info; |
| 462 if (TEMP_FAILURE_RETRY(lstat64(file_1, &file_1_info)) == -1 || | 494 if ((TEMP_FAILURE_RETRY(lstat64(file_1, &file_1_info)) == -1) || |
| 463 TEMP_FAILURE_RETRY(lstat64(file_2, &file_2_info)) == -1) { | 495 (TEMP_FAILURE_RETRY(lstat64(file_2, &file_2_info)) == -1)) { |
| 464 return File::kError; | 496 return File::kError; |
| 465 } | 497 } |
| 466 return (file_1_info.st_ino == file_2_info.st_ino && | 498 return ((file_1_info.st_ino == file_2_info.st_ino) && |
| 467 file_1_info.st_dev == file_2_info.st_dev) ? | 499 (file_1_info.st_dev == file_2_info.st_dev)) ? |
| 468 File::kIdentical : | 500 File::kIdentical : |
| 469 File::kDifferent; | 501 File::kDifferent; |
| 470 } | 502 } |
| 471 | 503 |
| 472 } // namespace bin | 504 } // namespace bin |
| 473 } // namespace dart | 505 } // namespace dart |
| 474 | 506 |
| 475 #endif // defined(TARGET_OS_LINUX) | 507 #endif // defined(TARGET_OS_LINUX) |
| OLD | NEW |