#define _GNU_SOURCE
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <dirent.h>
#include <unistd.h>
#include <fcntl.h>
#include <time.h>
#include <sys/xattr.h>
typedef struct FileList FileList;
struct FileList {
char *name;
char *path;
FileList *next;
};
static char * props[] = {
"user.test1", "user.test2", "user.test3", "user.test4",
"user.test5", "user.test6", "user.test7", "user.test8",
"user.test9", "user.test10", "user.test11", "user.test12",
"user.test13", "user.test14", "user.test15", "user.test16",
"user.test17", "user.test18", "user.test19", "user.test20",
"user.test21", "user.test22", "user.test23", "user.test24",
"user.test25", "user.test26", "user.test27", "user.test28",
"user.test29", "user.test30", "user.test31", "user.test32",
};
#ifndef NUM_XATTR
#define NUM_XATTR 16
#endif
#ifdef USE_FD
int get_attr(int dirfd, FileList *elm) {
int fd = openat(dirfd, elm->name, O_RDONLY);
if(fd == -1) {
perror("openat");
return -1;
}
int num = NUM_XATTR > 4 ? 4 : NUM_XATTR;
int ret = 0;
char buf[128];
for(int i=0;i<num;i++) {
ssize_t s = fgetxattr(fd, props[i], buf, 128);
if(s <= 0) {
ret = -1;
}
}
close(fd);
return 0;
}
#else
int get_attr(int dirfd, FileList *elm) {
int num = NUM_XATTR > 4 ? 4 : NUM_XATTR;
int ret = 0;
char buf[128];
for(int i=0;i<num;i++) {
ssize_t s = getxattr(elm->path, props[i], buf, 128);
if(s <= 0) {
ret = -1;
}
}
return ret;
}
#endif
int main(int argc, char **argv) {
if(argc < 2) {
fprintf(stderr, "Usage: %s <dir>\n", argv[0]);
return EXIT_FAILURE;
}
printf("test %d xattr\n", NUM_XATTR);
#ifdef USE_FD
printf("use fgetattr\n");
#else
printf("use getattr\n");
#endif
char *path = argv[1];
size_t pathlen = strlen(path);
DIR *dir = opendir(path);
int fd = dirfd(dir);
if(!dir) {
fprintf(stderr, "Cannot open directory: %s\n", path);
return EXIT_FAILURE;
}
FileList *files = NULL;
FileList *last = NULL;
size_t count = 0;
struct dirent *entry;
while((entry = readdir(dir)) != NULL) {
if(!strcmp(entry->d_name, ".") || !strcmp(entry->d_name, "..")) {
continue;
}
FileList *file = calloc(1, sizeof(FileList));
file->name = strdup(entry->d_name);
if(path[pathlen - 1] == '/') {
asprintf(&file->path, "%s%s", path, entry->d_name);
} else {
asprintf(&file->path, "%s/%s", path, entry->d_name);
}
if(!files) {
files = file;
} else {
last->next = file;
}
last = file;
count++;
}
if(files) {
printf("test %zu files:\n\nbegin\n", count);
struct timespec begin;
clock_gettime(CLOCK_REALTIME, &begin);
FileList *elm = files;
while(elm) {
if(get_attr(fd, elm)) {
fprintf(stderr, "Error.\nAbort.\n");
break;
}
elm = elm->next;
}
struct timespec end;
clock_gettime(CLOCK_REALTIME, &end);
printf("time: %ld ns\n\n", end.tv_nsec - begin.tv_nsec);
} else {
fprintf(stderr, "No files in %s\n", path);
}
FileList *elm = files;
while(elm) {
free(elm->name);
free(elm->path);
FileList *next = elm->next;
free(elm);
elm = next;
}
closedir(dir);
return EXIT_SUCCESS;
}