]>
Commit | Line | Data |
---|---|---|
49bf30f4 | 1 | // Wrapper of C-language FILE struct -*- C++ -*- |
2 | ||
fbd26352 | 3 | // Copyright (C) 2000-2019 Free Software Foundation, Inc. |
49bf30f4 | 4 | // |
5 | // This file is part of the GNU ISO C++ Library. This library is free | |
6 | // software; you can redistribute it and/or modify it under the | |
7 | // terms of the GNU General Public License as published by the | |
6bc9506f | 8 | // Free Software Foundation; either version 3, or (at your option) |
49bf30f4 | 9 | // any later version. |
10 | ||
11 | // This library is distributed in the hope that it will be useful, | |
12 | // but WITHOUT ANY WARRANTY; without even the implied warranty of | |
13 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
14 | // GNU General Public License for more details. | |
15 | ||
6bc9506f | 16 | // Under Section 7 of GPL version 3, you are granted additional |
17 | // permissions described in the GCC Runtime Library Exception, version | |
18 | // 3.1, as published by the Free Software Foundation. | |
49bf30f4 | 19 | |
6bc9506f | 20 | // You should have received a copy of the GNU General Public License and |
21 | // a copy of the GCC Runtime Library Exception along with this program; | |
22 | // see the files COPYING3 and COPYING.RUNTIME respectively. If not, see | |
23 | // <http://www.gnu.org/licenses/>. | |
49bf30f4 | 24 | |
25 | // | |
26 | // ISO C++ 14882: 27.8 File-based streams | |
27 | // | |
28 | ||
29 | #include <bits/basic_file.h> | |
c3b8e7f7 | 30 | #include <fcntl.h> |
deea81ea | 31 | #include <errno.h> |
49bf30f4 | 32 | |
35f1a4f0 | 33 | #ifdef _GLIBCXX_HAVE_POLL |
34 | #include <poll.h> | |
35 | #endif | |
36 | ||
37 | // Pick up ioctl on Solaris 2.8 | |
38 | #ifdef _GLIBCXX_HAVE_UNISTD_H | |
39 | #include <unistd.h> | |
40 | #endif | |
41 | ||
42 | // Pick up FIONREAD on Solaris 2 | |
5a64d8cf | 43 | #ifdef _GLIBCXX_HAVE_SYS_IOCTL_H |
33b7ef52 | 44 | #define BSD_COMP |
3a278579 | 45 | #include <sys/ioctl.h> |
46 | #endif | |
47 | ||
48 | // Pick up FIONREAD on Solaris 2.5. | |
5a64d8cf | 49 | #ifdef _GLIBCXX_HAVE_SYS_FILIO_H |
3a278579 | 50 | #include <sys/filio.h> |
51 | #endif | |
52 | ||
4709cd2d | 53 | #ifdef _GLIBCXX_HAVE_SYS_UIO_H |
54 | #include <sys/uio.h> | |
55 | #endif | |
56 | ||
5a64d8cf | 57 | #if defined(_GLIBCXX_HAVE_S_ISREG) || defined(_GLIBCXX_HAVE_S_IFREG) |
3a278579 | 58 | # include <sys/stat.h> |
5a64d8cf | 59 | # ifdef _GLIBCXX_HAVE_S_ISREG |
60 | # define _GLIBCXX_ISREG(x) S_ISREG(x) | |
3a278579 | 61 | # else |
5a64d8cf | 62 | # define _GLIBCXX_ISREG(x) (((x) & S_IFMT) == S_IFREG) |
3a278579 | 63 | # endif |
64 | #endif | |
65 | ||
b1e0564a | 66 | #include <limits> // For <off_t>::max() and min() and <streamsize>::max() |
440c107f | 67 | |
33b7ef52 | 68 | namespace |
7b251560 | 69 | { |
70 | // Map ios_base::openmode flags to a string for use in fopen(). | |
71 | // Table of valid combinations as given in [lib.filebuf.members]/2. | |
72 | static const char* | |
73 | fopen_mode(std::ios_base::openmode mode) | |
74 | { | |
33b7ef52 | 75 | enum |
7b251560 | 76 | { |
77 | in = std::ios_base::in, | |
78 | out = std::ios_base::out, | |
79 | trunc = std::ios_base::trunc, | |
80 | app = std::ios_base::app, | |
81 | binary = std::ios_base::binary | |
82 | }; | |
3ec0e581 | 83 | |
84 | // _GLIBCXX_RESOLVE_LIB_DEFECTS | |
85 | // 596. 27.8.1.3 Table 112 omits "a+" and "a+b" modes. | |
7b251560 | 86 | switch (mode & (in|out|trunc|app|binary)) |
87 | { | |
3ec0e581 | 88 | case ( out ): return "w"; |
89 | case ( out |app ): return "a"; | |
90 | case ( app ): return "a"; | |
91 | case ( out|trunc ): return "w"; | |
92 | case (in ): return "r"; | |
93 | case (in|out ): return "r+"; | |
94 | case (in|out|trunc ): return "w+"; | |
95 | case (in|out |app ): return "a+"; | |
96 | case (in |app ): return "a+"; | |
97 | ||
98 | case ( out |binary): return "wb"; | |
99 | case ( out |app|binary): return "ab"; | |
100 | case ( app|binary): return "ab"; | |
101 | case ( out|trunc |binary): return "wb"; | |
102 | case (in |binary): return "rb"; | |
7b251560 | 103 | case (in|out |binary): return "r+b"; |
104 | case (in|out|trunc |binary): return "w+b"; | |
71021d76 | 105 | case (in|out |app|binary): return "a+b"; |
3ec0e581 | 106 | case (in |app|binary): return "a+b"; |
107 | ||
7b251560 | 108 | default: return 0; // invalid |
109 | } | |
110 | } | |
6e49c2bf | 111 | |
112 | // Wrapper handling partial write. | |
113 | static std::streamsize | |
114 | xwrite(int __fd, const char* __s, std::streamsize __n) | |
115 | { | |
116 | std::streamsize __nleft = __n; | |
41ae48fe | 117 | |
118 | for (;;) | |
6e49c2bf | 119 | { |
120 | const std::streamsize __ret = write(__fd, __s, __nleft); | |
121 | if (__ret == -1L && errno == EINTR) | |
122 | continue; | |
41ae48fe | 123 | if (__ret == -1L) |
6e49c2bf | 124 | break; |
41ae48fe | 125 | |
6e49c2bf | 126 | __nleft -= __ret; |
41ae48fe | 127 | if (__nleft == 0) |
128 | break; | |
129 | ||
6e49c2bf | 130 | __s += __ret; |
131 | } | |
41ae48fe | 132 | |
6e49c2bf | 133 | return __n - __nleft; |
134 | } | |
135 | ||
136 | #ifdef _GLIBCXX_HAVE_WRITEV | |
137 | // Wrapper handling partial writev. | |
138 | static std::streamsize | |
139 | xwritev(int __fd, const char* __s1, std::streamsize __n1, | |
140 | const char* __s2, std::streamsize __n2) | |
141 | { | |
41ae48fe | 142 | std::streamsize __nleft = __n1 + __n2; |
143 | std::streamsize __n1_left = __n1; | |
6e49c2bf | 144 | |
145 | struct iovec __iov[2]; | |
6e49c2bf | 146 | __iov[1].iov_base = const_cast<char*>(__s2); |
147 | __iov[1].iov_len = __n2; | |
148 | ||
41ae48fe | 149 | for (;;) |
6e49c2bf | 150 | { |
41ae48fe | 151 | __iov[0].iov_base = const_cast<char*>(__s1); |
152 | __iov[0].iov_len = __n1_left; | |
153 | ||
154 | const std::streamsize __ret = writev(__fd, __iov, 2); | |
155 | if (__ret == -1L && errno == EINTR) | |
156 | continue; | |
157 | if (__ret == -1L) | |
158 | break; | |
159 | ||
160 | __nleft -= __ret; | |
161 | if (__nleft == 0) | |
162 | break; | |
163 | ||
164 | const std::streamsize __off = __ret - __n1_left; | |
165 | if (__off >= 0) | |
6e49c2bf | 166 | { |
41ae48fe | 167 | __nleft -= xwrite(__fd, __s2 + __off, __n2 - __off); |
168 | break; | |
6e49c2bf | 169 | } |
33b7ef52 | 170 | |
41ae48fe | 171 | __s1 += __ret; |
172 | __n1_left -= __ret; | |
6e49c2bf | 173 | } |
174 | ||
41ae48fe | 175 | return __n1 + __n2 - __nleft; |
6e49c2bf | 176 | } |
177 | #endif | |
29b00143 | 178 | } // anonymous namespace |
7b251560 | 179 | |
1069247d | 180 | |
2948dd21 | 181 | namespace std _GLIBCXX_VISIBILITY(default) |
182 | { | |
183 | _GLIBCXX_BEGIN_NAMESPACE_VERSION | |
1069247d | 184 | |
b6c37935 | 185 | // Definitions for __basic_file<char>. |
6261db62 | 186 | __basic_file<char>::__basic_file(__c_lock* /*__lock*/) throw() |
b6c37935 | 187 | : _M_cfile(NULL), _M_cfile_created(false) { } |
188 | ||
189 | __basic_file<char>::~__basic_file() | |
5f8a31fe | 190 | { this->close(); } |
33b7ef52 | 191 | |
b6c37935 | 192 | __basic_file<char>* |
33b7ef52 | 193 | __basic_file<char>::sys_open(__c_file* __file, ios_base::openmode) |
b6c37935 | 194 | { |
195 | __basic_file* __ret = NULL; | |
196 | if (!this->is_open() && __file) | |
197 | { | |
e6e4aafa | 198 | int __err, __save_errno = errno; |
199 | // POSIX guarantees that fflush sets errno on error, but C doesn't. | |
33b7ef52 | 200 | errno = 0; |
d1f75b60 | 201 | do |
e6e4aafa | 202 | __err = fflush(__file); |
d1f75b60 | 203 | while (__err && errno == EINTR); |
e6e4aafa | 204 | errno = __save_errno; |
d1f75b60 | 205 | if (!__err) |
206 | { | |
207 | _M_cfile = __file; | |
208 | _M_cfile_created = false; | |
209 | __ret = this; | |
210 | } | |
120167de | 211 | } |
212 | return __ret; | |
213 | } | |
33b7ef52 | 214 | |
120167de | 215 | __basic_file<char>* |
add36446 | 216 | __basic_file<char>::sys_open(int __fd, ios_base::openmode __mode) throw () |
120167de | 217 | { |
218 | __basic_file* __ret = NULL; | |
29b00143 | 219 | const char* __c_mode = fopen_mode(__mode); |
4bada8ba | 220 | if (__c_mode && !this->is_open() && (_M_cfile = fdopen(__fd, __c_mode))) |
120167de | 221 | { |
4bada8ba | 222 | char* __buf = NULL; |
0eaa766c | 223 | _M_cfile_created = true; |
120167de | 224 | if (__fd == 0) |
4bada8ba | 225 | setvbuf(_M_cfile, __buf, _IONBF, 0); |
b6c37935 | 226 | __ret = this; |
227 | } | |
228 | return __ret; | |
229 | } | |
33b7ef52 | 230 | |
231 | __basic_file<char>* | |
232 | __basic_file<char>::open(const char* __name, ios_base::openmode __mode, | |
b6c37935 | 233 | int /*__prot*/) |
234 | { | |
235 | __basic_file* __ret = NULL; | |
29b00143 | 236 | const char* __c_mode = fopen_mode(__mode); |
7b251560 | 237 | if (__c_mode && !this->is_open()) |
b6c37935 | 238 | { |
440c107f | 239 | #ifdef _GLIBCXX_USE_LFS |
240 | if ((_M_cfile = fopen64(__name, __c_mode))) | |
241 | #else | |
b6c37935 | 242 | if ((_M_cfile = fopen(__name, __c_mode))) |
440c107f | 243 | #endif |
b6c37935 | 244 | { |
245 | _M_cfile_created = true; | |
246 | __ret = this; | |
247 | } | |
248 | } | |
249 | return __ret; | |
250 | } | |
33b7ef52 | 251 | |
d4fd5c49 | 252 | #if _GLIBCXX_HAVE__WFOPEN && _GLIBCXX_USE_WCHAR_T |
253 | __basic_file<char>* | |
254 | __basic_file<char>::open(const wchar_t* __name, ios_base::openmode __mode) | |
255 | { | |
256 | __basic_file* __ret = NULL; | |
257 | const char* __c_mode = fopen_mode(__mode); | |
258 | if (__c_mode && !this->is_open()) | |
259 | { | |
260 | wchar_t __wc_mode[4] = { }; | |
261 | int __i = 0; | |
262 | do | |
263 | { | |
264 | switch(__c_mode[__i]) { | |
265 | case 'a': __wc_mode[__i] = L'a'; break; | |
266 | case 'b': __wc_mode[__i] = L'b'; break; | |
267 | case 'r': __wc_mode[__i] = L'r'; break; | |
268 | case 'w': __wc_mode[__i] = L'w'; break; | |
269 | case '+': __wc_mode[__i] = L'+'; break; | |
270 | default: return __ret; | |
271 | } | |
272 | } | |
273 | while (__c_mode[++__i]); | |
274 | ||
275 | if ((_M_cfile = _wfopen(__name, __wc_mode))) | |
276 | { | |
277 | _M_cfile_created = true; | |
278 | __ret = this; | |
279 | } | |
280 | } | |
281 | return __ret; | |
282 | } | |
283 | #endif | |
284 | ||
33b7ef52 | 285 | bool |
add36446 | 286 | __basic_file<char>::is_open() const throw () |
120167de | 287 | { return _M_cfile != 0; } |
33b7ef52 | 288 | |
289 | int | |
add36446 | 290 | __basic_file<char>::fd() throw () |
84215fe8 | 291 | { return fileno(_M_cfile); } |
33b7ef52 | 292 | |
84215fe8 | 293 | __c_file* |
add36446 | 294 | __basic_file<char>::file() throw () |
84215fe8 | 295 | { return _M_cfile; } |
33b7ef52 | 296 | |
297 | __basic_file<char>* | |
b6c37935 | 298 | __basic_file<char>::close() |
33b7ef52 | 299 | { |
0eaa766c | 300 | __basic_file* __ret = static_cast<__basic_file*>(NULL); |
5f8a31fe | 301 | if (this->is_open()) |
302 | { | |
8fdcd1ba | 303 | int __err = 0; |
bd18ac96 | 304 | if (_M_cfile_created) |
e847d2db | 305 | __err = fclose(_M_cfile); |
8fdcd1ba | 306 | _M_cfile = 0; |
d1f75b60 | 307 | if (!__err) |
308 | __ret = this; | |
5f8a31fe | 309 | } |
0eaa766c | 310 | return __ret; |
b6c37935 | 311 | } |
33b7ef52 | 312 | |
313 | streamsize | |
fd63f08b | 314 | __basic_file<char>::xsgetn(char* __s, streamsize __n) |
80c85eae | 315 | { |
316 | streamsize __ret; | |
317 | do | |
318 | __ret = read(this->fd(), __s, __n); | |
319 | while (__ret == -1L && errno == EINTR); | |
320 | return __ret; | |
321 | } | |
227f9e56 | 322 | |
33b7ef52 | 323 | streamsize |
227f9e56 | 324 | __basic_file<char>::xsputn(const char* __s, streamsize __n) |
29b00143 | 325 | { return xwrite(this->fd(), __s, __n); } |
0d554d4f | 326 | |
33b7ef52 | 327 | streamsize |
4709cd2d | 328 | __basic_file<char>::xsputn_2(const char* __s1, streamsize __n1, |
329 | const char* __s2, streamsize __n2) | |
330 | { | |
331 | streamsize __ret = 0; | |
332 | #ifdef _GLIBCXX_HAVE_WRITEV | |
29b00143 | 333 | __ret = xwritev(this->fd(), __s1, __n1, __s2, __n2); |
4709cd2d | 334 | #else |
335 | if (__n1) | |
29b00143 | 336 | __ret = xwrite(this->fd(), __s1, __n1); |
4709cd2d | 337 | |
338 | if (__ret == __n1) | |
29b00143 | 339 | __ret += xwrite(this->fd(), __s2, __n2); |
4709cd2d | 340 | #endif |
341 | return __ret; | |
342 | } | |
343 | ||
b812c14e | 344 | streamoff |
add36446 | 345 | __basic_file<char>::seekoff(streamoff __off, ios_base::seekdir __way) throw () |
440c107f | 346 | { |
347 | #ifdef _GLIBCXX_USE_LFS | |
348 | return lseek64(this->fd(), __off, __way); | |
349 | #else | |
b1e0564a | 350 | if (__off > numeric_limits<off_t>::max() |
351 | || __off < numeric_limits<off_t>::min()) | |
440c107f | 352 | return -1L; |
353 | return lseek(this->fd(), __off, __way); | |
354 | #endif | |
355 | } | |
0d554d4f | 356 | |
33b7ef52 | 357 | int |
358 | __basic_file<char>::sync() | |
120167de | 359 | { return fflush(_M_cfile); } |
3a278579 | 360 | |
361 | streamsize | |
fd63f08b | 362 | __basic_file<char>::showmanyc() |
3a278579 | 363 | { |
c63a2732 | 364 | #ifndef _GLIBCXX_NO_IOCTL |
3a278579 | 365 | #ifdef FIONREAD |
33b7ef52 | 366 | // Pipes and sockets. |
3a278579 | 367 | int __num = 0; |
368 | int __r = ioctl(this->fd(), FIONREAD, &__num); | |
369 | if (!__r && __num >= 0) | |
33b7ef52 | 370 | return __num; |
c63a2732 | 371 | #endif |
372 | #endif | |
3a278579 | 373 | |
5a64d8cf | 374 | #ifdef _GLIBCXX_HAVE_POLL |
3a278579 | 375 | // Cheap test. |
376 | struct pollfd __pfd[1]; | |
377 | __pfd[0].fd = this->fd(); | |
378 | __pfd[0].events = POLLIN; | |
379 | if (poll(__pfd, 1, 0) <= 0) | |
380 | return 0; | |
33b7ef52 | 381 | #endif |
3a278579 | 382 | |
5a64d8cf | 383 | #if defined(_GLIBCXX_HAVE_S_ISREG) || defined(_GLIBCXX_HAVE_S_IFREG) |
3a278579 | 384 | // Regular files. |
b1e0564a | 385 | #ifdef _GLIBCXX_USE_LFS |
386 | struct stat64 __buffer; | |
387 | const int __err = fstat64(this->fd(), &__buffer); | |
388 | if (!__err && _GLIBCXX_ISREG(__buffer.st_mode)) | |
389 | { | |
390 | const streamoff __off = __buffer.st_size - lseek64(this->fd(), 0, | |
391 | ios_base::cur); | |
392 | return std::min(__off, streamoff(numeric_limits<streamsize>::max())); | |
393 | } | |
394 | #else | |
3a278579 | 395 | struct stat __buffer; |
b1e0564a | 396 | const int __err = fstat(this->fd(), &__buffer); |
397 | if (!__err && _GLIBCXX_ISREG(__buffer.st_mode)) | |
398 | return __buffer.st_size - lseek(this->fd(), 0, ios_base::cur); | |
399 | #endif | |
3a278579 | 400 | #endif |
401 | return 0; | |
402 | } | |
1069247d | 403 | |
2948dd21 | 404 | _GLIBCXX_END_NAMESPACE_VERSION |
405 | } // namespace | |
1069247d | 406 |