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#include <cstdio>
31#if !defined(__ISCPP__)
32extern "C" {
33#  include <sys/stat.h>
34}
35#endif
36
37#if defined( __MSL__ )
38#  include <unix.h>
39#endif
40
41#if defined(__ISCPP__)
42#  include <c_locale_is/filestat.h>
43#endif
44
45#if defined(__BEOS__) && defined(__INTEL__)
46#  include <fcntl.h>
47#  include <sys/stat.h>         // For _fstat
48#endif
49
50#if defined (_STLP_MSVC) || defined (__MINGW32__)
51#  include <fcntl.h>
52#  define S_IREAD _S_IREAD
53#  define S_IWRITE _S_IWRITE
54#  define S_IFREG _S_IFREG
55     // map permission masks
56#  ifndef S_IRUSR
57#    define S_IRUSR _S_IREAD
58#    define S_IWUSR _S_IWRITE
59#  endif
60#  ifndef S_IRGRP
61#    define S_IRGRP _S_IREAD
62#    define S_IWGRP _S_IWRITE
63#  endif
64#  ifndef S_IROTH
65#    define S_IROTH _S_IREAD
66#    define S_IWOTH _S_IWRITE
67#  endif
68
69#  ifndef O_RDONLY
70#    define O_RDONLY _O_RDONLY
71#    define O_WRONLY _O_WRONLY
72#    define O_RDWR   _O_RDWR
73#    define O_APPEND _O_APPEND
74#    define O_CREAT  _O_CREAT
75#    define O_TRUNC  _O_TRUNC
76#    define O_TEXT   _O_TEXT
77#    define O_BINARY _O_BINARY
78#  endif
79
80#  ifndef O_ACCMODE
81#    define O_ACCMODE (O_RDONLY|O_WRONLY|O_RDWR)
82#  endif
83#endif
84
85const _STLP_fd INVALID_STLP_FD = -1;
86
87
88#  ifdef __MSL__
89#    define _O_TEXT 0x0
90#    if !defined( O_TEXT )
91#      define O_TEXT _O_TEXT
92#    endif
93#    define _S_IFREG S_IFREG
94#    define S_IREAD        S_IRUSR
95#    define S_IWRITE       S_IWUSR
96#    define S_IEXEC        S_IXUSR
97#    define _S_IWRITE S_IWRITE
98#    define _S_IREAD S_IREAD
99#    define _open open
100#    define _close close
101#    define _read read
102#    define _write write
103#  endif
104
105_STLP_BEGIN_NAMESPACE
106
107// Compare with streamoff definition in stl/char_traits.h!
108
109#if defined (_STLP_USE_DEFAULT_FILE_OFFSET) || \
110    (!defined(_LARGEFILE_SOURCE) && !defined(_LARGEFILE64_SOURCE))
111#  define FOPEN fopen
112#  define FSEEK fseek
113#  define FSTAT fstat
114#  define STAT  stat
115#  define FTELL ftell
116#else
117#  define FOPEN fopen64
118#  define FSEEK fseeko64
119#  define FSTAT fstat64
120#  define STAT  stat64
121#  define FTELL ftello64
122#endif
123
124_STLP_MOVE_TO_PRIV_NAMESPACE
125
126// Helper functions for _Filebuf_base.
127
128static bool __is_regular_file(_STLP_fd fd) {
129  struct STAT buf;
130  return FSTAT(fd, &buf) == 0 && (buf.st_mode & S_IFREG) != 0 ;
131}
132
133// Number of characters in the file.
134static streamoff __file_size(_STLP_fd fd) {
135  streamoff ret = 0;
136
137  struct STAT buf;
138  if (FSTAT(fd, &buf) == 0 && (buf.st_mode & S_IFREG) != 0)
139    ret = buf.st_size > 0 ? buf.st_size : 0;
140
141  return ret;
142}
143
144_STLP_MOVE_TO_STD_NAMESPACE
145
146// All version of Unix have mmap and lseek system calls.  Some also have
147// longer versions of those system calls to accommodate 64-bit offsets.
148// If we're on a Unix system, define some macros to encapsulate those
149// differences.
150
151size_t _Filebuf_base::_M_page_size = 4096;
152
153_Filebuf_base::_Filebuf_base()
154  : _M_file_id(INVALID_STLP_FD),
155    _M_openmode(0),
156    _M_is_open(false),
157    _M_should_close(false)
158{}
159
160void _Filebuf_base::_S_initialize()
161{
162
163}
164
165// Return the size of the file.  This is a wrapper for stat.
166// Returns zero if the size cannot be determined or is ill-defined.
167streamoff _Filebuf_base::_M_file_size()
168{
169  return _STLP_PRIV __file_size(_M_file_id);
170}
171
172bool _Filebuf_base::_M_open(const char* name, ios_base::openmode openmode,
173                            long permission)
174{
175  _STLP_fd file_no;
176
177  if (_M_is_open)
178    return false;
179
180  // use FILE-based i/o
181  const char* flags;
182
183  switch (openmode & (~ios_base::ate)) {
184    case ios_base::out:
185    case ios_base::out | ios_base::trunc:
186      flags = "w";
187      break;
188
189    case ios_base::out | ios_base::binary:
190    case ios_base::out | ios_base::trunc | ios_base::binary:
191      flags = "wb";
192      break;
193
194    case ios_base::out | ios_base::app:
195      flags = "a";
196      break;
197
198    case ios_base::out | ios_base::app | ios_base::binary:
199      flags = "ab";
200      break;
201
202    case ios_base::in:
203      flags = "r";
204      break;
205
206    case ios_base::in | ios_base::binary:
207      flags = "rb";
208      break;
209
210    case ios_base::in | ios_base::out:
211      flags = "r+";
212      break;
213
214    case ios_base::in | ios_base::out | ios_base::binary:
215      flags = "r+b";
216      break;
217
218    case ios_base::in | ios_base::out | ios_base::trunc:
219      flags = "w+";
220      break;
221
222    case ios_base::in | ios_base::out | ios_base::trunc | ios_base::binary:
223      flags = "w+b";
224      break;
225
226    default:                      // The above are the only combinations of
227      return false;               // flags allowed by the C++ standard.
228  }
229
230  // fbp : TODO : set permissions !
231  (void)permission; // currently unused    //*TY 02/26/2000 - added to suppress warning message
232  _M_file = FOPEN(name, flags);
233
234  if (_M_file) {
235    file_no = fileno(_M_file);
236  } else {
237    return false;
238  }
239
240  // unset buffering immediately
241  setbuf(_M_file, 0);
242
243  _M_is_open = true;
244
245  if (openmode & ios_base::ate) {
246    if (FSEEK(_M_file, 0, SEEK_END) != 0)
247      _M_is_open = false;
248  }
249
250  _M_file_id = file_no;
251  _M_should_close = _M_is_open;
252  _M_openmode = openmode;
253
254  if (_M_is_open)
255    _M_regular_file = _STLP_PRIV __is_regular_file(_M_file_id);
256
257  return (_M_is_open != 0);
258}
259
260
261bool _Filebuf_base::_M_open(const char* name, ios_base::openmode openmode)
262{
263  // This doesn't really grant everyone in the world read/write
264  // access.  On Unix, file-creation system calls always clear
265  // bits that are set in the umask from the permissions flag.
266  return this->_M_open(name, openmode, S_IRUSR | S_IWUSR | S_IRGRP |
267                                       S_IWGRP | S_IROTH | S_IWOTH);
268}
269
270// Associated the filebuf with a file descriptor pointing to an already-
271// open file.  Mode is set to be consistent with the way that the file
272// was opened.
273bool _Filebuf_base::_M_open( int file_no, ios_base::openmode )
274{
275  if (_M_is_open || file_no < 0)
276    return false;
277
278  struct STAT buf;
279  if (FSTAT(file_no, &buf) != 0)
280    return false;
281  int mode = buf.st_mode;
282
283  switch ( mode & (S_IWRITE | S_IREAD) ) {
284    case S_IREAD:
285      _M_openmode = ios_base::in;
286      break;
287    case S_IWRITE:
288      _M_openmode = ios_base::out;
289      break;
290    case (S_IWRITE | S_IREAD):
291      _M_openmode = ios_base::in | ios_base::out;
292      break;
293    default:
294      return false;
295  }
296  _M_file_id = file_no;
297  _M_is_open = true;
298  _M_should_close = false;
299  _M_regular_file = _STLP_PRIV __is_regular_file(_M_file_id);
300  return true;
301}
302
303bool _Filebuf_base::_M_close()
304{
305  if (!_M_is_open)
306    return false;
307
308  bool ok = _M_should_close ? (fclose(_M_file) == 0) : true;
309
310  _M_is_open = _M_should_close = false;
311  _M_openmode = 0;
312  return ok;
313}
314
315// Read up to n characters into a buffer.  Return value is number of
316// characters read.
317ptrdiff_t _Filebuf_base::_M_read(char* buf, ptrdiff_t n) {
318  return fread(buf, 1, n, _M_file);
319}
320
321// Write n characters from a buffer.  Return value: true if we managed
322// to write the entire buffer, false if we didn't.
323bool _Filebuf_base::_M_write(char* buf, ptrdiff_t n)
324{
325  for (;;) {
326    ptrdiff_t written = fwrite(buf, 1, n, _M_file);
327
328    if (n == written) {
329      return true;
330    }
331
332    if (written > 0 && written < n) {
333      n -= written;
334      buf += written;
335    } else {
336      return false;
337    }
338  }
339}
340
341// Wrapper for lseek or the like.
342streamoff _Filebuf_base::_M_seek(streamoff offset, ios_base::seekdir dir)
343{
344  int whence;
345
346  switch ( dir ) {
347    case ios_base::beg:
348      if (offset < 0 /* || offset > _M_file_size() */ )
349        return streamoff(-1);
350      whence = SEEK_SET;
351      break;
352    case ios_base::cur:
353      whence = SEEK_CUR;
354      break;
355    case ios_base::end:
356      if (/* offset > 0 || */  -offset > _M_file_size() )
357        return streamoff(-1);
358      whence = SEEK_END;
359      break;
360    default:
361      return streamoff(-1);
362  }
363
364  if ( FSEEK(_M_file, offset, whence) == 0 ) {
365    return FTELL(_M_file);
366  }
367
368  return streamoff(-1);
369}
370
371
372// Attempts to memory-map len bytes of the current file, starting
373// at position offset.  Precondition: offset is a multiple of the
374// page size.  Postcondition: return value is a null pointer if the
375// memory mapping failed.  Otherwise the return value is a pointer to
376// the memory-mapped file and the file position is set to offset.
377void *_Filebuf_base::_M_mmap(streamoff, streamoff )
378{
379  return 0;
380}
381
382void _Filebuf_base::_M_unmap(void*, streamoff)
383{
384  // precondition : there is a valid mapping at the moment
385}
386
387_STLP_END_NAMESPACE
388