Home | History | Annotate | Download | only in details
      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
    348