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
00026 #include "file.h"
00027
00028 #include <config.h>
00029
00030 #include <QtCore/QFile>
00031
00032 #include <kde_file.h>
00033 #include <kdebug.h>
00034 #include <kconfiggroup.h>
00035 #include <kmountpoint.h>
00036
00037 #include <dirent.h>
00038 #include <errno.h>
00039 #include <fcntl.h>
00040 #include <grp.h>
00041 #include <utime.h>
00042 #include <pwd.h>
00043
00044 #if defined(HAVE_LIMITS_H)
00045 #include <limits.h>
00046 #endif
00047
00048 using namespace KIO;
00049
00050 #define MAX_IPC_SIZE (1024*32)
00051
00052 static bool
00053 same_inode(const KDE_struct_stat &src, const KDE_struct_stat &dest)
00054 {
00055 if (src.st_ino == dest.st_ino &&
00056 src.st_dev == dest.st_dev)
00057 return true;
00058
00059 return false;
00060 }
00061
00062 extern int write_all(int fd, const char *buf, size_t len);
00063
00064 void FileProtocol::copy( const KUrl &src, const KUrl &dest,
00065 int _mode, JobFlags _flags )
00066 {
00067 kDebug(7101) << "copy(): " << src << " -> " << dest << ", mode=" << _mode;
00068
00069 QByteArray _src( QFile::encodeName(src.toLocalFile()));
00070 QByteArray _dest( QFile::encodeName(dest.toLocalFile()));
00071 KDE_struct_stat buff_src;
00072 #ifdef HAVE_POSIX_ACL
00073 acl_t acl;
00074 #endif
00075
00076 if ( KDE_stat( _src.data(), &buff_src ) == -1 ) {
00077 if ( errno == EACCES )
00078 error( KIO::ERR_ACCESS_DENIED, _src );
00079 else
00080 error( KIO::ERR_DOES_NOT_EXIST, _src );
00081 return;
00082 }
00083
00084 if ( S_ISDIR( buff_src.st_mode ) ) {
00085 error( KIO::ERR_IS_DIRECTORY, src.path() );
00086 return;
00087 }
00088 if ( S_ISFIFO( buff_src.st_mode ) || S_ISSOCK ( buff_src.st_mode ) ) {
00089 error( KIO::ERR_CANNOT_OPEN_FOR_READING, src.path() );
00090 return;
00091 }
00092
00093 KDE_struct_stat buff_dest;
00094 bool dest_exists = ( KDE_lstat( _dest.data(), &buff_dest ) != -1 );
00095 if ( dest_exists )
00096 {
00097 if (S_ISDIR(buff_dest.st_mode))
00098 {
00099 error( KIO::ERR_DIR_ALREADY_EXIST, _dest );
00100 return;
00101 }
00102
00103 if ( same_inode( buff_dest, buff_src) )
00104 {
00105 error( KIO::ERR_IDENTICAL_FILES, _dest );
00106 return;
00107 }
00108
00109 if (!(_flags & KIO::Overwrite))
00110 {
00111 error( KIO::ERR_FILE_ALREADY_EXIST, _dest );
00112 return;
00113 }
00114
00115
00116
00117
00118 if ((_flags & KIO::Overwrite) && S_ISLNK(buff_dest.st_mode))
00119 {
00120
00121 remove( _dest.data() );
00122 }
00123 }
00124
00125 int src_fd = KDE_open( _src.data(), O_RDONLY);
00126 if ( src_fd < 0 ) {
00127 error( KIO::ERR_CANNOT_OPEN_FOR_READING, _src );
00128 return;
00129 }
00130
00131 #ifdef HAVE_FADVISE
00132 posix_fadvise(src_fd,0,0,POSIX_FADV_SEQUENTIAL);
00133 #endif
00134
00135
00136 mode_t initialMode;
00137 if (_mode != -1)
00138 initialMode = _mode | S_IWUSR;
00139 else
00140 initialMode = 0666;
00141
00142 int dest_fd = KDE_open(_dest.data(), O_CREAT | O_TRUNC | O_WRONLY, initialMode);
00143 if ( dest_fd < 0 ) {
00144 kDebug(7101) << "###### COULD NOT WRITE " << dest.url();
00145 if ( errno == EACCES ) {
00146 error( KIO::ERR_WRITE_ACCESS_DENIED, _dest );
00147 } else {
00148 error( KIO::ERR_CANNOT_OPEN_FOR_WRITING, _dest );
00149 }
00150 ::close(src_fd);
00151 return;
00152 }
00153
00154 #ifdef HAVE_FADVISE
00155 posix_fadvise(dest_fd,0,0,POSIX_FADV_SEQUENTIAL);
00156 #endif
00157
00158 #ifdef HAVE_POSIX_ACL
00159 acl = acl_get_fd(src_fd);
00160 if ( acl && !isExtendedACL( acl ) ) {
00161 kDebug(7101) << _dest.data() << " doesn't have extended ACL";
00162 acl_free( acl );
00163 acl = NULL;
00164 }
00165 #endif
00166 totalSize( buff_src.st_size );
00167
00168 KIO::filesize_t processed_size = 0;
00169 char buffer[ MAX_IPC_SIZE ];
00170 int n;
00171 #ifdef USE_SENDFILE
00172 bool use_sendfile=buff_src.st_size < 0x7FFFFFFF;
00173 #endif
00174 while( 1 )
00175 {
00176 #ifdef USE_SENDFILE
00177 if (use_sendfile) {
00178 off_t sf = processed_size;
00179 n = KDE_sendfile( dest_fd, src_fd, &sf, MAX_IPC_SIZE );
00180 processed_size = sf;
00181 if ( n == -1 && ( errno == EINVAL || errno == ENOSYS ) ) {
00182 kDebug(7101) << "sendfile() not supported, falling back ";
00183 use_sendfile = false;
00184 }
00185 }
00186 if (!use_sendfile)
00187 #endif
00188 n = ::read( src_fd, buffer, MAX_IPC_SIZE );
00189
00190 if (n == -1)
00191 {
00192 if (errno == EINTR)
00193 continue;
00194 #ifdef USE_SENDFILE
00195 if ( use_sendfile ) {
00196 kDebug(7101) << "sendfile() error:" << strerror(errno);
00197 if ( errno == ENOSPC )
00198 {
00199 error( KIO::ERR_DISK_FULL, _dest );
00200 remove( _dest.data() );
00201 }
00202 else {
00203 error( KIO::ERR_SLAVE_DEFINED,
00204 i18n("Cannot copy file from %1 to %2. (Errno: %3)",
00205 src.toLocalFile(), dest.toLocalFile(), errno ) );
00206 }
00207 } else
00208 #endif
00209 error( KIO::ERR_COULD_NOT_READ, _src );
00210 ::close(src_fd);
00211 ::close(dest_fd);
00212 #ifdef HAVE_POSIX_ACL
00213 if (acl) acl_free(acl);
00214 #endif
00215 return;
00216 }
00217 if (n == 0)
00218 break;
00219 #ifdef USE_SENDFILE
00220 if ( !use_sendfile ) {
00221 #endif
00222 if (write_all( dest_fd, buffer, n))
00223 {
00224 ::close(src_fd);
00225 ::close(dest_fd);
00226
00227 if ( errno == ENOSPC )
00228 {
00229 error( KIO::ERR_DISK_FULL, _dest );
00230 remove( _dest.data() );
00231 }
00232 else
00233 {
00234 kWarning(7101) << "Couldn't write[2]. Error:" << strerror(errno);
00235 error( KIO::ERR_COULD_NOT_WRITE, _dest );
00236 }
00237 #ifdef HAVE_POSIX_ACL
00238 if (acl) acl_free(acl);
00239 #endif
00240 return;
00241 }
00242 processed_size += n;
00243 #ifdef USE_SENDFILE
00244 }
00245 #endif
00246 processedSize( processed_size );
00247 }
00248
00249 ::close( src_fd );
00250
00251 if (::close( dest_fd))
00252 {
00253 kWarning(7101) << "Error when closing file descriptor[2]:" << strerror(errno);
00254 error( KIO::ERR_COULD_NOT_WRITE, _dest );
00255 #ifdef HAVE_POSIX_ACL
00256 if (acl) acl_free(acl);
00257 #endif
00258 return;
00259 }
00260
00261
00262 if ( _mode != -1 )
00263 {
00264 if ( (::chmod(_dest.data(), _mode) != 0)
00265 #ifdef HAVE_POSIX_ACL
00266 || (acl && acl_set_file(_dest.data(), ACL_TYPE_ACCESS, acl) != 0)
00267 #endif
00268 )
00269 {
00270 KMountPoint::Ptr mp = KMountPoint::currentMountPoints().findByPath(_dest);
00271
00272 if ( mp && mp->testFileSystemFlag( KMountPoint::SupportsChmod ) )
00273 warning( i18n( "Could not change permissions for\n%1" , dest.toLocalFile() ) );
00274 }
00275 }
00276 #ifdef HAVE_POSIX_ACL
00277 if (acl) acl_free(acl);
00278 #endif
00279
00280
00281 struct utimbuf ut;
00282 ut.actime = buff_src.st_atime;
00283 ut.modtime = buff_src.st_mtime;
00284 if ( ::utime( _dest.data(), &ut ) != 0 )
00285 {
00286 kWarning() << QString::fromLatin1("Couldn't preserve access and modification time for\n%1").arg( _dest.data() );
00287 }
00288
00289 processedSize( buff_src.st_size );
00290 finished();
00291 }
00292
00293 void FileProtocol::listDir( const KUrl& url)
00294 {
00295 kDebug(7101) << "========= LIST " << url.url() << " =========";
00296 if (!url.isLocalFile()) {
00297 KUrl redir(url);
00298 redir.setProtocol(config()->readEntry("DefaultRemoteProtocol", "smb"));
00299 redirection(redir);
00300 kDebug(7101) << "redirecting to " << redir.url();
00301 finished();
00302 return;
00303 }
00304 QByteArray _path( QFile::encodeName(url.toLocalFile()) );
00305 KDE_struct_stat buff;
00306 if ( KDE_stat( _path.data(), &buff ) == -1 ) {
00307 error( KIO::ERR_DOES_NOT_EXIST, _path );
00308 return;
00309 }
00310
00311 if ( !S_ISDIR( buff.st_mode ) ) {
00312 error( KIO::ERR_IS_FILE, _path );
00313 return;
00314 }
00315
00316 DIR *dp = 0L;
00317 KDE_struct_dirent *ep;
00318
00319 dp = opendir( _path.data() );
00320 if ( dp == 0 ) {
00321 switch (errno)
00322 {
00323 #ifdef ENOMEDIUM
00324 case ENOMEDIUM:
00325 error( ERR_SLAVE_DEFINED,
00326 i18n( "No media in device for %1", url.toLocalFile() ) );
00327 break;
00328 #else
00329 case ENOENT:
00330 #endif
00331 default:
00332 error( KIO::ERR_CANNOT_ENTER_DIRECTORY, _path );
00333 break;
00334 }
00335 return;
00336 }
00337
00338
00339
00340
00341 QList<QByteArray> entryNames;
00342 while ( ( ep = KDE_readdir( dp ) ) != 0L )
00343 entryNames.append( ep->d_name );
00344
00345 closedir( dp );
00346 totalSize( entryNames.count() );
00347
00348
00349
00350
00351
00352
00353
00354
00355 char path_buffer[PATH_MAX];
00356 getcwd(path_buffer, PATH_MAX - 1);
00357 if ( chdir( _path.data() ) ) {
00358 if (errno == EACCES)
00359 error(ERR_ACCESS_DENIED, _path);
00360 else
00361 error(ERR_CANNOT_ENTER_DIRECTORY, _path);
00362 finished();
00363 }
00364
00365 UDSEntry entry;
00366 QList<QByteArray>::ConstIterator it = entryNames.constBegin();
00367 QList<QByteArray>::ConstIterator end = entryNames.constEnd();
00368 for (; it != end; ++it) {
00369 entry.clear();
00370 if ( createUDSEntry( QFile::decodeName(*it),
00371 *it ,
00372 entry, 2, true ) )
00373 listEntry( entry, false);
00374 }
00375
00376 listEntry( entry, true );
00377
00378 kDebug(7101) << "============= COMPLETED LIST ============";
00379
00380 chdir(path_buffer);
00381 finished();
00382 }
00383
00384 void FileProtocol::rename( const KUrl &src, const KUrl &dest,
00385 KIO::JobFlags _flags )
00386 {
00387 char off_t_should_be_64_bits[sizeof(off_t) >= 8 ? 1 : -1]; (void) off_t_should_be_64_bits;
00388 QByteArray _src(QFile::encodeName(src.toLocalFile()));
00389 QByteArray _dest(QFile::encodeName(dest.toLocalFile()));
00390 KDE_struct_stat buff_src;
00391 if ( KDE_lstat( _src.data(), &buff_src ) == -1 ) {
00392 if ( errno == EACCES )
00393 error( KIO::ERR_ACCESS_DENIED, _src );
00394 else
00395 error( KIO::ERR_DOES_NOT_EXIST, _src );
00396 return;
00397 }
00398
00399 KDE_struct_stat buff_dest;
00400
00401
00402 bool dest_exists = ( KDE_lstat( _dest.data(), &buff_dest ) != -1 );
00403 if ( dest_exists )
00404 {
00405 if (S_ISDIR(buff_dest.st_mode))
00406 {
00407 error( KIO::ERR_DIR_ALREADY_EXIST, _dest );
00408 return;
00409 }
00410
00411 if ( same_inode( buff_dest, buff_src) )
00412 {
00413 error( KIO::ERR_IDENTICAL_FILES, _dest );
00414 return;
00415 }
00416
00417 if (!(_flags & KIO::Overwrite))
00418 {
00419 error( KIO::ERR_FILE_ALREADY_EXIST, _dest );
00420 return;
00421 }
00422 }
00423
00424 if ( KDE_rename( _src.data(), _dest.data()))
00425 {
00426 if (( errno == EACCES ) || (errno == EPERM)) {
00427 error( KIO::ERR_ACCESS_DENIED, _dest );
00428 }
00429 else if (errno == EXDEV) {
00430 error( KIO::ERR_UNSUPPORTED_ACTION, QLatin1String("rename"));
00431 }
00432 else if (errno == EROFS) {
00433 error( KIO::ERR_CANNOT_DELETE, _src );
00434 }
00435 else {
00436 error( KIO::ERR_CANNOT_RENAME, _src );
00437 }
00438 return;
00439 }
00440
00441 finished();
00442 }
00443
00444 void FileProtocol::symlink( const QString &target, const KUrl &dest, KIO::JobFlags flags )
00445 {
00446
00447 if ( ::symlink( QFile::encodeName( target ), QFile::encodeName( dest.path() ) ) == -1 )
00448 {
00449
00450 if ( errno == EEXIST )
00451 {
00452 if ( (flags & KIO::Overwrite) )
00453 {
00454
00455 if ( unlink( QFile::encodeName( dest.path() ) ) != 0 )
00456 {
00457 error( KIO::ERR_CANNOT_DELETE, dest.path() );
00458 return;
00459 }
00460
00461 symlink( target, dest, flags );
00462 }
00463 else
00464 {
00465 KDE_struct_stat buff_dest;
00466 KDE_lstat( QFile::encodeName( dest.path() ), &buff_dest );
00467 if (S_ISDIR(buff_dest.st_mode))
00468 error( KIO::ERR_DIR_ALREADY_EXIST, dest.path() );
00469 else
00470 error( KIO::ERR_FILE_ALREADY_EXIST, dest.path() );
00471 return;
00472 }
00473 }
00474 else
00475 {
00476
00477 error( KIO::ERR_CANNOT_SYMLINK, dest.path() );
00478 return;
00479 }
00480 }
00481 finished();
00482 }
00483
00484 void FileProtocol::del( const KUrl& url, bool isfile)
00485 {
00486 QByteArray _path( QFile::encodeName(url.toLocalFile()));
00487
00488
00489
00490
00491 if (isfile) {
00492 kDebug( 7101 ) << "Deleting file "<< url.url();
00493
00494
00495
00496 if ( unlink( _path.data() ) == -1 ) {
00497 if ((errno == EACCES) || (errno == EPERM))
00498 error( KIO::ERR_ACCESS_DENIED, _path );
00499 else if (errno == EISDIR)
00500 error( KIO::ERR_IS_DIRECTORY, _path );
00501 else
00502 error( KIO::ERR_CANNOT_DELETE, _path );
00503 return;
00504 }
00505 } else {
00506
00507
00508
00509
00510
00511 kDebug( 7101 ) << "Deleting directory " << url.url();
00512
00513 if ( ::rmdir( _path.data() ) == -1 ) {
00514 if ((errno == EACCES) || (errno == EPERM))
00515 error( KIO::ERR_ACCESS_DENIED, _path );
00516 else {
00517 kDebug( 7101 ) << "could not rmdir " << perror;
00518 error( KIO::ERR_COULD_NOT_RMDIR, _path );
00519 return;
00520 }
00521 }
00522 }
00523
00524 finished();
00525 }
00526
00527 void FileProtocol::chown( const KUrl& url, const QString& owner, const QString& group )
00528 {
00529 const QByteArray _path( QFile::encodeName(url.toLocalFile()) );
00530 uid_t uid;
00531 gid_t gid;
00532
00533
00534 {
00535 struct passwd *p = ::getpwnam(owner.toAscii());
00536
00537 if ( ! p ) {
00538 error( KIO::ERR_SLAVE_DEFINED,
00539 i18n( "Could not get user id for given user name %1", owner ) );
00540 return;
00541 }
00542
00543 uid = p->pw_uid;
00544 }
00545
00546
00547 {
00548 struct group *p = ::getgrnam(group.toAscii());
00549
00550 if ( ! p ) {
00551 error( KIO::ERR_SLAVE_DEFINED,
00552 i18n( "Could not get group id for given group name %1", group ) );
00553 return;
00554 }
00555
00556 gid = p->gr_gid;
00557 }
00558
00559 if ( ::chown(_path, uid, gid) == -1 ) {
00560 switch ( errno ) {
00561 case EPERM:
00562 case EACCES:
00563 error( KIO::ERR_ACCESS_DENIED, _path );
00564 break;
00565 case ENOSPC:
00566 error( KIO::ERR_DISK_FULL, _path );
00567 break;
00568 default:
00569 error( KIO::ERR_CANNOT_CHOWN, _path );
00570 }
00571 } else
00572 finished();
00573 }