/ src / basic_file.cc
basic_file.cc
  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  
 74  namespace 
 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