00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033
00034
00035
00036
00037
00038
00039
00040
00041
00042 #include <vpr/vprConfig.h>
00043
00044 #include <stdio.h>
00045 #include <string.h>
00046 #include <unistd.h>
00047 #include <sys/types.h>
00048 #include <sys/stat.h>
00049 #include <fcntl.h>
00050
00051
00052 #ifdef VPR_OS_Solaris
00053 # define BSD_COMP
00054 #endif
00055
00056 #include <sys/ioctl.h>
00057 #include <sys/time.h>
00058 #include <unistd.h>
00059 #include <errno.h>
00060
00061 #ifdef HAVE_SYS_FILE_H
00062 # include <sys/file.h>
00063 #endif
00064
00065 #include <vpr/Util/Debug.h>
00066 #include <vpr/md/POSIX/IO/FileHandleImplUNIX.h>
00067
00068
00069 namespace vpr
00070 {
00071
00072
00073
00074
00075
00076
00077
00078
00079 FileHandleImplUNIX::FileHandleImplUNIX()
00080 : mOpen(false)
00081 , mOpenBlocking(true)
00082 , mBlocking(true)
00083 , mFdesc(-1)
00084 , mOpenMode(O_RDWR)
00085 {
00086 ;
00087 }
00088
00089
00090
00091 FileHandleImplUNIX::FileHandleImplUNIX(const std::string& file_name)
00092 : mName(file_name)
00093 , mOpen(false)
00094 , mOpenBlocking(true)
00095 , mBlocking(true)
00096 , mFdesc(-1)
00097 , mOpenMode(O_RDWR)
00098 {
00099 ;
00100 }
00101
00102
00103 FileHandleImplUNIX::~FileHandleImplUNIX()
00104 {
00105 if ( mOpen )
00106 {
00107 close();
00108 }
00109 }
00110
00111
00112 vpr::ReturnStatus FileHandleImplUNIX::open()
00113 {
00114 vpr::ReturnStatus status;
00115
00116 int open_flags(mOpenMode);
00117
00118 if ( ! mOpenBlocking )
00119 {
00120 open_flags |= O_NONBLOCK;
00121 }
00122
00123 mFdesc = ::open(mName.c_str(), open_flags);
00124
00125
00126
00127 if ( mFdesc == -1 )
00128 {
00129
00130 if ( errno == EWOULDBLOCK && ! mOpenBlocking )
00131 {
00132 status.setCode(vpr::ReturnStatus::WouldBlock);
00133 mOpen = true;
00134 }
00135
00136 else
00137 {
00138 vprDEBUG(vprDBG_ERROR, vprDBG_CRITICAL_LVL)
00139 << "[vpr::FileHandleImplUNIX::open()] Could not open " << mName
00140 << ": " << strerror(errno) << std::endl << vprDEBUG_FLUSH;
00141 status.setCode(ReturnStatus::Fail);
00142 mOpen = false;
00143 }
00144 }
00145
00146 else
00147 {
00148 mOpen = true;
00149 mBlocking = mOpenBlocking;
00150 }
00151
00152 return status;
00153 }
00154
00155
00156 vpr::ReturnStatus FileHandleImplUNIX::close()
00157 {
00158 vpr::ReturnStatus status;
00159
00160 vprDEBUG(vprDBG_ALL, vprDBG_VERB_LVL)
00161 << "[vpr::FileHandleImplUNIX::close()] Closing file descriptor "
00162 << mFdesc << std::endl << vprDEBUG_FLUSH;
00163
00164 if ( ::close(mFdesc) == -1 )
00165 {
00166 vprDEBUG(vprDBG_ALL, vprDBG_WARNING_LVL)
00167 << "[vpr::FileHandleImplUNIX::close()] Could not close " << mName
00168 << ": " << strerror(errno) << std::endl << vprDEBUG_FLUSH;
00169 status.setCode(ReturnStatus::Fail);
00170 }
00171 else
00172 {
00173 mFdesc = -1;
00174 mOpen = false;
00175 }
00176
00177 return status;
00178 }
00179
00180
00181 vpr::ReturnStatus FileHandleImplUNIX::setBlocking(bool blocking)
00182 {
00183 vpr::ReturnStatus retval;
00184
00185 if ( ! mOpen )
00186 {
00187 mOpenBlocking = blocking;
00188 }
00189 else
00190 {
00191 int cur_flags, new_flags;
00192
00193
00194 cur_flags = getFlags();
00195
00196 if ( blocking )
00197 {
00198 #ifdef _SGI_SOURCE
00199
00200
00201 new_flags = cur_flags & ~(FNONBLK | FNDELAY);
00202 #else
00203
00204
00205 new_flags = cur_flags & ~(O_NONBLOCK | O_NDELAY);
00206 #endif
00207 }
00208 else
00209 {
00210 #ifdef _SVR4_SOURCE
00211
00212
00213 new_flags = cur_flags | FNONBLK;
00214 #else
00215
00216
00217 new_flags = cur_flags | O_NONBLOCK;
00218 #endif
00219 }
00220
00221
00222 if ( setFlags(new_flags) == -1 )
00223 {
00224 vprDEBUG(vprDBG_ERROR, vprDBG_CRITICAL_LVL)
00225 << "[vpr::FileHandleImplUNIX::setBlocking()] Failed to set "
00226 << (blocking ? "blocking" : "non-blocking") << " state on "
00227 << mName << ": " << strerror(errno) << std::endl << vprDEBUG_FLUSH;
00228 retval.setCode(ReturnStatus::Fail);
00229 }
00230 else
00231 {
00232 mBlocking = blocking;
00233 }
00234 }
00235
00236 return retval;
00237 }
00238
00239 vpr::IOSys::Handle FileHandleImplUNIX::getHandle() const
00240 {
00241 #ifdef VPR_USE_NSPR
00242 vprDEBUG(vprDBG_ALL, vprDBG_CRITICAL_LVL)
00243 << "ERROR: Cannot get handle for UNIX file descriptor with NSPR!\n";
00244 return vpr::IOSys::NullHandle;
00245 #else
00246 return mFdesc;
00247 #endif
00248 }
00249
00250 void FileHandleImplUNIX::setOpenReadOnly()
00251 {
00252 mOpenMode = O_RDONLY;
00253 }
00254
00255 void FileHandleImplUNIX::setOpenWriteOnly()
00256 {
00257 mOpenMode = O_WRONLY;
00258 }
00259
00260 void FileHandleImplUNIX::setOpenReadWrite()
00261 {
00262 mOpenMode = O_RDWR;
00263 }
00264
00265
00266 vpr::ReturnStatus FileHandleImplUNIX::setAppend(bool append)
00267 {
00268 int cur_flags, new_flags, retval;
00269 vpr::ReturnStatus status;
00270
00271
00272 cur_flags = getFlags();
00273
00274
00275 if ( append )
00276 {
00277 new_flags = cur_flags | O_APPEND;
00278 }
00279
00280 else
00281 {
00282 new_flags = cur_flags & ~O_APPEND;
00283 }
00284
00285
00286 retval = setFlags(new_flags);
00287
00288 if ( retval == -1 )
00289 {
00290 vprDEBUG(vprDBG_ERROR, vprDBG_CRITICAL_LVL)
00291 << "[vpr::FileHandleImplUNIX::setAppend()] Failed to "
00292 << (append ? "enable" : "disable") << " append mode on "
00293 << mName << ": " << strerror(errno) << std::endl << vprDEBUG_FLUSH;
00294 status.setCode(ReturnStatus::Fail);
00295 }
00296
00297 return status;
00298 }
00299
00300
00301 vpr::ReturnStatus FileHandleImplUNIX::setSynchronousWrite(bool sync)
00302 {
00303 vpr::ReturnStatus status;
00304 #if ! defined(_POSIX_SOURCE) && defined(O_SYNC) && defined(O_ASYNC)
00305 int cur_flags, new_flags, retval;
00306
00307
00308 cur_flags = getFlags();
00309
00310
00311 if ( sync )
00312 {
00313 new_flags = cur_flags | O_SYNC;
00314 }
00315
00316 else
00317 {
00318 new_flags = cur_flags | O_ASYNC;
00319 }
00320
00321
00322 retval = setFlags(new_flags);
00323
00324 if ( retval == -1 )
00325 {
00326 vprDEBUG(vprDBG_ERROR, vprDBG_CRITICAL_LVL)
00327 << "[vpr::FileHandleImplUNIX::setSynchronousWrite()] Failed to enable "
00328 << (sync ? "synchronous" : "asynchronous") << " writes on "
00329 << mName << ": " << strerror(errno) << std::endl << vprDEBUG_FLUSH;
00330 status.setCode(vpr::ReturnStatus::Fail);
00331 }
00332 #else
00333 vprDEBUG(vprDBG_ALL, vprDBG_CRITICAL_LVL)
00334 << "[vpr::FileHandleImplUNIX::setSynchronousWrite()] Cannot enable "
00335 << (sync ? "synchronous" : "asynchronous")
00336 << " writes on this platform!\n" << vprDEBUG_FLUSH;
00337 status.setCode(vpr::ReturnStatus::Fail);
00338 #endif
00339
00340 return status;
00341 }
00342
00343 bool FileHandleImplUNIX::isReadOnly() const
00344 {
00345 return (mOpenMode == O_RDONLY);
00346 }
00347
00348 bool FileHandleImplUNIX::isWriteOnly() const
00349 {
00350 return (mOpenMode == O_WRONLY);
00351 }
00352
00353 bool FileHandleImplUNIX::isReadWrite() const
00354 {
00355 return (mOpenMode == O_RDWR);
00356 }
00357
00358 vpr::ReturnStatus FileHandleImplUNIX::getReadBufferSize(vpr::Int32& buffer) const
00359 {
00360 vpr::ReturnStatus status;
00361
00362 if ( ioctl(mFdesc, FIONREAD, &buffer) == -1 )
00363 {
00364 status.setCode(vpr::ReturnStatus::Fail);
00365 }
00366
00367 return status;
00368 }
00369
00370
00371
00372
00373
00374
00375
00376 vpr::ReturnStatus FileHandleImplUNIX::read_i(void* buffer,
00377 const vpr::Uint32 length,
00378 vpr::Uint32& bytesRead,
00379 const vpr::Interval timeout)
00380 {
00381 vpr::ReturnStatus status;
00382
00383 status = isReadable(timeout);
00384
00385 if ( status.success() )
00386 {
00387 ssize_t bytes;
00388
00389 bytes = ::read(mFdesc, buffer, length);
00390
00391
00392 if ( bytes < 0 )
00393 {
00394 bytesRead = 0;
00395
00396 if ( errno == EAGAIN && ! mBlocking )
00397 {
00398 status.setCode(vpr::ReturnStatus::WouldBlock);
00399 }
00400
00401
00402 if ( ! (errno == EAGAIN && ! mBlocking) )
00403 {
00404 vprDEBUG(vprDBG_ERROR, vprDBG_CRITICAL_LVL)
00405 << "[vpr::FileHandleImplUNIX::read_i()] Error reading from "
00406 << mName << ": " << strerror(errno) << std::endl
00407 << vprDEBUG_FLUSH;
00408 status.setCode(ReturnStatus::Fail);
00409 }
00410 }
00411
00412
00413 else if ( bytes == 0 && errno != 0 )
00414 {
00415
00416 status.setCode(ReturnStatus::Fail);
00417 bytesRead = 0;
00418
00419 vprDEBUG(vprDBG_ERROR, vprDBG_WARNING_LVL)
00420 << "[vpr::FileHandleImplUNIX::read_i()] Nothing read from "
00421 << mName << ": " << strerror(errno) << std::endl << vprDEBUG_FLUSH;
00422 }
00423 else
00424 {
00425 bytesRead = bytes;
00426 }
00427 }
00428 else
00429 {
00430 bytesRead = 0;
00431 }
00432
00433 return status;
00434 }
00435
00436
00437
00438
00439 vpr::ReturnStatus FileHandleImplUNIX::readn_i(void* buffer,
00440 const vpr::Uint32 buffer_size,
00441 vpr::Uint32& bytesRead,
00442 const vpr::Interval timeout)
00443 {
00444 size_t bytes_left;
00445 ssize_t bytes;
00446 vpr::ReturnStatus status;
00447
00448 if ( vpr::Interval::NoTimeout != timeout )
00449 {
00450 vprDEBUG(vprDBG_ALL,vprDBG_WARNING_LVL) << "Timeout not supported\n"
00451 << vprDEBUG_FLUSH;
00452 }
00453
00454 bytesRead = 0;
00455 bytes_left = buffer_size;
00456
00457 while ( bytes_left > 0 )
00458 {
00459 vprDEBUG(vprDBG_ALL, vprDBG_HVERB_LVL)
00460 << "[vpr::FileHandleImplUNIX::readn_i()] Reading " << bytes_left
00461 << " bytes from file handle " << mFdesc << std::endl
00462 << vprDEBUG_FLUSH;
00463
00464 bytes = ::read(mFdesc, buffer, bytes_left);
00465
00466 vprDEBUG_NEXT(vprDBG_ALL, vprDBG_HVERB_LVL)
00467 << "Read " << bytes << " bytes from file handle " << mFdesc
00468 << std::endl << vprDEBUG_FLUSH;
00469
00470
00471 if ( bytes < 0 )
00472 {
00473
00474 if ( errno == EINTR )
00475 {
00476 continue;
00477 }
00478
00479 else
00480 {
00481 status.setCode(ReturnStatus::Fail);
00482 bytesRead = 0;
00483 return status;
00484 }
00485 }
00486
00487
00488
00489 else if ( bytes == 0 )
00490 {
00491 vprDEBUG(vprDBG_ALL, vprDBG_HVERB_LVL)
00492 << "[vpr::FileHandleImplUNIX::readn_i()] Read EOF with "
00493 << bytes_left << " bytes left to read from file handle "
00494 << mFdesc << " and " << bytesRead << " bytes read in total."
00495 << std::endl << vprDEBUG_FLUSH;
00496
00497 return status;
00498 }
00499 else
00500 {
00501 buffer = (void*) ((char*) buffer + bytes);
00502 bytes_left -= bytes;
00503 bytesRead += bytes;
00504 }
00505 }
00506
00507 return status;
00508 }
00509
00510
00511 vpr::ReturnStatus FileHandleImplUNIX::write_i(const void* buffer,
00512 const vpr::Uint32 length,
00513 vpr::Uint32& bytesWritten,
00514 const vpr::Interval timeout)
00515 {
00516 vpr::ReturnStatus status;
00517
00518 status = isWriteable(timeout);
00519
00520 if ( status.success() )
00521 {
00522 ssize_t bytes;
00523
00524 bytes = ::write(mFdesc, buffer, length);
00525
00526 if ( bytes <= 0 )
00527 {
00528 bytesWritten = 0;
00529
00530 if ( errno == EAGAIN && ! mBlocking )
00531 {
00532 status.setCode(vpr::ReturnStatus::WouldBlock);
00533 }
00534 else
00535 {
00536 vprDEBUG(vprDBG_ERROR, vprDBG_CRITICAL_LVL)
00537 << "[vpr::FileHandleImplUNIX::write_i()] Error writing to "
00538 << mName << ": " << strerror(errno) << std::endl
00539 << vprDEBUG_FLUSH;
00540 status.setCode(ReturnStatus::Fail);
00541 }
00542 }
00543 else
00544 {
00545 bytesWritten = bytes;
00546 }
00547 }
00548
00549 return status;
00550 }
00551
00552 vpr::Uint32 FileHandleImplUNIX::availableBytes() const
00553 {
00554 int result;
00555
00556 if ( ioctl(mFdesc, FIONREAD, &result) < 0 )
00557 {
00558 result = 0;
00559 }
00560
00561 return result;
00562 }
00563
00564
00565 int FileHandleImplUNIX::getFlags() const
00566 {
00567 return fcntl(mFdesc, F_GETFL, 0);
00568 }
00569
00570
00571 int FileHandleImplUNIX::setFlags(const int flags)
00572 {
00573 return fcntl(mFdesc, F_SETFL, flags);
00574 }
00575
00576 vpr::ReturnStatus FileHandleImplUNIX::isReadable(const vpr::Interval timeout) const
00577 {
00578 vpr::ReturnStatus ready;
00579 fd_set read_set;
00580 int num_events;
00581 struct timeval timeout_obj;
00582
00583 if ( mFdesc == -1 )
00584 {
00585 ready.setCode(vpr::ReturnStatus::Fail);
00586 }
00587 else
00588 {
00589 if ( timeout == vpr::Interval::NoWait )
00590 {
00591 timeout_obj.tv_sec = 0;
00592 timeout_obj.tv_usec = 0;
00593 }
00594 else
00595 {
00596 if ( timeout.msec() >= 1000 )
00597 {
00598 timeout_obj.tv_sec = timeout.msec() / 1000;
00599 timeout_obj.tv_usec = (timeout.msec() % 1000) * 1000000;
00600 }
00601 else
00602 {
00603 timeout_obj.tv_sec = 0;
00604 timeout_obj.tv_usec = timeout.msec() * 1000;
00605 }
00606 }
00607
00608 FD_ZERO(&read_set);
00609 FD_SET(mFdesc, &read_set);
00610
00611 num_events = select(mFdesc + 1, &read_set, NULL, NULL,
00612 (timeout != vpr::Interval::NoTimeout) ? &timeout_obj :
00613 NULL);
00614
00615 if ( num_events == 0 )
00616 {
00617 if ( ! FD_ISSET(mFdesc, &read_set) )
00618 {
00619 ready.setCode(vpr::ReturnStatus::Timeout);
00620 }
00621 }
00622 else if ( num_events < 0 )
00623 {
00624 ready.setCode(vpr::ReturnStatus::Fail);
00625 }
00626 }
00627
00628 return ready;
00629 }
00630
00631 vpr::ReturnStatus FileHandleImplUNIX::isWriteable(const vpr::Interval timeout) const
00632 {
00633 vpr::ReturnStatus ready;
00634 fd_set write_set;
00635 int num_events;
00636 struct timeval timeout_obj;
00637
00638 if ( mFdesc == -1 )
00639 {
00640 ready.setCode(vpr::ReturnStatus::Fail);
00641 }
00642 else
00643 {
00644 if ( timeout == vpr::Interval::NoWait )
00645 {
00646 timeout_obj.tv_sec = 0;
00647 timeout_obj.tv_usec = 0;
00648 }
00649 else
00650 {
00651 if ( timeout.msec() >= 1000 )
00652 {
00653 timeout_obj.tv_sec = timeout.msec() / 1000;
00654 timeout_obj.tv_usec = (timeout.msec() % 1000) * 1000000;
00655 }
00656 else
00657 {
00658 timeout_obj.tv_sec = 0;
00659 timeout_obj.tv_usec = timeout.msec() * 1000;
00660 }
00661 }
00662
00663 FD_ZERO(&write_set);
00664 FD_SET(mFdesc, &write_set);
00665
00666 num_events = select(mFdesc + 1, NULL, &write_set, NULL,
00667 (timeout != vpr::Interval::NoTimeout) ? &timeout_obj :
00668 NULL);
00669
00670 if ( num_events == 0 )
00671 {
00672 if ( ! FD_ISSET(mFdesc, &write_set) )
00673 {
00674 ready.setCode(vpr::ReturnStatus::Timeout);
00675 }
00676 }
00677 else if ( num_events < 0 )
00678 {
00679 ready.setCode(vpr::ReturnStatus::Fail);
00680 }
00681 }
00682
00683 return ready;
00684 }
00685
00686 }