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