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

KIOSlave

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

kdelibs

Skip menu "kdelibs"
  • DNSSD
  • Interfaces
  •   KHexEdit
  •   KMediaPlayer
  •   KSpeech
  •   KTextEditor
  • Kate
  • 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
  • KUtils
  • Nepomuk
  • Plasma
  •     Sodep
  • Solid
  • Sonnet
  • ThreadWeaver
Generated for kdelibs by doxygen 1.5.9-20090814
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