Gedit 不保留文件编辑的扩展属性

Gedit 不保留文件编辑的扩展属性

我正在做一个项目,其中我主要依赖创建文件时设置的扩展属性。但我在修改文件时遇到了问题。

例子:

当我编辑文本文件时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 中最终会是什么样子?我无法帮助您。

https://wiki.gnome.org/Apps/Gedit/ReportingBugs

相关内容