lremovexattr 函数详解 链接到标题

1. 函数介绍 链接到标题

lremovexattr 是 Linux 系统中用于删除文件扩展属性(Extended Attributes,简称 xattrs)的系统调用,特别之处在于它不会跟随符号链接。可以把扩展属性想象成"文件的隐藏标签",而 lremovexattr 就是专门用来撕掉符号链接本身标签的工具。

removexattr 函数不同,当目标是符号链接时,lremovexattr 只会删除符号链接本身的扩展属性,而不会去删除符号链接指向的目标文件的扩展属性。这就像你有一张指向某个地址的名片,removexattr 会去撕掉那个地址的房子上的标签,而 lremovexattr 只撕掉这张名片上的标签。

2. 函数原型 链接到标题

#include <sys/xattr.h>

int lremovexattr(const char *path, const char *name);

3. 功能 链接到标题

lremovexattr 函数用于删除指定文件路径的扩展属性。如果目标是符号链接,lremovexattr 只会删除符号链接本身的扩展属性,而不会跟随符号链接去删除目标文件的扩展属性。

4. 参数 链接到标题

  • path: 指向文件路径的指针
  • name: 要删除的扩展属性名称(字符串格式)

5. 扩展属性命名规范 链接到标题

扩展属性名称通常采用以下格式:

  • namespace.attribute_name

常见命名空间:

  • user.*: 用户自定义属性(最常用,需要文件写权限)
  • trusted.*: 受信任的属性(只有特权用户可访问)
  • system.*: 系统属性(由内核或系统服务使用)
  • security.*: 安全相关属性(如 SELinux 标签)

6. 返回值 链接到标题

  • 成功: 返回 0
  • 失败: 返回 -1,并设置相应的 errno 错误码

7. 常见错误码 链接到标题

  • ENODATA: 指定的属性不存在
  • EACCES: 权限不足
  • ENOTSUP: 文件系统不支持扩展属性
  • ENOENT: 文件不存在
  • ENOTDIR: 路径组件不是目录
  • ELOOP: 符号链接循环
  • EPERM: 操作不被允许
  • EROFS: 文件系统只读
  • EFAULT: 参数指针无效

8. 相似函数或关联函数 链接到标题

  • removexattr: 删除扩展属性(会跟随符号链接)
  • fremovexattr: 通过文件描述符删除扩展属性
  • lsetxattr: 设置扩展属性(不跟随符号链接)
  • lgetxattr: 获取扩展属性(不跟随符号链接)
  • listxattr: 列出文件的所有扩展属性
  • llistxattr: 列出符号链接的扩展属性

9. 示例代码 链接到标题

示例1:基础用法 - 删除文件扩展属性 链接到标题

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/xattr.h>
#include <string.h>
#include <errno.h>
#include <sys/stat.h>

// 显示文件扩展属性信息
void show_file_xattrs(const char *filename, const char *description) {
    char *buffer;
    ssize_t list_size;
    
    printf("=== %s ===\n", description);
    printf("文件: %s\n", filename);
    
    // 获取属性列表大小
    list_size = llistxattr(filename, NULL, 0);
    if (list_size == -1) {
        if (errno == ENOTSUP) {
            printf("  文件系统不支持扩展属性\n");
        } else {
            printf("  获取属性列表失败: %s\n", strerror(errno));
        }
        printf("\n");
        return;
    }
    
    if (list_size == 0) {
        printf("  没有扩展属性\n");
        printf("\n");
        return;
    }
    
    printf("  扩展属性列表:\n");
    
    // 分配缓冲区并获取属性列表
    buffer = malloc(list_size + 1);
    if (!buffer) {
        printf("  内存分配失败\n");
        printf("\n");
        return;
    }
    
    ssize_t result = llistxattr(filename, buffer, list_size);
    if (result == -1) {
        printf("  获取属性列表失败: %s\n", strerror(errno));
        free(buffer);
        printf("\n");
        return;
    }
    
    // 解析属性列表
    char *attr_name = buffer;
    int count = 0;
    while (attr_name < buffer + result) {
        printf("    [%d] %s\n", ++count, attr_name);
        attr_name += strlen(attr_name) + 1;
    }
    
    free(buffer);
    printf("\n");
}

// 获取单个扩展属性值
void get_xattr_value(const char *filename, const char *attr_name) {
    char buffer[256];
    ssize_t size = lgetxattr(filename, attr_name, buffer, sizeof(buffer) - 1);
    
    if (size != -1) {
        buffer[size] = '\0';
        printf("  %s = '%s'\n", attr_name, buffer);
    } else {
        printf("  %s: %s\n", attr_name, strerror(errno));
    }
}

