2
Copyright (C) 2000-2002 Stephan Kulow <coolo@kde.org>
3
Copyright (C) 2000-2002 David Faure <faure@kde.org>
4
Copyright (C) 2000-2002 Waldo Bastian <bastian@kde.org>
5
Copyright (C) 2006 Allan Sandfeld Jensen <sandfeld@kde.org>
6
Copyright (C) 2007 Thiago Macieira <thiago@kde.org>
7
Copyright (C) 2007 Christian Ehrlicher <ch.ehrlicher@gmx.de>
9
This library is free software; you can redistribute it and/or
10
modify it under the terms of the GNU Library General Public
11
License (LGPL) as published by the Free Software Foundation;
12
either version 2 of the License, or (at your option) any later
15
This library is distributed in the hope that it will be useful,
16
but WITHOUT ANY WARRANTY; without even the implied warranty of
17
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
18
Library General Public License for more details.
20
You should have received a copy of the GNU Library General Public License
21
along with this library; see the file COPYING.LIB. If not, write to
22
the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
23
Boston, MA 02110-1301, USA.
26
#define QT_NO_CAST_FROM_ASCII
32
#include <QtCore/QFile>
36
#include <kconfiggroup.h>
37
#include <kmountpoint.h>
47
#if defined(HAVE_LIMITS_H)
48
#include <limits.h> // PATH_MAX
51
//sendfile has different semantics in different platforms
52
#if defined HAVE_SENDFILE && defined Q_OS_LINUX
53
#define USE_SENDFILE 1
57
#include <sys/sendfile.h>
63
struct CharArrayDeleter
65
CharArrayDeleter(char *b) : buf(b) {}
66
~CharArrayDeleter() { free(buf); }
74
#define MAX_IPC_SIZE (1024*32)
77
same_inode(const KDE_struct_stat &src, const KDE_struct_stat &dest)
79
if (src.st_ino == dest.st_ino &&
80
src.st_dev == dest.st_dev)
86
extern int write_all(int fd, const char *buf, size_t len);
88
void FileProtocol::copy( const KUrl &srcUrl, const KUrl &destUrl,
89
int _mode, JobFlags _flags )
91
kDebug(7101) << "copy(): " << srcUrl << " -> " << destUrl << ", mode=" << _mode;
93
const QString src = srcUrl.toLocalFile();
94
const QString dest = destUrl.toLocalFile();
95
QByteArray _src( QFile::encodeName(src));
96
QByteArray _dest( QFile::encodeName(dest));
97
KDE_struct_stat buff_src;
102
if ( KDE_stat( _src.data(), &buff_src ) == -1 ) {
103
if ( errno == EACCES )
104
error(KIO::ERR_ACCESS_DENIED, src);
106
error(KIO::ERR_DOES_NOT_EXIST, src);
110
if ( S_ISDIR( buff_src.st_mode ) ) {
111
error(KIO::ERR_IS_DIRECTORY, src);
114
if ( S_ISFIFO( buff_src.st_mode ) || S_ISSOCK ( buff_src.st_mode ) ) {
115
error(KIO::ERR_CANNOT_OPEN_FOR_READING, src);
119
KDE_struct_stat buff_dest;
120
bool dest_exists = ( KDE_lstat( _dest.data(), &buff_dest ) != -1 );
123
if (S_ISDIR(buff_dest.st_mode))
125
error(KIO::ERR_DIR_ALREADY_EXIST, dest);
129
if ( same_inode( buff_dest, buff_src) )
131
error(KIO::ERR_IDENTICAL_FILES, dest);
135
if (!(_flags & KIO::Overwrite))
137
error(KIO::ERR_FILE_ALREADY_EXIST, dest);
141
// If the destination is a symlink and overwrite is TRUE,
142
// remove the symlink first to prevent the scenario where
143
// the symlink actually points to current source!
144
if ((_flags & KIO::Overwrite) && S_ISLNK(buff_dest.st_mode))
146
//kDebug(7101) << "copy(): LINK DESTINATION";
147
remove( _dest.data() );
151
int src_fd = KDE_open( _src.data(), O_RDONLY);
153
error(KIO::ERR_CANNOT_OPEN_FOR_READING, src);
158
posix_fadvise(src_fd,0,0,POSIX_FADV_SEQUENTIAL);
160
// WABA: Make sure that we keep writing permissions ourselves,
161
// otherwise we can be in for a surprise on NFS.
164
initialMode = _mode | S_IWUSR;
168
int dest_fd = KDE_open(_dest.data(), O_CREAT | O_TRUNC | O_WRONLY, initialMode);
170
kDebug(7101) << "###### COULD NOT WRITE " << dest;
171
if ( errno == EACCES ) {
172
error(KIO::ERR_WRITE_ACCESS_DENIED, dest);
174
error(KIO::ERR_CANNOT_OPEN_FOR_WRITING, dest);
181
posix_fadvise(dest_fd,0,0,POSIX_FADV_SEQUENTIAL);
184
#ifdef HAVE_POSIX_ACL
185
acl = acl_get_fd(src_fd);
186
if ( acl && !isExtendedACL( acl ) ) {
187
kDebug(7101) << _dest.data() << " doesn't have extended ACL";
192
totalSize( buff_src.st_size );
194
KIO::filesize_t processed_size = 0;
195
char buffer[ MAX_IPC_SIZE ];
198
bool use_sendfile=buff_src.st_size < 0x7FFFFFFF;
204
off_t sf = processed_size;
205
n = KDE_sendfile( dest_fd, src_fd, &sf, MAX_IPC_SIZE );
207
if ( n == -1 && ( errno == EINVAL || errno == ENOSYS ) ) { //not all filesystems support sendfile()
208
kDebug(7101) << "sendfile() not supported, falling back ";
209
use_sendfile = false;
214
n = ::read( src_fd, buffer, MAX_IPC_SIZE );
221
if ( use_sendfile ) {
222
kDebug(7101) << "sendfile() error:" << strerror(errno);
223
if ( errno == ENOSPC ) // disk full
225
error(KIO::ERR_DISK_FULL, dest);
226
remove( _dest.data() );
229
error(KIO::ERR_SLAVE_DEFINED,
230
i18n("Cannot copy file from %1 to %2. (Errno: %3)",
235
error(KIO::ERR_COULD_NOT_READ, src);
238
#ifdef HAVE_POSIX_ACL
239
if (acl) acl_free(acl);
246
if ( !use_sendfile ) {
248
if (write_all( dest_fd, buffer, n))
253
if ( errno == ENOSPC ) // disk full
255
error(KIO::ERR_DISK_FULL, dest);
256
remove( _dest.data() );
260
kWarning(7101) << "Couldn't write[2]. Error:" << strerror(errno);
261
error(KIO::ERR_COULD_NOT_WRITE, dest);
263
#ifdef HAVE_POSIX_ACL
264
if (acl) acl_free(acl);
272
processedSize( processed_size );
277
if (::close( dest_fd))
279
kWarning(7101) << "Error when closing file descriptor[2]:" << strerror(errno);
280
error(KIO::ERR_COULD_NOT_WRITE, dest);
281
#ifdef HAVE_POSIX_ACL
282
if (acl) acl_free(acl);
287
// set final permissions
290
if ( (::chmod(_dest.data(), _mode) != 0)
291
#ifdef HAVE_POSIX_ACL
292
|| (acl && acl_set_file(_dest.data(), ACL_TYPE_ACCESS, acl) != 0)
296
KMountPoint::Ptr mp = KMountPoint::currentMountPoints().findByPath(dest);
297
// Eat the error if the filesystem apparently doesn't support chmod.
298
if ( mp && mp->testFileSystemFlag( KMountPoint::SupportsChmod ) )
299
warning(i18n("Could not change permissions for\n%1", dest));
302
#ifdef HAVE_POSIX_ACL
303
if (acl) acl_free(acl);
306
// copy access and modification time
308
ut.actime = buff_src.st_atime;
309
ut.modtime = buff_src.st_mtime;
310
if ( ::utime( _dest.data(), &ut ) != 0 )
312
kWarning() << QString::fromLatin1("Couldn't preserve access and modification time for\n%1").arg(dest);
315
processedSize( buff_src.st_size );
319
void FileProtocol::listDir( const KUrl& url)
321
if (!url.isLocalFile()) {
323
redir.setProtocol(config()->readEntry("DefaultRemoteProtocol", "smb"));
325
kDebug(7101) << "redirecting to " << redir.url();
329
const QString path(url.toLocalFile());
330
const QByteArray _path(QFile::encodeName(path));
331
DIR* dp = opendir(_path.data());
335
error(KIO::ERR_DOES_NOT_EXIST, path);
338
error(KIO::ERR_IS_FILE, path);
342
error(ERR_SLAVE_DEFINED,
343
i18n("No media in device for %1", path));
347
error(KIO::ERR_CANNOT_ENTER_DIRECTORY, path);
353
const QString sDetails = metaData(QLatin1String("details"));
354
const int details = sDetails.isEmpty() ? 2 : sDetails.toInt();
355
//kDebug(7101) << "========= LIST " << url << "details=" << details << " =========";
358
#ifndef HAVE_DIRENT_D_TYPE
361
// Don't make this a QStringList. The locale file name we get here
362
// should be passed intact to createUDSEntry to avoid problems with
363
// files where QFile::encodeName(QFile::decodeName(a)) != a.
364
QList<QByteArray> entryNames;
365
KDE_struct_dirent *ep;
367
// Fast path (for recursive deletion, mostly)
368
// Simply emit the name and file type, nothing else.
369
while ( ( ep = KDE_readdir( dp ) ) != 0 ) {
371
entry.insert(KIO::UDSEntry::UDS_NAME, QFile::decodeName(ep->d_name));
372
#ifdef HAVE_DIRENT_D_TYPE
373
entry.insert(KIO::UDSEntry::UDS_FILE_TYPE,
374
(ep->d_type & DT_DIR) ? S_IFDIR : S_IFREG );
375
const bool isSymLink = (ep->d_type & DT_LNK);
377
// oops, no fast way, we need to stat (e.g. on Solaris)
378
if (KDE_lstat(ep->d_name, &st) == -1) {
379
continue; // how can stat fail?
381
entry.insert(KIO::UDSEntry::UDS_FILE_TYPE,
382
(S_ISDIR(st.st_mode)) ? S_IFDIR : S_IFREG );
383
const bool isSymLink = S_ISLNK(st.st_mode);
386
// for symlinks obey the UDSEntry contract and provide UDS_LINK_DEST
387
// even if we don't know the link dest (and DeleteJob doesn't care...)
388
entry.insert(KIO::UDSEntry::UDS_LINK_DEST, QLatin1String("Dummy Link Target"));
390
listEntry(entry, false);
393
listEntry( entry, true ); // ready
395
while ( ( ep = KDE_readdir( dp ) ) != 0 ) {
396
entryNames.append( ep->d_name );
400
totalSize( entryNames.count() );
402
/* set the current dir to the path to speed up
403
in not having to pass an absolute path.
404
We restore the path later to get out of the
405
path - the kernel wouldn't unmount or delete
406
directories we keep as active directory. And
407
as the slave runs in the background, it's hard
408
to see for the user what the problem would be */
409
#if !defined(PATH_MAX) && defined(__GLIBC__)
410
char *path_buffer = ::get_current_dir_name();
411
const KDEPrivate::CharArrayDeleter path_buffer_deleter(path_buffer);
413
char path_buffer[PATH_MAX];
414
path_buffer[0] = '\0';
415
(void) getcwd(path_buffer, PATH_MAX - 1);
417
if ( chdir( _path.data() ) ) {
419
error(ERR_ACCESS_DENIED, path);
421
error(ERR_CANNOT_ENTER_DIRECTORY, path);
425
QList<QByteArray>::ConstIterator it = entryNames.constBegin();
426
QList<QByteArray>::ConstIterator end = entryNames.constEnd();
427
for (; it != end; ++it) {
429
if ( createUDSEntry( QFile::decodeName(*it),
430
*it /* we can use the filename as relative path*/,
431
entry, details, true ) )
432
listEntry( entry, false);
435
listEntry( entry, true ); // ready
437
//kDebug(7101) << "============= COMPLETED LIST ============";
439
#if !defined(PATH_MAX) && defined(__GLIBC__)
451
void FileProtocol::rename( const KUrl &srcUrl, const KUrl &destUrl,
452
KIO::JobFlags _flags )
454
char off_t_should_be_64_bits[sizeof(off_t) >= 8 ? 1 : -1]; (void) off_t_should_be_64_bits;
455
const QString src = srcUrl.toLocalFile();
456
const QString dest = destUrl.toLocalFile();
457
const QByteArray _src(QFile::encodeName(src));
458
const QByteArray _dest(QFile::encodeName(dest));
459
KDE_struct_stat buff_src;
460
if ( KDE_lstat( _src.data(), &buff_src ) == -1 ) {
461
if ( errno == EACCES )
462
error(KIO::ERR_ACCESS_DENIED, src);
464
error(KIO::ERR_DOES_NOT_EXIST, src);
468
KDE_struct_stat buff_dest;
469
// stat symlinks here (lstat, not stat), to avoid ERR_IDENTICAL_FILES when replacing symlink
470
// with its target (#169547)
471
bool dest_exists = ( KDE_lstat( _dest.data(), &buff_dest ) != -1 );
474
if (S_ISDIR(buff_dest.st_mode))
476
error(KIO::ERR_DIR_ALREADY_EXIST, dest);
480
if ( same_inode( buff_dest, buff_src) )
482
error(KIO::ERR_IDENTICAL_FILES, dest);
486
if (!(_flags & KIO::Overwrite))
488
error(KIO::ERR_FILE_ALREADY_EXIST, dest);
493
if ( KDE_rename( _src.data(), _dest.data()))
495
if (( errno == EACCES ) || (errno == EPERM)) {
496
error(KIO::ERR_ACCESS_DENIED, dest);
498
else if (errno == EXDEV) {
499
error(KIO::ERR_UNSUPPORTED_ACTION, QLatin1String("rename"));
501
else if (errno == EROFS) { // The file is on a read-only filesystem
502
error(KIO::ERR_CANNOT_DELETE, src);
505
error(KIO::ERR_CANNOT_RENAME, src);
513
void FileProtocol::symlink( const QString &target, const KUrl &destUrl, KIO::JobFlags flags )
515
const QString dest = destUrl.toLocalFile();
516
// Assume dest is local too (wouldn't be here otherwise)
517
if ( ::symlink( QFile::encodeName(target), QFile::encodeName(dest) ) == -1 )
519
// Does the destination already exist ?
520
if ( errno == EEXIST )
522
if ( (flags & KIO::Overwrite) )
524
// Try to delete the destination
525
if ( unlink( QFile::encodeName(dest) ) != 0 )
527
error(KIO::ERR_CANNOT_DELETE, dest);
530
// Try again - this won't loop forever since unlink succeeded
531
symlink( target, destUrl, flags );
535
KDE_struct_stat buff_dest;
536
KDE_lstat( QFile::encodeName(dest), &buff_dest );
537
if (S_ISDIR(buff_dest.st_mode))
538
error(KIO::ERR_DIR_ALREADY_EXIST, dest);
540
error(KIO::ERR_FILE_ALREADY_EXIST, dest);
546
// Some error occurred while we tried to symlink
547
error(KIO::ERR_CANNOT_SYMLINK, dest);
554
void FileProtocol::del(const KUrl& url, bool isfile)
556
const QString path = url.toLocalFile();
557
const QByteArray _path( QFile::encodeName(path));
563
kDebug(7101) << "Deleting file "<< url;
565
if ( unlink( _path.data() ) == -1 ) {
566
if ((errno == EACCES) || (errno == EPERM))
567
error(KIO::ERR_ACCESS_DENIED, path);
568
else if (errno == EISDIR)
569
error(KIO::ERR_IS_DIRECTORY, path);
571
error(KIO::ERR_CANNOT_DELETE, path);
577
* Delete empty directory
580
kDebug( 7101 ) << "Deleting directory " << url.url();
581
if (metaData(QLatin1String("recurse")) == QLatin1String("true")) {
582
if (!deleteRecursive(path))
585
if ( ::rmdir( _path.data() ) == -1 ) {
586
if ((errno == EACCES) || (errno == EPERM))
587
error(KIO::ERR_ACCESS_DENIED, path);
589
kDebug( 7101 ) << "could not rmdir " << perror;
590
error(KIO::ERR_COULD_NOT_RMDIR, path);
599
void FileProtocol::chown( const KUrl& url, const QString& owner, const QString& group )
601
const QString path = url.toLocalFile();
602
const QByteArray _path( QFile::encodeName(path) );
606
// get uid from given owner
608
struct passwd *p = ::getpwnam(owner.toAscii());
611
error( KIO::ERR_SLAVE_DEFINED,
612
i18n( "Could not get user id for given user name %1", owner ) );
619
// get gid from given group
621
struct group *p = ::getgrnam(group.toAscii());
624
error( KIO::ERR_SLAVE_DEFINED,
625
i18n( "Could not get group id for given group name %1", group ) );
632
if ( ::chown(_path, uid, gid) == -1 ) {
636
error(KIO::ERR_ACCESS_DENIED, path);
639
error(KIO::ERR_DISK_FULL, path);
642
error(KIO::ERR_CANNOT_CHOWN, path);
648
void FileProtocol::stat( const KUrl & url )
650
if (!url.isLocalFile()) {
652
redir.setProtocol(config()->readEntry("DefaultRemoteProtocol", "smb"));
654
kDebug(7101) << "redirecting to " << redir.url();
659
/* directories may not have a slash at the end if
660
* we want to stat() them; it requires that we
661
* change into it .. which may not be allowed
662
* stat("/is/unaccessible") -> rwx------
663
* stat("/is/unaccessible/") -> EPERM H.Z.
664
* This is the reason for the -1
666
const QString path(url.path(KUrl::RemoveTrailingSlash));
667
const QByteArray _path( QFile::encodeName(path));
668
const QString sDetails = metaData(QLatin1String("details"));
669
const int details = sDetails.isEmpty() ? 2 : sDetails.toInt();
672
if ( !createUDSEntry( url.fileName(), _path, entry, details, true /*with acls*/ ) )
674
error(KIO::ERR_DOES_NOT_EXIST, path);
679
MetaData::iterator it1 = mOutgoingMetaData.begin();
680
for ( ; it1 != mOutgoingMetaData.end(); it1++ ) {
681
kDebug(7101) << it1.key() << " = " << it1.data();