1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16 #define _GNU_SOURCE
17
18 #include <stdio.h>
19 #include <stdlib.h>
20
21 #include "libxattr.h"
22
23 #include <errno.h>
24 #include <sys/types.h>
25
26 #include <string.h>
27
28 #define LIST_BUF_LEN 1024
29 #define LIST_ARRAY_LEN 8
30 #define ATTR_BUF_LEN 1024
31
32
33 static int strarray_add(
char ***array_ptr,
size_t *pos,
size_t *len,
char *str) {
34 char **array = *array_ptr;
35 size_t array_pos = *pos;
36 size_t array_len = *len;
37 if(array_pos >= array_len) {
38 size_t newlen = array_len *
2;
39 char **new_array = realloc(array, newlen *
sizeof(
char*));
40 if(!new_array) {
41 return 1;
42 }
43 *len = array_len;
44 array = new_array;
45 *array_ptr = new_array;
46 }
47
48 array[array_pos] = str;
49 *pos = array_pos +
1;
50
51 return 0;
52 }
53
54 static void strarray_free(
char **array,
size_t nelm) {
55 for(
size_t i=
0;i<nelm;i++) {
56 free(array[i]);
57 }
58 free(array);
59 }
60
61 #ifdef __linux__
62 #define XATTR_SUPPORTED
63 #include <sys/xattr.h>
64
65 static char ** parse_xattrlist(
char *buf,
ssize_t length,
ssize_t *nelm) {
66 size_t arraylen =
LIST_ARRAY_LEN;
67 size_t arraypos =
0;
68 char **array = malloc(
LIST_ARRAY_LEN *
sizeof(
char*));
69 if(!array) {
70 *nelm = -
1;
71 return NULL;
72 }
73
74 char *name =
NULL;
75 for(
int i=
0;i<length;i++) {
76 if(!name && buf[i] ==
'.') {
77 name = buf + i +
1;
78 }
79 if(buf[i] ==
'\0') {
80 char *attrname = strdup(name);
81 if(!attrname) {
82 strarray_free(array, arraypos);
83 *nelm = -
1;
84 return NULL;
85 }
86 if(strarray_add(&array, &arraypos, &arraylen, attrname)) {
87 strarray_free(array, arraypos);
88 *nelm = -
1;
89 return NULL;
90 }
91 name =
NULL;
92 }
93 }
94
95 if(arraypos ==
0) {
96 free(array);
97 array =
NULL;
98 }
99
100 *nelm = arraypos;
101 return array;
102 }
103
104 char ** xattr_list(
const char *path,
ssize_t *nelm) {
105 char *list = malloc(
LIST_BUF_LEN);
106 if(!list) {
107 *nelm = -
1;
108 return NULL;
109 }
110 ssize_t len = listxattr(path, list,
LIST_BUF_LEN);
111 if(len == -
1) {
112 switch(errno) {
113 case ERANGE: {
114
115 ssize_t newlen = listxattr(path,
NULL,
0);
116 if(newlen >
0) {
117
118 char *new_list = realloc(list, newlen);
119 if(!new_list) {
120 free(list);
121 *nelm = -
1;
122 return NULL;
123 }
124 list = new_list;
125 len = listxattr(path, list, newlen);
126 if(len != -
1) {
127
128 break;
129 }
130 }
131 }
132 default: {
133 free(list);
134 *nelm = -
1;
135 return NULL;
136 }
137 }
138 }
139
140 char **ret = parse_xattrlist(list, len, nelm);
141 free(list);
142 return ret;
143 }
144
145 static char* name2nsname(
const char *name) {
146
147 size_t namelen = strlen(name);
148 char *attrname = malloc(
8 + namelen);
149 if(!attrname) {
150 return NULL;
151 }
152 memcpy(attrname,
"user.",
5);
153 memcpy(attrname+
5, name, namelen +
1);
154 return attrname;
155 }
156
157 char * xattr_get(
const char *path,
const char *attr,
ssize_t *len) {
158 char *attrname = name2nsname(attr);
159 if(!attrname) {
160 *len = -
1;
161 return NULL;
162 }
163
164 char *buf = malloc(
ATTR_BUF_LEN);
165 if(!buf) {
166 *len = -
1;
167 free(attrname);
168 return NULL;
169 }
170 ssize_t vlen = getxattr(path, attrname, buf,
ATTR_BUF_LEN -
1);
171 if(vlen <
0) {
172 switch(errno) {
173 case ERANGE: {
174 ssize_t attrlen = getxattr(path, attrname,
NULL,
0);
175 if(attrlen >
0) {
176 free(buf);
177 buf = malloc(attrlen +
1);
178 if(!buf) {
179 *len = -
1;
180 free(attrname);
181 return NULL;
182 }
183 vlen = getxattr(path, attrname, buf, attrlen);
184 if(vlen >
0) {
185 break;
186 }
187 }
188 }
189 default: {
190 *len = -
1;
191 free(buf);
192 free(attrname);
193 return NULL;
194 }
195 }
196 }
197 buf[vlen] =
0;
198
199 free(attrname);
200 *len = vlen;
201 return buf;
202 }
203
204 int xattr_set(
const char *path,
const char *name,
const void *value,
size_t len) {
205 char *attrname = name2nsname(name);
206 if(!attrname) {
207 return 1;
208 }
209 int ret = setxattr(path, attrname, value, len,
0);
210 free(attrname);
211 return ret;
212 }
213
214 int xattr_remove(
const char *path,
const char *name) {
215 char *attrname = name2nsname(name);
216 if(!attrname) {
217 return 1;
218 }
219 int ret = removexattr(path, attrname);
220 free(attrname);
221 return ret;
222 }
223
224 #endif
225
226 #ifdef __APPLE__
227 #define XATTR_SUPPORTED
228 #include <sys/xattr.h>
229
230 static char ** parse_xattrlist(
char *buf,
ssize_t length,
ssize_t *nelm) {
231 size_t arraylen =
LIST_ARRAY_LEN;
232 size_t arraypos =
0;
233 char **array = malloc(
LIST_ARRAY_LEN *
sizeof(
char*));
234
235 char *name = buf;
236 for(
int i=
0;i<length;i++) {
237 if(buf[i] ==
'\0') {
238 char *attrname = strdup(name);
239 if(strarray_add(&array, &arraypos, &arraylen, attrname)) {
240 strarray_free(array, arraypos);
241 *nelm = -
1;
242 return NULL;
243 }
244 name = buf + i +
1;
245 }
246 }
247
248 if(arraypos ==
0) {
249 free(array);
250 array =
NULL;
251 }
252
253 *nelm = arraypos;
254 return array;
255 }
256
257 char ** xattr_list(
const char *path,
ssize_t *nelm) {
258 char *list = malloc(
LIST_BUF_LEN);
259 if(!list) {
260 *nelm = -
1;
261 return NULL;
262 }
263 ssize_t len = listxattr(path, list,
LIST_BUF_LEN,
0);
264 if(len == -
1) {
265 switch(errno) {
266 case ERANGE: {
267
268 ssize_t newlen = listxattr(path,
NULL,
0,
0);
269 if(newlen >
0) {
270
271 char *new_list = realloc(list, newlen);
272 if(!new_list) {
273 free(list);
274 *nelm = -
1;
275 return NULL;
276 }
277 list = new_list;
278 len = listxattr(path, list, newlen,
0);
279 if(len != -
1) {
280
281 break;
282 }
283 }
284 }
285 default: {
286 free(list);
287 *nelm = -
1;
288 return NULL;
289 }
290 }
291 }
292
293 char **ret = parse_xattrlist(list, len, nelm);
294 free(list);
295 return ret;
296 }
297
298 char * xattr_get(
const char *path,
const char *attr,
ssize_t *len) {
299
300 ssize_t attrlen = getxattr(path, attr,
NULL,
0,
0,
0);
301 if(attrlen <
0) {
302 *len = -
1;
303 return NULL;
304 }
305
306 char *buf = malloc(attrlen +
1);
307 if(!buf) {
308 *len = -
1;
309 return NULL;
310 }
311 ssize_t vlen = getxattr(path, attr, buf, attrlen,
0,
0);
312 if(vlen <
0) {
313 *len = -
1;
314 free(buf);
315 return NULL;
316 }
317 buf[vlen] =
0;
318
319 *len = vlen;
320 return buf;
321 }
322
323 int xattr_set(
const char *path,
const char *name,
const void *value,
size_t len) {
324 int ret = setxattr(path, name, value, len,
0,
0);
325 return ret;
326 }
327
328 int xattr_remove(
const char *path,
const char *name) {
329 return removexattr(path, name,
0);
330 }
331
332 #endif
333
334 #ifdef __sun
335 #define XATTR_SUPPORTED
336 #include <unistd.h>
337 #include <sys/types.h>
338 #include <sys/stat.h>
339 #include <dirent.h>
340 #include <fcntl.h>
341
342 static int open_attrfile(
const char *path,
const char *attr,
int oflag) {
343 int file = open(path,
O_RDONLY);
344 if(file == -
1) {
345 return -
1;
346 }
347
348 int attrfile = openat(file, attr, oflag,
S_IRUSR|
S_IWUSR|
S_IRGRP|
S_IROTH);
349 close(file);
350 return attrfile;
351 }
352
353 char ** xattr_list(
const char *path,
ssize_t *nelm) {
354 *nelm = -
1;
355
356 int attrdir = open_attrfile(path,
".",
O_RDONLY|
O_XATTR);
357 if(attrdir == -
1) {
358 return NULL;
359 }
360
361 DIR *dir = fdopendir(attrdir);
362 if(!dir) {
363 close(attrdir);
364 return NULL;
365 }
366
367 size_t arraylen =
LIST_ARRAY_LEN;
368 size_t arraypos =
0;
369 char **array = malloc(
LIST_ARRAY_LEN *
sizeof(
char*));
370 if(!array) {
371 closedir(dir);
372 *nelm = -
1;
373 return NULL;
374 }
375
376 struct dirent *ent;
377 while((ent = readdir(dir)) !=
NULL) {
378 if(!strcmp(ent->d_name,
".") || !strcmp(ent->d_name,
"..") || !strcmp(ent->d_name,
"SUNWattr_ro") || !strcmp(ent->d_name,
"SUNWattr_rw")) {
379 continue;
380 }
381 char *name = strdup(ent->d_name);
382 if(strarray_add(&array, &arraypos, &arraylen, name)) {
383 strarray_free(array, arraypos);
384 *nelm = -
1;
385 closedir(dir);
386 return NULL;
387 }
388 }
389 closedir(dir);
390
391 *nelm = arraypos;
392 return array;
393 }
394
395 char * xattr_get(
const char *path,
const char *attr,
ssize_t *len) {
396 *len = -
1;
397
398 int attrfile = open_attrfile(path, attr,
O_RDONLY|
O_XATTR);
399 if(attrfile == -
1) {
400 return NULL;
401 }
402
403 struct stat s;
404 if(fstat(attrfile, &s)) {
405 close(attrfile);
406 return NULL;
407 }
408
409 size_t bufsize = (
size_t)s.st_size;
410 char *buf = malloc(bufsize +
1);
411 if(!buf) {
412 close(attrfile);
413 return NULL;
414 }
415
416 char *b = buf;
417 size_t cur =
0;
418 while(cur < bufsize) {
419 ssize_t r = read(attrfile, buf + cur, bufsize - cur);
420 if(r <=
0) {
421 break;
422 }
423 cur += r;
424 }
425
426 close(attrfile);
427 if(cur != bufsize) {
428 free(buf);
429 return NULL;
430 }
431
432 buf[cur] =
0;
433 *len = (
ssize_t)bufsize;
434 return buf;
435 }
436
437 int xattr_set(
const char *path,
const char *name,
const void *value,
size_t len) {
438 int attrfile = open_attrfile(path, name,
O_CREAT|
O_WRONLY|
O_XATTR|
O_TRUNC);
439 if(attrfile == -
1) {
440 return -
1;
441 }
442
443 const char *p = value;
444 size_t remaining = len;
445 while(remaining >
0) {
446 ssize_t w = write(attrfile, p, remaining);
447 if(w <=
0) {
448 break;
449 }
450 p += w;
451 remaining -= w;
452 }
453
454 close(attrfile);
455
456 return remaining >
0 ? -
1 :
0;
457 }
458
459 int xattr_remove(
const char *path,
const char *name) {
460 int attrdir = open_attrfile(path,
".",
O_RDONLY|
O_XATTR);
461 if(attrdir == -
1) {
462 return -
1;
463 }
464
465 int ret = unlinkat(attrdir, name,
0);
466 close(attrdir);
467 return ret;
468 }
469
470 #endif
471
472
473 #ifdef __FreeBSD__
474 #define XATTR_SUPPORTED
475
476 #include <sys/types.h>
477 #include <sys/extattr.h>
478
479 static char ** parse_xattrlist(
char *buf,
ssize_t length,
ssize_t *nelm) {
480 size_t arraylen =
LIST_ARRAY_LEN;
481 size_t arraypos =
0;
482 char **array = malloc(
LIST_ARRAY_LEN *
sizeof(
char*));
483 if(!array) {
484 *nelm = -
1;
485 return NULL;
486 }
487
488 for(
int i=
0;i<length;i++) {
489 int namelen = buf[i];
490 char *name = buf + i +
1;
491 char *attrname = malloc(namelen +
1);
492 if(!attrname) {
493 strarray_free(array, arraypos);
494 *nelm = -
1;
495 return NULL;
496 }
497 memcpy(attrname, name, namelen);
498 attrname[namelen] =
0;
499 if(strarray_add(&array, &arraypos, &arraylen, attrname)) {
500 strarray_free(array, arraypos);
501 *nelm = -
1;
502 return NULL;
503 }
504 i += namelen;
505 }
506
507 if(arraypos ==
0) {
508 free(array);
509 array =
NULL;
510 }
511
512 *nelm = arraypos;
513 return array;
514 }
515
516 char ** xattr_list(
const char *path,
ssize_t *nelm) {
517 *nelm = -
1;
518 ssize_t lslen = extattr_list_file(path,
EXTATTR_NAMESPACE_USER,
NULL,
0);
519 if(lslen <=
0) {
520 if(lslen ==
0) {
521 *nelm =
0;
522 }
523 return NULL;
524 }
525
526 char *list = malloc(lslen);
527 if(!list) {
528 return NULL;
529 }
530 ssize_t len = extattr_list_file(path,
EXTATTR_NAMESPACE_USER, list, lslen);
531 if(len == -
1) {
532 free(list);
533 return NULL;
534 }
535
536 char **ret = parse_xattrlist(list, len, nelm);
537 free(list);
538 return ret;
539 }
540
541 char * xattr_get(
const char *path,
const char *attr,
ssize_t *len) {
542
543 ssize_t attrlen = extattr_get_file(path,
EXTATTR_NAMESPACE_USER, attr,
NULL,
0);
544 if(attrlen <
0) {
545 *len = -
1;
546 return NULL;
547 }
548
549 char *buf = malloc(attrlen +
1);
550 ssize_t vlen = extattr_get_file(path,
EXTATTR_NAMESPACE_USER, attr, buf, attrlen);
551 if(vlen <
0) {
552 *len = -
1;
553 free(buf);
554 return NULL;
555 }
556 buf[attrlen] =
0;
557 *len = vlen;
558 return buf;
559 }
560
561 int xattr_set(
const char *path,
const char *name,
const void *value,
size_t len) {
562 int ret = extattr_set_file(path,
EXTATTR_NAMESPACE_USER, name, value, len);
563 return ret >=
0 ?
0 : ret;
564 }
565
566 int xattr_remove(
const char *path,
const char *name) {
567 return extattr_delete_file(path,
EXTATTR_NAMESPACE_USER, name);
568 }
569
570 #endif
571
572
573 #ifndef XATTR_SUPPORTED
574
575 char ** xattr_list(
const char *path,
ssize_t *nelm) {
576 *nelm = -
1;
577 return NULL;
578 }
579
580 char * xattr_get(
const char *path,
const char *attr,
ssize_t *len) {
581 *len = -
1;
582 return NULL;
583 }
584
585 int xattr_set(
const char *path,
const char *name,
const void *value,
size_t len) {
586 return -
1;
587 }
588
589 int xattr_remove(
const char *path,
const char *name) {
590 return -
1;
591 }
592
593 #endif
594
595 void xattr_free_list(
char **attrnames,
ssize_t nelm) {
596 if(attrnames) {
597 for(
int i=
0;i<nelm;i++) {
598 free(attrnames[i]);
599 }
600 free(attrnames);
601 }
602 }
603