int main() {
    const char *test_file = "xattr_remove_test.txt";
    const char *test_link = "xattr_remove_test_link";
    FILE *file;
    
    printf("=== lremovexattr 基础示例 ===\n\n");
    
    // 创建测试文件
    file = fopen(test_file, "w");
    if (file == NULL) {
        perror("创建测试文件失败");
        return 1;
    }
    fprintf(file, "Hello, Extended Attributes!\n");
    fclose(file);
    
    // 创建符号链接
    if (symlink(test_file, test_link) == -1) {
        perror("创建符号链接失败");
        unlink(test_file);
        return 1;
    }
    
    // 为原文件设置扩展属性
    const char *file_attr1 = "user.file_note1";
    const char *file_attr2 = "user.file_note2";
    const char *file_value1 = "这是原文件的属性1";
    const char *file_value2 = "这是原文件的属性2";
    
    if (setxattr(test_file, file_attr1, file_value1, strlen(file_value1), 0) == -1) {
        perror("为原文件设置扩展属性1失败");
    }
    if (setxattr(test_file, file_attr2, file_value2, strlen(file_value2), 0) == -1) {
        perror("为原文件设置扩展属性2失败");
    }
    
    // 为符号链接设置扩展属性
    const char *link_attr1 = "user.link_note1";
    const char *link_attr2 = "user.link_note2";
    const char *link_value1 = "这是符号链接的属性1";
    const char *link_value2 = "这是符号链接的属性2";
    
    if (lsetxattr(test_link, link_attr1, link_value1, strlen(link_value1), 0) == -1) {
        perror("为符号链接设置扩展属性1失败");
    }
    if (lsetxattr(test_link, link_attr2, link_value2, strlen(link_value2), 0) == -1) {
        perror("为符号链接设置扩展属性2失败");
    }
    
    printf("创建测试环境完成:\n");
    show_file_xattrs(test_file, "原文件扩展属性");
    show_file_xattrs(test_link, "符号链接扩展属性");
    
    // 演示 lremovexattr 的使用
    printf("=== 使用 lremovexattr 删除属性 ===\n");
    
    // 删除符号链接的属性
    printf("1. 删除符号链接的属性:\n");
    printf("   尝试删除 %s 的 %s\n", test_link, link_attr1);
    
    if (lremovexattr(test_link, link_attr1) == 0) {
        printf("   ✓ 成功删除符号链接属性\n");
    } else {
        printf("   ✗ 删除失败: %s\n", strerror(errno));
    }
    
    // 验证删除结果
    printf("   删除后符号链接属性:\n");
    get_xattr_value(test_link, link_attr1);
    get_xattr_value(test_link, link_attr2);
    printf("\n");
    
    // 尝试删除不存在的属性
    printf("2. 删除不存在的属性:\n");
    const char *nonexistent_attr = "user.nonexistent";
    printf("   尝试删除 %s 的 %s\n", test_link, nonexistent_attr);
    
    if (lremovexattr(test_link, nonexistent_attr) == 0) {
        printf("   ✓ 删除成功\n");
    } else {
        if (errno == ENODATA) {
            printf("   ✓ 正确: 属性不存在 (ENODATA)\n");
        } else {
            printf("   ✗ 删除失败: %s\n", strerror(errno));
        }
    }
    printf("\n");
    
    // 显示删除后的状态
    show_file_xattrs(test_file, "原文件扩展属性(应该不变)");
    show_file_xattrs(test_link, "符号链接扩展属性(已删除一个)");
    
    // 清理测试文件
    unlink(test_file);
    unlink(test_link);
    
    return 0;
}

示例2:符号链接与扩展属性删除的区别 链接到标题

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/xattr.h>
#include <string.h>
#include <errno.h>
#include <sys/stat.h>

// 显示文件详细信息
void show_file_details(const char *filename, const char *description) {
    struct stat file_stat;
    
    printf("=== %s ===\n", description);
    printf("文件名: %s\n", filename);
    
    // 使用 lstat(不跟随符号链接)
    if (lstat(filename, &file_stat) == -1) {
        printf("  获取信息失败: %s\n", strerror(errno));
        return;
    }
    
    printf("  Inode: %ld\n", (long)file_stat.st_ino);
    printf("  文件类型: ");
    
    if (S_ISLNK(file_stat.st_mode)) {
        printf("符号链接\n");
        // 显示符号链接指向的目标
        char target[256];
        ssize_t len = readlink(filename, target, sizeof(target) - 1);
        if (len != -1) {
            target[len] = '\0';
            printf("  指向: %s\n", target);
        }
    } else if (S_ISREG(file_stat.st_mode)) {
        printf("普通文件\n");
        printf("  大小: %ld 字节\n", (long)file_stat.st_size);
    } else {
        printf("其他类型\n");
    }
    
    printf("\n");
}

