src/server/util/libxattr.c

changeset 480
9f69e4b8b695
equal deleted inserted replaced
479:2a42ba73ecdd 480:9f69e4b8b695
1 /*
2 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
3 *
4 * Copyright 2018 Olaf Wintermann. All rights reserved.
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions are met:
8 *
9 * 1. Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 *
12 * 2. Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
17 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
20 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
21 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
22 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
23 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
24 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
25 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
26 * POSSIBILITY OF SUCH DAMAGE.
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; /* TODO: missing error handling for realloc() */ \
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 //printf("%.*s\n", nslen, begin);
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 // buffer too, get size of attribute list
102 ssize_t newlen = listxattr(path, NULL, 0);
103 if(newlen > 0) {
104 // second try
105 list = realloc(list, newlen);
106 len = listxattr(path, list, newlen);
107 if(len != -1) {
108 // this time it worked
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 // add the 'user' namespace to the name
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 /* Linux */
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 // buffer too, get size of attribute list
243 ssize_t newlen = listxattr(path, NULL, 0, 0);
244 if(newlen > 0) {
245 // second try
246 list = realloc(list, newlen);
247 len = listxattr(path, list, newlen, 0);
248 if(len != -1) {
249 // this time it worked
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 // get attribute length
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 /* Apple */
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 /* Sun */
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 // get attribute length
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 /* FreeBSD */
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 /* unsupported platform */
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 }

mercurial