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 <QtCore/QBool>
00031 #include <sys/types.h>
00032 #include <sys/wait.h>
00033 #include <sys/stat.h>
00034 #include <sys/socket.h>
00035 #ifdef HAVE_SYS_TIME_H
00036 #include <sys/time.h>
00037 #endif
00038
00039
00040 #if defined HAVE_SENDFILE && defined Q_OS_LINUX
00041 #define USE_SENDFILE 1
00042 #endif
00043
00044 #ifdef USE_SENDFILE
00045 #include <sys/sendfile.h>
00046 #endif
00047
00048 #ifdef HAVE_POSIX_ACL
00049 #include <sys/acl.h>
00050 #include <acl/libacl.h>
00051 #endif
00052
00053 #include <assert.h>
00054 #include <dirent.h>
00055 #include <errno.h>
00056 #include <fcntl.h>
00057 #include <grp.h>
00058 #include <pwd.h>
00059 #include <stdio.h>
00060 #include <stdlib.h>
00061 #include <signal.h>
00062 #include <time.h>
00063 #include <utime.h>
00064 #include <unistd.h>
00065 #ifdef HAVE_STRING_H
00066 #include <string.h>
00067 #endif
00068
00069 #include <QtCore/QByteRef>
00070 #include <QtCore/QDate>
00071 #include <QtCore/QVarLengthArray>
00072 #include <QtCore/QCoreApplication>
00073 #include <QtCore/QRegExp>
00074 #include <QtCore/QFile>
00075 #ifdef Q_WS_WIN
00076 #include <QtCore/QDir>
00077 #include <QtCore/QFileInfo>
00078 #endif
00079
00080 #include <kdebug.h>
00081 #include <kurl.h>
00082 #include <kcomponentdata.h>
00083 #include <kconfig.h>
00084 #include <kconfiggroup.h>
00085 #include <ktemporaryfile.h>
00086 #include <klocale.h>
00087 #include <limits.h>
00088 #include <kshell.h>
00089 #include <kmountpoint.h>
00090 #include <kstandarddirs.h>
00091
00092 #ifdef HAVE_VOLMGT
00093 #include <volmgt.h>
00094 #include <sys/mnttab.h>
00095 #endif
00096
00097 #include <kio/ioslave_defaults.h>
00098 #include <kde_file.h>
00099 #include <kglobal.h>
00100 #include <kmimetype.h>
00101
00102 using namespace KIO;
00103
00104 #define MAX_IPC_SIZE (1024*32)
00105
00106 static QString testLogFile( const QByteArray&_filename );
00107 #ifdef HAVE_POSIX_ACL
00108 static bool isExtendedACL( acl_t p_acl );
00109 static void appendACLAtoms( const QByteArray & path, UDSEntry& entry,
00110 mode_t type, bool withACL );
00111 #endif
00112
00113 extern "C" int KDE_EXPORT kdemain( int argc, char **argv )
00114 {
00115 QCoreApplication app( argc, argv );
00116 KComponentData componentData( "kio_file", "kdelibs4" );
00117 ( void ) KGlobal::locale();
00118
00119 kDebug(7101) << "Starting " << getpid();
00120
00121 if (argc != 4)
00122 {
00123 fprintf(stderr, "Usage: kio_file protocol domain-socket1 domain-socket2\n");
00124 exit(-1);
00125 }
00126
00127 FileProtocol slave(argv[2], argv[3]);
00128 slave.dispatchLoop();
00129
00130 kDebug(7101) << "Done";
00131 return 0;
00132 }
00133
00134 FileProtocol::FileProtocol( const QByteArray &pool, const QByteArray &app )
00135 : SlaveBase( "file", pool, app ), openFd(-1)
00136 {
00137 }
00138
00139 FileProtocol::~FileProtocol()
00140 {
00141 }
00142
00143 int FileProtocol::setACL( const char *path, mode_t perm, bool directoryDefault )
00144 {
00145 int ret = 0;
00146 #ifdef HAVE_POSIX_ACL
00147
00148 const QString ACLString = metaData( "ACL_STRING" );
00149 const QString defaultACLString = metaData( "DEFAULT_ACL_STRING" );
00150
00151 if ( !ACLString.isEmpty() ) {
00152 acl_t acl = 0;
00153 if ( ACLString == "ACL_DELETE" ) {
00154
00155
00156 acl = acl_from_mode( perm );
00157 }
00158 acl = acl_from_text( ACLString.toLatin1() );
00159 if ( acl_valid( acl ) == 0 ) {
00160 ret = acl_set_file( path, ACL_TYPE_ACCESS, acl );
00161 ssize_t size = acl_size( acl );
00162 kDebug(7101) << "Set ACL on: " << path << " to: " << acl_to_text( acl, &size );
00163 }
00164 acl_free( acl );
00165 if ( ret != 0 ) return ret;
00166 }
00167
00168 if ( directoryDefault && !defaultACLString.isEmpty() ) {
00169 if ( defaultACLString == "ACL_DELETE" ) {
00170
00171 ret += acl_delete_def_file( path );
00172 } else {
00173 acl_t acl = acl_from_text( defaultACLString.toLatin1() );
00174 if ( acl_valid( acl ) == 0 ) {
00175 ret += acl_set_file( path, ACL_TYPE_DEFAULT, acl );
00176 ssize_t size = acl_size( acl );
00177 kDebug(7101) << "Set Default ACL on: " << path << " to: " << acl_to_text( acl, &size );
00178 }
00179 acl_free( acl );
00180 }
00181 }
00182 #else
00183 Q_UNUSED(path);
00184 Q_UNUSED(perm);
00185 Q_UNUSED(directoryDefault);
00186 #endif
00187 return ret;
00188 }
00189
00190 void FileProtocol::chmod( const KUrl& url, int permissions )
00191 {
00192 QByteArray _path( QFile::encodeName(url.toLocalFile()) );
00193
00194 if ( ::chmod( _path.data(), permissions ) == -1 ||
00195 ( setACL( _path.data(), permissions, false ) == -1 ) ||
00196
00197 ( setACL( _path.data(), permissions, true ) == -1 && errno != ENOTDIR ) ) {
00198
00199 switch (errno) {
00200 case EPERM:
00201 case EACCES:
00202 error( KIO::ERR_ACCESS_DENIED, _path );
00203 break;
00204 #if defined(ENOTSUP)
00205 case ENOTSUP:
00206 error( KIO::ERR_UNSUPPORTED_ACTION, i18n( "Setting ACL for %1" , url.path() ) );
00207 break;
00208 #endif
00209 case ENOSPC:
00210 error( KIO::ERR_DISK_FULL, _path );
00211 break;
00212 default:
00213 error( KIO::ERR_CANNOT_CHMOD, _path );
00214 }
00215 } else
00216 finished();
00217 }
00218
00219 void FileProtocol::chown( const KUrl& url, const QString& owner, const QString& group )
00220 {
00221 QByteArray _path( QFile::encodeName(url.toLocalFile()) );
00222 #ifdef Q_WS_WIN
00223 error( KIO::ERR_CANNOT_CHOWN, _path );
00224 #else
00225
00226 uid_t uid;
00227 gid_t gid;
00228
00229
00230 {
00231 struct passwd *p = ::getpwnam(owner.toAscii());
00232
00233 if ( ! p ) {
00234 error( KIO::ERR_SLAVE_DEFINED,
00235 i18n( "Could not get user id for given user name %1", owner ) );
00236 return;
00237 }
00238
00239 uid = p->pw_uid;
00240 }
00241
00242
00243 {
00244 struct group *p = ::getgrnam(group.toAscii());
00245
00246 if ( ! p ) {
00247 error( KIO::ERR_SLAVE_DEFINED,
00248 i18n( "Could not get group id for given group name %1", group ) );
00249 return;
00250 }
00251
00252 gid = p->gr_gid;
00253 }
00254
00255 if ( ::chown(_path, uid, gid) == -1 ) {
00256 switch ( errno ) {
00257 case EPERM:
00258 case EACCES:
00259 error( KIO::ERR_ACCESS_DENIED, _path );
00260 break;
00261 case ENOSPC:
00262 error( KIO::ERR_DISK_FULL, _path );
00263 break;
00264 default:
00265 error( KIO::ERR_CANNOT_CHOWN, _path );
00266 }
00267 } else
00268 finished();
00269 #endif
00270 }
00271
00272 void FileProtocol::setModificationTime( const KUrl& url, const QDateTime& mtime )
00273 {
00274 const QByteArray path = QFile::encodeName(url.toLocalFile());
00275 KDE_struct_stat statbuf;
00276 if (KDE_lstat(path, &statbuf) == 0) {
00277 struct utimbuf utbuf;
00278 utbuf.actime = statbuf.st_atime;
00279 utbuf.modtime = mtime.toTime_t();
00280 if (utime(path, &utbuf) != 0) {
00281
00282 error(KIO::ERR_CANNOT_SETTIME, path);
00283 } else {
00284 finished();
00285 }
00286 } else {
00287 error( KIO::ERR_DOES_NOT_EXIST, path );
00288 }
00289 }
00290
00291 void FileProtocol::mkdir( const KUrl& url, int permissions )
00292 {
00293 QByteArray _path( QFile::encodeName(url.toLocalFile()));
00294
00295 kDebug(7101) << "mkdir(): " << _path << ", permission = " << permissions;
00296
00297 KDE_struct_stat buff;
00298 if ( KDE_stat( _path.data(), &buff ) == -1 ) {
00299 if ( KDE_mkdir( _path.data(), 0777 ) != 0 ) {
00300 if ( errno == EACCES ) {
00301 error( KIO::ERR_ACCESS_DENIED, _path );
00302 return;
00303 } else if ( errno == ENOSPC ) {
00304 error( KIO::ERR_DISK_FULL, _path );
00305 return;
00306 } else {
00307 error( KIO::ERR_COULD_NOT_MKDIR, _path );
00308 return;
00309 }
00310 } else {
00311 if ( permissions != -1 )
00312 chmod( url, permissions );
00313 else
00314 finished();
00315 return;
00316 }
00317 }
00318
00319 if ( S_ISDIR( buff.st_mode ) ) {
00320 kDebug(7101) << "ERR_DIR_ALREADY_EXIST";
00321 error( KIO::ERR_DIR_ALREADY_EXIST, _path );
00322 return;
00323 }
00324 error( KIO::ERR_FILE_ALREADY_EXIST, _path );
00325 return;
00326 }
00327
00328 void FileProtocol::get( const KUrl& url )
00329 {
00330 if (!url.isLocalFile()) {
00331 KUrl redir(url);
00332 redir.setProtocol(config()->readEntry("DefaultRemoteProtocol", "smb"));
00333 redirection(redir);
00334 finished();
00335 return;
00336 }
00337
00338 QByteArray _path( QFile::encodeName(url.toLocalFile()));
00339 KDE_struct_stat buff;
00340 if ( KDE_stat( _path.data(), &buff ) == -1 ) {
00341 if ( errno == EACCES )
00342 error( KIO::ERR_ACCESS_DENIED, _path );
00343 else
00344 error( KIO::ERR_DOES_NOT_EXIST, _path );
00345 return;
00346 }
00347
00348 if ( S_ISDIR( buff.st_mode ) ) {
00349 error( KIO::ERR_IS_DIRECTORY, _path );
00350 return;
00351 }
00352 if ( !S_ISREG( buff.st_mode ) ) {
00353 error( KIO::ERR_CANNOT_OPEN_FOR_READING, _path );
00354 return;
00355 }
00356
00357 int fd = KDE_open( _path.data(), O_RDONLY);
00358 if ( fd < 0 ) {
00359 error( KIO::ERR_CANNOT_OPEN_FOR_READING, _path );
00360 return;
00361 }
00362
00363 #ifdef HAVE_FADVISE
00364 posix_fadvise( fd, 0, 0, POSIX_FADV_SEQUENTIAL);
00365 #endif
00366
00367
00368
00369
00370
00371
00372 KMimeType::Ptr mt = KMimeType::findByUrl( url, buff.st_mode, true );
00373 emit mimeType( mt->name() );
00374
00375 totalSize( buff.st_size );
00376
00377 KIO::filesize_t processed_size = 0;
00378
00379 QString resumeOffset = metaData("resume");
00380 if ( !resumeOffset.isEmpty() )
00381 {
00382 bool ok;
00383 KIO::fileoffset_t offset = resumeOffset.toLongLong(&ok);
00384 if (ok && (offset > 0) && (offset < buff.st_size))
00385 {
00386 if (KDE_lseek(fd, offset, SEEK_SET) == offset)
00387 {
00388 canResume ();
00389 processed_size = offset;
00390 kDebug( 7101 ) << "Resume offset: " << KIO::number(offset);
00391 }
00392 }
00393 }
00394
00395 char buffer[ MAX_IPC_SIZE ];
00396 QByteArray array;
00397
00398 while( 1 )
00399 {
00400 int n = ::read( fd, buffer, MAX_IPC_SIZE );
00401 if (n == -1)
00402 {
00403 if (errno == EINTR)
00404 continue;
00405 error( KIO::ERR_COULD_NOT_READ, _path );
00406 ::close(fd);
00407 return;
00408 }
00409 if (n == 0)
00410 break;
00411
00412 array = QByteArray::fromRawData(buffer, n);
00413 data( array );
00414 array.clear();
00415
00416 processed_size += n;
00417 processedSize( processed_size );
00418
00419
00420 }
00421
00422 data( QByteArray() );
00423
00424 ::close( fd );
00425
00426 processedSize( buff.st_size );
00427 finished();
00428 }
00429
00430 static int
00431 write_all(int fd, const char *buf, size_t len)
00432 {
00433 while (len > 0)
00434 {
00435 ssize_t written = write(fd, buf, len);
00436 if (written < 0)
00437 {
00438 if (errno == EINTR)
00439 continue;
00440 return -1;
00441 }
00442 buf += written;
00443 len -= written;
00444 }
00445 return 0;
00446 }
00447
00448 void FileProtocol::open(const KUrl &url, QIODevice::OpenMode mode)
00449 {
00450 kDebug(7101) << "FileProtocol::open " << url.url();
00451
00452 openPath = QFile::encodeName(url.toLocalFile());
00453 KDE_struct_stat buff;
00454 if ( KDE_stat( openPath.data(), &buff ) == -1 ) {
00455 if ( errno == EACCES )
00456 error( KIO::ERR_ACCESS_DENIED, openPath );
00457 else
00458 error( KIO::ERR_DOES_NOT_EXIST, openPath );
00459 return;
00460 }
00461
00462 if ( S_ISDIR( buff.st_mode ) ) {
00463 error( KIO::ERR_IS_DIRECTORY, openPath );
00464 return;
00465 }
00466 if ( !S_ISREG( buff.st_mode ) ) {
00467 error( KIO::ERR_CANNOT_OPEN_FOR_READING, openPath );
00468 return;
00469 }
00470
00471 int flags = 0;
00472 if (mode & QIODevice::ReadOnly) {
00473 if (mode & QIODevice::WriteOnly) {
00474 flags = O_RDWR | O_CREAT;
00475 } else {
00476 flags = O_RDONLY;
00477 }
00478 } else if (mode & QIODevice::WriteOnly) {
00479 flags = O_WRONLY | O_CREAT;
00480 }
00481
00482 if (mode & QIODevice::Append) {
00483 flags |= O_APPEND;
00484 } else if (mode & QIODevice::Truncate) {
00485 flags |= O_TRUNC;
00486 }
00487
00488 int fd = KDE_open( openPath.data(), flags);
00489 if ( fd < 0 ) {
00490 error( KIO::ERR_CANNOT_OPEN_FOR_READING, openPath );
00491 return;
00492 }
00493
00494
00495
00496
00497 if (mode & QIODevice::ReadOnly){
00498 KMimeType::Ptr mt = KMimeType::findByUrl( url, buff.st_mode, true );
00499 emit mimeType( mt->name() );
00500 }
00501
00502 totalSize( buff.st_size );
00503 position( 0 );
00504
00505 emit opened();
00506 openFd = fd;
00507 }
00508
00509 void FileProtocol::read(KIO::filesize_t bytes)
00510 {
00511 kDebug( 7101 ) << "File::open -- read";
00512 Q_ASSERT(openFd != -1);
00513
00514 QVarLengthArray<char> buffer(bytes);
00515 while (true) {
00516 int res;
00517 do {
00518 res = ::read(openFd, buffer.data(), bytes);
00519 } while (res == -1 && errno == EINTR);
00520
00521 if (res > 0) {
00522 QByteArray array = array.fromRawData(buffer.data(), res);
00523 data( array );
00524 bytes -= res;
00525 } else {
00526
00527 data(QByteArray());
00528 if (res != 0) {
00529 error(KIO::ERR_COULD_NOT_READ, openPath);
00530 close();
00531 }
00532 break;
00533 }
00534 if (bytes <= 0) break;
00535 }
00536 }
00537
00538 void FileProtocol::write(const QByteArray &data)
00539 {
00540 kDebug( 7101 ) << "File::open -- write";
00541 Q_ASSERT(openFd != -1);
00542
00543 if (write_all(openFd, data.constData(), data.size())) {
00544 if (errno == ENOSPC) {
00545 error( KIO::ERR_DISK_FULL, openPath );
00546 close();
00547 } else {
00548 kWarning(7101) << "Couldn't write. Error:" << strerror(errno);
00549 error( KIO::ERR_COULD_NOT_WRITE, openPath );
00550 close();
00551 }
00552 } else {
00553 written(data.size());
00554 }
00555 }
00556
00557 void FileProtocol::seek(KIO::filesize_t offset)
00558 {
00559 kDebug( 7101 ) << "File::open -- seek";
00560 Q_ASSERT(openFd != -1);
00561
00562 int res = KDE_lseek(openFd, offset, SEEK_SET);
00563 if (res != -1) {
00564 position( offset );
00565 } else {
00566 error(KIO::ERR_COULD_NOT_SEEK, openPath );
00567 close();
00568 }
00569 }
00570
00571 void FileProtocol::close()
00572 {
00573 kDebug( 7101 ) << "File::open -- close ";
00574 Q_ASSERT(openFd != -1);
00575
00576 ::close( openFd );
00577 openFd = -1;
00578 openPath.clear();
00579
00580 finished();
00581 }
00582
00583 static bool
00584 same_inode(const KDE_struct_stat &src, const KDE_struct_stat &dest)
00585 {
00586 if (src.st_ino == dest.st_ino &&
00587 src.st_dev == dest.st_dev)
00588 return true;
00589
00590 return false;
00591 }
00592
00593 void FileProtocol::put( const KUrl& url, int _mode, KIO::JobFlags _flags )
00594 {
00595 QString dest_orig = url.toLocalFile();
00596 QByteArray _dest_orig( QFile::encodeName(dest_orig));
00597
00598 kDebug(7101) << "put(): " << dest_orig << ", mode=" << _mode;
00599
00600 QString dest_part( dest_orig );
00601 dest_part += QLatin1String(".part");
00602 QByteArray _dest_part( QFile::encodeName(dest_part));
00603
00604 KDE_struct_stat buff_orig;
00605 bool bOrigExists = (KDE_lstat( _dest_orig.data(), &buff_orig ) != -1);
00606 bool bPartExists = false;
00607 bool bMarkPartial = config()->readEntry("MarkPartial", true);
00608
00609 if (bMarkPartial)
00610 {
00611 KDE_struct_stat buff_part;
00612 bPartExists = (KDE_stat( _dest_part.data(), &buff_part ) != -1);
00613
00614 if (bPartExists && !(_flags & KIO::Resume) && !(_flags & KIO::Overwrite) && buff_part.st_size > 0 && S_ISREG(buff_part.st_mode))
00615 {
00616 kDebug(7101) << "FileProtocol::put : calling canResume with "
00617 << KIO::number(buff_part.st_size);
00618
00619
00620
00621
00622 _flags |= canResume( buff_part.st_size ) ? KIO::Resume : KIO::DefaultFlags;
00623
00624 kDebug(7101) << "FileProtocol::put got answer " << (_flags & KIO::Resume);
00625 }
00626 }
00627
00628 if ( bOrigExists && !(_flags & KIO::Overwrite) && !(_flags & KIO::Resume))
00629 {
00630 if (S_ISDIR(buff_orig.st_mode))
00631 error( KIO::ERR_DIR_ALREADY_EXIST, dest_orig );
00632 else
00633 error( KIO::ERR_FILE_ALREADY_EXIST, dest_orig );
00634 return;
00635 }
00636
00637 int result;
00638 QString dest;
00639 QByteArray _dest;
00640
00641 int fd = -1;
00642
00643
00644 do
00645 {
00646 QByteArray buffer;
00647 dataReq();
00648 result = readData( buffer );
00649
00650 if (result >= 0)
00651 {
00652 if (dest.isEmpty())
00653 {
00654 if (bMarkPartial)
00655 {
00656 kDebug(7101) << "Appending .part extension to " << dest_orig;
00657 dest = dest_part;
00658 if ( bPartExists && !(_flags & KIO::Resume) )
00659 {
00660 kDebug(7101) << "Deleting partial file " << dest_part;
00661 remove( _dest_part.data() );
00662
00663 }
00664 }
00665 else
00666 {
00667 dest = dest_orig;
00668 if ( bOrigExists && !(_flags & KIO::Resume) )
00669 {
00670 kDebug(7101) << "Deleting destination file " << dest_orig;
00671 remove( _dest_orig.data() );
00672
00673 }
00674 }
00675
00676 _dest = QFile::encodeName(dest);
00677
00678 if ( (_flags & KIO::Resume) )
00679 {
00680 fd = KDE_open( _dest.data(), O_RDWR );
00681 KDE_lseek(fd, 0, SEEK_END);
00682 }
00683 else
00684 {
00685
00686
00687 mode_t initialMode;
00688 if (_mode != -1)
00689 initialMode = _mode | S_IWUSR | S_IRUSR;
00690 else
00691 initialMode = 0666;
00692
00693 fd = KDE_open(_dest.data(), O_CREAT | O_TRUNC | O_WRONLY, initialMode);
00694 }
00695
00696 if ( fd < 0 )
00697 {
00698 kDebug(7101) << "####################### COULD NOT WRITE " << dest << " _mode=" << _mode;
00699 kDebug(7101) << "errno==" << errno << "(" << strerror(errno) << ")";
00700 if ( errno == EACCES )
00701 error( KIO::ERR_WRITE_ACCESS_DENIED, dest );
00702 else
00703 error( KIO::ERR_CANNOT_OPEN_FOR_WRITING, dest );
00704 return;
00705 }
00706 }
00707
00708 if (write_all( fd, buffer.data(), buffer.size()))
00709 {
00710 if ( errno == ENOSPC )
00711 {
00712 error( KIO::ERR_DISK_FULL, dest_orig);
00713 result = -2;
00714 }
00715 else
00716 {
00717 kWarning(7101) << "Couldn't write. Error:" << strerror(errno);
00718 error( KIO::ERR_COULD_NOT_WRITE, dest_orig);
00719 result = -1;
00720 }
00721 }
00722 }
00723 }
00724 while ( result > 0 );
00725
00726
00727 if (result < 0)
00728 {
00729 kDebug(7101) << "Error during 'put'. Aborting.";
00730
00731 if (fd != -1)
00732 {
00733 ::close(fd);
00734
00735 KDE_struct_stat buff;
00736 if (bMarkPartial && KDE_stat( _dest.data(), &buff ) == 0)
00737 {
00738 int size = config()->readEntry("MinimumKeepSize", DEFAULT_MINIMUM_KEEP_SIZE);
00739 if (buff.st_size < size)
00740 remove(_dest.data());
00741 }
00742 }
00743
00744 ::exit(255);
00745 }
00746
00747 if ( fd == -1 )
00748 {
00749 finished();
00750 return;
00751 }
00752
00753 if ( ::close(fd) )
00754 {
00755 kWarning(7101) << "Error when closing file descriptor:" << strerror(errno);
00756 error( KIO::ERR_COULD_NOT_WRITE, dest_orig);
00757 return;
00758 }
00759
00760
00761 if ( bMarkPartial )
00762 {
00763
00764
00765
00766 if( (_flags & KIO::Overwrite) && S_ISLNK( buff_orig.st_mode ) )
00767 remove( _dest_orig.data() );
00768
00769 #ifdef Q_OS_WIN
00770 if ( MoveFileExA( _dest.data(),
00771 _dest_orig.data(),
00772 MOVEFILE_REPLACE_EXISTING|MOVEFILE_COPY_ALLOWED ) == 0 )
00773 #else
00774 if ( KDE_rename( _dest.data(), _dest_orig.data() ) )
00775 #endif
00776 {
00777 kWarning(7101) << " Couldn't rename " << _dest << " to " << _dest_orig;
00778 error( KIO::ERR_CANNOT_RENAME_PARTIAL, dest_orig );
00779 return;
00780 }
00781 }
00782
00783
00784 if ( _mode != -1 && !(_flags & KIO::Resume) )
00785 {
00786 if (::chmod(_dest_orig.data(), _mode) != 0)
00787 {
00788
00789 KMountPoint::Ptr mp = KMountPoint::currentMountPoints().findByPath(_dest_orig);
00790 if (mp && mp->testFileSystemFlag(KMountPoint::SupportsChmod))
00791 warning( i18n( "Could not change permissions for\n%1" , dest_orig ) );
00792 }
00793 }
00794
00795
00796 const QString mtimeStr = metaData( "modified" );
00797 if ( !mtimeStr.isEmpty() ) {
00798 QDateTime dt = QDateTime::fromString( mtimeStr, Qt::ISODate );
00799 if ( dt.isValid() ) {
00800 KDE_struct_stat dest_statbuf;
00801 if (KDE_stat( _dest_orig.data(), &dest_statbuf ) == 0) {
00802 struct utimbuf utbuf;
00803 utbuf.actime = dest_statbuf.st_atime;
00804 utbuf.modtime = dt.toTime_t();
00805 utime( _dest_orig.data(), &utbuf );
00806 }
00807 }
00808
00809 }
00810
00811
00812 finished();
00813 }
00814
00815 #ifndef Q_OS_WIN
00816
00817 void FileProtocol::copy( const KUrl &src, const KUrl &dest,
00818 int _mode, JobFlags _flags )
00819 {
00820 kDebug(7101) << "copy(): " << src << " -> " << dest << ", mode=" << _mode;
00821
00822 QByteArray _src( QFile::encodeName(src.toLocalFile()));
00823 QByteArray _dest( QFile::encodeName(dest.toLocalFile()));
00824 KDE_struct_stat buff_src;
00825 #ifdef HAVE_POSIX_ACL
00826 acl_t acl;
00827 #endif
00828
00829 if ( KDE_stat( _src.data(), &buff_src ) == -1 ) {
00830 if ( errno == EACCES )
00831 error( KIO::ERR_ACCESS_DENIED, _src );
00832 else
00833 error( KIO::ERR_DOES_NOT_EXIST, _src );
00834 return;
00835 }
00836
00837 if ( S_ISDIR( buff_src.st_mode ) ) {
00838 error( KIO::ERR_IS_DIRECTORY, src.path() );
00839 return;
00840 }
00841 if ( S_ISFIFO( buff_src.st_mode ) || S_ISSOCK ( buff_src.st_mode ) ) {
00842 error( KIO::ERR_CANNOT_OPEN_FOR_READING, src.path() );
00843 return;
00844 }
00845
00846 KDE_struct_stat buff_dest;
00847 bool dest_exists = ( KDE_lstat( _dest.data(), &buff_dest ) != -1 );
00848 if ( dest_exists )
00849 {
00850 if (S_ISDIR(buff_dest.st_mode))
00851 {
00852 error( KIO::ERR_DIR_ALREADY_EXIST, _dest );
00853 return;
00854 }
00855
00856 if ( same_inode( buff_dest, buff_src) )
00857 {
00858 error( KIO::ERR_IDENTICAL_FILES, _dest );
00859 return;
00860 }
00861
00862 if (!(_flags & KIO::Overwrite))
00863 {
00864 error( KIO::ERR_FILE_ALREADY_EXIST, _dest );
00865 return;
00866 }
00867
00868
00869
00870
00871 if ((_flags & KIO::Overwrite) && S_ISLNK(buff_dest.st_mode))
00872 {
00873
00874 remove( _dest.data() );
00875 }
00876 }
00877
00878 int src_fd = KDE_open( _src.data(), O_RDONLY);
00879 if ( src_fd < 0 ) {
00880 error( KIO::ERR_CANNOT_OPEN_FOR_READING, _src );
00881 return;
00882 }
00883
00884 #ifdef HAVE_FADVISE
00885 posix_fadvise(src_fd,0,0,POSIX_FADV_SEQUENTIAL);
00886 #endif
00887
00888
00889 mode_t initialMode;
00890 if (_mode != -1)
00891 initialMode = _mode | S_IWUSR;
00892 else
00893 initialMode = 0666;
00894
00895 int dest_fd = KDE_open(_dest.data(), O_CREAT | O_TRUNC | O_WRONLY, initialMode);
00896 if ( dest_fd < 0 ) {
00897 kDebug(7101) << "###### COULD NOT WRITE " << dest.url();
00898 if ( errno == EACCES ) {
00899 error( KIO::ERR_WRITE_ACCESS_DENIED, _dest );
00900 } else {
00901 error( KIO::ERR_CANNOT_OPEN_FOR_WRITING, _dest );
00902 }
00903 ::close(src_fd);
00904 return;
00905 }
00906
00907 #ifdef HAVE_FADVISE
00908 posix_fadvise(dest_fd,0,0,POSIX_FADV_SEQUENTIAL);
00909 #endif
00910
00911 #ifdef HAVE_POSIX_ACL
00912 acl = acl_get_fd(src_fd);
00913 if ( acl && !isExtendedACL( acl ) ) {
00914 kDebug(7101) << _dest.data() << " doesn't have extended ACL";
00915 acl_free( acl );
00916 acl = NULL;
00917 }
00918 #endif
00919 totalSize( buff_src.st_size );
00920
00921 KIO::filesize_t processed_size = 0;
00922 char buffer[ MAX_IPC_SIZE ];
00923 int n;
00924 #ifdef USE_SENDFILE
00925 bool use_sendfile=buff_src.st_size < 0x7FFFFFFF;
00926 #endif
00927 while( 1 )
00928 {
00929 #ifdef USE_SENDFILE
00930 if (use_sendfile) {
00931 off_t sf = processed_size;
00932 n = KDE_sendfile( dest_fd, src_fd, &sf, MAX_IPC_SIZE );
00933 processed_size = sf;
00934 if ( n == -1 && ( errno == EINVAL || errno == ENOSYS ) ) {
00935 kDebug(7101) << "sendfile() not supported, falling back ";
00936 use_sendfile = false;
00937 }
00938 }
00939 if (!use_sendfile)
00940 #endif
00941 n = ::read( src_fd, buffer, MAX_IPC_SIZE );
00942
00943 if (n == -1)
00944 {
00945 if (errno == EINTR)
00946 continue;
00947 #ifdef USE_SENDFILE
00948 if ( use_sendfile ) {
00949 kDebug(7101) << "sendfile() error:" << strerror(errno);
00950 if ( errno == ENOSPC )
00951 {
00952 error( KIO::ERR_DISK_FULL, _dest );
00953 remove( _dest.data() );
00954 }
00955 else {
00956 error( KIO::ERR_SLAVE_DEFINED,
00957 i18n("Cannot copy file from %1 to %2. (Errno: %3)",
00958 src.toLocalFile(), dest.toLocalFile(), errno ) );
00959 }
00960 } else
00961 #endif
00962 error( KIO::ERR_COULD_NOT_READ, _src );
00963 ::close(src_fd);
00964 ::close(dest_fd);
00965 #ifdef HAVE_POSIX_ACL
00966 if (acl) acl_free(acl);
00967 #endif
00968 return;
00969 }
00970 if (n == 0)
00971 break;
00972 #ifdef USE_SENDFILE
00973 if ( !use_sendfile ) {
00974 #endif
00975 if (write_all( dest_fd, buffer, n))
00976 {
00977 ::close(src_fd);
00978 ::close(dest_fd);
00979
00980 if ( errno == ENOSPC )
00981 {
00982 error( KIO::ERR_DISK_FULL, _dest );
00983 remove( _dest.data() );
00984 }
00985 else
00986 {
00987 kWarning(7101) << "Couldn't write[2]. Error:" << strerror(errno);
00988 error( KIO::ERR_COULD_NOT_WRITE, _dest );
00989 }
00990 #ifdef HAVE_POSIX_ACL
00991 if (acl) acl_free(acl);
00992 #endif
00993 return;
00994 }
00995 processed_size += n;
00996 #ifdef USE_SENDFILE
00997 }
00998 #endif
00999 processedSize( processed_size );
01000 }
01001
01002 ::close( src_fd );
01003
01004 if (::close( dest_fd))
01005 {
01006 kWarning(7101) << "Error when closing file descriptor[2]:" << strerror(errno);
01007 error( KIO::ERR_COULD_NOT_WRITE, _dest );
01008 #ifdef HAVE_POSIX_ACL
01009 if (acl) acl_free(acl);
01010 #endif
01011 return;
01012 }
01013
01014
01015 if ( _mode != -1 )
01016 {
01017 if ( (::chmod(_dest.data(), _mode) != 0)
01018 #ifdef HAVE_POSIX_ACL
01019 || (acl && acl_set_file(_dest.data(), ACL_TYPE_ACCESS, acl) != 0)
01020 #endif
01021 )
01022 {
01023 KMountPoint::Ptr mp = KMountPoint::currentMountPoints().findByPath(_dest);
01024
01025 if ( mp && mp->testFileSystemFlag( KMountPoint::SupportsChmod ) )
01026 warning( i18n( "Could not change permissions for\n%1" , dest.toLocalFile() ) );
01027 }
01028 }
01029 #ifdef HAVE_POSIX_ACL
01030 if (acl) acl_free(acl);
01031 #endif
01032
01033
01034 struct utimbuf ut;
01035 ut.actime = buff_src.st_atime;
01036 ut.modtime = buff_src.st_mtime;
01037 if ( ::utime( _dest.data(), &ut ) != 0 )
01038 {
01039 kWarning() << QString::fromLatin1("Couldn't preserve access and modification time for\n%1").arg( _dest.data() );
01040 }
01041
01042 processedSize( buff_src.st_size );
01043 finished();
01044 }
01045
01046 void FileProtocol::rename( const KUrl &src, const KUrl &dest,
01047 KIO::JobFlags _flags )
01048 {
01049 char off_t_should_be_64_bits[sizeof(off_t) >= 8 ? 1 : -1]; (void) off_t_should_be_64_bits;
01050 QByteArray _src(QFile::encodeName(src.toLocalFile()));
01051 QByteArray _dest(QFile::encodeName(dest.toLocalFile()));
01052 KDE_struct_stat buff_src;
01053 if ( KDE_lstat( _src.data(), &buff_src ) == -1 ) {
01054 if ( errno == EACCES )
01055 error( KIO::ERR_ACCESS_DENIED, _src );
01056 else
01057 error( KIO::ERR_DOES_NOT_EXIST, _src );
01058 return;
01059 }
01060
01061 KDE_struct_stat buff_dest;
01062
01063
01064 bool dest_exists = ( KDE_lstat( _dest.data(), &buff_dest ) != -1 );
01065 if ( dest_exists )
01066 {
01067 if (S_ISDIR(buff_dest.st_mode))
01068 {
01069 error( KIO::ERR_DIR_ALREADY_EXIST, _dest );
01070 return;
01071 }
01072
01073 if ( same_inode( buff_dest, buff_src) )
01074 {
01075 error( KIO::ERR_IDENTICAL_FILES, _dest );
01076 return;
01077 }
01078
01079 if (!(_flags & KIO::Overwrite))
01080 {
01081 error( KIO::ERR_FILE_ALREADY_EXIST, _dest );
01082 return;
01083 }
01084 }
01085
01086 if ( KDE_rename( _src.data(), _dest.data()))
01087 {
01088 if (( errno == EACCES ) || (errno == EPERM)) {
01089 error( KIO::ERR_ACCESS_DENIED, _dest );
01090 }
01091 else if (errno == EXDEV) {
01092 error( KIO::ERR_UNSUPPORTED_ACTION, QLatin1String("rename"));
01093 }
01094 else if (errno == EROFS) {
01095 error( KIO::ERR_CANNOT_DELETE, _src );
01096 }
01097 else {
01098 error( KIO::ERR_CANNOT_RENAME, _src );
01099 }
01100 return;
01101 }
01102
01103 finished();
01104 }
01105
01106 void FileProtocol::symlink( const QString &target, const KUrl &dest, KIO::JobFlags flags )
01107 {
01108
01109 if ( ::symlink( QFile::encodeName( target ), QFile::encodeName( dest.path() ) ) == -1 )
01110 {
01111
01112 if ( errno == EEXIST )
01113 {
01114 if ( (flags & KIO::Overwrite) )
01115 {
01116
01117 if ( unlink( QFile::encodeName( dest.path() ) ) != 0 )
01118 {
01119 error( KIO::ERR_CANNOT_DELETE, dest.path() );
01120 return;
01121 }
01122
01123 symlink( target, dest, flags );
01124 }
01125 else
01126 {
01127 KDE_struct_stat buff_dest;
01128 KDE_lstat( QFile::encodeName( dest.path() ), &buff_dest );
01129 if (S_ISDIR(buff_dest.st_mode))
01130 error( KIO::ERR_DIR_ALREADY_EXIST, dest.path() );
01131 else
01132 error( KIO::ERR_FILE_ALREADY_EXIST, dest.path() );
01133 return;
01134 }
01135 }
01136 else
01137 {
01138
01139 error( KIO::ERR_CANNOT_SYMLINK, dest.path() );
01140 return;
01141 }
01142 }
01143 finished();
01144 }
01145
01146 void FileProtocol::del( const KUrl& url, bool isfile)
01147 {
01148 QByteArray _path( QFile::encodeName(url.toLocalFile()));
01149
01150
01151
01152
01153 if (isfile) {
01154 kDebug( 7101 ) << "Deleting file "<< url.url();
01155
01156
01157
01158 if ( unlink( _path.data() ) == -1 ) {
01159 if ((errno == EACCES) || (errno == EPERM))
01160 error( KIO::ERR_ACCESS_DENIED, _path );
01161 else if (errno == EISDIR)
01162 error( KIO::ERR_IS_DIRECTORY, _path );
01163 else
01164 error( KIO::ERR_CANNOT_DELETE, _path );
01165 return;
01166 }
01167 } else {
01168
01169
01170
01171
01172
01173 kDebug( 7101 ) << "Deleting directory " << url.url();
01174
01175 if ( ::rmdir( _path.data() ) == -1 ) {
01176 if ((errno == EACCES) || (errno == EPERM))
01177 error( KIO::ERR_ACCESS_DENIED, _path );
01178 else {
01179 kDebug( 7101 ) << "could not rmdir " << perror;
01180 error( KIO::ERR_COULD_NOT_RMDIR, _path );
01181 return;
01182 }
01183 }
01184 }
01185
01186 finished();
01187 }
01188
01189 #endif // Q_OS_WIN
01190
01191 QString FileProtocol::getUserName( uid_t uid ) const
01192 {
01193 if ( !mUsercache.contains( uid ) ) {
01194 struct passwd *user = getpwuid( uid );
01195 if ( user ) {
01196 mUsercache.insert( uid, QString::fromLatin1(user->pw_name) );
01197 }
01198 else
01199 return QString::number( uid );
01200 }
01201 return mUsercache[uid];
01202 }
01203
01204 QString FileProtocol::getGroupName( gid_t gid ) const
01205 {
01206 if ( !mGroupcache.contains( gid ) ) {
01207 struct group *grp = getgrgid( gid );
01208 if ( grp ) {
01209 mGroupcache.insert( gid, QString::fromLatin1(grp->gr_name) );
01210 }
01211 else
01212 return QString::number( gid );
01213 }
01214 return mGroupcache[gid];
01215 }
01216
01217 bool FileProtocol::createUDSEntry( const QString & filename, const QByteArray & path, UDSEntry & entry,
01218 short int details, bool withACL )
01219 {
01220 #ifndef HAVE_POSIX_ACL
01221 Q_UNUSED(withACL);
01222 #endif
01223 assert(entry.count() == 0);
01224
01225
01226
01227
01228
01229
01230 entry.insert( KIO::UDSEntry::UDS_NAME, filename );
01231
01232 mode_t type;
01233 mode_t access;
01234 KDE_struct_stat buff;
01235
01236 if ( KDE_lstat( path.data(), &buff ) == 0 ) {
01237
01238 if (S_ISLNK(buff.st_mode)) {
01239
01240 char buffer2[ 1000 ];
01241 int n = readlink( path.data(), buffer2, 1000 );
01242 if ( n != -1 ) {
01243 buffer2[ n ] = 0;
01244 }
01245
01246 entry.insert( KIO::UDSEntry::UDS_LINK_DEST, QFile::decodeName( buffer2 ) );
01247
01248
01249 if ( details > 1 && KDE_stat( path.data(), &buff ) == -1 ) {
01250
01251 type = S_IFMT - 1;
01252 access = S_IRWXU | S_IRWXG | S_IRWXO;
01253
01254 entry.insert( KIO::UDSEntry::UDS_FILE_TYPE, type );
01255 entry.insert( KIO::UDSEntry::UDS_ACCESS, access );
01256 entry.insert( KIO::UDSEntry::UDS_SIZE, 0LL );
01257 goto notype;
01258
01259 }
01260 }
01261 } else {
01262
01263 return false;
01264 }
01265
01266 type = buff.st_mode & S_IFMT;
01267 access = buff.st_mode & 07777;
01268
01269 entry.insert( KIO::UDSEntry::UDS_FILE_TYPE, type );
01270 entry.insert( KIO::UDSEntry::UDS_ACCESS, access );
01271
01272 entry.insert( KIO::UDSEntry::UDS_SIZE, buff.st_size );
01273
01274 #ifdef HAVE_POSIX_ACL
01275
01276
01277
01278 appendACLAtoms( path, entry, type, withACL );
01279 #endif
01280
01281 notype:
01282 entry.insert( KIO::UDSEntry::UDS_MODIFICATION_TIME, buff.st_mtime );
01283 entry.insert( KIO::UDSEntry::UDS_USER, getUserName( buff.st_uid ) );
01284 entry.insert( KIO::UDSEntry::UDS_GROUP, getGroupName( buff.st_gid ) );
01285 entry.insert( KIO::UDSEntry::UDS_ACCESS_TIME, buff.st_atime );
01286
01287
01288
01289
01290
01291 return true;
01292 }
01293
01294 void FileProtocol::stat( const KUrl & url )
01295 {
01296 if (!url.isLocalFile()) {
01297 KUrl redir(url);
01298 redir.setProtocol(config()->readEntry("DefaultRemoteProtocol", "smb"));
01299 redirection(redir);
01300 kDebug(7101) << "redirecting to " << redir.url();
01301 finished();
01302 return;
01303 }
01304
01305
01306
01307
01308
01309
01310
01311
01312 #ifdef Q_WS_WIN
01313 QByteArray _path( QFile::encodeName(url.toLocalFile()) );
01314 #else
01315 QByteArray _path( QFile::encodeName(url.path(KUrl::RemoveTrailingSlash)));
01316 #endif
01317 QString sDetails = metaData(QLatin1String("details"));
01318 int details = sDetails.isEmpty() ? 2 : sDetails.toInt();
01319 kDebug(7101) << "FileProtocol::stat details=" << details;
01320
01321 UDSEntry entry;
01322 if ( !createUDSEntry( url.fileName(), _path, entry, details, true ) )
01323 {
01324 error( KIO::ERR_DOES_NOT_EXIST, _path );
01325 return;
01326 }
01327 #if 0
01329 MetaData::iterator it1 = mOutgoingMetaData.begin();
01330 for ( ; it1 != mOutgoingMetaData.end(); it1++ ) {
01331 kDebug(7101) << it1.key() << " = " << it1.data();
01332 }
01334 #endif
01335 statEntry( entry );
01336
01337 finished();
01338 }
01339
01340 #ifndef Q_OS_WIN
01341 void FileProtocol::listDir( const KUrl& url)
01342 {
01343 kDebug(7101) << "========= LIST " << url.url() << " =========";
01344 if (!url.isLocalFile()) {
01345 KUrl redir(url);
01346 redir.setProtocol(config()->readEntry("DefaultRemoteProtocol", "smb"));
01347 redirection(redir);
01348 kDebug(7101) << "redirecting to " << redir.url();
01349 finished();
01350 return;
01351 }
01352 QByteArray _path( QFile::encodeName(url.toLocalFile()) );
01353 KDE_struct_stat buff;
01354 if ( KDE_stat( _path.data(), &buff ) == -1 ) {
01355 error( KIO::ERR_DOES_NOT_EXIST, _path );
01356 return;
01357 }
01358
01359 if ( !S_ISDIR( buff.st_mode ) ) {
01360 error( KIO::ERR_IS_FILE, _path );
01361 return;
01362 }
01363
01364 DIR *dp = 0L;
01365 KDE_struct_dirent *ep;
01366
01367 dp = opendir( _path.data() );
01368 if ( dp == 0 ) {
01369 switch (errno)
01370 {
01371 #ifdef ENOMEDIUM
01372 case ENOMEDIUM:
01373 error( ERR_SLAVE_DEFINED,
01374 i18n( "No media in device for %1", url.toLocalFile() ) );
01375 break;
01376 #else
01377 case ENOENT:
01378 #endif
01379 default:
01380 error( KIO::ERR_CANNOT_ENTER_DIRECTORY, _path );
01381 break;
01382 }
01383 return;
01384 }
01385
01386
01387
01388
01389 QList<QByteArray> entryNames;
01390 while ( ( ep = KDE_readdir( dp ) ) != 0L )
01391 entryNames.append( ep->d_name );
01392
01393 closedir( dp );
01394 totalSize( entryNames.count() );
01395
01396
01397
01398
01399
01400
01401
01402
01403 char path_buffer[PATH_MAX];
01404 getcwd(path_buffer, PATH_MAX - 1);
01405 if ( chdir( _path.data() ) ) {
01406 if (errno == EACCES)
01407 error(ERR_ACCESS_DENIED, _path);
01408 else
01409 error(ERR_CANNOT_ENTER_DIRECTORY, _path);
01410 finished();
01411 }
01412
01413 UDSEntry entry;
01414 QList<QByteArray>::ConstIterator it = entryNames.constBegin();
01415 QList<QByteArray>::ConstIterator end = entryNames.constEnd();
01416 for (; it != end; ++it) {
01417 entry.clear();
01418 if ( createUDSEntry( QFile::decodeName(*it),
01419 *it ,
01420 entry, 2, true ) )
01421 listEntry( entry, false);
01422 }
01423
01424 listEntry( entry, true );
01425
01426 kDebug(7101) << "============= COMPLETED LIST ============";
01427
01428 chdir(path_buffer);
01429 finished();
01430 }
01431 #endif // !Q_OS_WIN
01432
01433
01434
01435
01436
01437
01438
01439
01440
01441
01442
01443
01444
01445
01446
01447
01448
01449
01450
01451
01452 void FileProtocol::special( const QByteArray &data)
01453 {
01454 int tmp;
01455 QDataStream stream(data);
01456
01457 stream >> tmp;
01458 switch (tmp) {
01459 case 1:
01460 {
01461 QString fstype, dev, point;
01462 qint8 iRo;
01463
01464 stream >> iRo >> fstype >> dev >> point;
01465
01466 bool ro = ( iRo != 0 );
01467
01468 kDebug(7101) << "MOUNTING fstype=" << fstype << " dev=" << dev << " point=" << point << " ro=" << ro;
01469 bool ok = pmount( dev );
01470 if (ok)
01471 finished();
01472 else
01473 mount( ro, fstype.toAscii(), dev, point );
01474
01475 }
01476 break;
01477 case 2:
01478 {
01479 QString point;
01480 stream >> point;
01481 bool ok = pumount( point );
01482 if (ok)
01483 finished();
01484 else
01485 unmount( point );
01486 }
01487 break;
01488
01489 default:
01490 break;
01491 }
01492 }
01493
01494
01495 void FileProtocol::slotProcessedSize( KIO::filesize_t bytes )
01496 {
01497 kDebug(7101) << "FileProtocol::slotProcessedSize (" << (unsigned int) bytes << ")";
01498 processedSize( bytes );
01499 }
01500
01501
01502 void FileProtocol::slotInfoMessage( const QString & msg )
01503 {
01504 kDebug(7101) << "FileProtocol::slotInfoMessage (" << msg << ")";
01505 infoMessage( msg );
01506 }
01507
01508 void FileProtocol::mount( bool _ro, const char *_fstype, const QString& _dev, const QString& _point )
01509 {
01510 kDebug(7101) << "FileProtocol::mount _fstype=" << _fstype;
01511
01512 #ifdef HAVE_VOLMGT
01513
01514
01515
01516 QString err;
01517 QByteArray devname = QFile::encodeName( _dev );
01518
01519 if( volmgt_running() ) {
01520
01521 if( volmgt_check( devname.data() ) == 0 ) {
01522 kDebug(7101) << "VOLMGT: no media in "
01523 << devname.data();
01524 err = i18n("No Media inserted or Media not recognized.");
01525 error( KIO::ERR_COULD_NOT_MOUNT, err );
01526 return;
01527 } else {
01528 kDebug(7101) << "VOLMGT: " << devname.data()
01529 << ": media ok";
01530 finished();
01531 return;
01532 }
01533 } else {
01534 err = i18n("\"vold\" is not running.");
01535 kDebug(7101) << "VOLMGT: " << err;
01536 error( KIO::ERR_COULD_NOT_MOUNT, err );
01537 return;
01538 }
01539 #else
01540
01541
01542 KTemporaryFile tmpFile;
01543 tmpFile.setAutoRemove(false);
01544 tmpFile.open();
01545 QByteArray tmpFileName = QFile::encodeName(tmpFile.fileName());
01546 QByteArray dev;
01547 if ( _dev.startsWith( "LABEL=" ) ) {
01548 QString labelName = _dev.mid( 6 );
01549 dev = "-L ";
01550 dev += QFile::encodeName( KShell::quoteArg( labelName ) );
01551 } else if ( _dev.startsWith( "UUID=" ) ) {
01552 QString uuidName = _dev.mid( 5 );
01553 dev = "-U ";
01554 dev += QFile::encodeName( KShell::quoteArg( uuidName ) );
01555 }
01556 else
01557 dev = QFile::encodeName( KShell::quoteArg(_dev) );
01558
01559 QByteArray point = QFile::encodeName( KShell::quoteArg(_point) );
01560 bool fstype_empty = !_fstype || !*_fstype;
01561 QByteArray fstype = KShell::quoteArg(_fstype).toLatin1();
01562 QByteArray readonly = _ro ? "-r" : "";
01563 QString epath = QString::fromLocal8Bit(qgetenv("PATH"));
01564 QString path = QLatin1String("/sbin:/bin");
01565 if(!epath.isEmpty())
01566 path += QLatin1String(":") + epath;
01567 QByteArray mountProg = KGlobal::dirs()->findExe("mount", path).toLocal8Bit();
01568 if (mountProg.isEmpty()){
01569 error( KIO::ERR_COULD_NOT_MOUNT, i18n("Could not find program \"mount\""));
01570 return;
01571 }
01572 QByteArray buffer = mountProg + ' ';
01573
01574
01575 for ( int step = 0 ; step <= 1 ; step++ )
01576 {
01577
01578 if ( !_dev.isEmpty() && _point.isEmpty() && fstype_empty )
01579 buffer += dev;
01580 else
01581
01582 if ( !_point.isEmpty() && _dev.isEmpty() && fstype_empty )
01583 buffer += point;
01584 else
01585
01586 if ( !_point.isEmpty() && !_dev.isEmpty() && fstype_empty )
01587 buffer += readonly + ' ' + dev + ' ' + point;
01588 else
01589
01590 #if defined(__svr4__) && defined(Q_OS_SOLARIS) // MARCO for Solaris 8 and I
01591
01592 buffer += "-F " + fstype + ' ' + (_ro ? "-oro" : "") + ' ' + dev + ' ' + point;
01593 #else
01594 buffer += readonly + " -t " + fstype + ' ' + dev + ' ' + point;
01595 #endif
01596 buffer += " 2>" + tmpFileName;
01597 kDebug(7101) << buffer;
01598
01599 int mount_ret = system( buffer.constData() );
01600
01601 QString err = testLogFile( tmpFileName );
01602 if ( err.isEmpty() && mount_ret == 0)
01603 {
01604 finished();
01605 return;
01606 }
01607 else
01608 {
01609
01610 KMountPoint::Ptr mp = KMountPoint::currentMountPoints().findByDevice( _dev );
01611
01612 if ( mp && mount_ret == 0)
01613 {
01614 kDebug(7101) << "mount got a warning: " << err;
01615 warning( err );
01616 finished();
01617 return;
01618 }
01619 else
01620 {
01621 if ( (step == 0) && !_point.isEmpty())
01622 {
01623 kDebug(7101) << err;
01624 kDebug(7101) << "Mounting with those options didn't work, trying with only mountpoint";
01625 fstype = "";
01626 fstype_empty = true;
01627 dev = "";
01628
01629
01630
01631
01632
01633
01634
01635
01636 }
01637 else
01638 {
01639 error( KIO::ERR_COULD_NOT_MOUNT, err );
01640 return;
01641 }
01642 }
01643 }
01644 }
01645 #endif
01646 }
01647
01648
01649 void FileProtocol::unmount( const QString& _point )
01650 {
01651 QByteArray buffer;
01652
01653 KTemporaryFile tmpFile;
01654 tmpFile.setAutoRemove(false);
01655 tmpFile.open();
01656 QByteArray tmpFileName = QFile::encodeName(tmpFile.fileName());
01657 QString err;
01658
01659 #ifdef HAVE_VOLMGT
01660
01661
01662
01663 char *devname;
01664 char *ptr;
01665 FILE *mnttab;
01666 struct mnttab mnt;
01667
01668 if( volmgt_running() ) {
01669 kDebug(7101) << "VOLMGT: looking for "
01670 << _point.toLocal8Bit();
01671
01672 if( (mnttab = KDE_fopen( MNTTAB, "r" )) == NULL ) {
01673 err = "could not open mnttab";
01674 kDebug(7101) << "VOLMGT: " << err;
01675 error( KIO::ERR_COULD_NOT_UNMOUNT, err );
01676 return;
01677 }
01678
01679
01680
01681
01682
01683
01684
01685 devname = NULL;
01686 rewind( mnttab );
01687 while( getmntent( mnttab, &mnt ) == 0 ) {
01688 if( strcmp( _point.toLocal8Bit(), mnt.mnt_mountp ) == 0 ){
01689 devname = mnt.mnt_special;
01690 break;
01691 }
01692 }
01693 fclose( mnttab );
01694
01695 if( devname == NULL ) {
01696 err = "not in mnttab";
01697 kDebug(7101) << "VOLMGT: "
01698 << QFile::encodeName(_point).data()
01699 << ": " << err;
01700 error( KIO::ERR_COULD_NOT_UNMOUNT, err );
01701 return;
01702 }
01703
01704
01705
01706
01707
01708
01709 ptr = strrchr( devname, '/' );
01710 *ptr = '\0';
01711 QByteArray qdevname(QFile::encodeName(KShell::quoteArg(QFile::decodeName(QByteArray(devname)))).data());
01712 buffer = "/usr/bin/eject " + qdevname + " 2>" + tmpFileName;
01713 kDebug(7101) << "VOLMGT: eject " << qdevname;
01714
01715
01716
01717
01718
01719 if( WEXITSTATUS( system( buffer.constData() )) == 4 ) {
01720
01721
01722
01723
01724 QFile::remove( tmpFileName );
01725 finished();
01726 return;
01727 }
01728 } else {
01729
01730
01731
01732
01733
01734
01735 err = i18n("\"vold\" is not running.");
01736 kDebug(7101) << "VOLMGT: " << err;
01737 error( KIO::ERR_COULD_NOT_UNMOUNT, err );
01738 return;
01739 }
01740 #else
01741 QString epath = QString::fromLocal8Bit(qgetenv("PATH"));
01742 QString path = QLatin1String("/sbin:/bin");
01743 if (!epath.isEmpty())
01744 path += ':' + epath;
01745 QByteArray umountProg = KGlobal::dirs()->findExe("umount", path).toLocal8Bit();
01746
01747 if (umountProg.isEmpty()) {
01748 error( KIO::ERR_COULD_NOT_UNMOUNT, i18n("Could not find program \"umount\""));
01749 return;
01750 }
01751 buffer = umountProg + QFile::encodeName(KShell::quoteArg(_point)) + " 2>" + tmpFileName;
01752 system( buffer.constData() );
01753 #endif
01754
01755 err = testLogFile( tmpFileName );
01756 if ( err.isEmpty() )
01757 finished();
01758 else
01759 error( KIO::ERR_COULD_NOT_UNMOUNT, err );
01760 }
01761
01762
01763
01764
01765
01766
01767
01768 bool FileProtocol::pmount(const QString &dev)
01769 {
01770 QString epath = QString::fromLocal8Bit(qgetenv("PATH"));
01771 QString path = QLatin1String("/sbin:/bin");
01772 if (!epath.isEmpty())
01773 path += ':' + epath;
01774 QString pmountProg = KGlobal::dirs()->findExe("pmount", path);
01775
01776 if (pmountProg.isEmpty())
01777 return false;
01778
01779 QByteArray buffer = QFile::encodeName(pmountProg) + ' ' +
01780 QFile::encodeName(KShell::quoteArg(dev));
01781
01782 int res = system( buffer.constData() );
01783
01784 return res==0;
01785 }
01786
01787 bool FileProtocol::pumount(const QString &point)
01788 {
01789 KMountPoint::Ptr mp = KMountPoint::currentMountPoints(KMountPoint::NeedRealDeviceName).findByPath(point);
01790 if (!mp)
01791 return false;
01792 QString dev = mp->realDeviceName();
01793 if (dev.isEmpty()) return false;
01794
01795 QString epath = QString::fromLocal8Bit(qgetenv("PATH"));
01796 QString path = QLatin1String("/sbin:/bin");
01797 if (!epath.isEmpty())
01798 path += ':' + epath;
01799 QString pumountProg = KGlobal::dirs()->findExe("pumount", path);
01800
01801 if (pumountProg.isEmpty())
01802 return false;
01803
01804 QByteArray buffer = QFile::encodeName(pumountProg);
01805 buffer += ' ';
01806 buffer += QFile::encodeName(KShell::quoteArg(dev));
01807
01808 int res = system( buffer.data() );
01809
01810 return res==0;
01811 }
01812
01813
01814
01815
01816
01817
01818
01819 static QString testLogFile( const QByteArray& _filename )
01820 {
01821 char buffer[ 1024 ];
01822 KDE_struct_stat buff;
01823
01824 QString result;
01825
01826 KDE_stat( _filename, &buff );
01827 int size = buff.st_size;
01828 if ( size == 0 ) {
01829 unlink( _filename );
01830 return result;
01831 }
01832
01833 FILE * f = KDE_fopen( _filename, "rb" );
01834 if ( f == 0L ) {
01835 unlink( _filename );
01836 result = i18n("Could not read %1", QFile::decodeName(_filename));
01837 return result;
01838 }
01839
01840 result = "";
01841 const char *p = "";
01842 while ( p != 0L ) {
01843 p = fgets( buffer, sizeof(buffer)-1, f );
01844 if ( p != 0L )
01845 result += QString::fromLocal8Bit(buffer);
01846 }
01847
01848 fclose( f );
01849
01850 unlink( _filename );
01851
01852 return result;
01853 }
01854
01855
01856
01857
01858
01859
01860 #ifdef HAVE_POSIX_ACL
01861
01862 static bool isExtendedACL( acl_t acl )
01863 {
01864 return ( acl_equiv_mode( acl, 0 ) != 0 );
01865 }
01866
01867 static void appendACLAtoms( const QByteArray & path, UDSEntry& entry, mode_t type, bool withACL )
01868 {
01869
01870 if ( acl_extended_file( path.data() ) == 0 ) return;
01871
01872 acl_t acl = 0;
01873 acl_t defaultAcl = 0;
01874 bool isDir = S_ISDIR( type );
01875
01876 acl = acl_get_file( path.data(), ACL_TYPE_ACCESS );
01877
01878
01879 if ( isDir ) {
01880 if ( acl ) {
01881 if ( !isExtendedACL( acl ) ) {
01882 acl_free( acl );
01883 acl = 0;
01884 }
01885 }
01886 defaultAcl = acl_get_file( path.data(), ACL_TYPE_DEFAULT );
01887 }
01888 if ( acl || defaultAcl ) {
01889 kDebug(7101) << path.data() << " has extended ACL entries ";
01890 entry.insert( KIO::UDSEntry::UDS_EXTENDED_ACL, 1 );
01891 }
01892 if ( withACL ) {
01893 if ( acl ) {
01894 ssize_t size = acl_size( acl );
01895 const QString str = QString::fromLatin1( acl_to_text( acl, &size ) );
01896 entry.insert( KIO::UDSEntry::UDS_ACL_STRING, str );
01897 kDebug(7101) << path.data() << "ACL: " << str;
01898 }
01899 if ( defaultAcl ) {
01900 ssize_t size = acl_size( defaultAcl );
01901 const QString str = QString::fromLatin1( acl_to_text( defaultAcl, &size ) );
01902 entry.insert( KIO::UDSEntry::UDS_DEFAULT_ACL_STRING, str );
01903 kDebug(7101) << path.data() << "DEFAULT ACL: " << str;
01904 }
01905 }
01906 if ( acl ) acl_free( acl );
01907 if ( defaultAcl ) acl_free( defaultAcl );
01908 }
01909 #endif
01910
01911 #include "file.moc"