/*************************************************************************** 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 #include #include #include #include #include #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(*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 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 void vfs::slotKdsResult( TDEIO::Job* job){ if( job && !job->error() ){ KDirSize* kds = static_cast(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(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(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 vfs::vfs_search(const KRQuery& filter) { TQValueList result; for ( vfile *vf = vfs_getFirstFile(); vf != 0 ; vf = vfs_getNextFile() ) if (filter.match(vf)) result.append(vf); return result; } #include "vfs.moc"