You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
355 lines
8.9 KiB
C++
355 lines
8.9 KiB
C++
/*******************************************************************************
|
|
Extended attributes support for TDE
|
|
Copyright © 2025 Philippe Mavridis <philippe.mavridis@yandex.com>
|
|
|
|
Based on xattr_p.h from KFileMetaData
|
|
Copyright © 2014 Raphael Kubo da Costa <rakuco@FreeBSD.org>
|
|
|
|
This program or library is free software; you can redistribute it and/or
|
|
modify it under the terms of the GNU Lesser General Public License as
|
|
published by the Free Software Foundation; either version 2.1 of the License,
|
|
or (at your option) any later version.
|
|
|
|
This library is distributed in the hope that it will be useful, but WITHOUT
|
|
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
|
|
FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
|
|
details.
|
|
|
|
You should have received a copy of the GNU Lesser General Public License
|
|
along with this library; if not, write to the Free Software Foundation, Inc.,
|
|
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
|
|
|
*******************************************************************************/
|
|
|
|
#include <sys/types.h>
|
|
#include <errno.h>
|
|
|
|
#if defined(Q_OS_LINUX) || defined(__GLIBC__)
|
|
# include <sys/xattr.h>
|
|
#elif defined(Q_OS_FREEBSD) || defined(Q_OS_NETBSD)
|
|
# include <sys/extattr.h>
|
|
#endif
|
|
|
|
#include <tqfile.h>
|
|
|
|
#include "tdexattr.h"
|
|
|
|
#if defined(Q_OS_LINUX) || defined(Q_OS_FREEBSD) || defined(Q_OS_NETBSD)
|
|
|
|
# define CHECK_URL(url) \
|
|
if (!url.isValid() || url.isEmpty()) return TDEIO::ERR_MALFORMED_URL; \
|
|
if (!url.isLocalFile()) return 0; // silently ignore non-local urls
|
|
|
|
# define GET_ENCODED_PATH(url) \
|
|
const TQByteArray p = TQFile::encodeName(url.path()); \
|
|
const char* encodedPath = p.data();
|
|
|
|
#if defined(Q_OS_FREEBSD) || defined(Q_OS_NETBSD)
|
|
static TQValueList<TQCString> // FIXME untested
|
|
splitLengthValue(TQByteArray data)
|
|
{
|
|
uint pos = 0;
|
|
TQValueList<TQCString> entries;
|
|
char *s;
|
|
while (pos < data.size())
|
|
{
|
|
uchar len = data[pos];
|
|
|
|
if (pos + 1 + len <= data.size())
|
|
{
|
|
strncat(s, &data[pos + 1], len);
|
|
entries.append(TQCString(s, len));
|
|
}
|
|
|
|
pos += 1 + len;
|
|
}
|
|
return entries;
|
|
}
|
|
#else
|
|
static TQValueList<TQCString>
|
|
splitZeroSeparator(TQByteArray data)
|
|
{
|
|
uint pos = 0;
|
|
TQValueList<TQCString> entries;
|
|
while (pos < data.size())
|
|
{
|
|
const char *c = &data[pos];
|
|
size_t len = strlen(c);
|
|
entries.append(TQCString(c));
|
|
pos += len + 1;
|
|
}
|
|
|
|
return entries;
|
|
}
|
|
#endif
|
|
|
|
uint
|
|
TDEXAttr::list(const KURL& url, TQValueList<TQCString> *list)
|
|
{
|
|
CHECK_URL(url);
|
|
GET_ENCODED_PATH(url);
|
|
|
|
#if defined(Q_OS_LINUX)
|
|
const ssize_t size = listxattr(encodedPath, nullptr, 0);
|
|
#elif defined(Q_OS_FREEBSD) || defined(Q_OS_NETBSD)
|
|
const ssize_t size = extattr_list_file(encodedPath, EXTATTR_NAMESPACE_USER, nullptr, 0);
|
|
#endif
|
|
|
|
if (size == 0)
|
|
{
|
|
return 0;
|
|
}
|
|
else if (size == -1)
|
|
{
|
|
return parseError(errno, TDEIO::CMD_LISTATTR);
|
|
}
|
|
else
|
|
{
|
|
TQByteArray data(size);
|
|
|
|
for (;;)
|
|
{
|
|
#if defined(Q_OS_LINUX)
|
|
const ssize_t r = listxattr(encodedPath, data.data(), data.size());
|
|
#elif defined(Q_OS_FREEBSD) || defined(Q_OS_NETBSD)
|
|
const ssize_t r = extattr_list_file(encodedPath, EXTATTR_NAMESPACE_USER, data.data(), data.size());
|
|
#endif
|
|
|
|
if (r == 0) {
|
|
list->clear();
|
|
return 0;
|
|
}
|
|
|
|
if (r == -1 && errno != ERANGE)
|
|
{
|
|
list->clear();
|
|
return parseError(errno, TDEIO::CMD_LISTATTR);
|
|
}
|
|
|
|
if (r > 0)
|
|
{
|
|
data.resize(r);
|
|
break;
|
|
}
|
|
else // ERANGE
|
|
{
|
|
data.resize(data.size() * 2);
|
|
}
|
|
}
|
|
|
|
#if defined(Q_OS_LINUX)
|
|
const TQValueList<TQCString> entries = splitZeroSeparator(data);
|
|
#elif defined(Q_OS_FREEBSD) || defined(Q_OS_NETBSD)
|
|
const TQValueList<TQCString> entries = splitLengthValue(data);
|
|
#endif
|
|
|
|
list->clear();
|
|
|
|
TQValueList<TQCString>::const_iterator it;
|
|
for (it = entries.begin(); it != entries.end(); ++it)
|
|
{
|
|
TQCString attribute(*it);
|
|
|
|
#if defined(Q_OS_LINUX)
|
|
if (attribute.left(5) != "user.")
|
|
{
|
|
continue;
|
|
}
|
|
#endif
|
|
|
|
*list << getVisibleAttributeName(attribute);
|
|
}
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
uint
|
|
TDEXAttr::read(const KURL& url, const TQCString& attribute, TQCString *value)
|
|
{
|
|
CHECK_URL(url);
|
|
GET_ENCODED_PATH(url);
|
|
TQCString attr = getLocalAttributeName(attribute);
|
|
|
|
#if defined(Q_OS_LINUX) || (defined(__GLIBC__) && !defined(__stub_getxattr))
|
|
const ssize_t size = getxattr(encodedPath, attr, nullptr, 0);
|
|
#elif defined(Q_OS_FREEBSD) || defined(Q_OS_NETBSD)
|
|
const ssize_t size = extattr_get_file(encodedPath, EXTATTR_NAMESPACE_USER, attr, NULL, 0);
|
|
#endif
|
|
|
|
if (size == -1)
|
|
{
|
|
return parseError(errno, TDEIO::CMD_READATTR);
|
|
}
|
|
else if (size == 0)
|
|
{
|
|
*value = "";
|
|
return 0;
|
|
}
|
|
else
|
|
{
|
|
TQByteArray data(size);
|
|
|
|
for (;;)
|
|
{
|
|
|
|
#if defined(Q_OS_LINUX) || (defined(__GLIBC__) && !defined(__stub_getxattr))
|
|
const ssize_t r = getxattr(encodedPath, attr, data.data(), data.size());
|
|
#elif defined(Q_OS_FREEBSD) || defined(Q_OS_NETBSD)
|
|
const ssize_t r = extattr_get_file(encodedPath, EXTATTR_NAMESPACE_USER, attr, data.data(), data.size());
|
|
#endif
|
|
|
|
if (r == -1 && errno != ERANGE)
|
|
{
|
|
*value = "";
|
|
return parseError(errno, TDEIO::CMD_READATTR);
|
|
}
|
|
else if (r == 0)
|
|
{
|
|
*value = "";
|
|
return 0;
|
|
}
|
|
else if (r >= 0)
|
|
{
|
|
*value = TQCString(data, r + 1);
|
|
return 0;
|
|
}
|
|
else // ERANGE
|
|
{
|
|
data.resize(data.size() * 2);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
uint
|
|
TDEXAttr::write(const KURL& url, const TQCString& attribute, const TQCString& value)
|
|
{
|
|
CHECK_URL(url);
|
|
GET_ENCODED_PATH(url);
|
|
TQCString attr = getLocalAttributeName(attribute);
|
|
|
|
int r;
|
|
#if defined(Q_OS_LINUX) || (defined(__GLIBC__) && !defined(__stub_setxattr))
|
|
r = setxattr(encodedPath, attr, value.data(), value.size(), 0);
|
|
#elif defined(Q_OS_FREEBSD) || defined(Q_OS_NETBSD)
|
|
r = extattr_set_file(encodedPath, EXTATTR_NAMESPACE_USER, attr, value.data(), value.size());
|
|
#endif
|
|
|
|
return r == -1 ? parseError(errno, TDEIO::CMD_WRITEATTR) : 0;
|
|
}
|
|
|
|
uint
|
|
TDEXAttr::remove(const KURL& url, const TQCString& attribute)
|
|
{
|
|
CHECK_URL(url);
|
|
GET_ENCODED_PATH(url);
|
|
TQCString attr = getLocalAttributeName(attribute);
|
|
|
|
int r;
|
|
#if defined(Q_OS_LINUX) || (defined(__GLIBC__) && !defined(__stub_removexattr))
|
|
r = removexattr(encodedPath, attr);
|
|
#elif defined(Q_OS_FREEBSD) || defined(Q_OS_NETBSD)
|
|
r = extattr_delete_file (encodedPath, EXTATTR_NAMESPACE_USER, attr);
|
|
#else
|
|
return TDEIO::ERR_UNSUPPORTED_ACTION;
|
|
#endif
|
|
|
|
return r == -1 ? parseError(errno, TDEIO::CMD_REMOVEATTR) : 0;
|
|
}
|
|
|
|
bool
|
|
TDEXAttr::supported(const KURL& url)
|
|
{
|
|
return read(url, "test", nullptr) != TDEIO::ERR_UNSUPPORTED_ACTION;
|
|
}
|
|
|
|
#else // stubs for unsupported platforms
|
|
|
|
uint
|
|
TDEXAttr::list(const KURL& url, TQValueList<TQCString> *list)
|
|
{
|
|
return TDEIO::ERR_UNSUPPORTED_ACTION;
|
|
}
|
|
|
|
uint
|
|
TDEXAttr::read(const KURL& url, const TQCString& attr, TQCString *value)
|
|
{
|
|
return TDEIO::ERR_UNSUPPORTED_ACTION;
|
|
}
|
|
|
|
uint
|
|
TDEXAttr::write(const KURL& url, const TQCString& attr, const TQCString& value)
|
|
{
|
|
return TDEIO::ERR_UNSUPPORTED_ACTION;
|
|
}
|
|
|
|
TDEIO::Error
|
|
TDEXAttr::remove(const KURL& url, const TQCString& attr)
|
|
{
|
|
return TDEIO::ERR_UNSUPPORTED_ACTION;
|
|
}
|
|
|
|
bool
|
|
TDEXAttr::supported(const KURL& url)
|
|
{
|
|
return TDEIO::ERR_UNSUPPORTED_ACTION;
|
|
}
|
|
#endif
|
|
|
|
uint
|
|
TDEXAttr::parseError(int _errno, int command)
|
|
{
|
|
switch (_errno)
|
|
{
|
|
case E2BIG:
|
|
case ENODATA:
|
|
{
|
|
return command == TDEIO::CMD_READATTR ?
|
|
TDEIO::ERR_COULD_NOT_READ :
|
|
TDEIO::ERR_COULD_NOT_WRITE;
|
|
}
|
|
case ENOTSUP:
|
|
{
|
|
return TDEIO::ERR_UNSUPPORTED_ACTION;
|
|
}
|
|
case ERANGE:
|
|
{
|
|
return TDEIO::ERR_OUT_OF_MEMORY;
|
|
}
|
|
case EDQUOT:
|
|
case ENOSPC:
|
|
{
|
|
return TDEIO::ERR_DISK_FULL;
|
|
}
|
|
case EPERM:
|
|
{
|
|
return TDEIO::ERR_WRITE_ACCESS_DENIED;
|
|
}
|
|
default:
|
|
{
|
|
return TDEIO::ERR_INTERNAL;
|
|
}
|
|
}
|
|
}
|
|
|
|
TQCString
|
|
TDEXAttr::getLocalAttributeName(const TQCString& attr)
|
|
{
|
|
TQCString a(attr);
|
|
#if defined(Q_OS_LINUX)
|
|
a = a.prepend("user.");
|
|
#endif
|
|
return a;
|
|
}
|
|
|
|
TQCString
|
|
TDEXAttr::getVisibleAttributeName(const TQCString& attr)
|
|
{
|
|
TQCString a(attr);
|
|
#if defined(Q_OS_LINUX)
|
|
a = a.remove(0, 5);
|
|
#endif
|
|
return a;
|
|
}
|
|
|
|
// kate: replace-tabs true; tab-width 4;
|