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 |