UNIXworkcode

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 } 577