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