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