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