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 #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
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 );
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
00150 if ( !ACLString.isEmpty() ) {
00151 acl_t acl = 0;
00152 if ( ACLString == "ACL_DELETE" ) {
00153
00154
00155 acl = acl_from_mode( perm );
00156 }
00157 acl = acl_from_text( ACLString.toLatin1() );
00158 if ( acl_valid( acl ) == 0 ) {
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;
00165 }
00166
00167 if ( directoryDefault && !defaultACLString.isEmpty() ) {
00168 if ( defaultACLString == "ACL_DELETE" ) {
00169
00170 ret += acl_delete_def_file( path );
00171 } else {
00172 acl_t acl = acl_from_text( defaultACLString.toLatin1() );
00173 if ( acl_valid( acl ) == 0 ) {
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
00193 if ( ::chmod( _path.data(), permissions ) == -1 ||
00194 ( setACL( _path.data(), permissions, false ) == -1 ) ||
00195
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:
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;
00225 utbuf.modtime = mtime.toTime_t();
00226 if (utime(path, &utbuf) != 0) {
00227
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 ) != 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
00314
00315
00316
00317
00318 KMimeType::Ptr mt = KMimeType::findByUrl( url, buff.st_mode, true );
00319 emit mimeType( mt->name() );
00320
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;
00357
00358 array = QByteArray::fromRawData(buffer, n);
00359 data( array );
00360 array.clear();
00361
00362 processed_size += n;
00363 processedSize( processed_size );
00364
00365
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
00439
00440
00441
00442 if (mode & QIODevice::ReadOnly){
00443 KMimeType::Ptr mt = KMimeType::findByUrl( url, buff.st_mode, true );
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
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) {
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
00555
00556
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
00579 do
00580 {
00581 QByteArray buffer;
00582 dataReq();
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
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
00608 }
00609 }
00610
00611 _dest = QFile::encodeName(dest);
00612
00613 if ( (_flags & KIO::Resume) )
00614 {
00615 fd = KDE_open( _dest.data(), O_RDWR );
00616 KDE_lseek(fd, 0, SEEK_END);
00617 }
00618 else
00619 {
00620
00621
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 )
00646 {
00647 error( KIO::ERR_DISK_FULL, dest_orig);
00648 result = -2;
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
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 )
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
00696 if ( bMarkPartial )
00697 {
00698
00699
00700
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
00719 if ( _mode != -1 && !(_flags & KIO::Resume) )
00720 {
00721 if (::chmod(_dest_orig.data(), _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( "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;
00739 utbuf.modtime = dt.toTime_t();
00740 utime( _dest_orig.data(), &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
00786
00787
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
00808 if ( details > 1 && KDE_stat( path.data(), &buff ) == -1 ) {
00809
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
00822 return false;
00823 }
00824
00825 type = buff.st_mode & S_IFMT;
00826 access = buff.st_mode & 07777;
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
00835
00836
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
00847
00848
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
00865
00866
00867
00868
00869
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 ) )
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
00901
00902
00903
00904
00905
00906
00907
00908
00909
00910
00911
00912
00913
00914
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
00967
00968 QString err;
00969 QByteArray devname = QFile::encodeName( _dev );
00970
00971 if( volmgt_running() ) {
00972
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=" ) ) {
01000 QString labelName = _dev.mid( 6 );
01001 dev = "-L ";
01002 dev += QFile::encodeName( KShell::quoteArg( labelName ) );
01003 } else if ( _dev.startsWith( "UUID=" ) ) {
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) );
01010
01011 QByteArray point = QFile::encodeName( KShell::quoteArg(_point) );
01012 bool fstype_empty = !_fstype || !*_fstype;
01013 QByteArray fstype = KShell::quoteArg(_fstype).toLatin1();
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
01027 for ( int step = 0 ; step <= 1 ; step++ )
01028 {
01029
01030 if ( !_dev.isEmpty() && _point.isEmpty() && fstype_empty )
01031 buffer += dev;
01032 else
01033
01034 if ( !_point.isEmpty() && _dev.isEmpty() && fstype_empty )
01035 buffer += point;
01036 else
01037
01038 if ( !_point.isEmpty() && !_dev.isEmpty() && fstype_empty )
01039 buffer += readonly + ' ' + dev + ' ' + point;
01040 else
01041
01042 #if defined(__svr4__) && defined(Q_OS_SOLARIS) // MARCO for Solaris 8 and I
01043
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
01062 KMountPoint::Ptr mp = KMountPoint::currentMountPoints().findByDevice( _dev );
01063
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
01081
01082
01083
01084
01085
01086
01087
01088 }
01089 else
01090 {
01091 error( KIO::ERR_COULD_NOT_MOUNT, err );
01092 return;
01093 }
01094 }
01095 }
01096 }
01097 #endif
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
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
01133
01134
01135
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
01158
01159
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
01169
01170
01171 if( WEXITSTATUS( system( buffer.constData() )) == 4 ) {
01172
01173
01174
01175
01176 QFile::remove( tmpFileName );
01177 finished();
01178 return;
01179 }
01180 } else {
01181
01182
01183
01184
01185
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
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
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
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
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
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
01328 acl = acl_get_file( path.data(), ACL_TYPE_ACCESS );
01329
01330
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"