|
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 |
|
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 |
|
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. |
|
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 |
|
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 |
|
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. |
|
150 streamoff _Filebuf_base::_M_file_size() |
|
151 { |
|
152 return _STLP_PRIV __file_size(_M_file_id); |
|
153 } |
|
154 |
|
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 |
|
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. |
|
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 |
|
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. |
|
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. |
|
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. |
|
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. |
|
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 |
|
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 |