• Skip to content
  • Skip to link menu
KDE 4.1 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 void DeleteJobPrivate::slotReport()
00141 {
00142    Q_Q(DeleteJob);
00143    emit q->deleting( q, m_currentURL );
00144    JobPrivate::emitDeleting( q, m_currentURL);
00145 
00146    switch( state ) {
00147         case DELETEJOB_STATE_STATING:
00148         case DELETEJOB_STATE_LISTING:
00149             q->setTotalAmount(KJob::Bytes, m_totalSize);
00150             q->setTotalAmount(KJob::Files, files.count());
00151             q->setTotalAmount(KJob::Directories, dirs.count());
00152             break;
00153         case DELETEJOB_STATE_DELETING_DIRS:
00154             q->setProcessedAmount(KJob::Directories, m_processedDirs);
00155             q->emitPercent( m_processedFiles + m_processedDirs, m_totalFilesDirs );
00156             break;
00157         case DELETEJOB_STATE_DELETING_FILES:
00158             q->setProcessedAmount(KJob::Files, m_processedFiles);
00159             q->emitPercent( m_processedFiles, m_totalFilesDirs );
00160             break;
00161    }
00162 }
00163 
00164 
00165 void DeleteJobPrivate::slotEntries(KIO::Job* job, const UDSEntryList& list)
00166 {
00167     UDSEntryList::ConstIterator it = list.begin();
00168     const UDSEntryList::ConstIterator end = list.end();
00169     for (; it != end; ++it)
00170     {
00171         const UDSEntry& entry = *it;
00172         const QString displayName = entry.stringValue( KIO::UDSEntry::UDS_NAME );
00173 
00174         assert(!displayName.isEmpty());
00175         if (displayName != ".." && displayName != ".")
00176         {
00177             KUrl url;
00178             const QString urlStr = entry.stringValue( KIO::UDSEntry::UDS_URL );
00179             if ( !urlStr.isEmpty() )
00180                 url = urlStr;
00181             else {
00182                 url = ((SimpleJob *)job)->url(); // assumed to be a dir
00183                 url.addPath( displayName );
00184             }
00185 
00186             m_totalSize += (KIO::filesize_t)entry.numberValue( KIO::UDSEntry::UDS_SIZE, 0 );
00187 
00188             //kDebug(7007) << displayName << "(" << url << ")";
00189             if ( entry.isLink() )
00190                 symlinks.append( url );
00191             else if ( entry.isDir() )
00192                 dirs.append( url );
00193             else
00194                 files.append( url );
00195         }
00196     }
00197 }
00198 
00199 
00200 void DeleteJobPrivate::statNextSrc()
00201 {
00202     Q_Q(DeleteJob);
00203     //kDebug(7007) << "statNextSrc";
00204     if ( m_currentStat != m_srcList.end() )
00205     {
00206         m_currentURL = (*m_currentStat);
00207 
00208         // if the file system doesn't support deleting, we do not even stat
00209         if (!KProtocolManager::supportsDeleting(m_currentURL)) {
00210             QPointer<DeleteJob> that = q;
00211             ++m_currentStat;
00212             emit q->warning( q, buildErrorString(ERR_CANNOT_DELETE, m_currentURL.prettyUrl()) );
00213             if (that)
00214                 statNextSrc();
00215             return;
00216         }
00217         // Stat it
00218         state = DELETEJOB_STATE_STATING;
00219         KIO::SimpleJob * job = KIO::stat( m_currentURL, StatJob::SourceSide, 1, KIO::HideProgressInfo );
00220         Scheduler::scheduleJob(job);
00221         //kDebug(7007) << "KIO::stat (DeleteJob) " << m_currentURL;
00222         q->addSubjob(job);
00223     } else
00224     {
00225         m_totalFilesDirs = files.count()+symlinks.count() + dirs.count();
00226         slotReport();
00227         // Now we know which dirs hold the files we're going to delete.
00228         // To speed things up and prevent double-notification, we disable KDirWatch
00229         // on those dirs temporarily (using KDirWatch::self, that's the instanced
00230         // used by e.g. kdirlister).
00231         for ( QStringList::Iterator it = m_parentDirs.begin() ; it != m_parentDirs.end() ; ++it )
00232             KDirWatch::self()->stopDirScan( *it );
00233         state = DELETEJOB_STATE_DELETING_FILES;
00234         deleteNextFile();
00235     }
00236 }
00237 
00238 void DeleteJobPrivate::deleteNextFile()
00239 {
00240     Q_Q(DeleteJob);
00241     //kDebug(7007) << "deleteNextFile";
00242     if ( !files.isEmpty() || !symlinks.isEmpty() )
00243     {
00244         SimpleJob *job;
00245         do {
00246             // Take first file to delete out of list
00247             KUrl::List::Iterator it = files.begin();
00248             bool isLink = false;
00249             if ( it == files.end() ) // No more files
00250             {
00251                 it = symlinks.begin(); // Pick up a symlink to delete
00252                 isLink = true;
00253             }
00254             // Normal deletion
00255             // If local file, try do it directly
00256             if ( (*it).isLocalFile() && unlink( QFile::encodeName((*it).path()) ) == 0 ) {
00257                 //kdDebug(7007) << "DeleteJob deleted" << (*it).path();
00258                 job = 0;
00259                 m_processedFiles++;
00260                 if ( m_processedFiles % 300 == 0 || m_totalFilesDirs < 300) { // update progress info every 300 files
00261                     m_currentURL = *it;
00262                     slotReport();
00263                 }
00264             } else
00265             { // if remote - or if unlink() failed (we'll use the job's error handling in that case)
00266                 job = KIO::file_delete( *it, KIO::HideProgressInfo );
00267                 Scheduler::scheduleJob(job);
00268                 m_currentURL=(*it);
00269             }
00270             if ( isLink )
00271                 symlinks.erase(it);
00272             else
00273                 files.erase(it);
00274             if ( job ) {
00275                 q->addSubjob(job);
00276                 return;
00277             }
00278             // loop only if direct deletion worked (job=0) and there is something else to delete
00279         } while (!job && (!files.isEmpty() || !symlinks.isEmpty()));
00280     }
00281     state = DELETEJOB_STATE_DELETING_DIRS;
00282     deleteNextDir();
00283 }
00284 
00285 void DeleteJobPrivate::deleteNextDir()
00286 {
00287     Q_Q(DeleteJob);
00288     if ( !dirs.isEmpty() ) // some dirs to delete ?
00289     {
00290         do {
00291             // Take first dir to delete out of list - last ones first !
00292             KUrl::List::Iterator it = --dirs.end();
00293             // If local dir, try to rmdir it directly
00294             if ( (*it).isLocalFile() && ::rmdir( QFile::encodeName((*it).path()) ) == 0 ) {
00295 
00296                 m_processedDirs++;
00297                 if ( m_processedDirs % 100 == 0 ) { // update progress info every 100 dirs
00298                     m_currentURL = *it;
00299                     slotReport();
00300                 }
00301             } else {
00302                 SimpleJob* job;
00303                 if ( KProtocolManager::canDeleteRecursive( *it ) ) {
00304                     // If the ioslave supports recursive deletion of a directory, then
00305                     // we only need to send a single CMD_DEL command, so we use file_delete :)
00306                     job = KIO::file_delete( *it, KIO::HideProgressInfo );
00307                 } else {
00308                     job = KIO::rmdir( *it );
00309                 }
00310                 Scheduler::scheduleJob(job);
00311                 dirs.erase(it);
00312                 q->addSubjob( job );
00313                 return;
00314             }
00315             dirs.erase(it);
00316         } while ( !dirs.isEmpty() );
00317     }
00318 
00319     // Re-enable watching on the dirs that held the deleted files
00320     for ( QStringList::Iterator it = m_parentDirs.begin() ; it != m_parentDirs.end() ; ++it )
00321         KDirWatch::self()->restartDirScan( *it );
00322 
00323     // Finished - tell the world
00324     if ( !m_srcList.isEmpty() )
00325     {
00326         //kDebug(7007) << "KDirNotify'ing FilesRemoved " << m_srcList.toStringList();
00327         org::kde::KDirNotify::emitFilesRemoved( m_srcList.toStringList() );
00328     }
00329     if (m_reportTimer!=0)
00330        m_reportTimer->stop();
00331     q->emitResult();
00332 }
00333 
00334 // Note: I don't think this slot is connected to anywhere! -thiago
00335 void DeleteJobPrivate::slotProcessedSize( KJob*, qulonglong data_size )
00336 {
00337    Q_Q(DeleteJob);
00338    // Note: this is the same implementation as CopyJob::slotProcessedSize but
00339    // it's different from FileCopyJob::slotProcessedSize - which is why this
00340    // is not in Job.
00341 
00342    m_fileProcessedSize = data_size;
00343    q->setProcessedAmount(KJob::Bytes, m_processedSize + m_fileProcessedSize);
00344 
00345    //kDebug(7007) << (unsigned int) (m_processedSize + m_fileProcessedSize);
00346 
00347    q->setProcessedAmount(KJob::Bytes, m_processedSize + m_fileProcessedSize);
00348 
00349    // calculate percents
00350    if ( m_totalSize == 0 )
00351       q->setPercent( 100 );
00352    else
00353       q->setPercent( (unsigned long)(( (float)(m_processedSize + m_fileProcessedSize) / (float)m_totalSize ) * 100.0) );
00354 }
00355 
00356 void DeleteJob::slotResult( KJob *job )
00357 {
00358     Q_D(DeleteJob);
00359     switch ( d->state )
00360     {
00361     case DELETEJOB_STATE_STATING:
00362     {
00363         // Was there an error while stating ?
00364         if (job->error() )
00365         {
00366             // Probably : doesn't exist
00367             Job::slotResult( job ); // will set the error and emit result(this)
00368             return;
00369         }
00370 
00371         const UDSEntry entry = static_cast<StatJob*>(job)->statResult();
00372         const KUrl url = static_cast<SimpleJob*>(job)->url();
00373         const bool isLink = entry.isLink();
00374 
00375         removeSubjob( job );
00376         assert( !hasSubjobs() );
00377 
00378         // Is it a file or a dir ?
00379         if (entry.isDir() && !isLink)
00380         {
00381             // Add toplevel dir in list of dirs
00382             d->dirs.append( url );
00383             if ( url.isLocalFile() && !d->m_parentDirs.contains( url.path(KUrl::RemoveTrailingSlash) ) )
00384               d->m_parentDirs.append( url.path(KUrl::RemoveTrailingSlash) );
00385 
00386             if ( !KProtocolManager::canDeleteRecursive( url ) ) {
00387                 //kDebug(7007) << " Target is a directory ";
00388                 // List it
00389                 d->state = DELETEJOB_STATE_LISTING;
00390                 ListJob *newjob = KIO::listRecursive( url, KIO::HideProgressInfo );
00391                 newjob->setUnrestricted(true); // No KIOSK restrictions
00392                 Scheduler::scheduleJob(newjob);
00393                 connect(newjob, SIGNAL(entries( KIO::Job *,
00394                                                 const KIO::UDSEntryList& )),
00395                         SLOT( slotEntries( KIO::Job*,
00396                                            const KIO::UDSEntryList& )));
00397                 addSubjob(newjob);
00398             } else {
00399                 ++d->m_currentStat;
00400                 d->statNextSrc();
00401             }
00402         }
00403         else
00404         {
00405             if ( isLink ) {
00406                 //kDebug(7007) << " Target is a symlink";
00407                 d->symlinks.append( url );
00408             } else {
00409                 //kDebug(7007) << " Target is a file";
00410                 d->files.append( url );
00411             }
00412             if ( url.isLocalFile() && !d->m_parentDirs.contains( url.directory(KUrl::ObeyTrailingSlash) ) )
00413                 d->m_parentDirs.append( url.directory(KUrl::ObeyTrailingSlash) );
00414             ++d->m_currentStat;
00415             d->statNextSrc();
00416         }
00417     }
00418         break;
00419     case DELETEJOB_STATE_LISTING:
00420         if ( job->error() )
00421         {
00422             // Try deleting nonetheless, it may be empty (and non-listable)
00423         }
00424         removeSubjob( job );
00425         assert( !hasSubjobs() );
00426         ++d->m_currentStat;
00427         d->statNextSrc();
00428         break;
00429     case DELETEJOB_STATE_DELETING_FILES:
00430         if ( job->error() )
00431         {
00432             Job::slotResult( job ); // will set the error and emit result(this)
00433             return;
00434         }
00435         removeSubjob( job );
00436         assert( !hasSubjobs() );
00437         d->m_processedFiles++;
00438 
00439         d->deleteNextFile();
00440         break;
00441     case DELETEJOB_STATE_DELETING_DIRS:
00442         if ( job->error() )
00443         {
00444             Job::slotResult( job ); // will set the error and emit result(this)
00445             return;
00446         }
00447         removeSubjob( job );
00448         assert( !hasSubjobs() );
00449         d->m_processedDirs++;
00450         //emit processedAmount( this, KJob::Directories, d->m_processedDirs );
00451         //emitPercent( d->m_processedFiles + d->m_processedDirs, d->m_totalFilesDirs );
00452 
00453         d->deleteNextDir();
00454         break;
00455     default:
00456         assert(0);
00457     }
00458 }
00459 
00460 DeleteJob *KIO::del( const KUrl& src, JobFlags flags )
00461 {
00462     KUrl::List srcList;
00463     srcList.append( src );
00464     return DeleteJobPrivate::newJob(srcList, flags);
00465 }
00466 
00467 DeleteJob *KIO::del( const KUrl::List& src, JobFlags flags )
00468 {
00469     return DeleteJobPrivate::newJob(src, flags);
00470 }
00471 
00472 #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
  •   KJS-API
  •   WTF
  • kjsembed
  • KNewStuff
  • KParts
  • Kross
  • KUtils
  • Nepomuk
  • 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