// 比较 lremovexattr 和 removexattr 的区别
void demonstrate_remove_difference() {
    const char *target_file = "target_remove_file.txt";
    const char *symlink_file = "symlink_to_remove_target";
    FILE *file;
    
    printf("=== lremovexattr 与 removexattr 区别演示 ===\n\n");
    
    // 创建目标文件
    file = fopen(target_file, "w");
    if (file == NULL) {
        perror("创建目标文件失败");
        return;
    }
    fprintf(file, "目标文件内容\n");
    fclose(file);
    
    // 创建符号链接
    if (symlink(target_file, symlink_file) == -1) {
        perror("创建符号链接失败");
        unlink(target_file);
        return;
    }
    
    printf("创建测试环境:\n");
    show_file_details(target_file, "目标文件");
    show_file_details(symlink_file, "符号链接");
    
    // 为目标文件设置扩展属性
    const char *target_attr = "user.target_property";
    const char *target_value = "这是目标文件的属性";
    if (setxattr(target_file, target_attr, target_value, strlen(target_value), 0) == -1) {
        perror("设置目标文件属性失败");
    } else {
        printf("✓ 为目标文件设置扩展属性: %s = %s\n", target_attr, target_value);
    }
    
    // 为符号链接设置相同的扩展属性名称但不同值
    const char *link_value = "这是符号链接的属性";
    if (lsetxattr(symlink_file, target_attr, link_value, strlen(link_value), 0) == -1) {
        perror("设置符号链接属性失败");
    } else {
        printf("✓ 为符号链接设置扩展属性: %s = %s\n", target_attr, link_value);
    }
    
    printf("\n=== 删除操作比较 ===\n");
    
    // 使用 lremovexattr 删除符号链接的属性
    printf("1. 使用 lremovexattr 删除符号链接属性:\n");
    if (lremovexattr(symlink_file, target_attr) == 0) {
        printf("   ✓ lremovexattr 成功删除符号链接属性\n");
    } else {
        printf("   ✗ lremovexattr 删除失败: %s\n", strerror(errno));
    }
    
    // 验证结果
    printf("   删除后检查:\n");
    char buffer[256];
    ssize_t size;
    
    // 检查符号链接是否还有该属性
    size = lgetxattr(symlink_file, target_attr, buffer, sizeof(buffer) - 1);
    if (size != -1) {
        buffer[size] = '\0';
        printf("   符号链接属性: %s = %s\n", target_attr, buffer);
    } else {
        printf("   符号链接属性: 不存在 (%s)\n", strerror(errno));
    }
    
    // 检查目标文件是否还有该属性
    size = getxattr(target_file, target_attr, buffer, sizeof(buffer) - 1);
    if (size != -1) {
        buffer[size] = '\0';
        printf("   目标文件属性: %s = %s\n", target_attr, buffer);
    } else {
        printf("   目标文件属性: 不存在 (%s)\n", strerror(errno));
    }
    
    printf("\n");
    
    // 重新为符号链接设置属性
    if (lsetxattr(symlink_file, target_attr, link_value, strlen(link_value), 0) == -1) {
        perror("重新设置符号链接属性失败");
    } else {
        printf("✓ 重新为符号链接设置扩展属性\n");
    }
    
    // 使用 removexattr 删除(会删除目标文件的属性)
    printf("2. 使用 removexattr 删除属性:\n");
    if (removexattr(symlink_file, target_attr) == 0) {
        printf("   ✓ removexattr 成功删除属性\n");
    } else {
        printf("   ✗ removexattr 删除失败: %s\n", strerror(errno));
    }
    
    // 验证结果
    printf("   删除后检查:\n");
    
    // 检查符号链接是否还有该属性
    size = lgetxattr(symlink_file, target_attr, buffer, sizeof(buffer) - 1);
    if (size != -1) {
        buffer[size] = '\0';
        printf("   符号链接属性: %s = %s\n", target_attr, buffer);
    } else {
        printf("   符号链接属性: 不存在 (%s)\n", strerror(errno));
    }
    
    // 检查目标文件是否还有该属性
    size = getxattr(target_file, target_attr, buffer, sizeof(buffer) - 1);
    if (size != -1) {
        buffer[size] = '\0';
        printf("   目标文件属性: %s = %s\n", target_attr, buffer);
    } else {
        printf("   目标文件属性: 不存在 (%s)\n", strerror(errno));
    }
    
    // 清理
    unlink(target_file);
    unlink(symlink_file);
}

