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