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 #include "CeylanStandardFile.h"
00028
00029 #include "CeylanLogPlug.h"
00030 #include "CeylanOperators.h"
00031 #include "CeylanStandardFileSystemManager.h"
00032
00033
00034 #ifdef CEYLAN_USES_CONFIG_H
00035 #include "CeylanConfig.h"
00036 #endif // CEYLAN_USES_CONFIG_H
00037
00038
00039
00040
00041 extern "C"
00042 {
00043
00044
00045 #ifdef CEYLAN_USES_SYS_TYPES_H
00046 #include <sys/types.h>
00047 #endif // CEYLAN_USES_SYS_TYPES_H
00048
00049 #ifdef CEYLAN_USES_SYS_STAT_H
00050 #include <sys/stat.h>
00051 #endif // CEYLAN_USES_SYS_STAT_H
00052
00053 #ifdef CEYLAN_USES_FCNTL_H
00054 #include <fcntl.h>
00055 #endif // CEYLAN_USES_FCNTL_H
00056
00057 #ifdef CEYLAN_USES_UNISTD_H
00058 #include <unistd.h>
00059 #endif // CEYLAN_USES_UNISTD_H
00060
00061 }
00062
00063
00064
00065 #include <cerrno>
00066 #include <cstdio>
00067 #include <fstream>
00068
00069
00070
00071
00072
00073
00074
00075
00076
00077
00078
00079
00080
00081
00082
00083 using std::fstream ;
00084 using std::ifstream ;
00085
00086 using std::ios ;
00087 using std::ios_base ;
00088
00089 using std::string ;
00090
00091
00092 using namespace Ceylan ;
00093 using namespace Ceylan::System ;
00094 using namespace Ceylan::Log ;
00095
00096
00097
00098
00099
00100
00101
00102
00103
00104
00105
00106
00107
00108
00109
00110
00111
00112
00113
00114 #if CEYLAN_USES_FILE_DESCRIPTORS
00115
00116
00117 struct StandardFile::SystemSpecificPermissionFlag
00118 {
00119 mode_t _mode ;
00120
00121 } ;
00122
00123 #endif // CEYLAN_USES_FILE_DESCRIPTORS
00124
00125
00126
00127
00128
00138 #define CEYLAN_PREFERS_RDBUF_TO_DIRECT_FSTREAM 1
00139
00140
00141
00142 StandardFileException::StandardFileException( const string & reason ) :
00143 FileException( reason )
00144 {
00145
00146 }
00147
00148
00149
00150 StandardFileException::~StandardFileException() throw()
00151 {
00152
00153 }
00154
00155
00156
00157
00158
00159
00160
00161
00162 StandardFile::~StandardFile() throw()
00163 {
00164
00165 if ( isOpen() )
00166 {
00167
00168 try
00169 {
00170 close() ;
00171 }
00172 catch( const Stream::CloseException & e )
00173 {
00174 LogPlug::error( "StandardFile destructor: close failed: "
00175 + e.toString() ) ;
00176 }
00177
00178 }
00179
00180 }
00181
00182
00183
00184
00185
00186
00187
00188
00189
00190
00191
00192
00193 bool StandardFile::isOpen() const
00194 {
00195
00196 #if CEYLAN_ARCH_NINTENDO_DS
00197
00198 return false ;
00199
00200 #else // CEYLAN_ARCH_NINTENDO_DS
00201
00202
00203 #if CEYLAN_USES_FILE_DESCRIPTORS
00204
00205 return ( _fdes != 0 ) ;
00206
00207 #else // CEYLAN_USES_FILE_DESCRIPTORS
00208
00209 return ( _fstream.is_open() ) ;
00210
00211 #endif // CEYLAN_USES_FILE_DESCRIPTORS
00212
00213 #endif // CEYLAN_ARCH_NINTENDO_DS
00214
00215 }
00216
00217
00218
00219 bool StandardFile::close()
00220 {
00221
00222 if ( ! isOpen() )
00223 {
00224
00225 LogPlug::warning( "StandardFile::close: file '" + _name
00226 + "' does not seem to have been already opened." ) ;
00227
00228 return false ;
00229
00230 }
00231 else
00232 {
00233
00234
00235
00236 #if CEYLAN_ARCH_NINTENDO_DS
00237
00238 throw Stream::CloseException( "StandardFile::close: "
00239 "not supported on the Nintendo DS platform." ) ;
00240
00241 #else // CEYLAN_ARCH_NINTENDO_DS
00242
00243
00244
00245
00246
00247
00248
00249
00250 #if CEYLAN_USES_FILE_DESCRIPTORS
00251
00252 return Stream::Close( _fdes ) ;
00253
00254 #else // CEYLAN_USES_FILE_DESCRIPTORS
00255
00256 _fstream.close() ;
00257 return true ;
00258
00259 #endif // CEYLAN_USES_FILE_DESCRIPTORS
00260
00261 #endif // CEYLAN_ARCH_NINTENDO_DS
00262
00263 }
00264
00265 }
00266
00267
00268
00269 void StandardFile::saveAs( const string & newName )
00270 {
00271
00272 #if CEYLAN_ARCH_NINTENDO_DS
00273
00274 throw FileException( "StandardFile::saveAs: "
00275 "not supported on the Nintendo DS platform." ) ;
00276
00277 #else // CEYLAN_ARCH_NINTENDO_DS
00278
00279 #if CEYLAN_USES_FILE_DESCRIPTORS
00280
00281
00282 StandardFile & f = StandardFile::Create( newName ) ;
00283 serialize( f._fdes ) ;
00284 delete &f ;
00285
00286 #else // CEYLAN_USES_FILE_DESCRIPTORS
00287
00288 throw FileException(
00289 "StandardFile::saveAs: not implemented on this platform." ) ;
00290
00291 #endif // CEYLAN_USES_FILE_DESCRIPTORS
00292
00293 #endif // CEYLAN_ARCH_NINTENDO_DS
00294
00295 }
00296
00297
00298
00299
00300
00301
00302
00303
00318 void StandardFile::lockForReading() const
00319 {
00320
00321 #if CEYLAN_ARCH_NINTENDO_DS
00322
00323 throw FileReadLockingFailed( "StandardFile::lockForReading: "
00324 "not supported on the Nintendo DS platform." ) ;
00325
00326 #else // CEYLAN_ARCH_NINTENDO_DS
00327
00328 #if CEYLAN_USES_FILE_LOCKS
00329
00330 struct flock lk ;
00331 lk.l_type = F_RDLCK ;
00332 lk.l_whence = SEEK_SET ;
00333 lk.l_start = 0 ;
00334 lk.l_len = 0 ;
00335
00336 while ( true )
00337 {
00338
00339 if ( ::fcntl( _fdes, F_SETLKW, &lk ) == - 1 )
00340 {
00341
00342 ErrorCode error = getError() ;
00343
00344 if ( error == EINTR )
00345 continue ;
00346
00347 if ( error != ENOLCK )
00348 throw FileReadLockingFailed(
00349 "StandardFile::lockForReading: locking failed for '"
00350 + _name + "': " + System::explainError() ) ;
00351 else
00352 LogPlug::warning( "StandardFile::lockForReading: "
00353 "lock for reading failed for '" + _name
00354 + "': check your NFS daemons (if any)." ) ;
00355
00356 break ;
00357 }
00358 else
00359 {
00360 break ;
00361 }
00362
00363 }
00364
00365 #else // CEYLAN_USES_FILE_LOCKS
00366
00367 throw FileReadLockingFailed( "StandardFile::lockForReading: "
00368 "lock feature not available" ) ;
00369
00370 #endif // CEYLAN_USES_FILE_LOCKS
00371
00372 #endif // CEYLAN_ARCH_NINTENDO_DS
00373
00374 }
00375
00376
00377
00378 void StandardFile::unlockForReading() const
00379 {
00380
00381 #if CEYLAN_ARCH_NINTENDO_DS
00382
00383 throw FileReadUnlockingFailed( "StandardFile::unlockForReading: "
00384 "not supported on the Nintendo DS platform." ) ;
00385
00386 #else // CEYLAN_ARCH_NINTENDO_DS
00387
00388 #if CEYLAN_USES_FILE_LOCKS
00389
00390 struct flock lk ;
00391 lk.l_type = F_UNLCK ;
00392 lk.l_whence = SEEK_SET ;
00393 lk.l_start = 0 ;
00394 lk.l_len = 0 ;
00395
00396 while ( true )
00397 {
00398 if ( ::fcntl( _fdes, F_SETLKW, &lk ) == - 1 )
00399 {
00400 if ( errno == EINTR )
00401 continue ;
00402
00403 if ( errno != ENOLCK )
00404 throw FileReadUnlockingFailed(
00405 "StandardFile::unlockForReading: unlocking failed for '"
00406 + _name + "': " + System::explainError() ) ;
00407 else
00408 LogPlug::warning( "StandardFile::unlockForReading: "
00409 "unlock for reading failed for '" + _name
00410 + "': check your NFS daemons (if any)." ) ;
00411 break ;
00412 }
00413 else
00414 {
00415 break ;
00416 }
00417 }
00418
00419 #else // CEYLAN_USES_FILE_LOCKS
00420
00421 throw FileReadUnlockingFailed(
00422 "StandardFile::unlockForReading: lock feature not available" ) ;
00423
00424 #endif // CEYLAN_USES_FILE_LOCKS
00425
00426 #endif // CEYLAN_ARCH_NINTENDO_DS
00427
00428 }
00429
00430
00431
00432 void StandardFile::lockForWriting() const
00433 {
00434
00435 #if CEYLAN_ARCH_NINTENDO_DS
00436
00437 throw FileWriteLockingFailed( "StandardFile::lockForWriting: "
00438 "not supported on the Nintendo DS platform." ) ;
00439
00440 #else // CEYLAN_ARCH_NINTENDO_DS
00441
00442 #if CEYLAN_USES_FILE_LOCKS
00443
00444 struct flock lk ;
00445 lk.l_type = F_WRLCK ;
00446 lk.l_whence = SEEK_SET ;
00447 lk.l_start = 0 ;
00448 lk.l_len = 0 ;
00449
00450 while ( true )
00451 {
00452 if ( ::fcntl( _fdes, F_SETLKW, &lk ) == - 1 )
00453 {
00454 if ( errno == EINTR )
00455 continue ;
00456
00457 if ( errno != ENOLCK )
00458 throw FileWriteLockingFailed(
00459 "StandardFile::lockForWriting: locking failed for '"
00460 + _name + "': " + System::explainError() ) ;
00461 else
00462 LogPlug::warning( "StandardFile::lockForWriting: "
00463 "lock for writing failed for '" + _name
00464 + "': check your NFS daemons (if any)." ) ;
00465 break ;
00466 }
00467 else
00468 {
00469 break ;
00470 }
00471 }
00472
00473 #else // CEYLAN_USES_FILE_LOCKS
00474
00475 throw FileWriteLockingFailed( "StandardFile::lockForWriting: "
00476 "lock feature not available" ) ;
00477
00478 #endif // CEYLAN_USES_FILE_LOCKS
00479
00480 #endif // CEYLAN_ARCH_NINTENDO_DS
00481
00482 }
00483
00484
00485
00486 void StandardFile::unlockForWriting() const
00487 {
00488
00489 #if CEYLAN_ARCH_NINTENDO_DS
00490
00491 throw FileWriteUnlockingFailed( "StandardFile::unlockForWriting: "
00492 "not supported on the Nintendo DS platform." ) ;
00493
00494 #else // CEYLAN_ARCH_NINTENDO_DS
00495
00496 #if CEYLAN_USES_FILE_LOCKS
00497
00498 struct flock lk ;
00499 lk.l_type = F_UNLCK ;
00500 lk.l_whence = SEEK_SET ;
00501 lk.l_start = 0 ;
00502 lk.l_len = 0 ;
00503
00504 while ( true )
00505 {
00506
00507 if ( ::fcntl( _fdes, F_SETLKW, &lk ) == - 1 )
00508 {
00509 if ( errno == EINTR )
00510 continue;
00511
00512 if ( errno != ENOLCK )
00513 throw FileWriteUnlockingFailed(
00514 "StandardFile::unlockForWriting: unlocking failed for '"
00515 + _name + "': " + System::explainError() ) ;
00516 else
00517 LogPlug::warning( "StandardFile::unlockForWriting: "
00518 "unlock for writing failed for '" + _name
00519 + "': check your NFS daemons (if any)." ) ;
00520 break ;
00521 }
00522 else
00523 {
00524 break ;
00525 }
00526 }
00527
00528 #else // CEYLAN_USES_FILE_LOCKS
00529
00530 throw FileWriteUnlockingFailed( "StandardFile::unlockForWriting: "
00531 "lock feature not available" ) ;
00532
00533 #endif // CEYLAN_USES_FILE_LOCKS
00534
00535 #endif // CEYLAN_ARCH_NINTENDO_DS
00536
00537 }
00538
00539
00540
00541 bool StandardFile::isLocked() const
00542 {
00543
00544 #if CEYLAN_ARCH_NINTENDO_DS
00545
00546 return false ;
00547
00548 #else // CEYLAN_ARCH_NINTENDO_DS
00549
00550 #if CEYLAN_USES_FILE_LOCKS
00551
00552 struct flock lk ;
00553 lk.l_type = F_WRLCK ;
00554 lk.l_whence = SEEK_SET ;
00555 lk.l_start = 0 ;
00556 lk.l_len = 0 ;
00557 lk.l_pid = 0 ;
00558
00559 while ( true )
00560 {
00561 if ( ::fcntl( _fdes, F_GETLK, &lk ) == - 1 )
00562 {
00563 if ( errno == EINTR )
00564 continue ;
00565 else
00566 LogPlug::warning( "StandardFile::isLocked: "
00567 "lock ckecking failed for '" + _name
00568 + "': check your NFS daemons (if any)." ) ;
00569 }
00570 break ;
00571 }
00572
00573 return ( lk.l_pid != 0 ) ;
00574
00575 #else // CEYLAN_USES_FILE_LOCKS
00576
00577 return false ;
00578
00579 #endif // CEYLAN_USES_FILE_LOCKS
00580
00581 #endif // CEYLAN_ARCH_NINTENDO_DS
00582
00583 }
00584
00585
00586
00587 time_t StandardFile::getLastChangeTime() const
00588 {
00589
00590 #if CEYLAN_ARCH_NINTENDO_DS
00591
00592 throw FileLastChangeTimeRequestFailed( "StandardFile::getLastChangeTime:"
00593 "not supported on the Nintendo DS platform." ) ;
00594
00595 #else // CEYLAN_ARCH_NINTENDO_DS
00596
00597
00598 #ifdef CEYLAN_USES_STAT
00599
00600 struct stat buf ;
00601
00602 if ( ::stat( _name.c_str(), & buf ) == 0 )
00603 return buf.st_ctime ;
00604
00605 throw FileLastChangeTimeRequestFailed(
00606 "StandardFile::getLastChangeTime failed for '"
00607 + _name + "': " + System::explainError() ) ;
00608
00609 #else // CEYLAN_USES_STAT
00610
00611 throw FileLastChangeTimeRequestFailed(
00612 "StandardFile::getLastChangeTime: not available on this platform." ) ;
00613
00614 #endif // CEYLAN_USES_STAT
00615
00616 #endif // CEYLAN_ARCH_NINTENDO_DS
00617
00618 }
00619
00620
00621
00622 Size StandardFile::read( Ceylan::Byte * buffer, Size maxLength )
00623 {
00624
00625 #if CEYLAN_ARCH_NINTENDO_DS
00626
00627 throw InputStream::ReadFailedException( "StandardFile::read:"
00628 "not supported on the Nintendo DS platform." ) ;
00629
00630
00631 #else // CEYLAN_ARCH_NINTENDO_DS
00632
00633 setSelected( false ) ;
00634
00635 #if CEYLAN_USES_FILE_DESCRIPTORS
00636
00637 try
00638 {
00639
00640 return System::FDRead( _fdes, buffer, maxLength ) ;
00641
00642 }
00643 catch( const Ceylan::Exception & e )
00644 {
00645 throw InputStream::ReadFailedException(
00646 "StandardFile::read failed for file '" + _name + "': "
00647 + e.toString() ) ;
00648 }
00649
00650 #else // CEYLAN_USES_FILE_DESCRIPTORS
00651
00652
00653 #if CEYLAN_PREFERS_RDBUF_TO_DIRECT_FSTREAM
00654
00655 SignedSize n = ( _fstream.rdbuf() )->sgetn( buffer,
00656 static_cast<std::streamsize>( maxLength ) ) ;
00657
00658 if ( ! _fstream.good() )
00659 throw InputStream::ReadFailedException(
00660 "StandardFile::read failed for file '" + _name
00661 + "': " + interpretState() ) ;
00662
00663
00664
00665 if ( n < 0 )
00666 throw InputStream::ReadFailedException(
00667 "StandardFile::read failed for file '"
00668 + _name + "': negative size read" ) ;
00669
00670 return static_cast<Size>( n ) ;
00671
00672 #else // CEYLAN_PREFERS_RDBUF_TO_DIRECT_FSTREAM
00673
00674
00675 SignedSize n = _fstream.readsome( buffer,
00676 static_cast<std::streamsize>( maxLength ) ) ;
00677
00678 if ( ! _fstream.good() )
00679 throw InputStream::ReadFailedException(
00680 "StandardFile::read failed for file '" + _name
00681 + "': " + interpretState() ) ;
00682
00683
00684 if ( n < 0 )
00685 throw InputStream::ReadFailedException(
00686 "StandardFile::read failed for file '"
00687 + _name + "': negative size read" ) ;
00688
00689 return static_cast<Size>( n ) ;
00690
00691 #endif // CEYLAN_PREFERS_RDBUF_TO_DIRECT_FSTREAM
00692
00693 #endif // CEYLAN_USES_FILE_DESCRIPTORS
00694
00695 #endif // CEYLAN_ARCH_NINTENDO_DS
00696
00697 }
00698
00699
00700
00701 Size StandardFile::write( const string & message )
00702 {
00703
00704 #if CEYLAN_ARCH_NINTENDO_DS
00705
00706 throw OutputStream::WriteFailedException( "StandardFile::write:"
00707 "not supported on the Nintendo DS platform." ) ;
00708
00709
00710 #else // CEYLAN_ARCH_NINTENDO_DS
00711
00712 #if CEYLAN_USES_FILE_DESCRIPTORS
00713
00714 try
00715 {
00716
00717 return System::FDWrite( _fdes, message.c_str(), message.size() ) ;
00718
00719 }
00720 catch( const Ceylan::Exception & e )
00721 {
00722 throw OutputStream::WriteFailedException(
00723 "StandardFile::write failed for file '" + _name + "': "
00724 + e.toString() ) ;
00725 }
00726
00727 #else // if CEYLAN_USES_FILE_DESCRIPTORS
00728
00729
00730 return write( message.c_str(),
00731 static_cast<std::streamsize>( message.size() ) ) ;
00732
00733
00734 #endif // if CEYLAN_USES_FILE_DESCRIPTORS
00735
00736 #endif // CEYLAN_ARCH_NINTENDO_DS
00737
00738 }
00739
00740
00741
00742 Position StandardFile::tell()
00743 {
00744
00745 #if CEYLAN_ARCH_NINTENDO_DS
00746
00747 throw FileException( "StandardFile::tell:"
00748 "not supported on the Nintendo DS platform." ) ;
00749
00750 #else // CEYLAN_ARCH_NINTENDO_DS
00751
00752 #if CEYLAN_USES_FILE_DESCRIPTORS
00753
00754
00755
00756
00757
00758
00759 off_t pos = ::lseek( _fdes, 0, SEEK_CUR ) ;
00760
00761 if ( pos < 0 )
00762 throw FileException( "StandardFile::tell failed for '" + _name
00763 + "': " + System::explainError() ) ;
00764
00765 return pos ;
00766
00767 #else // if CEYLAN_USES_FILE_DESCRIPTORS
00768
00769
00770 Position pos = _fstream.tellg() ;
00771
00772 if ( ! _fstream.good() )
00773 throw FileException( "StandardFile::tell failed for '" + _name
00774 + "': " + interpretState() ) ;
00775
00776 if ( pos < 0 )
00777 throw FileException( "StandardFile::tell failed for '" + _name
00778 + "'" ) ;
00779
00780 return pos ;
00781
00782 #endif // if CEYLAN_USES_FILE_DESCRIPTORS
00783
00784 #endif // CEYLAN_ARCH_NINTENDO_DS
00785
00786 }
00787
00788
00789
00790 void StandardFile::seek( Position targetPosition )
00791 {
00792
00793 #if CEYLAN_ARCH_NINTENDO_DS
00794
00795 throw FileException( "StandardFile::seek:"
00796 "not supported on the Nintendo DS platform." ) ;
00797
00798
00799 #else // CEYLAN_ARCH_NINTENDO_DS
00800
00801 #if CEYLAN_USES_FILE_DESCRIPTORS
00802
00803
00804 int res = ::lseek( _fdes, targetPosition, SEEK_SET ) ;
00805
00806 if ( res < 0 )
00807 throw FileException( "StandardFile::seek failed for '" + _name
00808 + "': " + System::explainError() ) ;
00809
00810 #else // if CEYLAN_USES_FILE_DESCRIPTORS
00811
00812
00813 _fstream.seekg( targetPosition ) ;
00814
00815 if ( ! _fstream.good() )
00816 throw FileOpeningFailed( "StandardFile::seek failed for '" + _name
00817 + "': " + interpretState() ) ;
00818
00819 #endif // if CEYLAN_USES_FILE_DESCRIPTORS
00820
00821 #endif // CEYLAN_ARCH_NINTENDO_DS
00822
00823 }
00824
00825
00826
00827
00828 Size StandardFile::write( const Ceylan::Byte * buffer, Size maxLength )
00829 {
00830
00831 #if CEYLAN_ARCH_NINTENDO_DS
00832
00833 throw OutputStream::WriteFailedException( "StandardFile::write:"
00834 "not supported on the Nintendo DS platform." ) ;
00835
00836
00837 #else // CEYLAN_ARCH_NINTENDO_DS
00838
00839
00840 #if CEYLAN_USES_FILE_DESCRIPTORS
00841
00842 try
00843 {
00844
00845 return System::FDWrite( _fdes, buffer, maxLength ) ;
00846
00847 }
00848 catch( const Ceylan::Exception & e )
00849 {
00850 throw OutputStream::WriteFailedException(
00851 "StandardFile::write failed for file '" + _name + "': "
00852 + e.toString() ) ;
00853 }
00854
00855 #else // CEYLAN_USES_FILE_DESCRIPTORS
00856
00857
00858
00859 #if CEYLAN_PREFERS_RDBUF_TO_DIRECT_FSTREAM
00860
00861
00862 SignedSize n = ( _fstream.rdbuf() )->sputn( buffer,
00863 static_cast<std::streamsize>( maxLength ) ) ;
00864
00865 if ( n < 0 )
00866 throw OutputStream::WriteFailedException(
00867 "StandardFile::write failed for file '"
00868 + _name + "': negative size written" ) ;
00869
00870 Size realSize = static_cast<Size>( n ) ;
00871
00872 if ( realSize < maxLength )
00873 throw OutputStream::WriteFailedException(
00874 "StandardFile::write failed for file '" + _name
00875 + "', fewer bytes wrote than expected: " + interpretState() ) ;
00876
00877
00878
00879
00880
00881
00882
00883
00884
00885
00886
00887 if ( Synchronous & _openFlag )
00888 _fstream.flush() ;
00889
00890 return realSize ;
00891
00892
00893 #else // CEYLAN_PREFERS_RDBUF_TO_DIRECT_FSTREAM
00894
00895
00896 _fstream.write( buffer, static_cast<std::streamsize>( maxLength ) ) ;
00897
00898 if ( ! _fstream.good() )
00899 throw WriteFailed( "StandardFile::write failed for file '" + _name
00900 + "': " + interpretState() ) ;
00901
00902 if ( Synchronous & _openFlag )
00903 _fstream.flush() ;
00904
00905
00906
00907
00908
00909
00910 return maxLength ;
00911
00912
00913 #endif // CEYLAN_PREFERS_RDBUF_TO_DIRECT_FSTREAM
00914
00915 #endif // CEYLAN_USES_FILE_DESCRIPTORS
00916
00917 #endif // CEYLAN_ARCH_NINTENDO_DS
00918
00919 }
00920
00921
00922
00923
00924
00925
00926
00927 void StandardFile::serialize( FileDescriptor fd ) const
00928 {
00929
00930 #if CEYLAN_ARCH_NINTENDO_DS
00931
00932 throw StandardFileException( "StandardFile::serialize: "
00933 "not supported on the Nintendo DS platform." ) ;
00934
00935 #else // CEYLAN_ARCH_NINTENDO_DS
00936
00937 #if CEYLAN_USES_FILE_DESCRIPTORS
00938
00939
00940 FromFDtoFD( _fdes, fd, size() ) ;
00941
00942 #else // CEYLAN_USES_FILE_DESCRIPTORS
00943
00944 throw StandardFileException( "StandardFile::serialize: "
00945 "file descriptor feature not available" ) ;
00946
00947 #endif // CEYLAN_USES_FILE_DESCRIPTORS
00948
00949 #endif // CEYLAN_ARCH_NINTENDO_DS
00950
00951 }
00952
00953
00954
00955 FileDescriptor StandardFile::getFileDescriptor() const
00956 {
00957
00958 #if CEYLAN_USES_FILE_DESCRIPTORS
00959
00960 return _fdes ;
00961
00962 #else // if CEYLAN_USES_FILE_DESCRIPTORS
00963
00964 throw StandardFileException(
00965 "StandardFile::getFileDescriptor: "
00966 "file descriptor feature not available" ) ;
00967
00968 #endif // if CEYLAN_USES_FILE_DESCRIPTORS
00969
00970 }
00971
00972
00973
00974
00975 StreamID StandardFile::getStreamID() const
00976 {
00977
00978 #if CEYLAN_USES_FILE_DESCRIPTORS
00979
00980 return static_cast<StreamID>( getFileDescriptor() ) ;
00981
00982 #else // if CEYLAN_USES_FILE_DESCRIPTORS
00983
00984
00985 return -1 ;
00986
00987 #endif // if CEYLAN_USES_FILE_DESCRIPTORS
00988
00989 }
00990
00991
00992
00993 const std::string StandardFile::toString( Ceylan::VerbosityLevels level ) const
00994 {
00995
00996 string res = "Standard file object for filename '" + _name + "'" ;
00997
00998 #if CEYLAN_USES_FILE_DESCRIPTORS
00999 res += ", with file descriptor " + Ceylan::toString( getFileDescriptor() ) ;
01000 #endif // CEYLAN_USES_FILE_DESCRIPTORS
01001
01002 res += ", with opening openFlags = " + Ceylan::toString( _openFlag )
01003 + ", with mode openFlags = " + Ceylan::toString( _permissions ) ;
01004
01005 #if CEYLAN_USES_FILE_LOCKS
01006
01007 if ( _lockedForReading )
01008 res += ", locked for reading" ;
01009 else
01010 res += ", not locked for reading" ;
01011
01012 if ( _lockedForWriting )
01013 res += ", locked for writing" ;
01014 else
01015 res += ", not locked for writing" ;
01016
01017 #endif // CEYLAN_USES_FILE_LOCKS
01018
01019 return res ;
01020
01021 }
01022
01023
01024
01025 string StandardFile::InterpretState( const ifstream & inputFile )
01026 {
01027
01028 if ( inputFile.good() )
01029 return "Standard file is in clean state (no error)" ;
01030
01031 string res = "Standard file in error" ;
01032
01033 if ( inputFile.rdstate() & ifstream::badbit )
01034 res += ", critical error in stream buffer" ;
01035
01036 if ( inputFile.rdstate() & ifstream::eofbit )
01037 res += ", End-Of-File reached while extracting" ;
01038
01039 if ( inputFile.rdstate() & ifstream::failbit )
01040 res += ", failure extracting from stream" ;
01041
01042 return res ;
01043
01044 }
01045
01046
01047
01048 string StandardFile::InterpretState( const fstream & file )
01049 {
01050
01051 if ( file.good() )
01052 return "Standard file is in clean state (no error)" ;
01053
01054 string res = "Standard file in error" ;
01055
01056 if ( file.rdstate() & fstream::badbit )
01057 res += ", critical error in stream buffer" ;
01058
01059 if ( file.rdstate() & fstream::eofbit )
01060 res += ", End-Of-File reached while extracting" ;
01061
01062 if ( file.rdstate() & fstream::failbit )
01063 res += ", failure extracting from stream" ;
01064
01065 return res ;
01066
01067 }
01068
01069
01070
01071 StandardFile & StandardFile::Create( const std::string & filename,
01072 OpeningFlag createFlag, PermissionFlag permissionFlag )
01073 {
01074
01075
01076 return * new StandardFile( filename, createFlag | File::CreateFile,
01077 permissionFlag ) ;
01078
01079 }
01080
01081
01082
01083 StandardFile & StandardFile::Open( const std::string & filename,
01084 OpeningFlag openFlag )
01085 {
01086
01087
01088 return * new StandardFile( filename, openFlag & ~File::CreateFile
01089 ) ;
01090
01091 }
01092
01093
01094
01095
01096
01097
01098
01099 StandardFile::StandardFile( const string & name, OpeningFlag openFlag,
01100 PermissionFlag permissions ) :
01101 File( name, openFlag, permissions )
01102 {
01103
01104
01105
01106 #if CEYLAN_ARCH_NINTENDO_DS
01107
01108 throw StandardFileException( "StandardFile constructor: "
01109 "not supported on the Nintendo DS platform." ) ;
01110
01111 #else // CEYLAN_ARCH_NINTENDO_DS
01112
01113 if ( openFlag != DoNotOpen )
01114 reopen() ;
01115
01116 #endif // CEYLAN_ARCH_NINTENDO_DS
01117
01118 }
01119
01120
01121
01122
01123
01124
01125
01126
01127 FileSystemManager & StandardFile::getCorrespondingFileSystemManager() const
01128 {
01129
01130 try
01131 {
01132
01133 return StandardFileSystemManager::GetStandardFileSystemManager() ;
01134
01135 }
01136 catch( const StandardFileSystemManagerException & e )
01137 {
01138
01139 throw FileDelegatingException(
01140 "StandardFile::getCorrespondingFileSystemManager failed: "
01141 + e.toString() ) ;
01142
01143 }
01144
01145 }
01146
01147
01148
01149 void StandardFile::reopen()
01150 {
01151
01152 #if CEYLAN_ARCH_NINTENDO_DS
01153
01154 throw FileOpeningFailed( "StandardFile::reopen: "
01155 "not supported on the Nintendo DS platform." ) ;
01156
01157 #else // CEYLAN_ARCH_NINTENDO_DS
01158
01159 #if CEYLAN_USES_FILE_DESCRIPTORS
01160
01161 SystemSpecificPermissionFlag myMode ;
01162
01163 ConvertToFileDescriptorPermissionFlag( _permissions, myMode ) ;
01164
01165 _fdes = ::open( _name.c_str(), ConvertToFileDescriptorOpenFlag( _openFlag ),
01166 myMode._mode ) ;
01167
01168 if ( _fdes < 0 )
01169 throw FileOpeningFailed( "StandardFile::reopen failed for '" + _name
01170 + "': " + System::explainError() ) ;
01171
01172
01173 #else // if CEYLAN_USES_FILE_DESCRIPTORS
01174
01175
01176
01177
01178
01179
01180
01181
01182
01183
01184
01185
01186
01187
01188
01189
01190
01191
01192
01193
01194
01195
01196 if ( Synchronous & _openFlag )
01197 _fstream.rdbuf()->pubsetbuf( 0, 0 ) ;
01198
01199 _fstream.open( _name.c_str(),
01200 ConvertToStreamOpenFlag( _openFlag, _name ) ) ;
01201
01202
01203
01204 if ( ! _fstream.is_open() )
01205 throw FileOpeningFailed( "StandardFile::reopen failed for '" + _name
01206 + "': error opening file, " + interpretState() ) ;
01207
01208 if ( ! _fstream.good() )
01209 throw FileOpeningFailed( "StandardFile::reopen failed for '" + _name
01210 + "': " + interpretState() ) ;
01211
01212 #endif // if CEYLAN_USES_FILE_DESCRIPTORS
01213
01214 #endif // CEYLAN_ARCH_NINTENDO_DS
01215
01216 }
01217
01218
01219
01220 string StandardFile::interpretState() const
01221 {
01222
01223 #if CEYLAN_USES_FILE_DESCRIPTORS
01224
01225 return "StandardFile uses file descriptor " + Ceylan::toString( _fdes ) ;
01226
01227 #else // CEYLAN_USES_FILE_DESCRIPTORS
01228
01229 return InterpretState( _fstream ) ;
01230
01231 #endif // CEYLAN_USES_FILE_DESCRIPTORS
01232
01233 }
01234
01235
01236
01237
01238
01239
01240
01241 int StandardFile::ConvertToFileDescriptorOpenFlag( OpeningFlag openFlag )
01242 {
01243
01244 #if CEYLAN_ARCH_NINTENDO_DS
01245
01246 throw ConversionFailed( "StandardFile ConvertToFileDescriptorOpenFlag: "
01247 "not supported on the Nintendo DS platform." ) ;
01248
01249 #else // CEYLAN_ARCH_NINTENDO_DS
01250
01251
01252
01253 #if CEYLAN_USES_FILE_DESCRIPTORS
01254
01255
01256 #if CEYLAN_DEBUG
01257
01258 if ( openFlag == DoNotOpen )
01259 throw ConversionFailed(
01260 "StandardFile::ConvertToFileDescriptorOpenFlag: "
01261 "flags specify that the file is not to be opened." ) ;
01262
01263 #endif // CEYLAN_DEBUG
01264
01265
01266 int actualFlags = 0 ;
01267
01268 if ( Read & openFlag )
01269 {
01270 if ( Write & openFlag )
01271 actualFlags |= O_RDWR ;
01272 else
01273 actualFlags |= O_RDONLY ;
01274 }
01275 else
01276 {
01277 if ( Write & openFlag )
01278 actualFlags |= O_WRONLY ;
01279 }
01280
01281 if ( CreateFile & openFlag )
01282 actualFlags |= O_CREAT ;
01283
01284 if ( TruncateFile & openFlag )
01285 actualFlags |= O_TRUNC ;
01286
01287 if ( AppendFile & openFlag )
01288 actualFlags |= O_APPEND ;
01289
01290
01291
01292
01293 #if CEYLAN_USES_ADVANCED_FILE_ATTRIBUTES
01294
01295 if ( NonBlocking & openFlag )
01296 actualFlags |= O_NONBLOCK ;
01297
01298 if ( Synchronous & openFlag )
01299 actualFlags |= O_SYNC ;
01300
01301 #endif // CEYLAN_USES_ADVANCED_FILE_ATTRIBUTES
01302
01303 return actualFlags ;
01304
01305 #else // CEYLAN_USES_FILE_DESCRIPTORS
01306
01307 throw ConversionFailed( "StandardFile::ConvertToFileDescriptorOpenFlag: "
01308 "file descriptor feature is not available" ) ;
01309
01310 #endif // CEYLAN_USES_FILE_DESCRIPTORS
01311
01312 #endif // CEYLAN_ARCH_NINTENDO_DS
01313
01314 }
01315
01316
01317
01318 void StandardFile::ConvertToFileDescriptorPermissionFlag(
01319 PermissionFlag permissionFlag,
01320 struct SystemSpecificPermissionFlag & returned )
01321 {
01322
01323 #if CEYLAN_ARCH_NINTENDO_DS
01324
01325 throw ConversionFailed(
01326 "StandardFile ConvertToFileDescriptorPermissionFlag: "
01327 "not supported on the Nintendo DS platform." ) ;
01328
01329 #else // CEYLAN_ARCH_NINTENDO_DS
01330
01331
01332 #if CEYLAN_USES_FILE_DESCRIPTORS
01333
01334 mode_t actualPermissions = 0 ;
01335
01336 if ( permissionFlag & OwnerRead )
01337 actualPermissions |= S_IRUSR ;
01338
01339 if ( permissionFlag & OwnerWrite )
01340 actualPermissions |= S_IWUSR ;
01341
01342 if ( permissionFlag & OwnerExec )
01343 actualPermissions |= S_IXUSR ;
01344
01345 #if CEYLAN_USES_ADVANCED_FILE_ATTRIBUTES
01346
01347
01348 if ( permissionFlag & GroupRead )
01349 actualPermissions |= S_IRGRP ;
01350
01351 if ( permissionFlag & GroupWrite )
01352 actualPermissions |= S_IWGRP ;
01353
01354 if ( permissionFlag & GroupExec )
01355 actualPermissions |= S_IXGRP ;
01356
01357
01358 if ( permissionFlag & OthersRead )
01359 actualPermissions |= S_IROTH ;
01360
01361 if ( permissionFlag & OthersWrite )
01362 actualPermissions |= S_IWOTH ;
01363
01364 if ( permissionFlag & OthersExec )
01365 actualPermissions |= S_IXOTH ;
01366
01367
01368 #endif // CEYLAN_USES_ADVANCED_FILE_ATTRIBUTES
01369
01370 returned._mode = actualPermissions ;
01371
01372 #else // CEYLAN_USES_FILE_DESCRIPTORS
01373
01374 throw ConversionFailed(
01375 "StandardFile::ConvertToFileDescriptorPermissionFlag: "
01376 "file descriptor feature is not available" ) ;
01377
01378 #endif // CEYLAN_USES_FILE_DESCRIPTORS
01379
01380 #endif // CEYLAN_ARCH_NINTENDO_DS
01381
01382 }
01383
01384
01385
01386 ios_base::openmode StandardFile::ConvertToStreamOpenFlag(
01387 OpeningFlag openFlag, const std::string & filename )
01388 {
01389
01390 #if CEYLAN_ARCH_NINTENDO_DS
01391
01392 throw ConversionFailed( "StandardFile ConvertToStreamOpenFlag: "
01393 "not supported on the Nintendo DS platform." ) ;
01394
01395 #else // CEYLAN_ARCH_NINTENDO_DS
01396
01397
01398 #if CEYLAN_DEBUG
01399
01400 if ( openFlag == DoNotOpen )
01401 throw ConversionFailed( "StandardFile::ConvertToStreamOpenFlag: "
01402 "flags specify that the file is not to be opened." ) ;
01403
01404 #endif // CEYLAN_DEBUG
01405
01406
01407 ios_base::openmode actualFlags =
01408 static_cast<ios_base::openmode>( 0 ) ;
01409
01410 if ( Read & openFlag )
01411 actualFlags |= fstream::in ;
01412
01413 if ( Write & openFlag )
01414 actualFlags |= fstream::out ;
01415
01416
01417 if ( ! ( CreateFile & openFlag ) )
01418 {
01419
01420
01421
01422 bool alreadyExisting = false ;
01423
01424 try
01425 {
01426
01427 alreadyExisting = StandardFileSystemManager::GetStandardFileSystemManager().existsAsFileOrSymbolicLink( filename ) ;
01428
01429 }
01430 catch( const FileException & e )
01431 {
01432
01433 throw ConversionFailed( "StandardFile::ConvertToStreamOpenFlag: "
01434 "error while checking the existence of file: "
01435 + e.toString() ) ;
01436
01437 }
01438
01439 if ( ! alreadyExisting )
01440 throw ConversionFailed(
01441 "StandardFile::ConvertToStreamOpenFlag: the file '"
01442 + filename + "' does not exist whereas it should "
01443 "( no 'CreateFile' attribute in opening flag)" ) ;
01444
01445 }
01446
01447 if ( TruncateFile & openFlag )
01448 actualFlags |= fstream::trunc ;
01449
01450 if ( AppendFile & openFlag )
01451 actualFlags |= fstream::app ;
01452
01453 if ( Binary & openFlag )
01454 actualFlags |= fstream::binary ;
01455
01456
01457
01458 return actualFlags ;
01459
01460 #endif // CEYLAN_ARCH_NINTENDO_DS
01461
01462 }
01463
01464
01465
01466
01467
01468
01469
01470
01471
01472 void StandardFile::FromFDtoFD( FileDescriptor from, FileDescriptor to,
01473 Size length )
01474 {
01475
01476 #if CEYLAN_USES_FILE_DESCRIPTORS
01477
01478 Size written = 0 ;
01479
01480 Size bufferSize = ( length > BigBufferSize ? BigBufferSize: length ) ;
01481
01482 Ceylan::Byte * buf = new Ceylan::Byte[ bufferSize ] ;
01483
01484 Size readCount ;
01485
01486 try
01487 {
01488
01489 while ( written < length )
01490 {
01491
01492 Size toRead = length - written ;
01493
01494 if ( toRead > bufferSize )
01495 toRead = bufferSize ;
01496
01497 readCount = FDRead( from, buf, toRead ) ;
01498
01499 FDWrite( to, buf, readCount ) ;
01500
01501 written += readCount ;
01502
01503 }
01504
01505 delete [] buf ;
01506
01507 }
01508 catch( const Ceylan::Exception & e )
01509 {
01510
01511 delete [] buf ;
01512 throw StandardFileException(
01513 "StandardFile::FromFDtoFD failed: " + e.toString() ) ;
01514
01515 }
01516
01517 #else // CEYLAN_USES_FILE_DESCRIPTORS
01518
01519 throw StandardFileException( "StandardFile::FromFDtoFD: "
01520 "file descriptor feature not available" ) ;
01521
01522 #endif // CEYLAN_USES_FILE_DESCRIPTORS
01523
01524 }
01525