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

KIOSlave

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

kdelibs

Skip menu "kdelibs"
  • DNSSD
  • Interfaces
  •   KHexEdit
  •   KMediaPlayer
  •   KSpeech
  •   KTextEditor
  • Kate
  • kconf_update
  • KDE3Support
  •   KUnitTest
  • KDECore
  • KDED
  • KDEsu
  • KDEUI
  • KDocTools
  • KFile
  • KHTML
  • KImgIO
  • KInit
  • kio
  • KIOSlave
  • KJS
  •   KJS-API
  •   WTF
  • kjsembed
  • KNewStuff
  • KParts
  • Kross
  • KUtils
  • Nepomuk
  • Plasma
  • Solid
  • Sonnet
  • ThreadWeaver
Generated for kdelibs by doxygen 1.5.7
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