int main() {
    printf("=== lremovexattr 与符号链接扩展属性删除 ===\n\n");
    
    // 演示区别
    demonstrate_remove_difference();
    
    printf("\n=== 重要说明 ===\n");
    printf("1. lremovexattr: 只删除符号链接本身的扩展属性\n");
    printf("2. removexattr: 会跟随符号链接删除目标文件的扩展属性\n");
    printf("3. 对于普通文件,lremovexattr 和 removexattr 效果相同\n");
    printf("4. 需要适当权限才能删除扩展属性\n");
    
    return 0;
}

示例3:完整的扩展属性管理工具 链接到标题

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/xattr.h>
#include <string.h>
#include <errno.h>
#include <getopt.h>
#include <sys/stat.h>

// 显示单个扩展属性
int show_single_xattr(const char *filename, const char *attr_name, int use_lgetxattr) {
    char buffer[1024];
    ssize_t size;
    
    if (use_lgetxattr) {
        size = lgetxattr(filename, attr_name, buffer, sizeof(buffer) - 1);
    } else {
        size = getxattr(filename, attr_name, buffer, sizeof(buffer) - 1);
    }
    
    if (size != -1) {
        buffer[size] = '\0';
        printf("%s = '%s'\n", attr_name, buffer);
        return 0;
    } else {
        return -1;
    }
}

// 列出所有扩展属性
void list_all_xattrs(const char *filename, int use_lgetxattr) {
    char *buffer;
    ssize_t list_size;
    
    if (use_lgetxattr) {
        list_size = llistxattr(filename, NULL, 0);
    } else {
        list_size = listxattr(filename, NULL, 0);
    }
    
    if (list_size == -1) {
        if (errno == ENOTSUP) {
            printf("文件系统不支持扩展属性\n");
        } else {
            printf("获取属性列表失败: %s\n", strerror(errno));
        }
        return;
    }
    
    if (list_size == 0) {
        printf("没有扩展属性\n");
        return;
    }
    
    buffer = malloc(list_size + 1);
    if (!buffer) {
        printf("内存分配失败\n");
        return;
    }
    
    if (use_lgetxattr) {
        list_size = llistxattr(filename, buffer, list_size);
    } else {
        list_size = listxattr(filename, buffer, list_size);
    }
    
    if (list_size == -1) {
        printf("获取属性列表失败: %s\n", strerror(errno));
        free(buffer);
        return;
    }
    
    // 解析属性列表
    char *attr_name = buffer;
    while (attr_name < buffer + list_size) {
        if (show_single_xattr(filename, attr_name, use_lgetxattr) == -1) {
            printf("%s: %s\n", attr_name, strerror(errno));
        }
        attr_name += strlen(attr_name) + 1;
    }
    
    free(buffer);
}

// 删除扩展属性
int remove_xattr(const char *filename, const char *attr_name, int use_lremovexattr) {
    int result;
    
    if (use_lremovexattr) {
        result = lremovexattr(filename, attr_name);
    } else {
        result = removexattr(filename, attr_name);
    }
    
    return result;
}

// 显示帮助信息
void show_help(const char *program_name) {
    printf("用法: %s [选项] 文件 [属性名]\n", program_name);
    printf("\n选项:\n");
    printf("  -l, --lremovexattr     使用 lremovexattr (不跟随符号链接)\n");
    printf("  -r, --removexattr      使用 removexattr (跟随符号链接) [默认]\n");
    printf("  -a, --all              列出所有扩展属性\n");
    printf("  -v, --verbose          显示详细信息\n");
    printf("  -h, --help             显示此帮助信息\n");
    printf("\n示例:\n");
    printf("  %s file.txt user.description          # 删除指定属性\n");
    printf("  %s -l symlink user.attr               # 删除符号链接本身的属性\n");
    printf("  %s -a file.txt                        # 列出所有属性\n");
    printf("  %s -r symlink user.attr               # 删除符号链接指向文件的属性\n");
}

