From c383a347ea1ca630aabaf15242f7bcdaf10632c9 Mon Sep 17 00:00:00 2001 From: Alexander Hajnal Date: Wed, 21 Dec 2022 21:17:36 -0500 Subject: [PATCH] Adds user extended attribute copying support to libkio. See tdeio/tdeio/README.xattr for more info. Signed-off-by: Alexander Hajnal --- tdeio/tdeio/README.xattr | 86 +++++++++++++++++++++++++++++++++++++ tdeio/tdeio/job.cpp | 92 ++++++++++++++++++++++++++++++++++++++++ 2 files changed, 178 insertions(+) create mode 100644 tdeio/tdeio/README.xattr diff --git a/tdeio/tdeio/README.xattr b/tdeio/tdeio/README.xattr new file mode 100644 index 000000000..8e18f529a --- /dev/null +++ b/tdeio/tdeio/README.xattr @@ -0,0 +1,86 @@ +This is a small patch adding user extended attribute support[1] for local files +to tdeio. With the patch in place user xattrs are preserved when copying or +moving files on the local system[2]. It relies on libattr[3] to do the heavy +lifting. + +The code adds a call to attr_copy_file in libattr that copies the user xattrs +from the source file to the destination file. The call is made after the +source file has been closed and immediately before the source file is deleted +(in the case that a move is being done). This code is based on the sample +code[4] provided with libattr (examples/copyattr.c). + +This code has been in daily use by the author of this patch for just over five +years without any issues. What's missing though is the addition of tests for +xattr and libattr support at configuration/compile time. The code I've added +is enclosed by '#ifdef USE_XATTR' statements so a test should be added that +sets this macro[5] if configure-time tests show that xattrs/libattr are working. +I don't know how to go about adding such tests though so I've simply included a +'#define USE_XATTR 1' statement to the top of the code. This should obviously +be fixed before general release. + +This code has been tested on select Ubuntu Linux releases (natty, precise, +xenial, and jammy) using x86_64 Linux kernels 3.14.1, 4.18.3, and 5.15.0. +Tested filesystems are ext4 and squashfs. + +As far as cross-platform availability goes this code is only known to work on +Linux[6][7]. That said, this code adds functionality that (as far as I'm aware) +isn't currently present in TDE on any of the platforms it runs on. In other +words, even if it only runs on Linux in its current state there is no loss of +functionality on any other platforms (just a lack of a gaining a feature). In +addition, determining the proper location to insert the library call was the +hard part with the actual implementation being quite straightforward. Adding +additional backends for other platforms should be pretty easy. + +To test the code build and install it[8] then run the following from the +commandline in e.g. Konsole: + + $ cd PATH_SUPPORTING_USER_XATTRS_AT_THE_FILESYSTEM_LEVEL + $ touch test + $ setfattr -n "user.AttributeName" -v "Attribute value" attr_test + $ kfmclient copy attr_test attr_test.copy + $ getfattr -d attr_test* + +The final command should output (minus the indents): + + # file: attr_test + user.AttributeName="Attribute value" + + # file: attr_test.copy + user.AttributeName="Attribute value" + +Enjoy! + + + - Alex Kent Hajnal (AKH) 2022-12-21 + + + +[1] This includeds all attributes residing (on Linux) in the "user" namespace. + ACLs, etc. are not copied. + + See the xattr(7) and e.g. the getfattr(1) manpages for more info. + +[2] The underlying filesytems must, of course, have xattr support enabled. + This should be the case by default on modern systems that support xattrs. + +[3] This is libattr1 and libattr1-dev on Ubuntu. + + See http://savannah.nongnu.org/projects/attr for more info. + See also https://github.com/philips/attr + +[4] The code that this patch is based on is licensed GPL v2 (or later). + +[5] One has to use '#define USE_XATTR 1'; specifying '#define USE_XATTR' + doesn't enable the code (at least on my system). + +[6] I'm not sure which non-Linux platforms (if any) libattr runs on. + + +[7] Another known issue is namespaces. Linux, FreeBSD, and NetBSD support + xattrs using the 'user' namespace. Solaris and OSX support user xattrs + but do not support namespaces. + (source: File::ExtAttr(3pm), personal testing) + +[8] Instead of doing a full install one can simply copy the updated library: + + cp -va "BUILD_DIR/tdeio/libtdeio.so.14.0.0" /opt/trinity/lib/ && ldconfig diff --git a/tdeio/tdeio/job.cpp b/tdeio/tdeio/job.cpp index f6156a966..6f90bd213 100644 --- a/tdeio/tdeio/job.cpp +++ b/tdeio/tdeio/job.cpp @@ -2,6 +2,8 @@ Copyright (C) 2000 Stephan Kulow David Faure Waldo Bastian + Copyright (C) 2009 Andreas Gruenbacher + Copyright (C) 2022 Alexander Hajnal This library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public @@ -78,6 +80,88 @@ extern "C" { #include #endif + + +// Set this macro if libattr is installed and working +#define USE_XATTR 1 + +// Extended attribute support (added AKH 2017-11-26, updated AKH 2022-12-16) +// Based on copyattr.c by Andreas Gruenbacher (included with libattr) +// This does NOT also copy Access Control Lists! + +#ifdef USE_XATTR + +//#include // For errno (already included above) +//#include // For free (already included above) +//#include // For errno, strdup, and strcmp (already implictly included above) +#include // For va_start and va_end + +extern "C" { +# include +# include +} + +/* + * Optional error handler for attr_copy_file(). CTX is the error + * context passed to attr_copy_file(), ERR is the errno value + * that occurred. FMT and the rest are printf style arguments. + */ +static void +error(struct error_context *ctx, const char *fmt, ...) +{ + va_list ap; + + va_start(ap, fmt); + if (vfprintf(stderr, fmt, ap)) + fprintf(stderr, ": "); + fprintf(stderr, "%s\n", strerror(errno)); + va_end(ap); +} + +/* + * Optional handler for quoting path names in error messages. + * (This is a very stupid example!) + */ +static const char * +quote(struct error_context *ctx, const char *pathname) +{ + char *pn = strdup(pathname), *p; + pathname = strdup(pathname); + for (p = pn; *p != '\0'; p++) + if (*p & 0x80) + *p='?'; + return pn; +} + +static void +quote_free(struct error_context *ctx, const char *name) +{ + free((void *)name); +} + +/* + * The error context we pass to attr_copy_file(). + */ +struct error_context ctx = { error, quote, quote_free }; + +/* + * Optional attribute filter for attr_copy_file(). This example + * excludes all attributes other than extended user attributes. + * + * This function isn't used by the current code. + */ +static int is_user_attr(const char *name, struct error_context *ctx) +{ + // Note that non-Linux systems (including Solaris and Darwin/OSX) may + // use a different naming scheme for user attributes. AFAIK FreeBSD + // and NetBSD do support the "user" namespace. + return strcmp(name, "user.") == 0; +} + +#endif /* USE_XATTR */ + + + using namespace TDEIO; template class TQPtrList; @@ -1958,6 +2042,14 @@ void FileCopyJob::slotResult( TDEIO::Job *job) if (job == m_copyJob) { m_copyJob = 0; + +#ifdef USE_XATTR + { + // Copy extended attributes (added AKH 2017-11-26) + attr_copy_file(TQFile::encodeName(m_src.path()), TQFile::encodeName(m_dest.path()), NULL, &ctx); + } +#endif + if (m_move) { d->m_delJob = file_delete( m_src, false/*no GUI*/ ); // Delete source