| 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_WINDOWS) | 6 #if defined(TARGET_OS_WINDOWS) |
| 7 | 7 |
| 8 #include "bin/file.h" | 8 #include "bin/file.h" |
| 9 | 9 |
| 10 #include <fcntl.h> // NOLINT | 10 #include <fcntl.h> // NOLINT |
| 11 #include <io.h> // NOLINT | 11 #include <io.h> // NOLINT |
| 12 #include <stdio.h> // NOLINT | 12 #include <stdio.h> // NOLINT |
| 13 #include <string.h> // NOLINT | 13 #include <string.h> // NOLINT |
| 14 #include <sys/stat.h> // NOLINT | 14 #include <sys/stat.h> // NOLINT |
| 15 #include <sys/utime.h> // NOLINT | 15 #include <sys/utime.h> // NOLINT |
| 16 #include <WinIoCtl.h> // NOLINT | 16 #include <WinIoCtl.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 "bin/utils.h" | 20 #include "bin/utils.h" |
| 21 #include "bin/utils_win.h" | 21 #include "bin/utils_win.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) |
| 30 : fd_(fd), real_fd_(-1), binary_(true), is_atty_(false) {} |
| 30 ~FileHandle() {} | 31 ~FileHandle() {} |
| 31 int fd() const { return fd_; } | 32 int fd() const { return fd_; } |
| 32 void set_fd(int fd) { fd_ = fd; } | 33 void set_fd(int fd) { fd_ = fd; } |
| 33 | 34 |
| 35 int real_fd() const { |
| 36 ASSERT(is_atty_); |
| 37 return real_fd_; |
| 38 } |
| 39 void set_real_fd(int real_fd) { |
| 40 ASSERT(is_atty_); |
| 41 real_fd_ = real_fd; |
| 42 } |
| 43 |
| 44 bool binary() const { return binary_; } |
| 45 void SetBinary(bool binary) { |
| 46 ASSERT(fd_ >= 0); |
| 47 if (binary) { |
| 48 // Setting the mode to _O_TEXT is needed first to reset _write to allow |
| 49 // an odd number of bytes, which setting to _O_BINARY alone doesn't |
| 50 // accomplish. |
| 51 if (binary != binary_) { |
| 52 _setmode(fd_, _O_TEXT); |
| 53 } |
| 54 _setmode(fd_, _O_BINARY); |
| 55 } else { |
| 56 // Only allow non-binary modes if we're attached to a terminal. |
| 57 ASSERT(_isatty(fd_)); |
| 58 _setmode(fd_, _O_WTEXT); |
| 59 } |
| 60 binary_ = binary; |
| 61 } |
| 62 |
| 63 bool is_atty() const { return is_atty_; } |
| 64 void set_is_atty(bool is_atty) { is_atty_ = is_atty; } |
| 65 |
| 34 private: | 66 private: |
| 35 int fd_; | 67 int fd_; |
| 68 int real_fd_; |
| 69 bool binary_; |
| 70 bool is_atty_; |
| 36 | 71 |
| 37 DISALLOW_COPY_AND_ASSIGN(FileHandle); | 72 DISALLOW_COPY_AND_ASSIGN(FileHandle); |
| 38 }; | 73 }; |
| 39 | 74 |
| 40 | 75 |
| 41 File::~File() { | 76 File::~File() { |
| 42 if (!IsClosed() && handle_->fd() != _fileno(stdout) && | 77 if (!IsClosed() && handle_->fd() != _fileno(stdout) && |
| 43 handle_->fd() != _fileno(stderr)) { | 78 handle_->fd() != _fileno(stderr)) { |
| 44 Close(); | 79 Close(); |
| 45 } | 80 } |
| 46 delete handle_; | 81 delete handle_; |
| 47 } | 82 } |
| 48 | 83 |
| 49 | 84 |
| 50 void File::Close() { | 85 void File::Close() { |
| 51 ASSERT(handle_->fd() >= 0); | 86 ASSERT(handle_->fd() >= 0); |
| 52 if ((handle_->fd() == _fileno(stdout)) || | 87 int closing_fd; |
| 53 (handle_->fd() == _fileno(stderr))) { | 88 if (handle_->is_atty()) { |
| 89 close(handle_->fd()); |
| 90 closing_fd = handle_->real_fd(); |
| 91 } else { |
| 92 closing_fd = handle_->fd(); |
| 93 } |
| 94 if ((closing_fd == _fileno(stdout)) || (closing_fd == _fileno(stderr))) { |
| 54 int fd = _open("NUL", _O_WRONLY); | 95 int fd = _open("NUL", _O_WRONLY); |
| 55 ASSERT(fd >= 0); | 96 ASSERT(fd >= 0); |
| 56 _dup2(fd, handle_->fd()); | 97 _dup2(fd, closing_fd); |
| 57 close(fd); | 98 close(fd); |
| 58 } else { | 99 } else { |
| 59 int err = close(handle_->fd()); | 100 int err = close(closing_fd); |
| 60 if (err != 0) { | 101 if (err != 0) { |
| 61 Log::PrintErr("%s\n", strerror(errno)); | 102 Log::PrintErr("%s\n", strerror(errno)); |
| 62 } | 103 } |
| 63 } | 104 } |
| 64 handle_->set_fd(kClosedFd); | 105 handle_->set_fd(kClosedFd); |
| 65 } | 106 } |
| 66 | 107 |
| 67 | 108 |
| 68 intptr_t File::GetFD() { | 109 intptr_t File::GetFD() { |
| 69 return handle_->fd(); | 110 return handle_->fd(); |
| (...skipping 53 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 123 } | 164 } |
| 124 | 165 |
| 125 | 166 |
| 126 int64_t File::Read(void* buffer, int64_t num_bytes) { | 167 int64_t File::Read(void* buffer, int64_t num_bytes) { |
| 127 ASSERT(handle_->fd() >= 0); | 168 ASSERT(handle_->fd() >= 0); |
| 128 return read(handle_->fd(), buffer, num_bytes); | 169 return read(handle_->fd(), buffer, num_bytes); |
| 129 } | 170 } |
| 130 | 171 |
| 131 | 172 |
| 132 int64_t File::Write(const void* buffer, int64_t num_bytes) { | 173 int64_t File::Write(const void* buffer, int64_t num_bytes) { |
| 133 ASSERT(handle_->fd() >= 0); | 174 int fd = handle_->fd(); |
| 134 return write(handle_->fd(), buffer, num_bytes); | 175 ASSERT(fd >= 0); |
| 176 if (handle_->binary()) { |
| 177 return _write(fd, buffer, num_bytes); |
| 178 } else { |
| 179 // If we've done _setmode(fd, _O_WTEXT) then _write() expects |
| 180 // a buffer of wchar_t with an even unmber of bytes. |
| 181 Utf8ToWideScope wide(reinterpret_cast<const char*>(buffer), num_bytes); |
| 182 ASSERT((wide.size_in_bytes() % 2) == 0); |
| 183 return _write(fd, wide.wide(), wide.size_in_bytes()); |
| 184 } |
| 135 } | 185 } |
| 136 | 186 |
| 137 | 187 |
| 138 int64_t File::Position() { | 188 int64_t File::Position() { |
| 139 ASSERT(handle_->fd() >= 0); | 189 ASSERT(handle_->fd() >= 0); |
| 140 return _lseeki64(handle_->fd(), 0, SEEK_CUR); | 190 return _lseeki64(handle_->fd(), 0, SEEK_CUR); |
| 141 } | 191 } |
| 142 | 192 |
| 143 | 193 |
| 144 bool File::SetPosition(int64_t position) { | 194 bool File::SetPosition(int64_t position) { |
| 145 ASSERT(handle_->fd() >= 0); | 195 ASSERT(handle_->fd() >= 0); |
| 146 return _lseeki64(handle_->fd(), position, SEEK_SET) >= 0; | 196 return _lseeki64(handle_->fd(), position, SEEK_SET) >= 0; |
| 147 } | 197 } |
| 148 | 198 |
| 149 | 199 |
| 200 void File::SetTranslation(DartFileTranslation translation) { |
| 201 ASSERT(handle_->fd() >= 0); |
| 202 // Only allow setting the translation mode if we're attached to a terminal. |
| 203 // TODO(zra): Is this restriction needed? Is it already handled correctly |
| 204 // by _write()? |
| 205 if (handle_->is_atty()) { |
| 206 handle_->SetBinary(translation == kBinary); |
| 207 } |
| 208 } |
| 209 |
| 210 |
| 150 bool File::Truncate(int64_t length) { | 211 bool File::Truncate(int64_t length) { |
| 151 ASSERT(handle_->fd() >= 0); | 212 ASSERT(handle_->fd() >= 0); |
| 152 return _chsize_s(handle_->fd(), length) == 0; | 213 return _chsize_s(handle_->fd(), length) == 0; |
| 153 } | 214 } |
| 154 | 215 |
| 155 | 216 |
| 156 bool File::Flush() { | 217 bool File::Flush() { |
| 157 ASSERT(handle_->fd()); | 218 ASSERT(handle_->fd()); |
| 158 return _commit(handle_->fd()) != -1; | 219 return _commit(handle_->fd()) != -1; |
| 159 } | 220 } |
| (...skipping 82 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 242 | 303 |
| 243 | 304 |
| 244 File* File::Open(const char* path, FileOpenMode mode) { | 305 File* File::Open(const char* path, FileOpenMode mode) { |
| 245 Utf8ToWideScope system_name(path); | 306 Utf8ToWideScope system_name(path); |
| 246 File* file = FileOpenW(system_name.wide(), mode); | 307 File* file = FileOpenW(system_name.wide(), mode); |
| 247 return file; | 308 return file; |
| 248 } | 309 } |
| 249 | 310 |
| 250 | 311 |
| 251 File* File::OpenStdio(int fd) { | 312 File* File::OpenStdio(int fd) { |
| 313 int stdio_fd = -1; |
| 252 switch (fd) { | 314 switch (fd) { |
| 253 case 1: | 315 case 1: |
| 254 fd = _fileno(stdout); | 316 stdio_fd = _fileno(stdout); |
| 255 break; | 317 break; |
| 256 case 2: | 318 case 2: |
| 257 fd = _fileno(stderr); | 319 stdio_fd = _fileno(stderr); |
| 258 break; | 320 break; |
| 259 default: | 321 default: |
| 260 UNREACHABLE(); | 322 UNREACHABLE(); |
| 261 } | 323 } |
| 262 _setmode(fd, _O_BINARY); | 324 FileHandle* handle; |
| 263 return new File(new FileHandle(fd)); | 325 if (_isatty(stdio_fd)) { |
| 326 // We _dup these fds to avoid different Isoaltes racing on calls to |
| 327 // _setmode() and _write() on the same file descriptor. That is, a call to |
| 328 // _setmode() followed by a call to _write() on the same file descriptor is |
| 329 // not atomic. When the corresponding Dart File object is closed, these |
| 330 // dup'd fds will be closed. |
| 331 int stdio_fd_dup = _dup(stdio_fd); |
| 332 handle = new FileHandle(stdio_fd_dup); |
| 333 handle->set_is_atty(true); |
| 334 handle->set_real_fd(stdio_fd); |
| 335 } else { |
| 336 handle = new FileHandle(stdio_fd); |
| 337 } |
| 338 handle->SetBinary(true); |
| 339 return new File(handle); |
| 264 } | 340 } |
| 265 | 341 |
| 266 | 342 |
| 267 static bool StatHelper(wchar_t* path, struct __stat64* st) { | 343 static bool StatHelper(wchar_t* path, struct __stat64* st) { |
| 268 int stat_status = _wstat64(path, st); | 344 int stat_status = _wstat64(path, st); |
| 269 if (stat_status != 0) { | 345 if (stat_status != 0) { |
| 270 return false; | 346 return false; |
| 271 } | 347 } |
| 272 if ((st->st_mode & S_IFMT) != S_IFREG) { | 348 if ((st->st_mode & S_IFMT) != S_IFREG) { |
| 273 SetLastError(ERROR_NOT_SUPPORTED); | 349 SetLastError(ERROR_NOT_SUPPORTED); |
| (...skipping 454 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 728 return kIdentical; | 804 return kIdentical; |
| 729 } else { | 805 } else { |
| 730 return kDifferent; | 806 return kDifferent; |
| 731 } | 807 } |
| 732 } | 808 } |
| 733 | 809 |
| 734 } // namespace bin | 810 } // namespace bin |
| 735 } // namespace dart | 811 } // namespace dart |
| 736 | 812 |
| 737 #endif // defined(TARGET_OS_WINDOWS) | 813 #endif // defined(TARGET_OS_WINDOWS) |
| OLD | NEW |