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 |