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 "CeylanStandardDirectory.h"
00028
00029
00030 #include "CeylanFileSystemManager.h"
00031 #include "CeylanStandardFileSystemManager.h"
00032
00033 #include "CeylanLogLight.h"
00034 #include "CeylanOperators.h"
00035
00036
00037
00038 #ifdef CEYLAN_USES_CONFIG_H
00039 #include "CeylanConfig.h"
00040 #endif // CEYLAN_USES_CONFIG_H
00041
00042
00043
00044
00045 extern "C"
00046 {
00047
00048 #ifdef CEYLAN_USES_UNISTD_H
00049 #include <unistd.h>
00050 #endif // CEYLAN_USES_UNISTD_H
00051
00052 #ifdef CEYLAN_USES_DIRENT_H
00053 #include <dirent.h>
00054 #endif // CEYLAN_USES_DIRENT_H
00055
00056 #ifdef CEYLAN_USES_SYS_TYPES_H
00057 #include <sys/types.h>
00058 #endif // CEYLAN_USES_SYS_TYPES_H
00059
00060 #ifdef CEYLAN_USES_SYS_STAT_H
00061 #include <sys/stat.h>
00062 #endif // CEYLAN_USES_SYS_STAT_H
00063
00064 #ifdef CEYLAN_USES_DIRECT_H
00065 #include <direct.h>
00066 #endif // CEYLAN_USES_DIRECT_H
00067
00068 }
00069
00070
00071
00072
00073
00074
00075
00076
00077
00078
00079
00080
00081
00082
00083
00084
00085 using std::string ;
00086 using std::list ;
00087
00088 using namespace Ceylan::System ;
00089
00090
00091
00092
00094
00095 #if CEYLAN_USES_ADVANCED_FILE_ATTRIBUTES
00096
00097 const mode_t basicDirectory =
00098 S_IRWXU | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH ;
00099
00100 #else // CEYLAN_USES_ADVANCED_FILE_ATTRIBUTES
00101
00102 #ifdef CEYLAN_USES_MKDIR_TWO_ARGS
00103
00104
00105 const mode_t basicDirectory = S_IRWXU ;
00106
00107 #endif // CEYLAN_USES_MKDIR_TWO_ARGS
00108
00109 #endif // CEYLAN_USES_ADVANCED_FILE_ATTRIBUTES
00110
00111
00112
00113
00114
00115
00116
00117
00118
00119
00120
00121
00122 StandardDirectory::~StandardDirectory() throw()
00123 {
00124
00125
00126
00127 }
00128
00129
00130
00131
00132
00133
00134
00135
00136
00137
00138
00139
00140
00141
00142
00143
00144 bool StandardDirectory::hasDirectory( const string & subdirectoryName ) const
00145 {
00146
00147 #ifdef CEYLAN_USES_STAT
00148
00149 FileSystemManager * fsManager ;
00150
00151 try
00152 {
00153
00154 fsManager = & getCorrespondingFileSystemManager() ;
00155
00156 }
00157 catch( const DirectoryDelegatingException & e )
00158 {
00159
00160 throw DirectoryLookupFailed(
00161 "StandardDirectory::hasDirectory failed: " + e.toString() ) ;
00162
00163 }
00164
00165
00166 if ( ( subdirectoryName == fsManager->getAliasForCurrentDirectory() )
00167 || ( subdirectoryName == fsManager->getAliasForParentDirectory() ) )
00168 return true ;
00169
00170 struct stat buf ;
00171
00172 string tmp = fsManager->joinPath( _path, subdirectoryName ) ;
00173
00174 return ( ::stat( tmp.c_str(), & buf ) == 0 ) && S_ISDIR( buf.st_mode ) ;
00175
00176
00177 #else // CEYLAN_USES_STAT
00178
00179
00180 #ifdef CEYLAN_USES__STAT
00181
00182
00183 FileSystemManager * fsManager ;
00184
00185 try
00186 {
00187
00188 fsManager = & getCorrespondingFileSystemManager() ;
00189
00190 }
00191 catch( const DirectoryDelegatingException & e )
00192 {
00193
00194 throw DirectoryLookupFailed(
00195 "StandardDirectory::hasDirectory failed: " + e.toString() ) ;
00196
00197 }
00198
00199
00200 if ( ( subdirectoryName == fsManager->getAliasForCurrentDirectory() )
00201 || ( subdirectoryName == fsManager->getAliasForParentDirectory() ) )
00202 return true ;
00203
00204 struct _stat buf ;
00205
00206 string tmp = fsManager->joinPath( _path, subdirectoryName ) ;
00207
00208 return ( ::_stat( tmp.c_str(), & buf ) == 0 )
00209 && ( buf.st_mode & _S_IFDIR ) ;
00210
00211 #else // CEYLAN_USES__STAT
00212
00213 throw DirectoryException( "StandardDirectory::hasDirectory: "
00214 "not implemented on this platform." ) ;
00215
00216 #endif // CEYLAN_USES__STAT
00217
00218 #endif // CEYLAN_USES_STAT
00219
00220 }
00221
00222
00223
00224 bool StandardDirectory::hasFile( const string & fileName ) const
00225 {
00226
00227 #ifdef CEYLAN_USES_STAT
00228
00229 FileSystemManager * fsManager ;
00230
00231 try
00232 {
00233
00234 fsManager = & getCorrespondingFileSystemManager() ;
00235
00236 }
00237 catch( const DirectoryDelegatingException & e )
00238 {
00239
00240 throw DirectoryLookupFailed(
00241 "StandardDirectory::hasFile failed: " + e.toString() ) ;
00242
00243 }
00244
00245
00246 if ( ( fileName == fsManager->getAliasForCurrentDirectory() )
00247 || ( fileName == fsManager->getAliasForParentDirectory() ) )
00248 return false ;
00249
00250 struct stat buf ;
00251
00252 string tmp = fsManager->joinPath( _path, fileName ) ;
00253
00254 return ( ::stat( tmp.c_str(), & buf ) == 0 ) &&
00255 ( S_ISREG( buf.st_mode ) || S_ISLNK( buf.st_mode ) ) ;
00256
00257
00258 #else // CEYLAN_USES_STAT
00259
00260
00261 #ifdef CEYLAN_USES__STAT
00262
00263
00264 FileSystemManager * fsManager ;
00265
00266 try
00267 {
00268
00269 fsManager = & getCorrespondingFileSystemManager() ;
00270
00271 }
00272 catch( const DirectoryDelegatingException & e )
00273 {
00274
00275 throw DirectoryLookupFailed(
00276 "StandardDirectory::hasFile failed: " + e.toString() ) ;
00277
00278 }
00279
00280
00281 if ( ( fileName == fsManager->getAliasForCurrentDirectory() )
00282 || ( fileName == fsManager->getAliasForParentDirectory() ) )
00283 return false ;
00284
00285 struct _stat buf ;
00286
00287 string tmp = fsManager->joinPath( _path, fileName ) ;
00288
00289 return ( ::_stat( tmp.c_str(), & buf ) == 0 )
00290 && ( buf.st_mode & _S_IFREG ) ;
00291
00292 #else // CEYLAN_USES__STAT
00293
00294 throw DirectoryException( "StandardDirectory::hasFile: "
00295 "not implemented on this platform." ) ;
00296
00297 #endif // CEYLAN_USES__STAT
00298
00299 #endif // CEYLAN_USES_STAT
00300
00301 }
00302
00303
00304
00305 bool StandardDirectory::hasEntry( const string & entryName ) const
00306 {
00307
00308 #ifdef CEYLAN_USES_STAT
00309
00310 struct stat buf ;
00311
00312 string tmp ;
00313
00314 try
00315 {
00316
00317 tmp = getCorrespondingFileSystemManager().joinPath( _path, entryName ) ;
00318
00319 }
00320 catch( const DirectoryDelegatingException & e )
00321 {
00322
00323 throw DirectoryLookupFailed( "StandardDirectory::hasEntry:"
00324 + e.toString() ) ;
00325
00326 }
00327
00328 return ::stat( tmp.c_str(), & buf ) == 0 ;
00329
00330 #else // CEYLAN_USES_STAT
00331
00332
00333 #ifdef CEYLAN_USES__STAT
00334
00335
00336 struct _stat buf ;
00337
00338 string tmp ;
00339
00340 try
00341 {
00342
00343 tmp = getCorrespondingFileSystemManager().joinPath( _path, entryName ) ;
00344
00345 }
00346 catch( const DirectoryDelegatingException & e )
00347 {
00348
00349 throw DirectoryLookupFailed( "StandardDirectory::hasEntry:"
00350 + e.toString() ) ;
00351
00352 }
00353
00354 return ::_stat( tmp.c_str(), & buf ) == 0 ;
00355
00356 #else // CEYLAN_USES__STAT
00357
00358 throw DirectoryException( "StandardDirectory::hasEntry: "
00359 "not implemented on this platform." ) ;
00360
00361 #endif // CEYLAN_USES__STAT
00362
00363 #endif // CEYLAN_USES_STAT
00364
00365 }
00366
00367
00368
00369 void StandardDirectory::getSubdirectories( list<string> & subDirectories ) const
00370 {
00371
00372 #ifdef CEYLAN_USES_DIRENT_H
00373
00374 DIR * d = ::opendir( _path.c_str() ) ;
00375
00376 if ( d == 0 )
00377 throw DirectoryLookupFailed(
00378 "StandardDirectory::getSubdirectories: open: " + explainError() ) ;
00379
00380 struct dirent * de = 0 ;
00381
00382 while( ( de = ::readdir( d ) ) != 0 )
00383 {
00384
00385 string name = de->d_name ;
00386
00387
00388 if ( hasDirectory( name ) )
00389 subDirectories.push_back( name ) ;
00390
00391 }
00392
00393
00394
00395
00396
00397
00398
00399
00400
00401
00402
00403 if ( ::closedir( d ) == -1 )
00404 throw DirectoryLookupFailed(
00405 "StandardDirectory::getSubdirectories: close: " + explainError() ) ;
00406
00407
00408 #else // CEYLAN_USES_DIRENT_H
00409
00410
00411
00412
00413
00414
00415
00416 throw DirectoryLookupFailed( "StandardDirectory::getSubdirectories: "
00417 "not available on this platform." ) ;
00418
00419 #endif // CEYLAN_USES_DIRENT_H
00420
00421 }
00422
00423
00424
00425 void StandardDirectory::getFiles( list<string> & files ) const
00426 {
00427
00428 #ifdef CEYLAN_USES_DIRENT_H
00429
00430
00431 DIR * d = ::opendir( _path.c_str() ) ;
00432
00433 if ( d == 0 )
00434 throw DirectoryLookupFailed(
00435 "StandardDirectory::getFiles: open: " + explainError() ) ;
00436
00437 struct dirent * de = 0 ;
00438
00439 while( ( de = ::readdir( d ) ) != 0 )
00440 {
00441
00442 string name = de->d_name ;
00443
00444
00445 if ( hasFile( name ) )
00446 files.push_back( name ) ;
00447 }
00448
00449
00450
00451
00452
00453
00454
00455
00456
00457
00458
00459 if ( ::closedir( d ) == -1 )
00460 throw DirectoryLookupFailed(
00461 "StandardDirectory::getFiles: close: " + explainError() ) ;
00462
00463
00464 #else // CEYLAN_USES_DIRENT_H
00465
00466
00467
00468
00469
00470
00471
00472 throw DirectoryLookupFailed( "StandardDirectory::getFiles: "
00473 "not available on this platform." ) ;
00474
00475 #endif // CEYLAN_USES_DIRENT_H
00476
00477 }
00478
00479
00480
00481 void StandardDirectory::getEntries( list<string> & entries ) const
00482 {
00483
00484 #ifdef CEYLAN_USES_DIRENT_H
00485
00486 DIR * d = ::opendir( _path.c_str() ) ;
00487
00488 if ( d == 0 )
00489 throw DirectoryLookupFailed(
00490 "StandardDirectory::getEntries: open: " + explainError() ) ;
00491
00492 struct dirent * de = 0 ;
00493
00494 while( ( de = ::readdir( d ) ) != 0 )
00495 {
00496
00497 string name = de->d_name ;
00498
00499
00500 if ( hasEntry( name ) )
00501 entries.push_back( name ) ;
00502
00503 }
00504
00505
00506
00507
00508
00509
00510
00511
00512
00513
00514
00515 if ( ::closedir( d ) == -1 )
00516 throw DirectoryLookupFailed(
00517 "StandardDirectory::getEntries: close: " + explainError() ) ;
00518
00519
00520 #else // CEYLAN_USES_DIRENT_H
00521
00522
00523
00524
00525
00526
00527
00528 throw DirectoryLookupFailed( "StandardDirectory::getEntries: "
00529 "not available on this platform." ) ;
00530
00531 #endif // CEYLAN_USES_DIRENT_H
00532
00533 }
00534
00535
00536
00537 void StandardDirectory::getSortedEntries( list<string> & subDirectories,
00538 list<string> & files, list<string> & otherEntries ) const
00539 {
00540
00541 #ifdef CEYLAN_USES_DIRENT_H
00542
00543 FileSystemManager * fsManager ;
00544
00545 try
00546 {
00547
00548 fsManager = & getCorrespondingFileSystemManager() ;
00549
00550 }
00551 catch( const DirectoryDelegatingException & e )
00552 {
00553
00554 throw DirectoryLookupFailed(
00555 "StandardDirectory::getSortedEntries failed: " + e.toString() ) ;
00556
00557 }
00558
00559 DIR * d = ::opendir( _path.c_str() ) ;
00560
00561 if ( d == 0 )
00562 throw DirectoryLookupFailed(
00563 "StandardDirectory::getSortedEntries: open: " + explainError() ) ;
00564
00565 struct dirent * de = 0 ;
00566 struct stat buf ;
00567
00568 while( ( de = ::readdir( d ) ) != 0 )
00569 {
00570
00571 string name = de->d_name ;
00572 string fullname = fsManager->joinPath( _path, name ) ;
00573
00574
00575 if ( name != fsManager->getAliasForCurrentDirectory()
00576 && name != fsManager->getAliasForParentDirectory()
00577 &&::stat( fullname.c_str(), & buf ) == 0 )
00578 {
00579
00580 if ( S_ISDIR( buf.st_mode ) )
00581 subDirectories.push_back( name ) ;
00582 else
00583 #ifdef CEYLAN_USES_STAT
00584 if ( S_ISREG( buf.st_mode ) || S_ISLNK( buf.st_mode ) )
00585 #else // CEYLAN_USES_STAT
00586 if ( S_ISREG( buf.st_mode ) )
00587 #endif // CEYLAN_USES_STAT
00588 files.push_back( name ) ;
00589 else
00590 otherEntries.push_back( name ) ;
00591
00592 }
00593 }
00594
00595
00596
00597
00598
00599
00600
00601
00602
00603
00604
00605 if ( ::closedir( d ) == -1 )
00606 throw DirectoryLookupFailed(
00607 "StandardDirectory::getSortedEntries: close: " + explainError() ) ;
00608
00609
00610 #else // CEYLAN_USES_DIRENT_H
00611
00612
00613
00614
00615
00616
00617
00618 throw DirectoryLookupFailed( "StandardDirectory::getSortedEntries: "
00619 "not available on this platform." ) ;
00620
00621 #endif // CEYLAN_USES_DIRENT_H
00622
00623 }
00624
00625
00626
00627
00628
00629
00630
00631
00632 const string StandardDirectory::toString( Ceylan::VerbosityLevels level ) const
00633 {
00634
00635 return "Standard directory referring to path '" + _path + "'" ;
00636
00637 }
00638
00639
00640
00641
00642
00643
00644
00645
00646
00647 StandardDirectory & StandardDirectory::Create( const string & newDirectoryName )
00648 {
00649
00650 return * new StandardDirectory( newDirectoryName, true ) ;
00651
00652 }
00653
00654
00655
00656 StandardDirectory & StandardDirectory::Open( const string & directoryName )
00657 {
00658
00659 return * new StandardDirectory( directoryName, false ) ;
00660
00661 }
00662
00663
00664
00665 StandardDirectory::StandardDirectory( const string & directoryName,
00666 bool create ) :
00667 Directory( directoryName )
00668 {
00669
00670 #if CEYLAN_ARCH_NINTENDO_DS
00671
00672 throw DirectoryCreationFailed( "StandardDirectory constructor: "
00673 "not supported on the Nintendo DS platform." ) ;
00674
00675 #else // CEYLAN_ARCH_NINTENDO_DS
00676
00677
00678
00679 FileSystemManager & fsManager = getCorrespondingFileSystemManager() ;
00680
00681 if ( _path.empty() )
00682 _path = fsManager.getCurrentWorkingDirectoryPath() ;
00683
00684
00685
00686 removeLeadingSeparator() ;
00687
00688
00689 #ifdef CEYLAN_USES_MKDIR
00690
00691 CEYLAN_LOG( "StandardDirectory constructor: "
00692 "creating directory reference for " + _path ) ;
00693
00694 if ( create && ! isValid() )
00695 {
00696
00697 CEYLAN_LOG( "StandardDirectory constructor: directory " + _path
00698 + " does not exist yet and is to be created." ) ;
00699
00700
00701
00702
00703
00704
00705
00706 string path ;
00707
00708 #if CEYLAN_ARCH_UNIX
00709
00710
00711 if ( fsManager.isAbsolutePath( _path ) )
00712 path = fsManager.getRootDirectoryPrefix()
00713 + fsManager.getSeparatorAsString() ;
00714
00715 #endif // CEYLAN_ARCH_UNIX
00716
00717 #if CEYLAN_ARCH_WINDOWS
00718
00719
00720
00721
00722
00723
00724
00725
00726
00727 bool firstPathElement = true ;
00728
00729 #endif // CEYLAN_ARCH_WINDOWS
00730
00731
00732
00733 list<string> nodes = fsManager.splitPath( _path ) ;
00734
00735 CEYLAN_LOG( "StandardDirectory constructor: creating sub-elements." ) ;
00736
00737 for ( list<string>::const_iterator it = nodes.begin();
00738 it != nodes.end(); it++ )
00739 {
00740
00741 path += *it ;
00742
00743 #if CEYLAN_ARCH_WINDOWS
00744 if ( firstPathElement )
00745 {
00746
00747
00748 path += fsManager.getSeparatorAsString() ;
00749 firstPathElement = false ;
00750
00751 }
00752 #endif // CEYLAN_ARCH_WINDOWS
00753
00754
00755 CEYLAN_LOG( "StandardDirectory constructor: examining " + path ) ;
00756
00757 if ( ! fsManager.existsAsDirectory( path ) )
00758 {
00759
00760 CEYLAN_LOG( "StandardDirectory constructor: creating "
00761 + path ) ;
00762
00763
00764
00765 #ifdef CEYLAN_USES_MKDIR_TWO_ARGS
00766
00767 if ( ::mkdir( path.c_str(), basicDirectory ) == -1 )
00768
00769 #else // CEYLAN_USES_MKDIR_TWO_ARGS
00770
00771 #ifdef CEYLAN_USES__MKDIR
00772
00773 if ( ::_mkdir( path.c_str() )
00774 == -1 )
00775
00776 #else // CEYLAN_USES__MKDIR
00777
00778 if ( ::mkdir( path.c_str() )
00779 == -1 )
00780
00781 #endif // CEYLAN_USES__MKDIR
00782
00783 #endif // CEYLAN_USES_MKDIR_TWO_ARGS
00784 throw DirectoryCreationFailed(
00785 "StandardDirectory constructor failed for path "
00786 + path + ": " + explainError() ) ;
00787 }
00788
00789 path += fsManager.getSeparatorAsString() ;
00790
00791 }
00792
00793 }
00794
00795
00796 if ( ! fsManager.isAbsolutePath( _path ) )
00797 _path = fsManager.joinPath(
00798 fsManager.getCurrentWorkingDirectoryPath(), _path ) ;
00799
00800 CEYLAN_LOG( "Directory reference to " + _path + " done." ) ;
00801
00802 #else // CEYLAN_USES_MKDIR
00803
00804 throw DirectoryException( "StandardDirectory constructor: operation not "
00805 "available on this platform." ) ;
00806
00807 #endif // CEYLAN_USES_MKDIR
00808
00809 #endif // CEYLAN_ARCH_NINTENDO_DS
00810
00811 }
00812
00813
00814
00815
00816
00817
00818
00819 FileSystemManager & StandardDirectory::getCorrespondingFileSystemManager() const
00820 {
00821
00822 try
00823 {
00824
00825 return StandardFileSystemManager::GetStandardFileSystemManager() ;
00826
00827 }
00828 catch ( const StandardFileSystemManagerException & e )
00829 {
00830
00831 throw DirectoryDelegatingException(
00832 "StandardDirectory::getCorrespondingFileSystemManager failed: "
00833 + e.toString() ) ;
00834
00835 }
00836
00837 }
00838
00839