UNIXworkcode

/* * DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE * Version 2, December 2004 * * Copyright (C) 2016 Olaf Wintermann <olaf.wintermann@gmail.com> * * Everyone is permitted to copy and distribute verbatim or modified * copies of this license document, and changing it is allowed as long * as the name is changed. * * DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE * TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION * * 0. You just DO WHAT THE FUCK YOU WANT TO. */ /* create a test directory with this script: #!/bin/sh echo create $1 files for i in `seq 1 $1`; do file=file$i echo create $file echo "hello" > $file for j in `seq 1 32`; do setfattr -n user.test$j -v content$j $file done done */ #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); } // cleanup FileList *elm = files; while(elm) { free(elm->name); free(elm->path); FileList *next = elm->next; free(elm); elm = next; } closedir(dir); return EXIT_SUCCESS; }