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