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 "CeylanLibfatFile.h"
00028
00029 #include "CeylanLogPlug.h"
00030 #include "CeylanOperators.h"
00031 #include "CeylanLibfatFileSystemManager.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 #if CEYLAN_ARCH_NINTENDO_DS
00045
00046 #include "fat.h"
00047
00048 #include <fcntl.h>
00049 #include <unistd.h>
00050
00051 #endif // CEYLAN_ARCH_NINTENDO_DS
00052
00053 }
00054
00055
00056 #include <cstdlib>
00057
00058 #include <cerrno>
00059 #include <cstdio>
00060
00061
00062
00063
00064
00065
00066
00067
00068
00069
00070
00071
00072
00073 using std::string ;
00074
00075
00076 using namespace Ceylan ;
00077 using namespace Ceylan::System ;
00078 using namespace Ceylan::Log ;
00079
00080
00081
00082
00083
00084
00085
00086
00087
00088
00089 LibfatFileException::LibfatFileException( const string & reason ) :
00090 FileException( reason )
00091 {
00092
00093 }
00094
00095
00096
00097 LibfatFileException::~LibfatFileException() throw()
00098 {
00099
00100 }
00101
00102
00103
00104
00105
00106
00107
00108
00109 LibfatFile::~LibfatFile() throw()
00110 {
00111
00112
00113
00114 if ( isOpen() )
00115 {
00116
00117 try
00118 {
00119 close() ;
00120 }
00121 catch( const Stream::CloseException & e )
00122 {
00123 LogPlug::error( "LibfatFile destructor: close failed: "
00124 + e.toString() ) ;
00125 }
00126
00127 }
00128
00129 }
00130
00131
00132
00133
00134
00135
00136
00137
00138
00139
00140
00141
00142
00143
00144 bool LibfatFile::isOpen() const
00145 {
00146
00147 #if CEYLAN_ARCH_NINTENDO_DS
00148
00149 #ifdef CEYLAN_RUNS_ON_ARM7
00150
00151 return false ;
00152
00153 #else // CEYLAN_RUNS_ON_ARM7
00154
00155 return ( _fdes != 0 ) ;
00156
00157 #endif // CEYLAN_RUNS_ON_ARM7
00158
00159 #else // CEYLAN_ARCH_NINTENDO_DS
00160
00161 return false ;
00162
00163 #endif // CEYLAN_ARCH_NINTENDO_DS
00164
00165 }
00166
00167
00168
00169 bool LibfatFile::close()
00170 {
00171
00172 if ( ! isOpen() )
00173 {
00174
00175 LogPlug::warning( "LibfatFile::close: file '" + _name
00176 + "' does not seem to have been already opened." ) ;
00177
00178 return false ;
00179
00180 }
00181 else
00182 {
00183
00184
00185
00186 #if CEYLAN_ARCH_NINTENDO_DS
00187
00188 #ifdef CEYLAN_RUNS_ON_ARM7
00189
00190 throw Stream::CloseException( "LibfatFile::close: "
00191 "not supported on the ARM7 (no libfat available)" ) ;
00192
00193 #else // CEYLAN_RUNS_ON_ARM7
00194
00195
00196
00197
00198
00199
00200
00201
00202 return Stream::Close( _fdes ) ;
00203
00204
00205 #endif // CEYLAN_RUNS_ON_ARM7
00206
00207
00208 #else // CEYLAN_ARCH_NINTENDO_DS
00209
00210 throw Stream::CloseException( "LibfatFile::close: "
00211 "not supported on this platform" ) ;
00212
00213 #endif // CEYLAN_ARCH_NINTENDO_DS
00214
00215 }
00216
00217 }
00218
00219
00220
00221 void LibfatFile::saveAs( const string & newName )
00222 {
00223
00224 #if CEYLAN_ARCH_NINTENDO_DS
00225
00226 #ifdef CEYLAN_RUNS_ON_ARM7
00227
00228 throw FileException( "LibfatFile::saveAs: "
00229 "not supported on the ARM7 (no libfat available)" ) ;
00230
00231 #else // CEYLAN_RUNS_ON_ARM7
00232
00233
00234
00235 LibfatFile & f = LibfatFile::Create( newName ) ;
00236 serialize( f._fdes ) ;
00237 delete &f ;
00238
00239 #endif // CEYLAN_RUNS_ON_ARM7
00240
00241
00242 #else // CEYLAN_ARCH_NINTENDO_DS
00243
00244 throw FileException( "LibfatFile::saveAs: "
00245 "not supported on this platform" ) ;
00246
00247 #endif // CEYLAN_ARCH_NINTENDO_DS
00248
00249 }
00250
00251
00252
00253
00254
00255
00256
00257
00266 time_t LibfatFile::getLastChangeTime() const
00267 {
00268
00269 #if CEYLAN_ARCH_NINTENDO_DS
00270
00271 #ifdef CEYLAN_RUNS_ON_ARM7
00272
00273 throw FileException( "LibfatFile::getLastChangeTime: "
00274 "not supported on the ARM7 (no libfat available)" ) ;
00275
00276 #else // CEYLAN_RUNS_ON_ARM7
00277
00278 struct stat buf ;
00279
00280 if ( ::stat( _name.c_str(), & buf ) == 0 )
00281 return buf.st_ctime ;
00282
00283 throw FileLastChangeTimeRequestFailed(
00284 "LibfatFile::getLastChangeTime failed for '"
00285 + _name + "': " + System::explainError() ) ;
00286
00287 #endif // CEYLAN_RUNS_ON_ARM7
00288
00289 #else // CEYLAN_ARCH_NINTENDO_DS
00290
00291
00292 throw FileLastChangeTimeRequestFailed( "LibfatFile::getLastChangeTime:"
00293 "not supported on this platform." ) ;
00294
00295 #endif // CEYLAN_ARCH_NINTENDO_DS
00296
00297 }
00298
00299
00300
00301 Size LibfatFile::read( Ceylan::Byte * buffer, Size maxLength )
00302 {
00303
00304 #if CEYLAN_ARCH_NINTENDO_DS
00305
00306 #ifdef CEYLAN_RUNS_ON_ARM7
00307
00308 throw InputStream::ReadFailedException( "LibfatFile::read: "
00309 "not supported on the ARM7 (no libfat available)" ) ;
00310
00311 #else // CEYLAN_RUNS_ON_ARM7
00312
00313 setSelected( false ) ;
00314
00315 try
00316 {
00317
00318 return System::FDRead( _fdes, buffer, maxLength ) ;
00319
00320 }
00321 catch( const Ceylan::Exception & e )
00322 {
00323 throw InputStream::ReadFailedException(
00324 "LibfatFile::read failed for file '" + _name + "': "
00325 + e.toString() ) ;
00326 }
00327
00328 #endif // CEYLAN_RUNS_ON_ARM7
00329
00330 #else // CEYLAN_ARCH_NINTENDO_DS
00331
00332 throw InputStream::ReadFailedException( "LibfatFile::read:"
00333 "not supported on this platform." ) ;
00334
00335 #endif // CEYLAN_ARCH_NINTENDO_DS
00336
00337 }
00338
00339
00340
00341 Size LibfatFile::write( const string & message )
00342 {
00343
00344 #if CEYLAN_ARCH_NINTENDO_DS
00345
00346 #ifdef CEYLAN_RUNS_ON_ARM7
00347
00348 throw OutputStream::WriteFailedException( "LibfatFile::write: "
00349 "not supported on the ARM7 (no libfat available)" ) ;
00350
00351 #else // CEYLAN_RUNS_ON_ARM7
00352
00353 try
00354 {
00355
00356 return System::FDWrite( _fdes, message.c_str(), message.size() ) ;
00357
00358 }
00359 catch( const Ceylan::Exception & e )
00360 {
00361 throw OutputStream::WriteFailedException(
00362 "LibfatFile::write failed for file '" + _name + "': "
00363 + e.toString() ) ;
00364 }
00365
00366 #endif // CEYLAN_RUNS_ON_ARM7
00367
00368 #else // CEYLAN_ARCH_NINTENDO_DS
00369
00370 throw OutputStream::WriteFailedException( "LibfatFile::write:"
00371 "not supported on this platform." ) ;
00372
00373 #endif // CEYLAN_ARCH_NINTENDO_DS
00374
00375 }
00376
00377
00378
00379 Size LibfatFile::write( const Ceylan::Byte * buffer, Size maxLength )
00380 {
00381
00382 #if CEYLAN_ARCH_NINTENDO_DS
00383
00384 #ifdef CEYLAN_RUNS_ON_ARM7
00385
00386 throw OutputStream::WriteFailedException( "LibfatFile::write: "
00387 "not supported on the ARM7 (no libfat available)" ) ;
00388
00389 #else // CEYLAN_RUNS_ON_ARM7
00390
00391 try
00392 {
00393
00394 return System::FDWrite( _fdes, buffer, maxLength ) ;
00395
00396 }
00397 catch( const Ceylan::Exception & e )
00398 {
00399 throw OutputStream::WriteFailedException(
00400 "LibfatFile::write failed for file '" + _name + "': "
00401 + e.toString() ) ;
00402 }
00403
00404 #endif // CEYLAN_RUNS_ON_ARM7
00405
00406 #else // CEYLAN_ARCH_NINTENDO_DS
00407
00408 throw OutputStream::WriteFailedException( "LibfatFile::write:"
00409 "not supported on this platform." ) ;
00410
00411 #endif // CEYLAN_ARCH_NINTENDO_DS
00412
00413 }
00414
00415
00416
00417 Position LibfatFile::tell()
00418 {
00419
00420 #if CEYLAN_ARCH_NINTENDO_DS
00421
00422 #ifdef CEYLAN_RUNS_ON_ARM7
00423
00424 throw FileException( "LibfatFile::tell: "
00425 "not supported on the ARM7 (no libfat available)" ) ;
00426
00427 #else // CEYLAN_RUNS_ON_ARM7
00428
00429 throw FileException( "LibfatFile::tell:"
00430 "not currently implemented." ) ;
00431
00432 #endif // CEYLAN_RUNS_ON_ARM7
00433
00434 #else // CEYLAN_ARCH_NINTENDO_DS
00435
00436 throw FileException( "LibfatFile::tell:"
00437 "not supported on this platform." ) ;
00438
00439 #endif // CEYLAN_ARCH_NINTENDO_DS
00440
00441 }
00442
00443
00444
00445 void LibfatFile::seek( Position targetPosition )
00446 {
00447
00448 #if CEYLAN_ARCH_NINTENDO_DS
00449
00450 #ifdef CEYLAN_RUNS_ON_ARM7
00451
00452 throw FileException( "LibfatFile::seek: "
00453 "not supported on the ARM7 (no libfat available)" ) ;
00454
00455 #else // CEYLAN_RUNS_ON_ARM7
00456
00457 throw FileException( "LibfatFile::seek:"
00458 "not currently implemented." ) ;
00459
00460 #endif // CEYLAN_RUNS_ON_ARM7
00461
00462 #else // CEYLAN_ARCH_NINTENDO_DS
00463
00464 throw FileException( "LibfatFile::seek:"
00465 "not supported on this platform." ) ;
00466
00467 #endif // CEYLAN_ARCH_NINTENDO_DS
00468
00469 }
00470
00471
00472
00473
00474
00475
00476
00477
00478
00479 void LibfatFile::serialize( FileDescriptor fd ) const
00480 {
00481
00482 #if CEYLAN_ARCH_NINTENDO_DS
00483
00484 #ifdef CEYLAN_RUNS_ON_ARM7
00485
00486 throw LibfatFileException( "LibfatFile::serialize: "
00487 "not supported on the ARM7 (no libfat available)" ) ;
00488
00489 #else // CEYLAN_RUNS_ON_ARM7
00490
00491
00492 FromFDtoFD( _fdes, fd, size() ) ;
00493
00494 #endif // CEYLAN_RUNS_ON_ARM7
00495
00496 #else // CEYLAN_ARCH_NINTENDO_DS
00497
00498 throw LibfatFileException( "LibfatFile::serialize: "
00499 "not supported on this platform." ) ;
00500
00501 #endif // CEYLAN_ARCH_NINTENDO_DS
00502
00503 }
00504
00505
00506
00507 FileDescriptor LibfatFile::getFileDescriptor() const
00508 {
00509
00510 #if CEYLAN_ARCH_NINTENDO_DS
00511
00512 #ifdef CEYLAN_RUNS_ON_ARM7
00513
00514 throw LibfatFileException( "LibfatFile::getFileDescriptor: "
00515 "not supported on the ARM7 (no libfat available)" ) ;
00516
00517 #else // CEYLAN_RUNS_ON_ARM7
00518
00519 return _fdes ;
00520
00521 #endif // CEYLAN_RUNS_ON_ARM7
00522
00523 #else // CEYLAN_ARCH_NINTENDO_DS
00524
00525 throw LibfatFileException( "LibfatFile::getFileDescriptor: "
00526 "not supported on this platform." ) ;
00527
00528 #endif // CEYLAN_ARCH_NINTENDO_DS
00529
00530 }
00531
00532
00533
00534 StreamID LibfatFile::getStreamID() const
00535 {
00536
00537 #if CEYLAN_ARCH_NINTENDO_DS
00538
00539 #ifdef CEYLAN_RUNS_ON_ARM7
00540
00541
00542 return -1 ;
00543
00544 #else // CEYLAN_RUNS_ON_ARM7
00545
00546 return static_cast<StreamID>( getFileDescriptor() ) ;
00547
00548 #endif // CEYLAN_RUNS_ON_ARM7
00549
00550 #else // CEYLAN_ARCH_NINTENDO_DS
00551
00552
00553 return -1 ;
00554
00555 #endif // CEYLAN_ARCH_NINTENDO_DS
00556
00557 }
00558
00559
00560
00561 const std::string LibfatFile::toString( Ceylan::VerbosityLevels level ) const
00562 {
00563
00564 string res = "Libfat file object for filename '" + _name + "'" ;
00565
00566 res += ", with file descriptor " + Ceylan::toString( getFileDescriptor() ) ;
00567
00568 res += ", with opening openFlags = " + Ceylan::toString( _openFlag )
00569 + ", with mode openFlags = " + Ceylan::toString( _permissions ) ;
00570
00571 return res ;
00572
00573 }
00574
00575
00576
00577
00578
00579
00580
00581
00582 LibfatFile & LibfatFile::Create( const std::string & filename,
00583 OpeningFlag createFlag )
00584 {
00585
00586
00587 return * new LibfatFile( filename, createFlag | File::CreateFile ) ;
00588
00589 }
00590
00591
00592
00593 LibfatFile & LibfatFile::Open( const std::string & filename,
00594 OpeningFlag openFlag )
00595 {
00596
00597
00598 return * new LibfatFile( filename, openFlag & ~File::CreateFile ) ;
00599
00600 }
00601
00602
00603
00604
00605
00606
00607
00608 LibfatFile::LibfatFile( const string & name, OpeningFlag openFlag ) :
00609 File( name, openFlag, OwnerReadWrite )
00610 {
00611
00612
00613
00614 #if CEYLAN_ARCH_NINTENDO_DS
00615
00616 #ifdef CEYLAN_RUNS_ON_ARM7
00617
00618 throw LibfatFileException( "LibfatFile constructor: "
00619 "not supported on the ARM7 (no libfat available)" ) ;
00620
00621 #else // CEYLAN_RUNS_ON_ARM7
00622
00623 LibfatFileSystemManager::SecureLibfatFileSystemManager() ;
00624
00625 if ( openFlag != DoNotOpen )
00626 reopen() ;
00627
00628 #endif // CEYLAN_RUNS_ON_ARM7
00629
00630
00631 #else // CEYLAN_ARCH_NINTENDO_DS
00632
00633 throw LibfatFileException( "LibfatFile constructor: "
00634 "not supported on this platform." ) ;
00635
00636 #endif // CEYLAN_ARCH_NINTENDO_DS
00637
00638 }
00639
00640
00641
00642
00643
00644
00645
00646 FileSystemManager & LibfatFile::getCorrespondingFileSystemManager() const
00647 {
00648
00649 try
00650 {
00651
00652 return LibfatFileSystemManager::GetLibfatFileSystemManager() ;
00653
00654 }
00655 catch( const LibfatFileSystemManagerException & e )
00656 {
00657
00658 throw FileDelegatingException(
00659 "LibfatFile::getCorrespondingFileSystemManager failed: "
00660 + e.toString() ) ;
00661
00662 }
00663
00664 }
00665
00666
00667
00668 void LibfatFile::reopen()
00669 {
00670
00671 #if CEYLAN_ARCH_NINTENDO_DS
00672
00673 #ifdef CEYLAN_RUNS_ON_ARM7
00674
00675 throw FileOpeningFailed( "LibfatFile::reopen: "
00676 "not supported on the ARM7 (no libfat available)" ) ;
00677
00678 #else // CEYLAN_RUNS_ON_ARM7
00679
00680 _fdes = ::open( _name.c_str(),
00681 ConvertToFileDescriptorOpenFlag( _openFlag ) ) ;
00682
00683 if ( _fdes < 0 )
00684 throw FileOpeningFailed( "LibfatFile::reopen failed for '" + _name
00685 + "': " + System::explainError() ) ;
00686
00687 #endif // CEYLAN_RUNS_ON_ARM7
00688
00689
00690 #else // CEYLAN_ARCH_NINTENDO_DS
00691
00692 throw FileOpeningFailed( "LibfatFile::reopen: "
00693 "not supported on this platform." ) ;
00694
00695 #endif // CEYLAN_ARCH_NINTENDO_DS
00696
00697 }
00698
00699
00700
00701 string LibfatFile::interpretState() const
00702 {
00703
00704 return "LibfatFile uses file descriptor " + Ceylan::toString( _fdes ) ;
00705
00706 }
00707
00708
00709
00710
00711
00712
00713
00714 int LibfatFile::ConvertToFileDescriptorOpenFlag( OpeningFlag openFlag )
00715 {
00716
00717 #if CEYLAN_ARCH_NINTENDO_DS
00718
00719 #ifdef CEYLAN_RUNS_ON_ARM7
00720
00721 throw ConversionFailed( "LibfatFile::ConvertToFileDescriptorOpenFlag: "
00722 "not supported on the ARM7 (no libfat available)" ) ;
00723
00724 #else // CEYLAN_RUNS_ON_ARM7
00725
00726
00727 #if CEYLAN_DEBUG
00728
00729 if ( openFlag == DoNotOpen )
00730 throw ConversionFailed(
00731 "LibfatFile::ConvertToFileDescriptorOpenFlag: "
00732 "flags specify that the file is not to be opened." ) ;
00733
00734 #endif // CEYLAN_DEBUG
00735
00736
00737 int actualFlags = 0 ;
00738
00739 if ( Read & openFlag )
00740 {
00741 if ( Write & openFlag )
00742 actualFlags |= O_RDWR ;
00743 else
00744 actualFlags |= O_RDONLY ;
00745 }
00746 else
00747 {
00748 if ( Write & openFlag )
00749 actualFlags |= O_WRONLY ;
00750 }
00751
00752 if ( CreateFile & openFlag )
00753 actualFlags |= O_CREAT ;
00754
00755 if ( TruncateFile & openFlag )
00756 actualFlags |= O_TRUNC ;
00757
00758 if ( AppendFile & openFlag )
00759 actualFlags |= O_APPEND ;
00760
00761
00762
00763 return actualFlags ;
00764
00765 #endif // CEYLAN_RUNS_ON_ARM7
00766
00767
00768 #else // CEYLAN_ARCH_NINTENDO_DS
00769
00770 throw ConversionFailed( "LibfatFile::ConvertToFileDescriptorOpenFlag: "
00771 "not supported on this platform." ) ;
00772
00773 #endif // CEYLAN_ARCH_NINTENDO_DS
00774
00775 }
00776
00777
00778
00779
00780
00781
00782
00783
00784
00785
00786 void LibfatFile::FromFDtoFD( FileDescriptor from, FileDescriptor to,
00787 Size length )
00788 {
00789
00790 #if CEYLAN_ARCH_NINTENDO_DS
00791
00792 #ifdef CEYLAN_RUNS_ON_ARM7
00793
00794 throw LibfatFileException( "LibfatFile::FromFDtoFD: "
00795 "not supported on the ARM7 (no libfat available)" ) ;
00796
00797 #else // CEYLAN_RUNS_ON_ARM7
00798
00799 LibfatFileSystemManager::SecureLibfatFileSystemManager() ;
00800
00801 Size written = 0 ;
00802
00803 Size bufferSize = ( length > BigBufferSize ? BigBufferSize: length ) ;
00804
00805 Ceylan::Byte * buf = new Ceylan::Byte[ bufferSize ] ;
00806
00807 Size readCount ;
00808
00809 try
00810 {
00811
00812 while ( written < length )
00813 {
00814
00815 Size toRead = length - written ;
00816
00817 if ( toRead > bufferSize )
00818 toRead = bufferSize ;
00819
00820 readCount = FDRead( from, buf, toRead ) ;
00821
00822 FDWrite( to, buf, readCount ) ;
00823
00824 written += readCount ;
00825
00826 }
00827
00828 delete [] buf ;
00829
00830 }
00831 catch( const Ceylan::Exception & e )
00832 {
00833
00834 delete [] buf ;
00835 throw LibfatFileException(
00836 "LibfatFile::FromFDtoFD failed: " + e.toString() ) ;
00837
00838 }
00839
00840 #endif // CEYLAN_RUNS_ON_ARM7
00841
00842
00843 #else // CEYLAN_ARCH_NINTENDO_DS
00844
00845 throw LibfatFileException( "LibfatFile::FromFDtoFD: "
00846 "not supported on this platform." ) ;
00847
00848 #endif // CEYLAN_ARCH_NINTENDO_DS
00849
00850 }
00851