我正在做一个项目,其中我主要依赖创建文件时设置的扩展属性。但我在修改文件时遇到了问题。
例子:
当我编辑文本文件时Sublime Text,所有扩展属性都保留,inode 值也与以前相同。但是当我在编辑,它会创建新文件而不是修改现有文件。因此 inode 值、用户定义/扩展属性不会被保留。
我认为该问题是由于 Gedit 的复制行为造成的。
有没有办法在使用 Gedit 时保留它们?
答案1
答案是否定的。您必须提交错误报告,或分叉项目并实施扩展属性协议。
在 C++/Qt 中,我编写了一个使用 实现此目的的库<sys/xattr.h>
。您必须将它附加到 QFile,如果您想要将它合并到 Gedit,则必须将其转换为 C 代码。无论如何,它提供了一个实现示例。基本头文件
#ifndef QXATTR_H
#define QXATTR_H
#include <QObject>
#include <QFile>
#include <sys/xattr.h>
class QXattr : public QObject
{
Q_OBJECT
public:
explicit QXattr(QFile &parent);
template<typename T> bool insert ( const QString &name, T value ); // Returns true if properly serialized
template<typename T> T value ( const QString &name ); // Gets value of name. Returns Null pointer if none found.
template<typename T> QString name ( T value ); // Returns first name of given value
template<typename T> QStringList names ( T value ); // Returns all names of a given value
QStringList names (); // Returns all names
bool contains( const QString &name ); // Returns true if name exists.
bool remove ( const QString &name ); // Returns true if something was removed.
QString errorString(); // Last registered errno
protected:
inline const char *fileName();
void setErrorString(const QString &error);
void getNames(); // Should trigger on a move action in case the filesystem changed
signals:
void namesChanged();
void errorStringChanged( QString error );
// More signals will be placed here
private:
QStringList m_Names;
QFile &m_File;
QString m_ErrorString;
};
#endif // QXATTR_H
基本来源。
#include "qxattr.h"
#include "qconsoletoolkit.h"
QXattr::QXattr(QFile &parent)
: QObject(&parent)
, m_File(parent)
{
}
/* Insertion Templates */
template<typename T> bool QXattr::insert(const QString &name, T value)
{
Q_UNUSED(name)
Q_UNUSED(value)
return false;
}
template<> bool QXattr::insert<QByteArray> (const QString &name, QByteArray value)
{
int error = setxattr(fileName(), name.toLocal8Bit().data(), value.data(), size_t(value.size()), 0 );
ct_Check(error == -1, strerror(errno));
this->getNames();
return true;
}
template<> bool QXattr::insert<QString> (const QString &name, QString value)
{
return this->insert<QByteArray>(name, value.toLocal8Bit());
}
template<> bool QXattr::insert<const char*>(const QString &name, const char* value)
{
return this->insert<QByteArray>(name, QByteArray(value));
}
/* Value Templates */
template<typename T> T QXattr::value(const QString &name)
{
Q_UNUSED(name)
}
template<> QByteArray QXattr::value<QByteArray>(const QString &name)
{
ssize_t valueLength;
valueLength = getxattr(fileName(), name.toLocal8Bit().data(), nullptr, 0);
ct_Check(valueLength == -1, strerror(errno));
if (!valueLength) { return QByteArray(); }
QByteArray val(int(valueLength), ' ');
valueLength = getxattr(fileName(), name.toLocal8Bit().data(), val.data(), size_t(valueLength));
ct_Check(valueLength == -1, strerror(errno));
return val;
}
/* Name Templates */
template<typename T> QString QXattr::name(T value)
{
Q_UNUSED(value)
return QString();
}
template<> QString QXattr::name<const char *>(const char* value)
{
getNames();
QByteArray ba(value);
for ( int i = 0; i < m_Names.length(); i++ ) {
if (ba == this->value<QByteArray>(m_Names.at(i))) { return m_Names.at(i); }
}
return QString();
}
/* Names Templates */
template<class T> QStringList QXattr::names(T value)
{
Q_UNUSED(value)
return QStringList();
}
template<> QStringList QXattr::names<const char *>(const char* value)
{
getNames();
QByteArray ba(value);
QStringList names;
for ( int i = 0; i < m_Names.length(); i++ ) {
if (ba == this->value<QByteArray>(m_Names.at(i))) { names << m_Names.at(i); }
}
return names;
}
QStringList QXattr::names()
{
getNames();
return m_Names;
}
/* Regular Functions */
bool QXattr::contains(const QString &name)
{
getNames();
return m_Names.contains(name);
}
bool QXattr::remove(const QString &name)
{
// Returns false if error.
// Error can mean, that the name simply did not exist.
if ( removexattr(fileName(), name.toLocal8Bit().data()) == -1 ) {
setErrorString(strerror(errno));
return false;
}
return true;
}
/* Convenience Functions */
const char* QXattr::fileName()
{
return m_File.fileName().toLocal8Bit().data();
}
void QXattr::setErrorString(const QString &error)
{
m_ErrorString = error;
emit errorStringChanged( error );
}
void QXattr::getNames()
{
m_Names.clear();
ssize_t bufferLength(0);
ssize_t nameLength;
char *name;
/* Determine the length of the buffer needed. */
bufferLength = listxattr(fileName(), nullptr, 0);
ct_Check(bufferLength == -1, strerror(errno));
if (!bufferLength) { return; }
/* Allocate the buffer. */
QByteArray buffer(int(bufferLength), ' ');
/* Copy the list of attribute keys to the buffer. */
bufferLength = listxattr(fileName(), buffer.data(), size_t(bufferLength));
ct_Check(bufferLength == -1, strerror(errno));
/* Loop over the list of zero terminated strings with the attribute keys.
* Use the remaining buffer length to determine the end of the list. */
name = buffer.data();
QStringList names;
while (bufferLength > 0) {
m_Names << name;
/* Forward to next attribute name. */
nameLength = ssize_t(strlen(name) + 1);
bufferLength -= nameLength;
name += nameLength ;
}
}
您需要添加更多模板才能处理不同数据类型的序列化。原始函数采用 void 指针,因此您实际上可以将任何东西放入其中。这在 C 中最终会是什么样子?我无法帮助您。