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(