int main(int argc, char *argv[]) {
    int use_lremovexattr = 0;
    int list_all = 0;
    int verbose = 0;
    int opt;
    
    // 解析命令行参数
    static struct option long_options[] = {
        {"lremovexattr", no_argument, 0, 'l'},
        {"removexattr",  no_argument, 0, 'r'},
        {"all",          no_argument, 0, 'a'},
        {"verbose",      no_argument, 0, 'v'},
        {"help",         no_argument, 0, 'h'},
        {0, 0, 0, 0}
    };
    
    while ((opt = getopt_long(argc, argv, "lrahv", long_options, NULL)) != -1) {
        switch (opt) {
            case 'l':
                use_lremovexattr = 1;
                break;
            case 'r':
                use_lremovexattr = 0;
                break;
            case 'a':
                list_all = 1;
                break;
            case 'v':
                verbose = 1;
                break;
            case 'h':
                show_help(argv[0]);
                return 0;
            default:
                fprintf(stderr, "使用 '%s --help' 查看帮助信息\n", argv[0]);
                return 1;
        }
    }
    
    // 检查文件参数
    if (optind >= argc) {
        fprintf(stderr, "错误: 请指定文件名\n");
        fprintf(stderr, "使用 '%s --help' 查看帮助信息\n", argv[0]);
        return 1;
    }
    
    const char *filename = argv[optind];
    
    printf("=== 扩展属性删除工具 ===\n\n");
    
    // 检查文件是否存在
    if (access(filename, F_OK) == -1) {
        fprintf(stderr, "错误: 文件 '%s' 不存在\n", filename);
        return 1;
    }
    
    if (verbose) {
        printf("操作模式: %s\n", 
               use_lremovexattr ? "lremovexattr (不跟随符号链接)" : "removexattr (跟随符号链接)");
        printf("详细模式: %s\n", verbose ? "开启" : "关闭");
        printf("\n");
    }
    
    if (list_all) {
        // 列出所有扩展属性
        printf("文件 '%s' 的扩展属性:\n", filename);
        list_all_xattrs(filename, use_lremovexattr);
    } else if (optind + 1 < argc) {
        // 删除指定属性
        const char *attr_name = argv[optind + 1];
        
        printf("文件: %s\n", filename);
        printf("属性: %s\n", attr_name);
        printf("模式: %s\n", use_lremovexattr ? "lremovexattr" : "removexattr");
        
        // 显示删除前的属性值
        if (verbose) {
            printf("删除前: ");
            if (show_single_xattr(filename, attr_name, use_lremovexattr) == -1) {
                printf("属性不存在 (%s)\n", strerror(errno));
            }
        }
        
        // 删除属性
        if (remove_xattr(filename, attr_name, use_lremovexattr) == 0) {
            printf("✓ 成功删除属性\n");
        } else {
            if (errno == ENODATA) {
                printf("✓ 属性不存在(无需删除)\n");
            } else {
                printf("✗ 删除失败: %s\n", strerror(errno));
                return 1;
            }
        }
        
        // 显示删除后的状态
        if (verbose) {
            printf("删除后: ");
            if (show_single_xattr(filename, attr_name, use_lremovexattr) == -1) {
                printf("属性不存在 (%s)\n", strerror(errno));
            }
        }
    } else {
        // 默认行为:列出所有扩展属性
        printf("文件 '%s' 的扩展属性:\n", filename);
        list_all_xattrs(filename, use_lremovexattr);
    }
    
    // 显示文件系统支持信息
    printf("\n=== 系统信息 ===\n");
    struct statfs fs_info;
    if (statfs(filename, &fs_info) == 0) {
        printf("文件系统类型: 0x%lx\n", (unsigned long)fs_info.f_type);
        // 简单检查是否支持扩展属性
        if (fs_info.f_type == 0xEF53 ||  // ext2/3/4
            fs_info.f_type == 0x58465342 || // XFS
            fs_info.f_type == 0x65735546) { // FUSE
            printf("扩展属性支持: 可能支持\n");
        }
    }
    
    printf("\n=== 使用说明 ===\n");
    printf("符号链接处理:\n");
    printf("  lremovexattr: 只删除符号链接本身的扩展属性\n");
    printf("  removexattr:  删除符号链接指向文件的扩展属性\n");
    printf("\n权限要求:\n");
    printf("  user.* 属性: 需要文件写权限\n");
    printf("  其他命名空间: 可能需要特权权限\n");
    
    return 0;
}

编译和运行说明 链接到标题

# 编译示例程序
gcc -o lremovexattr_example1 example1.c
gcc -o lremovexattr_example2 example2.c
gcc -o lremovexattr_example3 example3.c

