用 C 語言獲取檔案的擴充套件屬性
本文將介紹幾種如何在 C 語言中獲取檔案擴充套件屬性的方法。
使用 getxattr
和 listxattr
函式獲取檔案的擴充套件屬性
一些基於 UNIX 的系統為檔案提供擴充套件的屬性,表示可以與檔案關聯的後設資料的名稱/值對。擴充套件屬性需要基礎檔案系統支援,但是常見檔案系統型別具有此功能。擴充套件屬性具有 namespace.name
型別的特定格式,其中 namespace
用於對功能相似的分組,而 name
部分則標識單個擴充套件屬性。名稱空間可以具有以下值:user
,trusted
,system
和 security
,作為一種慣例,它們區分了幾種許可權型別(在這裡有詳細描述)。在這種情況下,我們實現了一個例子程式,該程式將多個檔名用作命令列引數,並因此為每個檔案檢索所有擴充套件屬性。請注意,該程式使用 getopt
函式處理多個檔案引數。
getxattr
函式採用四個引數來檢索擴充套件的屬性值。第一個引數指定檔案系統中的路徑,以指示應為其檢索 EA 的檔案,第二個引數指定屬性名稱。最後兩個引數是指向由 getxattr
儲存值的位置的指標,以及該地址上可用的緩衝區大小。請注意,可以通過將值 0
作為大小引數傳遞來檢索屬性值的大小,並且呼叫的返回值是所需緩衝區的位元組數。儘管在呼叫第二個呼叫以檢索該值時,它可能會更改並且大小不同;因此,最好檢查錯誤程式碼以確保無誤執行。
另一方面,listxattr
函式檢索給定檔案路徑的擴充套件屬性名稱列表。它包含三個引數,第一個是檔案路徑。接下來的兩個參數列示將儲存檢索到的列表的緩衝區,緩衝區的大小以位元組為單位。請注意,此緩衝區是由呼叫方分配的,並且呼叫方負責分配足夠的記憶體。同樣,類似於 getxattr
,可以將值 0
作為該函式的第三個引數傳遞,返回值將是儲存完整列表所需的緩衝區大小。
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <stdbool.h>
#include <sys/xattr.h>
#define XATTR_SIZE 10000
#define errExit(msg) do { perror(msg); exit(EXIT_FAILURE); \
} while (0)
static void usageError(char *progName)
{
fprintf(stderr, "Usage: %s [-x] file...\n", progName);
exit(EXIT_FAILURE);
}
int main(int argc, char *argv[]) {
char list[XATTR_SIZE], value[XATTR_SIZE];
ssize_t listLen, valueLen;
int ns, j, k, opt;
bool hexDisplay;
hexDisplay = 0;
while ((opt = getopt(argc, argv, "x")) != -1) {
switch (opt) {
case 'x': hexDisplay = 1; break;
case '?': usageError(argv[0]);
}
}
if (optind >= argc)
usageError(argv[0]);
for (j = optind; j < argc; j++) {
listLen = listxattr(argv[j], list, XATTR_SIZE);
if (listLen == -1)
errExit("listxattr");
printf("%s:\n", argv[j]);
for (ns = 0; ns < listLen; ns += strlen(&list[ns]) + 1) {
printf(" name=%s; ", &list[ns]);
valueLen = getxattr(argv[j], &list[ns], value, XATTR_SIZE);
if (valueLen == -1) {
printf("couldn't get value");
} else if (!hexDisplay) {
printf("value=%.*s", (int) valueLen, value);
} else {
printf("value=");
for (k = 0; k < valueLen; k++)
printf("%02x ", (unsigned char) value[k]);
}
printf("\n");
}
printf("\n");
}
exit(EXIT_SUCCESS);
}
使用 setxattr
函式來設定檔案的擴充套件屬性
另外,我們可以使用 setxattr
函式為檔案設定任意屬性,該函式將檔案的路徑名,名稱/值對作為單獨的引數,值的大小,一個整數,該整數指定不同設定操作的預定義值。如果最後一個引數為零(預設值),則擴充套件屬性(如果不存在)將建立;否則,擴充套件屬性將被建立。否則,將替換該值。可以指定 XATTR_CREATE
巨集以指示僅建立選項,如果該屬性存在則將失敗,而可以指定 XATTR_REPLACE
進行替換,如果該屬性不存在則將失敗。
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/xattr.h>
#define errExit(msg) do { perror(msg); exit(EXIT_FAILURE); \
} while (0)
static void usageError(char *progName)
{
fprintf(stderr, "Usage: %s file\n", progName);
exit(EXIT_FAILURE);
}
int main(int argc, char *argv[]) {
char *value;
if (argc < 2 || strcmp(argv[1], "--help") == 0)
usageError(argv[0]);
value = "x attribute value";
if (setxattr(argv[1], "user.x", value, strlen(value), 0) == -1)
errExit("setxattr");
value = "y attribute value";
if (setxattr(argv[1], "user.y", value, strlen(value), 0) == -1)
errExit("setxattr");
exit(EXIT_SUCCESS);
}
Founder of DelftStack.com. Jinku has worked in the robotics and automotive industries for over 8 years. He sharpened his coding skills when he needed to do the automatic testing, data collection from remote servers and report creation from the endurance test. He is from an electrical/electronics engineering background but has expanded his interest to embedded electronics, embedded programming and front-/back-end programming.
LinkedIn