1228753Smm/*- 2228753Smm * Copyright (c) 2003-2009 Tim Kientzle 3228753Smm * All rights reserved. 4228753Smm * 5228753Smm * Redistribution and use in source and binary forms, with or without 6228753Smm * modification, are permitted provided that the following conditions 7228753Smm * are met: 8228753Smm * 1. Redistributions of source code must retain the above copyright 9228753Smm * notice, this list of conditions and the following disclaimer. 10228753Smm * 2. Redistributions in binary form must reproduce the above copyright 11228753Smm * notice, this list of conditions and the following disclaimer in the 12228753Smm * documentation and/or other materials provided with the distribution. 13228753Smm * 14228753Smm * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR 15228753Smm * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 16228753Smm * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 17228753Smm * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT, 18228753Smm * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 19228753Smm * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 20228753Smm * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 21228753Smm * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 22228753Smm * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 23228753Smm * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 24228753Smm */ 25228753Smm 26228753Smm#include "archive_platform.h" 27229592Smm__FBSDID("$FreeBSD$"); 28228753Smm 29228753Smm#ifdef HAVE_SYS_TYPES_H 30228753Smm/* Mac OSX requires sys/types.h before sys/acl.h. */ 31228753Smm#include <sys/types.h> 32228753Smm#endif 33228753Smm#ifdef HAVE_SYS_ACL_H 34228753Smm#include <sys/acl.h> 35228753Smm#endif 36228753Smm#ifdef HAVE_SYS_EXTATTR_H 37228753Smm#include <sys/extattr.h> 38228753Smm#endif 39228753Smm#ifdef HAVE_SYS_PARAM_H 40228753Smm#include <sys/param.h> 41228753Smm#endif 42228753Smm#ifdef HAVE_SYS_STAT_H 43228753Smm#include <sys/stat.h> 44228753Smm#endif 45228753Smm#ifdef HAVE_SYS_XATTR_H 46228753Smm#include <sys/xattr.h> 47228753Smm#endif 48228753Smm#ifdef HAVE_ACL_LIBACL_H 49228753Smm#include <acl/libacl.h> 50228753Smm#endif 51228753Smm#ifdef HAVE_ATTR_XATTR_H 52228753Smm#include <attr/xattr.h> 53228753Smm#endif 54228753Smm#ifdef HAVE_ERRNO_H 55228753Smm#include <errno.h> 56228753Smm#endif 57228753Smm#ifdef HAVE_LIMITS_H 58228753Smm#include <limits.h> 59228753Smm#endif 60228753Smm#ifdef HAVE_WINDOWS_H 61228753Smm#include <windows.h> 62228753Smm#endif 63228753Smm 64228753Smm#include "archive.h" 65228753Smm#include "archive_entry.h" 66228753Smm#include "archive_private.h" 67228753Smm#include "archive_read_disk_private.h" 68228753Smm 69228753Smm/* 70228753Smm * Linux and FreeBSD plug this obvious hole in POSIX.1e in 71228753Smm * different ways. 72228753Smm */ 73228753Smm#if HAVE_ACL_GET_PERM 74228753Smm#define ACL_GET_PERM acl_get_perm 75228753Smm#elif HAVE_ACL_GET_PERM_NP 76228753Smm#define ACL_GET_PERM acl_get_perm_np 77228753Smm#endif 78228753Smm 79228753Smmstatic int setup_acls_posix1e(struct archive_read_disk *, 80228753Smm struct archive_entry *, int fd); 81228753Smmstatic int setup_xattrs(struct archive_read_disk *, 82228753Smm struct archive_entry *, int fd); 83228753Smm 84228753Smmint 85228753Smmarchive_read_disk_entry_from_file(struct archive *_a, 86228753Smm struct archive_entry *entry, 87228753Smm int fd, const struct stat *st) 88228753Smm{ 89228753Smm struct archive_read_disk *a = (struct archive_read_disk *)_a; 90228753Smm const char *path, *name; 91228753Smm struct stat s; 92228753Smm int initial_fd = fd; 93228753Smm int r, r1; 94228753Smm 95228753Smm archive_clear_error(_a); 96228753Smm path = archive_entry_sourcepath(entry); 97228753Smm if (path == NULL) 98228753Smm path = archive_entry_pathname(entry); 99228753Smm 100228753Smm#ifdef EXT2_IOC_GETFLAGS 101228753Smm /* Linux requires an extra ioctl to pull the flags. Although 102228753Smm * this is an extra step, it has a nice side-effect: We get an 103228753Smm * open file descriptor which we can use in the subsequent lookups. */ 104228753Smm if ((S_ISREG(st->st_mode) || S_ISDIR(st->st_mode))) { 105228753Smm if (fd < 0) 106228753Smm fd = open(pathname, O_RDONLY | O_NONBLOCK | O_BINARY); 107228753Smm if (fd >= 0) { 108228753Smm unsigned long stflags; 109228753Smm int r = ioctl(fd, EXT2_IOC_GETFLAGS, &stflags); 110228753Smm if (r == 0 && stflags != 0) 111228753Smm archive_entry_set_fflags(entry, stflags, 0); 112228753Smm } 113228753Smm } 114228753Smm#endif 115228753Smm 116228753Smm if (st == NULL) { 117228753Smm /* TODO: On Windows, use GetFileInfoByHandle() here. 118228753Smm * Using Windows stat() call is badly broken, but 119228753Smm * even the stat() wrapper has problems because 120228753Smm * 'struct stat' is broken on Windows. 121228753Smm */ 122228753Smm#if HAVE_FSTAT 123228753Smm if (fd >= 0) { 124228753Smm if (fstat(fd, &s) != 0) { 125228753Smm archive_set_error(&a->archive, errno, 126228753Smm "Can't fstat"); 127228753Smm return (ARCHIVE_FAILED); 128228753Smm } 129228753Smm } else 130228753Smm#endif 131228753Smm#if HAVE_LSTAT 132228753Smm if (!a->follow_symlinks) { 133228753Smm if (lstat(path, &s) != 0) { 134228753Smm archive_set_error(&a->archive, errno, 135228753Smm "Can't lstat %s", path); 136228753Smm return (ARCHIVE_FAILED); 137228753Smm } 138228753Smm } else 139228753Smm#endif 140228753Smm if (stat(path, &s) != 0) { 141228753Smm archive_set_error(&a->archive, errno, 142228753Smm "Can't lstat %s", path); 143228753Smm return (ARCHIVE_FAILED); 144228753Smm } 145228753Smm st = &s; 146228753Smm } 147228753Smm archive_entry_copy_stat(entry, st); 148228753Smm 149228753Smm /* Lookup uname/gname */ 150228753Smm name = archive_read_disk_uname(_a, archive_entry_uid(entry)); 151228753Smm if (name != NULL) 152228753Smm archive_entry_copy_uname(entry, name); 153228753Smm name = archive_read_disk_gname(_a, archive_entry_gid(entry)); 154228753Smm if (name != NULL) 155228753Smm archive_entry_copy_gname(entry, name); 156228753Smm 157228753Smm#ifdef HAVE_STRUCT_STAT_ST_FLAGS 158228753Smm /* On FreeBSD, we get flags for free with the stat. */ 159228753Smm /* TODO: Does this belong in copy_stat()? */ 160228753Smm if (st->st_flags != 0) 161228753Smm archive_entry_set_fflags(entry, st->st_flags, 0); 162228753Smm#endif 163228753Smm 164228753Smm#ifdef HAVE_READLINK 165228753Smm if (S_ISLNK(st->st_mode)) { 166228753Smm char linkbuffer[PATH_MAX + 1]; 167228753Smm int lnklen = readlink(path, linkbuffer, PATH_MAX); 168228753Smm if (lnklen < 0) { 169228753Smm archive_set_error(&a->archive, errno, 170228753Smm "Couldn't read link data"); 171228753Smm return (ARCHIVE_FAILED); 172228753Smm } 173228753Smm linkbuffer[lnklen] = 0; 174228753Smm archive_entry_set_symlink(entry, linkbuffer); 175228753Smm } 176228753Smm#endif 177228753Smm 178228753Smm r = setup_acls_posix1e(a, entry, fd); 179228753Smm r1 = setup_xattrs(a, entry, fd); 180228753Smm if (r1 < r) 181228753Smm r = r1; 182228753Smm /* If we opened the file earlier in this function, close it. */ 183228753Smm if (initial_fd != fd) 184228753Smm close(fd); 185228753Smm return (r); 186228753Smm} 187228753Smm 188228753Smm#ifdef HAVE_POSIX_ACL 189228753Smmstatic void setup_acl_posix1e(struct archive_read_disk *a, 190228753Smm struct archive_entry *entry, acl_t acl, int archive_entry_acl_type); 191228753Smm 192228753Smmstatic int 193228753Smmsetup_acls_posix1e(struct archive_read_disk *a, 194228753Smm struct archive_entry *entry, int fd) 195228753Smm{ 196228753Smm const char *accpath; 197228753Smm acl_t acl; 198228753Smm 199228753Smm accpath = archive_entry_sourcepath(entry); 200228753Smm if (accpath == NULL) 201228753Smm accpath = archive_entry_pathname(entry); 202228753Smm 203228753Smm archive_entry_acl_clear(entry); 204228753Smm 205228753Smm /* Retrieve access ACL from file. */ 206228753Smm if (fd >= 0) 207228753Smm acl = acl_get_fd(fd); 208228753Smm#if HAVE_ACL_GET_LINK_NP 209228753Smm else if (!a->follow_symlinks) 210228753Smm acl = acl_get_link_np(accpath, ACL_TYPE_ACCESS); 211228753Smm#else 212228753Smm else if ((!a->follow_symlinks) 213228753Smm && (archive_entry_filetype(entry) == AE_IFLNK)) 214228753Smm /* We can't get the ACL of a symlink, so we assume it can't 215228753Smm have one. */ 216228753Smm acl = NULL; 217228753Smm#endif 218228753Smm else 219228753Smm acl = acl_get_file(accpath, ACL_TYPE_ACCESS); 220228753Smm if (acl != NULL) { 221228753Smm setup_acl_posix1e(a, entry, acl, 222228753Smm ARCHIVE_ENTRY_ACL_TYPE_ACCESS); 223228753Smm acl_free(acl); 224228753Smm } 225228753Smm 226228753Smm /* Only directories can have default ACLs. */ 227228753Smm if (S_ISDIR(archive_entry_mode(entry))) { 228228753Smm acl = acl_get_file(accpath, ACL_TYPE_DEFAULT); 229228753Smm if (acl != NULL) { 230228753Smm setup_acl_posix1e(a, entry, acl, 231228753Smm ARCHIVE_ENTRY_ACL_TYPE_DEFAULT); 232228753Smm acl_free(acl); 233228753Smm } 234228753Smm } 235228753Smm return (ARCHIVE_OK); 236228753Smm} 237228753Smm 238228753Smm/* 239228753Smm * Translate POSIX.1e ACL into libarchive internal structure. 240228753Smm */ 241228753Smmstatic void 242228753Smmsetup_acl_posix1e(struct archive_read_disk *a, 243228753Smm struct archive_entry *entry, acl_t acl, int archive_entry_acl_type) 244228753Smm{ 245228753Smm acl_tag_t acl_tag; 246228753Smm acl_entry_t acl_entry; 247228753Smm acl_permset_t acl_permset; 248228753Smm int s, ae_id, ae_tag, ae_perm; 249228753Smm const char *ae_name; 250228753Smm 251228753Smm s = acl_get_entry(acl, ACL_FIRST_ENTRY, &acl_entry); 252228753Smm while (s == 1) { 253228753Smm ae_id = -1; 254228753Smm ae_name = NULL; 255228753Smm 256228753Smm acl_get_tag_type(acl_entry, &acl_tag); 257228753Smm if (acl_tag == ACL_USER) { 258228753Smm ae_id = (int)*(uid_t *)acl_get_qualifier(acl_entry); 259228753Smm ae_name = archive_read_disk_uname(&a->archive, ae_id); 260228753Smm ae_tag = ARCHIVE_ENTRY_ACL_USER; 261228753Smm } else if (acl_tag == ACL_GROUP) { 262228753Smm ae_id = (int)*(gid_t *)acl_get_qualifier(acl_entry); 263228753Smm ae_name = archive_read_disk_gname(&a->archive, ae_id); 264228753Smm ae_tag = ARCHIVE_ENTRY_ACL_GROUP; 265228753Smm } else if (acl_tag == ACL_MASK) { 266228753Smm ae_tag = ARCHIVE_ENTRY_ACL_MASK; 267228753Smm } else if (acl_tag == ACL_USER_OBJ) { 268228753Smm ae_tag = ARCHIVE_ENTRY_ACL_USER_OBJ; 269228753Smm } else if (acl_tag == ACL_GROUP_OBJ) { 270228753Smm ae_tag = ARCHIVE_ENTRY_ACL_GROUP_OBJ; 271228753Smm } else if (acl_tag == ACL_OTHER) { 272228753Smm ae_tag = ARCHIVE_ENTRY_ACL_OTHER; 273228753Smm } else { 274228753Smm /* Skip types that libarchive can't support. */ 275228753Smm continue; 276228753Smm } 277228753Smm 278228753Smm acl_get_permset(acl_entry, &acl_permset); 279228753Smm ae_perm = 0; 280228753Smm /* 281228753Smm * acl_get_perm() is spelled differently on different 282228753Smm * platforms; see above. 283228753Smm */ 284228753Smm if (ACL_GET_PERM(acl_permset, ACL_EXECUTE)) 285228753Smm ae_perm |= ARCHIVE_ENTRY_ACL_EXECUTE; 286228753Smm if (ACL_GET_PERM(acl_permset, ACL_READ)) 287228753Smm ae_perm |= ARCHIVE_ENTRY_ACL_READ; 288228753Smm if (ACL_GET_PERM(acl_permset, ACL_WRITE)) 289228753Smm ae_perm |= ARCHIVE_ENTRY_ACL_WRITE; 290228753Smm 291228753Smm archive_entry_acl_add_entry(entry, 292228753Smm archive_entry_acl_type, ae_perm, ae_tag, 293228753Smm ae_id, ae_name); 294228753Smm 295228753Smm s = acl_get_entry(acl, ACL_NEXT_ENTRY, &acl_entry); 296228753Smm } 297228753Smm} 298228753Smm#else 299228753Smmstatic int 300228753Smmsetup_acls_posix1e(struct archive_read_disk *a, 301228753Smm struct archive_entry *entry, int fd) 302228753Smm{ 303228753Smm (void)a; /* UNUSED */ 304228753Smm (void)entry; /* UNUSED */ 305228753Smm (void)fd; /* UNUSED */ 306228753Smm return (ARCHIVE_OK); 307228753Smm} 308228753Smm#endif 309228753Smm 310228753Smm#if HAVE_LISTXATTR && HAVE_LLISTXATTR && HAVE_GETXATTR && HAVE_LGETXATTR 311228753Smm 312228753Smm/* 313228753Smm * Linux extended attribute support. 314228753Smm * 315228753Smm * TODO: By using a stack-allocated buffer for the first 316228753Smm * call to getxattr(), we might be able to avoid the second 317228753Smm * call entirely. We only need the second call if the 318228753Smm * stack-allocated buffer is too small. But a modest buffer 319228753Smm * of 1024 bytes or so will often be big enough. Same applies 320228753Smm * to listxattr(). 321228753Smm */ 322228753Smm 323228753Smm 324228753Smmstatic int 325228753Smmsetup_xattr(struct archive_read_disk *a, 326228753Smm struct archive_entry *entry, const char *name, int fd) 327228753Smm{ 328228753Smm ssize_t size; 329228753Smm void *value = NULL; 330228753Smm const char *accpath; 331228753Smm 332228753Smm (void)fd; /* UNUSED */ 333228753Smm 334228753Smm accpath = archive_entry_sourcepath(entry); 335228753Smm if (accpath == NULL) 336228753Smm accpath = archive_entry_pathname(entry); 337228753Smm 338228753Smm if (!a->follow_symlinks) 339228753Smm size = lgetxattr(accpath, name, NULL, 0); 340228753Smm else 341228753Smm size = getxattr(accpath, name, NULL, 0); 342228753Smm 343228753Smm if (size == -1) { 344228753Smm archive_set_error(&a->archive, errno, 345228753Smm "Couldn't query extended attribute"); 346228753Smm return (ARCHIVE_WARN); 347228753Smm } 348228753Smm 349228753Smm if (size > 0 && (value = malloc(size)) == NULL) { 350228753Smm archive_set_error(&a->archive, errno, "Out of memory"); 351228753Smm return (ARCHIVE_FATAL); 352228753Smm } 353228753Smm 354228753Smm if (!a->follow_symlinks) 355228753Smm size = lgetxattr(accpath, name, value, size); 356228753Smm else 357228753Smm size = getxattr(accpath, name, value, size); 358228753Smm 359228753Smm if (size == -1) { 360228753Smm archive_set_error(&a->archive, errno, 361228753Smm "Couldn't read extended attribute"); 362228753Smm return (ARCHIVE_WARN); 363228753Smm } 364228753Smm 365228753Smm archive_entry_xattr_add_entry(entry, name, value, size); 366228753Smm 367228753Smm free(value); 368228753Smm return (ARCHIVE_OK); 369228753Smm} 370228753Smm 371228753Smmstatic int 372228753Smmsetup_xattrs(struct archive_read_disk *a, 373228753Smm struct archive_entry *entry, int fd) 374228753Smm{ 375228753Smm char *list, *p; 376228753Smm const char *path; 377228753Smm ssize_t list_size; 378228753Smm 379228753Smm 380228753Smm path = archive_entry_sourcepath(entry); 381228753Smm if (path == NULL) 382228753Smm path = archive_entry_pathname(entry); 383228753Smm 384228753Smm if (!a->follow_symlinks) 385228753Smm list_size = llistxattr(path, NULL, 0); 386228753Smm else 387228753Smm list_size = listxattr(path, NULL, 0); 388228753Smm 389228753Smm if (list_size == -1) { 390228753Smm if (errno == ENOTSUP) 391228753Smm return (ARCHIVE_OK); 392228753Smm archive_set_error(&a->archive, errno, 393228753Smm "Couldn't list extended attributes"); 394228753Smm return (ARCHIVE_WARN); 395228753Smm } 396228753Smm 397228753Smm if (list_size == 0) 398228753Smm return (ARCHIVE_OK); 399228753Smm 400228753Smm if ((list = malloc(list_size)) == NULL) { 401228753Smm archive_set_error(&a->archive, errno, "Out of memory"); 402228753Smm return (ARCHIVE_FATAL); 403228753Smm } 404228753Smm 405228753Smm if (!a->follow_symlinks) 406228753Smm list_size = llistxattr(path, list, list_size); 407228753Smm else 408228753Smm list_size = listxattr(path, list, list_size); 409228753Smm 410228753Smm if (list_size == -1) { 411228753Smm archive_set_error(&a->archive, errno, 412228753Smm "Couldn't retrieve extended attributes"); 413228753Smm free(list); 414228753Smm return (ARCHIVE_WARN); 415228753Smm } 416228753Smm 417228753Smm for (p = list; (p - list) < list_size; p += strlen(p) + 1) { 418228753Smm if (strncmp(p, "system.", 7) == 0 || 419228753Smm strncmp(p, "xfsroot.", 8) == 0) 420228753Smm continue; 421228753Smm setup_xattr(a, entry, p, fd); 422228753Smm } 423228753Smm 424228753Smm free(list); 425228753Smm return (ARCHIVE_OK); 426228753Smm} 427228753Smm 428228753Smm#elif HAVE_EXTATTR_GET_FILE && HAVE_EXTATTR_LIST_FILE && \ 429228753Smm HAVE_DECL_EXTATTR_NAMESPACE_USER 430228753Smm 431228753Smm/* 432228753Smm * FreeBSD extattr interface. 433228753Smm */ 434228753Smm 435228753Smm/* TODO: Implement this. Follow the Linux model above, but 436228753Smm * with FreeBSD-specific system calls, of course. Be careful 437228753Smm * to not include the system extattrs that hold ACLs; we handle 438228753Smm * those separately. 439228753Smm */ 440228753Smmstatic int 441228753Smmsetup_xattr(struct archive_read_disk *a, struct archive_entry *entry, 442228753Smm int namespace, const char *name, const char *fullname, int fd); 443228753Smm 444228753Smmstatic int 445228753Smmsetup_xattr(struct archive_read_disk *a, struct archive_entry *entry, 446228753Smm int namespace, const char *name, const char *fullname, int fd) 447228753Smm{ 448228753Smm ssize_t size; 449228753Smm void *value = NULL; 450228753Smm const char *accpath; 451228753Smm 452228753Smm (void)fd; /* UNUSED */ 453228753Smm 454228753Smm accpath = archive_entry_sourcepath(entry); 455228753Smm if (accpath == NULL) 456228753Smm accpath = archive_entry_pathname(entry); 457228753Smm 458228753Smm if (!a->follow_symlinks) 459228753Smm size = extattr_get_link(accpath, namespace, name, NULL, 0); 460228753Smm else 461228753Smm size = extattr_get_file(accpath, namespace, name, NULL, 0); 462228753Smm 463228753Smm if (size == -1) { 464228753Smm archive_set_error(&a->archive, errno, 465228753Smm "Couldn't query extended attribute"); 466228753Smm return (ARCHIVE_WARN); 467228753Smm } 468228753Smm 469228753Smm if (size > 0 && (value = malloc(size)) == NULL) { 470228753Smm archive_set_error(&a->archive, errno, "Out of memory"); 471228753Smm return (ARCHIVE_FATAL); 472228753Smm } 473228753Smm 474228753Smm if (!a->follow_symlinks) 475228753Smm size = extattr_get_link(accpath, namespace, name, value, size); 476228753Smm else 477228753Smm size = extattr_get_file(accpath, namespace, name, value, size); 478228753Smm 479228753Smm if (size == -1) { 480228753Smm archive_set_error(&a->archive, errno, 481228753Smm "Couldn't read extended attribute"); 482228753Smm return (ARCHIVE_WARN); 483228753Smm } 484228753Smm 485228753Smm archive_entry_xattr_add_entry(entry, fullname, value, size); 486228753Smm 487228753Smm free(value); 488228753Smm return (ARCHIVE_OK); 489228753Smm} 490228753Smm 491228753Smmstatic int 492228753Smmsetup_xattrs(struct archive_read_disk *a, 493228753Smm struct archive_entry *entry, int fd) 494228753Smm{ 495228753Smm char buff[512]; 496228753Smm char *list, *p; 497228753Smm ssize_t list_size; 498228753Smm const char *path; 499228753Smm int namespace = EXTATTR_NAMESPACE_USER; 500228753Smm 501228753Smm path = archive_entry_sourcepath(entry); 502228753Smm if (path == NULL) 503228753Smm path = archive_entry_pathname(entry); 504228753Smm 505228753Smm if (!a->follow_symlinks) 506228753Smm list_size = extattr_list_link(path, namespace, NULL, 0); 507228753Smm else 508228753Smm list_size = extattr_list_file(path, namespace, NULL, 0); 509228753Smm 510228753Smm if (list_size == -1 && errno == EOPNOTSUPP) 511228753Smm return (ARCHIVE_OK); 512228753Smm if (list_size == -1) { 513228753Smm archive_set_error(&a->archive, errno, 514228753Smm "Couldn't list extended attributes"); 515228753Smm return (ARCHIVE_WARN); 516228753Smm } 517228753Smm 518228753Smm if (list_size == 0) 519228753Smm return (ARCHIVE_OK); 520228753Smm 521228753Smm if ((list = malloc(list_size)) == NULL) { 522228753Smm archive_set_error(&a->archive, errno, "Out of memory"); 523228753Smm return (ARCHIVE_FATAL); 524228753Smm } 525228753Smm 526228753Smm if (!a->follow_symlinks) 527228753Smm list_size = extattr_list_link(path, namespace, list, list_size); 528228753Smm else 529228753Smm list_size = extattr_list_file(path, namespace, list, list_size); 530228753Smm 531228753Smm if (list_size == -1) { 532228753Smm archive_set_error(&a->archive, errno, 533228753Smm "Couldn't retrieve extended attributes"); 534228753Smm free(list); 535228753Smm return (ARCHIVE_WARN); 536228753Smm } 537228753Smm 538228753Smm p = list; 539228753Smm while ((p - list) < list_size) { 540228753Smm size_t len = 255 & (int)*p; 541228753Smm char *name; 542228753Smm 543228753Smm strcpy(buff, "user."); 544228753Smm name = buff + strlen(buff); 545228753Smm memcpy(name, p + 1, len); 546228753Smm name[len] = '\0'; 547228753Smm setup_xattr(a, entry, namespace, name, buff, fd); 548228753Smm p += 1 + len; 549228753Smm } 550228753Smm 551228753Smm free(list); 552228753Smm return (ARCHIVE_OK); 553228753Smm} 554228753Smm 555228753Smm#else 556228753Smm 557228753Smm/* 558228753Smm * Generic (stub) extended attribute support. 559228753Smm */ 560228753Smmstatic int 561228753Smmsetup_xattrs(struct archive_read_disk *a, 562228753Smm struct archive_entry *entry, int fd) 563228753Smm{ 564228753Smm (void)a; /* UNUSED */ 565228753Smm (void)entry; /* UNUSED */ 566228753Smm (void)fd; /* UNUSED */ 567228753Smm return (ARCHIVE_OK); 568228753Smm} 569228753Smm 570228753Smm#endif 571