]> CyberLeo.Net >> Repos - FreeBSD/stable/10.git/blob - contrib/libarchive/libarchive/archive_read_disk_entry_from_file.c
MFC r309300,r309363,r309405,r309523,r309590,r310185,r310623:
[FreeBSD/stable/10.git] / contrib / libarchive / libarchive / archive_read_disk_entry_from_file.c
1 /*-
2  * Copyright (c) 2003-2009 Tim Kientzle
3  * Copyright (c) 2010-2012 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$");
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 #if defined(HAVE_SYS_XATTR_H)
53 #include <sys/xattr.h>
54 #elif defined(HAVE_ATTR_XATTR_H)
55 #include <attr/xattr.h>
56 #endif
57 #ifdef HAVE_SYS_EA_H
58 #include <sys/ea.h>
59 #endif
60 #ifdef HAVE_ACL_LIBACL_H
61 #include <acl/libacl.h>
62 #endif
63 #ifdef HAVE_COPYFILE_H
64 #include <copyfile.h>
65 #endif
66 #ifdef HAVE_ERRNO_H
67 #include <errno.h>
68 #endif
69 #ifdef HAVE_FCNTL_H
70 #include <fcntl.h>
71 #endif
72 #ifdef HAVE_LIMITS_H
73 #include <limits.h>
74 #endif
75 #ifdef HAVE_LINUX_TYPES_H
76 #include <linux/types.h>
77 #endif
78 #ifdef HAVE_LINUX_FIEMAP_H
79 #include <linux/fiemap.h>
80 #endif
81 #ifdef HAVE_LINUX_FS_H
82 #include <linux/fs.h>
83 #endif
84 /*
85  * Some Linux distributions have both linux/ext2_fs.h and ext2fs/ext2_fs.h.
86  * As the include guards don't agree, the order of include is important.
87  */
88 #ifdef HAVE_LINUX_EXT2_FS_H
89 #include <linux/ext2_fs.h>      /* for Linux file flags */
90 #endif
91 #if defined(HAVE_EXT2FS_EXT2_FS_H) && !defined(__CYGWIN__)
92 #include <ext2fs/ext2_fs.h>     /* Linux file flags, broken on Cygwin */
93 #endif
94 #ifdef HAVE_PATHS_H
95 #include <paths.h>
96 #endif
97 #ifdef HAVE_UNISTD_H
98 #include <unistd.h>
99 #endif
100
101 #include "archive.h"
102 #include "archive_entry.h"
103 #include "archive_private.h"
104 #include "archive_read_disk_private.h"
105
106 #ifndef O_CLOEXEC
107 #define O_CLOEXEC       0
108 #endif
109
110 /*
111  * Linux and FreeBSD plug this obvious hole in POSIX.1e in
112  * different ways.
113  */
114 #if HAVE_ACL_GET_PERM
115 #define ACL_GET_PERM acl_get_perm
116 #elif HAVE_ACL_GET_PERM_NP
117 #define ACL_GET_PERM acl_get_perm_np
118 #endif
119
120 static int setup_acls(struct archive_read_disk *,
121     struct archive_entry *, int *fd);
122 static int setup_mac_metadata(struct archive_read_disk *,
123     struct archive_entry *, int *fd);
124 static int setup_xattrs(struct archive_read_disk *,
125     struct archive_entry *, int *fd);
126 static int setup_sparse(struct archive_read_disk *,
127     struct archive_entry *, int *fd);
128 #if defined(HAVE_LINUX_FIEMAP_H)
129 static int setup_sparse_fiemap(struct archive_read_disk *,
130     struct archive_entry *, int *fd);
131 #endif
132
133 int
134 archive_read_disk_entry_from_file(struct archive *_a,
135     struct archive_entry *entry,
136     int fd,
137     const struct stat *st)
138 {
139         struct archive_read_disk *a = (struct archive_read_disk *)_a;
140         const char *path, *name;
141         struct stat s;
142         int initial_fd = fd;
143         int r, r1;
144
145         archive_clear_error(_a);
146         path = archive_entry_sourcepath(entry);
147         if (path == NULL)
148                 path = archive_entry_pathname(entry);
149
150         if (a->tree == NULL) {
151                 if (st == NULL) {
152 #if HAVE_FSTAT
153                         if (fd >= 0) {
154                                 if (fstat(fd, &s) != 0) {
155                                         archive_set_error(&a->archive, errno,
156                                             "Can't fstat");
157                                         return (ARCHIVE_FAILED);
158                                 }
159                         } else
160 #endif
161 #if HAVE_LSTAT
162                         if (!a->follow_symlinks) {
163                                 if (lstat(path, &s) != 0) {
164                                         archive_set_error(&a->archive, errno,
165                                             "Can't lstat %s", path);
166                                         return (ARCHIVE_FAILED);
167                                 }
168                         } else
169 #endif
170                         if (stat(path, &s) != 0) {
171                                 archive_set_error(&a->archive, errno,
172                                     "Can't stat %s", path);
173                                 return (ARCHIVE_FAILED);
174                         }
175                         st = &s;
176                 }
177                 archive_entry_copy_stat(entry, st);
178         }
179
180         /* Lookup uname/gname */
181         name = archive_read_disk_uname(_a, archive_entry_uid(entry));
182         if (name != NULL)
183                 archive_entry_copy_uname(entry, name);
184         name = archive_read_disk_gname(_a, archive_entry_gid(entry));
185         if (name != NULL)
186                 archive_entry_copy_gname(entry, name);
187
188 #ifdef HAVE_STRUCT_STAT_ST_FLAGS
189         /* On FreeBSD, we get flags for free with the stat. */
190         /* TODO: Does this belong in copy_stat()? */
191         if (st->st_flags != 0)
192                 archive_entry_set_fflags(entry, st->st_flags, 0);
193 #endif
194
195 #if defined(EXT2_IOC_GETFLAGS) && defined(HAVE_WORKING_EXT2_IOC_GETFLAGS)
196         /* Linux requires an extra ioctl to pull the flags.  Although
197          * this is an extra step, it has a nice side-effect: We get an
198          * open file descriptor which we can use in the subsequent lookups. */
199         if ((S_ISREG(st->st_mode) || S_ISDIR(st->st_mode))) {
200                 if (fd < 0) {
201                         if (a->tree != NULL)
202                                 fd = a->open_on_current_dir(a->tree, path,
203                                         O_RDONLY | O_NONBLOCK | O_CLOEXEC);
204                         else
205                                 fd = open(path, O_RDONLY | O_NONBLOCK |
206                                                 O_CLOEXEC);
207                         __archive_ensure_cloexec_flag(fd);
208                 }
209                 if (fd >= 0) {
210                         int stflags;
211                         r = ioctl(fd, EXT2_IOC_GETFLAGS, &stflags);
212                         if (r == 0 && stflags != 0)
213                                 archive_entry_set_fflags(entry, stflags, 0);
214                 }
215         }
216 #endif
217
218 #if defined(HAVE_READLINK) || defined(HAVE_READLINKAT)
219         if (S_ISLNK(st->st_mode)) {
220                 size_t linkbuffer_len = st->st_size + 1;
221                 char *linkbuffer;
222                 int lnklen;
223
224                 linkbuffer = malloc(linkbuffer_len);
225                 if (linkbuffer == NULL) {
226                         archive_set_error(&a->archive, ENOMEM,
227                             "Couldn't read link data");
228                         return (ARCHIVE_FAILED);
229                 }
230                 if (a->tree != NULL) {
231 #ifdef HAVE_READLINKAT
232                         lnklen = readlinkat(a->tree_current_dir_fd(a->tree),
233                             path, linkbuffer, linkbuffer_len);
234 #else
235                         if (a->tree_enter_working_dir(a->tree) != 0) {
236                                 archive_set_error(&a->archive, errno,
237                                     "Couldn't read link data");
238                                 free(linkbuffer);
239                                 return (ARCHIVE_FAILED);
240                         }
241                         lnklen = readlink(path, linkbuffer, linkbuffer_len);
242 #endif /* HAVE_READLINKAT */
243                 } else
244                         lnklen = readlink(path, linkbuffer, linkbuffer_len);
245                 if (lnklen < 0) {
246                         archive_set_error(&a->archive, errno,
247                             "Couldn't read link data");
248                         free(linkbuffer);
249                         return (ARCHIVE_FAILED);
250                 }
251                 linkbuffer[lnklen] = 0;
252                 archive_entry_set_symlink(entry, linkbuffer);
253                 free(linkbuffer);
254         }
255 #endif /* HAVE_READLINK || HAVE_READLINKAT */
256
257         r = setup_acls(a, entry, &fd);
258         if (!a->suppress_xattr) {
259                 r1 = setup_xattrs(a, entry, &fd);
260                 if (r1 < r)
261                         r = r1;
262         }
263         if (a->enable_copyfile) {
264                 r1 = setup_mac_metadata(a, entry, &fd);
265                 if (r1 < r)
266                         r = r1;
267         }
268         r1 = setup_sparse(a, entry, &fd);
269         if (r1 < r)
270                 r = r1;
271
272         /* If we opened the file earlier in this function, close it. */
273         if (initial_fd != fd)
274                 close(fd);
275         return (r);
276 }
277
278 #if defined(__APPLE__) && defined(HAVE_COPYFILE_H)
279 /*
280  * The Mac OS "copyfile()" API copies the extended metadata for a
281  * file into a separate file in AppleDouble format (see RFC 1740).
282  *
283  * Mac OS tar and cpio implementations store this extended
284  * metadata as a separate entry just before the regular entry
285  * with a "._" prefix added to the filename.
286  *
287  * Note that this is currently done unconditionally; the tar program has
288  * an option to discard this information before the archive is written.
289  *
290  * TODO: If there's a failure, report it and return ARCHIVE_WARN.
291  */
292 static int
293 setup_mac_metadata(struct archive_read_disk *a,
294     struct archive_entry *entry, int *fd)
295 {
296         int tempfd = -1;
297         int copyfile_flags = COPYFILE_NOFOLLOW | COPYFILE_ACL | COPYFILE_XATTR;
298         struct stat copyfile_stat;
299         int ret = ARCHIVE_OK;
300         void *buff = NULL;
301         int have_attrs;
302         const char *name, *tempdir;
303         struct archive_string tempfile;
304
305         (void)fd; /* UNUSED */
306         name = archive_entry_sourcepath(entry);
307         if (name == NULL)
308                 name = archive_entry_pathname(entry);
309         if (name == NULL) {
310                 archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
311                     "Can't open file to read extended attributes: No name");
312                 return (ARCHIVE_WARN);
313         }
314
315         if (a->tree != NULL) {
316                 if (a->tree_enter_working_dir(a->tree) != 0) {
317                         archive_set_error(&a->archive, errno,
318                                     "Couldn't change dir");
319                                 return (ARCHIVE_FAILED);
320                 }
321         }
322
323         /* Short-circuit if there's nothing to do. */
324         have_attrs = copyfile(name, NULL, 0, copyfile_flags | COPYFILE_CHECK);
325         if (have_attrs == -1) {
326                 archive_set_error(&a->archive, errno,
327                         "Could not check extended attributes");
328                 return (ARCHIVE_WARN);
329         }
330         if (have_attrs == 0)
331                 return (ARCHIVE_OK);
332
333         tempdir = NULL;
334         if (issetugid() == 0)
335                 tempdir = getenv("TMPDIR");
336         if (tempdir == NULL)
337                 tempdir = _PATH_TMP;
338         archive_string_init(&tempfile);
339         archive_strcpy(&tempfile, tempdir);
340         archive_strcat(&tempfile, "tar.md.XXXXXX");
341         tempfd = mkstemp(tempfile.s);
342         if (tempfd < 0) {
343                 archive_set_error(&a->archive, errno,
344                     "Could not open extended attribute file");
345                 ret = ARCHIVE_WARN;
346                 goto cleanup;
347         }
348         __archive_ensure_cloexec_flag(tempfd);
349
350         /* XXX I wish copyfile() could pack directly to a memory
351          * buffer; that would avoid the temp file here.  For that
352          * matter, it would be nice if fcopyfile() actually worked,
353          * that would reduce the many open/close races here. */
354         if (copyfile(name, tempfile.s, 0, copyfile_flags | COPYFILE_PACK)) {
355                 archive_set_error(&a->archive, errno,
356                     "Could not pack extended attributes");
357                 ret = ARCHIVE_WARN;
358                 goto cleanup;
359         }
360         if (fstat(tempfd, &copyfile_stat)) {
361                 archive_set_error(&a->archive, errno,
362                     "Could not check size of extended attributes");
363                 ret = ARCHIVE_WARN;
364                 goto cleanup;
365         }
366         buff = malloc(copyfile_stat.st_size);
367         if (buff == NULL) {
368                 archive_set_error(&a->archive, errno,
369                     "Could not allocate memory for extended attributes");
370                 ret = ARCHIVE_WARN;
371                 goto cleanup;
372         }
373         if (copyfile_stat.st_size != read(tempfd, buff, copyfile_stat.st_size)) {
374                 archive_set_error(&a->archive, errno,
375                     "Could not read extended attributes into memory");
376                 ret = ARCHIVE_WARN;
377                 goto cleanup;
378         }
379         archive_entry_copy_mac_metadata(entry, buff, copyfile_stat.st_size);
380
381 cleanup:
382         if (tempfd >= 0) {
383                 close(tempfd);
384                 unlink(tempfile.s);
385         }
386         archive_string_free(&tempfile);
387         free(buff);
388         return (ret);
389 }
390
391 #else
392
393 /*
394  * Stub implementation for non-Mac systems.
395  */
396 static int
397 setup_mac_metadata(struct archive_read_disk *a,
398     struct archive_entry *entry, int *fd)
399 {
400         (void)a; /* UNUSED */
401         (void)entry; /* UNUSED */
402         (void)fd; /* UNUSED */
403         return (ARCHIVE_OK);
404 }
405 #endif
406
407
408 #ifdef HAVE_POSIX_ACL
409 static int translate_acl(struct archive_read_disk *a,
410     struct archive_entry *entry, acl_t acl, int archive_entry_acl_type);
411
412 static int
413 setup_acls(struct archive_read_disk *a,
414     struct archive_entry *entry, int *fd)
415 {
416         const char      *accpath;
417         acl_t            acl;
418         int             r;
419
420         accpath = archive_entry_sourcepath(entry);
421         if (accpath == NULL)
422                 accpath = archive_entry_pathname(entry);
423
424         if (*fd < 0 && a->tree != NULL) {
425                 if (a->follow_symlinks ||
426                     archive_entry_filetype(entry) != AE_IFLNK)
427                         *fd = a->open_on_current_dir(a->tree,
428                             accpath, O_RDONLY | O_NONBLOCK);
429                 if (*fd < 0) {
430                         if (a->tree_enter_working_dir(a->tree) != 0) {
431                                 archive_set_error(&a->archive, errno,
432                                     "Couldn't access %s", accpath);
433                                 return (ARCHIVE_FAILED);
434                         }
435                 }
436         }
437
438         archive_entry_acl_clear(entry);
439
440         acl = NULL;
441
442 #ifdef ACL_TYPE_NFS4
443         /* Try NFS4 ACL first. */
444         if (*fd >= 0)
445 #if HAVE_ACL_GET_FD_NP
446                 acl = acl_get_fd_np(*fd, ACL_TYPE_NFS4);
447 #else
448                 acl = acl_get_fd(*fd);
449 #endif
450 #if HAVE_ACL_GET_LINK_NP
451         else if (!a->follow_symlinks)
452                 acl = acl_get_link_np(accpath, ACL_TYPE_NFS4);
453 #else
454         else if ((!a->follow_symlinks)
455             && (archive_entry_filetype(entry) == AE_IFLNK))
456                 /* We can't get the ACL of a symlink, so we assume it can't
457                    have one. */
458                 acl = NULL;
459 #endif
460         else
461                 acl = acl_get_file(accpath, ACL_TYPE_NFS4);
462
463 #if HAVE_ACL_IS_TRIVIAL_NP
464         if (acl != NULL && acl_is_trivial_np(acl, &r) == 0) {
465                 /* Ignore "trivial" ACLs that just mirror the file mode. */
466                 if (r) {
467                         acl_free(acl);
468                         acl = NULL;
469                         /*
470                          * Simultaneous NFSv4 and POSIX.1e ACLs for the same
471                          * entry are not allowed, so we should return here
472                          */
473                         return (ARCHIVE_OK);
474                 }
475         }
476 #endif
477         if (acl != NULL) {
478                 r = translate_acl(a, entry, acl, ARCHIVE_ENTRY_ACL_TYPE_NFS4);
479                 acl_free(acl);
480                 if (r != ARCHIVE_OK) {
481                         archive_set_error(&a->archive, errno,
482                             "Couldn't translate NFSv4 ACLs: %s", accpath);
483                 }
484                 return (r);
485         }
486 #endif  /* ACL_TYPE_NFS4 */
487
488         /* Retrieve access ACL from file. */
489         if (*fd >= 0)
490                 acl = acl_get_fd(*fd);
491 #if HAVE_ACL_GET_LINK_NP
492         else if (!a->follow_symlinks)
493                 acl = acl_get_link_np(accpath, ACL_TYPE_ACCESS);
494 #else
495         else if ((!a->follow_symlinks)
496             && (archive_entry_filetype(entry) == AE_IFLNK))
497                 /* We can't get the ACL of a symlink, so we assume it can't
498                    have one. */
499                 acl = NULL;
500 #endif
501         else
502                 acl = acl_get_file(accpath, ACL_TYPE_ACCESS);
503
504 #if HAVE_ACL_IS_TRIVIAL_NP
505         /* Ignore "trivial" ACLs that just mirror the file mode. */
506         if (acl != NULL && acl_is_trivial_np(acl, &r) == 0) {
507                 if (r) {
508                         acl_free(acl);
509                         acl = NULL;
510                 }
511         }
512 #endif
513
514         if (acl != NULL) {
515                 r = translate_acl(a, entry, acl,
516                     ARCHIVE_ENTRY_ACL_TYPE_ACCESS);
517                 acl_free(acl);
518                 acl = NULL;
519                 if (r != ARCHIVE_OK) {
520                         archive_set_error(&a->archive, errno,
521                             "Couldn't translate access ACLs: %s", accpath);
522                         return (r);
523                 }
524         }
525
526         /* Only directories can have default ACLs. */
527         if (S_ISDIR(archive_entry_mode(entry))) {
528                 acl = acl_get_file(accpath, ACL_TYPE_DEFAULT);
529                 if (acl != NULL) {
530                         r = translate_acl(a, entry, acl,
531                             ARCHIVE_ENTRY_ACL_TYPE_DEFAULT);
532                         acl_free(acl);
533                         if (r != ARCHIVE_OK) {
534                                 archive_set_error(&a->archive, errno,
535                                     "Couldn't translate default ACLs: %s",
536                                     accpath);
537                                 return (r);
538                         }
539                 }
540         }
541         return (ARCHIVE_OK);
542 }
543
544 /*
545  * Translate system ACL into libarchive internal structure.
546  */
547
548 static struct {
549         int archive_perm;
550         int platform_perm;
551 } acl_perm_map[] = {
552         {ARCHIVE_ENTRY_ACL_EXECUTE, ACL_EXECUTE},
553         {ARCHIVE_ENTRY_ACL_WRITE, ACL_WRITE},
554         {ARCHIVE_ENTRY_ACL_READ, ACL_READ},
555 #ifdef ACL_TYPE_NFS4
556         {ARCHIVE_ENTRY_ACL_READ_DATA, ACL_READ_DATA},
557         {ARCHIVE_ENTRY_ACL_LIST_DIRECTORY, ACL_LIST_DIRECTORY},
558         {ARCHIVE_ENTRY_ACL_WRITE_DATA, ACL_WRITE_DATA},
559         {ARCHIVE_ENTRY_ACL_ADD_FILE, ACL_ADD_FILE},
560         {ARCHIVE_ENTRY_ACL_APPEND_DATA, ACL_APPEND_DATA},
561         {ARCHIVE_ENTRY_ACL_ADD_SUBDIRECTORY, ACL_ADD_SUBDIRECTORY},
562         {ARCHIVE_ENTRY_ACL_READ_NAMED_ATTRS, ACL_READ_NAMED_ATTRS},
563         {ARCHIVE_ENTRY_ACL_WRITE_NAMED_ATTRS, ACL_WRITE_NAMED_ATTRS},
564         {ARCHIVE_ENTRY_ACL_DELETE_CHILD, ACL_DELETE_CHILD},
565         {ARCHIVE_ENTRY_ACL_READ_ATTRIBUTES, ACL_READ_ATTRIBUTES},
566         {ARCHIVE_ENTRY_ACL_WRITE_ATTRIBUTES, ACL_WRITE_ATTRIBUTES},
567         {ARCHIVE_ENTRY_ACL_DELETE, ACL_DELETE},
568         {ARCHIVE_ENTRY_ACL_READ_ACL, ACL_READ_ACL},
569         {ARCHIVE_ENTRY_ACL_WRITE_ACL, ACL_WRITE_ACL},
570         {ARCHIVE_ENTRY_ACL_WRITE_OWNER, ACL_WRITE_OWNER},
571         {ARCHIVE_ENTRY_ACL_SYNCHRONIZE, ACL_SYNCHRONIZE}
572 #endif
573 };
574
575 #ifdef ACL_TYPE_NFS4
576 static struct {
577         int archive_inherit;
578         int platform_inherit;
579 } acl_inherit_map[] = {
580         {ARCHIVE_ENTRY_ACL_ENTRY_FILE_INHERIT, ACL_ENTRY_FILE_INHERIT},
581         {ARCHIVE_ENTRY_ACL_ENTRY_DIRECTORY_INHERIT, ACL_ENTRY_DIRECTORY_INHERIT},
582         {ARCHIVE_ENTRY_ACL_ENTRY_NO_PROPAGATE_INHERIT, ACL_ENTRY_NO_PROPAGATE_INHERIT},
583         {ARCHIVE_ENTRY_ACL_ENTRY_INHERIT_ONLY, ACL_ENTRY_INHERIT_ONLY}
584 };
585 #endif
586 static int
587 translate_acl(struct archive_read_disk *a,
588     struct archive_entry *entry, acl_t acl, int default_entry_acl_type)
589 {
590         acl_tag_t        acl_tag;
591 #ifdef ACL_TYPE_NFS4
592         acl_entry_type_t acl_type;
593         acl_flagset_t    acl_flagset;
594         int brand;
595 #endif
596         acl_entry_t      acl_entry;
597         acl_permset_t    acl_permset;
598         int              i, entry_acl_type;
599         int              r, s, ae_id, ae_tag, ae_perm;
600         const char      *ae_name;
601
602 #ifdef ACL_TYPE_NFS4
603         // FreeBSD "brands" ACLs as POSIX.1e or NFSv4
604         // Make sure the "brand" on this ACL is consistent
605         // with the default_entry_acl_type bits provided.
606         if (acl_get_brand_np(acl, &brand) != 0) {
607                 archive_set_error(&a->archive, errno,
608                     "Failed to read ACL brand");
609                 return (ARCHIVE_WARN);
610         }
611         switch (brand) {
612         case ACL_BRAND_POSIX:
613                 switch (default_entry_acl_type) {
614                 case ARCHIVE_ENTRY_ACL_TYPE_ACCESS:
615                 case ARCHIVE_ENTRY_ACL_TYPE_DEFAULT:
616                         break;
617                 default:
618                         archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
619                             "Invalid ACL entry type for POSIX.1e ACL");
620                         return (ARCHIVE_WARN);
621                 }
622                 break;
623         case ACL_BRAND_NFS4:
624                 if (default_entry_acl_type & ~ARCHIVE_ENTRY_ACL_TYPE_NFS4) {
625                         archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
626                             "Invalid ACL entry type for NFSv4 ACL");
627                         return (ARCHIVE_WARN);
628                 }
629                 break;
630         default:
631                 archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
632                     "Unknown ACL brand");
633                 return (ARCHIVE_WARN);
634         }
635 #endif
636
637
638         s = acl_get_entry(acl, ACL_FIRST_ENTRY, &acl_entry);
639         if (s == -1) {
640                 archive_set_error(&a->archive, errno,
641                     "Failed to get first ACL entry");
642                 return (ARCHIVE_WARN);
643         }
644         while (s == 1) {
645                 ae_id = -1;
646                 ae_name = NULL;
647                 ae_perm = 0;
648
649                 if (acl_get_tag_type(acl_entry, &acl_tag) != 0) {
650                         archive_set_error(&a->archive, errno,
651                             "Failed to get ACL tag type");
652                         return (ARCHIVE_WARN);
653                 }
654                 switch (acl_tag) {
655                 case ACL_USER:
656                         ae_id = (int)*(uid_t *)acl_get_qualifier(acl_entry);
657                         ae_name = archive_read_disk_uname(&a->archive, ae_id);
658                         ae_tag = ARCHIVE_ENTRY_ACL_USER;
659                         break;
660                 case ACL_GROUP:
661                         ae_id = (int)*(gid_t *)acl_get_qualifier(acl_entry);
662                         ae_name = archive_read_disk_gname(&a->archive, ae_id);
663                         ae_tag = ARCHIVE_ENTRY_ACL_GROUP;
664                         break;
665                 case ACL_MASK:
666                         ae_tag = ARCHIVE_ENTRY_ACL_MASK;
667                         break;
668                 case ACL_USER_OBJ:
669                         ae_tag = ARCHIVE_ENTRY_ACL_USER_OBJ;
670                         break;
671                 case ACL_GROUP_OBJ:
672                         ae_tag = ARCHIVE_ENTRY_ACL_GROUP_OBJ;
673                         break;
674                 case ACL_OTHER:
675                         ae_tag = ARCHIVE_ENTRY_ACL_OTHER;
676                         break;
677 #ifdef ACL_TYPE_NFS4
678                 case ACL_EVERYONE:
679                         ae_tag = ARCHIVE_ENTRY_ACL_EVERYONE;
680                         break;
681 #endif
682                 default:
683                         /* Skip types that libarchive can't support. */
684                         s = acl_get_entry(acl, ACL_NEXT_ENTRY, &acl_entry);
685                         continue;
686                 }
687
688                 // XXX acl_type maps to allow/deny/audit/YYYY bits
689                 entry_acl_type = default_entry_acl_type;
690 #ifdef ACL_TYPE_NFS4
691                 if (default_entry_acl_type & ARCHIVE_ENTRY_ACL_TYPE_NFS4) {
692                         /*
693                          * acl_get_entry_type_np() fails with non-NFSv4 ACLs
694                          */
695                         if (acl_get_entry_type_np(acl_entry, &acl_type) != 0) {
696                                 archive_set_error(&a->archive, errno, "Failed "
697                                     "to get ACL type from a NFSv4 ACL entry");
698                                 return (ARCHIVE_WARN);
699                         }
700                         switch (acl_type) {
701                         case ACL_ENTRY_TYPE_ALLOW:
702                                 entry_acl_type = ARCHIVE_ENTRY_ACL_TYPE_ALLOW;
703                                 break;
704                         case ACL_ENTRY_TYPE_DENY:
705                                 entry_acl_type = ARCHIVE_ENTRY_ACL_TYPE_DENY;
706                                 break;
707                         case ACL_ENTRY_TYPE_AUDIT:
708                                 entry_acl_type = ARCHIVE_ENTRY_ACL_TYPE_AUDIT;
709                                 break;
710                         case ACL_ENTRY_TYPE_ALARM:
711                                 entry_acl_type = ARCHIVE_ENTRY_ACL_TYPE_ALARM;
712                                 break;
713                         default:
714                                 archive_set_error(&a->archive, errno,
715                                     "Invalid NFSv4 ACL entry type");
716                                 return (ARCHIVE_WARN);
717                         }
718
719                         /*
720                          * Libarchive stores "flag" (NFSv4 inheritance bits)
721                          * in the ae_perm bitmap.
722                          *
723                          * acl_get_flagset_np() fails with non-NFSv4 ACLs
724                          */
725                         if (acl_get_flagset_np(acl_entry, &acl_flagset) != 0) {
726                                 archive_set_error(&a->archive, errno,
727                                     "Failed to get flagset from a NFSv4 ACL entry");
728                                 return (ARCHIVE_WARN);
729                         }
730                         for (i = 0; i < (int)(sizeof(acl_inherit_map) / sizeof(acl_inherit_map[0])); ++i) {
731                                 r = acl_get_flag_np(acl_flagset,
732                                     acl_inherit_map[i].platform_inherit);
733                                 if (r == -1) {
734                                         archive_set_error(&a->archive, errno,
735                                             "Failed to check flag in a NFSv4 "
736                                             "ACL flagset");
737                                         return (ARCHIVE_WARN);
738                                 } else if (r)
739                                         ae_perm |= acl_inherit_map[i].archive_inherit;
740                         }
741                 }
742 #endif
743
744                 if (acl_get_permset(acl_entry, &acl_permset) != 0) {
745                         archive_set_error(&a->archive, errno,
746                             "Failed to get ACL permission set");
747                         return (ARCHIVE_WARN);
748                 }
749                 for (i = 0; i < (int)(sizeof(acl_perm_map) / sizeof(acl_perm_map[0])); ++i) {
750                         /*
751                          * acl_get_perm() is spelled differently on different
752                          * platforms; see above.
753                          */
754                         r = ACL_GET_PERM(acl_permset, acl_perm_map[i].platform_perm);
755                         if (r == -1) {
756                                 archive_set_error(&a->archive, errno,
757                                     "Failed to check permission in an ACL permission set");
758                                 return (ARCHIVE_WARN);
759                         } else if (r)
760                                 ae_perm |= acl_perm_map[i].archive_perm;
761                 }
762
763                 archive_entry_acl_add_entry(entry, entry_acl_type,
764                                             ae_perm, ae_tag,
765                                             ae_id, ae_name);
766
767                 s = acl_get_entry(acl, ACL_NEXT_ENTRY, &acl_entry);
768                 if (s == -1) {
769                         archive_set_error(&a->archive, errno,
770                             "Failed to get next ACL entry");
771                         return (ARCHIVE_WARN);
772                 }
773         }
774         return (ARCHIVE_OK);
775 }
776 #else
777 static int
778 setup_acls(struct archive_read_disk *a,
779     struct archive_entry *entry, int *fd)
780 {
781         (void)a;      /* UNUSED */
782         (void)entry;  /* UNUSED */
783         (void)fd;     /* UNUSED */
784         return (ARCHIVE_OK);
785 }
786 #endif
787
788 #if (HAVE_FGETXATTR && HAVE_FLISTXATTR && HAVE_LISTXATTR && \
789     HAVE_LLISTXATTR && HAVE_GETXATTR && HAVE_LGETXATTR) || \
790     (HAVE_FGETEA && HAVE_FLISTEA && HAVE_LISTEA)
791
792 /*
793  * Linux and AIX extended attribute support.
794  *
795  * TODO:  By using a stack-allocated buffer for the first
796  * call to getxattr(), we might be able to avoid the second
797  * call entirely.  We only need the second call if the
798  * stack-allocated buffer is too small.  But a modest buffer
799  * of 1024 bytes or so will often be big enough.  Same applies
800  * to listxattr().
801  */
802
803
804 static int
805 setup_xattr(struct archive_read_disk *a,
806     struct archive_entry *entry, const char *name, int fd)
807 {
808         ssize_t size;
809         void *value = NULL;
810         const char *accpath;
811
812         accpath = archive_entry_sourcepath(entry);
813         if (accpath == NULL)
814                 accpath = archive_entry_pathname(entry);
815
816 #if HAVE_FGETXATTR
817         if (fd >= 0)
818                 size = fgetxattr(fd, name, NULL, 0);
819         else if (!a->follow_symlinks)
820                 size = lgetxattr(accpath, name, NULL, 0);
821         else
822                 size = getxattr(accpath, name, NULL, 0);
823 #elif HAVE_FGETEA
824         if (fd >= 0)
825                 size = fgetea(fd, name, NULL, 0);
826         else if (!a->follow_symlinks)
827                 size = lgetea(accpath, name, NULL, 0);
828         else
829                 size = getea(accpath, name, NULL, 0);
830 #endif
831
832         if (size == -1) {
833                 archive_set_error(&a->archive, errno,
834                     "Couldn't query extended attribute");
835                 return (ARCHIVE_WARN);
836         }
837
838         if (size > 0 && (value = malloc(size)) == NULL) {
839                 archive_set_error(&a->archive, errno, "Out of memory");
840                 return (ARCHIVE_FATAL);
841         }
842
843 #if HAVE_FGETXATTR
844         if (fd >= 0)
845                 size = fgetxattr(fd, name, value, size);
846         else if (!a->follow_symlinks)
847                 size = lgetxattr(accpath, name, value, size);
848         else
849                 size = getxattr(accpath, name, value, size);
850 #elif HAVE_FGETEA
851         if (fd >= 0)
852                 size = fgetea(fd, name, value, size);
853         else if (!a->follow_symlinks)
854                 size = lgetea(accpath, name, value, size);
855         else
856                 size = getea(accpath, name, value, size);
857 #endif
858
859         if (size == -1) {
860                 archive_set_error(&a->archive, errno,
861                     "Couldn't read extended attribute");
862                 return (ARCHIVE_WARN);
863         }
864
865         archive_entry_xattr_add_entry(entry, name, value, size);
866
867         free(value);
868         return (ARCHIVE_OK);
869 }
870
871 static int
872 setup_xattrs(struct archive_read_disk *a,
873     struct archive_entry *entry, int *fd)
874 {
875         char *list, *p;
876         const char *path;
877         ssize_t list_size;
878
879         path = archive_entry_sourcepath(entry);
880         if (path == NULL)
881                 path = archive_entry_pathname(entry);
882
883         if (*fd < 0 && a->tree != NULL) {
884                 if (a->follow_symlinks ||
885                     archive_entry_filetype(entry) != AE_IFLNK)
886                         *fd = a->open_on_current_dir(a->tree, path,
887                                 O_RDONLY | O_NONBLOCK);
888                 if (*fd < 0) {
889                         if (a->tree_enter_working_dir(a->tree) != 0) {
890                                 archive_set_error(&a->archive, errno,
891                                     "Couldn't access %s", path);
892                                 return (ARCHIVE_FAILED);
893                         }
894                 }
895         }
896
897 #if HAVE_FLISTXATTR
898         if (*fd >= 0)
899                 list_size = flistxattr(*fd, NULL, 0);
900         else if (!a->follow_symlinks)
901                 list_size = llistxattr(path, NULL, 0);
902         else
903                 list_size = listxattr(path, NULL, 0);
904 #elif HAVE_FLISTEA
905         if (*fd >= 0)
906                 list_size = flistea(*fd, NULL, 0);
907         else if (!a->follow_symlinks)
908                 list_size = llistea(path, NULL, 0);
909         else
910                 list_size = listea(path, NULL, 0);
911 #endif
912
913         if (list_size == -1) {
914                 if (errno == ENOTSUP || errno == ENOSYS)
915                         return (ARCHIVE_OK);
916                 archive_set_error(&a->archive, errno,
917                         "Couldn't list extended attributes");
918                 return (ARCHIVE_WARN);
919         }
920
921         if (list_size == 0)
922                 return (ARCHIVE_OK);
923
924         if ((list = malloc(list_size)) == NULL) {
925                 archive_set_error(&a->archive, errno, "Out of memory");
926                 return (ARCHIVE_FATAL);
927         }
928
929 #if HAVE_FLISTXATTR
930         if (*fd >= 0)
931                 list_size = flistxattr(*fd, list, list_size);
932         else if (!a->follow_symlinks)
933                 list_size = llistxattr(path, list, list_size);
934         else
935                 list_size = listxattr(path, list, list_size);
936 #elif HAVE_FLISTEA
937         if (*fd >= 0)
938                 list_size = flistea(*fd, list, list_size);
939         else if (!a->follow_symlinks)
940                 list_size = llistea(path, list, list_size);
941         else
942                 list_size = listea(path, list, list_size);
943 #endif
944
945         if (list_size == -1) {
946                 archive_set_error(&a->archive, errno,
947                         "Couldn't retrieve extended attributes");
948                 free(list);
949                 return (ARCHIVE_WARN);
950         }
951
952         for (p = list; (p - list) < list_size; p += strlen(p) + 1) {
953                 if (strncmp(p, "system.", 7) == 0 ||
954                                 strncmp(p, "xfsroot.", 8) == 0)
955                         continue;
956                 setup_xattr(a, entry, p, *fd);
957         }
958
959         free(list);
960         return (ARCHIVE_OK);
961 }
962
963 #elif HAVE_EXTATTR_GET_FILE && HAVE_EXTATTR_LIST_FILE && \
964     HAVE_DECL_EXTATTR_NAMESPACE_USER
965
966 /*
967  * FreeBSD extattr interface.
968  */
969
970 /* TODO: Implement this.  Follow the Linux model above, but
971  * with FreeBSD-specific system calls, of course.  Be careful
972  * to not include the system extattrs that hold ACLs; we handle
973  * those separately.
974  */
975 static int
976 setup_xattr(struct archive_read_disk *a, struct archive_entry *entry,
977     int namespace, const char *name, const char *fullname, int fd);
978
979 static int
980 setup_xattr(struct archive_read_disk *a, struct archive_entry *entry,
981     int namespace, const char *name, const char *fullname, int fd)
982 {
983         ssize_t size;
984         void *value = NULL;
985         const char *accpath;
986
987         accpath = archive_entry_sourcepath(entry);
988         if (accpath == NULL)
989                 accpath = archive_entry_pathname(entry);
990
991         if (fd >= 0)
992                 size = extattr_get_fd(fd, namespace, name, NULL, 0);
993         else if (!a->follow_symlinks)
994                 size = extattr_get_link(accpath, namespace, name, NULL, 0);
995         else
996                 size = extattr_get_file(accpath, namespace, name, NULL, 0);
997
998         if (size == -1) {
999                 archive_set_error(&a->archive, errno,
1000                     "Couldn't query extended attribute");
1001                 return (ARCHIVE_WARN);
1002         }
1003
1004         if (size > 0 && (value = malloc(size)) == NULL) {
1005                 archive_set_error(&a->archive, errno, "Out of memory");
1006                 return (ARCHIVE_FATAL);
1007         }
1008
1009         if (fd >= 0)
1010                 size = extattr_get_fd(fd, namespace, name, value, size);
1011         else if (!a->follow_symlinks)
1012                 size = extattr_get_link(accpath, namespace, name, value, size);
1013         else
1014                 size = extattr_get_file(accpath, namespace, name, value, size);
1015
1016         if (size == -1) {
1017                 free(value);
1018                 archive_set_error(&a->archive, errno,
1019                     "Couldn't read extended attribute");
1020                 return (ARCHIVE_WARN);
1021         }
1022
1023         archive_entry_xattr_add_entry(entry, fullname, value, size);
1024
1025         free(value);
1026         return (ARCHIVE_OK);
1027 }
1028
1029 static int
1030 setup_xattrs(struct archive_read_disk *a,
1031     struct archive_entry *entry, int *fd)
1032 {
1033         char buff[512];
1034         char *list, *p;
1035         ssize_t list_size;
1036         const char *path;
1037         int namespace = EXTATTR_NAMESPACE_USER;
1038
1039         path = archive_entry_sourcepath(entry);
1040         if (path == NULL)
1041                 path = archive_entry_pathname(entry);
1042
1043         if (*fd < 0 && a->tree != NULL) {
1044                 if (a->follow_symlinks ||
1045                     archive_entry_filetype(entry) != AE_IFLNK)
1046                         *fd = a->open_on_current_dir(a->tree, path,
1047                                 O_RDONLY | O_NONBLOCK);
1048                 if (*fd < 0) {
1049                         if (a->tree_enter_working_dir(a->tree) != 0) {
1050                                 archive_set_error(&a->archive, errno,
1051                                     "Couldn't access %s", path);
1052                                 return (ARCHIVE_FAILED);
1053                         }
1054                 }
1055         }
1056
1057         if (*fd >= 0)
1058                 list_size = extattr_list_fd(*fd, namespace, NULL, 0);
1059         else if (!a->follow_symlinks)
1060                 list_size = extattr_list_link(path, namespace, NULL, 0);
1061         else
1062                 list_size = extattr_list_file(path, namespace, NULL, 0);
1063
1064         if (list_size == -1 && errno == EOPNOTSUPP)
1065                 return (ARCHIVE_OK);
1066         if (list_size == -1) {
1067                 archive_set_error(&a->archive, errno,
1068                         "Couldn't list extended attributes");
1069                 return (ARCHIVE_WARN);
1070         }
1071
1072         if (list_size == 0)
1073                 return (ARCHIVE_OK);
1074
1075         if ((list = malloc(list_size)) == NULL) {
1076                 archive_set_error(&a->archive, errno, "Out of memory");
1077                 return (ARCHIVE_FATAL);
1078         }
1079
1080         if (*fd >= 0)
1081                 list_size = extattr_list_fd(*fd, namespace, list, list_size);
1082         else if (!a->follow_symlinks)
1083                 list_size = extattr_list_link(path, namespace, list, list_size);
1084         else
1085                 list_size = extattr_list_file(path, namespace, list, list_size);
1086
1087         if (list_size == -1) {
1088                 archive_set_error(&a->archive, errno,
1089                         "Couldn't retrieve extended attributes");
1090                 free(list);
1091                 return (ARCHIVE_WARN);
1092         }
1093
1094         p = list;
1095         while ((p - list) < list_size) {
1096                 size_t len = 255 & (int)*p;
1097                 char *name;
1098
1099                 strcpy(buff, "user.");
1100                 name = buff + strlen(buff);
1101                 memcpy(name, p + 1, len);
1102                 name[len] = '\0';
1103                 setup_xattr(a, entry, namespace, name, buff, *fd);
1104                 p += 1 + len;
1105         }
1106
1107         free(list);
1108         return (ARCHIVE_OK);
1109 }
1110
1111 #else
1112
1113 /*
1114  * Generic (stub) extended attribute support.
1115  */
1116 static int
1117 setup_xattrs(struct archive_read_disk *a,
1118     struct archive_entry *entry, int *fd)
1119 {
1120         (void)a;     /* UNUSED */
1121         (void)entry; /* UNUSED */
1122         (void)fd;    /* UNUSED */
1123         return (ARCHIVE_OK);
1124 }
1125
1126 #endif
1127
1128 #if defined(HAVE_LINUX_FIEMAP_H)
1129
1130 /*
1131  * Linux FIEMAP sparse interface.
1132  *
1133  * The FIEMAP ioctl returns an "extent" for each physical allocation
1134  * on disk.  We need to process those to generate a more compact list
1135  * of logical file blocks.  We also need to be very careful to use
1136  * FIEMAP_FLAG_SYNC here, since there are reports that Linux sometimes
1137  * does not report allocations for newly-written data that hasn't
1138  * been synced to disk.
1139  *
1140  * It's important to return a minimal sparse file list because we want
1141  * to not trigger sparse file extensions if we don't have to, since
1142  * not all readers support them.
1143  */
1144
1145 static int
1146 setup_sparse_fiemap(struct archive_read_disk *a,
1147     struct archive_entry *entry, int *fd)
1148 {
1149         char buff[4096];
1150         struct fiemap *fm;
1151         struct fiemap_extent *fe;
1152         int64_t size;
1153         int count, do_fiemap, iters;
1154         int exit_sts = ARCHIVE_OK;
1155
1156         if (archive_entry_filetype(entry) != AE_IFREG
1157             || archive_entry_size(entry) <= 0
1158             || archive_entry_hardlink(entry) != NULL)
1159                 return (ARCHIVE_OK);
1160
1161         if (*fd < 0) {
1162                 const char *path;
1163
1164                 path = archive_entry_sourcepath(entry);
1165                 if (path == NULL)
1166                         path = archive_entry_pathname(entry);
1167                 if (a->tree != NULL)
1168                         *fd = a->open_on_current_dir(a->tree, path,
1169                                 O_RDONLY | O_NONBLOCK | O_CLOEXEC);
1170                 else
1171                         *fd = open(path, O_RDONLY | O_NONBLOCK | O_CLOEXEC);
1172                 if (*fd < 0) {
1173                         archive_set_error(&a->archive, errno,
1174                             "Can't open `%s'", path);
1175                         return (ARCHIVE_FAILED);
1176                 }
1177                 __archive_ensure_cloexec_flag(*fd);
1178         }
1179
1180         /* Initialize buffer to avoid the error valgrind complains about. */
1181         memset(buff, 0, sizeof(buff));
1182         count = (sizeof(buff) - sizeof(*fm))/sizeof(*fe);
1183         fm = (struct fiemap *)buff;
1184         fm->fm_start = 0;
1185         fm->fm_length = ~0ULL;;
1186         fm->fm_flags = FIEMAP_FLAG_SYNC;
1187         fm->fm_extent_count = count;
1188         do_fiemap = 1;
1189         size = archive_entry_size(entry);
1190         for (iters = 0; ; ++iters) {
1191                 int i, r;
1192
1193                 r = ioctl(*fd, FS_IOC_FIEMAP, fm); 
1194                 if (r < 0) {
1195                         /* When something error happens, it is better we
1196                          * should return ARCHIVE_OK because an earlier
1197                          * version(<2.6.28) cannot perform FS_IOC_FIEMAP. */
1198                         goto exit_setup_sparse_fiemap;
1199                 }
1200                 if (fm->fm_mapped_extents == 0) {
1201                         if (iters == 0) {
1202                                 /* Fully sparse file; insert a zero-length "data" entry */
1203                                 archive_entry_sparse_add_entry(entry, 0, 0);
1204                         }
1205                         break;
1206                 }
1207                 fe = fm->fm_extents;
1208                 for (i = 0; i < (int)fm->fm_mapped_extents; i++, fe++) {
1209                         if (!(fe->fe_flags & FIEMAP_EXTENT_UNWRITTEN)) {
1210                                 /* The fe_length of the last block does not
1211                                  * adjust itself to its size files. */
1212                                 int64_t length = fe->fe_length;
1213                                 if (fe->fe_logical + length > (uint64_t)size)
1214                                         length -= fe->fe_logical + length - size;
1215                                 if (fe->fe_logical == 0 && length == size) {
1216                                         /* This is not sparse. */
1217                                         do_fiemap = 0;
1218                                         break;
1219                                 }
1220                                 if (length > 0)
1221                                         archive_entry_sparse_add_entry(entry,
1222                                             fe->fe_logical, length);
1223                         }
1224                         if (fe->fe_flags & FIEMAP_EXTENT_LAST)
1225                                 do_fiemap = 0;
1226                 }
1227                 if (do_fiemap) {
1228                         fe = fm->fm_extents + fm->fm_mapped_extents -1;
1229                         fm->fm_start = fe->fe_logical + fe->fe_length;
1230                 } else
1231                         break;
1232         }
1233 exit_setup_sparse_fiemap:
1234         return (exit_sts);
1235 }
1236
1237 #if !defined(SEEK_HOLE) || !defined(SEEK_DATA)
1238 static int
1239 setup_sparse(struct archive_read_disk *a,
1240     struct archive_entry *entry, int *fd)
1241 {
1242         return setup_sparse_fiemap(a, entry, fd);
1243 }
1244 #endif
1245 #endif  /* defined(HAVE_LINUX_FIEMAP_H) */
1246
1247 #if defined(SEEK_HOLE) && defined(SEEK_DATA)
1248
1249 /*
1250  * SEEK_HOLE sparse interface (FreeBSD, Linux, Solaris)
1251  */
1252
1253 static int
1254 setup_sparse(struct archive_read_disk *a,
1255     struct archive_entry *entry, int *fd)
1256 {
1257         int64_t size;
1258         off_t initial_off;
1259         off_t off_s, off_e;
1260         int exit_sts = ARCHIVE_OK;
1261         int check_fully_sparse = 0;
1262
1263         if (archive_entry_filetype(entry) != AE_IFREG
1264             || archive_entry_size(entry) <= 0
1265             || archive_entry_hardlink(entry) != NULL)
1266                 return (ARCHIVE_OK);
1267
1268         /* Does filesystem support the reporting of hole ? */
1269         if (*fd < 0 && a->tree != NULL) {
1270                 const char *path;
1271
1272                 path = archive_entry_sourcepath(entry);
1273                 if (path == NULL)
1274                         path = archive_entry_pathname(entry);
1275                 *fd = a->open_on_current_dir(a->tree, path,
1276                                 O_RDONLY | O_NONBLOCK);
1277                 if (*fd < 0) {
1278                         archive_set_error(&a->archive, errno,
1279                             "Can't open `%s'", path);
1280                         return (ARCHIVE_FAILED);
1281                 }
1282         }
1283
1284         if (*fd >= 0) {
1285 #ifdef _PC_MIN_HOLE_SIZE
1286                 if (fpathconf(*fd, _PC_MIN_HOLE_SIZE) <= 0)
1287                         return (ARCHIVE_OK);
1288 #endif
1289                 initial_off = lseek(*fd, 0, SEEK_CUR);
1290                 if (initial_off != 0)
1291                         lseek(*fd, 0, SEEK_SET);
1292         } else {
1293                 const char *path;
1294
1295                 path = archive_entry_sourcepath(entry);
1296                 if (path == NULL)
1297                         path = archive_entry_pathname(entry);
1298                         
1299 #ifdef _PC_MIN_HOLE_SIZE
1300                 if (pathconf(path, _PC_MIN_HOLE_SIZE) <= 0)
1301                         return (ARCHIVE_OK);
1302 #endif
1303                 *fd = open(path, O_RDONLY | O_NONBLOCK | O_CLOEXEC);
1304                 if (*fd < 0) {
1305                         archive_set_error(&a->archive, errno,
1306                             "Can't open `%s'", path);
1307                         return (ARCHIVE_FAILED);
1308                 }
1309                 __archive_ensure_cloexec_flag(*fd);
1310                 initial_off = 0;
1311         }
1312
1313 #ifndef _PC_MIN_HOLE_SIZE
1314         /* Check if the underlying filesystem supports seek hole */
1315         off_s = lseek(*fd, 0, SEEK_HOLE);
1316         if (off_s < 0)
1317 #if defined(HAVE_LINUX_FIEMAP_H)
1318                 return setup_sparse_fiemap(a, entry, fd);
1319 #else
1320                 goto exit_setup_sparse;
1321 #endif
1322         else if (off_s > 0)
1323                 lseek(*fd, 0, SEEK_SET);
1324 #endif
1325
1326         off_s = 0;
1327         size = archive_entry_size(entry);
1328         while (off_s < size) {
1329                 off_s = lseek(*fd, off_s, SEEK_DATA);
1330                 if (off_s == (off_t)-1) {
1331                         if (errno == ENXIO) {
1332                                 /* no more hole */
1333                                 if (archive_entry_sparse_count(entry) == 0) {
1334                                         /* Potentially a fully-sparse file. */
1335                                         check_fully_sparse = 1;
1336                                 }
1337                                 break;
1338                         }
1339                         archive_set_error(&a->archive, errno,
1340                             "lseek(SEEK_HOLE) failed");
1341                         exit_sts = ARCHIVE_FAILED;
1342                         goto exit_setup_sparse;
1343                 }
1344                 off_e = lseek(*fd, off_s, SEEK_HOLE);
1345                 if (off_e == (off_t)-1) {
1346                         if (errno == ENXIO) {
1347                                 off_e = lseek(*fd, 0, SEEK_END);
1348                                 if (off_e != (off_t)-1)
1349                                         break;/* no more data */
1350                         }
1351                         archive_set_error(&a->archive, errno,
1352                             "lseek(SEEK_DATA) failed");
1353                         exit_sts = ARCHIVE_FAILED;
1354                         goto exit_setup_sparse;
1355                 }
1356                 if (off_s == 0 && off_e == size)
1357                         break;/* This is not sparse. */
1358                 archive_entry_sparse_add_entry(entry, off_s,
1359                         off_e - off_s);
1360                 off_s = off_e;
1361         }
1362
1363         if (check_fully_sparse) {
1364                 if (lseek(*fd, 0, SEEK_HOLE) == 0 &&
1365                         lseek(*fd, 0, SEEK_END) == size) {
1366                         /* Fully sparse file; insert a zero-length "data" entry */
1367                         archive_entry_sparse_add_entry(entry, 0, 0);
1368                 }
1369         }
1370 exit_setup_sparse:
1371         lseek(*fd, initial_off, SEEK_SET);
1372         return (exit_sts);
1373 }
1374
1375 #elif !defined(HAVE_LINUX_FIEMAP_H)
1376
1377 /*
1378  * Generic (stub) sparse support.
1379  */
1380 static int
1381 setup_sparse(struct archive_read_disk *a,
1382     struct archive_entry *entry, int *fd)
1383 {
1384         (void)a;     /* UNUSED */
1385         (void)entry; /* UNUSED */
1386         (void)fd;    /* UNUSED */
1387         return (ARCHIVE_OK);
1388 }
1389
1390 #endif
1391
1392 #endif /* !defined(_WIN32) || defined(__CYGWIN__) */
1393