Import libarchive-3.0.3.
[dragonfly.git] / contrib / libarchive / libarchive / archive_read_disk_entry_from_file.c
1 /*-
2  * Copyright (c) 2003-2009 Tim Kientzle
3  * Copyright (c) 2010 Michihiro NAKAJIMA
4  * 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
8  * are met:
9  * 1. Redistributions of source code must retain the above copyright
10  *    notice, this list of conditions and the following disclaimer.
11  * 2. Redistributions in binary form must reproduce the above copyright
12  *    notice, this list of conditions and the following disclaimer in the
13  *    documentation and/or other materials provided with the distribution.
14  *
15  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR
16  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
17  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
18  * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT,
19  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
20  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
21  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
22  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
23  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
24  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
25  */
26
27 #include "archive_platform.h"
28 __FBSDID("$FreeBSD: head/lib/libarchive/archive_read_disk_entry_from_file.c 201084 2009-12-28 02:14:09Z kientzle $");
29
30 /* This is the tree-walking code for POSIX systems. */
31 #if !defined(_WIN32) || defined(__CYGWIN__)
32
33 #ifdef HAVE_SYS_TYPES_H
34 /* Mac OSX requires sys/types.h before sys/acl.h. */
35 #include <sys/types.h>
36 #endif
37 #ifdef HAVE_SYS_ACL_H
38 #include <sys/acl.h>
39 #endif
40 #ifdef HAVE_SYS_EXTATTR_H
41 #include <sys/extattr.h>
42 #endif
43 #ifdef HAVE_SYS_IOCTL_H
44 #include <sys/ioctl.h>
45 #endif
46 #ifdef HAVE_SYS_PARAM_H
47 #include <sys/param.h>
48 #endif
49 #ifdef HAVE_SYS_STAT_H
50 #include <sys/stat.h>
51 #endif
52 #ifdef HAVE_SYS_XATTR_H
53 #include <sys/xattr.h>
54 #endif
55 #ifdef HAVE_SYS_EA_H
56 #include <sys/ea.h>
57 #endif
58 #ifdef HAVE_ACL_LIBACL_H
59 #include <acl/libacl.h>
60 #endif
61 #ifdef HAVE_ATTR_XATTR_H
62 #include <attr/xattr.h>
63 #endif
64 #ifdef HAVE_COPYFILE_H
65 #include <copyfile.h>
66 #endif
67 #ifdef HAVE_ERRNO_H
68 #include <errno.h>
69 #endif
70 #ifdef HAVE_FCNTL_H
71 #include <fcntl.h>
72 #endif
73 #ifdef HAVE_LIMITS_H
74 #include <limits.h>
75 #endif
76 #ifdef HAVE_LINUX_FIEMAP_H
77 #include <linux/fiemap.h>
78 #endif
79 #ifdef HAVE_LINUX_FS_H
80 #include <linux/fs.h>
81 #endif
82 /*
83  * Some Linux distributions have both linux/ext2_fs.h and ext2fs/ext2_fs.h.
84  * As the include guards don't agree, the order of include is important.
85  */
86 #ifdef HAVE_LINUX_EXT2_FS_H
87 #include <linux/ext2_fs.h>      /* for Linux file flags */
88 #endif
89 #if defined(HAVE_EXT2FS_EXT2_FS_H) && !defined(__CYGWIN__)
90 #include <ext2fs/ext2_fs.h>     /* Linux file flags, broken on Cygwin */
91 #endif
92 #ifdef HAVE_PATHS_H
93 #include <paths.h>
94 #endif
95 #ifdef HAVE_UNISTD_H
96 #include <unistd.h>
97 #endif
98
99 #include "archive.h"
100 #include "archive_entry.h"
101 #include "archive_private.h"
102 #include "archive_read_disk_private.h"
103
104 /*
105  * Linux and FreeBSD plug this obvious hole in POSIX.1e in
106  * different ways.
107  */
108 #if HAVE_ACL_GET_PERM
109 #define ACL_GET_PERM acl_get_perm
110 #elif HAVE_ACL_GET_PERM_NP
111 #define ACL_GET_PERM acl_get_perm_np
112 #endif
113
114 static int setup_acls_posix1e(struct archive_read_disk *,
115     struct archive_entry *, int fd);
116 static int setup_mac_metadata(struct archive_read_disk *,
117     struct archive_entry *, int fd);
118 static int setup_xattrs(struct archive_read_disk *,
119     struct archive_entry *, int fd);
120 static int setup_sparse(struct archive_read_disk *,
121     struct archive_entry *, int fd);
122
123 int
124 archive_read_disk_entry_from_file(struct archive *_a,
125     struct archive_entry *entry,
126     int fd,
127     const struct stat *st)
128 {
129         struct archive_read_disk *a = (struct archive_read_disk *)_a;
130         const char *path, *name;
131         struct stat s;
132         int initial_fd = fd;
133         int r, r1;
134
135         archive_clear_error(_a);
136         path = archive_entry_sourcepath(entry);
137         if (path == NULL)
138                 path = archive_entry_pathname(entry);
139
140         if (a->tree == NULL) {
141                 if (st == NULL) {
142 #if HAVE_FSTAT
143                         if (fd >= 0) {
144                                 if (fstat(fd, &s) != 0) {
145                                         archive_set_error(&a->archive, errno,
146                                             "Can't fstat");
147                                         return (ARCHIVE_FAILED);
148                                 }
149                         } else
150 #endif
151 #if HAVE_LSTAT
152                         if (!a->follow_symlinks) {
153                                 if (lstat(path, &s) != 0) {
154                                         archive_set_error(&a->archive, errno,
155                                             "Can't lstat %s", path);
156                                         return (ARCHIVE_FAILED);
157                                 }
158                         } else
159 #endif
160                         if (stat(path, &s) != 0) {
161                                 archive_set_error(&a->archive, errno,
162                                     "Can't stat %s", path);
163                                 return (ARCHIVE_FAILED);
164                         }
165                         st = &s;
166                 }
167                 archive_entry_copy_stat(entry, st);
168         }
169
170         /* Lookup uname/gname */
171         name = archive_read_disk_uname(_a, archive_entry_uid(entry));
172         if (name != NULL)
173                 archive_entry_copy_uname(entry, name);
174         name = archive_read_disk_gname(_a, archive_entry_gid(entry));
175         if (name != NULL)
176                 archive_entry_copy_gname(entry, name);
177
178 #ifdef HAVE_STRUCT_STAT_ST_FLAGS
179         /* On FreeBSD, we get flags for free with the stat. */
180         /* TODO: Does this belong in copy_stat()? */
181         if (st->st_flags != 0)
182                 archive_entry_set_fflags(entry, st->st_flags, 0);
183 #endif
184
185 #if defined(EXT2_IOC_GETFLAGS) && defined(HAVE_WORKING_EXT2_IOC_GETFLAGS)
186         /* Linux requires an extra ioctl to pull the flags.  Although
187          * this is an extra step, it has a nice side-effect: We get an
188          * open file descriptor which we can use in the subsequent lookups. */
189         if ((S_ISREG(st->st_mode) || S_ISDIR(st->st_mode))) {
190                 if (fd < 0)
191                         fd = open(path, O_RDONLY | O_NONBLOCK);
192                 if (fd >= 0) {
193                         unsigned long stflags;
194                         int r = ioctl(fd, EXT2_IOC_GETFLAGS, &stflags);
195                         if (r == 0 && stflags != 0)
196                                 archive_entry_set_fflags(entry, stflags, 0);
197                 }
198         }
199 #endif
200
201 #if defined(HAVE_READLINK) || defined(HAVE_READLINKAT)
202         if (S_ISLNK(st->st_mode)) {
203                 size_t linkbuffer_len = st->st_size + 1;
204                 char *linkbuffer;
205                 int lnklen;
206
207                 linkbuffer = malloc(linkbuffer_len);
208                 if (linkbuffer == NULL) {
209                         archive_set_error(&a->archive, ENOMEM,
210                             "Couldn't read link data");
211                         return (ARCHIVE_FAILED);
212                 }
213 #ifdef HAVE_READLINKAT
214                 if (a->entry_wd_fd >= 0)
215                         lnklen = readlinkat(a->entry_wd_fd, path,
216                             linkbuffer, linkbuffer_len);
217                 else
218 #endif /* HAVE_READLINKAT */
219                 lnklen = readlink(path, linkbuffer, linkbuffer_len);
220                 if (lnklen < 0) {
221                         archive_set_error(&a->archive, errno,
222                             "Couldn't read link data");
223                         free(linkbuffer);
224                         return (ARCHIVE_FAILED);
225                 }
226                 linkbuffer[lnklen] = 0;
227                 archive_entry_set_symlink(entry, linkbuffer);
228                 free(linkbuffer);
229         }
230 #endif /* HAVE_READLINK || HAVE_READLINKAT */
231
232         r = setup_acls_posix1e(a, entry, fd);
233         r1 = setup_xattrs(a, entry, fd);
234         if (r1 < r)
235                 r = r1;
236         r1 = setup_mac_metadata(a, entry, fd);
237         if (r1 < r)
238                 r = r1;
239         r1 = setup_sparse(a, entry, fd);
240         if (r1 < r)
241                 r = r1;
242
243         /* If we opened the file earlier in this function, close it. */
244         if (initial_fd != fd)
245                 close(fd);
246         return (r);
247 }
248
249 #if defined(__APPLE__) && defined(HAVE_COPYFILE_H)
250 /*
251  * The Mac OS "copyfile()" API copies the extended metadata for a
252  * file into a separate file in AppleDouble format (see RFC 1740).
253  *
254  * Mac OS tar and cpio implementations store this extended
255  * metadata as a separate entry just before the regular entry
256  * with a "._" prefix added to the filename.
257  *
258  * Note that this is currently done unconditionally; the tar program has
259  * an option to discard this information before the archive is written.
260  *
261  * TODO: If there's a failure, report it and return ARCHIVE_WARN.
262  */
263 static int
264 setup_mac_metadata(struct archive_read_disk *a,
265     struct archive_entry *entry, int fd)
266 {
267         int tempfd = -1;
268         int copyfile_flags = COPYFILE_NOFOLLOW | COPYFILE_ACL | COPYFILE_XATTR;
269         struct stat copyfile_stat;
270         int ret = ARCHIVE_OK;
271         void *buff;
272         int have_attrs;
273         const char *name, *tempdir, *tempfile = NULL;
274
275         name = archive_entry_sourcepath(entry);
276         if (name == NULL)
277                 name = archive_entry_pathname(entry);
278         if (name == NULL) {
279                 archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
280                     "Can't open file to read extended attributes: No name");
281                 return (ARCHIVE_WARN);
282         }
283
284         /* Short-circuit if there's nothing to do. */
285         have_attrs = copyfile(name, NULL, 0, copyfile_flags | COPYFILE_CHECK);
286         if (have_attrs == -1) {
287                 archive_set_error(&a->archive, errno,
288                         "Could not check extended attributes");
289                 return (ARCHIVE_WARN);
290         }
291         if (have_attrs == 0)
292                 return (ARCHIVE_OK);
293
294         tempdir = NULL;
295         if (issetugid() == 0)
296                 tempdir = getenv("TMPDIR");
297         if (tempdir == NULL)
298                 tempdir = _PATH_TMP;
299         tempfile = tempnam(tempdir, "tar.md.");
300
301         /* XXX I wish copyfile() could pack directly to a memory
302          * buffer; that would avoid the temp file here.  For that
303          * matter, it would be nice if fcopyfile() actually worked,
304          * that would reduce the many open/close races here. */
305         if (copyfile(name, tempfile, 0, copyfile_flags | COPYFILE_PACK)) {
306                 archive_set_error(&a->archive, errno,
307                     "Could not pack extended attributes");
308                 ret = ARCHIVE_WARN;
309                 goto cleanup;
310         }
311         tempfd = open(tempfile, O_RDONLY);
312         if (tempfd < 0) {
313                 archive_set_error(&a->archive, errno,
314                     "Could not open extended attribute file");
315                 ret = ARCHIVE_WARN;
316                 goto cleanup;
317         }
318         if (fstat(tempfd, &copyfile_stat)) {
319                 archive_set_error(&a->archive, errno,
320                     "Could not check size of extended attributes");
321                 ret = ARCHIVE_WARN;
322                 goto cleanup;
323         }
324         buff = malloc(copyfile_stat.st_size);
325         if (buff == NULL) {
326                 archive_set_error(&a->archive, errno,
327                     "Could not allocate memory for extended attributes");
328                 ret = ARCHIVE_WARN;
329                 goto cleanup;
330         }
331         if (copyfile_stat.st_size != read(tempfd, buff, copyfile_stat.st_size)) {
332                 archive_set_error(&a->archive, errno,
333                     "Could not read extended attributes into memory");
334                 ret = ARCHIVE_WARN;
335                 goto cleanup;
336         }
337         archive_entry_copy_mac_metadata(entry, buff, copyfile_stat.st_size);
338
339 cleanup:
340         if (tempfd >= 0)
341                 close(tempfd);
342         if (tempfile != NULL)
343                 unlink(tempfile);
344         return (ret);
345 }
346
347 #else
348
349 /*
350  * Stub implementation for non-Mac systems.
351  */
352 static int
353 setup_mac_metadata(struct archive_read_disk *a,
354     struct archive_entry *entry, int fd)
355 {
356         (void)a; /* UNUSED */
357         (void)entry; /* UNUSED */
358         (void)fd; /* UNUSED */
359         return (ARCHIVE_OK);
360 }
361 #endif
362
363
364 #ifdef HAVE_POSIX_ACL
365 static void setup_acl_posix1e(struct archive_read_disk *a,
366     struct archive_entry *entry, acl_t acl, int archive_entry_acl_type);
367
368 static int
369 setup_acls_posix1e(struct archive_read_disk *a,
370     struct archive_entry *entry, int fd)
371 {
372         const char      *accpath;
373         acl_t            acl;
374
375         accpath = archive_entry_sourcepath(entry);
376         if (accpath == NULL)
377                 accpath = archive_entry_pathname(entry);
378
379         archive_entry_acl_clear(entry);
380
381         /* Retrieve access ACL from file. */
382         if (fd >= 0)
383                 acl = acl_get_fd(fd);
384 #if HAVE_ACL_GET_LINK_NP
385         else if (!a->follow_symlinks)
386                 acl = acl_get_link_np(accpath, ACL_TYPE_ACCESS);
387 #else
388         else if ((!a->follow_symlinks)
389             && (archive_entry_filetype(entry) == AE_IFLNK))
390                 /* We can't get the ACL of a symlink, so we assume it can't
391                    have one. */
392                 acl = NULL;
393 #endif
394         else
395                 acl = acl_get_file(accpath, ACL_TYPE_ACCESS);
396         if (acl != NULL) {
397                 setup_acl_posix1e(a, entry, acl,
398                     ARCHIVE_ENTRY_ACL_TYPE_ACCESS);
399                 acl_free(acl);
400         }
401
402         /* Only directories can have default ACLs. */
403         if (S_ISDIR(archive_entry_mode(entry))) {
404                 acl = acl_get_file(accpath, ACL_TYPE_DEFAULT);
405                 if (acl != NULL) {
406                         setup_acl_posix1e(a, entry, acl,
407                             ARCHIVE_ENTRY_ACL_TYPE_DEFAULT);
408                         acl_free(acl);
409                 }
410         }
411         return (ARCHIVE_OK);
412 }
413
414 /*
415  * Translate POSIX.1e ACL into libarchive internal structure.
416  */
417 static void
418 setup_acl_posix1e(struct archive_read_disk *a,
419     struct archive_entry *entry, acl_t acl, int archive_entry_acl_type)
420 {
421         acl_tag_t        acl_tag;
422         acl_entry_t      acl_entry;
423         acl_permset_t    acl_permset;
424         int              s, ae_id, ae_tag, ae_perm;
425         const char      *ae_name;
426
427         s = acl_get_entry(acl, ACL_FIRST_ENTRY, &acl_entry);
428         while (s == 1) {
429                 ae_id = -1;
430                 ae_name = NULL;
431
432                 acl_get_tag_type(acl_entry, &acl_tag);
433                 if (acl_tag == ACL_USER) {
434                         ae_id = (int)*(uid_t *)acl_get_qualifier(acl_entry);
435                         ae_name = archive_read_disk_uname(&a->archive, ae_id);
436                         ae_tag = ARCHIVE_ENTRY_ACL_USER;
437                 } else if (acl_tag == ACL_GROUP) {
438                         ae_id = (int)*(gid_t *)acl_get_qualifier(acl_entry);
439                         ae_name = archive_read_disk_gname(&a->archive, ae_id);
440                         ae_tag = ARCHIVE_ENTRY_ACL_GROUP;
441                 } else if (acl_tag == ACL_MASK) {
442                         ae_tag = ARCHIVE_ENTRY_ACL_MASK;
443                 } else if (acl_tag == ACL_USER_OBJ) {
444                         ae_tag = ARCHIVE_ENTRY_ACL_USER_OBJ;
445                 } else if (acl_tag == ACL_GROUP_OBJ) {
446                         ae_tag = ARCHIVE_ENTRY_ACL_GROUP_OBJ;
447                 } else if (acl_tag == ACL_OTHER) {
448                         ae_tag = ARCHIVE_ENTRY_ACL_OTHER;
449                 } else {
450                         /* Skip types that libarchive can't support. */
451                         continue;
452                 }
453
454                 acl_get_permset(acl_entry, &acl_permset);
455                 ae_perm = 0;
456                 /*
457                  * acl_get_perm() is spelled differently on different
458                  * platforms; see above.
459                  */
460                 if (ACL_GET_PERM(acl_permset, ACL_EXECUTE))
461                         ae_perm |= ARCHIVE_ENTRY_ACL_EXECUTE;
462                 if (ACL_GET_PERM(acl_permset, ACL_READ))
463                         ae_perm |= ARCHIVE_ENTRY_ACL_READ;
464                 if (ACL_GET_PERM(acl_permset, ACL_WRITE))
465                         ae_perm |= ARCHIVE_ENTRY_ACL_WRITE;
466
467                 archive_entry_acl_add_entry(entry,
468                     archive_entry_acl_type, ae_perm, ae_tag,
469                     ae_id, ae_name);
470
471                 s = acl_get_entry(acl, ACL_NEXT_ENTRY, &acl_entry);
472         }
473 }
474 #else
475 static int
476 setup_acls_posix1e(struct archive_read_disk *a,
477     struct archive_entry *entry, int fd)
478 {
479         (void)a;      /* UNUSED */
480         (void)entry;  /* UNUSED */
481         (void)fd;     /* UNUSED */
482         return (ARCHIVE_OK);
483 }
484 #endif
485
486 #if (HAVE_FGETXATTR && HAVE_FLISTXATTR && HAVE_LISTXATTR && \
487     HAVE_LLISTXATTR && HAVE_GETXATTR && HAVE_LGETXATTR) || \
488     (HAVE_FGETEA && HAVE_FLISTEA && HAVE_LISTEA)
489
490 /*
491  * Linux and AIX extended attribute support.
492  *
493  * TODO:  By using a stack-allocated buffer for the first
494  * call to getxattr(), we might be able to avoid the second
495  * call entirely.  We only need the second call if the
496  * stack-allocated buffer is too small.  But a modest buffer
497  * of 1024 bytes or so will often be big enough.  Same applies
498  * to listxattr().
499  */
500
501
502 static int
503 setup_xattr(struct archive_read_disk *a,
504     struct archive_entry *entry, const char *name, int fd)
505 {
506         ssize_t size;
507         void *value = NULL;
508         const char *accpath;
509
510         accpath = archive_entry_sourcepath(entry);
511         if (accpath == NULL)
512                 accpath = archive_entry_pathname(entry);
513
514 #if HAVE_FGETXATTR
515         if (fd >= 0)
516                 size = fgetxattr(fd, name, NULL, 0);
517         else if (!a->follow_symlinks)
518                 size = lgetxattr(accpath, name, NULL, 0);
519         else
520                 size = getxattr(accpath, name, NULL, 0);
521 #elif HAVE_FGETEA
522         if (fd >= 0)
523                 size = fgetea(fd, name, NULL, 0);
524         else if (!a->follow_symlinks)
525                 size = lgetea(accpath, name, NULL, 0);
526         else
527                 size = getea(accpath, name, NULL, 0);
528 #endif
529
530         if (size == -1) {
531                 archive_set_error(&a->archive, errno,
532                     "Couldn't query extended attribute");
533                 return (ARCHIVE_WARN);
534         }
535
536         if (size > 0 && (value = malloc(size)) == NULL) {
537                 archive_set_error(&a->archive, errno, "Out of memory");
538                 return (ARCHIVE_FATAL);
539         }
540
541 #if HAVE_FGETXATTR
542         if (fd >= 0)
543                 size = fgetxattr(fd, name, value, size);
544         else if (!a->follow_symlinks)
545                 size = lgetxattr(accpath, name, value, size);
546         else
547                 size = getxattr(accpath, name, value, size);
548 #elif HAVE_FGETEA
549         if (fd >= 0)
550                 size = fgetea(fd, name, value, size);
551         else if (!a->follow_symlinks)
552                 size = lgetea(accpath, name, value, size);
553         else
554                 size = getea(accpath, name, value, size);
555 #endif
556
557         if (size == -1) {
558                 archive_set_error(&a->archive, errno,
559                     "Couldn't read extended attribute");
560                 return (ARCHIVE_WARN);
561         }
562
563         archive_entry_xattr_add_entry(entry, name, value, size);
564
565         free(value);
566         return (ARCHIVE_OK);
567 }
568
569 static int
570 setup_xattrs(struct archive_read_disk *a,
571     struct archive_entry *entry, int fd)
572 {
573         char *list, *p;
574         const char *path;
575         ssize_t list_size;
576
577         path = archive_entry_sourcepath(entry);
578         if (path == NULL)
579                 path = archive_entry_pathname(entry);
580
581 #if HAVE_FLISTXATTR
582         if (fd >= 0)
583                 list_size = flistxattr(fd, NULL, 0);
584         else if (!a->follow_symlinks)
585                 list_size = llistxattr(path, NULL, 0);
586         else
587                 list_size = listxattr(path, NULL, 0);
588 #elif HAVE_FLISTEA
589         if (fd >= 0)
590                 list_size = flistea(fd, NULL, 0);
591         else if (!a->follow_symlinks)
592                 list_size = llistea(path, NULL, 0);
593         else
594                 list_size = listea(path, NULL, 0);
595 #endif
596
597         if (list_size == -1) {
598                 if (errno == ENOTSUP || errno == ENOSYS)
599                         return (ARCHIVE_OK);
600                 archive_set_error(&a->archive, errno,
601                         "Couldn't list extended attributes");
602                 return (ARCHIVE_WARN);
603         }
604
605         if (list_size == 0)
606                 return (ARCHIVE_OK);
607
608         if ((list = malloc(list_size)) == NULL) {
609                 archive_set_error(&a->archive, errno, "Out of memory");
610                 return (ARCHIVE_FATAL);
611         }
612
613 #if HAVE_FLISTXATTR
614         if (fd >= 0)
615                 list_size = flistxattr(fd, list, list_size);
616         else if (!a->follow_symlinks)
617                 list_size = llistxattr(path, list, list_size);
618         else
619                 list_size = listxattr(path, list, list_size);
620 #elif HAVE_FLISTEA
621         if (fd >= 0)
622                 list_size = flistea(fd, list, list_size);
623         else if (!a->follow_symlinks)
624                 list_size = llistea(path, list, list_size);
625         else
626                 list_size = listea(path, list, list_size);
627 #endif
628
629         if (list_size == -1) {
630                 archive_set_error(&a->archive, errno,
631                         "Couldn't retrieve extended attributes");
632                 free(list);
633                 return (ARCHIVE_WARN);
634         }
635
636         for (p = list; (p - list) < list_size; p += strlen(p) + 1) {
637                 if (strncmp(p, "system.", 7) == 0 ||
638                                 strncmp(p, "xfsroot.", 8) == 0)
639                         continue;
640                 setup_xattr(a, entry, p, fd);
641         }
642
643         free(list);
644         return (ARCHIVE_OK);
645 }
646
647 #elif HAVE_EXTATTR_GET_FILE && HAVE_EXTATTR_LIST_FILE && \
648     HAVE_DECL_EXTATTR_NAMESPACE_USER
649
650 /*
651  * FreeBSD extattr interface.
652  */
653
654 /* TODO: Implement this.  Follow the Linux model above, but
655  * with FreeBSD-specific system calls, of course.  Be careful
656  * to not include the system extattrs that hold ACLs; we handle
657  * those separately.
658  */
659 static int
660 setup_xattr(struct archive_read_disk *a, struct archive_entry *entry,
661     int namespace, const char *name, const char *fullname, int fd);
662
663 static int
664 setup_xattr(struct archive_read_disk *a, struct archive_entry *entry,
665     int namespace, const char *name, const char *fullname, int fd)
666 {
667         ssize_t size;
668         void *value = NULL;
669         const char *accpath;
670
671         accpath = archive_entry_sourcepath(entry);
672         if (accpath == NULL)
673                 accpath = archive_entry_pathname(entry);
674
675         if (fd >= 0)
676                 size = extattr_get_fd(fd, namespace, name, NULL, 0);
677         else if (!a->follow_symlinks)
678                 size = extattr_get_link(accpath, namespace, name, NULL, 0);
679         else
680                 size = extattr_get_file(accpath, namespace, name, NULL, 0);
681
682         if (size == -1) {
683                 archive_set_error(&a->archive, errno,
684                     "Couldn't query extended attribute");
685                 return (ARCHIVE_WARN);
686         }
687
688         if (size > 0 && (value = malloc(size)) == NULL) {
689                 archive_set_error(&a->archive, errno, "Out of memory");
690                 return (ARCHIVE_FATAL);
691         }
692
693         if (fd >= 0)
694                 size = extattr_get_fd(fd, namespace, name, value, size);
695         else if (!a->follow_symlinks)
696                 size = extattr_get_link(accpath, namespace, name, value, size);
697         else
698                 size = extattr_get_file(accpath, namespace, name, value, size);
699
700         if (size == -1) {
701                 archive_set_error(&a->archive, errno,
702                     "Couldn't read extended attribute");
703                 return (ARCHIVE_WARN);
704         }
705
706         archive_entry_xattr_add_entry(entry, fullname, value, size);
707
708         free(value);
709         return (ARCHIVE_OK);
710 }
711
712 static int
713 setup_xattrs(struct archive_read_disk *a,
714     struct archive_entry *entry, int fd)
715 {
716         char buff[512];
717         char *list, *p;
718         ssize_t list_size;
719         const char *path;
720         int namespace = EXTATTR_NAMESPACE_USER;
721
722         path = archive_entry_sourcepath(entry);
723         if (path == NULL)
724                 path = archive_entry_pathname(entry);
725
726         if (fd >= 0)
727                 list_size = extattr_list_fd(fd, namespace, NULL, 0);
728         else if (!a->follow_symlinks)
729                 list_size = extattr_list_link(path, namespace, NULL, 0);
730         else
731                 list_size = extattr_list_file(path, namespace, NULL, 0);
732
733         if (list_size == -1 && errno == EOPNOTSUPP)
734                 return (ARCHIVE_OK);
735         if (list_size == -1) {
736                 archive_set_error(&a->archive, errno,
737                         "Couldn't list extended attributes");
738                 return (ARCHIVE_WARN);
739         }
740
741         if (list_size == 0)
742                 return (ARCHIVE_OK);
743
744         if ((list = malloc(list_size)) == NULL) {
745                 archive_set_error(&a->archive, errno, "Out of memory");
746                 return (ARCHIVE_FATAL);
747         }
748
749         if (fd >= 0)
750                 list_size = extattr_list_fd(fd, namespace, list, list_size);
751         else if (!a->follow_symlinks)
752                 list_size = extattr_list_link(path, namespace, list, list_size);
753         else
754                 list_size = extattr_list_file(path, namespace, list, list_size);
755
756         if (list_size == -1) {
757                 archive_set_error(&a->archive, errno,
758                         "Couldn't retrieve extended attributes");
759                 free(list);
760                 return (ARCHIVE_WARN);
761         }
762
763         p = list;
764         while ((p - list) < list_size) {
765                 size_t len = 255 & (int)*p;
766                 char *name;
767
768                 strcpy(buff, "user.");
769                 name = buff + strlen(buff);
770                 memcpy(name, p + 1, len);
771                 name[len] = '\0';
772                 setup_xattr(a, entry, namespace, name, buff, fd);
773                 p += 1 + len;
774         }
775
776         free(list);
777         return (ARCHIVE_OK);
778 }
779
780 #else
781
782 /*
783  * Generic (stub) extended attribute support.
784  */
785 static int
786 setup_xattrs(struct archive_read_disk *a,
787     struct archive_entry *entry, int fd)
788 {
789         (void)a;     /* UNUSED */
790         (void)entry; /* UNUSED */
791         (void)fd;    /* UNUSED */
792         return (ARCHIVE_OK);
793 }
794
795 #endif
796
797 #if defined(HAVE_LINUX_FIEMAP_H)
798
799 /*
800  * Linux sparse interface.
801  *
802  * The FIEMAP ioctl returns an "extent" for each physical allocation
803  * on disk.  We need to process those to generate a more compact list
804  * of logical file blocks.  We also need to be very careful to use
805  * FIEMAP_FLAG_SYNC here, since there are reports that Linux sometimes
806  * does not report allocations for newly-written data that hasn't
807  * been synced to disk.
808  *
809  * It's important to return a minimal sparse file list because we want
810  * to not trigger sparse file extensions if we don't have to, since
811  * not all readers support them.
812  */
813
814 static int
815 setup_sparse(struct archive_read_disk *a,
816     struct archive_entry *entry, int fd)
817 {
818         char buff[4096];
819         struct fiemap *fm;
820         struct fiemap_extent *fe;
821         int64_t size;
822         int count, do_fiemap;
823         int initial_fd = fd;
824         int exit_sts = ARCHIVE_OK;
825
826         if (archive_entry_filetype(entry) != AE_IFREG
827             || archive_entry_size(entry) <= 0
828             || archive_entry_hardlink(entry) != NULL)
829                 return (ARCHIVE_OK);
830
831         if (fd < 0) {
832                 const char *path;
833
834                 path = archive_entry_sourcepath(entry);
835                 if (path == NULL)
836                         path = archive_entry_pathname(entry);
837                 fd = open(path, O_RDONLY | O_NONBLOCK);
838                 if (fd < 0) {
839                         archive_set_error(&a->archive, errno,
840                             "Can't open `%s'", path);
841                         return (ARCHIVE_FAILED);
842                 }
843         }
844
845         count = (sizeof(buff) - sizeof(*fm))/sizeof(*fe);
846         fm = (struct fiemap *)buff;
847         fm->fm_start = 0;
848         fm->fm_length = ~0ULL;;
849         fm->fm_flags = FIEMAP_FLAG_SYNC;
850         fm->fm_extent_count = count;
851         do_fiemap = 1;
852         size = archive_entry_size(entry);
853         for (;;) {
854                 int i, r;
855
856                 r = ioctl(fd, FS_IOC_FIEMAP, fm); 
857                 if (r < 0) {
858                         /* When errno is ENOTTY, it is better we should
859                          * return ARCHIVE_OK because an earlier version
860                          *(<2.6.28) cannot perfom FS_IOC_FIEMAP.
861                          * We should also check if errno is EOPNOTSUPP,
862                          * it means "Operation not supported". */
863                         if (errno != ENOTTY && errno != EOPNOTSUPP) {
864                                 archive_set_error(&a->archive, errno,
865                                     "FIEMAP failed");
866                                 exit_sts = ARCHIVE_FAILED;
867                         }
868                         goto exit_setup_sparse;
869                 }
870                 if (fm->fm_mapped_extents == 0)
871                         break;
872                 fe = fm->fm_extents;
873                 for (i = 0; i < fm->fm_mapped_extents; i++, fe++) {
874                         if (!(fe->fe_flags & FIEMAP_EXTENT_UNWRITTEN)) {
875                                 /* The fe_length of the last block does not
876                                  * adjust itself to its size files. */
877                                 int64_t length = fe->fe_length;
878                                 if (fe->fe_logical + length > size)
879                                         length -= fe->fe_logical + length - size;
880                                 if (fe->fe_logical == 0 && length == size) {
881                                         /* This is not sparse. */
882                                         do_fiemap = 0;
883                                         break;
884                                 }
885                                 if (length > 0)
886                                         archive_entry_sparse_add_entry(entry,
887                                             fe->fe_logical, length);
888                         }
889                         if (fe->fe_flags & FIEMAP_EXTENT_LAST)
890                                 do_fiemap = 0;
891                 }
892                 if (do_fiemap) {
893                         fe = fm->fm_extents + fm->fm_mapped_extents -1;
894                         fm->fm_start = fe->fe_logical + fe->fe_length;
895                 } else
896                         break;
897         }
898 exit_setup_sparse:
899         if (initial_fd != fd)
900                 close(fd);
901         return (exit_sts);
902 }
903
904 #elif defined(SEEK_HOLE) && defined(SEEK_DATA) && defined(_PC_MIN_HOLE_SIZE)
905
906 /*
907  * FreeBSD and Solaris sparse interface.
908  */
909
910 static int
911 setup_sparse(struct archive_read_disk *a,
912     struct archive_entry *entry, int fd)
913 {
914         int64_t size;
915         int initial_fd = fd;
916         off_t initial_off; /* FreeBSD/Solaris only, so off_t okay here */
917         off_t off_s, off_e; /* FreeBSD/Solaris only, so off_t okay here */
918         int exit_sts = ARCHIVE_OK;
919
920         if (archive_entry_filetype(entry) != AE_IFREG
921             || archive_entry_size(entry) <= 0
922             || archive_entry_hardlink(entry) != NULL)
923                 return (ARCHIVE_OK);
924
925         /* Does filesystem support the reporting of hole ? */
926         if (fd >= 0) {
927                 if (fpathconf(fd, _PC_MIN_HOLE_SIZE) <= 0)
928                         return (ARCHIVE_OK);
929                 initial_off = lseek(fd, 0, SEEK_CUR);
930                 if (initial_off != 0)
931                         lseek(fd, 0, SEEK_SET);
932         } else {
933                 const char *path;
934
935                 path = archive_entry_sourcepath(entry);
936                 if (path == NULL)
937                         path = archive_entry_pathname(entry);
938                 if (pathconf(path, _PC_MIN_HOLE_SIZE) <= 0)
939                         return (ARCHIVE_OK);
940                 fd = open(path, O_RDONLY | O_NONBLOCK);
941                 if (fd < 0) {
942                         archive_set_error(&a->archive, errno,
943                             "Can't open `%s'", path);
944                         return (ARCHIVE_FAILED);
945                 }
946                 initial_off = 0;
947         }
948
949         off_s = 0;
950         size = archive_entry_size(entry);
951         while (off_s < size) {
952                 off_s = lseek(fd, off_s, SEEK_DATA);
953                 if (off_s == (off_t)-1) {
954                         if (errno == ENXIO)
955                                 break;/* no more hole */
956                         archive_set_error(&a->archive, errno,
957                             "lseek(SEEK_HOLE) failed");
958                         exit_sts = ARCHIVE_FAILED;
959                         goto exit_setup_sparse;
960                 }
961                 off_e = lseek(fd, off_s, SEEK_HOLE);
962                 if (off_s == (off_t)-1) {
963                         if (errno == ENXIO) {
964                                 off_e = lseek(fd, 0, SEEK_END);
965                                 if (off_e != (off_t)-1)
966                                         break;/* no more data */
967                         }
968                         archive_set_error(&a->archive, errno,
969                             "lseek(SEEK_DATA) failed");
970                         exit_sts = ARCHIVE_FAILED;
971                         goto exit_setup_sparse;
972                 }
973                 if (off_s == 0 && off_e == size)
974                         break;/* This is not spase. */
975                 archive_entry_sparse_add_entry(entry, off_s,
976                         off_e - off_s);
977                 off_s = off_e;
978         }
979 exit_setup_sparse:
980         if (initial_fd != fd)
981                 close(fd);
982         else
983                 lseek(fd, initial_off, SEEK_SET);
984         return (exit_sts);
985 }
986
987 #else
988
989 /*
990  * Generic (stub) sparse support.
991  */
992 static int
993 setup_sparse(struct archive_read_disk *a,
994     struct archive_entry *entry, int fd)
995 {
996         (void)a;     /* UNUSED */
997         (void)entry; /* UNUSED */
998         (void)fd;    /* UNUSED */
999         return (ARCHIVE_OK);
1000 }
1001
1002 #endif
1003
1004 #endif /* !defined(_WIN32) || defined(__CYGWIN__) */
1005