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