• Skip to content
  • Skip to link menu
KDE 4.0 API Reference
  • KDE API Reference
  • kdelibs
  • Sitemap
  • Contact Us
 

KIO

deletejob.cpp

Go to the documentation of this file.
00001 /* This file is part of the KDE libraries
00002     Copyright 2000       Stephan Kulow <coolo@kde.org>
00003     Copyright 2000-2006  David Faure <faure@kde.org>
00004     Copyright 2000       Waldo Bastian <bastian@kde.org>
00005 
00006     This library is free software; you can redistribute it and/or
00007     modify it under the terms of the GNU Library General Public
00008     License as published by the Free Software Foundation; either
00009     version 2 of the License, or (at your option) any later version.
00010 
00011     This library is distributed in the hope that it will be useful,
00012     but WITHOUT ANY WARRANTY; without even the implied warranty of
00013     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00014     Library General Public License for more details.
00015 
00016     You should have received a copy of the GNU Library General Public License
00017     along with this library; see the file COPYING.LIB.  If not, write to
00018     the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
00019     Boston, MA 02110-1301, USA.
00020 */
00021 
00022 #include "deletejob.h"
00023 
00024 #include "kmimetype.h"
00025 #include "scheduler.h"
00026 #include "kdirwatch.h"
00027 #include "kprotocolmanager.h"
00028 #include "jobuidelegate.h"
00029 #include <kdirnotify.h>
00030 #include <kuiserverjobtracker.h>
00031 
00032 #include <kauthorized.h>
00033 #include <klocale.h>
00034 #include <kdebug.h>
00035 #include <kde_file.h>
00036 
00037 #include <assert.h>
00038 #include <stdlib.h>
00039 #include <time.h>
00040 
00041 #include <QtCore/QTimer>
00042 #include <QtCore/QFile>
00043 #include <QPointer>
00044 
00045 #include "job_p.h"
00046 
00047 namespace KIO
00048 {
00049     enum DeleteJobState {
00050         DELETEJOB_STATE_STATING,
00051         DELETEJOB_STATE_LISTING,
00052         DELETEJOB_STATE_DELETING_FILES,
00053         DELETEJOB_STATE_DELETING_DIRS
00054     };
00055 
00056     class DeleteJobPrivate: public KIO::JobPrivate
00057     {
00058     public:
00059         DeleteJobPrivate(const KUrl::List& src)
00060             : state( DELETEJOB_STATE_STATING )
00061             , m_totalSize( 0 )
00062             , m_processedSize( 0 )
00063             , m_fileProcessedSize( 0 )
00064             , m_processedFiles( 0 )
00065             , m_processedDirs( 0 )
00066             , m_totalFilesDirs( 0 )
00067             , m_srcList( src )
00068             , m_currentStat( m_srcList.begin() )
00069             , m_reportTimer( 0 )
00070         {
00071         }
00072         DeleteJobState state;
00073         KIO::filesize_t m_totalSize;
00074         KIO::filesize_t m_processedSize;
00075         KIO::filesize_t m_fileProcessedSize;
00076         int m_processedFiles;
00077         int m_processedDirs;
00078         int m_totalFilesDirs;
00079         KUrl m_currentURL;
00080         KUrl::List files;
00081         KUrl::List symlinks;
00082         KUrl::List dirs;
00083         KUrl::List m_srcList;
00084         KUrl::List::Iterator m_currentStat;
00085     QStringList m_parentDirs;
00086         QTimer *m_reportTimer;
00087 
00088         void statNextSrc();
00089         void deleteNextFile();
00090         void deleteNextDir();
00094         void slotProcessedSize( KJob*, qulonglong data_size );
00095         void slotReport();
00096         void slotStart();
00097         void slotEntries( KIO::Job*, const KIO::UDSEntryList& list );
00098 
00099         Q_DECLARE_PUBLIC(DeleteJob)
00100 
00101         static inline DeleteJob *newJob(const KUrl::List &src, JobFlags flags)
00102         {
00103             DeleteJob *job = new DeleteJob(*new DeleteJobPrivate(src));
00104             job->setUiDelegate(new JobUiDelegate);
00105             if (!(flags & HideProgressInfo))
00106                 KIO::getJobTracker()->registerJob(job);
00107             return job;
00108         }
00109     };
00110 
00111 } // namespace KIO
00112 
00113 using namespace KIO;
00114 
00115 DeleteJob::DeleteJob(DeleteJobPrivate &dd)
00116     : Job(dd)
00117 {
00118     d_func()->m_reportTimer = new QTimer(this);
00119     connect(d_func()->m_reportTimer,SIGNAL(timeout()),this,SLOT(slotReport()));
00120     //this will update the report dialog with 5 Hz, I think this is fast enough, aleXXX
00121     d_func()->m_reportTimer->start( 200 );
00122 
00123     QTimer::singleShot(0, this, SLOT(slotStart()));
00124 }
00125 
00126 DeleteJob::~DeleteJob()
00127 {
00128 }
00129 
00130 KUrl::List DeleteJob::urls() const
00131 {
00132     return d_func()->m_srcList;
00133 }
00134 
00135 void DeleteJobPrivate::slotStart()
00136 {
00137     statNextSrc();
00138 }
00139 
00140 //this is called often, so calling the functions
00141 //from Observer here directly might improve the performance a little bit
00142 //aleXXX
00143 void DeleteJobPrivate::slotReport()
00144 {
00145    Q_Q(DeleteJob);
00146    emit q->deleting( q, m_currentURL );
00147    JobPrivate::emitDeleting( q, m_currentURL);
00148 
00149    switch( state ) {
00150         case DELETEJOB_STATE_STATING:
00151         case DELETEJOB_STATE_LISTING:
00152             q->setTotalAmount(KJob::Bytes, m_totalSize);
00153             q->setTotalAmount(KJob::Files, files.count());
00154             q->setTotalAmount(KJob::Directories, dirs.count());
00155             break;
00156         case DELETEJOB_STATE_DELETING_DIRS:
00157             q->setProcessedAmount(KJob::Directories, m_processedDirs);
00158             q->emitPercent( m_processedFiles + m_processedDirs, m_totalFilesDirs );
00159             break;
00160         case DELETEJOB_STATE_DELETING_FILES:
00161             q->setProcessedAmount(KJob::Files, m_processedFiles);
00162             q->emitPercent( m_processedFiles, m_totalFilesDirs );
00163             break;
00164    }
00165 }
00166 
00167 
00168 void DeleteJobPrivate::slotEntries(KIO::Job* job, const UDSEntryList& list)
00169 {
00170     UDSEntryList::ConstIterator it = list.begin();
00171     const UDSEntryList::ConstIterator end = list.end();
00172     for (; it != end; ++it)
00173     {
00174         const UDSEntry& entry = *it;
00175         const QString displayName = entry.stringValue( KIO::UDSEntry::UDS_NAME );
00176 
00177         assert(!displayName.isEmpty());
00178         if (displayName != ".." && displayName != ".")
00179         {
00180             KUrl url;
00181             const QString urlStr = entry.stringValue( KIO::UDSEntry::UDS_URL );
00182             if ( !urlStr.isEmpty() )
00183                 url = urlStr;
00184             else {
00185                 url = ((SimpleJob *)job)->url(); // assumed to be a dir
00186                 url.addPath( displayName );
00187             }
00188 
00189             m_totalSize += (KIO::filesize_t)entry.numberValue( KIO::UDSEntry::UDS_SIZE, 0 );
00190 
00191             //kDebug(7007) << "DeleteJob::slotEntries " << displayName << " (" << url << ")";
00192             if ( entry.isLink() )
00193                 symlinks.append( url );
00194             else if ( entry.isDir() )
00195                 dirs.append( url );
00196             else
00197                 files.append( url );
00198         }
00199     }
00200 }
00201 
00202 
00203 void DeleteJobPrivate::statNextSrc()
00204 {
00205     Q_Q(DeleteJob);
00206     //kDebug(7007) << "statNextSrc";
00207     if ( m_currentStat != m_srcList.end() )
00208     {
00209         m_currentURL = (*m_currentStat);
00210 
00211         // if the file system doesn't support deleting, we do not even stat
00212         if (!KProtocolManager::supportsDeleting(m_currentURL)) {
00213             QPointer<DeleteJob> that = q;
00214             ++m_currentStat;
00215             emit q->warning( q, buildErrorString(ERR_CANNOT_DELETE, m_currentURL.prettyUrl()) );
00216             if (that)
00217                 statNextSrc();
00218             return;
00219         }
00220         // Stat it
00221         state = DELETEJOB_STATE_STATING;
00222         KIO::SimpleJob * job = KIO::stat( m_currentURL, StatJob::SourceSide, 1, KIO::HideProgressInfo );
00223         Scheduler::scheduleJob(job);
00224         //kDebug(7007) << "KIO::stat (DeleteJob) " << m_currentURL;
00225         q->addSubjob(job);
00226     } else
00227     {
00228         m_totalFilesDirs = files.count()+symlinks.count() + dirs.count();
00229         slotReport();
00230         // Now we know which dirs hold the files we're going to delete.
00231         // To speed things up and prevent double-notification, we disable KDirWatch
00232         // on those dirs temporarily (using KDirWatch::self, that's the instanced
00233         // used by e.g. kdirlister).
00234         for ( QStringList::Iterator it = m_parentDirs.begin() ; it != m_parentDirs.end() ; ++it )
00235             KDirWatch::self()->stopDirScan( *it );
00236         state = DELETEJOB_STATE_DELETING_FILES;
00237         deleteNextFile();
00238     }
00239 }
00240 
00241 void DeleteJobPrivate::deleteNextFile()
00242 {
00243     Q_Q(DeleteJob);
00244     //kDebug(7007) << "deleteNextFile";
00245     if ( !files.isEmpty() || !symlinks.isEmpty() )
00246     {
00247         SimpleJob *job;
00248         do {
00249             // Take first file to delete out of list
00250             KUrl::List::Iterator it = files.begin();
00251             bool isLink = false;
00252             if ( it == files.end() ) // No more files
00253             {
00254                 it = symlinks.begin(); // Pick up a symlink to delete
00255                 isLink = true;
00256             }
00257             // Normal deletion
00258             // If local file, try do it directly
00259             if ( (*it).isLocalFile() && unlink( QFile::encodeName((*it).path()) ) == 0 ) {
00260                 //kdDebug(7007) << "DeleteJob deleted " << (*it).path() << endl;
00261                 job = 0;
00262                 m_processedFiles++;
00263                 if ( m_processedFiles % 300 == 0 || m_totalFilesDirs < 300) { // update progress info every 300 files
00264                     m_currentURL = *it;
00265                     slotReport();
00266                 }
00267             } else
00268             { // if remote - or if unlink() failed (we'll use the job's error handling in that case)
00269                 job = KIO::file_delete( *it, KIO::HideProgressInfo );
00270                 Scheduler::scheduleJob(job);
00271                 m_currentURL=(*it);
00272             }
00273             if ( isLink )
00274                 symlinks.erase(it);
00275             else
00276                 files.erase(it);
00277             if ( job ) {
00278                 q->addSubjob(job);
00279                 return;
00280             }
00281             // loop only if direct deletion worked (job=0) and there is something else to delete
00282         } while (!job && (!files.isEmpty() || !symlinks.isEmpty()));
00283     }
00284     state = DELETEJOB_STATE_DELETING_DIRS;
00285     deleteNextDir();
00286 }
00287 
00288 void DeleteJobPrivate::deleteNextDir()
00289 {
00290     Q_Q(DeleteJob);
00291     if ( !dirs.isEmpty() ) // some dirs to delete ?
00292     {
00293         do {
00294             // Take first dir to delete out of list - last ones first !
00295             KUrl::List::Iterator it = --dirs.end();
00296             // If local dir, try to rmdir it directly
00297             if ( (*it).isLocalFile() && ::rmdir( QFile::encodeName((*it).path()) ) == 0 ) {
00298 
00299                 m_processedDirs++;
00300                 if ( m_processedDirs % 100 == 0 ) { // update progress info every 100 dirs
00301                     m_currentURL = *it;
00302                     slotReport();
00303                 }
00304             } else {
00305                 SimpleJob* job;
00306                 if ( KProtocolManager::canDeleteRecursive( *it ) ) {
00307                     // If the ioslave supports recursive deletion of a directory, then
00308                     // we only need to send a single CMD_DEL command, so we use file_delete :)
00309                     job = KIO::file_delete( *it, KIO::HideProgressInfo );
00310                 } else {
00311                     job = KIO::rmdir( *it );
00312                 }
00313                 Scheduler::scheduleJob(job);
00314                 dirs.erase(it);
00315                 q->addSubjob( job );
00316                 return;
00317             }
00318             dirs.erase(it);
00319         } while ( !dirs.isEmpty() );
00320     }
00321 
00322     // Re-enable watching on the dirs that held the deleted files
00323     for ( QStringList::Iterator it = m_parentDirs.begin() ; it != m_parentDirs.end() ; ++it )
00324         KDirWatch::self()->restartDirScan( *it );
00325 
00326     // Finished - tell the world
00327     if ( !m_srcList.isEmpty() )
00328     {
00329         //kDebug(7007) << "KDirNotify'ing FilesRemoved " << m_srcList.toStringList();
00330         org::kde::KDirNotify::emitFilesRemoved( m_srcList.toStringList() );
00331     }
00332     if (m_reportTimer!=0)
00333        m_reportTimer->stop();
00334     q->emitResult();
00335 }
00336 
00337 // Note: I don't think this slot is connected to anywhere! -thiago
00338 void DeleteJobPrivate::slotProcessedSize( KJob*, qulonglong data_size )
00339 {
00340    Q_Q(DeleteJob);
00341    // Note: this is the same implementation as CopyJob::slotProcessedSize but
00342    // it's different from FileCopyJob::slotProcessedSize - which is why this
00343    // is not in Job.
00344 
00345    m_fileProcessedSize = data_size;
00346    q->setProcessedAmount(KJob::Bytes, m_processedSize + m_fileProcessedSize);
00347 
00348    //kDebug(7007) << "DeleteJob::slotProcessedSize " << (unsigned int) (m_processedSize + m_fileProcessedSize);
00349 
00350    q->setProcessedAmount(KJob::Bytes, m_processedSize + m_fileProcessedSize);
00351 
00352    // calculate percents
00353    if ( m_totalSize == 0 )
00354       q->setPercent( 100 );
00355    else
00356       q->setPercent( (unsigned long)(( (float)(m_processedSize + m_fileProcessedSize) / (float)m_totalSize ) * 100.0) );
00357 }
00358 
00359 void DeleteJob::slotResult( KJob *job )
00360 {
00361     Q_D(DeleteJob);
00362     switch ( d->state )
00363     {
00364     case DELETEJOB_STATE_STATING:
00365     {
00366         // Was there an error while stating ?
00367         if (job->error() )
00368         {
00369             // Probably : doesn't exist
00370             Job::slotResult( job ); // will set the error and emit result(this)
00371             return;
00372         }
00373 
00374         const UDSEntry entry = static_cast<StatJob*>(job)->statResult();
00375         const KUrl url = static_cast<SimpleJob*>(job)->url();
00376         const bool isLink = entry.isLink();
00377 
00378         removeSubjob( job );
00379         assert( !hasSubjobs() );
00380 
00381         // Is it a file or a dir ?
00382         if (entry.isDir() && !isLink)
00383         {
00384             // Add toplevel dir in list of dirs
00385             d->dirs.append( url );
00386             if ( url.isLocalFile() && !d->m_parentDirs.contains( url.path(KUrl::RemoveTrailingSlash) ) )
00387               d->m_parentDirs.append( url.path(KUrl::RemoveTrailingSlash) );
00388 
00389             if ( !KProtocolManager::canDeleteRecursive( url ) ) {
00390                 //kDebug(7007) << " Target is a directory ";
00391                 // List it
00392                 d->state = DELETEJOB_STATE_LISTING;
00393                 ListJob *newjob = KIO::listRecursive( url, KIO::HideProgressInfo );
00394                 newjob->setUnrestricted(true); // No KIOSK restrictions
00395                 Scheduler::scheduleJob(newjob);
00396                 connect(newjob, SIGNAL(entries( KIO::Job *,
00397                                                 const KIO::UDSEntryList& )),
00398                         SLOT( slotEntries( KIO::Job*,
00399                                            const KIO::UDSEntryList& )));
00400                 addSubjob(newjob);
00401             } else {
00402                 ++d->m_currentStat;
00403                 d->statNextSrc();
00404             }
00405         }
00406         else
00407         {
00408             if ( isLink ) {
00409                 //kDebug(7007) << " Target is a symlink";
00410                 d->symlinks.append( url );
00411             } else {
00412                 //kDebug(7007) << " Target is a file";
00413                 d->files.append( url );
00414             }
00415             if ( url.isLocalFile() && !d->m_parentDirs.contains( url.directory(KUrl::ObeyTrailingSlash) ) )
00416                 d->m_parentDirs.append( url.directory(KUrl::ObeyTrailingSlash) );
00417             ++d->m_currentStat;
00418             d->statNextSrc();
00419         }
00420     }
00421         break;
00422     case DELETEJOB_STATE_LISTING:
00423         if ( job->error() )
00424         {
00425             // Try deleting nonetheless, it may be empty (and non-listable)
00426         }
00427         removeSubjob( job );
00428         assert( !hasSubjobs() );
00429         ++d->m_currentStat;
00430         d->statNextSrc();
00431         break;
00432     case DELETEJOB_STATE_DELETING_FILES:
00433         if ( job->error() )
00434         {
00435             Job::slotResult( job ); // will set the error and emit result(this)
00436             return;
00437         }
00438         removeSubjob( job );
00439         assert( !hasSubjobs() );
00440         d->m_processedFiles++;
00441 
00442         d->deleteNextFile();
00443         break;
00444     case DELETEJOB_STATE_DELETING_DIRS:
00445         if ( job->error() )
00446         {
00447             Job::slotResult( job ); // will set the error and emit result(this)
00448             return;
00449         }
00450         removeSubjob( job );
00451         assert( !hasSubjobs() );
00452         d->m_processedDirs++;
00453         //emit processedAmount( this, KJob::Directories, d->m_processedDirs );
00454         //emitPercent( d->m_processedFiles + d->m_processedDirs, d->m_totalFilesDirs );
00455 
00456         d->deleteNextDir();
00457         break;
00458     default:
00459         assert(0);
00460     }
00461 }
00462 
00463 DeleteJob *KIO::del( const KUrl& src, JobFlags flags )
00464 {
00465     KUrl::List srcList;
00466     srcList.append( src );
00467     return DeleteJobPrivate::newJob(srcList, flags);
00468 }
00469 
00470 DeleteJob *KIO::del( const KUrl::List& src, JobFlags flags )
00471 {
00472     return DeleteJobPrivate::newJob(src, flags);
00473 }
00474 
00475 #include "deletejob.moc"

KIO

Skip menu "KIO"
  • Main Page
  • Namespace List
  • Class Hierarchy
  • Alphabetical List
  • Class List
  • File List
  • Namespace Members
  • Class Members
  • Related Pages

kdelibs

Skip menu "kdelibs"
  • DNSSD
  • Interfaces
  •   KHexEdit
  •   KMediaPlayer
  •   KSpeech
  •   KTextEditor
  • Kate
  • kconf_update
  • KDE3Support
  •   KUnitTest
  • KDECore
  • KDED
  • KDEsu
  • KDEUI
  • KDocTools
  • KFile
  • KHTML
  • KImgIO
  • KInit
  • KIO
  • KIOSlave
  • KJS
  •   WTF
  • KJSEmbed
  • KNewStuff
  • KParts
  • Kross
  • KUtils
  • Nepomuk
  •   core
  • Phonon
  •   Backend
  • Solid
  • Sonnet
  • ThreadWeaver
Generated for kdelibs by doxygen 1.5.4
This website is maintained by Adriaan de Groot and Allen Winter.
KDE® and the K Desktop Environment® logo are registered trademarks of KDE e.V. | Legal