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