| 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(HOST_OS_WINDOWS) | 6 #if defined(HOST_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) | 29 explicit FileHandle(int fd) : fd_(fd) {} |
| 30 : fd_(fd), real_fd_(-1), binary_(true), is_atty_(false) {} | |
| 31 ~FileHandle() {} | 30 ~FileHandle() {} |
| 32 int fd() const { return fd_; } | 31 int fd() const { return fd_; } |
| 33 void set_fd(int fd) { fd_ = fd; } | 32 void set_fd(int fd) { fd_ = fd; } |
| 34 | 33 |
| 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 | |
| 66 private: | 34 private: |
| 67 int fd_; | 35 int fd_; |
| 68 int real_fd_; | |
| 69 bool binary_; | |
| 70 bool is_atty_; | |
| 71 | 36 |
| 72 DISALLOW_COPY_AND_ASSIGN(FileHandle); | 37 DISALLOW_COPY_AND_ASSIGN(FileHandle); |
| 73 }; | 38 }; |
| 74 | 39 |
| 75 | 40 |
| 76 File::~File() { | 41 File::~File() { |
| 77 if (!IsClosed() && handle_->fd() != _fileno(stdout) && | 42 if (!IsClosed() && handle_->fd() != _fileno(stdout) && |
| 78 handle_->fd() != _fileno(stderr)) { | 43 handle_->fd() != _fileno(stderr)) { |
| 79 Close(); | 44 Close(); |
| 80 } | 45 } |
| 81 delete handle_; | 46 delete handle_; |
| 82 } | 47 } |
| 83 | 48 |
| 84 | 49 |
| 85 void File::Close() { | 50 void File::Close() { |
| 86 ASSERT(handle_->fd() >= 0); | 51 ASSERT(handle_->fd() >= 0); |
| 87 int closing_fd; | 52 int closing_fd = handle_->fd(); |
| 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))) { | 53 if ((closing_fd == _fileno(stdout)) || (closing_fd == _fileno(stderr))) { |
| 95 int fd = _open("NUL", _O_WRONLY); | 54 int fd = _open("NUL", _O_WRONLY); |
| 96 ASSERT(fd >= 0); | 55 ASSERT(fd >= 0); |
| 97 _dup2(fd, closing_fd); | 56 _dup2(fd, closing_fd); |
| 98 close(fd); | 57 close(fd); |
| 99 } else { | 58 } else { |
| 100 int err = close(closing_fd); | 59 int err = close(closing_fd); |
| 101 if (err != 0) { | 60 if (err != 0) { |
| 102 Log::PrintErr("%s\n", strerror(errno)); | 61 Log::PrintErr("%s\n", strerror(errno)); |
| 103 } | 62 } |
| (...skipping 62 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 166 | 125 |
| 167 int64_t File::Read(void* buffer, int64_t num_bytes) { | 126 int64_t File::Read(void* buffer, int64_t num_bytes) { |
| 168 ASSERT(handle_->fd() >= 0); | 127 ASSERT(handle_->fd() >= 0); |
| 169 return read(handle_->fd(), buffer, num_bytes); | 128 return read(handle_->fd(), buffer, num_bytes); |
| 170 } | 129 } |
| 171 | 130 |
| 172 | 131 |
| 173 int64_t File::Write(const void* buffer, int64_t num_bytes) { | 132 int64_t File::Write(const void* buffer, int64_t num_bytes) { |
| 174 int fd = handle_->fd(); | 133 int fd = handle_->fd(); |
| 175 ASSERT(fd >= 0); | 134 ASSERT(fd >= 0); |
| 176 if (handle_->binary()) { | 135 HANDLE handle = reinterpret_cast<HANDLE>(_get_osfhandle(fd)); |
| 177 return _write(fd, buffer, num_bytes); | 136 DWORD written = 0; |
| 178 } else { | 137 BOOL result = WriteFile(handle, buffer, num_bytes, &written, NULL); |
| 179 // If we've done _setmode(fd, _O_WTEXT) then _write() expects | 138 if (!result) { |
| 180 // a buffer of wchar_t with an even unmber of bytes. | 139 return -1; |
| 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 } | 140 } |
| 141 DWORD mode; |
| 142 int64_t bytes_written = written; |
| 143 if (GetConsoleMode(handle, &mode)) { |
| 144 // If `handle` is for a console, then `written` may refer to the number of |
| 145 // characters printed to the screen rather than the number of bytes of the |
| 146 // buffer that were actually consumed. To compute the number of bytes that |
| 147 // were actually consumed, we convert the buffer to a wchar_t using the |
| 148 // console's current code page, filling as many characters as were |
| 149 // printed, and then convert that many characters back to the encoding for |
| 150 // the code page, which gives the number of bytes of `buffer` used to |
| 151 // generate the characters that were printed. |
| 152 wchar_t* wide = new wchar_t[written]; |
| 153 int cp = GetConsoleOutputCP(); |
| 154 MultiByteToWideChar(cp, 0, reinterpret_cast<const char*>(buffer), -1, wide, |
| 155 written); |
| 156 int buffer_len = |
| 157 WideCharToMultiByte(cp, 0, wide, written, NULL, 0, NULL, NULL); |
| 158 delete wide; |
| 159 bytes_written = buffer_len; |
| 160 } |
| 161 return bytes_written; |
| 185 } | 162 } |
| 186 | 163 |
| 187 | 164 |
| 188 bool File::VPrint(const char* format, va_list args) { | 165 bool File::VPrint(const char* format, va_list args) { |
| 189 // Measure. | 166 // Measure. |
| 190 va_list measure_args; | 167 va_list measure_args; |
| 191 va_copy(measure_args, args); | 168 va_copy(measure_args, args); |
| 192 intptr_t len = _vscprintf(format, measure_args); | 169 intptr_t len = _vscprintf(format, measure_args); |
| 193 va_end(measure_args); | 170 va_end(measure_args); |
| 194 | 171 |
| (...skipping 16 matching lines...) Expand all Loading... |
| 211 return _lseeki64(handle_->fd(), 0, SEEK_CUR); | 188 return _lseeki64(handle_->fd(), 0, SEEK_CUR); |
| 212 } | 189 } |
| 213 | 190 |
| 214 | 191 |
| 215 bool File::SetPosition(int64_t position) { | 192 bool File::SetPosition(int64_t position) { |
| 216 ASSERT(handle_->fd() >= 0); | 193 ASSERT(handle_->fd() >= 0); |
| 217 return _lseeki64(handle_->fd(), position, SEEK_SET) >= 0; | 194 return _lseeki64(handle_->fd(), position, SEEK_SET) >= 0; |
| 218 } | 195 } |
| 219 | 196 |
| 220 | 197 |
| 221 void File::SetTranslation(DartFileTranslation translation) { | |
| 222 ASSERT(handle_->fd() >= 0); | |
| 223 // Only allow setting the translation mode if we're attached to a terminal. | |
| 224 // TODO(zra): Is this restriction needed? Is it already handled correctly | |
| 225 // by _write()? | |
| 226 if (handle_->is_atty()) { | |
| 227 handle_->SetBinary(translation == kBinary); | |
| 228 } | |
| 229 } | |
| 230 | |
| 231 | |
| 232 bool File::Truncate(int64_t length) { | 198 bool File::Truncate(int64_t length) { |
| 233 ASSERT(handle_->fd() >= 0); | 199 ASSERT(handle_->fd() >= 0); |
| 234 return _chsize_s(handle_->fd(), length) == 0; | 200 return _chsize_s(handle_->fd(), length) == 0; |
| 235 } | 201 } |
| 236 | 202 |
| 237 | 203 |
| 238 bool File::Flush() { | 204 bool File::Flush() { |
| 239 ASSERT(handle_->fd()); | 205 ASSERT(handle_->fd()); |
| 240 return _commit(handle_->fd()) != -1; | 206 return _commit(handle_->fd()) != -1; |
| 241 } | 207 } |
| (...skipping 93 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 335 switch (fd) { | 301 switch (fd) { |
| 336 case 1: | 302 case 1: |
| 337 stdio_fd = _fileno(stdout); | 303 stdio_fd = _fileno(stdout); |
| 338 break; | 304 break; |
| 339 case 2: | 305 case 2: |
| 340 stdio_fd = _fileno(stderr); | 306 stdio_fd = _fileno(stderr); |
| 341 break; | 307 break; |
| 342 default: | 308 default: |
| 343 UNREACHABLE(); | 309 UNREACHABLE(); |
| 344 } | 310 } |
| 345 FileHandle* handle; | 311 _setmode(stdio_fd, _O_BINARY); |
| 346 if (_isatty(stdio_fd)) { | 312 return new File(new FileHandle(stdio_fd)); |
| 347 // We _dup these fds to avoid different Isoaltes racing on calls to | |
| 348 // _setmode() and _write() on the same file descriptor. That is, a call to | |
| 349 // _setmode() followed by a call to _write() on the same file descriptor is | |
| 350 // not atomic. When the corresponding Dart File object is closed, these | |
| 351 // dup'd fds will be closed. | |
| 352 int stdio_fd_dup = _dup(stdio_fd); | |
| 353 handle = new FileHandle(stdio_fd_dup); | |
| 354 handle->set_is_atty(true); | |
| 355 handle->set_real_fd(stdio_fd); | |
| 356 } else { | |
| 357 handle = new FileHandle(stdio_fd); | |
| 358 } | |
| 359 handle->SetBinary(true); | |
| 360 return new File(handle); | |
| 361 } | 313 } |
| 362 | 314 |
| 363 | 315 |
| 364 static bool StatHelper(wchar_t* path, struct __stat64* st) { | 316 static bool StatHelper(wchar_t* path, struct __stat64* st) { |
| 365 int stat_status = _wstat64(path, st); | 317 int stat_status = _wstat64(path, st); |
| 366 if (stat_status != 0) { | 318 if (stat_status != 0) { |
| 367 return false; | 319 return false; |
| 368 } | 320 } |
| 369 if ((st->st_mode & S_IFMT) != S_IFREG) { | 321 if ((st->st_mode & S_IFMT) != S_IFREG) { |
| 370 SetLastError(ERROR_NOT_SUPPORTED); | 322 SetLastError(ERROR_NOT_SUPPORTED); |
| (...skipping 454 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 825 return kIdentical; | 777 return kIdentical; |
| 826 } else { | 778 } else { |
| 827 return kDifferent; | 779 return kDifferent; |
| 828 } | 780 } |
| 829 } | 781 } |
| 830 | 782 |
| 831 } // namespace bin | 783 } // namespace bin |
| 832 } // namespace dart | 784 } // namespace dart |
| 833 | 785 |
| 834 #endif // defined(HOST_OS_WINDOWS) | 786 #endif // defined(HOST_OS_WINDOWS) |
| OLD | NEW |