# 运行示例
./lremovexattr_example1
./lremovexattr_example2
./lremovexattr_example3 --help
./lremovexattr_example3 -a test_file.txt
./lremovexattr_example3 test_file.txt user.description

命令行工具配合使用 链接到标题

# 使用 setfattr/removexattr 命令行工具
setfattr -n user.description -v "test" file    # 设置属性
setfattr -x user.description file              # 删除属性
getfattr file                                  # 列出所有属性

# 删除符号链接的属性
setfattr -n user.note -v "link note" symlink   # 为链接设置属性
setfattr -x user.note symlink                  # 删除链接属性
setfattr -h -x user.note symlink               # 明确指定删除链接本身属性

# 查看属性
getfattr -n user.description file              # 获取指定属性
getfattr --absolute file                       # 使用绝对路径
getfattr --match=user file                     # 匹配特定命名空间

系统要求检查 链接到标题

# 检查文件系统是否支持扩展属性
mount | grep -E "(ext[234]|xfs|btrfs)"

# 检查内核支持
grep -i xattr /boot/config-$(uname -r)

# 检查挂载选项
mount | grep user_xattr

重要注意事项 链接到标题

  1. 文件系统支持: 不是所有文件系统都支持扩展属性
  2. 权限要求: user.* 属性需要文件写权限
  3. 符号链接: lremovexattr 不跟随符号链接
  4. 错误处理: 始终检查返回值和 errno
  5. 幂等性: 删除不存在的属性通常返回 ENODATA

实际应用场景 链接到标题

  1. 清理操作: 删除不再需要的自定义属性
  2. 安全清理: 移除敏感的元数据信息
  3. 备份恢复: 清理临时的备份标记
  4. 配置管理: 移除过时的配置属性
  5. 系统维护: 清理系统生成的临时属性

与相关函数的区别 链接到标题

// removexattr - 跟随符号链接
removexattr("symlink", "user.attr");    // 删除目标文件属性

// lremovexattr - 不跟随符号链接
lremovexattr("symlink", "user.attr");   // 删除符号链接属性

// fremovexattr - 通过文件描述符
int fd = open("file", O_WRONLY);
fremovexattr(fd, "user.attr");          // 删除已打开文件属性

最佳实践 链接到标题

// 安全地删除扩展属性
int safe_lremovexattr(const char *path, const char *name) {
    // 检查文件存在性
    if (access(path, F_OK) == -1) {
        return -1;
    }
    
    // 尝试删除属性
    int result = lremovexattr(path, name);
    
    // 处理常见情况
    if (result == -1) {
        if (errno == ENODATA) {
            // 属性不存在,视为成功
            return 0;
        }
        // 其他错误返回 -1
    }
    
    return result;
}

// 批量删除扩展属性
int batch_lremovexattr(const char *path, const char **attr_names, int count) {
    int success = 0;
    int failed = 0;
    
    for (int i = 0; i < count; i++) {
        if (lremovexattr(path, attr_names[i]) == 0) {
            success++;
        } else {
            if (errno != ENODATA) {  // 忽略不存在的属性
                failed++;
                fprintf(stderr, "删除 %s 失败: %s\n", attr_names[i], strerror(errno));
            } else {
                success++;  // 不存在也算成功
            }
        }
    }
    
    printf("批量删除完成: 成功 %d, 失败 %d\n", success, failed);
    return failed;
}

// 删除所有用户属性
int remove_all_user_xattrs(const char *path) {
    char *buffer;
    ssize_t list_size;
    
    // 获取属性列表
    list_size = llistxattr(path, NULL, 0);
    if (list_size <= 0) {
        return 0;  // 没有属性或出错
    }
    
    buffer = malloc(list_size);
    if (!buffer) return -1;
    
    list_size = llistxattr(path, buffer, list_size);
    if (list_size <= 0) {
        free(buffer);
        return -1;
    }
    
    // 删除所有 user.* 属性
    int removed = 0;
    for (char *p = buffer; p < buffer + list_size; p += strlen(p) + 1) {
        if (strncmp(p, "user.", 5) == 0) {
            if (lremovexattr(path, p) == 0) {
                removed++;
            }
        }
    }
    
    free(buffer);
    printf("删除了 %d 个用户属性\n", removed);
    return 0;
}

这些示例展示了 lremovexattr 函数的各种使用方法,从基础的属性删除到完整的扩展属性管理工具,帮助你全面掌握 Linux 系统中的扩展属性删除机制。