Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(170)

Side by Side Diff: runtime/bin/file_win.cc

Issue 2761673002: [dart:io][windows] Use WriteFile instead of _write (Closed)
Patch Set: Format stdio.dart Created 3 years, 8 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « runtime/bin/file_unsupported.cc ('k') | runtime/bin/io_natives.cc » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
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
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
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
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
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)
OLDNEW
« no previous file with comments | « runtime/bin/file_unsupported.cc ('k') | runtime/bin/io_natives.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698