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