Im vorherigen Teil ging es darum, wie man unter Linux Extended Attributes auf der Kommandozeile bearbeitet. Das Thema diesmal ist, mit welchen Syscalls man dies in C erledigen kann.
Für die 4 verschiedenen Operationen die man benötigt, nämlich listxattr, getxattr, setxattr und removexattr, gibt es jeweils 3 Syscalls.
#include <sys/types.h>
#include <sys/xattr.h>
ssize_t listxattr(const char *path, char *list, size_t size);
ssize_t llistxattr(const char *path, char *list, size_t size);
ssize_t flistxattr(int fd, char *list, size_t size);
ssize_t getxattr(const char *path, const char *name,
void *value, size_t size);
ssize_t lgetxattr(const char *path, const char *name,
void *value, size_t size);
ssize_t fgetxattr(int fd, const char *name,
void *value, size_t size);
int setxattr(const char *path, const char *name,
const void *value, size_t size, int flags);
int lsetxattr(const char *path, const char *name,
const void *value, size_t size, int flags);
int fsetxattr(int fd, const char *name,
const void *value, size_t size, int flags);
int removexattr(const char *path, const char *name);
int lremovexattr(const char *path, const char *name);
int fremovexattr(int fd, const char *name);
Die Syscalls mit dem l-Prefix liefern für den Fall dass path
ein Symlink ist die Attribute des Symlinks selber, und nicht von der Datei, auf die der Symlink zeigt.
Bei den Syscalls mit dem f-Prefix übergibt man statt des Pfades einen Filedescriptor, den man mit open erhält.
Mit listxattr
erhält man eine komplette Liste aller Extended Attributes für die Datei. Man muss einen vorher allozierten Buffer und seine Größe übergeben. Die Namen der Extended Attributes werden dann in diesen Buffer geschrieben, getrennt immer durch ein 0-Byte. Falls der Buffer zu klein ist, liefert die Funktion -1 zurück und setzt errno
auf ERANGE
. Man kann auch abfragen, wie groß der Buffer sein müsste, in dem man als size
0 übergibt. Der Rückgabewert ist dann die benötigte Größe des Buffers.
Hier ist ein Beispielprogramm, dass alle Extended Attributes einer Datei auflistet. Der Code um die Liste der Namen zu erhalten ist:
char *list = malloc(BUF_LEN);
ssize_t len = listxattr(path, list, BUF_LEN);
Wenn wir die Namen der Attribute haben, können wir den Wert mit getxattr
erhalten. Diese Funktion erwartet ebenfalls einen Buffer, in den der Wert dann geschrieben wird. Auch hier kann man für size
0 angeben, um die Länge des Attributwerts zu erhalten.
Um das Beispielprogramm zu erweitern, dass es auch die Werte der Attribute ausgibt, könnte man die for-Schleife am Ende durch diesen Code ersetzen:
// print attributes
int begin = 0;
for(int i=0;i<len;i++) {
if(list[i] == '\0') {
char *xattr_name = list + begin;
char value[0x10000];
ssize_t vallen = getxattr(path, xattr_name, value, 0x10000);
printf("%s: %.*s\n", xattr_name, (int)vallen, value);
begin = i + 1;
}
}
Es fehlt zwar die Fehlerbehandlung, es sollte jedoch immer funktionieren. Die Größe ist eh auf 64kb beschränkt, bei vielen Dateisystemen sogar noch weniger.
Kommen wir zu setxattr
, mit dem man ein Extended Attribute setzt. Die Funktion erwartet als letzten Parameter ein flag. Ist dies 0, wird der Wert gesetzt, egal ob er schon existiert oder nicht. Bei XATTR_CREATE
liefert die Funktion einen Fehler, wenn das Attribut schon existiert und bei XATTR_REPLACE
gibt es einen Fehler, wenn der Wert nicht existiert.
xsetattr(path, "user.myattrname", value, valuelen, 0);
Bleibt zuletzt noch removexattr
, dem man einfach nur den Dateipfad und den Attribut-Namen gibt, und der wird dann entfernt.