1 /*
2  * Copyright (c) 1999
3  * Silicon Graphics Computer Systems, Inc.
4  *
5  * Copyright (c) 1999
6  * Boris Fomitchev
7  *
8  * This material is provided "as is", with absolutely no warranty expressed
9  * or implied. Any use is at your own risk.
10  *
11  * Permission to use or copy this software for any purpose is hereby granted
12  * without fee, provided the above notices are retained on all copies.
13  * Permission to modify the code and to distribute modified code is granted,
14  * provided the above notices are retained, and a notice that the code was
15  * modified is included with the above copyright notice.
16  *
17  */
18 
19 #if defined  (__SUNPPRO_CC)  && !defined (_STLP_NO_NEW_C_HEADERS)
20 #  include <time.h>
21 // For sunpro, it chokes if time.h is included through stat.h
22 #endif
23 
24 #include <fstream>
25 
26 #ifdef __CYGWIN__
27 #  define __int64 long long
28 #endif
29 
30 extern "C" {
31 // open/close/read/write
32 #include <sys/stat.h>           // For stat
33 #if !defined (_CRAY) && ! defined (__EMX__)
34 #  include <sys/mman.h>           // For mmap
35 #endif
36 
37 //  on HP-UX 11, this one contradicts with pthread.h on pthread_atfork, unless we unset this
38 #if defined (__hpux) && defined (__GNUC__)
39 #  undef _INCLUDE_POSIX1C_SOURCE
40 #endif
41 
42 #include <unistd.h>
43 #include <fcntl.h>
44 }
45 
46 #ifdef __APPLE__
47 #  include <sys/sysctl.h>
48 #endif
49 
50 const _STLP_fd INVALID_STLP_FD = -1;
51 
52 #ifndef O_ACCMODE
53 #  define O_ACCMODE (O_RDONLY|O_WRONLY|O_RDWR)
54 #endif
55 
56 // Compare with streamoff definition in stl/char_traits.h!
57 #if defined (_STLP_USE_DEFAULT_FILE_OFFSET) || \
58     (!defined(_LARGEFILE_SOURCE) && !defined (_LARGEFILE64_SOURCE))
59 #  define FSTAT fstat
60 #  define STAT  stat
61 #  define LSEEK lseek
62 #  define MMAP  mmap
63 #  define OPEN  open
64 #else
65 #  define FSTAT fstat64
66 #  define STAT  stat64
67 #  define LSEEK lseek64
68 #  define MMAP  mmap64
69 #  define OPEN  open64
70 #endif
71 
72 #ifndef MAP_FAILED /* MMAP failure return code */
73 #  define MAP_FAILED -1
74 #endif
75 
76 _STLP_BEGIN_NAMESPACE
77 
flag_to_openmode(int mode)78 static ios_base::openmode flag_to_openmode(int mode)
79 {
80   ios_base::openmode ret = ios_base::__default_mode;
81 
82   switch ( mode & O_ACCMODE ) {
83     case O_RDONLY:
84       ret = ios_base::in;
85       break;
86     case O_WRONLY:
87       ret = ios_base::out;
88       break;
89     case O_RDWR:
90       ret = ios_base::in | ios_base::out;
91       break;
92   }
93 
94   if ( mode & O_APPEND )
95     ret |= ios_base::app;
96 
97   return ret;
98 }
99 
100 _STLP_MOVE_TO_PRIV_NAMESPACE
101 
102 // Helper functions for _Filebuf_base.
103 
__is_regular_file(_STLP_fd fd)104 static bool __is_regular_file(_STLP_fd fd) {
105   struct STAT buf;
106   return FSTAT(fd, &buf) == 0 && S_ISREG(buf.st_mode);
107 }
108 
109 // Number of characters in the file.
__file_size(_STLP_fd fd)110 static streamoff __file_size(_STLP_fd fd) {
111   streamoff ret = 0;
112 
113   struct STAT buf;
114   if (FSTAT(fd, &buf) == 0 && S_ISREG(buf.st_mode))
115     ret = buf.st_size > 0 ? buf.st_size : 0;
116 
117   return ret;
118 }
119 
120 _STLP_MOVE_TO_STD_NAMESPACE
121 
122 size_t _Filebuf_base::_M_page_size = 4096;
123 
_Filebuf_base()124 _Filebuf_base::_Filebuf_base()
125   : _M_file_id(INVALID_STLP_FD),
126     _M_openmode(0),
127     _M_is_open(false),
128     _M_should_close(false)
129 {}
130 
_S_initialize()131 void _Filebuf_base::_S_initialize()
132 {
133 #if defined (__APPLE__)
134   int mib[2];
135   size_t pagesize, len;
136   mib[0] = CTL_HW;
137   mib[1] = HW_PAGESIZE;
138   len = sizeof(pagesize);
139   sysctl(mib, 2, &pagesize, &len, NULL, 0);
140   _M_page_size = pagesize;
141 #elif defined (__DJGPP) && defined (_CRAY)
142   _M_page_size = BUFSIZ;
143 #else
144   _M_page_size = sysconf(_SC_PAGESIZE);
145 #endif
146 }
147 
148 // Return the size of the file.  This is a wrapper for stat.
149 // Returns zero if the size cannot be determined or is ill-defined.
_M_file_size()150 streamoff _Filebuf_base::_M_file_size()
151 {
152   return _STLP_PRIV __file_size(_M_file_id);
153 }
154 
_M_open(const char * name,ios_base::openmode openmode,long permission)155 bool _Filebuf_base::_M_open(const char* name, ios_base::openmode openmode,
156                             long permission)
157 {
158   _STLP_fd file_no;
159 
160   if (_M_is_open)
161     return false;
162 
163   int flags = 0;
164 
165   // Unix makes no distinction between text and binary files.
166   switch ( openmode & (~ios_base::ate & ~ios_base::binary) ) {
167     case ios_base::out:
168     case ios_base::out | ios_base::trunc:
169       flags = O_WRONLY | O_CREAT | O_TRUNC;
170       break;
171     case ios_base::app:
172     case ios_base::out | ios_base::app:
173       flags = O_WRONLY | O_CREAT | O_APPEND;
174       break;
175     case ios_base::in:
176       flags = O_RDONLY;
177       permission = 0;             // Irrelevant unless we're writing.
178       break;
179     case ios_base::in | ios_base::out:
180       flags = O_RDWR;
181       break;
182     case ios_base::in | ios_base::out | ios_base::trunc:
183       flags = O_RDWR | O_CREAT | O_TRUNC;
184       break;
185     case ios_base::in | ios_base::app:
186     case ios_base::in | ios_base::out | ios_base::app:
187       flags = O_RDWR | O_CREAT | O_APPEND;
188       break;
189     default:                      // The above are the only combinations of
190       return false;               // flags allowed by the C++ standard.
191   }
192 
193   file_no = OPEN(name, flags, permission);
194 
195   if (file_no < 0)
196     return false;
197 
198   _M_is_open = true;
199 
200   if ((openmode & (ios_base::ate | ios_base::app)) && (LSEEK(file_no, 0, SEEK_END) == -1)) {
201     _M_is_open = false;
202   }
203 
204   _M_file_id = file_no;
205   _M_should_close = _M_is_open;
206   _M_openmode = openmode;
207 
208   if (_M_is_open)
209     _M_regular_file = _STLP_PRIV __is_regular_file(_M_file_id);
210 
211   return (_M_is_open != 0);
212 }
213 
214 
_M_open(const char * name,ios_base::openmode openmode)215 bool _Filebuf_base::_M_open(const char* name, ios_base::openmode openmode)
216 {
217   // This doesn't really grant everyone in the world read/write
218   // access.  On Unix, file-creation system calls always clear
219   // bits that are set in the umask from the permissions flag.
220   return this->_M_open(name, openmode, S_IRUSR | S_IWUSR | S_IRGRP |
221                                        S_IWGRP | S_IROTH | S_IWOTH);
222 }
223 
224 // Associated the filebuf with a file descriptor pointing to an already-
225 // open file.  Mode is set to be consistent with the way that the file
226 // was opened.
_M_open(int file_no,ios_base::openmode)227 bool _Filebuf_base::_M_open(int file_no, ios_base::openmode)
228 {
229   if (_M_is_open || file_no < 0)
230     return false;
231 
232   int mode = fcntl(file_no, F_GETFL);
233 
234   if (mode == -1)
235     return false;
236 
237   _M_openmode = flag_to_openmode(mode);
238   _M_file_id = file_no;
239 
240   _M_is_open = true;
241   _M_should_close = false;
242   _M_regular_file = _STLP_PRIV __is_regular_file(_M_file_id);
243   return true;
244 }
245 
_M_close()246 bool _Filebuf_base::_M_close()
247 {
248   if (!_M_is_open)
249     return false;
250 
251   bool ok = _M_should_close ? (close(_M_file_id) == 0) : true;
252 
253   _M_is_open = _M_should_close = false;
254   _M_openmode = 0;
255   return ok;
256 }
257 
258 // Read up to n characters into a buffer.  Return value is number of
259 // characters read.
_M_read(char * buf,ptrdiff_t n)260 ptrdiff_t _Filebuf_base::_M_read(char* buf, ptrdiff_t n)
261 {
262   return read(_M_file_id, buf, n);
263 }
264 
265 // Write n characters from a buffer.  Return value: true if we managed
266 // to write the entire buffer, false if we didn't.
_M_write(char * buf,ptrdiff_t n)267 bool _Filebuf_base::_M_write(char* buf, ptrdiff_t n)
268 {
269   for (;;) {
270     ptrdiff_t written = write(_M_file_id, buf, n);
271 
272     if (n == written) {
273       return true;
274     }
275 
276     if (written > 0 && written < n) {
277       n -= written;
278       buf += written;
279     } else {
280       return false;
281     }
282   }
283 }
284 
285 // Wrapper for lseek or the like.
_M_seek(streamoff offset,ios_base::seekdir dir)286 streamoff _Filebuf_base::_M_seek(streamoff offset, ios_base::seekdir dir)
287 {
288   int whence;
289 
290   switch ( dir ) {
291     case ios_base::beg:
292       if (offset < 0 /* || offset > _M_file_size() */ )
293         return streamoff(-1);
294       whence = SEEK_SET;
295       break;
296     case ios_base::cur:
297       whence = SEEK_CUR;
298       break;
299     case ios_base::end:
300       if (/* offset > 0 || */  -offset > _M_file_size() )
301         return streamoff(-1);
302       whence = SEEK_END;
303       break;
304     default:
305       return streamoff(-1);
306   }
307 
308   return LSEEK(_M_file_id, offset, whence);
309 }
310 
311 // Attempts to memory-map len bytes of the current file, starting
312 // at position offset.  Precondition: offset is a multiple of the
313 // page size.  Postcondition: return value is a null pointer if the
314 // memory mapping failed.  Otherwise the return value is a pointer to
315 // the memory-mapped file and the file position is set to offset.
_M_mmap(streamoff offset,streamoff len)316 void* _Filebuf_base::_M_mmap(streamoff offset, streamoff len)
317 {
318   void* base;
319 #if !defined (__DJGPP) && !defined (_CRAY)
320   base = MMAP(0, len, PROT_READ, MAP_PRIVATE, _M_file_id, offset);
321   if (base != (void*)MAP_FAILED) {
322     if (LSEEK(_M_file_id, offset + len, SEEK_SET) < 0) {
323       this->_M_unmap(base, len);
324       base = 0;
325     }
326   } else
327     base =0;
328 #else
329   _STLP_MARK_PARAMETER_AS_UNUSED(&offset)
330   _STLP_MARK_PARAMETER_AS_UNUSED(&len)
331   base = 0;
332 #endif
333   return base;
334 }
335 
_M_unmap(void * base,streamoff len)336 void _Filebuf_base::_M_unmap(void* base, streamoff len)
337 {
338   // precondition : there is a valid mapping at the moment
339 #if !defined (__DJGPP) && !defined (_CRAY)
340   munmap((char*)base, len);
341 #else
342   _STLP_MARK_PARAMETER_AS_UNUSED(&len)
343   _STLP_MARK_PARAMETER_AS_UNUSED(base)
344 #endif
345 }
346 
347 _STLP_END_NAMESPACE
348