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 kDebug(7101) << "copy(): LINK DESTINATION";
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 bool dest_exists = ( KDE_stat( _dest.data(), &buff_dest ) != -1 );
01063 if ( dest_exists )
01064 {
01065 if (S_ISDIR(buff_dest.st_mode))
01066 {
01067 error( KIO::ERR_DIR_ALREADY_EXIST, _dest );
01068 return;
01069 }
01070
01071 if ( same_inode( buff_dest, buff_src) )
01072 {
01073 error( KIO::ERR_IDENTICAL_FILES, _dest );
01074 return;
01075 }
01076
01077 if (!(_flags & KIO::Overwrite))
01078 {
01079 error( KIO::ERR_FILE_ALREADY_EXIST, _dest );
01080 return;
01081 }
01082 }
01083
01084 if ( KDE_rename( _src.data(), _dest.data()))
01085 {
01086 if (( errno == EACCES ) || (errno == EPERM)) {
01087 error( KIO::ERR_ACCESS_DENIED, _dest );
01088 }
01089 else if (errno == EXDEV) {
01090 error( KIO::ERR_UNSUPPORTED_ACTION, QLatin1String("rename"));
01091 }
01092 else if (errno == EROFS) {
01093 error( KIO::ERR_CANNOT_DELETE, _src );
01094 }
01095 else {
01096 error( KIO::ERR_CANNOT_RENAME, _src );
01097 }
01098 return;
01099 }
01100
01101 finished();
01102 }
01103
01104 void FileProtocol::symlink( const QString &target, const KUrl &dest, KIO::JobFlags flags )
01105 {
01106
01107 if ( ::symlink( QFile::encodeName( target ), QFile::encodeName( dest.path() ) ) == -1 )
01108 {
01109
01110 if ( errno == EEXIST )
01111 {
01112 if ( (flags & KIO::Overwrite) )
01113 {
01114
01115 if ( unlink( QFile::encodeName( dest.path() ) ) != 0 )
01116 {
01117 error( KIO::ERR_CANNOT_DELETE, dest.path() );
01118 return;
01119 }
01120
01121 symlink( target, dest, flags );
01122 }
01123 else
01124 {
01125 KDE_struct_stat buff_dest;
01126 KDE_lstat( QFile::encodeName( dest.path() ), &buff_dest );
01127 if (S_ISDIR(buff_dest.st_mode))
01128 error( KIO::ERR_DIR_ALREADY_EXIST, dest.path() );
01129 else
01130 error( KIO::ERR_FILE_ALREADY_EXIST, dest.path() );
01131 return;
01132 }
01133 }
01134 else
01135 {
01136
01137 error( KIO::ERR_CANNOT_SYMLINK, dest.path() );
01138 return;
01139 }
01140 }
01141 finished();
01142 }
01143
01144 void FileProtocol::del( const KUrl& url, bool isfile)
01145 {
01146 QByteArray _path( QFile::encodeName(url.toLocalFile()));
01147
01148
01149
01150
01151 if (isfile) {
01152 kDebug( 7101 ) << "Deleting file "<< url.url();
01153
01154
01155
01156 if ( unlink( _path.data() ) == -1 ) {
01157 if ((errno == EACCES) || (errno == EPERM))
01158 error( KIO::ERR_ACCESS_DENIED, _path );
01159 else if (errno == EISDIR)
01160 error( KIO::ERR_IS_DIRECTORY, _path );
01161 else
01162 error( KIO::ERR_CANNOT_DELETE, _path );
01163 return;
01164 }
01165 } else {
01166
01167
01168
01169
01170
01171 kDebug( 7101 ) << "Deleting directory " << url.url();
01172
01173 if ( ::rmdir( _path.data() ) == -1 ) {
01174 if ((errno == EACCES) || (errno == EPERM))
01175 error( KIO::ERR_ACCESS_DENIED, _path );
01176 else {
01177 kDebug( 7101 ) << "could not rmdir " << perror;
01178 error( KIO::ERR_COULD_NOT_RMDIR, _path );
01179 return;
01180 }
01181 }
01182 }
01183
01184 finished();
01185 }
01186
01187 #endif // Q_OS_WIN
01188
01189 QString FileProtocol::getUserName( uid_t uid ) const
01190 {
01191 if ( !mUsercache.contains( uid ) ) {
01192 struct passwd *user = getpwuid( uid );
01193 if ( user ) {
01194 mUsercache.insert( uid, QString::fromLatin1(user->pw_name) );
01195 }
01196 else
01197 return QString::number( uid );
01198 }
01199 return mUsercache[uid];
01200 }
01201
01202 QString FileProtocol::getGroupName( gid_t gid ) const
01203 {
01204 if ( !mGroupcache.contains( gid ) ) {
01205 struct group *grp = getgrgid( gid );
01206 if ( grp ) {
01207 mGroupcache.insert( gid, QString::fromLatin1(grp->gr_name) );
01208 }
01209 else
01210 return QString::number( gid );
01211 }
01212 return mGroupcache[gid];
01213 }
01214
01215 bool FileProtocol::createUDSEntry( const QString & filename, const QByteArray & path, UDSEntry & entry,
01216 short int details, bool withACL )
01217 {
01218 #ifndef HAVE_POSIX_ACL
01219 Q_UNUSED(withACL);
01220 #endif
01221 assert(entry.count() == 0);
01222
01223
01224
01225
01226
01227
01228 entry.insert( KIO::UDSEntry::UDS_NAME, filename );
01229
01230 mode_t type;
01231 mode_t access;
01232 KDE_struct_stat buff;
01233
01234 if ( KDE_lstat( path.data(), &buff ) == 0 ) {
01235
01236 if (S_ISLNK(buff.st_mode)) {
01237
01238 char buffer2[ 1000 ];
01239 int n = readlink( path.data(), buffer2, 1000 );
01240 if ( n != -1 ) {
01241 buffer2[ n ] = 0;
01242 }
01243
01244 entry.insert( KIO::UDSEntry::UDS_LINK_DEST, QFile::decodeName( buffer2 ) );
01245
01246
01247 if ( details > 1 && KDE_stat( path.data(), &buff ) == -1 ) {
01248
01249 type = S_IFMT - 1;
01250 access = S_IRWXU | S_IRWXG | S_IRWXO;
01251
01252 entry.insert( KIO::UDSEntry::UDS_FILE_TYPE, type );
01253 entry.insert( KIO::UDSEntry::UDS_ACCESS, access );
01254 entry.insert( KIO::UDSEntry::UDS_SIZE, 0LL );
01255 goto notype;
01256
01257 }
01258 }
01259 } else {
01260
01261 return false;
01262 }
01263
01264 type = buff.st_mode & S_IFMT;
01265 access = buff.st_mode & 07777;
01266
01267 entry.insert( KIO::UDSEntry::UDS_FILE_TYPE, type );
01268 entry.insert( KIO::UDSEntry::UDS_ACCESS, access );
01269
01270 entry.insert( KIO::UDSEntry::UDS_SIZE, buff.st_size );
01271
01272 #ifdef HAVE_POSIX_ACL
01273
01274
01275
01276 appendACLAtoms( path, entry, type, withACL );
01277 #endif
01278
01279 notype:
01280 entry.insert( KIO::UDSEntry::UDS_MODIFICATION_TIME, buff.st_mtime );
01281 entry.insert( KIO::UDSEntry::UDS_USER, getUserName( buff.st_uid ) );
01282 entry.insert( KIO::UDSEntry::UDS_GROUP, getGroupName( buff.st_gid ) );
01283 entry.insert( KIO::UDSEntry::UDS_ACCESS_TIME, buff.st_atime );
01284
01285
01286
01287
01288
01289 return true;
01290 }
01291
01292 void FileProtocol::stat( const KUrl & url )
01293 {
01294 if (!url.isLocalFile()) {
01295 KUrl redir(url);
01296 redir.setProtocol(config()->readEntry("DefaultRemoteProtocol", "smb"));
01297 redirection(redir);
01298 kDebug(7101) << "redirecting to " << redir.url();
01299 finished();
01300 return;
01301 }
01302
01303
01304
01305
01306
01307
01308
01309
01310 #ifdef Q_WS_WIN
01311 QByteArray _path( QFile::encodeName(url.toLocalFile()) );
01312 #else
01313 QByteArray _path( QFile::encodeName(url.path(KUrl::RemoveTrailingSlash)));
01314 #endif
01315 QString sDetails = metaData(QLatin1String("details"));
01316 int details = sDetails.isEmpty() ? 2 : sDetails.toInt();
01317 kDebug(7101) << "FileProtocol::stat details=" << details;
01318
01319 UDSEntry entry;
01320 if ( !createUDSEntry( url.fileName(), _path, entry, details, true ) )
01321 {
01322 error( KIO::ERR_DOES_NOT_EXIST, _path );
01323 return;
01324 }
01325 #if 0
01327 MetaData::iterator it1 = mOutgoingMetaData.begin();
01328 for ( ; it1 != mOutgoingMetaData.end(); it1++ ) {
01329 kDebug(7101) << it1.key() << " = " << it1.data();
01330 }
01332 #endif
01333 statEntry( entry );
01334
01335 finished();
01336 }
01337
01338 #ifndef Q_OS_WIN
01339 void FileProtocol::listDir( const KUrl& url)
01340 {
01341 kDebug(7101) << "========= LIST " << url.url() << " =========";
01342 if (!url.isLocalFile()) {
01343 KUrl redir(url);
01344 redir.setProtocol(config()->readEntry("DefaultRemoteProtocol", "smb"));
01345 redirection(redir);
01346 kDebug(7101) << "redirecting to " << redir.url();
01347 finished();
01348 return;
01349 }
01350 QByteArray _path( QFile::encodeName(url.toLocalFile()) );
01351 KDE_struct_stat buff;
01352 if ( KDE_stat( _path.data(), &buff ) == -1 ) {
01353 error( KIO::ERR_DOES_NOT_EXIST, _path );
01354 return;
01355 }
01356
01357 if ( !S_ISDIR( buff.st_mode ) ) {
01358 error( KIO::ERR_IS_FILE, _path );
01359 return;
01360 }
01361
01362 DIR *dp = 0L;
01363 KDE_struct_dirent *ep;
01364
01365 dp = opendir( _path.data() );
01366 if ( dp == 0 ) {
01367 switch (errno)
01368 {
01369 #ifdef ENOMEDIUM
01370 case ENOMEDIUM:
01371 error( ERR_SLAVE_DEFINED,
01372 i18n( "No media in device for %1", url.toLocalFile() ) );
01373 break;
01374 #else
01375 case ENOENT:
01376 #endif
01377 default:
01378 error( KIO::ERR_CANNOT_ENTER_DIRECTORY, _path );
01379 break;
01380 }
01381 return;
01382 }
01383
01384
01385
01386
01387 QList<QByteArray> entryNames;
01388 while ( ( ep = KDE_readdir( dp ) ) != 0L )
01389 entryNames.append( ep->d_name );
01390
01391 closedir( dp );
01392 totalSize( entryNames.count() );
01393
01394
01395
01396
01397
01398
01399
01400
01401 char path_buffer[PATH_MAX];
01402 getcwd(path_buffer, PATH_MAX - 1);
01403 if ( chdir( _path.data() ) ) {
01404 if (errno == EACCES)
01405 error(ERR_ACCESS_DENIED, _path);
01406 else
01407 error(ERR_CANNOT_ENTER_DIRECTORY, _path);
01408 finished();
01409 }
01410
01411 UDSEntry entry;
01412 QList<QByteArray>::ConstIterator it = entryNames.constBegin();
01413 QList<QByteArray>::ConstIterator end = entryNames.constEnd();
01414 for (; it != end; ++it) {
01415 entry.clear();
01416 if ( createUDSEntry( QFile::decodeName(*it),
01417 *it ,
01418 entry, 2, true ) )
01419 listEntry( entry, false);
01420 }
01421
01422 listEntry( entry, true );
01423
01424 kDebug(7101) << "============= COMPLETED LIST ============";
01425
01426 chdir(path_buffer);
01427 finished();
01428 }
01429 #endif // !Q_OS_WIN
01430
01431
01432
01433
01434
01435
01436
01437
01438
01439
01440
01441
01442
01443
01444
01445
01446
01447
01448
01449
01450 void FileProtocol::special( const QByteArray &data)
01451 {
01452 int tmp;
01453 QDataStream stream(data);
01454
01455 stream >> tmp;
01456 switch (tmp) {
01457 case 1:
01458 {
01459 QString fstype, dev, point;
01460 qint8 iRo;
01461
01462 stream >> iRo >> fstype >> dev >> point;
01463
01464 bool ro = ( iRo != 0 );
01465
01466 kDebug(7101) << "MOUNTING fstype=" << fstype << " dev=" << dev << " point=" << point << " ro=" << ro;
01467 bool ok = pmount( dev );
01468 if (ok)
01469 finished();
01470 else
01471 mount( ro, fstype.toAscii(), dev, point );
01472
01473 }
01474 break;
01475 case 2:
01476 {
01477 QString point;
01478 stream >> point;
01479 bool ok = pumount( point );
01480 if (ok)
01481 finished();
01482 else
01483 unmount( point );
01484 }
01485 break;
01486
01487 default:
01488 break;
01489 }
01490 }
01491
01492
01493 void FileProtocol::slotProcessedSize( KIO::filesize_t bytes )
01494 {
01495 kDebug(7101) << "FileProtocol::slotProcessedSize (" << (unsigned int) bytes << ")";
01496 processedSize( bytes );
01497 }
01498
01499
01500 void FileProtocol::slotInfoMessage( const QString & msg )
01501 {
01502 kDebug(7101) << "FileProtocol::slotInfoMessage (" << msg << ")";
01503 infoMessage( msg );
01504 }
01505
01506 void FileProtocol::mount( bool _ro, const char *_fstype, const QString& _dev, const QString& _point )
01507 {
01508 kDebug(7101) << "FileProtocol::mount _fstype=" << _fstype;
01509
01510 #ifdef HAVE_VOLMGT
01511
01512
01513
01514 QString err;
01515 QByteArray devname = QFile::encodeName( _dev );
01516
01517 if( volmgt_running() ) {
01518
01519 if( volmgt_check( devname.data() ) == 0 ) {
01520 kDebug(7101) << "VOLMGT: no media in "
01521 << devname.data();
01522 err = i18n("No Media inserted or Media not recognized.");
01523 error( KIO::ERR_COULD_NOT_MOUNT, err );
01524 return;
01525 } else {
01526 kDebug(7101) << "VOLMGT: " << devname.data()
01527 << ": media ok";
01528 finished();
01529 return;
01530 }
01531 } else {
01532 err = i18n("\"vold\" is not running.");
01533 kDebug(7101) << "VOLMGT: " << err;
01534 error( KIO::ERR_COULD_NOT_MOUNT, err );
01535 return;
01536 }
01537 #else
01538
01539
01540 KTemporaryFile tmpFile;
01541 tmpFile.setAutoRemove(false);
01542 tmpFile.open();
01543 QByteArray tmpFileName = QFile::encodeName(tmpFile.fileName());
01544 QByteArray dev;
01545 if ( _dev.startsWith( "LABEL=" ) ) {
01546 QString labelName = _dev.mid( 6 );
01547 dev = "-L ";
01548 dev += QFile::encodeName( KShell::quoteArg( labelName ) );
01549 } else if ( _dev.startsWith( "UUID=" ) ) {
01550 QString uuidName = _dev.mid( 5 );
01551 dev = "-U ";
01552 dev += QFile::encodeName( KShell::quoteArg( uuidName ) );
01553 }
01554 else
01555 dev = QFile::encodeName( KShell::quoteArg(_dev) );
01556
01557 QByteArray point = QFile::encodeName( KShell::quoteArg(_point) );
01558 bool fstype_empty = !_fstype || !*_fstype;
01559 QByteArray fstype = KShell::quoteArg(_fstype).toLatin1();
01560 QByteArray readonly = _ro ? "-r" : "";
01561 QString epath = QString::fromLocal8Bit(qgetenv("PATH"));
01562 QString path = QLatin1String("/sbin:/bin");
01563 if(!epath.isEmpty())
01564 path += QLatin1String(":") + epath;
01565 QByteArray mountProg = KGlobal::dirs()->findExe("mount", path).toLocal8Bit();
01566 if (mountProg.isEmpty()){
01567 error( KIO::ERR_COULD_NOT_MOUNT, i18n("Could not find program \"mount\""));
01568 return;
01569 }
01570 QByteArray buffer = mountProg + ' ';
01571
01572
01573 for ( int step = 0 ; step <= 1 ; step++ )
01574 {
01575
01576 if ( !_dev.isEmpty() && _point.isEmpty() && fstype_empty )
01577 buffer += dev;
01578 else
01579
01580 if ( !_point.isEmpty() && _dev.isEmpty() && fstype_empty )
01581 buffer += point;
01582 else
01583
01584 if ( !_point.isEmpty() && !_dev.isEmpty() && fstype_empty )
01585 buffer += readonly + ' ' + dev + ' ' + point;
01586 else
01587
01588 #if defined(__svr4__) && defined(Q_OS_SOLARIS) // MARCO for Solaris 8 and I
01589
01590 buffer += "-F " + fstype + ' ' + (_ro ? "-oro" : "") + ' ' + dev + ' ' + point;
01591 #else
01592 buffer += readonly + " -t " + fstype + ' ' + dev + ' ' + point;
01593 #endif
01594 buffer += " 2>" + tmpFileName;
01595 kDebug(7101) << buffer;
01596
01597 int mount_ret = system( buffer.constData() );
01598
01599 QString err = testLogFile( tmpFileName );
01600 if ( err.isEmpty() && mount_ret == 0)
01601 {
01602 finished();
01603 return;
01604 }
01605 else
01606 {
01607
01608 KMountPoint::Ptr mp = KMountPoint::currentMountPoints().findByDevice( _dev );
01609
01610 if ( mp && mount_ret == 0)
01611 {
01612 kDebug(7101) << "mount got a warning: " << err;
01613 warning( err );
01614 finished();
01615 return;
01616 }
01617 else
01618 {
01619 if ( (step == 0) && !_point.isEmpty())
01620 {
01621 kDebug(7101) << err;
01622 kDebug(7101) << "Mounting with those options didn't work, trying with only mountpoint";
01623 fstype = "";
01624 fstype_empty = true;
01625 dev = "";
01626
01627
01628
01629
01630
01631
01632
01633
01634 }
01635 else
01636 {
01637 error( KIO::ERR_COULD_NOT_MOUNT, err );
01638 return;
01639 }
01640 }
01641 }
01642 }
01643 #endif
01644 }
01645
01646
01647 void FileProtocol::unmount( const QString& _point )
01648 {
01649 QByteArray buffer;
01650
01651 KTemporaryFile tmpFile;
01652 tmpFile.setAutoRemove(false);
01653 tmpFile.open();
01654 QByteArray tmpFileName = QFile::encodeName(tmpFile.fileName());
01655 QString err;
01656
01657 #ifdef HAVE_VOLMGT
01658
01659
01660
01661 char *devname;
01662 char *ptr;
01663 FILE *mnttab;
01664 struct mnttab mnt;
01665
01666 if( volmgt_running() ) {
01667 kDebug(7101) << "VOLMGT: looking for "
01668 << _point.toLocal8Bit();
01669
01670 if( (mnttab = KDE_fopen( MNTTAB, "r" )) == NULL ) {
01671 err = "could not open mnttab";
01672 kDebug(7101) << "VOLMGT: " << err;
01673 error( KIO::ERR_COULD_NOT_UNMOUNT, err );
01674 return;
01675 }
01676
01677
01678
01679
01680
01681
01682
01683 devname = NULL;
01684 rewind( mnttab );
01685 while( getmntent( mnttab, &mnt ) == 0 ) {
01686 if( strcmp( _point.toLocal8Bit(), mnt.mnt_mountp ) == 0 ){
01687 devname = mnt.mnt_special;
01688 break;
01689 }
01690 }
01691 fclose( mnttab );
01692
01693 if( devname == NULL ) {
01694 err = "not in mnttab";
01695 kDebug(7101) << "VOLMGT: "
01696 << QFile::encodeName(_point).data()
01697 << ": " << err;
01698 error( KIO::ERR_COULD_NOT_UNMOUNT, err );
01699 return;
01700 }
01701
01702
01703
01704
01705
01706
01707 ptr = strrchr( devname, '/' );
01708 *ptr = '\0';
01709 QByteArray qdevname(QFile::encodeName(KShell::quoteArg(QFile::decodeName(QByteArray(devname)))).data());
01710 buffer = "/usr/bin/eject " + qdevname + " 2>" + tmpFileName;
01711 kDebug(7101) << "VOLMGT: eject " << qdevname;
01712
01713
01714
01715
01716
01717 if( WEXITSTATUS( system( buffer.constData() )) == 4 ) {
01718
01719
01720
01721
01722 QFile::remove( tmpFileName );
01723 finished();
01724 return;
01725 }
01726 } else {
01727
01728
01729
01730
01731
01732
01733 err = i18n("\"vold\" is not running.");
01734 kDebug(7101) << "VOLMGT: " << err;
01735 error( KIO::ERR_COULD_NOT_UNMOUNT, err );
01736 return;
01737 }
01738 #else
01739 QString epath = QString::fromLocal8Bit(qgetenv("PATH"));
01740 QString path = QLatin1String("/sbin:/bin");
01741 if (!epath.isEmpty())
01742 path += ':' + epath;
01743 QByteArray umountProg = KGlobal::dirs()->findExe("umount", path).toLocal8Bit();
01744
01745 if (umountProg.isEmpty()) {
01746 error( KIO::ERR_COULD_NOT_UNMOUNT, i18n("Could not find program \"umount\""));
01747 return;
01748 }
01749 buffer = umountProg + QFile::encodeName(KShell::quoteArg(_point)) + " 2>" + tmpFileName;
01750 system( buffer.constData() );
01751 #endif
01752
01753 err = testLogFile( tmpFileName );
01754 if ( err.isEmpty() )
01755 finished();
01756 else
01757 error( KIO::ERR_COULD_NOT_UNMOUNT, err );
01758 }
01759
01760
01761
01762
01763
01764
01765
01766 bool FileProtocol::pmount(const QString &dev)
01767 {
01768 QString epath = QString::fromLocal8Bit(qgetenv("PATH"));
01769 QString path = QLatin1String("/sbin:/bin");
01770 if (!epath.isEmpty())
01771 path += ':' + epath;
01772 QString pmountProg = KGlobal::dirs()->findExe("pmount", path);
01773
01774 if (pmountProg.isEmpty())
01775 return false;
01776
01777 QByteArray buffer = QFile::encodeName(pmountProg) + ' ' +
01778 QFile::encodeName(KShell::quoteArg(dev));
01779
01780 int res = system( buffer.constData() );
01781
01782 return res==0;
01783 }
01784
01785 bool FileProtocol::pumount(const QString &point)
01786 {
01787 KMountPoint::Ptr mp = KMountPoint::currentMountPoints(KMountPoint::NeedRealDeviceName).findByPath(point);
01788 if (!mp)
01789 return false;
01790 QString dev = mp->realDeviceName();
01791 if (dev.isEmpty()) return false;
01792
01793 QString epath = QString::fromLocal8Bit(qgetenv("PATH"));
01794 QString path = QLatin1String("/sbin:/bin");
01795 if (!epath.isEmpty())
01796 path += ':' + epath;
01797 QString pumountProg = KGlobal::dirs()->findExe("pumount", path);
01798
01799 if (pumountProg.isEmpty())
01800 return false;
01801
01802 QByteArray buffer = QFile::encodeName(pumountProg);
01803 buffer += ' ';
01804 buffer += QFile::encodeName(KShell::quoteArg(dev));
01805
01806 int res = system( buffer.data() );
01807
01808 return res==0;
01809 }
01810
01811
01812
01813
01814
01815
01816
01817 static QString testLogFile( const QByteArray& _filename )
01818 {
01819 char buffer[ 1024 ];
01820 KDE_struct_stat buff;
01821
01822 QString result;
01823
01824 KDE_stat( _filename, &buff );
01825 int size = buff.st_size;
01826 if ( size == 0 ) {
01827 unlink( _filename );
01828 return result;
01829 }
01830
01831 FILE * f = KDE_fopen( _filename, "rb" );
01832 if ( f == 0L ) {
01833 unlink( _filename );
01834 result = i18n("Could not read %1", QFile::decodeName(_filename));
01835 return result;
01836 }
01837
01838 result = "";
01839 const char *p = "";
01840 while ( p != 0L ) {
01841 p = fgets( buffer, sizeof(buffer)-1, f );
01842 if ( p != 0L )
01843 result += QString::fromLocal8Bit(buffer);
01844 }
01845
01846 fclose( f );
01847
01848 unlink( _filename );
01849
01850 return result;
01851 }
01852
01853
01854
01855
01856
01857
01858 #ifdef HAVE_POSIX_ACL
01859
01860 static bool isExtendedACL( acl_t acl )
01861 {
01862 return ( acl_equiv_mode( acl, 0 ) != 0 );
01863 }
01864
01865 static void appendACLAtoms( const QByteArray & path, UDSEntry& entry, mode_t type, bool withACL )
01866 {
01867
01868 if ( acl_extended_file( path.data() ) == 0 ) return;
01869
01870 acl_t acl = 0;
01871 acl_t defaultAcl = 0;
01872 bool isDir = S_ISDIR( type );
01873
01874 acl = acl_get_file( path.data(), ACL_TYPE_ACCESS );
01875
01876
01877 if ( isDir ) {
01878 if ( acl ) {
01879 if ( !isExtendedACL( acl ) ) {
01880 acl_free( acl );
01881 acl = 0;
01882 }
01883 }
01884 defaultAcl = acl_get_file( path.data(), ACL_TYPE_DEFAULT );
01885 }
01886 if ( acl || defaultAcl ) {
01887 kDebug(7101) << path.data() << " has extended ACL entries ";
01888 entry.insert( KIO::UDSEntry::UDS_EXTENDED_ACL, 1 );
01889 }
01890 if ( withACL ) {
01891 if ( acl ) {
01892 ssize_t size = acl_size( acl );
01893 const QString str = QString::fromLatin1( acl_to_text( acl, &size ) );
01894 entry.insert( KIO::UDSEntry::UDS_ACL_STRING, str );
01895 kDebug(7101) << path.data() << "ACL: " << str;
01896 }
01897 if ( defaultAcl ) {
01898 ssize_t size = acl_size( defaultAcl );
01899 const QString str = QString::fromLatin1( acl_to_text( defaultAcl, &size ) );
01900 entry.insert( KIO::UDSEntry::UDS_DEFAULT_ACL_STRING, str );
01901 kDebug(7101) << path.data() << "DEFAULT ACL: " << str;
01902 }
01903 }
01904 if ( acl ) acl_free( acl );
01905 if ( defaultAcl ) acl_free( defaultAcl );
01906 }
01907 #endif
01908
01909 #include "file.moc"