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