piobase.cxx (8167B)
1 /* 2 * 3 * C++ Portable Types Library (PTypes) 4 * Version 2.1.1 Released 27-Jun-2007 5 * 6 * Copyright (C) 2001-2007 Hovik Melikyan 7 * 8 * http://www.melikyan.com/ptypes/ 9 * 10 */ 11 12 #include <errno.h> 13 #include <limits.h> 14 15 #ifdef WIN32 16 # include <windows.h> 17 #else 18 # include <signal.h> 19 # include <unistd.h> 20 #endif 21 22 #include "pstreams.h" 23 24 25 namespace ptypes { 26 27 28 /* 29 30 Known UNIX error codes: 31 32 EPERM 1 Not owner 33 ENOENT 2 No such file or directory 34 ESRCH 3 No such process 35 EINTR 4 Interrupted system call 36 EIO 5 I/O error 37 ENXIO 6 No such device or address 38 E2BIG 7 Argument list too long 39 ENOEXEC 8 Exec format error 40 EBADF 9 Bad file number 41 ECHILD 10 No spawned processes 42 EAGAIN 11 No more processes; not enough memory; maximum nesting level reached 43 ENOMEM 12 Not enough memory 44 EACCES 13 Permission denied 45 EFAULT 14 Bad address 46 ENOTBLK 15 Block device required 47 EBUSY 16 Mount device busy 48 EEXIST 17 File exists 49 EXDEV 18 Cross-device link 50 ENODEV 19 No such device 51 ENOTDIR 20 Not a directory 52 EISDIR 21 Is a directory 53 EINVAL 22 Invalid argument 54 ENFILE 23 File table overflow 55 EMFILE 24 Too many open files 56 ENOTTY 25 Not a teletype 57 ETXTBSY 26 Text file busy 58 EFBIG 27 File too large 59 ENOSPC 28 No space left on device 60 ESPIPE 29 Illegal seek 61 EROFS 30 Read-only file system 62 EMLINK 31 Too many links 63 EPIPE 32 Broken pipe 64 EDOM 33 Math argument 65 ERANGE 34 Result too large 66 EUCLEAN 35 File system needs cleaning 67 EDEADLK 36 Resource deadlock would occur 68 EDEADLOCK 36 Resource deadlock would occur 69 70 */ 71 72 73 #ifndef WIN32 74 75 static class _io_init 76 { 77 public: 78 _io_init(); 79 } _io_init_inst; 80 81 82 _io_init::_io_init() 83 { 84 // We don't like broken pipes. PTypes will throw an exception instead. 85 signal(SIGPIPE, SIG_IGN); 86 } 87 88 #endif 89 90 91 92 int ptdecl unixerrno() 93 { 94 #ifdef WIN32 95 switch(GetLastError()) 96 { 97 case ERROR_FILE_NOT_FOUND: 98 case ERROR_PATH_NOT_FOUND: return ENOENT; 99 case ERROR_TOO_MANY_OPEN_FILES: return EMFILE; 100 case ERROR_ACCESS_DENIED: 101 case ERROR_SHARING_VIOLATION: return EACCES; 102 case ERROR_INVALID_HANDLE: return EBADF; 103 case ERROR_NOT_ENOUGH_MEMORY: 104 case ERROR_OUTOFMEMORY: return ENOMEM; 105 case ERROR_INVALID_DRIVE: return ENODEV; 106 case ERROR_WRITE_PROTECT: return EROFS; 107 case ERROR_FILE_EXISTS: return EEXIST; 108 case ERROR_BROKEN_PIPE: return EPIPE; 109 case ERROR_DISK_FULL: return ENOSPC; 110 case ERROR_SEEK_ON_DEVICE: return ESPIPE; 111 default: return EIO; 112 } 113 #else 114 return errno; 115 #endif 116 } 117 118 119 // 120 // This function gives error messages for most frequently occurring 121 // IO errors. If the function returns NULL a generic message 122 // can be given, e.g. "I/O error". See also iobase::get_errormsg() 123 // 124 125 const char* ptdecl unixerrmsg(int code) 126 { 127 switch(code) 128 { 129 case EBADF: return "Invalid file descriptor"; 130 case ESPIPE: return "Can not seek on this device"; 131 case ENOENT: return "No such file or directory"; 132 case EMFILE: return "Too many open files"; 133 case EACCES: return "Access denied"; 134 case ENOMEM: return "Not enough memory"; 135 case ENODEV: return "No such device"; 136 case EROFS: return "Read-only file system"; 137 case EEXIST: return "File already exists"; 138 case ENOSPC: return "Disk full"; 139 case EPIPE: return "Broken pipe"; 140 case EFBIG: return "File too large"; 141 default: return nil; 142 } 143 } 144 145 146 estream::estream(iobase* ierrstm, int icode, const char* imsg) 147 : exception(imsg), code(icode), errstm(ierrstm) {} 148 149 150 estream::estream(iobase* ierrstm, int icode, const string& imsg) 151 : exception(imsg), code(icode), errstm(ierrstm) {} 152 153 154 estream::~estream() {} 155 156 157 int defbufsize = 8192; 158 int stmbalance = 0; 159 160 iobase::iobase(int ibufsize) 161 : component(), active(false), cancelled(false), eof(true), 162 handle(invhandle), abspos(0), bufsize(0), bufdata(nil), bufpos(0), bufend(0), 163 stmerrno(0), deferrormsg(), status(IO_CREATED), onstatus(nil) 164 { 165 if (ibufsize < 0) 166 bufsize = defbufsize; 167 else 168 bufsize = ibufsize; 169 } 170 171 172 iobase::~iobase() 173 { 174 } 175 176 177 void iobase::bufalloc() 178 { 179 if (bufdata != nil) 180 fatal(CRIT_FIRST + 13, "(ptypes internal) invalid buffer allocation"); 181 bufdata = (char*)memalloc(bufsize); 182 } 183 184 185 void iobase::buffree() 186 { 187 bufclear(); 188 memfree(bufdata); 189 bufdata = 0; 190 } 191 192 193 void iobase::chstat(int newstat) 194 { 195 status = newstat; 196 if (onstatus != nil) 197 (*onstatus)(this, newstat); 198 } 199 200 201 void iobase::errstminactive() 202 { 203 error(EIO, "Stream inactive"); 204 } 205 206 207 void iobase::errbufrequired() 208 { 209 fatal(CRIT_FIRST + 11, "Internal: buffer required"); 210 } 211 212 213 int iobase::convertoffset(large offs) 214 { 215 if (offs < 0 || offs > INT_MAX) 216 error(EFBIG, "File offset value too large"); 217 return (int)offs; 218 } 219 220 221 void iobase::open() 222 { 223 cancel(); 224 chstat(IO_OPENING); 225 abspos = 0; 226 cancelled = false; 227 eof = false; 228 stmerrno = 0; 229 clear(deferrormsg); 230 active = true; 231 stmbalance++; 232 bufalloc(); 233 doopen(); 234 chstat(IO_OPENED); 235 } 236 237 238 void iobase::close() 239 { 240 if (!active) 241 return; 242 stmbalance--; 243 try 244 { 245 if (bufdata != 0 && !cancelled) 246 flush(); 247 doclose(); 248 } 249 catch(estream* e) 250 { 251 delete e; 252 } 253 buffree(); 254 active = false; 255 eof = true; 256 chstat(IO_CLOSED); 257 } 258 259 260 void iobase::cancel() 261 { 262 cancelled = true; 263 close(); 264 } 265 266 267 large iobase::seekx(large newpos, ioseekmode mode) 268 { 269 if (!active) 270 errstminactive(); 271 flush(); 272 large ret = doseek(newpos, mode); 273 if (ret < 0) 274 error(ESPIPE, "Seek failed"); 275 bufclear(); 276 eof = false; 277 abspos = ret; 278 return ret; 279 } 280 281 282 void iobase::flush() 283 { 284 } 285 286 287 large iobase::doseek(large newpos, ioseekmode mode) 288 { 289 if (handle == invhandle) 290 { 291 error(ESPIPE, "Can't seek on this device"); 292 return -1; 293 } 294 #ifdef WIN32 295 static int wmode[3] = {FILE_BEGIN, FILE_CURRENT, FILE_END}; 296 LARGE_INTEGER li; 297 li.QuadPart = newpos; 298 li.LowPart = SetFilePointer(HANDLE(handle), li.LowPart, &li.HighPart, wmode[mode]); 299 if (li.LowPart == INVALID_SET_FILE_POINTER && GetLastError() != NO_ERROR) 300 return -1; 301 return li.QuadPart; 302 #else 303 static int umode[3] = {SEEK_SET, SEEK_CUR, SEEK_END}; 304 return lseek(handle, newpos, umode[mode]); 305 #endif 306 } 307 308 309 void iobase::doclose() 310 { 311 #ifdef WIN32 312 CloseHandle(HANDLE(pexchange(&handle, invhandle))); 313 #else 314 ::close(pexchange(&handle, invhandle)); 315 #endif 316 } 317 318 319 void iobase::set_active(bool newval) 320 { 321 if (newval != active) 322 { 323 if (newval) 324 open(); 325 else 326 close(); 327 } 328 } 329 330 331 void iobase::set_bufsize(int newval) 332 { 333 if (active) 334 fatal(CRIT_FIRST + 12, "Cannot change buffer size while stream is active"); 335 if (newval < 0) 336 bufsize = defbufsize; 337 else 338 bufsize = newval; 339 } 340 341 342 string iobase::get_errstmname() 343 { 344 return get_streamname(); 345 } 346 347 348 const char* iobase::uerrmsg(int code) 349 { 350 return unixerrmsg(code); 351 } 352 353 354 int iobase::uerrno() 355 { 356 return unixerrno(); 357 } 358 359 360 string iobase::get_errormsg() 361 { 362 string s = uerrmsg(stmerrno); 363 if (isempty(s)) 364 s = deferrormsg; 365 if (pos('[', s) >= 0 && *(pconst(s) + length(s) - 1) == ']') 366 return s; 367 string e = get_errstmname(); 368 if (isempty(e)) 369 return s; 370 return s + " [" + e + ']'; 371 } 372 373 374 #ifdef _MSC_VER 375 // disable "unreachable code" warning for throw (known compiler bug) 376 # pragma warning (disable: 4702) 377 #endif 378 379 void iobase::error(int code, const char* defmsg) 380 { 381 eof = true; 382 stmerrno = code; 383 deferrormsg = defmsg; 384 throw new estream(this, code, get_errormsg()); 385 } 386 387 388 }