• Skip to content
  • Skip to link menu
  • KDE API Reference
  • kdelibs-4.9.5 API Reference
  • KDE Home
  • Contact Us
 

KIOSlave

file.cpp
Go to the documentation of this file.
00001 /*
00002    Copyright (C) 2000-2002 Stephan Kulow <coolo@kde.org>
00003    Copyright (C) 2000-2002 David Faure <faure@kde.org>
00004    Copyright (C) 2000-2002 Waldo Bastian <bastian@kde.org>
00005    Copyright (C) 2006 Allan Sandfeld Jensen <sandfeld@kde.org>
00006    Copyright (C) 2007 Thiago Macieira <thiago@kde.org>
00007 
00008    This library is free software; you can redistribute it and/or
00009    modify it under the terms of the GNU Library General Public
00010    License (LGPL) as published by the Free Software Foundation;
00011    either version 2 of the License, or (at your option) any later
00012    version.
00013 
00014    This library is distributed in the hope that it will be useful,
00015    but WITHOUT ANY WARRANTY; without even the implied warranty of
00016    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00017    Library General Public License for more details.
00018 
00019    You should have received a copy of the GNU Library General Public License
00020    along with this library; see the file COPYING.LIB.  If not, write to
00021    the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
00022    Boston, MA 02110-1301, USA.
00023 */
00024 
00025 #define QT_NO_CAST_FROM_ASCII
00026 
00027 #include "file.h"
00028 #include <QDirIterator>
00029 
00030 #include <config.h>
00031 #include <config-kioslave-file.h>
00032 
00033 
00034 #include <sys/types.h>
00035 #include <sys/wait.h>
00036 #include <sys/stat.h>
00037 #include <sys/socket.h>
00038 #ifdef HAVE_SYS_TIME_H
00039 #include <sys/time.h>
00040 #endif
00041 
00042 #include <assert.h>
00043 #include <dirent.h>
00044 #include <errno.h>
00045 #include <fcntl.h>
00046 #include <grp.h>
00047 #include <pwd.h>
00048 #include <stdio.h>
00049 #include <stdlib.h>
00050 #include <signal.h>
00051 #include <time.h>
00052 #include <utime.h>
00053 #include <unistd.h>
00054 #ifdef HAVE_STRING_H
00055 #include <string.h>
00056 #endif
00057 
00058 #include <QtCore/QByteRef>
00059 #include <QtCore/QDate>
00060 #include <QtCore/QVarLengthArray>
00061 #include <QtCore/QCoreApplication>
00062 #include <QtCore/QRegExp>
00063 #include <QtCore/QFile>
00064 #ifdef Q_WS_WIN
00065 #include <QtCore/QDir>
00066 #include <QtCore/QFileInfo>
00067 #endif
00068 
00069 #include <kdebug.h>
00070 #include <kurl.h>
00071 #include <kcomponentdata.h>
00072 #include <kconfig.h>
00073 #include <kconfiggroup.h>
00074 #include <ktemporaryfile.h>
00075 #include <klocale.h>
00076 #include <limits.h>
00077 #include <kshell.h>
00078 #include <kmountpoint.h>
00079 #include <kstandarddirs.h>
00080 
00081 #ifdef HAVE_VOLMGT
00082 #include <volmgt.h>
00083 #include <sys/mnttab.h>
00084 #endif
00085 
00086 #include <kdirnotify.h>
00087 #include <kio/ioslave_defaults.h>
00088 #include <kde_file.h>
00089 #include <kglobal.h>
00090 #include <kmimetype.h>
00091 
00092 using namespace KIO;
00093 
00094 #define MAX_IPC_SIZE (1024*32)
00095 
00096 static QString testLogFile( const QByteArray&_filename );
00097 #ifdef HAVE_POSIX_ACL
00098 static void appendACLAtoms( const QByteArray & path, UDSEntry& entry,
00099                             mode_t type, bool withACL );
00100 #endif
00101 
00102 extern "C" int KDE_EXPORT kdemain( int argc, char **argv )
00103 {
00104   QCoreApplication app( argc, argv ); // needed for QSocketNotifier
00105   KComponentData componentData( "kio_file", "kdelibs4" );
00106   ( void ) KGlobal::locale();
00107 
00108   kDebug(7101) << "Starting" << getpid();
00109 
00110   if (argc != 4)
00111   {
00112      fprintf(stderr, "Usage: kio_file protocol domain-socket1 domain-socket2\n");
00113      exit(-1);
00114   }
00115 
00116   FileProtocol slave(argv[2], argv[3]);
00117   slave.dispatchLoop();
00118 
00119   kDebug(7101) << "Done";
00120   return 0;
00121 }
00122 
00123 FileProtocol::FileProtocol( const QByteArray &pool, const QByteArray &app )
00124     : SlaveBase( "file", pool, app ), openFd(-1)
00125 {
00126 }
00127 
00128 FileProtocol::~FileProtocol()
00129 {
00130 }
00131 
00132 #ifdef HAVE_POSIX_ACL
00133 static QString aclToText(acl_t acl) {
00134     ssize_t size = 0;
00135     char* txt = acl_to_text(acl, &size);
00136     const QString ret = QString::fromLatin1(txt, size);
00137     acl_free(txt);
00138     return ret;
00139 }
00140 #endif
00141 
00142 int FileProtocol::setACL( const char *path, mode_t perm, bool directoryDefault )
00143 {
00144     int ret = 0;
00145 #ifdef HAVE_POSIX_ACL
00146 
00147     const QString ACLString = metaData(QLatin1String("ACL_STRING"));
00148     const QString defaultACLString = metaData(QLatin1String("DEFAULT_ACL_STRING"));
00149     // Empty strings mean leave as is
00150     if ( !ACLString.isEmpty() ) {
00151         acl_t acl = 0;
00152         if (ACLString == QLatin1String("ACL_DELETE")) {
00153             // user told us to delete the extended ACL, so let's write only
00154             // the minimal (UNIX permission bits) part
00155             acl = acl_from_mode( perm );
00156         }
00157         acl = acl_from_text( ACLString.toLatin1() );
00158         if ( acl_valid( acl ) == 0 ) { // let's be safe
00159             ret = acl_set_file( path, ACL_TYPE_ACCESS, acl );
00160             kDebug(7101) << "Set ACL on:" << path << "to:" << aclToText(acl);
00161         }
00162         acl_free( acl );
00163         if ( ret != 0 ) return ret; // better stop trying right away
00164     }
00165 
00166     if ( directoryDefault && !defaultACLString.isEmpty() ) {
00167         if ( defaultACLString == QLatin1String("ACL_DELETE") ) {
00168             // user told us to delete the default ACL, do so
00169             ret += acl_delete_def_file( path );
00170         } else {
00171             acl_t acl = acl_from_text( defaultACLString.toLatin1() );
00172             if ( acl_valid( acl ) == 0 ) { // let's be safe
00173                 ret += acl_set_file( path, ACL_TYPE_DEFAULT, acl );
00174                 kDebug(7101) << "Set Default ACL on:" << path << "to:" << aclToText(acl);
00175             }
00176             acl_free( acl );
00177         }
00178     }
00179 #else
00180     Q_UNUSED(path);
00181     Q_UNUSED(perm);
00182     Q_UNUSED(directoryDefault);
00183 #endif
00184     return ret;
00185 }
00186 
00187 void FileProtocol::chmod( const KUrl& url, int permissions )
00188 {
00189     const QString path(url.toLocalFile());
00190     const QByteArray _path( QFile::encodeName(path) );
00191     /* FIXME: Should be atomic */
00192     if ( KDE::chmod( path, permissions ) == -1 ||
00193         ( setACL( _path.data(), permissions, false ) == -1 ) ||
00194         /* if not a directory, cannot set default ACLs */
00195         ( setACL( _path.data(), permissions, true ) == -1 && errno != ENOTDIR ) ) {
00196 
00197         switch (errno) {
00198             case EPERM:
00199             case EACCES:
00200                 error(KIO::ERR_ACCESS_DENIED, path);
00201                 break;
00202 #if defined(ENOTSUP)
00203             case ENOTSUP: // from setACL since chmod can't return ENOTSUP
00204                 error(KIO::ERR_UNSUPPORTED_ACTION, i18n("Setting ACL for %1", path));
00205                 break;
00206 #endif
00207             case ENOSPC:
00208                 error(KIO::ERR_DISK_FULL, path);
00209                 break;
00210             default:
00211                 error(KIO::ERR_CANNOT_CHMOD, path);
00212         }
00213     } else
00214         finished();
00215 }
00216 
00217 void FileProtocol::setModificationTime( const KUrl& url, const QDateTime& mtime )
00218 {
00219     const QString path(url.toLocalFile());
00220     KDE_struct_stat statbuf;
00221     if (KDE::lstat(path, &statbuf) == 0) {
00222         struct utimbuf utbuf;
00223         utbuf.actime = statbuf.st_atime; // access time, unchanged
00224         utbuf.modtime = mtime.toTime_t(); // modification time
00225         if (KDE::utime(path, &utbuf) != 0) {
00226             // TODO: errno could be EACCES, EPERM, EROFS
00227             error(KIO::ERR_CANNOT_SETTIME, path);
00228         } else {
00229             finished();
00230         }
00231     } else {
00232         error(KIO::ERR_DOES_NOT_EXIST, path);
00233     }
00234 }
00235 
00236 void FileProtocol::mkdir( const KUrl& url, int permissions )
00237 {
00238     const QString path(url.toLocalFile());
00239 
00240     kDebug(7101) << path << "permission=" << permissions;
00241 
00242     // Remove existing file or symlink, if requested (#151851)
00243     if (metaData(QLatin1String("overwrite")) == QLatin1String("true"))
00244         QFile::remove(path);
00245 
00246     KDE_struct_stat buff;
00247     if ( KDE::lstat( path, &buff ) == -1 ) {
00248         if ( KDE::mkdir( path, 0777 /*umask will be applied*/ ) != 0 ) {
00249             if ( errno == EACCES ) {
00250                 error(KIO::ERR_ACCESS_DENIED, path);
00251                 return;
00252             } else if ( errno == ENOSPC ) {
00253                 error(KIO::ERR_DISK_FULL, path);
00254                 return;
00255             } else {
00256                 error(KIO::ERR_COULD_NOT_MKDIR, path);
00257                 return;
00258             }
00259         } else {
00260             if ( permissions != -1 )
00261                 chmod( url, permissions );
00262             else
00263                 finished();
00264             return;
00265         }
00266     }
00267 
00268     if ( S_ISDIR( buff.st_mode ) ) {
00269         kDebug(7101) << "ERR_DIR_ALREADY_EXIST";
00270         error(KIO::ERR_DIR_ALREADY_EXIST, path);
00271         return;
00272     }
00273     error(KIO::ERR_FILE_ALREADY_EXIST, path);
00274     return;
00275 }
00276 
00277 void FileProtocol::get( const KUrl& url )
00278 {
00279     if (!url.isLocalFile()) {
00280         KUrl redir(url);
00281     redir.setProtocol(config()->readEntry("DefaultRemoteProtocol", "smb"));
00282     redirection(redir);
00283     finished();
00284     return;
00285     }
00286 
00287     const QString path(url.toLocalFile());
00288     KDE_struct_stat buff;
00289     if ( KDE::stat( path, &buff ) == -1 ) {
00290         if ( errno == EACCES )
00291            error(KIO::ERR_ACCESS_DENIED, path);
00292         else
00293            error(KIO::ERR_DOES_NOT_EXIST, path);
00294         return;
00295     }
00296 
00297     if ( S_ISDIR( buff.st_mode ) ) {
00298         error(KIO::ERR_IS_DIRECTORY, path);
00299         return;
00300     }
00301     if ( !S_ISREG( buff.st_mode ) ) {
00302         error(KIO::ERR_CANNOT_OPEN_FOR_READING, path);
00303         return;
00304     }
00305 
00306     int fd = KDE::open( path, O_RDONLY);
00307     if ( fd < 0 ) {
00308         error(KIO::ERR_CANNOT_OPEN_FOR_READING, path);
00309         return;
00310     }
00311 
00312 #if HAVE_FADVISE
00313     posix_fadvise( fd, 0, 0, POSIX_FADV_SEQUENTIAL);
00314 #endif
00315 
00316     // Determine the mimetype of the file to be retrieved, and emit it.
00317     // This is mandatory in all slaves (for KRun/BrowserRun to work)
00318     // In real "remote" slaves, this is usually done using findByNameAndContent
00319     // after receiving some data. But we don't know how much data the mimemagic rules
00320     // need, so for local files, better use findByUrl with localUrl=true.
00321     KMimeType::Ptr mt = KMimeType::findByUrl( url, buff.st_mode, true /* local URL */ );
00322     emit mimeType( mt->name() );
00323     // Emit total size AFTER mimetype
00324     totalSize( buff.st_size );
00325 
00326     KIO::filesize_t processed_size = 0;
00327 
00328     const QString resumeOffset = metaData(QLatin1String("resume"));
00329     if ( !resumeOffset.isEmpty() )
00330     {
00331         bool ok;
00332         KIO::fileoffset_t offset = resumeOffset.toLongLong(&ok);
00333         if (ok && (offset > 0) && (offset < buff.st_size))
00334         {
00335             if (KDE_lseek(fd, offset, SEEK_SET) == offset)
00336             {
00337                 canResume ();
00338                 processed_size = offset;
00339                 kDebug(7101) << "Resume offset:" << KIO::number(offset);
00340             }
00341         }
00342     }
00343 
00344     char buffer[ MAX_IPC_SIZE ];
00345     QByteArray array;
00346 
00347     while( 1 )
00348     {
00349        int n = ::read( fd, buffer, MAX_IPC_SIZE );
00350        if (n == -1)
00351        {
00352           if (errno == EINTR)
00353               continue;
00354           error(KIO::ERR_COULD_NOT_READ, path);
00355           ::close(fd);
00356           return;
00357        }
00358        if (n == 0)
00359           break; // Finished
00360 
00361        array = QByteArray::fromRawData(buffer, n);
00362        data( array );
00363        array.clear();
00364 
00365        processed_size += n;
00366        processedSize( processed_size );
00367 
00368        //kDebug(7101) << "Processed: " << KIO::number (processed_size);
00369     }
00370 
00371     data( QByteArray() );
00372 
00373     ::close( fd );
00374 
00375     processedSize( buff.st_size );
00376     finished();
00377 }
00378 
00379 int write_all(int fd, const char *buf, size_t len)
00380 {
00381    while (len > 0)
00382    {
00383       ssize_t written = write(fd, buf, len);
00384       if (written < 0)
00385       {
00386           if (errno == EINTR)
00387              continue;
00388           return -1;
00389       }
00390       buf += written;
00391       len -= written;
00392    }
00393    return 0;
00394 }
00395 
00396 void FileProtocol::open(const KUrl &url, QIODevice::OpenMode mode)
00397 {
00398     kDebug(7101) << url;
00399 
00400     openPath = url.toLocalFile();
00401     KDE_struct_stat buff;
00402     if (KDE::stat(openPath, &buff) == -1) {
00403         if ( errno == EACCES )
00404            error(KIO::ERR_ACCESS_DENIED, openPath);
00405         else
00406            error(KIO::ERR_DOES_NOT_EXIST, openPath);
00407         return;
00408     }
00409 
00410     if ( S_ISDIR( buff.st_mode ) ) {
00411         error(KIO::ERR_IS_DIRECTORY, openPath);
00412         return;
00413     }
00414     if ( !S_ISREG( buff.st_mode ) ) {
00415         error(KIO::ERR_CANNOT_OPEN_FOR_READING, openPath);
00416         return;
00417     }
00418 
00419     int flags = 0;
00420     if (mode & QIODevice::ReadOnly) {
00421         if (mode & QIODevice::WriteOnly) {
00422             flags = O_RDWR | O_CREAT;
00423         } else {
00424             flags = O_RDONLY;
00425         }
00426     } else if (mode & QIODevice::WriteOnly) {
00427         flags = O_WRONLY | O_CREAT;
00428     }
00429 
00430     if (mode & QIODevice::Append) {
00431         flags |= O_APPEND;
00432     } else if (mode & QIODevice::Truncate) {
00433         flags |= O_TRUNC;
00434     }
00435 
00436     int fd = -1;
00437     if ( flags & O_CREAT)
00438         fd = KDE::open( openPath, flags, 0666);
00439     else
00440         fd = KDE::open( openPath, flags);
00441     if ( fd < 0 ) {
00442         error(KIO::ERR_CANNOT_OPEN_FOR_READING, openPath);
00443         return;
00444     }
00445     // Determine the mimetype of the file to be retrieved, and emit it.
00446     // This is mandatory in all slaves (for KRun/BrowserRun to work).
00447     // If we're not opening the file ReadOnly or ReadWrite, don't attempt to
00448     // read the file and send the mimetype.
00449     if (mode & QIODevice::ReadOnly){
00450         KMimeType::Ptr mt = KMimeType::findByUrl( url, buff.st_mode, true /* local URL */ );
00451         emit mimeType( mt->name() );
00452    }
00453 
00454     totalSize( buff.st_size );
00455     position( 0 );
00456 
00457     emit opened();
00458     openFd = fd;
00459 }
00460 
00461 void FileProtocol::read(KIO::filesize_t bytes)
00462 {
00463     kDebug(7101) << "File::open -- read";
00464     Q_ASSERT(openFd != -1);
00465 
00466     QVarLengthArray<char> buffer(bytes);
00467     while (true) {
00468         int res;
00469         do {
00470             res = ::read(openFd, buffer.data(), bytes);
00471         } while (res == -1 && errno == EINTR);
00472 
00473         if (res > 0) {
00474             QByteArray array = QByteArray::fromRawData(buffer.data(), res);
00475             data( array );
00476             bytes -= res;
00477         } else {
00478             // empty array designates eof
00479             data(QByteArray());
00480             if (res != 0) {
00481                 error(KIO::ERR_COULD_NOT_READ, openPath);
00482                 close();
00483             }
00484             break;
00485         }
00486         if (bytes <= 0) break;
00487     }
00488 }
00489 
00490 void FileProtocol::write(const QByteArray &data)
00491 {
00492     kDebug(7101) << "File::open -- write";
00493     Q_ASSERT(openFd != -1);
00494 
00495     if (write_all(openFd, data.constData(), data.size())) {
00496         if (errno == ENOSPC) { // disk full
00497             error(KIO::ERR_DISK_FULL, openPath);
00498             close();
00499         } else {
00500             kWarning(7101) << "Couldn't write. Error:" << strerror(errno);
00501             error(KIO::ERR_COULD_NOT_WRITE, openPath);
00502             close();
00503         }
00504     } else {
00505         written(data.size());
00506     }
00507 }
00508 
00509 void FileProtocol::seek(KIO::filesize_t offset)
00510 {
00511     kDebug(7101) << "File::open -- seek";
00512     Q_ASSERT(openFd != -1);
00513 
00514     int res = KDE_lseek(openFd, offset, SEEK_SET);
00515     if (res != -1) {
00516         position( offset );
00517     } else {
00518         error(KIO::ERR_COULD_NOT_SEEK, openPath);
00519         close();
00520     }
00521 }
00522 
00523 void FileProtocol::close()
00524 {
00525     kDebug(7101) << "File::open -- close ";
00526     Q_ASSERT(openFd != -1);
00527 
00528     ::close( openFd );
00529     openFd = -1;
00530     openPath.clear();
00531 
00532     finished();
00533 }
00534 
00535 void FileProtocol::put( const KUrl& url, int _mode, KIO::JobFlags _flags )
00536 {
00537     const QString dest_orig = url.toLocalFile();
00538 
00539     kDebug(7101) << dest_orig << "mode=" << _mode;
00540 
00541     QString dest_part(dest_orig + QLatin1String(".part"));
00542 
00543     KDE_struct_stat buff_orig;
00544     const bool bOrigExists = (KDE::lstat(dest_orig, &buff_orig) != -1);
00545     bool bPartExists = false;
00546     const bool bMarkPartial = config()->readEntry("MarkPartial", true);
00547 
00548     if (bMarkPartial)
00549     {
00550         KDE_struct_stat buff_part;
00551         bPartExists = (KDE::stat( dest_part, &buff_part ) != -1);
00552 
00553         if (bPartExists && !(_flags & KIO::Resume) && !(_flags & KIO::Overwrite) && buff_part.st_size > 0 && S_ISREG(buff_part.st_mode))
00554         {
00555             kDebug(7101) << "calling canResume with" << KIO::number(buff_part.st_size);
00556 
00557             // Maybe we can use this partial file for resuming
00558             // Tell about the size we have, and the app will tell us
00559             // if it's ok to resume or not.
00560             _flags |= canResume( buff_part.st_size ) ? KIO::Resume : KIO::DefaultFlags;
00561 
00562             kDebug(7101) << "got answer" << (_flags & KIO::Resume);
00563         }
00564     }
00565 
00566     if ( bOrigExists && !(_flags & KIO::Overwrite) && !(_flags & KIO::Resume))
00567     {
00568         if (S_ISDIR(buff_orig.st_mode))
00569             error( KIO::ERR_DIR_ALREADY_EXIST, dest_orig );
00570         else
00571             error( KIO::ERR_FILE_ALREADY_EXIST, dest_orig );
00572         return;
00573     }
00574 
00575     int result;
00576     QString dest;
00577     QByteArray _dest;
00578 
00579     int fd = -1;
00580 
00581     // Loop until we got 0 (end of data)
00582     do
00583     {
00584         QByteArray buffer;
00585         dataReq(); // Request for data
00586         result = readData( buffer );
00587 
00588         if (result >= 0)
00589         {
00590             if (dest.isEmpty())
00591             {
00592                 if (bMarkPartial)
00593                 {
00594                     kDebug(7101) << "Appending .part extension to" << dest_orig;
00595                     dest = dest_part;
00596                     if ( bPartExists && !(_flags & KIO::Resume) )
00597                     {
00598                         kDebug(7101) << "Deleting partial file" << dest_part;
00599                         QFile::remove( dest_part );
00600                         // Catch errors when we try to open the file.
00601                     }
00602                 }
00603                 else
00604                 {
00605                     dest = dest_orig;
00606                     if ( bOrigExists && !(_flags & KIO::Resume) )
00607                     {
00608                         kDebug(7101) << "Deleting destination file" << dest_orig;
00609                         QFile::remove( dest_orig );
00610                         // Catch errors when we try to open the file.
00611                     }
00612                 }
00613 
00614                 if ( (_flags & KIO::Resume) )
00615                 {
00616                     fd = KDE::open( dest, O_RDWR );  // append if resuming
00617                     KDE_lseek(fd, 0, SEEK_END); // Seek to end
00618                 }
00619                 else
00620                 {
00621                     // WABA: Make sure that we keep writing permissions ourselves,
00622                     // otherwise we can be in for a surprise on NFS.
00623                     mode_t initialMode;
00624                     if (_mode != -1)
00625                         initialMode = _mode | S_IWUSR | S_IRUSR;
00626                     else
00627                         initialMode = 0666;
00628 
00629                     fd = KDE::open(dest, O_CREAT | O_TRUNC | O_WRONLY, initialMode);
00630                 }
00631 
00632                 if ( fd < 0 )
00633                 {
00634                     kDebug(7101) << "####################### COULD NOT WRITE" << dest << "_mode=" << _mode;
00635                     kDebug(7101) << "errno==" << errno << "(" << strerror(errno) << ")";
00636                     if ( errno == EACCES )
00637                         error(KIO::ERR_WRITE_ACCESS_DENIED, dest);
00638                     else
00639                         error(KIO::ERR_CANNOT_OPEN_FOR_WRITING, dest);
00640                     return;
00641                 }
00642             }
00643 
00644             if (write_all( fd, buffer.data(), buffer.size()))
00645             {
00646                 if ( errno == ENOSPC ) // disk full
00647                 {
00648                   error(KIO::ERR_DISK_FULL, dest_orig);
00649                   result = -2; // means: remove dest file
00650                 }
00651                 else
00652                 {
00653                   kWarning(7101) << "Couldn't write. Error:" << strerror(errno);
00654                   error(KIO::ERR_COULD_NOT_WRITE, dest_orig);
00655                   result = -1;
00656                 }
00657             }
00658         }
00659     }
00660     while ( result > 0 );
00661 
00662     // An error occurred deal with it.
00663     if (result < 0)
00664     {
00665         kDebug(7101) << "Error during 'put'. Aborting.";
00666 
00667         if (fd != -1)
00668         {
00669           ::close(fd);
00670 
00671           KDE_struct_stat buff;
00672           if (bMarkPartial && KDE::stat( dest, &buff ) == 0)
00673           {
00674             int size = config()->readEntry("MinimumKeepSize", DEFAULT_MINIMUM_KEEP_SIZE);
00675             if (buff.st_size <  size)
00676               remove(_dest.data());
00677           }
00678         }
00679 
00680         ::exit(255);
00681     }
00682 
00683     if ( fd == -1 ) // we got nothing to write out, so we never opened the file
00684     {
00685         finished();
00686         return;
00687     }
00688 
00689     if ( ::close(fd) )
00690     {
00691         kWarning(7101) << "Error when closing file descriptor:" << strerror(errno);
00692         error(KIO::ERR_COULD_NOT_WRITE, dest_orig);
00693         return;
00694     }
00695 
00696     // after full download rename the file back to original name
00697     if ( bMarkPartial )
00698     {
00699         // If the original URL is a symlink and we were asked to overwrite it,
00700         // remove the symlink first. This ensures that we do not overwrite the
00701         // current source if the symlink points to it.
00702         if( (_flags & KIO::Overwrite) && S_ISLNK( buff_orig.st_mode ) )
00703           QFile::remove( dest_orig );
00704         if ( KDE::rename( dest, dest_orig ) )
00705         {
00706             kWarning(7101) << " Couldn't rename " << _dest << " to " << dest_orig;
00707             error(KIO::ERR_CANNOT_RENAME_PARTIAL, dest_orig);
00708             return;
00709         }
00710         org::kde::KDirNotify::emitFileRenamed(dest, dest_orig);
00711     }
00712 
00713     // set final permissions
00714     if ( _mode != -1 && !(_flags & KIO::Resume) )
00715     {
00716         if (KDE::chmod(dest_orig, _mode) != 0)
00717         {
00718             // couldn't chmod. Eat the error if the filesystem apparently doesn't support it.
00719             KMountPoint::Ptr mp = KMountPoint::currentMountPoints().findByPath(dest_orig);
00720             if (mp && mp->testFileSystemFlag(KMountPoint::SupportsChmod))
00721                  warning( i18n( "Could not change permissions for\n%1" ,  dest_orig ) );
00722         }
00723     }
00724 
00725     // set modification time
00726     const QString mtimeStr = metaData(QLatin1String("modified"));
00727     if ( !mtimeStr.isEmpty() ) {
00728         QDateTime dt = QDateTime::fromString( mtimeStr, Qt::ISODate );
00729         if ( dt.isValid() ) {
00730             KDE_struct_stat dest_statbuf;
00731             if (KDE::stat( dest_orig, &dest_statbuf ) == 0) {
00732                 struct timeval utbuf[2];
00733                 // access time
00734                 utbuf[0].tv_sec = dest_statbuf.st_atime; // access time, unchanged  ## TODO preserve msec
00735                 utbuf[0].tv_usec = 0;
00736                 // modification time
00737                 utbuf[1].tv_sec = dt.toTime_t();
00738                 utbuf[1].tv_usec = dt.time().msec() * 1000;
00739                 utimes( QFile::encodeName(dest_orig), utbuf );
00740             }
00741         }
00742 
00743     }
00744 
00745     // We have done our job => finish
00746     finished();
00747 }
00748 
00749 QString FileProtocol::getUserName( uid_t uid ) const
00750 {
00751     if ( !mUsercache.contains( uid ) ) {
00752         struct passwd *user = getpwuid( uid );
00753         if ( user ) {
00754             mUsercache.insert( uid, QString::fromLatin1(user->pw_name) );
00755         }
00756         else
00757             return QString::number( uid );
00758     }
00759     return mUsercache[uid];
00760 }
00761 
00762 QString FileProtocol::getGroupName( gid_t gid ) const
00763 {
00764     if ( !mGroupcache.contains( gid ) ) {
00765         struct group *grp = getgrgid( gid );
00766         if ( grp ) {
00767             mGroupcache.insert( gid, QString::fromLatin1(grp->gr_name) );
00768         }
00769         else
00770             return QString::number( gid );
00771     }
00772     return mGroupcache[gid];
00773 }
00774 
00775 bool FileProtocol::createUDSEntry( const QString & filename, const QByteArray & path, UDSEntry & entry,
00776                                    short int details, bool withACL )
00777 {
00778 #ifndef HAVE_POSIX_ACL
00779     Q_UNUSED(withACL);
00780 #endif
00781     assert(entry.count() == 0); // by contract :-)
00782     // entry.reserve( 8 ); // speed up QHash insertion
00783 
00784     entry.insert( KIO::UDSEntry::UDS_NAME, filename );
00785 
00786     mode_t type;
00787     mode_t access;
00788     KDE_struct_stat buff;
00789 
00790     if ( KDE_lstat( path.data(), &buff ) == 0 )  {
00791 
00792         if (details > 2) {
00793             entry.insert( KIO::UDSEntry::UDS_DEVICE_ID, buff.st_dev );
00794             entry.insert( KIO::UDSEntry::UDS_INODE, buff.st_ino );
00795         }
00796 
00797         if (S_ISLNK(buff.st_mode)) {
00798 
00799             char buffer2[ 1000 ];
00800             int n = readlink( path.data(), buffer2, 999 );
00801             if ( n != -1 ) {
00802                 buffer2[ n ] = 0;
00803             }
00804 
00805             entry.insert( KIO::UDSEntry::UDS_LINK_DEST, QFile::decodeName( buffer2 ) );
00806 
00807             // A symlink -> follow it only if details>1
00808             if ( details > 1 && KDE_stat( path.data(), &buff ) == -1 ) {
00809                 // It is a link pointing to nowhere
00810                 type = S_IFMT - 1;
00811                 access = S_IRWXU | S_IRWXG | S_IRWXO;
00812 
00813                 entry.insert( KIO::UDSEntry::UDS_FILE_TYPE, type );
00814                 entry.insert( KIO::UDSEntry::UDS_ACCESS, access );
00815                 entry.insert( KIO::UDSEntry::UDS_SIZE, 0LL );
00816                 goto notype;
00817 
00818             }
00819         }
00820     } else {
00821         // kWarning() << "lstat didn't work on " << path.data();
00822         return false;
00823     }
00824 
00825     type = buff.st_mode & S_IFMT; // extract file type
00826     access = buff.st_mode & 07777; // extract permissions
00827 
00828     entry.insert( KIO::UDSEntry::UDS_FILE_TYPE, type );
00829     entry.insert( KIO::UDSEntry::UDS_ACCESS, access );
00830 
00831     entry.insert( KIO::UDSEntry::UDS_SIZE, buff.st_size );
00832 
00833 #ifdef HAVE_POSIX_ACL
00834     if (details > 0) {
00835         /* Append an atom indicating whether the file has extended acl information
00836          * and if withACL is specified also one with the acl itself. If it's a directory
00837          * and it has a default ACL, also append that. */
00838         appendACLAtoms( path, entry, type, withACL );
00839     }
00840 #endif
00841 
00842  notype:
00843     if (details > 0) {
00844         entry.insert( KIO::UDSEntry::UDS_MODIFICATION_TIME, buff.st_mtime );
00845         entry.insert( KIO::UDSEntry::UDS_USER, getUserName( buff.st_uid ) );
00846         entry.insert( KIO::UDSEntry::UDS_GROUP, getGroupName( buff.st_gid ) );
00847         entry.insert( KIO::UDSEntry::UDS_ACCESS_TIME, buff.st_atime );
00848     }
00849 
00850     // Note: buff.st_ctime isn't the creation time !
00851     // We made that mistake for KDE 2.0, but it's in fact the
00852     // "file status" change time, which we don't care about.
00853 
00854     return true;
00855 }
00856 
00857 void FileProtocol::special( const QByteArray &data)
00858 {
00859     int tmp;
00860     QDataStream stream(data);
00861 
00862     stream >> tmp;
00863     switch (tmp) {
00864     case 1:
00865       {
00866     QString fstype, dev, point;
00867     qint8 iRo;
00868 
00869     stream >> iRo >> fstype >> dev >> point;
00870 
00871     bool ro = ( iRo != 0 );
00872 
00873     kDebug(7101) << "MOUNTING fstype=" << fstype << " dev=" << dev << " point=" << point << " ro=" << ro;
00874     bool ok = pmount( dev );
00875     if (ok)
00876         finished();
00877     else
00878         mount( ro, fstype.toAscii(), dev, point );
00879 
00880       }
00881       break;
00882     case 2:
00883       {
00884     QString point;
00885     stream >> point;
00886     bool ok = pumount( point );
00887     if (ok)
00888         finished();
00889     else
00890         unmount( point );
00891       }
00892       break;
00893 
00894     default:
00895       break;
00896     }
00897 }
00898 
00899 void FileProtocol::mount( bool _ro, const char *_fstype, const QString& _dev, const QString& _point )
00900 {
00901     kDebug(7101) << "fstype=" << _fstype;
00902 
00903 #ifndef _WIN32_WCE
00904 #ifdef HAVE_VOLMGT
00905     /*
00906      *  support for Solaris volume management
00907      */
00908     QString err;
00909     QByteArray devname = QFile::encodeName( _dev );
00910 
00911     if( volmgt_running() ) {
00912 //      kDebug(7101) << "VOLMGT: vold ok.";
00913         if( volmgt_check( devname.data() ) == 0 ) {
00914             kDebug(7101) << "VOLMGT: no media in "
00915                     << devname.data();
00916             err = i18n("No Media inserted or Media not recognized.");
00917             error( KIO::ERR_COULD_NOT_MOUNT, err );
00918             return;
00919         } else {
00920             kDebug(7101) << "VOLMGT: " << devname.data()
00921                 << ": media ok";
00922             finished();
00923             return;
00924         }
00925     } else {
00926         err = i18n("\"vold\" is not running.");
00927         kDebug(7101) << "VOLMGT: " << err;
00928         error( KIO::ERR_COULD_NOT_MOUNT, err );
00929         return;
00930     }
00931 #else
00932 
00933 
00934     KTemporaryFile tmpFile;
00935     tmpFile.setAutoRemove(false);
00936     tmpFile.open();
00937     QByteArray tmpFileName = QFile::encodeName(tmpFile.fileName());
00938     QByteArray dev;
00939     if (_dev.startsWith(QLatin1String("LABEL="))) { // turn LABEL=foo into -L foo (#71430)
00940         QString labelName = _dev.mid( 6 );
00941         dev = "-L ";
00942         dev += QFile::encodeName( KShell::quoteArg( labelName ) ); // is it correct to assume same encoding as filesystem?
00943     } else if (_dev.startsWith(QLatin1String("UUID="))) { // and UUID=bar into -U bar
00944         QString uuidName = _dev.mid( 5 );
00945         dev = "-U ";
00946         dev += QFile::encodeName( KShell::quoteArg( uuidName ) );
00947     }
00948     else
00949         dev = QFile::encodeName( KShell::quoteArg(_dev) ); // get those ready to be given to a shell
00950 
00951     QByteArray point = QFile::encodeName( KShell::quoteArg(_point) );
00952     bool fstype_empty = !_fstype || !*_fstype;
00953     QByteArray fstype = KShell::quoteArg(QString::fromLatin1(_fstype)).toLatin1(); // good guess
00954     QByteArray readonly = _ro ? "-r" : "";
00955     QString epath = QString::fromLocal8Bit(qgetenv("PATH"));
00956     QString path = QLatin1String("/sbin:/bin");
00957     if(!epath.isEmpty())
00958         path += QLatin1String(":") + epath;
00959     QByteArray mountProg = KGlobal::dirs()->findExe(QLatin1String("mount"), path).toLocal8Bit();
00960     if (mountProg.isEmpty()){
00961       error( KIO::ERR_COULD_NOT_MOUNT, i18n("Could not find program \"mount\""));
00962       return;
00963     }
00964 
00965     // Two steps, in case mount doesn't like it when we pass all options
00966     for ( int step = 0 ; step <= 1 ; step++ )
00967     {
00968         QByteArray buffer = mountProg + ' ';
00969         // Mount using device only if no fstype nor mountpoint (KDE-1.x like)
00970         if ( !dev.isEmpty() && _point.isEmpty() && fstype_empty )
00971             buffer += dev;
00972         else
00973           // Mount using the mountpoint, if no fstype nor device (impossible in first step)
00974           if ( !_point.isEmpty() && dev.isEmpty() && fstype_empty )
00975               buffer += point;
00976           else
00977             // mount giving device + mountpoint but no fstype
00978             if ( !_point.isEmpty() && !dev.isEmpty() && fstype_empty )
00979                 buffer += readonly + ' ' + dev + ' ' + point;
00980             else
00981               // mount giving device + mountpoint + fstype
00982 #if defined(__svr4__) && defined(Q_OS_SOLARIS) // MARCO for Solaris 8 and I
00983                 // believe this is true for SVR4 in general
00984                 buffer += "-F " + fstype + ' ' + (_ro ? "-oro" : "") + ' ' + dev + ' ' + point;
00985 #else
00986                 buffer += readonly + " -t " + fstype + ' ' + dev + ' ' + point;
00987 #endif
00988         buffer += " 2>" + tmpFileName;
00989         kDebug(7101) << buffer;
00990 
00991         int mount_ret = system( buffer.constData() );
00992 
00993         QString err = testLogFile( tmpFileName );
00994         if ( err.isEmpty() && mount_ret == 0)
00995         {
00996             finished();
00997             return;
00998         }
00999         else
01000         {
01001             // Didn't work - or maybe we just got a warning
01002             KMountPoint::Ptr mp = KMountPoint::currentMountPoints().findByDevice( _dev );
01003             // Is the device mounted ?
01004             if ( mp && mount_ret == 0)
01005             {
01006                 kDebug(7101) << "mount got a warning:" << err;
01007                 warning( err );
01008                 finished();
01009                 return;
01010             }
01011             else
01012             {
01013                 if ( (step == 0) && !_point.isEmpty())
01014                 {
01015                     kDebug(7101) << err;
01016                     kDebug(7101) << "Mounting with those options didn't work, trying with only mountpoint";
01017                     fstype = "";
01018                     fstype_empty = true;
01019                     dev = "";
01020                     // The reason for trying with only mountpoint (instead of
01021                     // only device) is that some people (hi Malte!) have the
01022                     // same device associated with two mountpoints
01023                     // for different fstypes, like /dev/fd0 /mnt/e2floppy and
01024                     // /dev/fd0 /mnt/dosfloppy.
01025                     // If the user has the same mountpoint associated with two
01026                     // different devices, well they shouldn't specify the
01027                     // mountpoint but just the device.
01028                 }
01029                 else
01030                 {
01031                     error( KIO::ERR_COULD_NOT_MOUNT, err );
01032                     return;
01033                 }
01034             }
01035         }
01036     }
01037 #endif /* ! HAVE_VOLMGT */
01038 #else
01039     QString err;
01040     err = i18n("mounting is not supported by wince.");
01041     error( KIO::ERR_COULD_NOT_MOUNT, err );
01042 #endif
01043 
01044 }
01045 
01046 
01047 void FileProtocol::unmount( const QString& _point )
01048 {
01049 #ifndef _WIN32_WCE
01050     QByteArray buffer;
01051 
01052     KTemporaryFile tmpFile;
01053     tmpFile.setAutoRemove(false);
01054     tmpFile.open();
01055     QByteArray tmpFileName = QFile::encodeName(tmpFile.fileName());
01056     QString err;
01057 
01058 #ifdef HAVE_VOLMGT
01059     /*
01060      *  support for Solaris volume management
01061      */
01062     char *devname;
01063     char *ptr;
01064     FILE *mnttab;
01065     struct mnttab mnt;
01066 
01067     if( volmgt_running() ) {
01068         kDebug(7101) << "VOLMGT: looking for "
01069             << _point.toLocal8Bit();
01070 
01071         if( (mnttab = KDE_fopen( MNTTAB, "r" )) == NULL ) {
01072             err = QLatin1String("could not open mnttab");
01073             kDebug(7101) << "VOLMGT: " << err;
01074             error( KIO::ERR_COULD_NOT_UNMOUNT, err );
01075             return;
01076         }
01077 
01078         /*
01079          *  since there's no way to derive the device name from
01080          *  the mount point through the volmgt library (and
01081          *  media_findname() won't work in this case), we have to
01082          *  look ourselves...
01083          */
01084         devname = NULL;
01085         rewind( mnttab );
01086         while( getmntent( mnttab, &mnt ) == 0 ) {
01087             if( strcmp( _point.toLocal8Bit(), mnt.mnt_mountp ) == 0 ){
01088                 devname = mnt.mnt_special;
01089                 break;
01090             }
01091         }
01092         fclose( mnttab );
01093 
01094         if( devname == NULL ) {
01095             err = QLatin1String("not in mnttab");
01096             kDebug(7101) << "VOLMGT: "
01097                 << QFile::encodeName(_point).data()
01098                 << ": " << err;
01099             error( KIO::ERR_COULD_NOT_UNMOUNT, err );
01100             return;
01101         }
01102 
01103         /*
01104          *  strip off the directory name (volume name)
01105          *  the eject(1) command will handle unmounting and
01106          *  physically eject the media (if possible)
01107          */
01108         ptr = strrchr( devname, '/' );
01109         *ptr = '\0';
01110                 QByteArray qdevname(QFile::encodeName(KShell::quoteArg(QFile::decodeName(QByteArray(devname)))).data());
01111         buffer = "/usr/bin/eject " + qdevname + " 2>" + tmpFileName;
01112         kDebug(7101) << "VOLMGT: eject " << qdevname;
01113 
01114         /*
01115          *  from eject(1): exit status == 0 => need to manually eject
01116          *                 exit status == 4 => media was ejected
01117          */
01118         if( WEXITSTATUS( system( buffer.constData() )) == 4 ) {
01119             /*
01120              *  this is not an error, so skip "testLogFile()"
01121              *  to avoid wrong/confusing error popup. The
01122              *  temporary file is removed by KTemporaryFile's
01123              *  destructor, so don't do that manually.
01124              */
01125             finished();
01126             return;
01127         }
01128     } else {
01129         /*
01130          *  eject(1) should do its job without vold(1M) running,
01131          *  so we probably could call eject anyway, but since the
01132          *  media is mounted now, vold must've died for some reason
01133          *  during the user's session, so it should be restarted...
01134          */
01135         err = i18n("\"vold\" is not running.");
01136         kDebug(7101) << "VOLMGT: " << err;
01137         error( KIO::ERR_COULD_NOT_UNMOUNT, err );
01138         return;
01139     }
01140 #else
01141     QString epath = QString::fromLocal8Bit(qgetenv("PATH"));
01142     QString path = QLatin1String("/sbin:/bin");
01143     if (!epath.isEmpty())
01144        path += QLatin1Char(':') + epath;
01145     QByteArray umountProg = KGlobal::dirs()->findExe(QLatin1String("umount"), path).toLocal8Bit();
01146 
01147     if (umountProg.isEmpty()) {
01148         error( KIO::ERR_COULD_NOT_UNMOUNT, i18n("Could not find program \"umount\""));
01149         return;
01150     }
01151     buffer = umountProg + ' ' + QFile::encodeName(KShell::quoteArg(_point)) + " 2>" + tmpFileName;
01152     system( buffer.constData() );
01153 #endif /* HAVE_VOLMGT */
01154 
01155     err = testLogFile( tmpFileName );
01156     if ( err.isEmpty() )
01157         finished();
01158     else
01159         error( KIO::ERR_COULD_NOT_UNMOUNT, err );
01160 #else
01161     QString err;
01162     err = i18n("unmounting is not supported by wince.");
01163     error( KIO::ERR_COULD_NOT_MOUNT, err );
01164 #endif
01165 }
01166 
01167 /*************************************
01168  *
01169  * pmount handling
01170  *
01171  *************************************/
01172 
01173 bool FileProtocol::pmount(const QString &dev)
01174 {
01175 #ifndef _WIN32_WCE
01176     QString epath = QString::fromLocal8Bit(qgetenv("PATH"));
01177     QString path = QLatin1String("/sbin:/bin");
01178     if (!epath.isEmpty())
01179         path += QLatin1Char(':') + epath;
01180     QString pmountProg = KGlobal::dirs()->findExe(QLatin1String("pmount"), path);
01181 
01182     if (pmountProg.isEmpty())
01183         return false;
01184 
01185     QByteArray buffer = QFile::encodeName(pmountProg) + ' ' +
01186                         QFile::encodeName(KShell::quoteArg(dev));
01187 
01188     int res = system( buffer.constData() );
01189 
01190     return res==0;
01191 #else
01192     return false;
01193 #endif
01194 }
01195 
01196 bool FileProtocol::pumount(const QString &point)
01197 {
01198 #ifndef _WIN32_WCE
01199     KMountPoint::Ptr mp = KMountPoint::currentMountPoints(KMountPoint::NeedRealDeviceName).findByPath(point);
01200     if (!mp)
01201         return false;
01202     QString dev = mp->realDeviceName();
01203     if (dev.isEmpty()) return false;
01204 
01205     QString epath = QString::fromLocal8Bit(qgetenv("PATH"));
01206     QString path = QLatin1String("/sbin:/bin");
01207     if (!epath.isEmpty())
01208         path += QLatin1Char(':') + epath;
01209     QString pumountProg = KGlobal::dirs()->findExe(QLatin1String("pumount"), path);
01210 
01211     if (pumountProg.isEmpty())
01212         return false;
01213 
01214     QByteArray buffer = QFile::encodeName(pumountProg);
01215     buffer += ' ';
01216     buffer += QFile::encodeName(KShell::quoteArg(dev));
01217 
01218     int res = system( buffer.data() );
01219 
01220     return res==0;
01221 #else
01222     return false;
01223 #endif
01224 }
01225 
01226 /*************************************
01227  *
01228  * Utilities
01229  *
01230  *************************************/
01231 
01232 static QString testLogFile( const QByteArray& _filename )
01233 {
01234     char buffer[ 1024 ];
01235     KDE_struct_stat buff;
01236 
01237     QString result;
01238 
01239     KDE_stat( _filename, &buff );
01240     int size = buff.st_size;
01241     if ( size == 0 ) {
01242     unlink( _filename );
01243     return result;
01244     }
01245 
01246     FILE * f = KDE_fopen( _filename, "rb" );
01247     if ( f == 0L ) {
01248     unlink( _filename );
01249     result = i18n("Could not read %1", QFile::decodeName(_filename));
01250     return result;
01251     }
01252 
01253     result.clear();
01254     const char *p = "";
01255     while ( p != 0L ) {
01256     p = fgets( buffer, sizeof(buffer)-1, f );
01257     if ( p != 0L )
01258         result += QString::fromLocal8Bit(buffer);
01259     }
01260 
01261     fclose( f );
01262 
01263     unlink( _filename );
01264 
01265     return result;
01266 }
01267 
01268 /*************************************
01269  *
01270  * ACL handling helpers
01271  *
01272  *************************************/
01273 #ifdef HAVE_POSIX_ACL
01274 
01275 bool FileProtocol::isExtendedACL( acl_t acl )
01276 {
01277     return ( acl_equiv_mode( acl, 0 ) != 0 );
01278 }
01279 
01280 static void appendACLAtoms( const QByteArray & path, UDSEntry& entry, mode_t type, bool withACL )
01281 {
01282     // first check for a noop
01283     if ( acl_extended_file( path.data() ) == 0 ) return;
01284 
01285     acl_t acl = 0;
01286     acl_t defaultAcl = 0;
01287     bool isDir = S_ISDIR( type );
01288     // do we have an acl for the file, and/or a default acl for the dir, if it is one?
01289     acl = acl_get_file( path.data(), ACL_TYPE_ACCESS );
01290     /* Sadly libacl does not provided a means of checking for extended ACL and default
01291      * ACL separately. Since a directory can have both, we need to check again. */
01292     if ( isDir ) {
01293         if ( acl ) {
01294             if ( !FileProtocol::isExtendedACL( acl ) ) {
01295                 acl_free( acl );
01296                 acl = 0;
01297             }
01298         }
01299         defaultAcl = acl_get_file( path.data(), ACL_TYPE_DEFAULT );
01300     }
01301     if ( acl || defaultAcl ) {
01302       kDebug(7101) << path.constData() << "has extended ACL entries";
01303       entry.insert( KIO::UDSEntry::UDS_EXTENDED_ACL, 1 );
01304     }
01305     if ( withACL ) {
01306         if ( acl ) {
01307             const QString str = aclToText(acl);
01308             entry.insert( KIO::UDSEntry::UDS_ACL_STRING, str );
01309             kDebug(7101) << path.constData() << "ACL:" << str;
01310         }
01311         if ( defaultAcl ) {
01312             const QString str = aclToText(defaultAcl);
01313             entry.insert( KIO::UDSEntry::UDS_DEFAULT_ACL_STRING, str );
01314             kDebug(7101) << path.constData() << "DEFAULT ACL:" << str;
01315         }
01316     }
01317     if ( acl ) acl_free( acl );
01318     if ( defaultAcl ) acl_free( defaultAcl );
01319 }
01320 #endif
01321 
01322 // We could port this to KTempDir::removeDir but then we wouldn't be able to tell the user
01323 // where exactly the deletion failed, in case of errors.
01324 bool FileProtocol::deleteRecursive(const QString& path)
01325 {
01326     //kDebug() << path;
01327     QDirIterator it(path, QDir::AllEntries | QDir::NoDotAndDotDot | QDir::System | QDir::Hidden,
01328                     QDirIterator::Subdirectories);
01329     QStringList dirsToDelete;
01330     while ( it.hasNext() ) {
01331         const QString itemPath = it.next();
01332         //kDebug() << "itemPath=" << itemPath;
01333         const QFileInfo info = it.fileInfo();
01334         if (info.isDir() && !info.isSymLink())
01335             dirsToDelete.prepend(itemPath);
01336         else {
01337             //kDebug() << "QFile::remove" << itemPath;
01338             if (!QFile::remove(itemPath)) {
01339                 error(KIO::ERR_CANNOT_DELETE, itemPath);
01340                 return false;
01341             }
01342         }
01343     }
01344     QDir dir;
01345     Q_FOREACH(const QString& itemPath, dirsToDelete) {
01346         //kDebug() << "QDir::rmdir" << itemPath;
01347         if (!dir.rmdir(itemPath)) {
01348             error(KIO::ERR_CANNOT_DELETE, itemPath);
01349             return false;
01350         }
01351     }
01352     return true;
01353 }
01354 
01355 #include "file.moc"
This file is part of the KDE documentation.
Documentation copyright © 1996-2019 The KDE developers.
Generated on Mon Jan 21 2019 12:37:22 by doxygen 1.7.5.1 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.

KIOSlave

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

kdelibs-4.9.5 API Reference

Skip menu "kdelibs-4.9.5 API Reference"
  • DNSSD
  • Interfaces
  •   KHexEdit
  •   KMediaPlayer
  •   KSpeech
  •   KTextEditor
  • kconf_update
  • KDE3Support
  •   KUnitTest
  • KDECore
  • KDED
  • KDEsu
  • KDEUI
  • KDEWebKit
  • KDocTools
  • KFile
  • KHTML
  • KImgIO
  • KInit
  • kio
  • KIOSlave
  • KJS
  •   KJS-API
  •   WTF
  • kjsembed
  • KNewStuff
  • KParts
  • KPty
  • Kross
  • KUnitConversion
  • KUtils
  • Nepomuk
  • Plasma
  • Solid
  • Sonnet
  • ThreadWeaver
Report problems with this website to our bug tracking system.
Contact the specific authors with questions and comments about the page contents.

KDE® and the K Desktop Environment® logo are registered trademarks of KDE e.V. | Legal