diff options
Diffstat (limited to 'src/app/VFS/vfs.cpp')
-rw-r--r-- | src/app/VFS/vfs.cpp | 393 |
1 files changed, 393 insertions, 0 deletions
diff --git a/src/app/VFS/vfs.cpp b/src/app/VFS/vfs.cpp new file mode 100644 index 0000000..e6804e6 --- /dev/null +++ b/src/app/VFS/vfs.cpp @@ -0,0 +1,393 @@ +/*************************************************************************** + vfs.cpp + ------------------- + copyright : (C) 2000 by Shie Erlich & Rafi Yanai + e-mail : krusader@users.sourceforge.net + web site : http://krusader.sourceforge.net + ------------------------------------------------------------------------ + the vfs class is an extendable class which by itself does (almost) + nothing. other VFSs like the normal_vfs inherits from this class and + make it possible to use a consistent API for all types of VFSs. + + *************************************************************************** + + A + + db dD d8888b. db db .d8888. .d8b. d8888b. d88888b d8888b. + 88 ,8P' 88 `8D 88 88 88' YP d8' `8b 88 `8D 88' 88 `8D + 88,8P 88oobY' 88 88 `8bo. 88ooo88 88 88 88ooooo 88oobY' + 88`8b 88`8b 88 88 `Y8b. 88~~~88 88 88 88~~~~~ 88`8b + 88 `88. 88 `88. 88b d88 db 8D 88 88 88 .8D 88. 88 `88. + YP YD 88 YD ~Y8888P' `8888Y' YP YP Y8888D' Y88888P 88 YD + + S o u r c e F i l e + + *************************************************************************** + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + ***************************************************************************/ + +#include <unistd.h> +#include <time.h> +#include <tqeventloop.h> +#include <tdeapplication.h> +#include <klargefile.h> +#include <tqdir.h> +#include "vfs.h" +#include "../krusader.h" +#include "../defaults.h" + +vfs::vfs(TQObject* panel, bool quiet): vfs_busy(false), quietMode(quiet),disableRefresh(false),postponedRefreshURL(), + invalidated(true),panelConnected(false),vfs_tempFilesP(0),vfileIterator(0),deletePossible( true ), + deleteRequested( false ) { + + + setVfsFilesP( new vfileDict() ); + if ( panel ){ + panelConnected = true; + connect(this,TQ_SIGNAL(startUpdate()),panel,TQ_SLOT(slotStartUpdate())); + connect(this,TQ_SIGNAL(incrementalRefreshFinished( const KURL& )),panel,TQ_SLOT(slotGetStats( const KURL& ))); + } + else quietMode = true; +} + +vfs::~vfs() { + if( !deletePossible ) + fprintf( stderr, "INTERNAL ERROR: trying to delete vfs while it is used! This may cause crash. Hoping the best...\n" ); + clear(); // please don't remove this line. This informs the view about deleting the references + delete vfs_filesP; +} + +TDEIO::filesize_t vfs::vfs_totalSize(){ + TDEIO::filesize_t temp=0; + class vfile* vf=vfs_getFirstFile(); + + while (vf!=0){ + if ( (vf->vfile_getName() != ".") && ( vf->vfile_getName() != "..") + && !(vf->vfile_isDir()) ) + temp+=vf->vfile_getSize(); + vf=vfs_getNextFile(); + } + return temp; +} + +bool vfs::vfs_refresh(TDEIO::Job* job){ + if(job && job->error()){ + job->showErrorDialog(krApp); + } + return vfs_refresh(vfs_origin); +} + +KURL vfs::fromPathOrURL( const TQString &originIn ) +{ + TQString password, loginName, origin = originIn; + bool bugfix = false; + + if ( originIn.contains( ":/" ) && !originIn.startsWith( "/" ) ) + { + // breakdown the url; + /* FIXME: untill KDE fixes the bug we have to check for + passwords and users with @ in them... */ + bugfix = origin.find("@") != origin.findRev("@"); + if(bugfix){ + if(origin.find(":") != origin.findRev(":", origin.findRev("@") )){ + int passStart = origin.find( ":",origin.find(":")+1 )+1; + int passLen = origin.findRev("@")-passStart; + password = origin.mid(passStart,passLen); + origin = origin.remove(passStart-1,passLen+1); + } + if(origin.find("@") != origin.findRev("@")){ + int usrStart = origin.find( "/" )+1; + if(origin.at(usrStart) == '/') ++usrStart; + int usrLen = origin.findRev("@")-usrStart; + loginName = origin.mid(usrStart,usrLen); + origin = origin.remove(usrStart,usrLen+1); + } + } + } + KURL url = KURL::fromPathOrURL( origin ); + if(loginName.isEmpty()) loginName = url.user(); + if(password.isEmpty()) password = url.pass(); + if(bugfix){ + url.setPass(password); + url.setUser(loginName); + } + + return url; +} + +TQString vfs::pathOrURL( const KURL &originIn, int trailingSlash ) +{ + if( originIn.isLocalFile() ) + return originIn.path( trailingSlash ); + return originIn.prettyURL( trailingSlash ); +} + +void vfs::setVfsFilesP(vfileDict* dict){ + vfs_filesP=dict; + vfs_tempFilesP = new vfileDict(); + vfs_tempFilesP->setAutoDelete( true ); + dict->setAutoDelete(true); + if( vfileIterator ) delete vfileIterator; + vfileIterator = new TQDictIterator<vfile>(*dict); +} + +bool vfs::vfs_refresh(){ + if( vfs_busy ) + return false; + + if( invalidated ) // invalidated fs requires total refresh + return vfs_refresh( vfs_getOrigin() ); + + if( disableRefresh ) + { + postponedRefreshURL = vfs_getOrigin(); + return false; + } + + vfs_busy = true; + // and populate it + krConfig->setGroup("Advanced"); + int maxIncrementalRefreshFileNr = krConfig->readNumEntry("Max Incremental Refresh File Nr", 50); + krConfig->setGroup("Look&Feel"); + bool showHidden = krConfig->readBoolEntry("Show Hidden",_ShowHidden); + bool res = populateVfsList(vfs_getOrigin(),showHidden); + + TQString name; + if( res ){ + // check if the maximum incremental refresh number is achieved + int diff = vfs_filesP->count() - vfs_tempFilesP->count(); + if( diff < 0 ) + diff = -diff; + if( diff >= maxIncrementalRefreshFileNr ) + { + // total filesystem refresh is cheaper than incremental refresh for many files + clear(); + delete vfs_filesP; + setVfsFilesP( vfs_tempFilesP ); + vfs_busy = false; + + emit startUpdate(); + return true; + } + + // compare the two list emiting signals when needed;; + for( vfile* vf = vfs_getFirstFile(); vf ; ){ + name = vf->vfile_getName(); + vfile* newVf = (*vfs_tempFilesP)[name]; + if( !newVf ){ + // the file was deleted.. + emit deletedVfile(name); + vfs_filesP->remove(name); + // the remove() advance our iterator ! + vf = vfileIterator->current(); + } else { + if( *vf != *newVf ){ + // the file was changed.. + *vf = *newVf; + emit updatedVfile(vf); + } + vf=vfs_getNextFile(); + } + vfs_tempFilesP->remove(name); + } + // everything thats left is a new file + TQDictIterator<vfile> it(*vfs_tempFilesP); + for(vfile* vf=it.toFirst(); vf; vf=(++it)){ + // sanity checking + if( !vf || (*vfs_filesP)[vf->vfile_getName()] ) continue; + + vfile* newVf = new vfile(); + *newVf = *vf; + vfs_filesP->insert(newVf->vfile_getName(),newVf); + emit addedVfile(newVf); + } + } + + // delete the temporary vfiles + vfs_tempFilesP->clear(); + vfs_busy = false; + + emit incrementalRefreshFinished( vfs_origin ); + + return res; +} + +bool vfs::vfs_refresh(const KURL& origin){ + if( vfs_busy ) + return false; + + if( disableRefresh ) + { + postponedRefreshURL = origin; + return true; + } + + if( !invalidated && origin.equals(vfs_getOrigin(),true) ) return vfs_refresh(); + + vfs_busy = true; + + krConfig->setGroup("Look&Feel"); + bool showHidden = krConfig->readBoolEntry("Show Hidden",_ShowHidden); + + vfs_tempFilesP->clear(); + // and re-populate it + if (!populateVfsList(origin,showHidden) ) + { + vfs_busy = false; + return false; + } + + clear(); + delete vfs_filesP; + setVfsFilesP( vfs_tempFilesP ); + vfs_busy = false; + + emit startUpdate(); + + invalidated = false; + return true; +} + +void vfs::vfs_enableRefresh(bool enable){ + if (vfs_type != NORMAL) return; + if (disableRefresh == !enable) return; // if gets called twice by mistake + disableRefresh = quietMode = !enable; + if( enable && !postponedRefreshURL.isEmpty() ) vfs_refresh( postponedRefreshURL ); + postponedRefreshURL = KURL(); +} + +void vfs::clear() +{ + emit cleared(); + vfs_filesP->clear(); +} + +bool vfs::vfs_processEvents() { + if( deleteRequested ) + return false; + deletePossible = false; + tqApp->eventLoop() ->processEvents( TQEventLoop::AllEvents | TQEventLoop::WaitForMore ); + deletePossible = true; + if( deleteRequested ) { + emit deleteAllowed(); + return false; + } + return true; +} + +void vfs::vfs_requestDelete() { + if( deletePossible ) + emit deleteAllowed(); + deleteRequested = true; +} + +/// to be implemented +#if KDE_IS_VERSION(3,3,0) +#include <kdirsize.h> +void vfs::slotKdsResult( TDEIO::Job* job){ + if( job && !job->error() ){ + KDirSize* kds = static_cast<KDirSize*>(job); + *kds_totalSize += kds->totalSize(); + *kds_totalFiles += kds->totalFiles(); + *kds_totalDirs += kds->totalSubdirs(); + } + *kds_busy = true; +} + +void vfs::vfs_calcSpace( TQString name , TDEIO::filesize_t* totalSize, unsigned long* totalFiles, unsigned long* totalDirs, bool* stop ) { + calculateURLSize( vfs_getFile( name ), totalSize, totalFiles, totalDirs, stop ); +} + +void vfs::calculateURLSize( KURL url, TDEIO::filesize_t* totalSize, unsigned long* totalFiles, unsigned long* totalDirs, bool* stop ) { + if ( stop && *stop ) return ; + kds_busy = stop; + kds_totalSize = totalSize ; + kds_totalFiles = totalFiles; + kds_totalDirs = totalDirs; + + if( url.isLocalFile() ) { + vfs_calcSpaceLocal( url.path(-1), totalSize, totalFiles, totalDirs, stop ); + return; + } else { + stat_busy = true; + TDEIO::StatJob* statJob = TDEIO::stat( url, false ); + connect( statJob, TQ_SIGNAL( result( TDEIO::Job* ) ), this, TQ_SLOT( slotStatResultArrived( TDEIO::Job* ) ) ); + while ( !(*stop) && stat_busy ) {usleep(1000);} + if( entry.isEmpty() ) return; // statJob failed + KFileItem kfi(entry, url, true ); + if( kfi.isFile() || kfi.isLink() ) { + *totalFiles++; + *totalSize += kfi.size(); + return; + } + } + + KDirSize* kds = KDirSize::dirSizeJob( url ); + connect( kds, TQ_SIGNAL( result( TDEIO::Job* ) ), this, TQ_SLOT( slotKdsResult( TDEIO::Job* ) ) ); + while ( !(*stop) ){ + // we are in a sepetate thread - so sleeping is OK + usleep(1000); + } +} + +void vfs::vfs_calcSpaceLocal(TQString name ,TDEIO::filesize_t *totalSize,unsigned long *totalFiles,unsigned long *totalDirs, bool* stop){ + if ( *stop ) return; + if (!name.contains("/")) name = vfs_workingDir()+"/"+name; + if (name == "/proc") return; + + KDE_struct_stat stat_p; // KDE lstat is necessary as TQFileInfo and KFileItem + KDE_lstat(name.local8Bit(),&stat_p); // reports wrong size for a symbolic link + + if( S_ISLNK(stat_p.st_mode) || !S_ISDIR(stat_p.st_mode) ) { // single files are easy : ) + ++(*totalFiles); + (*totalSize) += stat_p.st_size; + } + else{ // handle directories + // avoid a nasty crash on un-readable dirs + bool readable = ::access( name.local8Bit(), R_OK | X_OK ) == 0; + if( !readable ) + return; + + TQDir dir(name); + if ( !dir.exists() ) return; + + ++(*totalDirs); + dir.setFilter(TQDir::All | TQDir::System | TQDir::Hidden); + dir.setSorting(TQDir::Name | TQDir::DirsFirst); + + // recurse on all the files in the directory + TQFileInfoList* fileList = const_cast<TQFileInfoList*>(dir.entryInfoList()); + for (TQFileInfo* qfiP = fileList->first(); qfiP != 0; qfiP = fileList->next()){ + if ( *stop ) return; + if (qfiP->fileName() != "." && qfiP->fileName() != "..") + vfs_calcSpaceLocal(name+"/"+qfiP->fileName(),totalSize,totalFiles,totalDirs,stop); + } + } +} + + +void vfs::slotStatResultArrived( TDEIO::Job* job ) { + if( !job || job->error() ) entry = TDEIO::UDSEntry(); + else entry = static_cast<TDEIO::StatJob*>(job)->statResult(); + stat_busy = false; +} + +#else +void vfs::slotKdsResult(TDEIO::Job *job){/* empty */} +void vfs::vfs_calcSpace( TQString /*name*/ , TDEIO::filesize_t* /*totalSize*/, unsigned long* /*totalFiles*/, unsigned long* /*totalDirs*/, bool* /*stop*/ ) {/* empty*/} +#endif + +TQValueList<vfile*> vfs::vfs_search(const KRQuery& filter) { + TQValueList<vfile*> result; + for ( vfile *vf = vfs_getFirstFile(); vf != 0 ; vf = vfs_getNextFile() ) + if (filter.match(vf)) + result.append(vf); + return result; +} + +#include "vfs.moc" |