diff --git a/src/core/config-kiocore.h.cmake b/src/core/config-kiocore.h.cmake --- a/src/core/config-kiocore.h.cmake +++ b/src/core/config-kiocore.h.cmake @@ -4,6 +4,8 @@ #cmakedefine01 HAVE_POSIX_ACL /* Defined if acl/libacl.h exists */ #cmakedefine01 HAVE_ACL_LIBACL_H +/* Defined if system has extended file attributes support. */ +#cmakedefine01 HAVE_SYS_XATTR_H #define CMAKE_INSTALL_FULL_LIBEXECDIR_KF5 "${CMAKE_INSTALL_FULL_LIBEXECDIR_KF5}" diff --git a/src/core/copyjob.cpp b/src/core/copyjob.cpp --- a/src/core/copyjob.cpp +++ b/src/core/copyjob.cpp @@ -19,9 +19,19 @@ Boston, MA 02110-1301, USA. */ +#include + #include "copyjob.h" #include "kiocoredebug.h" #include +#if HAVE_SYS_XATTR_H + #if defined(Q_OS_LINUX) || defined(__GLIBC__) + #include + #elif defined(Q_OS_FREEBSD) || defined(Q_OS_NETBSD) + #include + #endif +#endif + #include "kcoredirlister.h" #include "kfileitem.h" #include "job.h" // buildErrorString @@ -234,6 +244,7 @@ void slotResultRenaming(KJob *job); void slotResultSettingDirAttributes(KJob *job); void setNextDirAttribute(); + void copyXattrs(const QUrl &source, const QUrl &dest); void startRenameJob(const QUrl &slave_url); bool shouldOverwriteDir(const QString &path) const; @@ -1115,6 +1126,7 @@ } } else { // no error : remove from list, to move on to next dir //this is required for the undo feature + copyXattrs((*it).uSource, (*it).uDest); emit q->copyingDone(q, (*it).uSource, finalDestUrl((*it).uSource, (*it).uDest), (*it).mtime, true, false); m_directoriesCopied.append(*it); dirs.erase(it); @@ -1358,6 +1370,7 @@ emit q->copyingLinkDone(q, (*it).uSource, target, finalUrl); } else { //required for the undo feature + copyXattrs((*it).uSource, (*it).uDest); emit q->copyingDone(q, (*it).uSource, finalUrl, (*it).mtime, false, false); if (m_mode == CopyJob::Move) { org::kde::KDirNotify::emitFileMoved((*it).uSource, finalUrl); @@ -1832,6 +1845,7 @@ q->setProcessedAmount(KJob::Bytes, m_processedSize + m_fileProcessedSize); } + void CopyJobPrivate::slotTotalSize(KJob *, qulonglong size) { Q_Q(CopyJob); @@ -2173,6 +2187,75 @@ } } + // copy xattr to new dir +void CopyJobPrivate::copyXattrs(const QUrl &source, const QUrl &dest) +{ +#if HAVE_SYS_XATTR_H + const char* xattr_src = source.path().toLocal8Bit().data(); + qDebug() << xattr_src; + // get size of key list + #if defined(Q_OS_LINUX) || (defined(__GLIBC__) && !defined(__stub_getxattr)) + ssize_t buflen = listxattr(xattr_src, nullptr, 0); + #elif defined(Q_OS_MAC) + ssize_t buflen = listxattr(xattr_src, NULL, 0, 0); + #elif defined(Q_OS_FREEBSD) || defined(Q_OS_NETBSD) + ssize_t buflen = extattr_list_file(xattr_src, EXTATTR_NAMESPACE_USER, NULL, 0); + #endif + qDebug() << xattr_src << buflen; + // bufflen > 0 if file have xattr + if (buflen > 0) { + QByteArray buf(buflen , Qt::Uninitialized); + qDebug() << buf.size(); + // get the key list + #if defined(Q_OS_LINUX) || (defined(__GLIBC__) && !defined(__stub_getxattr)) + buflen = listxattr(xattr_src, buf.data(), buflen); + #elif defined(Q_OS_MAC) + buflen = listxattr(xattr_src, buf.data(), buflen, 0); + #elif defined(Q_OS_FREEBSD) || defined(Q_OS_NETBSD) + buflen = extattr_list_file(xattr_src, EXTATTR_NAMESPACE_USER, buf.data(), buflen); + #endif + QList xattr_keys = buf.split('\0'); + xattr_keys.removeLast(); // the last item is alwys empty + qDebug() << xattr_src << xattr_keys; + for (int i = 0; i < xattr_keys.size(); i++) { + auto key = xattr_keys[i].data(); + // get the size of value for key + #if defined(Q_OS_LINUX) || (defined(__GLIBC__) && !defined(__stub_getxattr)) + ssize_t vallen = getxattr(xattr_src, key, nullptr, 0); + #elif defined(Q_OS_MAC) + ssize_t vallen = listxattr(xattr_src, key, NULL, 0, 0, 0); + #elif defined(Q_OS_FREEBSD) || defined(Q_OS_NETBSD) + ssize_t vallen = extattr_get_file(xattr_src, EXTATTR_NAMESPACE_USER, key, NULL, 0); + #endif + qDebug() < 0 if we have a valid value for key + if (vallen > 0) { + QByteArray val(vallen, Qt::Uninitialized); + //get the value of the key + #if defined(Q_OS_LINUX) || (defined(__GLIBC__) && !defined(__stub_getxattr)) + vallen = getxattr(xattr_src, key, val.data(), vallen); + #elif defined(Q_OS_MAC) + vallen = getxattr(xattr_src, key, val.data(), vallen, 0, 0); + #elif defined(Q_OS_FREEBSD) || defined(Q_OS_NETBSD) + vallen = extattr_get_file(xattr_src, EXTATTR_NAMESPACE_USER, key, val.data(), vallen); + #endif + qDebug() << val; + //write key:value pair on dest file + const char* xattr_dest = dest.path().toLocal8Bit().data(); + #if defined(Q_OS_LINUX) || (defined(__GLIBC__) && !defined(__stub_getxattr)) + ssize_t destlen = setxattr(xattr_dest, key, val.data(), vallen, 0); + #elif defined(Q_OS_MAC) + ssize_t destlen = setxattr(xattr_dest, key, val.data(), vallen, 0, 0); + #elif defined(Q_OS_FREEBSD) || defined(Q_OS_NETBSD) + ssize_t destlen = extattr_set_file(xattr_dest, EXTATTR_NAMESPACE_USER, key, val.data(), vallen); + #endif + qDebug() << "s" << xattr_src << "d" << xattr_dest << key << val.data() << vallen; + } + } + } +#endif +} + void KIO::CopyJob::setDefaultPermissions(bool b) { d_func()->m_defaultPermissions = b; diff --git a/src/ioslaves/file/file_unix.cpp b/src/ioslaves/file/file_unix.cpp --- a/src/ioslaves/file/file_unix.cpp +++ b/src/ioslaves/file/file_unix.cpp @@ -38,9 +38,15 @@ #include #include + #if HAVE_SYS_XATTR_H -#include + #if defined(Q_OS_LINUX) || defined(__GLIBC__) + #include + #elif defined(Q_OS_FREEBSD) || defined(Q_OS_NETBSD) + #include + #endif #endif + #include #include