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

KIOSlave

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

KDE's Doxygen guidelines are available online.

KIOSlave

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

kdelibs-4.8.3 API Reference

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

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