Я работаю над проектом, где я полагаюсь главным образом на расширенный атрибут файла, который я установил, когда я создаю файл. Но я сталкиваюсь с проблемой при изменении файла.
Пример:
Когда я редактирую текстовый файл в Сублимированном тексте, все расширенные атрибуты сохраняются, также значение inode остается тем же как прежде. Но когда я делаю то же в Gedit, оно создает новый файл вместо того, чтобы изменить существующий. Так inode значение, определяемый пользователем / расширился, атрибуты не сохраняются.
Я вижу, что эта проблема происходит из-за поведения копирования Gedit.
Существует ли способ сохранить их при использовании Gedit?
Ответ - нет. Вам нужно будет отправить отчет об ошибке или выполнить форк проекта и реализовать протокол расширенных атрибутов.
В C ++ / Qt я написал библиотеку, которая выполняет это с помощью
. Это то, что вам нужно будет прикрепить к 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 ;
}
}
Вам нужно будет добавить больше шаблонов, чтобы обрабатывать сериализацию различных типов данных. Исходные функции принимают пустые указатели, поэтому на самом деле вы можете поместить в них что угодно. Как это будет выглядеть на C? Не могу вам помочь.