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