libarchive-static 1.0.6 → 1.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/ext/extconf.rb +2 -9
- data/ext/libarchive-0.1.1/ext/archive_read_support_compression.c +6 -6
- data/ext/libarchive-0.1.1/ext/archive_read_support_compression.o +0 -0
- data/ext/libarchive-0.1.1/ext/archive_read_support_format.o +0 -0
- data/ext/libarchive-0.1.1/ext/archive_write_open_rb_str.c +1 -1
- data/ext/libarchive-0.1.1/ext/archive_write_open_rb_str.o +0 -0
- data/ext/libarchive-0.1.1/ext/archive_write_set_compression.c +5 -5
- data/ext/libarchive-0.1.1/ext/archive_write_set_compression.o +0 -0
- data/ext/libarchive-0.1.1/ext/config.h +23 -0
- data/ext/libarchive-0.1.1/ext/config.log +230 -0
- data/ext/libarchive-0.1.1/ext/config.status +671 -0
- data/ext/libarchive-0.1.1/ext/libarchive.c +1 -1
- data/ext/libarchive-0.1.1/ext/libarchive.o +0 -0
- data/ext/libarchive-0.1.1/ext/libarchive_archive.c +7 -7
- data/ext/libarchive-0.1.1/ext/libarchive_archive.o +0 -0
- data/ext/libarchive-0.1.1/ext/libarchive_entry.c +6 -0
- data/ext/libarchive-0.1.1/ext/libarchive_entry.o +0 -0
- data/ext/libarchive-0.1.1/ext/libarchive_reader.c +6 -4
- data/ext/libarchive-0.1.1/ext/libarchive_reader.o +0 -0
- data/ext/libarchive-0.1.1/ext/libarchive_ruby.so +0 -0
- data/ext/libarchive-0.1.1/ext/libarchive_win32.h +1 -1
- data/ext/libarchive-0.1.1/ext/libarchive_writer.c +2 -2
- data/ext/libarchive-0.1.1/ext/libarchive_writer.o +0 -0
- data/ext/libarchive-3.6.2/Makefile.in +16892 -0
- data/ext/libarchive-3.6.2/build/autoconf/ax_append_compile_flags.m4 +67 -0
- data/ext/libarchive-3.6.2/build/autoconf/ax_append_flag.m4 +71 -0
- data/ext/libarchive-3.6.2/build/autoconf/ax_check_compile_flag.m4 +74 -0
- data/ext/libarchive-3.6.2/build/autoconf/ax_require_defined.m4 +37 -0
- data/ext/{libarchive-2.8.4 → libarchive-3.6.2}/build/autoconf/check_stdcall_func.m4 +0 -0
- data/ext/libarchive-3.6.2/build/autoconf/compile +348 -0
- data/ext/libarchive-3.6.2/build/autoconf/config.guess +1754 -0
- data/ext/libarchive-3.6.2/build/autoconf/config.rpath +696 -0
- data/ext/libarchive-3.6.2/build/autoconf/config.sub +1890 -0
- data/ext/libarchive-3.6.2/build/autoconf/depcomp +791 -0
- data/ext/libarchive-3.6.2/build/autoconf/iconv.m4 +271 -0
- data/ext/libarchive-3.6.2/build/autoconf/install-sh +541 -0
- data/ext/{libarchive-2.8.4 → libarchive-3.6.2}/build/autoconf/la_uid_t.m4 +0 -0
- data/ext/libarchive-3.6.2/build/autoconf/lib-ld.m4 +109 -0
- data/ext/libarchive-3.6.2/build/autoconf/lib-link.m4 +777 -0
- data/ext/libarchive-3.6.2/build/autoconf/lib-prefix.m4 +224 -0
- data/ext/libarchive-3.6.2/build/autoconf/ltmain.sh +11251 -0
- data/ext/libarchive-3.6.2/build/autoconf/m4_ax_compile_check_sizeof.m4 +115 -0
- data/ext/libarchive-3.6.2/build/autoconf/missing +215 -0
- data/ext/libarchive-3.6.2/build/autoconf/test-driver +153 -0
- data/ext/{libarchive-2.8.4 → libarchive-3.6.2}/build/pkgconfig/libarchive.pc.in +4 -1
- data/ext/libarchive-3.6.2/config.h.in +1504 -0
- data/ext/libarchive-3.6.2/configure +25558 -0
- data/ext/libarchive-3.6.2/libarchive/archive.h +1212 -0
- data/ext/libarchive-3.6.2/libarchive/archive_acl.c +2097 -0
- data/ext/libarchive-3.6.2/libarchive/archive_acl_private.h +83 -0
- data/ext/libarchive-3.6.2/libarchive/archive_blake2.h +197 -0
- data/ext/libarchive-3.6.2/libarchive/archive_blake2_impl.h +161 -0
- data/ext/libarchive-3.6.2/libarchive/archive_blake2s_ref.c +369 -0
- data/ext/libarchive-3.6.2/libarchive/archive_blake2sp_ref.c +361 -0
- data/ext/{libarchive-2.8.4 → libarchive-3.6.2}/libarchive/archive_check_magic.c +63 -22
- data/ext/libarchive-3.6.2/libarchive/archive_cmdline.c +227 -0
- data/ext/libarchive-3.6.2/libarchive/archive_cmdline_private.h +47 -0
- data/ext/{libarchive-2.8.4 → libarchive-3.6.2}/libarchive/archive_crc32.h +17 -0
- data/ext/libarchive-3.6.2/libarchive/archive_cryptor.c +534 -0
- data/ext/libarchive-3.6.2/libarchive/archive_cryptor_private.h +188 -0
- data/ext/libarchive-3.6.2/libarchive/archive_digest.c +1505 -0
- data/ext/libarchive-3.6.2/libarchive/archive_digest_private.h +416 -0
- data/ext/libarchive-3.6.2/libarchive/archive_disk_acl_darwin.c +559 -0
- data/ext/libarchive-3.6.2/libarchive/archive_disk_acl_freebsd.c +712 -0
- data/ext/libarchive-3.6.2/libarchive/archive_disk_acl_linux.c +760 -0
- data/ext/libarchive-3.6.2/libarchive/archive_disk_acl_sunos.c +824 -0
- data/ext/{libarchive-2.8.4 → libarchive-3.6.2}/libarchive/archive_endian.h +48 -15
- data/ext/libarchive-3.6.2/libarchive/archive_entry.c +2149 -0
- data/ext/{libarchive-2.8.4 → libarchive-3.6.2}/libarchive/archive_entry.h +305 -106
- data/ext/{libarchive-2.8.4 → libarchive-3.6.2}/libarchive/archive_entry_copy_bhfi.c +5 -4
- data/ext/{libarchive-2.8.4 → libarchive-3.6.2}/libarchive/archive_entry_copy_stat.c +9 -3
- data/ext/{libarchive-2.8.4 → libarchive-3.6.2}/libarchive/archive_entry_link_resolver.c +104 -62
- data/ext/libarchive-3.6.2/libarchive/archive_entry_locale.h +92 -0
- data/ext/{libarchive-2.8.4 → libarchive-3.6.2}/libarchive/archive_entry_private.h +65 -49
- data/ext/libarchive-3.6.2/libarchive/archive_entry_sparse.c +156 -0
- data/ext/{libarchive-2.8.4 → libarchive-3.6.2}/libarchive/archive_entry_stat.c +6 -6
- data/ext/{libarchive-2.8.4 → libarchive-3.6.2}/libarchive/archive_entry_strmode.c +1 -1
- data/ext/{libarchive-2.8.4 → libarchive-3.6.2}/libarchive/archive_entry_xattr.c +4 -6
- data/ext/libarchive-3.6.2/libarchive/archive_getdate.c +1165 -0
- data/ext/libarchive-3.6.2/libarchive/archive_getdate.h +39 -0
- data/ext/libarchive-3.6.2/libarchive/archive_hmac.c +334 -0
- data/ext/libarchive-3.6.2/libarchive/archive_hmac_private.h +117 -0
- data/ext/libarchive-3.6.2/libarchive/archive_match.c +1875 -0
- data/ext/libarchive-3.6.2/libarchive/archive_openssl_evp_private.h +53 -0
- data/ext/libarchive-3.6.2/libarchive/archive_openssl_hmac_private.h +54 -0
- data/ext/libarchive-3.6.2/libarchive/archive_options.c +218 -0
- data/ext/libarchive-3.6.2/libarchive/archive_options_private.h +51 -0
- data/ext/libarchive-3.6.2/libarchive/archive_pack_dev.c +337 -0
- data/ext/libarchive-3.6.2/libarchive/archive_pack_dev.h +49 -0
- data/ext/libarchive-3.6.2/libarchive/archive_pathmatch.c +463 -0
- data/ext/libarchive-3.6.2/libarchive/archive_pathmatch.h +52 -0
- data/ext/{libarchive-2.8.4 → libarchive-3.6.2}/libarchive/archive_platform.h +77 -9
- data/ext/libarchive-3.6.2/libarchive/archive_platform_acl.h +55 -0
- data/ext/libarchive-3.6.2/libarchive/archive_platform_xattr.h +47 -0
- data/ext/libarchive-3.6.2/libarchive/archive_ppmd7.c +1168 -0
- data/ext/libarchive-3.6.2/libarchive/archive_ppmd7_private.h +119 -0
- data/ext/libarchive-3.6.2/libarchive/archive_ppmd8.c +1287 -0
- data/ext/libarchive-3.6.2/libarchive/archive_ppmd8_private.h +148 -0
- data/ext/libarchive-3.6.2/libarchive/archive_ppmd_private.h +151 -0
- data/ext/{libarchive-2.8.4 → libarchive-3.6.2}/libarchive/archive_private.h +74 -18
- data/ext/libarchive-3.6.2/libarchive/archive_random.c +272 -0
- data/ext/libarchive-3.6.2/libarchive/archive_random_private.h +36 -0
- data/ext/libarchive-3.6.2/libarchive/archive_rb.c +709 -0
- data/ext/libarchive-3.6.2/libarchive/archive_rb.h +113 -0
- data/ext/libarchive-3.6.2/libarchive/archive_read.c +1756 -0
- data/ext/libarchive-3.6.2/libarchive/archive_read_add_passphrase.c +190 -0
- data/ext/libarchive-3.6.2/libarchive/archive_read_append_filter.c +204 -0
- data/ext/{libarchive-2.8.4 → libarchive-3.6.2}/libarchive/archive_read_data_into_fd.c +64 -18
- data/ext/libarchive-3.6.2/libarchive/archive_read_disk_entry_from_file.c +1086 -0
- data/ext/libarchive-3.6.2/libarchive/archive_read_disk_posix.c +2732 -0
- data/ext/{libarchive-2.8.4 → libarchive-3.6.2}/libarchive/archive_read_disk_private.h +40 -4
- data/ext/{libarchive-2.8.4 → libarchive-3.6.2}/libarchive/archive_read_disk_set_standard_lookup.c +21 -11
- data/ext/libarchive-3.6.2/libarchive/archive_read_disk_windows.c +2479 -0
- data/ext/libarchive-3.6.2/libarchive/archive_read_extract.c +60 -0
- data/ext/{libarchive-2.8.4/libarchive/archive_read_extract.c → libarchive-3.6.2/libarchive/archive_read_extract2.c} +34 -61
- data/ext/{libarchive-2.8.4 → libarchive-3.6.2}/libarchive/archive_read_open_fd.c +70 -49
- data/ext/{libarchive-2.8.4 → libarchive-3.6.2}/libarchive/archive_read_open_file.c +38 -23
- data/ext/libarchive-3.6.2/libarchive/archive_read_open_filename.c +586 -0
- data/ext/{libarchive-2.8.4 → libarchive-3.6.2}/libarchive/archive_read_open_memory.c +58 -28
- data/ext/{libarchive-2.8.4 → libarchive-3.6.2}/libarchive/archive_read_private.h +127 -59
- data/ext/libarchive-3.6.2/libarchive/archive_read_set_format.c +117 -0
- data/ext/libarchive-3.6.2/libarchive/archive_read_set_options.c +133 -0
- data/ext/{libarchive-2.8.4/libarchive/archive_read_support_compression_all.c → libarchive-3.6.2/libarchive/archive_read_support_filter_all.c} +35 -10
- data/ext/libarchive-3.6.2/libarchive/archive_read_support_filter_by_code.c +83 -0
- data/ext/{libarchive-2.8.4/libarchive/archive_read_support_compression_bzip2.c → libarchive-3.6.2/libarchive/archive_read_support_filter_bzip2.c} +38 -26
- data/ext/{libarchive-2.8.4/libarchive/archive_read_support_compression_compress.c → libarchive-3.6.2/libarchive/archive_read_support_filter_compress.c} +52 -44
- data/ext/libarchive-3.6.2/libarchive/archive_read_support_filter_grzip.c +112 -0
- data/ext/{libarchive-2.8.4/libarchive/archive_read_support_compression_gzip.c → libarchive-3.6.2/libarchive/archive_read_support_filter_gzip.c} +108 -37
- data/ext/libarchive-3.6.2/libarchive/archive_read_support_filter_lrzip.c +122 -0
- data/ext/libarchive-3.6.2/libarchive/archive_read_support_filter_lz4.c +742 -0
- data/ext/libarchive-3.6.2/libarchive/archive_read_support_filter_lzop.c +499 -0
- data/ext/{libarchive-2.8.4/libarchive/archive_read_support_compression_none.c → libarchive-3.6.2/libarchive/archive_read_support_filter_none.c} +15 -3
- data/ext/{libarchive-2.8.4/libarchive/archive_read_support_compression_program.c → libarchive-3.6.2/libarchive/archive_read_support_filter_program.c} +114 -77
- data/ext/{libarchive-2.8.4/libarchive/archive_read_support_compression_rpm.c → libarchive-3.6.2/libarchive/archive_read_support_filter_rpm.c} +31 -31
- data/ext/{libarchive-2.8.4/libarchive/archive_read_support_compression_uu.c → libarchive-3.6.2/libarchive/archive_read_support_filter_uu.c} +141 -85
- data/ext/{libarchive-2.8.4/libarchive/archive_read_support_compression_xz.c → libarchive-3.6.2/libarchive/archive_read_support_filter_xz.c} +369 -284
- data/ext/libarchive-3.6.2/libarchive/archive_read_support_filter_zstd.c +297 -0
- data/ext/libarchive-3.6.2/libarchive/archive_read_support_format_7zip.c +3900 -0
- data/ext/libarchive-3.6.2/libarchive/archive_read_support_format_all.c +89 -0
- data/ext/{libarchive-2.8.4 → libarchive-3.6.2}/libarchive/archive_read_support_format_ar.c +126 -72
- data/ext/libarchive-3.6.2/libarchive/archive_read_support_format_by_code.c +92 -0
- data/ext/libarchive-3.6.2/libarchive/archive_read_support_format_cab.c +3228 -0
- data/ext/libarchive-3.6.2/libarchive/archive_read_support_format_cpio.c +1104 -0
- data/ext/{libarchive-2.8.4 → libarchive-3.6.2}/libarchive/archive_read_support_format_empty.c +14 -11
- data/ext/{libarchive-2.8.4 → libarchive-3.6.2}/libarchive/archive_read_support_format_iso9660.c +990 -541
- data/ext/libarchive-3.6.2/libarchive/archive_read_support_format_lha.c +2916 -0
- data/ext/libarchive-3.6.2/libarchive/archive_read_support_format_mtree.c +2150 -0
- data/ext/libarchive-3.6.2/libarchive/archive_read_support_format_rar.c +3797 -0
- data/ext/libarchive-3.6.2/libarchive/archive_read_support_format_rar5.c +4251 -0
- data/ext/{libarchive-2.8.4 → libarchive-3.6.2}/libarchive/archive_read_support_format_raw.c +38 -31
- data/ext/{libarchive-2.8.4 → libarchive-3.6.2}/libarchive/archive_read_support_format_tar.c +1157 -629
- data/ext/libarchive-3.6.2/libarchive/archive_read_support_format_warc.c +848 -0
- data/ext/{libarchive-2.8.4 → libarchive-3.6.2}/libarchive/archive_read_support_format_xar.c +439 -258
- data/ext/libarchive-3.6.2/libarchive/archive_read_support_format_zip.c +4270 -0
- data/ext/libarchive-3.6.2/libarchive/archive_string.c +4240 -0
- data/ext/libarchive-3.6.2/libarchive/archive_string.h +243 -0
- data/ext/libarchive-3.6.2/libarchive/archive_string_composition.h +2292 -0
- data/ext/{libarchive-2.8.4 → libarchive-3.6.2}/libarchive/archive_string_sprintf.c +44 -16
- data/ext/libarchive-3.6.2/libarchive/archive_util.c +655 -0
- data/ext/libarchive-3.6.2/libarchive/archive_version_details.c +151 -0
- data/ext/{libarchive-2.8.4 → libarchive-3.6.2}/libarchive/archive_virtual.c +85 -16
- data/ext/{libarchive-2.8.4 → libarchive-3.6.2}/libarchive/archive_windows.c +214 -541
- data/ext/{libarchive-2.8.4 → libarchive-3.6.2}/libarchive/archive_windows.h +74 -106
- data/ext/libarchive-3.6.2/libarchive/archive_write.c +828 -0
- data/ext/libarchive-3.6.2/libarchive/archive_write_add_filter.c +72 -0
- data/ext/libarchive-3.6.2/libarchive/archive_write_add_filter_b64encode.c +304 -0
- data/ext/libarchive-3.6.2/libarchive/archive_write_add_filter_by_name.c +77 -0
- data/ext/libarchive-3.6.2/libarchive/archive_write_add_filter_bzip2.c +401 -0
- data/ext/{libarchive-2.8.4/libarchive/archive_write_set_compression_compress.c → libarchive-3.6.2/libarchive/archive_write_add_filter_compress.c} +86 -131
- data/ext/libarchive-3.6.2/libarchive/archive_write_add_filter_grzip.c +135 -0
- data/ext/libarchive-3.6.2/libarchive/archive_write_add_filter_gzip.c +442 -0
- data/ext/libarchive-3.6.2/libarchive/archive_write_add_filter_lrzip.c +197 -0
- data/ext/libarchive-3.6.2/libarchive/archive_write_add_filter_lz4.c +700 -0
- data/ext/libarchive-3.6.2/libarchive/archive_write_add_filter_lzop.c +478 -0
- data/ext/{libarchive-2.8.4/libarchive/archive_read_support_format_all.c → libarchive-3.6.2/libarchive/archive_write_add_filter_none.c} +11 -11
- data/ext/libarchive-3.6.2/libarchive/archive_write_add_filter_program.c +391 -0
- data/ext/libarchive-3.6.2/libarchive/archive_write_add_filter_uuencode.c +295 -0
- data/ext/libarchive-3.6.2/libarchive/archive_write_add_filter_xz.c +545 -0
- data/ext/libarchive-3.6.2/libarchive/archive_write_add_filter_zstd.c +418 -0
- data/ext/libarchive-3.6.2/libarchive/archive_write_disk_posix.c +4711 -0
- data/ext/{libarchive-2.8.4 → libarchive-3.6.2}/libarchive/archive_write_disk_private.h +9 -2
- data/ext/{libarchive-2.8.4 → libarchive-3.6.2}/libarchive/archive_write_disk_set_standard_lookup.c +30 -29
- data/ext/libarchive-3.6.2/libarchive/archive_write_disk_windows.c +2842 -0
- data/ext/{libarchive-2.8.4 → libarchive-3.6.2}/libarchive/archive_write_open_fd.c +15 -10
- data/ext/{libarchive-2.8.4 → libarchive-3.6.2}/libarchive/archive_write_open_file.c +15 -9
- data/ext/{libarchive-2.8.4 → libarchive-3.6.2}/libarchive/archive_write_open_filename.c +128 -20
- data/ext/{libarchive-2.8.4 → libarchive-3.6.2}/libarchive/archive_write_open_memory.c +7 -18
- data/ext/{libarchive-2.8.4 → libarchive-3.6.2}/libarchive/archive_write_private.h +72 -29
- data/ext/{libarchive-2.8.4 → libarchive-3.6.2}/libarchive/archive_write_set_format.c +56 -3
- data/ext/libarchive-3.6.2/libarchive/archive_write_set_format_7zip.c +2322 -0
- data/ext/{libarchive-2.8.4 → libarchive-3.6.2}/libarchive/archive_write_set_format_ar.c +54 -34
- data/ext/{libarchive-2.8.4 → libarchive-3.6.2}/libarchive/archive_write_set_format_by_name.c +20 -2
- data/ext/libarchive-3.6.2/libarchive/archive_write_set_format_cpio.c +11 -0
- data/ext/libarchive-3.6.2/libarchive/archive_write_set_format_cpio_binary.c +610 -0
- data/ext/libarchive-3.6.2/libarchive/archive_write_set_format_cpio_newc.c +457 -0
- data/ext/libarchive-3.6.2/libarchive/archive_write_set_format_cpio_odc.c +500 -0
- data/ext/libarchive-3.6.2/libarchive/archive_write_set_format_filter_by_ext.c +142 -0
- data/ext/libarchive-3.6.2/libarchive/archive_write_set_format_gnutar.c +755 -0
- data/ext/libarchive-3.6.2/libarchive/archive_write_set_format_iso9660.c +8165 -0
- data/ext/libarchive-3.6.2/libarchive/archive_write_set_format_mtree.c +2217 -0
- data/ext/{libarchive-2.8.4 → libarchive-3.6.2}/libarchive/archive_write_set_format_pax.c +1049 -387
- data/ext/libarchive-3.6.2/libarchive/archive_write_set_format_private.h +42 -0
- data/ext/libarchive-3.6.2/libarchive/archive_write_set_format_raw.c +125 -0
- data/ext/{libarchive-2.8.4 → libarchive-3.6.2}/libarchive/archive_write_set_format_shar.c +62 -47
- data/ext/{libarchive-2.8.4 → libarchive-3.6.2}/libarchive/archive_write_set_format_ustar.c +279 -108
- data/ext/libarchive-3.6.2/libarchive/archive_write_set_format_v7tar.c +638 -0
- data/ext/libarchive-3.6.2/libarchive/archive_write_set_format_warc.c +453 -0
- data/ext/libarchive-3.6.2/libarchive/archive_write_set_format_xar.c +3259 -0
- data/ext/libarchive-3.6.2/libarchive/archive_write_set_format_zip.c +1704 -0
- data/ext/libarchive-3.6.2/libarchive/archive_write_set_options.c +130 -0
- data/ext/libarchive-3.6.2/libarchive/archive_write_set_passphrase.c +95 -0
- data/ext/libarchive-3.6.2/libarchive/archive_xxhash.h +48 -0
- data/ext/libarchive-3.6.2/libarchive/config_freebsd.h +271 -0
- data/ext/{libarchive-2.8.4 → libarchive-3.6.2}/libarchive/filter_fork.h +10 -5
- data/ext/{libarchive-2.8.4/libarchive/filter_fork.c → libarchive-3.6.2/libarchive/filter_fork_posix.c} +98 -19
- data/ext/libarchive-3.6.2/libarchive/filter_fork_windows.c +236 -0
- data/ext/libarchive-3.6.2/libarchive/xxhash.c +525 -0
- data/ext/libarchive-static-makefile +144 -80
- data/ext/libarchive-static-wrapper-makefile +1 -1
- data/ext/zlib-1.2.13/Makefile.in +404 -0
- data/ext/{zlib-1.2.5 → zlib-1.2.13}/adler32.c +51 -34
- data/ext/{zlib-1.2.5 → zlib-1.2.13}/compress.c +27 -21
- data/ext/zlib-1.2.13/configure +922 -0
- data/ext/zlib-1.2.13/crc32.c +1125 -0
- data/ext/zlib-1.2.13/crc32.h +9446 -0
- data/ext/{zlib-1.2.5 → zlib-1.2.13}/deflate.c +842 -459
- data/ext/{zlib-1.2.5 → zlib-1.2.13}/deflate.h +37 -33
- data/ext/{zlib-1.2.5 → zlib-1.2.13}/gzclose.c +0 -0
- data/ext/{zlib-1.2.5 → zlib-1.2.13}/gzguts.h +103 -16
- data/ext/{zlib-1.2.5 → zlib-1.2.13}/gzlib.c +155 -53
- data/ext/zlib-1.2.13/gzread.c +650 -0
- data/ext/zlib-1.2.13/gzwrite.c +677 -0
- data/ext/{zlib-1.2.5 → zlib-1.2.13}/infback.c +24 -12
- data/ext/{zlib-1.2.5 → zlib-1.2.13}/inffast.c +49 -66
- data/ext/{zlib-1.2.5 → zlib-1.2.13}/inffast.h +0 -0
- data/ext/{zlib-1.2.5 → zlib-1.2.13}/inffixed.h +3 -3
- data/ext/{zlib-1.2.5 → zlib-1.2.13}/inflate.c +209 -94
- data/ext/{zlib-1.2.5 → zlib-1.2.13}/inflate.h +9 -5
- data/ext/{zlib-1.2.5 → zlib-1.2.13}/inftrees.c +24 -50
- data/ext/{zlib-1.2.5 → zlib-1.2.13}/inftrees.h +1 -1
- data/ext/{zlib-1.2.5 → zlib-1.2.13}/trees.c +135 -198
- data/ext/{zlib-1.2.5 → zlib-1.2.13}/trees.h +0 -0
- data/ext/zlib-1.2.13/uncompr.c +93 -0
- data/ext/{zlib-1.2.5 → zlib-1.2.13}/zconf.h +182 -63
- data/ext/{zlib-1.2.5 → zlib-1.2.13}/zlib.h +617 -295
- data/ext/{zlib-1.2.5 → zlib-1.2.13}/zutil.c +50 -41
- data/ext/{zlib-1.2.5 → zlib-1.2.13}/zutil.h +83 -82
- metadata +241 -133
- data/ext/libarchive-0.1.1/libarchive.c +0 -1762
- data/ext/libarchive-2.8.4/Makefile.in +0 -7076
- data/ext/libarchive-2.8.4/build/autoconf/compile +0 -143
- data/ext/libarchive-2.8.4/build/autoconf/config.guess +0 -1502
- data/ext/libarchive-2.8.4/build/autoconf/config.sub +0 -1708
- data/ext/libarchive-2.8.4/build/autoconf/depcomp +0 -630
- data/ext/libarchive-2.8.4/build/autoconf/install-sh +0 -291
- data/ext/libarchive-2.8.4/build/autoconf/ltmain.sh +0 -8406
- data/ext/libarchive-2.8.4/build/autoconf/missing +0 -376
- data/ext/libarchive-2.8.4/config.h.in +0 -772
- data/ext/libarchive-2.8.4/configure +0 -17916
- data/ext/libarchive-2.8.4/libarchive/archive.h +0 -741
- data/ext/libarchive-2.8.4/libarchive/archive_entry.c +0 -2202
- data/ext/libarchive-2.8.4/libarchive/archive_hash.h +0 -281
- data/ext/libarchive-2.8.4/libarchive/archive_read.c +0 -1249
- data/ext/libarchive-2.8.4/libarchive/archive_read_disk.c +0 -198
- data/ext/libarchive-2.8.4/libarchive/archive_read_disk_entry_from_file.c +0 -570
- data/ext/libarchive-2.8.4/libarchive/archive_read_open_filename.c +0 -272
- data/ext/libarchive-2.8.4/libarchive/archive_read_support_format_cpio.c +0 -777
- data/ext/libarchive-2.8.4/libarchive/archive_read_support_format_mtree.c +0 -1304
- data/ext/libarchive-2.8.4/libarchive/archive_read_support_format_zip.c +0 -903
- data/ext/libarchive-2.8.4/libarchive/archive_string.c +0 -453
- data/ext/libarchive-2.8.4/libarchive/archive_string.h +0 -148
- data/ext/libarchive-2.8.4/libarchive/archive_util.c +0 -391
- data/ext/libarchive-2.8.4/libarchive/archive_write.c +0 -466
- data/ext/libarchive-2.8.4/libarchive/archive_write_disk.c +0 -2628
- data/ext/libarchive-2.8.4/libarchive/archive_write_set_compression_bzip2.c +0 -408
- data/ext/libarchive-2.8.4/libarchive/archive_write_set_compression_gzip.c +0 -477
- data/ext/libarchive-2.8.4/libarchive/archive_write_set_compression_none.c +0 -257
- data/ext/libarchive-2.8.4/libarchive/archive_write_set_compression_program.c +0 -347
- data/ext/libarchive-2.8.4/libarchive/archive_write_set_compression_xz.c +0 -438
- data/ext/libarchive-2.8.4/libarchive/archive_write_set_format_cpio.c +0 -344
- data/ext/libarchive-2.8.4/libarchive/archive_write_set_format_cpio_newc.c +0 -295
- data/ext/libarchive-2.8.4/libarchive/archive_write_set_format_mtree.c +0 -1050
- data/ext/libarchive-2.8.4/libarchive/archive_write_set_format_zip.c +0 -667
- data/ext/libarchive-2.8.4/libarchive/config_freebsd.h +0 -154
- data/ext/libarchive-2.8.4/libarchive/filter_fork_windows.c +0 -113
- data/ext/zlib-1.2.5/Makefile.in +0 -257
- data/ext/zlib-1.2.5/configure +0 -596
- data/ext/zlib-1.2.5/crc32.c +0 -442
- data/ext/zlib-1.2.5/crc32.h +0 -441
- data/ext/zlib-1.2.5/example.c +0 -565
- data/ext/zlib-1.2.5/gzread.c +0 -653
- data/ext/zlib-1.2.5/gzwrite.c +0 -531
- data/ext/zlib-1.2.5/minigzip.c +0 -440
- data/ext/zlib-1.2.5/uncompr.c +0 -59
|
@@ -0,0 +1,4711 @@
|
|
|
1
|
+
/*-
|
|
2
|
+
* Copyright (c) 2003-2010 Tim Kientzle
|
|
3
|
+
* Copyright (c) 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
|
+
* in this position and unchanged.
|
|
12
|
+
* 2. Redistributions in binary form must reproduce the above copyright
|
|
13
|
+
* notice, this list of conditions and the following disclaimer in the
|
|
14
|
+
* documentation and/or other materials provided with the distribution.
|
|
15
|
+
*
|
|
16
|
+
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR
|
|
17
|
+
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
|
18
|
+
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
|
19
|
+
* IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT,
|
|
20
|
+
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
|
|
21
|
+
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
|
22
|
+
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
|
23
|
+
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
|
24
|
+
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
|
|
25
|
+
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
26
|
+
*/
|
|
27
|
+
|
|
28
|
+
#include "archive_platform.h"
|
|
29
|
+
__FBSDID("$FreeBSD$");
|
|
30
|
+
|
|
31
|
+
#if !defined(_WIN32) || defined(__CYGWIN__)
|
|
32
|
+
|
|
33
|
+
#ifdef HAVE_SYS_TYPES_H
|
|
34
|
+
#include <sys/types.h>
|
|
35
|
+
#endif
|
|
36
|
+
#ifdef HAVE_SYS_ACL_H
|
|
37
|
+
#include <sys/acl.h>
|
|
38
|
+
#endif
|
|
39
|
+
#ifdef HAVE_SYS_EXTATTR_H
|
|
40
|
+
#include <sys/extattr.h>
|
|
41
|
+
#endif
|
|
42
|
+
#if HAVE_SYS_XATTR_H
|
|
43
|
+
#include <sys/xattr.h>
|
|
44
|
+
#elif HAVE_ATTR_XATTR_H
|
|
45
|
+
#include <attr/xattr.h>
|
|
46
|
+
#endif
|
|
47
|
+
#ifdef HAVE_SYS_EA_H
|
|
48
|
+
#include <sys/ea.h>
|
|
49
|
+
#endif
|
|
50
|
+
#ifdef HAVE_SYS_IOCTL_H
|
|
51
|
+
#include <sys/ioctl.h>
|
|
52
|
+
#endif
|
|
53
|
+
#ifdef HAVE_SYS_STAT_H
|
|
54
|
+
#include <sys/stat.h>
|
|
55
|
+
#endif
|
|
56
|
+
#ifdef HAVE_SYS_TIME_H
|
|
57
|
+
#include <sys/time.h>
|
|
58
|
+
#endif
|
|
59
|
+
#ifdef HAVE_SYS_UTIME_H
|
|
60
|
+
#include <sys/utime.h>
|
|
61
|
+
#endif
|
|
62
|
+
#ifdef HAVE_COPYFILE_H
|
|
63
|
+
#include <copyfile.h>
|
|
64
|
+
#endif
|
|
65
|
+
#ifdef HAVE_ERRNO_H
|
|
66
|
+
#include <errno.h>
|
|
67
|
+
#endif
|
|
68
|
+
#ifdef HAVE_FCNTL_H
|
|
69
|
+
#include <fcntl.h>
|
|
70
|
+
#endif
|
|
71
|
+
#ifdef HAVE_GRP_H
|
|
72
|
+
#include <grp.h>
|
|
73
|
+
#endif
|
|
74
|
+
#ifdef HAVE_LANGINFO_H
|
|
75
|
+
#include <langinfo.h>
|
|
76
|
+
#endif
|
|
77
|
+
#ifdef HAVE_LINUX_FS_H
|
|
78
|
+
#include <linux/fs.h> /* for Linux file flags */
|
|
79
|
+
#endif
|
|
80
|
+
/*
|
|
81
|
+
* Some Linux distributions have both linux/ext2_fs.h and ext2fs/ext2_fs.h.
|
|
82
|
+
* As the include guards don't agree, the order of include is important.
|
|
83
|
+
*/
|
|
84
|
+
#ifdef HAVE_LINUX_EXT2_FS_H
|
|
85
|
+
#include <linux/ext2_fs.h> /* for Linux file flags */
|
|
86
|
+
#endif
|
|
87
|
+
#if defined(HAVE_EXT2FS_EXT2_FS_H) && !defined(__CYGWIN__)
|
|
88
|
+
#include <ext2fs/ext2_fs.h> /* Linux file flags, broken on Cygwin */
|
|
89
|
+
#endif
|
|
90
|
+
#ifdef HAVE_LIMITS_H
|
|
91
|
+
#include <limits.h>
|
|
92
|
+
#endif
|
|
93
|
+
#ifdef HAVE_PWD_H
|
|
94
|
+
#include <pwd.h>
|
|
95
|
+
#endif
|
|
96
|
+
#include <stdio.h>
|
|
97
|
+
#ifdef HAVE_STDLIB_H
|
|
98
|
+
#include <stdlib.h>
|
|
99
|
+
#endif
|
|
100
|
+
#ifdef HAVE_STRING_H
|
|
101
|
+
#include <string.h>
|
|
102
|
+
#endif
|
|
103
|
+
#ifdef HAVE_UNISTD_H
|
|
104
|
+
#include <unistd.h>
|
|
105
|
+
#endif
|
|
106
|
+
#ifdef HAVE_UTIME_H
|
|
107
|
+
#include <utime.h>
|
|
108
|
+
#endif
|
|
109
|
+
#ifdef F_GETTIMES /* Tru64 specific */
|
|
110
|
+
#include <sys/fcntl1.h>
|
|
111
|
+
#endif
|
|
112
|
+
|
|
113
|
+
/*
|
|
114
|
+
* Macro to cast st_mtime and time_t to an int64 so that 2 numbers can reliably be compared.
|
|
115
|
+
*
|
|
116
|
+
* It assumes that the input is an integer type of no more than 64 bits.
|
|
117
|
+
* If the number is less than zero, t must be a signed type, so it fits in
|
|
118
|
+
* int64_t. Otherwise, it's a nonnegative value so we can cast it to uint64_t
|
|
119
|
+
* without loss. But it could be a large unsigned value, so we have to clip it
|
|
120
|
+
* to INT64_MAX.*
|
|
121
|
+
*/
|
|
122
|
+
#define to_int64_time(t) \
|
|
123
|
+
((t) < 0 ? (int64_t)(t) : (uint64_t)(t) > (uint64_t)INT64_MAX ? INT64_MAX : (int64_t)(t))
|
|
124
|
+
|
|
125
|
+
#if __APPLE__
|
|
126
|
+
#include <TargetConditionals.h>
|
|
127
|
+
#if TARGET_OS_MAC && !TARGET_OS_EMBEDDED && HAVE_QUARANTINE_H
|
|
128
|
+
#include <quarantine.h>
|
|
129
|
+
#define HAVE_QUARANTINE 1
|
|
130
|
+
#endif
|
|
131
|
+
#endif
|
|
132
|
+
|
|
133
|
+
#ifdef HAVE_ZLIB_H
|
|
134
|
+
#include <zlib.h>
|
|
135
|
+
#endif
|
|
136
|
+
|
|
137
|
+
/* TODO: Support Mac OS 'quarantine' feature. This is really just a
|
|
138
|
+
* standard tag to mark files that have been downloaded as "tainted".
|
|
139
|
+
* On Mac OS, we should mark the extracted files as tainted if the
|
|
140
|
+
* archive being read was tainted. Windows has a similar feature; we
|
|
141
|
+
* should investigate ways to support this generically. */
|
|
142
|
+
|
|
143
|
+
#include "archive.h"
|
|
144
|
+
#include "archive_acl_private.h"
|
|
145
|
+
#include "archive_string.h"
|
|
146
|
+
#include "archive_endian.h"
|
|
147
|
+
#include "archive_entry.h"
|
|
148
|
+
#include "archive_private.h"
|
|
149
|
+
#include "archive_write_disk_private.h"
|
|
150
|
+
|
|
151
|
+
#ifndef O_BINARY
|
|
152
|
+
#define O_BINARY 0
|
|
153
|
+
#endif
|
|
154
|
+
#ifndef O_CLOEXEC
|
|
155
|
+
#define O_CLOEXEC 0
|
|
156
|
+
#endif
|
|
157
|
+
|
|
158
|
+
/* Ignore non-int O_NOFOLLOW constant. */
|
|
159
|
+
/* gnulib's fcntl.h does this on AIX, but it seems practical everywhere */
|
|
160
|
+
#if defined O_NOFOLLOW && !(INT_MIN <= O_NOFOLLOW && O_NOFOLLOW <= INT_MAX)
|
|
161
|
+
#undef O_NOFOLLOW
|
|
162
|
+
#endif
|
|
163
|
+
|
|
164
|
+
#ifndef O_NOFOLLOW
|
|
165
|
+
#define O_NOFOLLOW 0
|
|
166
|
+
#endif
|
|
167
|
+
|
|
168
|
+
#ifndef AT_FDCWD
|
|
169
|
+
#define AT_FDCWD -100
|
|
170
|
+
#endif
|
|
171
|
+
|
|
172
|
+
struct fixup_entry {
|
|
173
|
+
struct fixup_entry *next;
|
|
174
|
+
struct archive_acl acl;
|
|
175
|
+
mode_t mode;
|
|
176
|
+
__LA_MODE_T filetype;
|
|
177
|
+
int64_t atime;
|
|
178
|
+
int64_t birthtime;
|
|
179
|
+
int64_t mtime;
|
|
180
|
+
int64_t ctime;
|
|
181
|
+
unsigned long atime_nanos;
|
|
182
|
+
unsigned long birthtime_nanos;
|
|
183
|
+
unsigned long mtime_nanos;
|
|
184
|
+
unsigned long ctime_nanos;
|
|
185
|
+
unsigned long fflags_set;
|
|
186
|
+
size_t mac_metadata_size;
|
|
187
|
+
void *mac_metadata;
|
|
188
|
+
int fixup; /* bitmask of what needs fixing */
|
|
189
|
+
char *name;
|
|
190
|
+
};
|
|
191
|
+
|
|
192
|
+
/*
|
|
193
|
+
* We use a bitmask to track which operations remain to be done for
|
|
194
|
+
* this file. In particular, this helps us avoid unnecessary
|
|
195
|
+
* operations when it's possible to take care of one step as a
|
|
196
|
+
* side-effect of another. For example, mkdir() can specify the mode
|
|
197
|
+
* for the newly-created object but symlink() cannot. This means we
|
|
198
|
+
* can skip chmod() if mkdir() succeeded, but we must explicitly
|
|
199
|
+
* chmod() if we're trying to create a directory that already exists
|
|
200
|
+
* (mkdir() failed) or if we're restoring a symlink. Similarly, we
|
|
201
|
+
* need to verify UID/GID before trying to restore SUID/SGID bits;
|
|
202
|
+
* that verification can occur explicitly through a stat() call or
|
|
203
|
+
* implicitly because of a successful chown() call.
|
|
204
|
+
*/
|
|
205
|
+
#define TODO_MODE_FORCE 0x40000000
|
|
206
|
+
#define TODO_MODE_BASE 0x20000000
|
|
207
|
+
#define TODO_SUID 0x10000000
|
|
208
|
+
#define TODO_SUID_CHECK 0x08000000
|
|
209
|
+
#define TODO_SGID 0x04000000
|
|
210
|
+
#define TODO_SGID_CHECK 0x02000000
|
|
211
|
+
#define TODO_APPLEDOUBLE 0x01000000
|
|
212
|
+
#define TODO_MODE (TODO_MODE_BASE|TODO_SUID|TODO_SGID)
|
|
213
|
+
#define TODO_TIMES ARCHIVE_EXTRACT_TIME
|
|
214
|
+
#define TODO_OWNER ARCHIVE_EXTRACT_OWNER
|
|
215
|
+
#define TODO_FFLAGS ARCHIVE_EXTRACT_FFLAGS
|
|
216
|
+
#define TODO_ACLS ARCHIVE_EXTRACT_ACL
|
|
217
|
+
#define TODO_XATTR ARCHIVE_EXTRACT_XATTR
|
|
218
|
+
#define TODO_MAC_METADATA ARCHIVE_EXTRACT_MAC_METADATA
|
|
219
|
+
#define TODO_HFS_COMPRESSION ARCHIVE_EXTRACT_HFS_COMPRESSION_FORCED
|
|
220
|
+
|
|
221
|
+
struct archive_write_disk {
|
|
222
|
+
struct archive archive;
|
|
223
|
+
|
|
224
|
+
mode_t user_umask;
|
|
225
|
+
struct fixup_entry *fixup_list;
|
|
226
|
+
struct fixup_entry *current_fixup;
|
|
227
|
+
int64_t user_uid;
|
|
228
|
+
int skip_file_set;
|
|
229
|
+
int64_t skip_file_dev;
|
|
230
|
+
int64_t skip_file_ino;
|
|
231
|
+
time_t start_time;
|
|
232
|
+
|
|
233
|
+
int64_t (*lookup_gid)(void *private, const char *gname, int64_t gid);
|
|
234
|
+
void (*cleanup_gid)(void *private);
|
|
235
|
+
void *lookup_gid_data;
|
|
236
|
+
int64_t (*lookup_uid)(void *private, const char *uname, int64_t uid);
|
|
237
|
+
void (*cleanup_uid)(void *private);
|
|
238
|
+
void *lookup_uid_data;
|
|
239
|
+
|
|
240
|
+
/*
|
|
241
|
+
* Full path of last file to satisfy symlink checks.
|
|
242
|
+
*/
|
|
243
|
+
struct archive_string path_safe;
|
|
244
|
+
|
|
245
|
+
/*
|
|
246
|
+
* Cached stat data from disk for the current entry.
|
|
247
|
+
* If this is valid, pst points to st. Otherwise,
|
|
248
|
+
* pst is null.
|
|
249
|
+
*/
|
|
250
|
+
struct stat st;
|
|
251
|
+
struct stat *pst;
|
|
252
|
+
|
|
253
|
+
/* Information about the object being restored right now. */
|
|
254
|
+
struct archive_entry *entry; /* Entry being extracted. */
|
|
255
|
+
char *name; /* Name of entry, possibly edited. */
|
|
256
|
+
struct archive_string _name_data; /* backing store for 'name' */
|
|
257
|
+
char *tmpname; /* Temporary name * */
|
|
258
|
+
struct archive_string _tmpname_data; /* backing store for 'tmpname' */
|
|
259
|
+
/* Tasks remaining for this object. */
|
|
260
|
+
int todo;
|
|
261
|
+
/* Tasks deferred until end-of-archive. */
|
|
262
|
+
int deferred;
|
|
263
|
+
/* Options requested by the client. */
|
|
264
|
+
int flags;
|
|
265
|
+
/* Handle for the file we're restoring. */
|
|
266
|
+
int fd;
|
|
267
|
+
/* Current offset for writing data to the file. */
|
|
268
|
+
int64_t offset;
|
|
269
|
+
/* Last offset actually written to disk. */
|
|
270
|
+
int64_t fd_offset;
|
|
271
|
+
/* Total bytes actually written to files. */
|
|
272
|
+
int64_t total_bytes_written;
|
|
273
|
+
/* Maximum size of file, -1 if unknown. */
|
|
274
|
+
int64_t filesize;
|
|
275
|
+
/* Dir we were in before this restore; only for deep paths. */
|
|
276
|
+
int restore_pwd;
|
|
277
|
+
/* Mode we should use for this entry; affected by _PERM and umask. */
|
|
278
|
+
mode_t mode;
|
|
279
|
+
/* UID/GID to use in restoring this entry. */
|
|
280
|
+
int64_t uid;
|
|
281
|
+
int64_t gid;
|
|
282
|
+
/*
|
|
283
|
+
* HFS+ Compression.
|
|
284
|
+
*/
|
|
285
|
+
/* Xattr "com.apple.decmpfs". */
|
|
286
|
+
uint32_t decmpfs_attr_size;
|
|
287
|
+
unsigned char *decmpfs_header_p;
|
|
288
|
+
/* ResourceFork set options used for fsetxattr. */
|
|
289
|
+
int rsrc_xattr_options;
|
|
290
|
+
/* Xattr "com.apple.ResourceFork". */
|
|
291
|
+
unsigned char *resource_fork;
|
|
292
|
+
size_t resource_fork_allocated_size;
|
|
293
|
+
unsigned int decmpfs_block_count;
|
|
294
|
+
uint32_t *decmpfs_block_info;
|
|
295
|
+
/* Buffer for compressed data. */
|
|
296
|
+
unsigned char *compressed_buffer;
|
|
297
|
+
size_t compressed_buffer_size;
|
|
298
|
+
size_t compressed_buffer_remaining;
|
|
299
|
+
/* The offset of the ResourceFork where compressed data will
|
|
300
|
+
* be placed. */
|
|
301
|
+
uint32_t compressed_rsrc_position;
|
|
302
|
+
uint32_t compressed_rsrc_position_v;
|
|
303
|
+
/* Buffer for uncompressed data. */
|
|
304
|
+
char *uncompressed_buffer;
|
|
305
|
+
size_t block_remaining_bytes;
|
|
306
|
+
size_t file_remaining_bytes;
|
|
307
|
+
#ifdef HAVE_ZLIB_H
|
|
308
|
+
z_stream stream;
|
|
309
|
+
int stream_valid;
|
|
310
|
+
int decmpfs_compression_level;
|
|
311
|
+
#endif
|
|
312
|
+
};
|
|
313
|
+
|
|
314
|
+
/*
|
|
315
|
+
* Default mode for dirs created automatically (will be modified by umask).
|
|
316
|
+
* Note that POSIX specifies 0777 for implicitly-created dirs, "modified
|
|
317
|
+
* by the process' file creation mask."
|
|
318
|
+
*/
|
|
319
|
+
#define DEFAULT_DIR_MODE 0777
|
|
320
|
+
/*
|
|
321
|
+
* Dir modes are restored in two steps: During the extraction, the permissions
|
|
322
|
+
* in the archive are modified to match the following limits. During
|
|
323
|
+
* the post-extract fixup pass, the permissions from the archive are
|
|
324
|
+
* applied.
|
|
325
|
+
*/
|
|
326
|
+
#define MINIMUM_DIR_MODE 0700
|
|
327
|
+
#define MAXIMUM_DIR_MODE 0775
|
|
328
|
+
|
|
329
|
+
/*
|
|
330
|
+
* Maximum uncompressed size of a decmpfs block.
|
|
331
|
+
*/
|
|
332
|
+
#define MAX_DECMPFS_BLOCK_SIZE (64 * 1024)
|
|
333
|
+
/*
|
|
334
|
+
* HFS+ compression type.
|
|
335
|
+
*/
|
|
336
|
+
#define CMP_XATTR 3/* Compressed data in xattr. */
|
|
337
|
+
#define CMP_RESOURCE_FORK 4/* Compressed data in resource fork. */
|
|
338
|
+
/*
|
|
339
|
+
* HFS+ compression resource fork.
|
|
340
|
+
*/
|
|
341
|
+
#define RSRC_H_SIZE 260 /* Base size of Resource fork header. */
|
|
342
|
+
#define RSRC_F_SIZE 50 /* Size of Resource fork footer. */
|
|
343
|
+
/* Size to write compressed data to resource fork. */
|
|
344
|
+
#define COMPRESSED_W_SIZE (64 * 1024)
|
|
345
|
+
/* decmpfs definitions. */
|
|
346
|
+
#define MAX_DECMPFS_XATTR_SIZE 3802
|
|
347
|
+
#ifndef DECMPFS_XATTR_NAME
|
|
348
|
+
#define DECMPFS_XATTR_NAME "com.apple.decmpfs"
|
|
349
|
+
#endif
|
|
350
|
+
#define DECMPFS_MAGIC 0x636d7066
|
|
351
|
+
#define DECMPFS_COMPRESSION_MAGIC 0
|
|
352
|
+
#define DECMPFS_COMPRESSION_TYPE 4
|
|
353
|
+
#define DECMPFS_UNCOMPRESSED_SIZE 8
|
|
354
|
+
#define DECMPFS_HEADER_SIZE 16
|
|
355
|
+
|
|
356
|
+
#define HFS_BLOCKS(s) ((s) >> 12)
|
|
357
|
+
|
|
358
|
+
|
|
359
|
+
static int la_opendirat(int, const char *);
|
|
360
|
+
static int la_mktemp(struct archive_write_disk *);
|
|
361
|
+
static int la_verify_filetype(mode_t, __LA_MODE_T);
|
|
362
|
+
static void fsobj_error(int *, struct archive_string *, int, const char *,
|
|
363
|
+
const char *);
|
|
364
|
+
static int check_symlinks_fsobj(char *, int *, struct archive_string *,
|
|
365
|
+
int, int);
|
|
366
|
+
static int check_symlinks(struct archive_write_disk *);
|
|
367
|
+
static int create_filesystem_object(struct archive_write_disk *);
|
|
368
|
+
static struct fixup_entry *current_fixup(struct archive_write_disk *,
|
|
369
|
+
const char *pathname);
|
|
370
|
+
#if defined(HAVE_FCHDIR) && defined(PATH_MAX)
|
|
371
|
+
static void edit_deep_directories(struct archive_write_disk *ad);
|
|
372
|
+
#endif
|
|
373
|
+
static int cleanup_pathname_fsobj(char *, int *, struct archive_string *,
|
|
374
|
+
int);
|
|
375
|
+
static int cleanup_pathname(struct archive_write_disk *);
|
|
376
|
+
static int create_dir(struct archive_write_disk *, char *);
|
|
377
|
+
static int create_parent_dir(struct archive_write_disk *, char *);
|
|
378
|
+
static ssize_t hfs_write_data_block(struct archive_write_disk *,
|
|
379
|
+
const char *, size_t);
|
|
380
|
+
static int fixup_appledouble(struct archive_write_disk *, const char *);
|
|
381
|
+
static int older(struct stat *, struct archive_entry *);
|
|
382
|
+
static int restore_entry(struct archive_write_disk *);
|
|
383
|
+
static int set_mac_metadata(struct archive_write_disk *, const char *,
|
|
384
|
+
const void *, size_t);
|
|
385
|
+
static int set_xattrs(struct archive_write_disk *);
|
|
386
|
+
static int clear_nochange_fflags(struct archive_write_disk *);
|
|
387
|
+
static int set_fflags(struct archive_write_disk *);
|
|
388
|
+
static int set_fflags_platform(struct archive_write_disk *, int fd,
|
|
389
|
+
const char *name, mode_t mode,
|
|
390
|
+
unsigned long fflags_set, unsigned long fflags_clear);
|
|
391
|
+
static int set_ownership(struct archive_write_disk *);
|
|
392
|
+
static int set_mode(struct archive_write_disk *, int mode);
|
|
393
|
+
static int set_time(int, int, const char *, time_t, long, time_t, long);
|
|
394
|
+
static int set_times(struct archive_write_disk *, int, int, const char *,
|
|
395
|
+
time_t, long, time_t, long, time_t, long, time_t, long);
|
|
396
|
+
static int set_times_from_entry(struct archive_write_disk *);
|
|
397
|
+
static struct fixup_entry *sort_dir_list(struct fixup_entry *p);
|
|
398
|
+
static ssize_t write_data_block(struct archive_write_disk *,
|
|
399
|
+
const char *, size_t);
|
|
400
|
+
|
|
401
|
+
static int _archive_write_disk_close(struct archive *);
|
|
402
|
+
static int _archive_write_disk_free(struct archive *);
|
|
403
|
+
static int _archive_write_disk_header(struct archive *,
|
|
404
|
+
struct archive_entry *);
|
|
405
|
+
static int64_t _archive_write_disk_filter_bytes(struct archive *, int);
|
|
406
|
+
static int _archive_write_disk_finish_entry(struct archive *);
|
|
407
|
+
static ssize_t _archive_write_disk_data(struct archive *, const void *,
|
|
408
|
+
size_t);
|
|
409
|
+
static ssize_t _archive_write_disk_data_block(struct archive *, const void *,
|
|
410
|
+
size_t, int64_t);
|
|
411
|
+
|
|
412
|
+
static int
|
|
413
|
+
la_mktemp(struct archive_write_disk *a)
|
|
414
|
+
{
|
|
415
|
+
int oerrno, fd;
|
|
416
|
+
mode_t mode;
|
|
417
|
+
|
|
418
|
+
archive_string_empty(&a->_tmpname_data);
|
|
419
|
+
archive_string_sprintf(&a->_tmpname_data, "%s.XXXXXX", a->name);
|
|
420
|
+
a->tmpname = a->_tmpname_data.s;
|
|
421
|
+
|
|
422
|
+
fd = __archive_mkstemp(a->tmpname);
|
|
423
|
+
if (fd == -1)
|
|
424
|
+
return -1;
|
|
425
|
+
|
|
426
|
+
mode = a->mode & 0777 & ~a->user_umask;
|
|
427
|
+
if (fchmod(fd, mode) == -1) {
|
|
428
|
+
oerrno = errno;
|
|
429
|
+
close(fd);
|
|
430
|
+
errno = oerrno;
|
|
431
|
+
return -1;
|
|
432
|
+
}
|
|
433
|
+
return fd;
|
|
434
|
+
}
|
|
435
|
+
|
|
436
|
+
static int
|
|
437
|
+
la_opendirat(int fd, const char *path) {
|
|
438
|
+
const int flags = O_CLOEXEC
|
|
439
|
+
#if defined(O_BINARY)
|
|
440
|
+
| O_BINARY
|
|
441
|
+
#endif
|
|
442
|
+
#if defined(O_DIRECTORY)
|
|
443
|
+
| O_DIRECTORY
|
|
444
|
+
#endif
|
|
445
|
+
#if defined(O_PATH)
|
|
446
|
+
| O_PATH
|
|
447
|
+
#elif defined(O_SEARCH)
|
|
448
|
+
| O_SEARCH
|
|
449
|
+
#elif defined(__FreeBSD__) && defined(O_EXEC)
|
|
450
|
+
| O_EXEC
|
|
451
|
+
#else
|
|
452
|
+
| O_RDONLY
|
|
453
|
+
#endif
|
|
454
|
+
;
|
|
455
|
+
|
|
456
|
+
#if !defined(HAVE_OPENAT)
|
|
457
|
+
if (fd != AT_FDCWD) {
|
|
458
|
+
errno = ENOTSUP;
|
|
459
|
+
return (-1);
|
|
460
|
+
} else
|
|
461
|
+
return (open(path, flags));
|
|
462
|
+
#else
|
|
463
|
+
return (openat(fd, path, flags));
|
|
464
|
+
#endif
|
|
465
|
+
}
|
|
466
|
+
|
|
467
|
+
static int
|
|
468
|
+
la_verify_filetype(mode_t mode, __LA_MODE_T filetype) {
|
|
469
|
+
int ret = 0;
|
|
470
|
+
|
|
471
|
+
switch (filetype) {
|
|
472
|
+
case AE_IFREG:
|
|
473
|
+
ret = (S_ISREG(mode));
|
|
474
|
+
break;
|
|
475
|
+
case AE_IFDIR:
|
|
476
|
+
ret = (S_ISDIR(mode));
|
|
477
|
+
break;
|
|
478
|
+
case AE_IFLNK:
|
|
479
|
+
ret = (S_ISLNK(mode));
|
|
480
|
+
break;
|
|
481
|
+
case AE_IFSOCK:
|
|
482
|
+
ret = (S_ISSOCK(mode));
|
|
483
|
+
break;
|
|
484
|
+
case AE_IFCHR:
|
|
485
|
+
ret = (S_ISCHR(mode));
|
|
486
|
+
break;
|
|
487
|
+
case AE_IFBLK:
|
|
488
|
+
ret = (S_ISBLK(mode));
|
|
489
|
+
break;
|
|
490
|
+
case AE_IFIFO:
|
|
491
|
+
ret = (S_ISFIFO(mode));
|
|
492
|
+
break;
|
|
493
|
+
default:
|
|
494
|
+
break;
|
|
495
|
+
}
|
|
496
|
+
|
|
497
|
+
return (ret);
|
|
498
|
+
}
|
|
499
|
+
|
|
500
|
+
static int
|
|
501
|
+
lazy_stat(struct archive_write_disk *a)
|
|
502
|
+
{
|
|
503
|
+
if (a->pst != NULL) {
|
|
504
|
+
/* Already have stat() data available. */
|
|
505
|
+
return (ARCHIVE_OK);
|
|
506
|
+
}
|
|
507
|
+
#ifdef HAVE_FSTAT
|
|
508
|
+
if (a->fd >= 0 && fstat(a->fd, &a->st) == 0) {
|
|
509
|
+
a->pst = &a->st;
|
|
510
|
+
return (ARCHIVE_OK);
|
|
511
|
+
}
|
|
512
|
+
#endif
|
|
513
|
+
/*
|
|
514
|
+
* XXX At this point, symlinks should not be hit, otherwise
|
|
515
|
+
* XXX a race occurred. Do we want to check explicitly for that?
|
|
516
|
+
*/
|
|
517
|
+
if (lstat(a->name, &a->st) == 0) {
|
|
518
|
+
a->pst = &a->st;
|
|
519
|
+
return (ARCHIVE_OK);
|
|
520
|
+
}
|
|
521
|
+
archive_set_error(&a->archive, errno, "Couldn't stat file");
|
|
522
|
+
return (ARCHIVE_WARN);
|
|
523
|
+
}
|
|
524
|
+
|
|
525
|
+
static const struct archive_vtable
|
|
526
|
+
archive_write_disk_vtable = {
|
|
527
|
+
.archive_close = _archive_write_disk_close,
|
|
528
|
+
.archive_filter_bytes = _archive_write_disk_filter_bytes,
|
|
529
|
+
.archive_free = _archive_write_disk_free,
|
|
530
|
+
.archive_write_header = _archive_write_disk_header,
|
|
531
|
+
.archive_write_finish_entry = _archive_write_disk_finish_entry,
|
|
532
|
+
.archive_write_data = _archive_write_disk_data,
|
|
533
|
+
.archive_write_data_block = _archive_write_disk_data_block,
|
|
534
|
+
};
|
|
535
|
+
|
|
536
|
+
static int64_t
|
|
537
|
+
_archive_write_disk_filter_bytes(struct archive *_a, int n)
|
|
538
|
+
{
|
|
539
|
+
struct archive_write_disk *a = (struct archive_write_disk *)_a;
|
|
540
|
+
(void)n; /* UNUSED */
|
|
541
|
+
if (n == -1 || n == 0)
|
|
542
|
+
return (a->total_bytes_written);
|
|
543
|
+
return (-1);
|
|
544
|
+
}
|
|
545
|
+
|
|
546
|
+
|
|
547
|
+
int
|
|
548
|
+
archive_write_disk_set_options(struct archive *_a, int flags)
|
|
549
|
+
{
|
|
550
|
+
struct archive_write_disk *a = (struct archive_write_disk *)_a;
|
|
551
|
+
|
|
552
|
+
a->flags = flags;
|
|
553
|
+
return (ARCHIVE_OK);
|
|
554
|
+
}
|
|
555
|
+
|
|
556
|
+
|
|
557
|
+
/*
|
|
558
|
+
* Extract this entry to disk.
|
|
559
|
+
*
|
|
560
|
+
* TODO: Validate hardlinks. According to the standards, we're
|
|
561
|
+
* supposed to check each extracted hardlink and squawk if it refers
|
|
562
|
+
* to a file that we didn't restore. I'm not entirely convinced this
|
|
563
|
+
* is a good idea, but more importantly: Is there any way to validate
|
|
564
|
+
* hardlinks without keeping a complete list of filenames from the
|
|
565
|
+
* entire archive?? Ugh.
|
|
566
|
+
*
|
|
567
|
+
*/
|
|
568
|
+
static int
|
|
569
|
+
_archive_write_disk_header(struct archive *_a, struct archive_entry *entry)
|
|
570
|
+
{
|
|
571
|
+
struct archive_write_disk *a = (struct archive_write_disk *)_a;
|
|
572
|
+
struct fixup_entry *fe;
|
|
573
|
+
const char *linkname;
|
|
574
|
+
int ret, r;
|
|
575
|
+
|
|
576
|
+
archive_check_magic(&a->archive, ARCHIVE_WRITE_DISK_MAGIC,
|
|
577
|
+
ARCHIVE_STATE_HEADER | ARCHIVE_STATE_DATA,
|
|
578
|
+
"archive_write_disk_header");
|
|
579
|
+
archive_clear_error(&a->archive);
|
|
580
|
+
if (a->archive.state & ARCHIVE_STATE_DATA) {
|
|
581
|
+
r = _archive_write_disk_finish_entry(&a->archive);
|
|
582
|
+
if (r == ARCHIVE_FATAL)
|
|
583
|
+
return (r);
|
|
584
|
+
}
|
|
585
|
+
|
|
586
|
+
/* Set up for this particular entry. */
|
|
587
|
+
a->pst = NULL;
|
|
588
|
+
a->current_fixup = NULL;
|
|
589
|
+
a->deferred = 0;
|
|
590
|
+
if (a->entry) {
|
|
591
|
+
archive_entry_free(a->entry);
|
|
592
|
+
a->entry = NULL;
|
|
593
|
+
}
|
|
594
|
+
a->entry = archive_entry_clone(entry);
|
|
595
|
+
a->fd = -1;
|
|
596
|
+
a->fd_offset = 0;
|
|
597
|
+
a->offset = 0;
|
|
598
|
+
a->restore_pwd = -1;
|
|
599
|
+
a->uid = a->user_uid;
|
|
600
|
+
a->mode = archive_entry_mode(a->entry);
|
|
601
|
+
if (archive_entry_size_is_set(a->entry))
|
|
602
|
+
a->filesize = archive_entry_size(a->entry);
|
|
603
|
+
else
|
|
604
|
+
a->filesize = -1;
|
|
605
|
+
archive_strcpy(&(a->_name_data), archive_entry_pathname(a->entry));
|
|
606
|
+
a->name = a->_name_data.s;
|
|
607
|
+
archive_clear_error(&a->archive);
|
|
608
|
+
|
|
609
|
+
/*
|
|
610
|
+
* Clean up the requested path. This is necessary for correct
|
|
611
|
+
* dir restores; the dir restore logic otherwise gets messed
|
|
612
|
+
* up by nonsense like "dir/.".
|
|
613
|
+
*/
|
|
614
|
+
ret = cleanup_pathname(a);
|
|
615
|
+
if (ret != ARCHIVE_OK)
|
|
616
|
+
return (ret);
|
|
617
|
+
|
|
618
|
+
/*
|
|
619
|
+
* Check if we have a hardlink that points to itself.
|
|
620
|
+
*/
|
|
621
|
+
linkname = archive_entry_hardlink(a->entry);
|
|
622
|
+
if (linkname != NULL && strcmp(a->name, linkname) == 0) {
|
|
623
|
+
archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
|
|
624
|
+
"Skipping hardlink pointing to itself: %s",
|
|
625
|
+
a->name);
|
|
626
|
+
return (ARCHIVE_WARN);
|
|
627
|
+
}
|
|
628
|
+
|
|
629
|
+
/*
|
|
630
|
+
* Query the umask so we get predictable mode settings.
|
|
631
|
+
* This gets done on every call to _write_header in case the
|
|
632
|
+
* user edits their umask during the extraction for some
|
|
633
|
+
* reason.
|
|
634
|
+
*/
|
|
635
|
+
umask(a->user_umask = umask(0));
|
|
636
|
+
|
|
637
|
+
/* Figure out what we need to do for this entry. */
|
|
638
|
+
a->todo = TODO_MODE_BASE;
|
|
639
|
+
if (a->flags & ARCHIVE_EXTRACT_PERM) {
|
|
640
|
+
a->todo |= TODO_MODE_FORCE; /* Be pushy about permissions. */
|
|
641
|
+
/*
|
|
642
|
+
* SGID requires an extra "check" step because we
|
|
643
|
+
* cannot easily predict the GID that the system will
|
|
644
|
+
* assign. (Different systems assign GIDs to files
|
|
645
|
+
* based on a variety of criteria, including process
|
|
646
|
+
* credentials and the gid of the enclosing
|
|
647
|
+
* directory.) We can only restore the SGID bit if
|
|
648
|
+
* the file has the right GID, and we only know the
|
|
649
|
+
* GID if we either set it (see set_ownership) or if
|
|
650
|
+
* we've actually called stat() on the file after it
|
|
651
|
+
* was restored. Since there are several places at
|
|
652
|
+
* which we might verify the GID, we need a TODO bit
|
|
653
|
+
* to keep track.
|
|
654
|
+
*/
|
|
655
|
+
if (a->mode & S_ISGID)
|
|
656
|
+
a->todo |= TODO_SGID | TODO_SGID_CHECK;
|
|
657
|
+
/*
|
|
658
|
+
* Verifying the SUID is simpler, but can still be
|
|
659
|
+
* done in multiple ways, hence the separate "check" bit.
|
|
660
|
+
*/
|
|
661
|
+
if (a->mode & S_ISUID)
|
|
662
|
+
a->todo |= TODO_SUID | TODO_SUID_CHECK;
|
|
663
|
+
} else {
|
|
664
|
+
/*
|
|
665
|
+
* User didn't request full permissions, so don't
|
|
666
|
+
* restore SUID, SGID bits and obey umask.
|
|
667
|
+
*/
|
|
668
|
+
a->mode &= ~S_ISUID;
|
|
669
|
+
a->mode &= ~S_ISGID;
|
|
670
|
+
a->mode &= ~S_ISVTX;
|
|
671
|
+
a->mode &= ~a->user_umask;
|
|
672
|
+
}
|
|
673
|
+
if (a->flags & ARCHIVE_EXTRACT_OWNER)
|
|
674
|
+
a->todo |= TODO_OWNER;
|
|
675
|
+
if (a->flags & ARCHIVE_EXTRACT_TIME)
|
|
676
|
+
a->todo |= TODO_TIMES;
|
|
677
|
+
if (a->flags & ARCHIVE_EXTRACT_ACL) {
|
|
678
|
+
#if ARCHIVE_ACL_DARWIN
|
|
679
|
+
/*
|
|
680
|
+
* On MacOS, platform ACLs get stored in mac_metadata, too.
|
|
681
|
+
* If we intend to extract mac_metadata and it is present
|
|
682
|
+
* we skip extracting libarchive NFSv4 ACLs.
|
|
683
|
+
*/
|
|
684
|
+
size_t metadata_size;
|
|
685
|
+
|
|
686
|
+
if ((a->flags & ARCHIVE_EXTRACT_MAC_METADATA) == 0 ||
|
|
687
|
+
archive_entry_mac_metadata(a->entry,
|
|
688
|
+
&metadata_size) == NULL || metadata_size == 0)
|
|
689
|
+
#endif
|
|
690
|
+
#if ARCHIVE_ACL_LIBRICHACL
|
|
691
|
+
/*
|
|
692
|
+
* RichACLs are stored in an extended attribute.
|
|
693
|
+
* If we intend to extract extended attributes and have this
|
|
694
|
+
* attribute we skip extracting libarchive NFSv4 ACLs.
|
|
695
|
+
*/
|
|
696
|
+
short extract_acls = 1;
|
|
697
|
+
if (a->flags & ARCHIVE_EXTRACT_XATTR && (
|
|
698
|
+
archive_entry_acl_types(a->entry) &
|
|
699
|
+
ARCHIVE_ENTRY_ACL_TYPE_NFS4)) {
|
|
700
|
+
const char *attr_name;
|
|
701
|
+
const void *attr_value;
|
|
702
|
+
size_t attr_size;
|
|
703
|
+
int i = archive_entry_xattr_reset(a->entry);
|
|
704
|
+
while (i--) {
|
|
705
|
+
archive_entry_xattr_next(a->entry, &attr_name,
|
|
706
|
+
&attr_value, &attr_size);
|
|
707
|
+
if (attr_name != NULL && attr_value != NULL &&
|
|
708
|
+
attr_size > 0 && strcmp(attr_name,
|
|
709
|
+
"trusted.richacl") == 0) {
|
|
710
|
+
extract_acls = 0;
|
|
711
|
+
break;
|
|
712
|
+
}
|
|
713
|
+
}
|
|
714
|
+
}
|
|
715
|
+
if (extract_acls)
|
|
716
|
+
#endif
|
|
717
|
+
#if ARCHIVE_ACL_DARWIN || ARCHIVE_ACL_LIBRICHACL
|
|
718
|
+
{
|
|
719
|
+
#endif
|
|
720
|
+
if (archive_entry_filetype(a->entry) == AE_IFDIR)
|
|
721
|
+
a->deferred |= TODO_ACLS;
|
|
722
|
+
else
|
|
723
|
+
a->todo |= TODO_ACLS;
|
|
724
|
+
#if ARCHIVE_ACL_DARWIN || ARCHIVE_ACL_LIBRICHACL
|
|
725
|
+
}
|
|
726
|
+
#endif
|
|
727
|
+
}
|
|
728
|
+
if (a->flags & ARCHIVE_EXTRACT_MAC_METADATA) {
|
|
729
|
+
if (archive_entry_filetype(a->entry) == AE_IFDIR)
|
|
730
|
+
a->deferred |= TODO_MAC_METADATA;
|
|
731
|
+
else
|
|
732
|
+
a->todo |= TODO_MAC_METADATA;
|
|
733
|
+
}
|
|
734
|
+
#if defined(__APPLE__) && defined(UF_COMPRESSED) && defined(HAVE_ZLIB_H)
|
|
735
|
+
if ((a->flags & ARCHIVE_EXTRACT_NO_HFS_COMPRESSION) == 0) {
|
|
736
|
+
unsigned long set, clear;
|
|
737
|
+
archive_entry_fflags(a->entry, &set, &clear);
|
|
738
|
+
if ((set & ~clear) & UF_COMPRESSED) {
|
|
739
|
+
a->todo |= TODO_HFS_COMPRESSION;
|
|
740
|
+
a->decmpfs_block_count = (unsigned)-1;
|
|
741
|
+
}
|
|
742
|
+
}
|
|
743
|
+
if ((a->flags & ARCHIVE_EXTRACT_HFS_COMPRESSION_FORCED) != 0 &&
|
|
744
|
+
(a->mode & AE_IFMT) == AE_IFREG && a->filesize > 0) {
|
|
745
|
+
a->todo |= TODO_HFS_COMPRESSION;
|
|
746
|
+
a->decmpfs_block_count = (unsigned)-1;
|
|
747
|
+
}
|
|
748
|
+
{
|
|
749
|
+
const char *p;
|
|
750
|
+
|
|
751
|
+
/* Check if the current file name is a type of the
|
|
752
|
+
* resource fork file. */
|
|
753
|
+
p = strrchr(a->name, '/');
|
|
754
|
+
if (p == NULL)
|
|
755
|
+
p = a->name;
|
|
756
|
+
else
|
|
757
|
+
p++;
|
|
758
|
+
if (p[0] == '.' && p[1] == '_') {
|
|
759
|
+
/* Do not compress "._XXX" files. */
|
|
760
|
+
a->todo &= ~TODO_HFS_COMPRESSION;
|
|
761
|
+
if (a->filesize > 0)
|
|
762
|
+
a->todo |= TODO_APPLEDOUBLE;
|
|
763
|
+
}
|
|
764
|
+
}
|
|
765
|
+
#endif
|
|
766
|
+
|
|
767
|
+
if (a->flags & ARCHIVE_EXTRACT_XATTR) {
|
|
768
|
+
#if ARCHIVE_XATTR_DARWIN
|
|
769
|
+
/*
|
|
770
|
+
* On MacOS, extended attributes get stored in mac_metadata,
|
|
771
|
+
* too. If we intend to extract mac_metadata and it is present
|
|
772
|
+
* we skip extracting extended attributes.
|
|
773
|
+
*/
|
|
774
|
+
size_t metadata_size;
|
|
775
|
+
|
|
776
|
+
if ((a->flags & ARCHIVE_EXTRACT_MAC_METADATA) == 0 ||
|
|
777
|
+
archive_entry_mac_metadata(a->entry,
|
|
778
|
+
&metadata_size) == NULL || metadata_size == 0)
|
|
779
|
+
#endif
|
|
780
|
+
a->todo |= TODO_XATTR;
|
|
781
|
+
}
|
|
782
|
+
if (a->flags & ARCHIVE_EXTRACT_FFLAGS)
|
|
783
|
+
a->todo |= TODO_FFLAGS;
|
|
784
|
+
if (a->flags & ARCHIVE_EXTRACT_SECURE_SYMLINKS) {
|
|
785
|
+
ret = check_symlinks(a);
|
|
786
|
+
if (ret != ARCHIVE_OK)
|
|
787
|
+
return (ret);
|
|
788
|
+
}
|
|
789
|
+
#if defined(HAVE_FCHDIR) && defined(PATH_MAX)
|
|
790
|
+
/* If path exceeds PATH_MAX, shorten the path. */
|
|
791
|
+
edit_deep_directories(a);
|
|
792
|
+
#endif
|
|
793
|
+
|
|
794
|
+
ret = restore_entry(a);
|
|
795
|
+
|
|
796
|
+
#if defined(__APPLE__) && defined(UF_COMPRESSED) && defined(HAVE_ZLIB_H)
|
|
797
|
+
/*
|
|
798
|
+
* Check if the filesystem the file is restoring on supports
|
|
799
|
+
* HFS+ Compression. If not, cancel HFS+ Compression.
|
|
800
|
+
*/
|
|
801
|
+
if (a->todo | TODO_HFS_COMPRESSION) {
|
|
802
|
+
/*
|
|
803
|
+
* NOTE: UF_COMPRESSED is ignored even if the filesystem
|
|
804
|
+
* supports HFS+ Compression because the file should
|
|
805
|
+
* have at least an extended attribute "com.apple.decmpfs"
|
|
806
|
+
* before the flag is set to indicate that the file have
|
|
807
|
+
* been compressed. If the filesystem does not support
|
|
808
|
+
* HFS+ Compression the system call will fail.
|
|
809
|
+
*/
|
|
810
|
+
if (a->fd < 0 || fchflags(a->fd, UF_COMPRESSED) != 0)
|
|
811
|
+
a->todo &= ~TODO_HFS_COMPRESSION;
|
|
812
|
+
}
|
|
813
|
+
#endif
|
|
814
|
+
|
|
815
|
+
/*
|
|
816
|
+
* TODO: There are rumours that some extended attributes must
|
|
817
|
+
* be restored before file data is written. If this is true,
|
|
818
|
+
* then we either need to write all extended attributes both
|
|
819
|
+
* before and after restoring the data, or find some rule for
|
|
820
|
+
* determining which must go first and which last. Due to the
|
|
821
|
+
* many ways people are using xattrs, this may prove to be an
|
|
822
|
+
* intractable problem.
|
|
823
|
+
*/
|
|
824
|
+
|
|
825
|
+
#ifdef HAVE_FCHDIR
|
|
826
|
+
/* If we changed directory above, restore it here. */
|
|
827
|
+
if (a->restore_pwd >= 0) {
|
|
828
|
+
r = fchdir(a->restore_pwd);
|
|
829
|
+
if (r != 0) {
|
|
830
|
+
archive_set_error(&a->archive, errno,
|
|
831
|
+
"chdir() failure");
|
|
832
|
+
ret = ARCHIVE_FATAL;
|
|
833
|
+
}
|
|
834
|
+
close(a->restore_pwd);
|
|
835
|
+
a->restore_pwd = -1;
|
|
836
|
+
}
|
|
837
|
+
#endif
|
|
838
|
+
|
|
839
|
+
/*
|
|
840
|
+
* Fixup uses the unedited pathname from archive_entry_pathname(),
|
|
841
|
+
* because it is relative to the base dir and the edited path
|
|
842
|
+
* might be relative to some intermediate dir as a result of the
|
|
843
|
+
* deep restore logic.
|
|
844
|
+
*/
|
|
845
|
+
if (a->deferred & TODO_MODE) {
|
|
846
|
+
fe = current_fixup(a, archive_entry_pathname(entry));
|
|
847
|
+
if (fe == NULL)
|
|
848
|
+
return (ARCHIVE_FATAL);
|
|
849
|
+
fe->filetype = archive_entry_filetype(entry);
|
|
850
|
+
fe->fixup |= TODO_MODE_BASE;
|
|
851
|
+
fe->mode = a->mode;
|
|
852
|
+
}
|
|
853
|
+
|
|
854
|
+
if ((a->deferred & TODO_TIMES)
|
|
855
|
+
&& (archive_entry_mtime_is_set(entry)
|
|
856
|
+
|| archive_entry_atime_is_set(entry))) {
|
|
857
|
+
fe = current_fixup(a, archive_entry_pathname(entry));
|
|
858
|
+
if (fe == NULL)
|
|
859
|
+
return (ARCHIVE_FATAL);
|
|
860
|
+
fe->filetype = archive_entry_filetype(entry);
|
|
861
|
+
fe->mode = a->mode;
|
|
862
|
+
fe->fixup |= TODO_TIMES;
|
|
863
|
+
if (archive_entry_atime_is_set(entry)) {
|
|
864
|
+
fe->atime = archive_entry_atime(entry);
|
|
865
|
+
fe->atime_nanos = archive_entry_atime_nsec(entry);
|
|
866
|
+
} else {
|
|
867
|
+
/* If atime is unset, use start time. */
|
|
868
|
+
fe->atime = a->start_time;
|
|
869
|
+
fe->atime_nanos = 0;
|
|
870
|
+
}
|
|
871
|
+
if (archive_entry_mtime_is_set(entry)) {
|
|
872
|
+
fe->mtime = archive_entry_mtime(entry);
|
|
873
|
+
fe->mtime_nanos = archive_entry_mtime_nsec(entry);
|
|
874
|
+
} else {
|
|
875
|
+
/* If mtime is unset, use start time. */
|
|
876
|
+
fe->mtime = a->start_time;
|
|
877
|
+
fe->mtime_nanos = 0;
|
|
878
|
+
}
|
|
879
|
+
if (archive_entry_birthtime_is_set(entry)) {
|
|
880
|
+
fe->birthtime = archive_entry_birthtime(entry);
|
|
881
|
+
fe->birthtime_nanos = archive_entry_birthtime_nsec(
|
|
882
|
+
entry);
|
|
883
|
+
} else {
|
|
884
|
+
/* If birthtime is unset, use mtime. */
|
|
885
|
+
fe->birthtime = fe->mtime;
|
|
886
|
+
fe->birthtime_nanos = fe->mtime_nanos;
|
|
887
|
+
}
|
|
888
|
+
}
|
|
889
|
+
|
|
890
|
+
if (a->deferred & TODO_ACLS) {
|
|
891
|
+
fe = current_fixup(a, archive_entry_pathname(entry));
|
|
892
|
+
if (fe == NULL)
|
|
893
|
+
return (ARCHIVE_FATAL);
|
|
894
|
+
fe->filetype = archive_entry_filetype(entry);
|
|
895
|
+
fe->fixup |= TODO_ACLS;
|
|
896
|
+
archive_acl_copy(&fe->acl, archive_entry_acl(entry));
|
|
897
|
+
}
|
|
898
|
+
|
|
899
|
+
if (a->deferred & TODO_MAC_METADATA) {
|
|
900
|
+
const void *metadata;
|
|
901
|
+
size_t metadata_size;
|
|
902
|
+
metadata = archive_entry_mac_metadata(a->entry, &metadata_size);
|
|
903
|
+
if (metadata != NULL && metadata_size > 0) {
|
|
904
|
+
fe = current_fixup(a, archive_entry_pathname(entry));
|
|
905
|
+
if (fe == NULL)
|
|
906
|
+
return (ARCHIVE_FATAL);
|
|
907
|
+
fe->filetype = archive_entry_filetype(entry);
|
|
908
|
+
fe->mac_metadata = malloc(metadata_size);
|
|
909
|
+
if (fe->mac_metadata != NULL) {
|
|
910
|
+
memcpy(fe->mac_metadata, metadata,
|
|
911
|
+
metadata_size);
|
|
912
|
+
fe->mac_metadata_size = metadata_size;
|
|
913
|
+
fe->fixup |= TODO_MAC_METADATA;
|
|
914
|
+
}
|
|
915
|
+
}
|
|
916
|
+
}
|
|
917
|
+
|
|
918
|
+
if (a->deferred & TODO_FFLAGS) {
|
|
919
|
+
fe = current_fixup(a, archive_entry_pathname(entry));
|
|
920
|
+
if (fe == NULL)
|
|
921
|
+
return (ARCHIVE_FATAL);
|
|
922
|
+
fe->filetype = archive_entry_filetype(entry);
|
|
923
|
+
fe->fixup |= TODO_FFLAGS;
|
|
924
|
+
/* TODO: Complete this.. defer fflags from below. */
|
|
925
|
+
}
|
|
926
|
+
|
|
927
|
+
/* We've created the object and are ready to pour data into it. */
|
|
928
|
+
if (ret >= ARCHIVE_WARN)
|
|
929
|
+
a->archive.state = ARCHIVE_STATE_DATA;
|
|
930
|
+
/*
|
|
931
|
+
* If it's not open, tell our client not to try writing.
|
|
932
|
+
* In particular, dirs, links, etc, don't get written to.
|
|
933
|
+
*/
|
|
934
|
+
if (a->fd < 0) {
|
|
935
|
+
archive_entry_set_size(entry, 0);
|
|
936
|
+
a->filesize = 0;
|
|
937
|
+
}
|
|
938
|
+
|
|
939
|
+
return (ret);
|
|
940
|
+
}
|
|
941
|
+
|
|
942
|
+
int
|
|
943
|
+
archive_write_disk_set_skip_file(struct archive *_a, la_int64_t d, la_int64_t i)
|
|
944
|
+
{
|
|
945
|
+
struct archive_write_disk *a = (struct archive_write_disk *)_a;
|
|
946
|
+
archive_check_magic(&a->archive, ARCHIVE_WRITE_DISK_MAGIC,
|
|
947
|
+
ARCHIVE_STATE_ANY, "archive_write_disk_set_skip_file");
|
|
948
|
+
a->skip_file_set = 1;
|
|
949
|
+
a->skip_file_dev = d;
|
|
950
|
+
a->skip_file_ino = i;
|
|
951
|
+
return (ARCHIVE_OK);
|
|
952
|
+
}
|
|
953
|
+
|
|
954
|
+
static ssize_t
|
|
955
|
+
write_data_block(struct archive_write_disk *a, const char *buff, size_t size)
|
|
956
|
+
{
|
|
957
|
+
uint64_t start_size = size;
|
|
958
|
+
ssize_t bytes_written = 0;
|
|
959
|
+
ssize_t block_size = 0, bytes_to_write;
|
|
960
|
+
|
|
961
|
+
if (size == 0)
|
|
962
|
+
return (ARCHIVE_OK);
|
|
963
|
+
|
|
964
|
+
if (a->filesize == 0 || a->fd < 0) {
|
|
965
|
+
archive_set_error(&a->archive, 0,
|
|
966
|
+
"Attempt to write to an empty file");
|
|
967
|
+
return (ARCHIVE_WARN);
|
|
968
|
+
}
|
|
969
|
+
|
|
970
|
+
if (a->flags & ARCHIVE_EXTRACT_SPARSE) {
|
|
971
|
+
#if HAVE_STRUCT_STAT_ST_BLKSIZE
|
|
972
|
+
int r;
|
|
973
|
+
if ((r = lazy_stat(a)) != ARCHIVE_OK)
|
|
974
|
+
return (r);
|
|
975
|
+
block_size = a->pst->st_blksize;
|
|
976
|
+
#else
|
|
977
|
+
/* XXX TODO XXX Is there a more appropriate choice here ? */
|
|
978
|
+
/* This needn't match the filesystem allocation size. */
|
|
979
|
+
block_size = 16*1024;
|
|
980
|
+
#endif
|
|
981
|
+
}
|
|
982
|
+
|
|
983
|
+
/* If this write would run beyond the file size, truncate it. */
|
|
984
|
+
if (a->filesize >= 0 && (int64_t)(a->offset + size) > a->filesize)
|
|
985
|
+
start_size = size = (size_t)(a->filesize - a->offset);
|
|
986
|
+
|
|
987
|
+
/* Write the data. */
|
|
988
|
+
while (size > 0) {
|
|
989
|
+
if (block_size == 0) {
|
|
990
|
+
bytes_to_write = size;
|
|
991
|
+
} else {
|
|
992
|
+
/* We're sparsifying the file. */
|
|
993
|
+
const char *p, *end;
|
|
994
|
+
int64_t block_end;
|
|
995
|
+
|
|
996
|
+
/* Skip leading zero bytes. */
|
|
997
|
+
for (p = buff, end = buff + size; p < end; ++p) {
|
|
998
|
+
if (*p != '\0')
|
|
999
|
+
break;
|
|
1000
|
+
}
|
|
1001
|
+
a->offset += p - buff;
|
|
1002
|
+
size -= p - buff;
|
|
1003
|
+
buff = p;
|
|
1004
|
+
if (size == 0)
|
|
1005
|
+
break;
|
|
1006
|
+
|
|
1007
|
+
/* Calculate next block boundary after offset. */
|
|
1008
|
+
block_end
|
|
1009
|
+
= (a->offset / block_size + 1) * block_size;
|
|
1010
|
+
|
|
1011
|
+
/* If the adjusted write would cross block boundary,
|
|
1012
|
+
* truncate it to the block boundary. */
|
|
1013
|
+
bytes_to_write = size;
|
|
1014
|
+
if (a->offset + bytes_to_write > block_end)
|
|
1015
|
+
bytes_to_write = block_end - a->offset;
|
|
1016
|
+
}
|
|
1017
|
+
/* Seek if necessary to the specified offset. */
|
|
1018
|
+
if (a->offset != a->fd_offset) {
|
|
1019
|
+
if (lseek(a->fd, a->offset, SEEK_SET) < 0) {
|
|
1020
|
+
archive_set_error(&a->archive, errno,
|
|
1021
|
+
"Seek failed");
|
|
1022
|
+
return (ARCHIVE_FATAL);
|
|
1023
|
+
}
|
|
1024
|
+
a->fd_offset = a->offset;
|
|
1025
|
+
}
|
|
1026
|
+
bytes_written = write(a->fd, buff, bytes_to_write);
|
|
1027
|
+
if (bytes_written < 0) {
|
|
1028
|
+
archive_set_error(&a->archive, errno, "Write failed");
|
|
1029
|
+
return (ARCHIVE_WARN);
|
|
1030
|
+
}
|
|
1031
|
+
buff += bytes_written;
|
|
1032
|
+
size -= bytes_written;
|
|
1033
|
+
a->total_bytes_written += bytes_written;
|
|
1034
|
+
a->offset += bytes_written;
|
|
1035
|
+
a->fd_offset = a->offset;
|
|
1036
|
+
}
|
|
1037
|
+
return (start_size - size);
|
|
1038
|
+
}
|
|
1039
|
+
|
|
1040
|
+
#if defined(__APPLE__) && defined(UF_COMPRESSED) && defined(HAVE_SYS_XATTR_H)\
|
|
1041
|
+
&& defined(HAVE_ZLIB_H)
|
|
1042
|
+
|
|
1043
|
+
/*
|
|
1044
|
+
* Set UF_COMPRESSED file flag.
|
|
1045
|
+
* This have to be called after hfs_write_decmpfs() because if the
|
|
1046
|
+
* file does not have "com.apple.decmpfs" xattr the flag is ignored.
|
|
1047
|
+
*/
|
|
1048
|
+
static int
|
|
1049
|
+
hfs_set_compressed_fflag(struct archive_write_disk *a)
|
|
1050
|
+
{
|
|
1051
|
+
int r;
|
|
1052
|
+
|
|
1053
|
+
if ((r = lazy_stat(a)) != ARCHIVE_OK)
|
|
1054
|
+
return (r);
|
|
1055
|
+
|
|
1056
|
+
a->st.st_flags |= UF_COMPRESSED;
|
|
1057
|
+
if (fchflags(a->fd, a->st.st_flags) != 0) {
|
|
1058
|
+
archive_set_error(&a->archive, errno,
|
|
1059
|
+
"Failed to set UF_COMPRESSED file flag");
|
|
1060
|
+
return (ARCHIVE_WARN);
|
|
1061
|
+
}
|
|
1062
|
+
return (ARCHIVE_OK);
|
|
1063
|
+
}
|
|
1064
|
+
|
|
1065
|
+
/*
|
|
1066
|
+
* HFS+ Compression decmpfs
|
|
1067
|
+
*
|
|
1068
|
+
* +------------------------------+ +0
|
|
1069
|
+
* | Magic(LE 4 bytes) |
|
|
1070
|
+
* +------------------------------+
|
|
1071
|
+
* | Type(LE 4 bytes) |
|
|
1072
|
+
* +------------------------------+
|
|
1073
|
+
* | Uncompressed size(LE 8 bytes)|
|
|
1074
|
+
* +------------------------------+ +16
|
|
1075
|
+
* | |
|
|
1076
|
+
* | Compressed data |
|
|
1077
|
+
* | (Placed only if Type == 3) |
|
|
1078
|
+
* | |
|
|
1079
|
+
* +------------------------------+ +3802 = MAX_DECMPFS_XATTR_SIZE
|
|
1080
|
+
*
|
|
1081
|
+
* Type is 3: decmpfs has compressed data.
|
|
1082
|
+
* Type is 4: Resource Fork has compressed data.
|
|
1083
|
+
*/
|
|
1084
|
+
/*
|
|
1085
|
+
* Write "com.apple.decmpfs"
|
|
1086
|
+
*/
|
|
1087
|
+
static int
|
|
1088
|
+
hfs_write_decmpfs(struct archive_write_disk *a)
|
|
1089
|
+
{
|
|
1090
|
+
int r;
|
|
1091
|
+
uint32_t compression_type;
|
|
1092
|
+
|
|
1093
|
+
r = fsetxattr(a->fd, DECMPFS_XATTR_NAME, a->decmpfs_header_p,
|
|
1094
|
+
a->decmpfs_attr_size, 0, 0);
|
|
1095
|
+
if (r < 0) {
|
|
1096
|
+
archive_set_error(&a->archive, errno,
|
|
1097
|
+
"Cannot restore xattr:%s", DECMPFS_XATTR_NAME);
|
|
1098
|
+
compression_type = archive_le32dec(
|
|
1099
|
+
&a->decmpfs_header_p[DECMPFS_COMPRESSION_TYPE]);
|
|
1100
|
+
if (compression_type == CMP_RESOURCE_FORK)
|
|
1101
|
+
fremovexattr(a->fd, XATTR_RESOURCEFORK_NAME,
|
|
1102
|
+
XATTR_SHOWCOMPRESSION);
|
|
1103
|
+
return (ARCHIVE_WARN);
|
|
1104
|
+
}
|
|
1105
|
+
return (ARCHIVE_OK);
|
|
1106
|
+
}
|
|
1107
|
+
|
|
1108
|
+
/*
|
|
1109
|
+
* HFS+ Compression Resource Fork
|
|
1110
|
+
*
|
|
1111
|
+
* +-----------------------------+
|
|
1112
|
+
* | Header(260 bytes) |
|
|
1113
|
+
* +-----------------------------+
|
|
1114
|
+
* | Block count(LE 4 bytes) |
|
|
1115
|
+
* +-----------------------------+ --+
|
|
1116
|
+
* +-- | Offset (LE 4 bytes) | |
|
|
1117
|
+
* | | [distance from Block count] | | Block 0
|
|
1118
|
+
* | +-----------------------------+ |
|
|
1119
|
+
* | | Compressed size(LE 4 bytes) | |
|
|
1120
|
+
* | +-----------------------------+ --+
|
|
1121
|
+
* | | |
|
|
1122
|
+
* | | .................. |
|
|
1123
|
+
* | | |
|
|
1124
|
+
* | +-----------------------------+ --+
|
|
1125
|
+
* | | Offset (LE 4 bytes) | |
|
|
1126
|
+
* | +-----------------------------+ | Block (Block count -1)
|
|
1127
|
+
* | | Compressed size(LE 4 bytes) | |
|
|
1128
|
+
* +-> +-----------------------------+ --+
|
|
1129
|
+
* | Compressed data(n bytes) | Block 0
|
|
1130
|
+
* +-----------------------------+
|
|
1131
|
+
* | |
|
|
1132
|
+
* | .................. |
|
|
1133
|
+
* | |
|
|
1134
|
+
* +-----------------------------+
|
|
1135
|
+
* | Compressed data(n bytes) | Block (Block count -1)
|
|
1136
|
+
* +-----------------------------+
|
|
1137
|
+
* | Footer(50 bytes) |
|
|
1138
|
+
* +-----------------------------+
|
|
1139
|
+
*
|
|
1140
|
+
*/
|
|
1141
|
+
/*
|
|
1142
|
+
* Write the header of "com.apple.ResourceFork"
|
|
1143
|
+
*/
|
|
1144
|
+
static int
|
|
1145
|
+
hfs_write_resource_fork(struct archive_write_disk *a, unsigned char *buff,
|
|
1146
|
+
size_t bytes, uint32_t position)
|
|
1147
|
+
{
|
|
1148
|
+
int ret;
|
|
1149
|
+
|
|
1150
|
+
ret = fsetxattr(a->fd, XATTR_RESOURCEFORK_NAME, buff, bytes,
|
|
1151
|
+
position, a->rsrc_xattr_options);
|
|
1152
|
+
if (ret < 0) {
|
|
1153
|
+
archive_set_error(&a->archive, errno,
|
|
1154
|
+
"Cannot restore xattr: %s at %u pos %u bytes",
|
|
1155
|
+
XATTR_RESOURCEFORK_NAME,
|
|
1156
|
+
(unsigned)position,
|
|
1157
|
+
(unsigned)bytes);
|
|
1158
|
+
return (ARCHIVE_WARN);
|
|
1159
|
+
}
|
|
1160
|
+
a->rsrc_xattr_options &= ~XATTR_CREATE;
|
|
1161
|
+
return (ARCHIVE_OK);
|
|
1162
|
+
}
|
|
1163
|
+
|
|
1164
|
+
static int
|
|
1165
|
+
hfs_write_compressed_data(struct archive_write_disk *a, size_t bytes_compressed)
|
|
1166
|
+
{
|
|
1167
|
+
int ret;
|
|
1168
|
+
|
|
1169
|
+
ret = hfs_write_resource_fork(a, a->compressed_buffer,
|
|
1170
|
+
bytes_compressed, a->compressed_rsrc_position);
|
|
1171
|
+
if (ret == ARCHIVE_OK)
|
|
1172
|
+
a->compressed_rsrc_position += bytes_compressed;
|
|
1173
|
+
return (ret);
|
|
1174
|
+
}
|
|
1175
|
+
|
|
1176
|
+
static int
|
|
1177
|
+
hfs_write_resource_fork_header(struct archive_write_disk *a)
|
|
1178
|
+
{
|
|
1179
|
+
unsigned char *buff;
|
|
1180
|
+
uint32_t rsrc_bytes;
|
|
1181
|
+
uint32_t rsrc_header_bytes;
|
|
1182
|
+
|
|
1183
|
+
/*
|
|
1184
|
+
* Write resource fork header + block info.
|
|
1185
|
+
*/
|
|
1186
|
+
buff = a->resource_fork;
|
|
1187
|
+
rsrc_bytes = a->compressed_rsrc_position - RSRC_F_SIZE;
|
|
1188
|
+
rsrc_header_bytes =
|
|
1189
|
+
RSRC_H_SIZE + /* Header base size. */
|
|
1190
|
+
4 + /* Block count. */
|
|
1191
|
+
(a->decmpfs_block_count * 8);/* Block info */
|
|
1192
|
+
archive_be32enc(buff, 0x100);
|
|
1193
|
+
archive_be32enc(buff + 4, rsrc_bytes);
|
|
1194
|
+
archive_be32enc(buff + 8, rsrc_bytes - 256);
|
|
1195
|
+
archive_be32enc(buff + 12, 0x32);
|
|
1196
|
+
memset(buff + 16, 0, 240);
|
|
1197
|
+
archive_be32enc(buff + 256, rsrc_bytes - 260);
|
|
1198
|
+
return hfs_write_resource_fork(a, buff, rsrc_header_bytes, 0);
|
|
1199
|
+
}
|
|
1200
|
+
|
|
1201
|
+
static size_t
|
|
1202
|
+
hfs_set_resource_fork_footer(unsigned char *buff, size_t buff_size)
|
|
1203
|
+
{
|
|
1204
|
+
static const char rsrc_footer[RSRC_F_SIZE] = {
|
|
1205
|
+
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
1206
|
+
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
1207
|
+
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
1208
|
+
0x00, 0x1c, 0x00, 0x32, 0x00, 0x00, 'c', 'm',
|
|
1209
|
+
'p', 'f', 0x00, 0x00, 0x00, 0x0a, 0x00, 0x01,
|
|
1210
|
+
0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
1211
|
+
0x00, 0x00
|
|
1212
|
+
};
|
|
1213
|
+
if (buff_size < sizeof(rsrc_footer))
|
|
1214
|
+
return (0);
|
|
1215
|
+
memcpy(buff, rsrc_footer, sizeof(rsrc_footer));
|
|
1216
|
+
return (sizeof(rsrc_footer));
|
|
1217
|
+
}
|
|
1218
|
+
|
|
1219
|
+
static int
|
|
1220
|
+
hfs_reset_compressor(struct archive_write_disk *a)
|
|
1221
|
+
{
|
|
1222
|
+
int ret;
|
|
1223
|
+
|
|
1224
|
+
if (a->stream_valid)
|
|
1225
|
+
ret = deflateReset(&a->stream);
|
|
1226
|
+
else
|
|
1227
|
+
ret = deflateInit(&a->stream, a->decmpfs_compression_level);
|
|
1228
|
+
|
|
1229
|
+
if (ret != Z_OK) {
|
|
1230
|
+
archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
|
|
1231
|
+
"Failed to initialize compressor");
|
|
1232
|
+
return (ARCHIVE_FATAL);
|
|
1233
|
+
} else
|
|
1234
|
+
a->stream_valid = 1;
|
|
1235
|
+
|
|
1236
|
+
return (ARCHIVE_OK);
|
|
1237
|
+
}
|
|
1238
|
+
|
|
1239
|
+
static int
|
|
1240
|
+
hfs_decompress(struct archive_write_disk *a)
|
|
1241
|
+
{
|
|
1242
|
+
uint32_t *block_info;
|
|
1243
|
+
unsigned int block_count;
|
|
1244
|
+
uint32_t data_pos, data_size;
|
|
1245
|
+
ssize_t r;
|
|
1246
|
+
ssize_t bytes_written, bytes_to_write;
|
|
1247
|
+
unsigned char *b;
|
|
1248
|
+
|
|
1249
|
+
block_info = (uint32_t *)(a->resource_fork + RSRC_H_SIZE);
|
|
1250
|
+
block_count = archive_le32dec(block_info++);
|
|
1251
|
+
while (block_count--) {
|
|
1252
|
+
data_pos = RSRC_H_SIZE + archive_le32dec(block_info++);
|
|
1253
|
+
data_size = archive_le32dec(block_info++);
|
|
1254
|
+
r = fgetxattr(a->fd, XATTR_RESOURCEFORK_NAME,
|
|
1255
|
+
a->compressed_buffer, data_size, data_pos, 0);
|
|
1256
|
+
if (r != data_size) {
|
|
1257
|
+
archive_set_error(&a->archive,
|
|
1258
|
+
(r < 0)?errno:ARCHIVE_ERRNO_MISC,
|
|
1259
|
+
"Failed to read resource fork");
|
|
1260
|
+
return (ARCHIVE_WARN);
|
|
1261
|
+
}
|
|
1262
|
+
if (a->compressed_buffer[0] == 0xff) {
|
|
1263
|
+
bytes_to_write = data_size -1;
|
|
1264
|
+
b = a->compressed_buffer + 1;
|
|
1265
|
+
} else {
|
|
1266
|
+
uLong dest_len = MAX_DECMPFS_BLOCK_SIZE;
|
|
1267
|
+
int zr;
|
|
1268
|
+
|
|
1269
|
+
zr = uncompress((Bytef *)a->uncompressed_buffer,
|
|
1270
|
+
&dest_len, a->compressed_buffer, data_size);
|
|
1271
|
+
if (zr != Z_OK) {
|
|
1272
|
+
archive_set_error(&a->archive,
|
|
1273
|
+
ARCHIVE_ERRNO_MISC,
|
|
1274
|
+
"Failed to decompress resource fork");
|
|
1275
|
+
return (ARCHIVE_WARN);
|
|
1276
|
+
}
|
|
1277
|
+
bytes_to_write = dest_len;
|
|
1278
|
+
b = (unsigned char *)a->uncompressed_buffer;
|
|
1279
|
+
}
|
|
1280
|
+
do {
|
|
1281
|
+
bytes_written = write(a->fd, b, bytes_to_write);
|
|
1282
|
+
if (bytes_written < 0) {
|
|
1283
|
+
archive_set_error(&a->archive, errno,
|
|
1284
|
+
"Write failed");
|
|
1285
|
+
return (ARCHIVE_WARN);
|
|
1286
|
+
}
|
|
1287
|
+
bytes_to_write -= bytes_written;
|
|
1288
|
+
b += bytes_written;
|
|
1289
|
+
} while (bytes_to_write > 0);
|
|
1290
|
+
}
|
|
1291
|
+
r = fremovexattr(a->fd, XATTR_RESOURCEFORK_NAME, 0);
|
|
1292
|
+
if (r == -1) {
|
|
1293
|
+
archive_set_error(&a->archive, errno,
|
|
1294
|
+
"Failed to remove resource fork");
|
|
1295
|
+
return (ARCHIVE_WARN);
|
|
1296
|
+
}
|
|
1297
|
+
return (ARCHIVE_OK);
|
|
1298
|
+
}
|
|
1299
|
+
|
|
1300
|
+
static int
|
|
1301
|
+
hfs_drive_compressor(struct archive_write_disk *a, const char *buff,
|
|
1302
|
+
size_t size)
|
|
1303
|
+
{
|
|
1304
|
+
unsigned char *buffer_compressed;
|
|
1305
|
+
size_t bytes_compressed;
|
|
1306
|
+
size_t bytes_used;
|
|
1307
|
+
int ret;
|
|
1308
|
+
|
|
1309
|
+
ret = hfs_reset_compressor(a);
|
|
1310
|
+
if (ret != ARCHIVE_OK)
|
|
1311
|
+
return (ret);
|
|
1312
|
+
|
|
1313
|
+
if (a->compressed_buffer == NULL) {
|
|
1314
|
+
size_t block_size;
|
|
1315
|
+
|
|
1316
|
+
block_size = COMPRESSED_W_SIZE + RSRC_F_SIZE +
|
|
1317
|
+
+ compressBound(MAX_DECMPFS_BLOCK_SIZE);
|
|
1318
|
+
a->compressed_buffer = malloc(block_size);
|
|
1319
|
+
if (a->compressed_buffer == NULL) {
|
|
1320
|
+
archive_set_error(&a->archive, ENOMEM,
|
|
1321
|
+
"Can't allocate memory for Resource Fork");
|
|
1322
|
+
return (ARCHIVE_FATAL);
|
|
1323
|
+
}
|
|
1324
|
+
a->compressed_buffer_size = block_size;
|
|
1325
|
+
a->compressed_buffer_remaining = block_size;
|
|
1326
|
+
}
|
|
1327
|
+
|
|
1328
|
+
buffer_compressed = a->compressed_buffer +
|
|
1329
|
+
a->compressed_buffer_size - a->compressed_buffer_remaining;
|
|
1330
|
+
a->stream.next_in = (Bytef *)(uintptr_t)(const void *)buff;
|
|
1331
|
+
a->stream.avail_in = size;
|
|
1332
|
+
a->stream.next_out = buffer_compressed;
|
|
1333
|
+
a->stream.avail_out = a->compressed_buffer_remaining;
|
|
1334
|
+
do {
|
|
1335
|
+
ret = deflate(&a->stream, Z_FINISH);
|
|
1336
|
+
switch (ret) {
|
|
1337
|
+
case Z_OK:
|
|
1338
|
+
case Z_STREAM_END:
|
|
1339
|
+
break;
|
|
1340
|
+
default:
|
|
1341
|
+
archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
|
|
1342
|
+
"Failed to compress data");
|
|
1343
|
+
return (ARCHIVE_FAILED);
|
|
1344
|
+
}
|
|
1345
|
+
} while (ret == Z_OK);
|
|
1346
|
+
bytes_compressed = a->compressed_buffer_remaining - a->stream.avail_out;
|
|
1347
|
+
|
|
1348
|
+
/*
|
|
1349
|
+
* If the compressed size is larger than the original size,
|
|
1350
|
+
* throw away compressed data, use uncompressed data instead.
|
|
1351
|
+
*/
|
|
1352
|
+
if (bytes_compressed > size) {
|
|
1353
|
+
buffer_compressed[0] = 0xFF;/* uncompressed marker. */
|
|
1354
|
+
memcpy(buffer_compressed + 1, buff, size);
|
|
1355
|
+
bytes_compressed = size + 1;
|
|
1356
|
+
}
|
|
1357
|
+
a->compressed_buffer_remaining -= bytes_compressed;
|
|
1358
|
+
|
|
1359
|
+
/*
|
|
1360
|
+
* If the compressed size is smaller than MAX_DECMPFS_XATTR_SIZE
|
|
1361
|
+
* and the block count in the file is only one, store compressed
|
|
1362
|
+
* data to decmpfs xattr instead of the resource fork.
|
|
1363
|
+
*/
|
|
1364
|
+
if (a->decmpfs_block_count == 1 &&
|
|
1365
|
+
(a->decmpfs_attr_size + bytes_compressed)
|
|
1366
|
+
<= MAX_DECMPFS_XATTR_SIZE) {
|
|
1367
|
+
archive_le32enc(&a->decmpfs_header_p[DECMPFS_COMPRESSION_TYPE],
|
|
1368
|
+
CMP_XATTR);
|
|
1369
|
+
memcpy(a->decmpfs_header_p + DECMPFS_HEADER_SIZE,
|
|
1370
|
+
buffer_compressed, bytes_compressed);
|
|
1371
|
+
a->decmpfs_attr_size += bytes_compressed;
|
|
1372
|
+
a->compressed_buffer_remaining = a->compressed_buffer_size;
|
|
1373
|
+
/*
|
|
1374
|
+
* Finish HFS+ Compression.
|
|
1375
|
+
* - Write the decmpfs xattr.
|
|
1376
|
+
* - Set the UF_COMPRESSED file flag.
|
|
1377
|
+
*/
|
|
1378
|
+
ret = hfs_write_decmpfs(a);
|
|
1379
|
+
if (ret == ARCHIVE_OK)
|
|
1380
|
+
ret = hfs_set_compressed_fflag(a);
|
|
1381
|
+
return (ret);
|
|
1382
|
+
}
|
|
1383
|
+
|
|
1384
|
+
/* Update block info. */
|
|
1385
|
+
archive_le32enc(a->decmpfs_block_info++,
|
|
1386
|
+
a->compressed_rsrc_position_v - RSRC_H_SIZE);
|
|
1387
|
+
archive_le32enc(a->decmpfs_block_info++, bytes_compressed);
|
|
1388
|
+
a->compressed_rsrc_position_v += bytes_compressed;
|
|
1389
|
+
|
|
1390
|
+
/*
|
|
1391
|
+
* Write the compressed data to the resource fork.
|
|
1392
|
+
*/
|
|
1393
|
+
bytes_used = a->compressed_buffer_size - a->compressed_buffer_remaining;
|
|
1394
|
+
while (bytes_used >= COMPRESSED_W_SIZE) {
|
|
1395
|
+
ret = hfs_write_compressed_data(a, COMPRESSED_W_SIZE);
|
|
1396
|
+
if (ret != ARCHIVE_OK)
|
|
1397
|
+
return (ret);
|
|
1398
|
+
bytes_used -= COMPRESSED_W_SIZE;
|
|
1399
|
+
if (bytes_used > COMPRESSED_W_SIZE)
|
|
1400
|
+
memmove(a->compressed_buffer,
|
|
1401
|
+
a->compressed_buffer + COMPRESSED_W_SIZE,
|
|
1402
|
+
bytes_used);
|
|
1403
|
+
else
|
|
1404
|
+
memcpy(a->compressed_buffer,
|
|
1405
|
+
a->compressed_buffer + COMPRESSED_W_SIZE,
|
|
1406
|
+
bytes_used);
|
|
1407
|
+
}
|
|
1408
|
+
a->compressed_buffer_remaining = a->compressed_buffer_size - bytes_used;
|
|
1409
|
+
|
|
1410
|
+
/*
|
|
1411
|
+
* If the current block is the last block, write the remaining
|
|
1412
|
+
* compressed data and the resource fork footer.
|
|
1413
|
+
*/
|
|
1414
|
+
if (a->file_remaining_bytes == 0) {
|
|
1415
|
+
size_t rsrc_size;
|
|
1416
|
+
int64_t bk;
|
|
1417
|
+
|
|
1418
|
+
/* Append the resource footer. */
|
|
1419
|
+
rsrc_size = hfs_set_resource_fork_footer(
|
|
1420
|
+
a->compressed_buffer + bytes_used,
|
|
1421
|
+
a->compressed_buffer_remaining);
|
|
1422
|
+
ret = hfs_write_compressed_data(a, bytes_used + rsrc_size);
|
|
1423
|
+
a->compressed_buffer_remaining = a->compressed_buffer_size;
|
|
1424
|
+
|
|
1425
|
+
/* If the compressed size is not enough smaller than
|
|
1426
|
+
* the uncompressed size. cancel HFS+ compression.
|
|
1427
|
+
* TODO: study a behavior of ditto utility and improve
|
|
1428
|
+
* the condition to fall back into no HFS+ compression. */
|
|
1429
|
+
bk = HFS_BLOCKS(a->compressed_rsrc_position);
|
|
1430
|
+
bk += bk >> 7;
|
|
1431
|
+
if (bk > HFS_BLOCKS(a->filesize))
|
|
1432
|
+
return hfs_decompress(a);
|
|
1433
|
+
/*
|
|
1434
|
+
* Write the resourcefork header.
|
|
1435
|
+
*/
|
|
1436
|
+
if (ret == ARCHIVE_OK)
|
|
1437
|
+
ret = hfs_write_resource_fork_header(a);
|
|
1438
|
+
/*
|
|
1439
|
+
* Finish HFS+ Compression.
|
|
1440
|
+
* - Write the decmpfs xattr.
|
|
1441
|
+
* - Set the UF_COMPRESSED file flag.
|
|
1442
|
+
*/
|
|
1443
|
+
if (ret == ARCHIVE_OK)
|
|
1444
|
+
ret = hfs_write_decmpfs(a);
|
|
1445
|
+
if (ret == ARCHIVE_OK)
|
|
1446
|
+
ret = hfs_set_compressed_fflag(a);
|
|
1447
|
+
}
|
|
1448
|
+
return (ret);
|
|
1449
|
+
}
|
|
1450
|
+
|
|
1451
|
+
static ssize_t
|
|
1452
|
+
hfs_write_decmpfs_block(struct archive_write_disk *a, const char *buff,
|
|
1453
|
+
size_t size)
|
|
1454
|
+
{
|
|
1455
|
+
const char *buffer_to_write;
|
|
1456
|
+
size_t bytes_to_write;
|
|
1457
|
+
int ret;
|
|
1458
|
+
|
|
1459
|
+
if (a->decmpfs_block_count == (unsigned)-1) {
|
|
1460
|
+
void *new_block;
|
|
1461
|
+
size_t new_size;
|
|
1462
|
+
unsigned int block_count;
|
|
1463
|
+
|
|
1464
|
+
if (a->decmpfs_header_p == NULL) {
|
|
1465
|
+
new_block = malloc(MAX_DECMPFS_XATTR_SIZE
|
|
1466
|
+
+ sizeof(uint32_t));
|
|
1467
|
+
if (new_block == NULL) {
|
|
1468
|
+
archive_set_error(&a->archive, ENOMEM,
|
|
1469
|
+
"Can't allocate memory for decmpfs");
|
|
1470
|
+
return (ARCHIVE_FATAL);
|
|
1471
|
+
}
|
|
1472
|
+
a->decmpfs_header_p = new_block;
|
|
1473
|
+
}
|
|
1474
|
+
a->decmpfs_attr_size = DECMPFS_HEADER_SIZE;
|
|
1475
|
+
archive_le32enc(&a->decmpfs_header_p[DECMPFS_COMPRESSION_MAGIC],
|
|
1476
|
+
DECMPFS_MAGIC);
|
|
1477
|
+
archive_le32enc(&a->decmpfs_header_p[DECMPFS_COMPRESSION_TYPE],
|
|
1478
|
+
CMP_RESOURCE_FORK);
|
|
1479
|
+
archive_le64enc(&a->decmpfs_header_p[DECMPFS_UNCOMPRESSED_SIZE],
|
|
1480
|
+
a->filesize);
|
|
1481
|
+
|
|
1482
|
+
/* Calculate a block count of the file. */
|
|
1483
|
+
block_count =
|
|
1484
|
+
(a->filesize + MAX_DECMPFS_BLOCK_SIZE -1) /
|
|
1485
|
+
MAX_DECMPFS_BLOCK_SIZE;
|
|
1486
|
+
/*
|
|
1487
|
+
* Allocate buffer for resource fork.
|
|
1488
|
+
* Set up related pointers;
|
|
1489
|
+
*/
|
|
1490
|
+
new_size =
|
|
1491
|
+
RSRC_H_SIZE + /* header */
|
|
1492
|
+
4 + /* Block count */
|
|
1493
|
+
(block_count * sizeof(uint32_t) * 2) +
|
|
1494
|
+
RSRC_F_SIZE; /* footer */
|
|
1495
|
+
if (new_size > a->resource_fork_allocated_size) {
|
|
1496
|
+
new_block = realloc(a->resource_fork, new_size);
|
|
1497
|
+
if (new_block == NULL) {
|
|
1498
|
+
archive_set_error(&a->archive, ENOMEM,
|
|
1499
|
+
"Can't allocate memory for ResourceFork");
|
|
1500
|
+
return (ARCHIVE_FATAL);
|
|
1501
|
+
}
|
|
1502
|
+
a->resource_fork_allocated_size = new_size;
|
|
1503
|
+
a->resource_fork = new_block;
|
|
1504
|
+
}
|
|
1505
|
+
|
|
1506
|
+
/* Allocate uncompressed buffer */
|
|
1507
|
+
if (a->uncompressed_buffer == NULL) {
|
|
1508
|
+
new_block = malloc(MAX_DECMPFS_BLOCK_SIZE);
|
|
1509
|
+
if (new_block == NULL) {
|
|
1510
|
+
archive_set_error(&a->archive, ENOMEM,
|
|
1511
|
+
"Can't allocate memory for decmpfs");
|
|
1512
|
+
return (ARCHIVE_FATAL);
|
|
1513
|
+
}
|
|
1514
|
+
a->uncompressed_buffer = new_block;
|
|
1515
|
+
}
|
|
1516
|
+
a->block_remaining_bytes = MAX_DECMPFS_BLOCK_SIZE;
|
|
1517
|
+
a->file_remaining_bytes = a->filesize;
|
|
1518
|
+
a->compressed_buffer_remaining = a->compressed_buffer_size;
|
|
1519
|
+
|
|
1520
|
+
/*
|
|
1521
|
+
* Set up a resource fork.
|
|
1522
|
+
*/
|
|
1523
|
+
a->rsrc_xattr_options = XATTR_CREATE;
|
|
1524
|
+
/* Get the position where we are going to set a bunch
|
|
1525
|
+
* of block info. */
|
|
1526
|
+
a->decmpfs_block_info =
|
|
1527
|
+
(uint32_t *)(a->resource_fork + RSRC_H_SIZE);
|
|
1528
|
+
/* Set the block count to the resource fork. */
|
|
1529
|
+
archive_le32enc(a->decmpfs_block_info++, block_count);
|
|
1530
|
+
/* Get the position where we are going to set compressed
|
|
1531
|
+
* data. */
|
|
1532
|
+
a->compressed_rsrc_position =
|
|
1533
|
+
RSRC_H_SIZE + 4 + (block_count * 8);
|
|
1534
|
+
a->compressed_rsrc_position_v = a->compressed_rsrc_position;
|
|
1535
|
+
a->decmpfs_block_count = block_count;
|
|
1536
|
+
}
|
|
1537
|
+
|
|
1538
|
+
/* Ignore redundant bytes. */
|
|
1539
|
+
if (a->file_remaining_bytes == 0)
|
|
1540
|
+
return ((ssize_t)size);
|
|
1541
|
+
|
|
1542
|
+
/* Do not overrun a block size. */
|
|
1543
|
+
if (size > a->block_remaining_bytes)
|
|
1544
|
+
bytes_to_write = a->block_remaining_bytes;
|
|
1545
|
+
else
|
|
1546
|
+
bytes_to_write = size;
|
|
1547
|
+
/* Do not overrun the file size. */
|
|
1548
|
+
if (bytes_to_write > a->file_remaining_bytes)
|
|
1549
|
+
bytes_to_write = a->file_remaining_bytes;
|
|
1550
|
+
|
|
1551
|
+
/* For efficiency, if a copy length is full of the uncompressed
|
|
1552
|
+
* buffer size, do not copy writing data to it. */
|
|
1553
|
+
if (bytes_to_write == MAX_DECMPFS_BLOCK_SIZE)
|
|
1554
|
+
buffer_to_write = buff;
|
|
1555
|
+
else {
|
|
1556
|
+
memcpy(a->uncompressed_buffer +
|
|
1557
|
+
MAX_DECMPFS_BLOCK_SIZE - a->block_remaining_bytes,
|
|
1558
|
+
buff, bytes_to_write);
|
|
1559
|
+
buffer_to_write = a->uncompressed_buffer;
|
|
1560
|
+
}
|
|
1561
|
+
a->block_remaining_bytes -= bytes_to_write;
|
|
1562
|
+
a->file_remaining_bytes -= bytes_to_write;
|
|
1563
|
+
|
|
1564
|
+
if (a->block_remaining_bytes == 0 || a->file_remaining_bytes == 0) {
|
|
1565
|
+
ret = hfs_drive_compressor(a, buffer_to_write,
|
|
1566
|
+
MAX_DECMPFS_BLOCK_SIZE - a->block_remaining_bytes);
|
|
1567
|
+
if (ret < 0)
|
|
1568
|
+
return (ret);
|
|
1569
|
+
a->block_remaining_bytes = MAX_DECMPFS_BLOCK_SIZE;
|
|
1570
|
+
}
|
|
1571
|
+
/* Ignore redundant bytes. */
|
|
1572
|
+
if (a->file_remaining_bytes == 0)
|
|
1573
|
+
return ((ssize_t)size);
|
|
1574
|
+
return (bytes_to_write);
|
|
1575
|
+
}
|
|
1576
|
+
|
|
1577
|
+
static ssize_t
|
|
1578
|
+
hfs_write_data_block(struct archive_write_disk *a, const char *buff,
|
|
1579
|
+
size_t size)
|
|
1580
|
+
{
|
|
1581
|
+
uint64_t start_size = size;
|
|
1582
|
+
ssize_t bytes_written = 0;
|
|
1583
|
+
ssize_t bytes_to_write;
|
|
1584
|
+
|
|
1585
|
+
if (size == 0)
|
|
1586
|
+
return (ARCHIVE_OK);
|
|
1587
|
+
|
|
1588
|
+
if (a->filesize == 0 || a->fd < 0) {
|
|
1589
|
+
archive_set_error(&a->archive, 0,
|
|
1590
|
+
"Attempt to write to an empty file");
|
|
1591
|
+
return (ARCHIVE_WARN);
|
|
1592
|
+
}
|
|
1593
|
+
|
|
1594
|
+
/* If this write would run beyond the file size, truncate it. */
|
|
1595
|
+
if (a->filesize >= 0 && (int64_t)(a->offset + size) > a->filesize)
|
|
1596
|
+
start_size = size = (size_t)(a->filesize - a->offset);
|
|
1597
|
+
|
|
1598
|
+
/* Write the data. */
|
|
1599
|
+
while (size > 0) {
|
|
1600
|
+
bytes_to_write = size;
|
|
1601
|
+
/* Seek if necessary to the specified offset. */
|
|
1602
|
+
if (a->offset < a->fd_offset) {
|
|
1603
|
+
/* Can't support backward move. */
|
|
1604
|
+
archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
|
|
1605
|
+
"Seek failed");
|
|
1606
|
+
return (ARCHIVE_FATAL);
|
|
1607
|
+
} else if (a->offset > a->fd_offset) {
|
|
1608
|
+
int64_t skip = a->offset - a->fd_offset;
|
|
1609
|
+
char nullblock[1024];
|
|
1610
|
+
|
|
1611
|
+
memset(nullblock, 0, sizeof(nullblock));
|
|
1612
|
+
while (skip > 0) {
|
|
1613
|
+
if (skip > (int64_t)sizeof(nullblock))
|
|
1614
|
+
bytes_written = hfs_write_decmpfs_block(
|
|
1615
|
+
a, nullblock, sizeof(nullblock));
|
|
1616
|
+
else
|
|
1617
|
+
bytes_written = hfs_write_decmpfs_block(
|
|
1618
|
+
a, nullblock, skip);
|
|
1619
|
+
if (bytes_written < 0) {
|
|
1620
|
+
archive_set_error(&a->archive, errno,
|
|
1621
|
+
"Write failed");
|
|
1622
|
+
return (ARCHIVE_WARN);
|
|
1623
|
+
}
|
|
1624
|
+
skip -= bytes_written;
|
|
1625
|
+
}
|
|
1626
|
+
|
|
1627
|
+
a->fd_offset = a->offset;
|
|
1628
|
+
}
|
|
1629
|
+
bytes_written =
|
|
1630
|
+
hfs_write_decmpfs_block(a, buff, bytes_to_write);
|
|
1631
|
+
if (bytes_written < 0)
|
|
1632
|
+
return (bytes_written);
|
|
1633
|
+
buff += bytes_written;
|
|
1634
|
+
size -= bytes_written;
|
|
1635
|
+
a->total_bytes_written += bytes_written;
|
|
1636
|
+
a->offset += bytes_written;
|
|
1637
|
+
a->fd_offset = a->offset;
|
|
1638
|
+
}
|
|
1639
|
+
return (start_size - size);
|
|
1640
|
+
}
|
|
1641
|
+
#else
|
|
1642
|
+
static ssize_t
|
|
1643
|
+
hfs_write_data_block(struct archive_write_disk *a, const char *buff,
|
|
1644
|
+
size_t size)
|
|
1645
|
+
{
|
|
1646
|
+
return (write_data_block(a, buff, size));
|
|
1647
|
+
}
|
|
1648
|
+
#endif
|
|
1649
|
+
|
|
1650
|
+
static ssize_t
|
|
1651
|
+
_archive_write_disk_data_block(struct archive *_a,
|
|
1652
|
+
const void *buff, size_t size, int64_t offset)
|
|
1653
|
+
{
|
|
1654
|
+
struct archive_write_disk *a = (struct archive_write_disk *)_a;
|
|
1655
|
+
ssize_t r;
|
|
1656
|
+
|
|
1657
|
+
archive_check_magic(&a->archive, ARCHIVE_WRITE_DISK_MAGIC,
|
|
1658
|
+
ARCHIVE_STATE_DATA, "archive_write_data_block");
|
|
1659
|
+
|
|
1660
|
+
a->offset = offset;
|
|
1661
|
+
if (a->todo & TODO_HFS_COMPRESSION)
|
|
1662
|
+
r = hfs_write_data_block(a, buff, size);
|
|
1663
|
+
else
|
|
1664
|
+
r = write_data_block(a, buff, size);
|
|
1665
|
+
if (r < ARCHIVE_OK)
|
|
1666
|
+
return (r);
|
|
1667
|
+
if ((size_t)r < size) {
|
|
1668
|
+
archive_set_error(&a->archive, 0,
|
|
1669
|
+
"Too much data: Truncating file at %ju bytes",
|
|
1670
|
+
(uintmax_t)a->filesize);
|
|
1671
|
+
return (ARCHIVE_WARN);
|
|
1672
|
+
}
|
|
1673
|
+
#if ARCHIVE_VERSION_NUMBER < 3999000
|
|
1674
|
+
return (ARCHIVE_OK);
|
|
1675
|
+
#else
|
|
1676
|
+
return (size);
|
|
1677
|
+
#endif
|
|
1678
|
+
}
|
|
1679
|
+
|
|
1680
|
+
static ssize_t
|
|
1681
|
+
_archive_write_disk_data(struct archive *_a, const void *buff, size_t size)
|
|
1682
|
+
{
|
|
1683
|
+
struct archive_write_disk *a = (struct archive_write_disk *)_a;
|
|
1684
|
+
|
|
1685
|
+
archive_check_magic(&a->archive, ARCHIVE_WRITE_DISK_MAGIC,
|
|
1686
|
+
ARCHIVE_STATE_DATA, "archive_write_data");
|
|
1687
|
+
|
|
1688
|
+
if (a->todo & TODO_HFS_COMPRESSION)
|
|
1689
|
+
return (hfs_write_data_block(a, buff, size));
|
|
1690
|
+
return (write_data_block(a, buff, size));
|
|
1691
|
+
}
|
|
1692
|
+
|
|
1693
|
+
static int
|
|
1694
|
+
_archive_write_disk_finish_entry(struct archive *_a)
|
|
1695
|
+
{
|
|
1696
|
+
struct archive_write_disk *a = (struct archive_write_disk *)_a;
|
|
1697
|
+
int ret = ARCHIVE_OK;
|
|
1698
|
+
|
|
1699
|
+
archive_check_magic(&a->archive, ARCHIVE_WRITE_DISK_MAGIC,
|
|
1700
|
+
ARCHIVE_STATE_HEADER | ARCHIVE_STATE_DATA,
|
|
1701
|
+
"archive_write_finish_entry");
|
|
1702
|
+
if (a->archive.state & ARCHIVE_STATE_HEADER)
|
|
1703
|
+
return (ARCHIVE_OK);
|
|
1704
|
+
archive_clear_error(&a->archive);
|
|
1705
|
+
|
|
1706
|
+
/* Pad or truncate file to the right size. */
|
|
1707
|
+
if (a->fd < 0) {
|
|
1708
|
+
/* There's no file. */
|
|
1709
|
+
} else if (a->filesize < 0) {
|
|
1710
|
+
/* File size is unknown, so we can't set the size. */
|
|
1711
|
+
} else if (a->fd_offset == a->filesize) {
|
|
1712
|
+
/* Last write ended at exactly the filesize; we're done. */
|
|
1713
|
+
/* Hopefully, this is the common case. */
|
|
1714
|
+
#if defined(__APPLE__) && defined(UF_COMPRESSED) && defined(HAVE_ZLIB_H)
|
|
1715
|
+
} else if (a->todo & TODO_HFS_COMPRESSION) {
|
|
1716
|
+
char null_d[1024];
|
|
1717
|
+
ssize_t r;
|
|
1718
|
+
|
|
1719
|
+
if (a->file_remaining_bytes)
|
|
1720
|
+
memset(null_d, 0, sizeof(null_d));
|
|
1721
|
+
while (a->file_remaining_bytes) {
|
|
1722
|
+
if (a->file_remaining_bytes > sizeof(null_d))
|
|
1723
|
+
r = hfs_write_data_block(
|
|
1724
|
+
a, null_d, sizeof(null_d));
|
|
1725
|
+
else
|
|
1726
|
+
r = hfs_write_data_block(
|
|
1727
|
+
a, null_d, a->file_remaining_bytes);
|
|
1728
|
+
if (r < 0)
|
|
1729
|
+
return ((int)r);
|
|
1730
|
+
}
|
|
1731
|
+
#endif
|
|
1732
|
+
} else {
|
|
1733
|
+
#if HAVE_FTRUNCATE
|
|
1734
|
+
if (ftruncate(a->fd, a->filesize) == -1 &&
|
|
1735
|
+
a->filesize == 0) {
|
|
1736
|
+
archive_set_error(&a->archive, errno,
|
|
1737
|
+
"File size could not be restored");
|
|
1738
|
+
return (ARCHIVE_FAILED);
|
|
1739
|
+
}
|
|
1740
|
+
#endif
|
|
1741
|
+
/*
|
|
1742
|
+
* Not all platforms implement the XSI option to
|
|
1743
|
+
* extend files via ftruncate. Stat() the file again
|
|
1744
|
+
* to see what happened.
|
|
1745
|
+
*/
|
|
1746
|
+
a->pst = NULL;
|
|
1747
|
+
if ((ret = lazy_stat(a)) != ARCHIVE_OK)
|
|
1748
|
+
return (ret);
|
|
1749
|
+
/* We can use lseek()/write() to extend the file if
|
|
1750
|
+
* ftruncate didn't work or isn't available. */
|
|
1751
|
+
if (a->st.st_size < a->filesize) {
|
|
1752
|
+
const char nul = '\0';
|
|
1753
|
+
if (lseek(a->fd, a->filesize - 1, SEEK_SET) < 0) {
|
|
1754
|
+
archive_set_error(&a->archive, errno,
|
|
1755
|
+
"Seek failed");
|
|
1756
|
+
return (ARCHIVE_FATAL);
|
|
1757
|
+
}
|
|
1758
|
+
if (write(a->fd, &nul, 1) < 0) {
|
|
1759
|
+
archive_set_error(&a->archive, errno,
|
|
1760
|
+
"Write to restore size failed");
|
|
1761
|
+
return (ARCHIVE_FATAL);
|
|
1762
|
+
}
|
|
1763
|
+
a->pst = NULL;
|
|
1764
|
+
}
|
|
1765
|
+
}
|
|
1766
|
+
|
|
1767
|
+
/* Restore metadata. */
|
|
1768
|
+
|
|
1769
|
+
/*
|
|
1770
|
+
* This is specific to Mac OS X.
|
|
1771
|
+
* If the current file is an AppleDouble file, it should be
|
|
1772
|
+
* linked with the data fork file and remove it.
|
|
1773
|
+
*/
|
|
1774
|
+
if (a->todo & TODO_APPLEDOUBLE) {
|
|
1775
|
+
int r2 = fixup_appledouble(a, a->name);
|
|
1776
|
+
if (r2 == ARCHIVE_EOF) {
|
|
1777
|
+
/* The current file has been successfully linked
|
|
1778
|
+
* with the data fork file and removed. So there
|
|
1779
|
+
* is nothing to do on the current file. */
|
|
1780
|
+
goto finish_metadata;
|
|
1781
|
+
}
|
|
1782
|
+
if (r2 < ret) ret = r2;
|
|
1783
|
+
}
|
|
1784
|
+
|
|
1785
|
+
/*
|
|
1786
|
+
* Look up the "real" UID only if we're going to need it.
|
|
1787
|
+
* TODO: the TODO_SGID condition can be dropped here, can't it?
|
|
1788
|
+
*/
|
|
1789
|
+
if (a->todo & (TODO_OWNER | TODO_SUID | TODO_SGID)) {
|
|
1790
|
+
a->uid = archive_write_disk_uid(&a->archive,
|
|
1791
|
+
archive_entry_uname(a->entry),
|
|
1792
|
+
archive_entry_uid(a->entry));
|
|
1793
|
+
}
|
|
1794
|
+
/* Look up the "real" GID only if we're going to need it. */
|
|
1795
|
+
/* TODO: the TODO_SUID condition can be dropped here, can't it? */
|
|
1796
|
+
if (a->todo & (TODO_OWNER | TODO_SGID | TODO_SUID)) {
|
|
1797
|
+
a->gid = archive_write_disk_gid(&a->archive,
|
|
1798
|
+
archive_entry_gname(a->entry),
|
|
1799
|
+
archive_entry_gid(a->entry));
|
|
1800
|
+
}
|
|
1801
|
+
|
|
1802
|
+
/*
|
|
1803
|
+
* Restore ownership before set_mode tries to restore suid/sgid
|
|
1804
|
+
* bits. If we set the owner, we know what it is and can skip
|
|
1805
|
+
* a stat() call to examine the ownership of the file on disk.
|
|
1806
|
+
*/
|
|
1807
|
+
if (a->todo & TODO_OWNER) {
|
|
1808
|
+
int r2 = set_ownership(a);
|
|
1809
|
+
if (r2 < ret) ret = r2;
|
|
1810
|
+
}
|
|
1811
|
+
|
|
1812
|
+
/*
|
|
1813
|
+
* HYPOTHESIS:
|
|
1814
|
+
* If we're not root, we won't be setting any security
|
|
1815
|
+
* attributes that may be wiped by the set_mode() routine
|
|
1816
|
+
* below. We also can't set xattr on non-owner-writable files,
|
|
1817
|
+
* which may be the state after set_mode(). Perform
|
|
1818
|
+
* set_xattrs() first based on these constraints.
|
|
1819
|
+
*/
|
|
1820
|
+
if (a->user_uid != 0 &&
|
|
1821
|
+
(a->todo & TODO_XATTR)) {
|
|
1822
|
+
int r2 = set_xattrs(a);
|
|
1823
|
+
if (r2 < ret) ret = r2;
|
|
1824
|
+
}
|
|
1825
|
+
|
|
1826
|
+
/*
|
|
1827
|
+
* set_mode must precede ACLs on systems such as Solaris and
|
|
1828
|
+
* FreeBSD where setting the mode implicitly clears extended ACLs
|
|
1829
|
+
*/
|
|
1830
|
+
if (a->todo & TODO_MODE) {
|
|
1831
|
+
int r2 = set_mode(a, a->mode);
|
|
1832
|
+
if (r2 < ret) ret = r2;
|
|
1833
|
+
}
|
|
1834
|
+
|
|
1835
|
+
/*
|
|
1836
|
+
* Security-related extended attributes (such as
|
|
1837
|
+
* security.capability on Linux) have to be restored last,
|
|
1838
|
+
* since they're implicitly removed by other file changes.
|
|
1839
|
+
* We do this last only when root.
|
|
1840
|
+
*/
|
|
1841
|
+
if (a->user_uid == 0 &&
|
|
1842
|
+
(a->todo & TODO_XATTR)) {
|
|
1843
|
+
int r2 = set_xattrs(a);
|
|
1844
|
+
if (r2 < ret) ret = r2;
|
|
1845
|
+
}
|
|
1846
|
+
|
|
1847
|
+
/*
|
|
1848
|
+
* Some flags prevent file modification; they must be restored after
|
|
1849
|
+
* file contents are written.
|
|
1850
|
+
*/
|
|
1851
|
+
if (a->todo & TODO_FFLAGS) {
|
|
1852
|
+
int r2 = set_fflags(a);
|
|
1853
|
+
if (r2 < ret) ret = r2;
|
|
1854
|
+
}
|
|
1855
|
+
|
|
1856
|
+
/*
|
|
1857
|
+
* Time must follow most other metadata;
|
|
1858
|
+
* otherwise atime will get changed.
|
|
1859
|
+
*/
|
|
1860
|
+
if (a->todo & TODO_TIMES) {
|
|
1861
|
+
int r2 = set_times_from_entry(a);
|
|
1862
|
+
if (r2 < ret) ret = r2;
|
|
1863
|
+
}
|
|
1864
|
+
|
|
1865
|
+
/*
|
|
1866
|
+
* Mac extended metadata includes ACLs.
|
|
1867
|
+
*/
|
|
1868
|
+
if (a->todo & TODO_MAC_METADATA) {
|
|
1869
|
+
const void *metadata;
|
|
1870
|
+
size_t metadata_size;
|
|
1871
|
+
metadata = archive_entry_mac_metadata(a->entry, &metadata_size);
|
|
1872
|
+
if (metadata != NULL && metadata_size > 0) {
|
|
1873
|
+
int r2 = set_mac_metadata(a, archive_entry_pathname(
|
|
1874
|
+
a->entry), metadata, metadata_size);
|
|
1875
|
+
if (r2 < ret) ret = r2;
|
|
1876
|
+
}
|
|
1877
|
+
}
|
|
1878
|
+
|
|
1879
|
+
/*
|
|
1880
|
+
* ACLs must be restored after timestamps because there are
|
|
1881
|
+
* ACLs that prevent attribute changes (including time).
|
|
1882
|
+
*/
|
|
1883
|
+
if (a->todo & TODO_ACLS) {
|
|
1884
|
+
int r2;
|
|
1885
|
+
r2 = archive_write_disk_set_acls(&a->archive, a->fd,
|
|
1886
|
+
archive_entry_pathname(a->entry),
|
|
1887
|
+
archive_entry_acl(a->entry),
|
|
1888
|
+
archive_entry_mode(a->entry));
|
|
1889
|
+
if (r2 < ret) ret = r2;
|
|
1890
|
+
}
|
|
1891
|
+
|
|
1892
|
+
finish_metadata:
|
|
1893
|
+
/* If there's an fd, we can close it now. */
|
|
1894
|
+
if (a->fd >= 0) {
|
|
1895
|
+
close(a->fd);
|
|
1896
|
+
a->fd = -1;
|
|
1897
|
+
if (a->tmpname) {
|
|
1898
|
+
if (rename(a->tmpname, a->name) == -1) {
|
|
1899
|
+
archive_set_error(&a->archive, errno,
|
|
1900
|
+
"Failed to rename temporary file");
|
|
1901
|
+
ret = ARCHIVE_FAILED;
|
|
1902
|
+
unlink(a->tmpname);
|
|
1903
|
+
}
|
|
1904
|
+
a->tmpname = NULL;
|
|
1905
|
+
}
|
|
1906
|
+
}
|
|
1907
|
+
/* If there's an entry, we can release it now. */
|
|
1908
|
+
archive_entry_free(a->entry);
|
|
1909
|
+
a->entry = NULL;
|
|
1910
|
+
a->archive.state = ARCHIVE_STATE_HEADER;
|
|
1911
|
+
return (ret);
|
|
1912
|
+
}
|
|
1913
|
+
|
|
1914
|
+
int
|
|
1915
|
+
archive_write_disk_set_group_lookup(struct archive *_a,
|
|
1916
|
+
void *private_data,
|
|
1917
|
+
la_int64_t (*lookup_gid)(void *private, const char *gname, la_int64_t gid),
|
|
1918
|
+
void (*cleanup_gid)(void *private))
|
|
1919
|
+
{
|
|
1920
|
+
struct archive_write_disk *a = (struct archive_write_disk *)_a;
|
|
1921
|
+
archive_check_magic(&a->archive, ARCHIVE_WRITE_DISK_MAGIC,
|
|
1922
|
+
ARCHIVE_STATE_ANY, "archive_write_disk_set_group_lookup");
|
|
1923
|
+
|
|
1924
|
+
if (a->cleanup_gid != NULL && a->lookup_gid_data != NULL)
|
|
1925
|
+
(a->cleanup_gid)(a->lookup_gid_data);
|
|
1926
|
+
|
|
1927
|
+
a->lookup_gid = lookup_gid;
|
|
1928
|
+
a->cleanup_gid = cleanup_gid;
|
|
1929
|
+
a->lookup_gid_data = private_data;
|
|
1930
|
+
return (ARCHIVE_OK);
|
|
1931
|
+
}
|
|
1932
|
+
|
|
1933
|
+
int
|
|
1934
|
+
archive_write_disk_set_user_lookup(struct archive *_a,
|
|
1935
|
+
void *private_data,
|
|
1936
|
+
int64_t (*lookup_uid)(void *private, const char *uname, int64_t uid),
|
|
1937
|
+
void (*cleanup_uid)(void *private))
|
|
1938
|
+
{
|
|
1939
|
+
struct archive_write_disk *a = (struct archive_write_disk *)_a;
|
|
1940
|
+
archive_check_magic(&a->archive, ARCHIVE_WRITE_DISK_MAGIC,
|
|
1941
|
+
ARCHIVE_STATE_ANY, "archive_write_disk_set_user_lookup");
|
|
1942
|
+
|
|
1943
|
+
if (a->cleanup_uid != NULL && a->lookup_uid_data != NULL)
|
|
1944
|
+
(a->cleanup_uid)(a->lookup_uid_data);
|
|
1945
|
+
|
|
1946
|
+
a->lookup_uid = lookup_uid;
|
|
1947
|
+
a->cleanup_uid = cleanup_uid;
|
|
1948
|
+
a->lookup_uid_data = private_data;
|
|
1949
|
+
return (ARCHIVE_OK);
|
|
1950
|
+
}
|
|
1951
|
+
|
|
1952
|
+
int64_t
|
|
1953
|
+
archive_write_disk_gid(struct archive *_a, const char *name, la_int64_t id)
|
|
1954
|
+
{
|
|
1955
|
+
struct archive_write_disk *a = (struct archive_write_disk *)_a;
|
|
1956
|
+
archive_check_magic(&a->archive, ARCHIVE_WRITE_DISK_MAGIC,
|
|
1957
|
+
ARCHIVE_STATE_ANY, "archive_write_disk_gid");
|
|
1958
|
+
if (a->lookup_gid)
|
|
1959
|
+
return (a->lookup_gid)(a->lookup_gid_data, name, id);
|
|
1960
|
+
return (id);
|
|
1961
|
+
}
|
|
1962
|
+
|
|
1963
|
+
int64_t
|
|
1964
|
+
archive_write_disk_uid(struct archive *_a, const char *name, la_int64_t id)
|
|
1965
|
+
{
|
|
1966
|
+
struct archive_write_disk *a = (struct archive_write_disk *)_a;
|
|
1967
|
+
archive_check_magic(&a->archive, ARCHIVE_WRITE_DISK_MAGIC,
|
|
1968
|
+
ARCHIVE_STATE_ANY, "archive_write_disk_uid");
|
|
1969
|
+
if (a->lookup_uid)
|
|
1970
|
+
return (a->lookup_uid)(a->lookup_uid_data, name, id);
|
|
1971
|
+
return (id);
|
|
1972
|
+
}
|
|
1973
|
+
|
|
1974
|
+
/*
|
|
1975
|
+
* Create a new archive_write_disk object and initialize it with global state.
|
|
1976
|
+
*/
|
|
1977
|
+
struct archive *
|
|
1978
|
+
archive_write_disk_new(void)
|
|
1979
|
+
{
|
|
1980
|
+
struct archive_write_disk *a;
|
|
1981
|
+
|
|
1982
|
+
a = (struct archive_write_disk *)calloc(1, sizeof(*a));
|
|
1983
|
+
if (a == NULL)
|
|
1984
|
+
return (NULL);
|
|
1985
|
+
a->archive.magic = ARCHIVE_WRITE_DISK_MAGIC;
|
|
1986
|
+
/* We're ready to write a header immediately. */
|
|
1987
|
+
a->archive.state = ARCHIVE_STATE_HEADER;
|
|
1988
|
+
a->archive.vtable = &archive_write_disk_vtable;
|
|
1989
|
+
a->start_time = time(NULL);
|
|
1990
|
+
/* Query and restore the umask. */
|
|
1991
|
+
umask(a->user_umask = umask(0));
|
|
1992
|
+
#ifdef HAVE_GETEUID
|
|
1993
|
+
a->user_uid = geteuid();
|
|
1994
|
+
#endif /* HAVE_GETEUID */
|
|
1995
|
+
if (archive_string_ensure(&a->path_safe, 512) == NULL) {
|
|
1996
|
+
free(a);
|
|
1997
|
+
return (NULL);
|
|
1998
|
+
}
|
|
1999
|
+
a->path_safe.s[0] = 0;
|
|
2000
|
+
|
|
2001
|
+
#ifdef HAVE_ZLIB_H
|
|
2002
|
+
a->decmpfs_compression_level = 5;
|
|
2003
|
+
#endif
|
|
2004
|
+
return (&a->archive);
|
|
2005
|
+
}
|
|
2006
|
+
|
|
2007
|
+
|
|
2008
|
+
/*
|
|
2009
|
+
* If pathname is longer than PATH_MAX, chdir to a suitable
|
|
2010
|
+
* intermediate dir and edit the path down to a shorter suffix. Note
|
|
2011
|
+
* that this routine never returns an error; if the chdir() attempt
|
|
2012
|
+
* fails for any reason, we just go ahead with the long pathname. The
|
|
2013
|
+
* object creation is likely to fail, but any error will get handled
|
|
2014
|
+
* at that time.
|
|
2015
|
+
*/
|
|
2016
|
+
#if defined(HAVE_FCHDIR) && defined(PATH_MAX)
|
|
2017
|
+
static void
|
|
2018
|
+
edit_deep_directories(struct archive_write_disk *a)
|
|
2019
|
+
{
|
|
2020
|
+
int ret;
|
|
2021
|
+
char *tail = a->name;
|
|
2022
|
+
|
|
2023
|
+
/* If path is short, avoid the open() below. */
|
|
2024
|
+
if (strlen(tail) < PATH_MAX)
|
|
2025
|
+
return;
|
|
2026
|
+
|
|
2027
|
+
/* Try to record our starting dir. */
|
|
2028
|
+
a->restore_pwd = la_opendirat(AT_FDCWD, ".");
|
|
2029
|
+
__archive_ensure_cloexec_flag(a->restore_pwd);
|
|
2030
|
+
if (a->restore_pwd < 0)
|
|
2031
|
+
return;
|
|
2032
|
+
|
|
2033
|
+
/* As long as the path is too long... */
|
|
2034
|
+
while (strlen(tail) >= PATH_MAX) {
|
|
2035
|
+
/* Locate a dir prefix shorter than PATH_MAX. */
|
|
2036
|
+
tail += PATH_MAX - 8;
|
|
2037
|
+
while (tail > a->name && *tail != '/')
|
|
2038
|
+
tail--;
|
|
2039
|
+
/* Exit if we find a too-long path component. */
|
|
2040
|
+
if (tail <= a->name)
|
|
2041
|
+
return;
|
|
2042
|
+
/* Create the intermediate dir and chdir to it. */
|
|
2043
|
+
*tail = '\0'; /* Terminate dir portion */
|
|
2044
|
+
ret = create_dir(a, a->name);
|
|
2045
|
+
if (ret == ARCHIVE_OK && chdir(a->name) != 0)
|
|
2046
|
+
ret = ARCHIVE_FAILED;
|
|
2047
|
+
*tail = '/'; /* Restore the / we removed. */
|
|
2048
|
+
if (ret != ARCHIVE_OK)
|
|
2049
|
+
return;
|
|
2050
|
+
tail++;
|
|
2051
|
+
/* The chdir() succeeded; we've now shortened the path. */
|
|
2052
|
+
a->name = tail;
|
|
2053
|
+
}
|
|
2054
|
+
return;
|
|
2055
|
+
}
|
|
2056
|
+
#endif
|
|
2057
|
+
|
|
2058
|
+
/*
|
|
2059
|
+
* The main restore function.
|
|
2060
|
+
*/
|
|
2061
|
+
static int
|
|
2062
|
+
restore_entry(struct archive_write_disk *a)
|
|
2063
|
+
{
|
|
2064
|
+
int ret = ARCHIVE_OK, en;
|
|
2065
|
+
|
|
2066
|
+
if (a->flags & ARCHIVE_EXTRACT_UNLINK && !S_ISDIR(a->mode)) {
|
|
2067
|
+
/*
|
|
2068
|
+
* TODO: Fix this. Apparently, there are platforms
|
|
2069
|
+
* that still allow root to hose the entire filesystem
|
|
2070
|
+
* by unlinking a dir. The S_ISDIR() test above
|
|
2071
|
+
* prevents us from using unlink() here if the new
|
|
2072
|
+
* object is a dir, but that doesn't mean the old
|
|
2073
|
+
* object isn't a dir.
|
|
2074
|
+
*/
|
|
2075
|
+
if (a->flags & ARCHIVE_EXTRACT_CLEAR_NOCHANGE_FFLAGS)
|
|
2076
|
+
(void)clear_nochange_fflags(a);
|
|
2077
|
+
if (unlink(a->name) == 0) {
|
|
2078
|
+
/* We removed it, reset cached stat. */
|
|
2079
|
+
a->pst = NULL;
|
|
2080
|
+
} else if (errno == ENOENT) {
|
|
2081
|
+
/* File didn't exist, that's just as good. */
|
|
2082
|
+
} else if (rmdir(a->name) == 0) {
|
|
2083
|
+
/* It was a dir, but now it's gone. */
|
|
2084
|
+
a->pst = NULL;
|
|
2085
|
+
} else {
|
|
2086
|
+
/* We tried, but couldn't get rid of it. */
|
|
2087
|
+
archive_set_error(&a->archive, errno,
|
|
2088
|
+
"Could not unlink");
|
|
2089
|
+
return(ARCHIVE_FAILED);
|
|
2090
|
+
}
|
|
2091
|
+
}
|
|
2092
|
+
|
|
2093
|
+
/* Try creating it first; if this fails, we'll try to recover. */
|
|
2094
|
+
en = create_filesystem_object(a);
|
|
2095
|
+
|
|
2096
|
+
if ((en == ENOTDIR || en == ENOENT)
|
|
2097
|
+
&& !(a->flags & ARCHIVE_EXTRACT_NO_AUTODIR)) {
|
|
2098
|
+
/* If the parent dir doesn't exist, try creating it. */
|
|
2099
|
+
create_parent_dir(a, a->name);
|
|
2100
|
+
/* Now try to create the object again. */
|
|
2101
|
+
en = create_filesystem_object(a);
|
|
2102
|
+
}
|
|
2103
|
+
|
|
2104
|
+
if ((en == ENOENT) && (archive_entry_hardlink(a->entry) != NULL)) {
|
|
2105
|
+
archive_set_error(&a->archive, en,
|
|
2106
|
+
"Hard-link target '%s' does not exist.",
|
|
2107
|
+
archive_entry_hardlink(a->entry));
|
|
2108
|
+
return (ARCHIVE_FAILED);
|
|
2109
|
+
}
|
|
2110
|
+
|
|
2111
|
+
if ((en == EISDIR || en == EEXIST)
|
|
2112
|
+
&& (a->flags & ARCHIVE_EXTRACT_NO_OVERWRITE)) {
|
|
2113
|
+
/* If we're not overwriting, we're done. */
|
|
2114
|
+
if (S_ISDIR(a->mode)) {
|
|
2115
|
+
/* Don't overwrite any settings on existing directories. */
|
|
2116
|
+
a->todo = 0;
|
|
2117
|
+
}
|
|
2118
|
+
archive_entry_unset_size(a->entry);
|
|
2119
|
+
return (ARCHIVE_OK);
|
|
2120
|
+
}
|
|
2121
|
+
|
|
2122
|
+
/*
|
|
2123
|
+
* Some platforms return EISDIR if you call
|
|
2124
|
+
* open(O_WRONLY | O_EXCL | O_CREAT) on a directory, some
|
|
2125
|
+
* return EEXIST. POSIX is ambiguous, requiring EISDIR
|
|
2126
|
+
* for open(O_WRONLY) on a dir and EEXIST for open(O_EXCL | O_CREAT)
|
|
2127
|
+
* on an existing item.
|
|
2128
|
+
*/
|
|
2129
|
+
if (en == EISDIR) {
|
|
2130
|
+
/* A dir is in the way of a non-dir, rmdir it. */
|
|
2131
|
+
if (rmdir(a->name) != 0) {
|
|
2132
|
+
archive_set_error(&a->archive, errno,
|
|
2133
|
+
"Can't remove already-existing dir");
|
|
2134
|
+
return (ARCHIVE_FAILED);
|
|
2135
|
+
}
|
|
2136
|
+
a->pst = NULL;
|
|
2137
|
+
/* Try again. */
|
|
2138
|
+
en = create_filesystem_object(a);
|
|
2139
|
+
} else if (en == EEXIST) {
|
|
2140
|
+
/*
|
|
2141
|
+
* We know something is in the way, but we don't know what;
|
|
2142
|
+
* we need to find out before we go any further.
|
|
2143
|
+
*/
|
|
2144
|
+
int r = 0;
|
|
2145
|
+
/*
|
|
2146
|
+
* The SECURE_SYMLINKS logic has already removed a
|
|
2147
|
+
* symlink to a dir if the client wants that. So
|
|
2148
|
+
* follow the symlink if we're creating a dir.
|
|
2149
|
+
*/
|
|
2150
|
+
if (S_ISDIR(a->mode))
|
|
2151
|
+
r = la_stat(a->name, &a->st);
|
|
2152
|
+
/*
|
|
2153
|
+
* If it's not a dir (or it's a broken symlink),
|
|
2154
|
+
* then don't follow it.
|
|
2155
|
+
*/
|
|
2156
|
+
if (r != 0 || !S_ISDIR(a->mode))
|
|
2157
|
+
r = lstat(a->name, &a->st);
|
|
2158
|
+
if (r != 0) {
|
|
2159
|
+
archive_set_error(&a->archive, errno,
|
|
2160
|
+
"Can't stat existing object");
|
|
2161
|
+
return (ARCHIVE_FAILED);
|
|
2162
|
+
}
|
|
2163
|
+
|
|
2164
|
+
/*
|
|
2165
|
+
* NO_OVERWRITE_NEWER doesn't apply to directories.
|
|
2166
|
+
*/
|
|
2167
|
+
if ((a->flags & ARCHIVE_EXTRACT_NO_OVERWRITE_NEWER)
|
|
2168
|
+
&& !S_ISDIR(a->st.st_mode)) {
|
|
2169
|
+
if (!older(&(a->st), a->entry)) {
|
|
2170
|
+
archive_entry_unset_size(a->entry);
|
|
2171
|
+
return (ARCHIVE_OK);
|
|
2172
|
+
}
|
|
2173
|
+
}
|
|
2174
|
+
|
|
2175
|
+
/* If it's our archive, we're done. */
|
|
2176
|
+
if (a->skip_file_set &&
|
|
2177
|
+
a->st.st_dev == (dev_t)a->skip_file_dev &&
|
|
2178
|
+
a->st.st_ino == (ino_t)a->skip_file_ino) {
|
|
2179
|
+
archive_set_error(&a->archive, 0,
|
|
2180
|
+
"Refusing to overwrite archive");
|
|
2181
|
+
return (ARCHIVE_FAILED);
|
|
2182
|
+
}
|
|
2183
|
+
|
|
2184
|
+
if (!S_ISDIR(a->st.st_mode)) {
|
|
2185
|
+
if (a->flags & ARCHIVE_EXTRACT_CLEAR_NOCHANGE_FFLAGS)
|
|
2186
|
+
(void)clear_nochange_fflags(a);
|
|
2187
|
+
|
|
2188
|
+
if ((a->flags & ARCHIVE_EXTRACT_SAFE_WRITES) &&
|
|
2189
|
+
S_ISREG(a->st.st_mode)) {
|
|
2190
|
+
/* Use a temporary file to extract */
|
|
2191
|
+
if ((a->fd = la_mktemp(a)) == -1) {
|
|
2192
|
+
archive_set_error(&a->archive, errno,
|
|
2193
|
+
"Can't create temporary file");
|
|
2194
|
+
return ARCHIVE_FAILED;
|
|
2195
|
+
}
|
|
2196
|
+
a->pst = NULL;
|
|
2197
|
+
en = 0;
|
|
2198
|
+
} else {
|
|
2199
|
+
/* A non-dir is in the way, unlink it. */
|
|
2200
|
+
if (unlink(a->name) != 0) {
|
|
2201
|
+
archive_set_error(&a->archive, errno,
|
|
2202
|
+
"Can't unlink already-existing "
|
|
2203
|
+
"object");
|
|
2204
|
+
return (ARCHIVE_FAILED);
|
|
2205
|
+
}
|
|
2206
|
+
a->pst = NULL;
|
|
2207
|
+
/* Try again. */
|
|
2208
|
+
en = create_filesystem_object(a);
|
|
2209
|
+
}
|
|
2210
|
+
} else if (!S_ISDIR(a->mode)) {
|
|
2211
|
+
/* A dir is in the way of a non-dir, rmdir it. */
|
|
2212
|
+
if (a->flags & ARCHIVE_EXTRACT_CLEAR_NOCHANGE_FFLAGS)
|
|
2213
|
+
(void)clear_nochange_fflags(a);
|
|
2214
|
+
if (rmdir(a->name) != 0) {
|
|
2215
|
+
archive_set_error(&a->archive, errno,
|
|
2216
|
+
"Can't replace existing directory with non-directory");
|
|
2217
|
+
return (ARCHIVE_FAILED);
|
|
2218
|
+
}
|
|
2219
|
+
/* Try again. */
|
|
2220
|
+
en = create_filesystem_object(a);
|
|
2221
|
+
} else {
|
|
2222
|
+
/*
|
|
2223
|
+
* There's a dir in the way of a dir. Don't
|
|
2224
|
+
* waste time with rmdir()/mkdir(), just fix
|
|
2225
|
+
* up the permissions on the existing dir.
|
|
2226
|
+
* Note that we don't change perms on existing
|
|
2227
|
+
* dirs unless _EXTRACT_PERM is specified.
|
|
2228
|
+
*/
|
|
2229
|
+
if ((a->mode != a->st.st_mode)
|
|
2230
|
+
&& (a->todo & TODO_MODE_FORCE))
|
|
2231
|
+
a->deferred |= (a->todo & TODO_MODE);
|
|
2232
|
+
/* Ownership doesn't need deferred fixup. */
|
|
2233
|
+
en = 0; /* Forget the EEXIST. */
|
|
2234
|
+
}
|
|
2235
|
+
}
|
|
2236
|
+
|
|
2237
|
+
if (en) {
|
|
2238
|
+
/* Everything failed; give up here. */
|
|
2239
|
+
if ((&a->archive)->error == NULL)
|
|
2240
|
+
archive_set_error(&a->archive, en, "Can't create '%s'",
|
|
2241
|
+
a->name);
|
|
2242
|
+
return (ARCHIVE_FAILED);
|
|
2243
|
+
}
|
|
2244
|
+
|
|
2245
|
+
a->pst = NULL; /* Cached stat data no longer valid. */
|
|
2246
|
+
return (ret);
|
|
2247
|
+
}
|
|
2248
|
+
|
|
2249
|
+
/*
|
|
2250
|
+
* Returns 0 if creation succeeds, or else returns errno value from
|
|
2251
|
+
* the failed system call. Note: This function should only ever perform
|
|
2252
|
+
* a single system call.
|
|
2253
|
+
*/
|
|
2254
|
+
static int
|
|
2255
|
+
create_filesystem_object(struct archive_write_disk *a)
|
|
2256
|
+
{
|
|
2257
|
+
/* Create the entry. */
|
|
2258
|
+
const char *linkname;
|
|
2259
|
+
mode_t final_mode, mode;
|
|
2260
|
+
int r;
|
|
2261
|
+
/* these for check_symlinks_fsobj */
|
|
2262
|
+
char *linkname_copy; /* non-const copy of linkname */
|
|
2263
|
+
struct stat st;
|
|
2264
|
+
struct archive_string error_string;
|
|
2265
|
+
int error_number;
|
|
2266
|
+
|
|
2267
|
+
/* We identify hard/symlinks according to the link names. */
|
|
2268
|
+
/* Since link(2) and symlink(2) don't handle modes, we're done here. */
|
|
2269
|
+
linkname = archive_entry_hardlink(a->entry);
|
|
2270
|
+
if (linkname != NULL) {
|
|
2271
|
+
#if !HAVE_LINK
|
|
2272
|
+
return (EPERM);
|
|
2273
|
+
#else
|
|
2274
|
+
archive_string_init(&error_string);
|
|
2275
|
+
linkname_copy = strdup(linkname);
|
|
2276
|
+
if (linkname_copy == NULL) {
|
|
2277
|
+
return (EPERM);
|
|
2278
|
+
}
|
|
2279
|
+
/*
|
|
2280
|
+
* TODO: consider using the cleaned-up path as the link
|
|
2281
|
+
* target?
|
|
2282
|
+
*/
|
|
2283
|
+
r = cleanup_pathname_fsobj(linkname_copy, &error_number,
|
|
2284
|
+
&error_string, a->flags);
|
|
2285
|
+
if (r != ARCHIVE_OK) {
|
|
2286
|
+
archive_set_error(&a->archive, error_number, "%s",
|
|
2287
|
+
error_string.s);
|
|
2288
|
+
free(linkname_copy);
|
|
2289
|
+
archive_string_free(&error_string);
|
|
2290
|
+
/*
|
|
2291
|
+
* EPERM is more appropriate than error_number for our
|
|
2292
|
+
* callers
|
|
2293
|
+
*/
|
|
2294
|
+
return (EPERM);
|
|
2295
|
+
}
|
|
2296
|
+
r = check_symlinks_fsobj(linkname_copy, &error_number,
|
|
2297
|
+
&error_string, a->flags, 1);
|
|
2298
|
+
if (r != ARCHIVE_OK) {
|
|
2299
|
+
archive_set_error(&a->archive, error_number, "%s",
|
|
2300
|
+
error_string.s);
|
|
2301
|
+
free(linkname_copy);
|
|
2302
|
+
archive_string_free(&error_string);
|
|
2303
|
+
/*
|
|
2304
|
+
* EPERM is more appropriate than error_number for our
|
|
2305
|
+
* callers
|
|
2306
|
+
*/
|
|
2307
|
+
return (EPERM);
|
|
2308
|
+
}
|
|
2309
|
+
free(linkname_copy);
|
|
2310
|
+
archive_string_free(&error_string);
|
|
2311
|
+
/*
|
|
2312
|
+
* Unlinking and linking here is really not atomic,
|
|
2313
|
+
* but doing it right, would require us to construct
|
|
2314
|
+
* an mktemplink() function, and then use rename(2).
|
|
2315
|
+
*/
|
|
2316
|
+
if (a->flags & ARCHIVE_EXTRACT_SAFE_WRITES)
|
|
2317
|
+
unlink(a->name);
|
|
2318
|
+
#ifdef HAVE_LINKAT
|
|
2319
|
+
r = linkat(AT_FDCWD, linkname, AT_FDCWD, a->name,
|
|
2320
|
+
0) ? errno : 0;
|
|
2321
|
+
#else
|
|
2322
|
+
r = link(linkname, a->name) ? errno : 0;
|
|
2323
|
+
#endif
|
|
2324
|
+
/*
|
|
2325
|
+
* New cpio and pax formats allow hardlink entries
|
|
2326
|
+
* to carry data, so we may have to open the file
|
|
2327
|
+
* for hardlink entries.
|
|
2328
|
+
*
|
|
2329
|
+
* If the hardlink was successfully created and
|
|
2330
|
+
* the archive doesn't have carry data for it,
|
|
2331
|
+
* consider it to be non-authoritative for meta data.
|
|
2332
|
+
* This is consistent with GNU tar and BSD pax.
|
|
2333
|
+
* If the hardlink does carry data, let the last
|
|
2334
|
+
* archive entry decide ownership.
|
|
2335
|
+
*/
|
|
2336
|
+
if (r == 0 && a->filesize <= 0) {
|
|
2337
|
+
a->todo = 0;
|
|
2338
|
+
a->deferred = 0;
|
|
2339
|
+
} else if (r == 0 && a->filesize > 0) {
|
|
2340
|
+
#ifdef HAVE_LSTAT
|
|
2341
|
+
r = lstat(a->name, &st);
|
|
2342
|
+
#else
|
|
2343
|
+
r = la_stat(a->name, &st);
|
|
2344
|
+
#endif
|
|
2345
|
+
if (r != 0)
|
|
2346
|
+
r = errno;
|
|
2347
|
+
else if ((st.st_mode & AE_IFMT) == AE_IFREG) {
|
|
2348
|
+
a->fd = open(a->name, O_WRONLY | O_TRUNC |
|
|
2349
|
+
O_BINARY | O_CLOEXEC | O_NOFOLLOW);
|
|
2350
|
+
__archive_ensure_cloexec_flag(a->fd);
|
|
2351
|
+
if (a->fd < 0)
|
|
2352
|
+
r = errno;
|
|
2353
|
+
}
|
|
2354
|
+
}
|
|
2355
|
+
return (r);
|
|
2356
|
+
#endif
|
|
2357
|
+
}
|
|
2358
|
+
linkname = archive_entry_symlink(a->entry);
|
|
2359
|
+
if (linkname != NULL) {
|
|
2360
|
+
#if HAVE_SYMLINK
|
|
2361
|
+
/*
|
|
2362
|
+
* Unlinking and linking here is really not atomic,
|
|
2363
|
+
* but doing it right, would require us to construct
|
|
2364
|
+
* an mktempsymlink() function, and then use rename(2).
|
|
2365
|
+
*/
|
|
2366
|
+
if (a->flags & ARCHIVE_EXTRACT_SAFE_WRITES)
|
|
2367
|
+
unlink(a->name);
|
|
2368
|
+
return symlink(linkname, a->name) ? errno : 0;
|
|
2369
|
+
#else
|
|
2370
|
+
return (EPERM);
|
|
2371
|
+
#endif
|
|
2372
|
+
}
|
|
2373
|
+
|
|
2374
|
+
/*
|
|
2375
|
+
* The remaining system calls all set permissions, so let's
|
|
2376
|
+
* try to take advantage of that to avoid an extra chmod()
|
|
2377
|
+
* call. (Recall that umask is set to zero right now!)
|
|
2378
|
+
*/
|
|
2379
|
+
|
|
2380
|
+
/* Mode we want for the final restored object (w/o file type bits). */
|
|
2381
|
+
final_mode = a->mode & 07777;
|
|
2382
|
+
/*
|
|
2383
|
+
* The mode that will actually be restored in this step. Note
|
|
2384
|
+
* that SUID, SGID, etc, require additional work to ensure
|
|
2385
|
+
* security, so we never restore them at this point.
|
|
2386
|
+
*/
|
|
2387
|
+
mode = final_mode & 0777 & ~a->user_umask;
|
|
2388
|
+
|
|
2389
|
+
/*
|
|
2390
|
+
* Always create writable such that [f]setxattr() works if we're not
|
|
2391
|
+
* root.
|
|
2392
|
+
*/
|
|
2393
|
+
if (a->user_uid != 0 &&
|
|
2394
|
+
a->todo & (TODO_HFS_COMPRESSION | TODO_XATTR)) {
|
|
2395
|
+
mode |= 0200;
|
|
2396
|
+
}
|
|
2397
|
+
|
|
2398
|
+
switch (a->mode & AE_IFMT) {
|
|
2399
|
+
default:
|
|
2400
|
+
/* POSIX requires that we fall through here. */
|
|
2401
|
+
/* FALLTHROUGH */
|
|
2402
|
+
case AE_IFREG:
|
|
2403
|
+
a->tmpname = NULL;
|
|
2404
|
+
a->fd = open(a->name,
|
|
2405
|
+
O_WRONLY | O_CREAT | O_EXCL | O_BINARY | O_CLOEXEC, mode);
|
|
2406
|
+
__archive_ensure_cloexec_flag(a->fd);
|
|
2407
|
+
r = (a->fd < 0);
|
|
2408
|
+
break;
|
|
2409
|
+
case AE_IFCHR:
|
|
2410
|
+
#ifdef HAVE_MKNOD
|
|
2411
|
+
/* Note: we use AE_IFCHR for the case label, and
|
|
2412
|
+
* S_IFCHR for the mknod() call. This is correct. */
|
|
2413
|
+
r = mknod(a->name, mode | S_IFCHR,
|
|
2414
|
+
archive_entry_rdev(a->entry));
|
|
2415
|
+
break;
|
|
2416
|
+
#else
|
|
2417
|
+
/* TODO: Find a better way to warn about our inability
|
|
2418
|
+
* to restore a char device node. */
|
|
2419
|
+
return (EINVAL);
|
|
2420
|
+
#endif /* HAVE_MKNOD */
|
|
2421
|
+
case AE_IFBLK:
|
|
2422
|
+
#ifdef HAVE_MKNOD
|
|
2423
|
+
r = mknod(a->name, mode | S_IFBLK,
|
|
2424
|
+
archive_entry_rdev(a->entry));
|
|
2425
|
+
break;
|
|
2426
|
+
#else
|
|
2427
|
+
/* TODO: Find a better way to warn about our inability
|
|
2428
|
+
* to restore a block device node. */
|
|
2429
|
+
return (EINVAL);
|
|
2430
|
+
#endif /* HAVE_MKNOD */
|
|
2431
|
+
case AE_IFDIR:
|
|
2432
|
+
mode = (mode | MINIMUM_DIR_MODE) & MAXIMUM_DIR_MODE;
|
|
2433
|
+
r = mkdir(a->name, mode);
|
|
2434
|
+
if (r == 0) {
|
|
2435
|
+
/* Defer setting dir times. */
|
|
2436
|
+
a->deferred |= (a->todo & TODO_TIMES);
|
|
2437
|
+
a->todo &= ~TODO_TIMES;
|
|
2438
|
+
/* Never use an immediate chmod(). */
|
|
2439
|
+
/* We can't avoid the chmod() entirely if EXTRACT_PERM
|
|
2440
|
+
* because of SysV SGID inheritance. */
|
|
2441
|
+
if ((mode != final_mode)
|
|
2442
|
+
|| (a->flags & ARCHIVE_EXTRACT_PERM))
|
|
2443
|
+
a->deferred |= (a->todo & TODO_MODE);
|
|
2444
|
+
a->todo &= ~TODO_MODE;
|
|
2445
|
+
}
|
|
2446
|
+
break;
|
|
2447
|
+
case AE_IFIFO:
|
|
2448
|
+
#ifdef HAVE_MKFIFO
|
|
2449
|
+
r = mkfifo(a->name, mode);
|
|
2450
|
+
break;
|
|
2451
|
+
#else
|
|
2452
|
+
/* TODO: Find a better way to warn about our inability
|
|
2453
|
+
* to restore a fifo. */
|
|
2454
|
+
return (EINVAL);
|
|
2455
|
+
#endif /* HAVE_MKFIFO */
|
|
2456
|
+
}
|
|
2457
|
+
|
|
2458
|
+
/* All the system calls above set errno on failure. */
|
|
2459
|
+
if (r)
|
|
2460
|
+
return (errno);
|
|
2461
|
+
|
|
2462
|
+
/* If we managed to set the final mode, we've avoided a chmod(). */
|
|
2463
|
+
if (mode == final_mode)
|
|
2464
|
+
a->todo &= ~TODO_MODE;
|
|
2465
|
+
return (0);
|
|
2466
|
+
}
|
|
2467
|
+
|
|
2468
|
+
/*
|
|
2469
|
+
* Cleanup function for archive_extract. Mostly, this involves processing
|
|
2470
|
+
* the fixup list, which is used to address a number of problems:
|
|
2471
|
+
* * Dir permissions might prevent us from restoring a file in that
|
|
2472
|
+
* dir, so we restore the dir with minimum 0700 permissions first,
|
|
2473
|
+
* then correct the mode at the end.
|
|
2474
|
+
* * Similarly, the act of restoring a file touches the directory
|
|
2475
|
+
* and changes the timestamp on the dir, so we have to touch-up dir
|
|
2476
|
+
* timestamps at the end as well.
|
|
2477
|
+
* * Some file flags can interfere with the restore by, for example,
|
|
2478
|
+
* preventing the creation of hardlinks to those files.
|
|
2479
|
+
* * Mac OS extended metadata includes ACLs, so must be deferred on dirs.
|
|
2480
|
+
*
|
|
2481
|
+
* Note that tar/cpio do not require that archives be in a particular
|
|
2482
|
+
* order; there is no way to know when the last file has been restored
|
|
2483
|
+
* within a directory, so there's no way to optimize the memory usage
|
|
2484
|
+
* here by fixing up the directory any earlier than the
|
|
2485
|
+
* end-of-archive.
|
|
2486
|
+
*
|
|
2487
|
+
* XXX TODO: Directory ACLs should be restored here, for the same
|
|
2488
|
+
* reason we set directory perms here. XXX
|
|
2489
|
+
*/
|
|
2490
|
+
static int
|
|
2491
|
+
_archive_write_disk_close(struct archive *_a)
|
|
2492
|
+
{
|
|
2493
|
+
struct archive_write_disk *a = (struct archive_write_disk *)_a;
|
|
2494
|
+
struct fixup_entry *next, *p;
|
|
2495
|
+
struct stat st;
|
|
2496
|
+
char *c;
|
|
2497
|
+
int fd, ret, openflags;
|
|
2498
|
+
|
|
2499
|
+
archive_check_magic(&a->archive, ARCHIVE_WRITE_DISK_MAGIC,
|
|
2500
|
+
ARCHIVE_STATE_HEADER | ARCHIVE_STATE_DATA,
|
|
2501
|
+
"archive_write_disk_close");
|
|
2502
|
+
ret = _archive_write_disk_finish_entry(&a->archive);
|
|
2503
|
+
|
|
2504
|
+
/* Sort dir list so directories are fixed up in depth-first order. */
|
|
2505
|
+
p = sort_dir_list(a->fixup_list);
|
|
2506
|
+
|
|
2507
|
+
while (p != NULL) {
|
|
2508
|
+
fd = -1;
|
|
2509
|
+
a->pst = NULL; /* Mark stat cache as out-of-date. */
|
|
2510
|
+
|
|
2511
|
+
/* We must strip trailing slashes from the path to avoid
|
|
2512
|
+
dereferencing symbolic links to directories */
|
|
2513
|
+
c = p->name;
|
|
2514
|
+
while (*c != '\0')
|
|
2515
|
+
c++;
|
|
2516
|
+
while (c != p->name && *(c - 1) == '/') {
|
|
2517
|
+
c--;
|
|
2518
|
+
*c = '\0';
|
|
2519
|
+
}
|
|
2520
|
+
|
|
2521
|
+
if (p->fixup == 0)
|
|
2522
|
+
goto skip_fixup_entry;
|
|
2523
|
+
else {
|
|
2524
|
+
/*
|
|
2525
|
+
* We need to verify if the type of the file
|
|
2526
|
+
* we are going to open matches the file type
|
|
2527
|
+
* of the fixup entry.
|
|
2528
|
+
*/
|
|
2529
|
+
openflags = O_BINARY | O_NOFOLLOW | O_RDONLY
|
|
2530
|
+
| O_CLOEXEC;
|
|
2531
|
+
#if defined(O_DIRECTORY)
|
|
2532
|
+
if (p->filetype == AE_IFDIR)
|
|
2533
|
+
openflags |= O_DIRECTORY;
|
|
2534
|
+
#endif
|
|
2535
|
+
fd = open(p->name, openflags);
|
|
2536
|
+
|
|
2537
|
+
#if defined(O_DIRECTORY)
|
|
2538
|
+
/*
|
|
2539
|
+
* If we support O_DIRECTORY and open was
|
|
2540
|
+
* successful we can skip the file type check
|
|
2541
|
+
* for directories. For other file types
|
|
2542
|
+
* we need to verify via fstat() or lstat()
|
|
2543
|
+
*/
|
|
2544
|
+
if (fd == -1 || p->filetype != AE_IFDIR) {
|
|
2545
|
+
#if HAVE_FSTAT
|
|
2546
|
+
if (fd > 0 && (
|
|
2547
|
+
fstat(fd, &st) != 0 ||
|
|
2548
|
+
la_verify_filetype(st.st_mode,
|
|
2549
|
+
p->filetype) == 0)) {
|
|
2550
|
+
goto skip_fixup_entry;
|
|
2551
|
+
} else
|
|
2552
|
+
#endif
|
|
2553
|
+
if (lstat(p->name, &st) != 0 ||
|
|
2554
|
+
la_verify_filetype(st.st_mode,
|
|
2555
|
+
p->filetype) == 0) {
|
|
2556
|
+
goto skip_fixup_entry;
|
|
2557
|
+
}
|
|
2558
|
+
}
|
|
2559
|
+
#else
|
|
2560
|
+
#if HAVE_FSTAT
|
|
2561
|
+
if (fd > 0 && (
|
|
2562
|
+
fstat(fd, &st) != 0 ||
|
|
2563
|
+
la_verify_filetype(st.st_mode,
|
|
2564
|
+
p->filetype) == 0)) {
|
|
2565
|
+
goto skip_fixup_entry;
|
|
2566
|
+
} else
|
|
2567
|
+
#endif
|
|
2568
|
+
if (lstat(p->name, &st) != 0 ||
|
|
2569
|
+
la_verify_filetype(st.st_mode,
|
|
2570
|
+
p->filetype) == 0) {
|
|
2571
|
+
goto skip_fixup_entry;
|
|
2572
|
+
}
|
|
2573
|
+
#endif
|
|
2574
|
+
}
|
|
2575
|
+
if (p->fixup & TODO_TIMES) {
|
|
2576
|
+
set_times(a, fd, p->mode, p->name,
|
|
2577
|
+
p->atime, p->atime_nanos,
|
|
2578
|
+
p->birthtime, p->birthtime_nanos,
|
|
2579
|
+
p->mtime, p->mtime_nanos,
|
|
2580
|
+
p->ctime, p->ctime_nanos);
|
|
2581
|
+
}
|
|
2582
|
+
if (p->fixup & TODO_MODE_BASE) {
|
|
2583
|
+
#ifdef HAVE_FCHMOD
|
|
2584
|
+
if (fd >= 0)
|
|
2585
|
+
fchmod(fd, p->mode & 07777);
|
|
2586
|
+
else
|
|
2587
|
+
#endif
|
|
2588
|
+
#ifdef HAVE_LCHMOD
|
|
2589
|
+
lchmod(p->name, p->mode & 07777);
|
|
2590
|
+
#else
|
|
2591
|
+
chmod(p->name, p->mode & 07777);
|
|
2592
|
+
#endif
|
|
2593
|
+
}
|
|
2594
|
+
if (p->fixup & TODO_ACLS)
|
|
2595
|
+
archive_write_disk_set_acls(&a->archive, fd,
|
|
2596
|
+
p->name, &p->acl, p->mode);
|
|
2597
|
+
if (p->fixup & TODO_FFLAGS)
|
|
2598
|
+
set_fflags_platform(a, fd, p->name,
|
|
2599
|
+
p->mode, p->fflags_set, 0);
|
|
2600
|
+
if (p->fixup & TODO_MAC_METADATA)
|
|
2601
|
+
set_mac_metadata(a, p->name, p->mac_metadata,
|
|
2602
|
+
p->mac_metadata_size);
|
|
2603
|
+
skip_fixup_entry:
|
|
2604
|
+
next = p->next;
|
|
2605
|
+
archive_acl_clear(&p->acl);
|
|
2606
|
+
free(p->mac_metadata);
|
|
2607
|
+
free(p->name);
|
|
2608
|
+
if (fd >= 0)
|
|
2609
|
+
close(fd);
|
|
2610
|
+
free(p);
|
|
2611
|
+
p = next;
|
|
2612
|
+
}
|
|
2613
|
+
a->fixup_list = NULL;
|
|
2614
|
+
return (ret);
|
|
2615
|
+
}
|
|
2616
|
+
|
|
2617
|
+
static int
|
|
2618
|
+
_archive_write_disk_free(struct archive *_a)
|
|
2619
|
+
{
|
|
2620
|
+
struct archive_write_disk *a;
|
|
2621
|
+
int ret;
|
|
2622
|
+
if (_a == NULL)
|
|
2623
|
+
return (ARCHIVE_OK);
|
|
2624
|
+
archive_check_magic(_a, ARCHIVE_WRITE_DISK_MAGIC,
|
|
2625
|
+
ARCHIVE_STATE_ANY | ARCHIVE_STATE_FATAL, "archive_write_disk_free");
|
|
2626
|
+
a = (struct archive_write_disk *)_a;
|
|
2627
|
+
ret = _archive_write_disk_close(&a->archive);
|
|
2628
|
+
archive_write_disk_set_group_lookup(&a->archive, NULL, NULL, NULL);
|
|
2629
|
+
archive_write_disk_set_user_lookup(&a->archive, NULL, NULL, NULL);
|
|
2630
|
+
archive_entry_free(a->entry);
|
|
2631
|
+
archive_string_free(&a->_name_data);
|
|
2632
|
+
archive_string_free(&a->_tmpname_data);
|
|
2633
|
+
archive_string_free(&a->archive.error_string);
|
|
2634
|
+
archive_string_free(&a->path_safe);
|
|
2635
|
+
a->archive.magic = 0;
|
|
2636
|
+
__archive_clean(&a->archive);
|
|
2637
|
+
free(a->decmpfs_header_p);
|
|
2638
|
+
free(a->resource_fork);
|
|
2639
|
+
free(a->compressed_buffer);
|
|
2640
|
+
free(a->uncompressed_buffer);
|
|
2641
|
+
#if defined(__APPLE__) && defined(UF_COMPRESSED) && defined(HAVE_SYS_XATTR_H)\
|
|
2642
|
+
&& defined(HAVE_ZLIB_H)
|
|
2643
|
+
if (a->stream_valid) {
|
|
2644
|
+
switch (deflateEnd(&a->stream)) {
|
|
2645
|
+
case Z_OK:
|
|
2646
|
+
break;
|
|
2647
|
+
default:
|
|
2648
|
+
archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
|
|
2649
|
+
"Failed to clean up compressor");
|
|
2650
|
+
ret = ARCHIVE_FATAL;
|
|
2651
|
+
break;
|
|
2652
|
+
}
|
|
2653
|
+
}
|
|
2654
|
+
#endif
|
|
2655
|
+
free(a);
|
|
2656
|
+
return (ret);
|
|
2657
|
+
}
|
|
2658
|
+
|
|
2659
|
+
/*
|
|
2660
|
+
* Simple O(n log n) merge sort to order the fixup list. In
|
|
2661
|
+
* particular, we want to restore dir timestamps depth-first.
|
|
2662
|
+
*/
|
|
2663
|
+
static struct fixup_entry *
|
|
2664
|
+
sort_dir_list(struct fixup_entry *p)
|
|
2665
|
+
{
|
|
2666
|
+
struct fixup_entry *a, *b, *t;
|
|
2667
|
+
|
|
2668
|
+
if (p == NULL)
|
|
2669
|
+
return (NULL);
|
|
2670
|
+
/* A one-item list is already sorted. */
|
|
2671
|
+
if (p->next == NULL)
|
|
2672
|
+
return (p);
|
|
2673
|
+
|
|
2674
|
+
/* Step 1: split the list. */
|
|
2675
|
+
t = p;
|
|
2676
|
+
a = p->next->next;
|
|
2677
|
+
while (a != NULL) {
|
|
2678
|
+
/* Step a twice, t once. */
|
|
2679
|
+
a = a->next;
|
|
2680
|
+
if (a != NULL)
|
|
2681
|
+
a = a->next;
|
|
2682
|
+
t = t->next;
|
|
2683
|
+
}
|
|
2684
|
+
/* Now, t is at the mid-point, so break the list here. */
|
|
2685
|
+
b = t->next;
|
|
2686
|
+
t->next = NULL;
|
|
2687
|
+
a = p;
|
|
2688
|
+
|
|
2689
|
+
/* Step 2: Recursively sort the two sub-lists. */
|
|
2690
|
+
a = sort_dir_list(a);
|
|
2691
|
+
b = sort_dir_list(b);
|
|
2692
|
+
|
|
2693
|
+
/* Step 3: Merge the returned lists. */
|
|
2694
|
+
/* Pick the first element for the merged list. */
|
|
2695
|
+
if (strcmp(a->name, b->name) > 0) {
|
|
2696
|
+
t = p = a;
|
|
2697
|
+
a = a->next;
|
|
2698
|
+
} else {
|
|
2699
|
+
t = p = b;
|
|
2700
|
+
b = b->next;
|
|
2701
|
+
}
|
|
2702
|
+
|
|
2703
|
+
/* Always put the later element on the list first. */
|
|
2704
|
+
while (a != NULL && b != NULL) {
|
|
2705
|
+
if (strcmp(a->name, b->name) > 0) {
|
|
2706
|
+
t->next = a;
|
|
2707
|
+
a = a->next;
|
|
2708
|
+
} else {
|
|
2709
|
+
t->next = b;
|
|
2710
|
+
b = b->next;
|
|
2711
|
+
}
|
|
2712
|
+
t = t->next;
|
|
2713
|
+
}
|
|
2714
|
+
|
|
2715
|
+
/* Only one list is non-empty, so just splice it on. */
|
|
2716
|
+
if (a != NULL)
|
|
2717
|
+
t->next = a;
|
|
2718
|
+
if (b != NULL)
|
|
2719
|
+
t->next = b;
|
|
2720
|
+
|
|
2721
|
+
return (p);
|
|
2722
|
+
}
|
|
2723
|
+
|
|
2724
|
+
/*
|
|
2725
|
+
* Returns a new, initialized fixup entry.
|
|
2726
|
+
*
|
|
2727
|
+
* TODO: Reduce the memory requirements for this list by using a tree
|
|
2728
|
+
* structure rather than a simple list of names.
|
|
2729
|
+
*/
|
|
2730
|
+
static struct fixup_entry *
|
|
2731
|
+
new_fixup(struct archive_write_disk *a, const char *pathname)
|
|
2732
|
+
{
|
|
2733
|
+
struct fixup_entry *fe;
|
|
2734
|
+
|
|
2735
|
+
fe = (struct fixup_entry *)calloc(1, sizeof(struct fixup_entry));
|
|
2736
|
+
if (fe == NULL) {
|
|
2737
|
+
archive_set_error(&a->archive, ENOMEM,
|
|
2738
|
+
"Can't allocate memory for a fixup");
|
|
2739
|
+
return (NULL);
|
|
2740
|
+
}
|
|
2741
|
+
fe->next = a->fixup_list;
|
|
2742
|
+
a->fixup_list = fe;
|
|
2743
|
+
fe->fixup = 0;
|
|
2744
|
+
fe->filetype = 0;
|
|
2745
|
+
fe->name = strdup(pathname);
|
|
2746
|
+
return (fe);
|
|
2747
|
+
}
|
|
2748
|
+
|
|
2749
|
+
/*
|
|
2750
|
+
* Returns a fixup structure for the current entry.
|
|
2751
|
+
*/
|
|
2752
|
+
static struct fixup_entry *
|
|
2753
|
+
current_fixup(struct archive_write_disk *a, const char *pathname)
|
|
2754
|
+
{
|
|
2755
|
+
if (a->current_fixup == NULL)
|
|
2756
|
+
a->current_fixup = new_fixup(a, pathname);
|
|
2757
|
+
return (a->current_fixup);
|
|
2758
|
+
}
|
|
2759
|
+
|
|
2760
|
+
/* Error helper for new *_fsobj functions */
|
|
2761
|
+
static void
|
|
2762
|
+
fsobj_error(int *a_eno, struct archive_string *a_estr,
|
|
2763
|
+
int err, const char *errstr, const char *path)
|
|
2764
|
+
{
|
|
2765
|
+
if (a_eno)
|
|
2766
|
+
*a_eno = err;
|
|
2767
|
+
if (a_estr)
|
|
2768
|
+
archive_string_sprintf(a_estr, "%s%s", errstr, path);
|
|
2769
|
+
}
|
|
2770
|
+
|
|
2771
|
+
/*
|
|
2772
|
+
* TODO: Someday, integrate this with the deep dir support; they both
|
|
2773
|
+
* scan the path and both can be optimized by comparing against other
|
|
2774
|
+
* recent paths.
|
|
2775
|
+
*/
|
|
2776
|
+
/*
|
|
2777
|
+
* Checks the given path to see if any elements along it are symlinks. Returns
|
|
2778
|
+
* ARCHIVE_OK if there are none, otherwise puts an error in errmsg.
|
|
2779
|
+
*/
|
|
2780
|
+
static int
|
|
2781
|
+
check_symlinks_fsobj(char *path, int *a_eno, struct archive_string *a_estr,
|
|
2782
|
+
int flags, int checking_linkname)
|
|
2783
|
+
{
|
|
2784
|
+
#if !defined(HAVE_LSTAT) && \
|
|
2785
|
+
!(defined(HAVE_OPENAT) && defined(HAVE_FSTATAT) && defined(HAVE_UNLINKAT))
|
|
2786
|
+
/* Platform doesn't have lstat, so we can't look for symlinks. */
|
|
2787
|
+
(void)path; /* UNUSED */
|
|
2788
|
+
(void)error_number; /* UNUSED */
|
|
2789
|
+
(void)error_string; /* UNUSED */
|
|
2790
|
+
(void)flags; /* UNUSED */
|
|
2791
|
+
(void)checking_linkname; /* UNUSED */
|
|
2792
|
+
return (ARCHIVE_OK);
|
|
2793
|
+
#else
|
|
2794
|
+
int res = ARCHIVE_OK;
|
|
2795
|
+
char *tail;
|
|
2796
|
+
char *head;
|
|
2797
|
+
int last;
|
|
2798
|
+
char c = '\0';
|
|
2799
|
+
int r;
|
|
2800
|
+
struct stat st;
|
|
2801
|
+
int chdir_fd;
|
|
2802
|
+
#if defined(HAVE_OPENAT) && defined(HAVE_FSTATAT) && defined(HAVE_UNLINKAT)
|
|
2803
|
+
int fd;
|
|
2804
|
+
#endif
|
|
2805
|
+
|
|
2806
|
+
/* Nothing to do here if name is empty */
|
|
2807
|
+
if(path[0] == '\0')
|
|
2808
|
+
return (ARCHIVE_OK);
|
|
2809
|
+
|
|
2810
|
+
/*
|
|
2811
|
+
* Guard against symlink tricks. Reject any archive entry whose
|
|
2812
|
+
* destination would be altered by a symlink.
|
|
2813
|
+
*
|
|
2814
|
+
* Walk the filename in chunks separated by '/'. For each segment:
|
|
2815
|
+
* - if it doesn't exist, continue
|
|
2816
|
+
* - if it's symlink, abort or remove it
|
|
2817
|
+
* - if it's a directory and it's not the last chunk, cd into it
|
|
2818
|
+
* As we go:
|
|
2819
|
+
* head points to the current (relative) path
|
|
2820
|
+
* tail points to the temporary \0 terminating the segment we're
|
|
2821
|
+
* currently examining
|
|
2822
|
+
* c holds what used to be in *tail
|
|
2823
|
+
* last is 1 if this is the last tail
|
|
2824
|
+
*/
|
|
2825
|
+
chdir_fd = la_opendirat(AT_FDCWD, ".");
|
|
2826
|
+
__archive_ensure_cloexec_flag(chdir_fd);
|
|
2827
|
+
if (chdir_fd < 0) {
|
|
2828
|
+
fsobj_error(a_eno, a_estr, errno,
|
|
2829
|
+
"Could not open ", path);
|
|
2830
|
+
return (ARCHIVE_FATAL);
|
|
2831
|
+
}
|
|
2832
|
+
head = path;
|
|
2833
|
+
tail = path;
|
|
2834
|
+
last = 0;
|
|
2835
|
+
/* TODO: reintroduce a safe cache here? */
|
|
2836
|
+
/* Skip the root directory if the path is absolute. */
|
|
2837
|
+
if(tail == path && tail[0] == '/')
|
|
2838
|
+
++tail;
|
|
2839
|
+
/* Keep going until we've checked the entire name.
|
|
2840
|
+
* head, tail, path all alias the same string, which is
|
|
2841
|
+
* temporarily zeroed at tail, so be careful restoring the
|
|
2842
|
+
* stashed (c=tail[0]) for error messages.
|
|
2843
|
+
* Exiting the loop with break is okay; continue is not.
|
|
2844
|
+
*/
|
|
2845
|
+
while (!last) {
|
|
2846
|
+
/*
|
|
2847
|
+
* Skip the separator we just consumed, plus any adjacent ones
|
|
2848
|
+
*/
|
|
2849
|
+
while (*tail == '/')
|
|
2850
|
+
++tail;
|
|
2851
|
+
/* Skip the next path element. */
|
|
2852
|
+
while (*tail != '\0' && *tail != '/')
|
|
2853
|
+
++tail;
|
|
2854
|
+
/* is this the last path component? */
|
|
2855
|
+
last = (tail[0] == '\0') || (tail[0] == '/' && tail[1] == '\0');
|
|
2856
|
+
/* temporarily truncate the string here */
|
|
2857
|
+
c = tail[0];
|
|
2858
|
+
tail[0] = '\0';
|
|
2859
|
+
/* Check that we haven't hit a symlink. */
|
|
2860
|
+
#if defined(HAVE_OPENAT) && defined(HAVE_FSTATAT) && defined(HAVE_UNLINKAT)
|
|
2861
|
+
r = fstatat(chdir_fd, head, &st, AT_SYMLINK_NOFOLLOW);
|
|
2862
|
+
#else
|
|
2863
|
+
r = lstat(head, &st);
|
|
2864
|
+
#endif
|
|
2865
|
+
if (r != 0) {
|
|
2866
|
+
tail[0] = c;
|
|
2867
|
+
/* We've hit a dir that doesn't exist; stop now. */
|
|
2868
|
+
if (errno == ENOENT) {
|
|
2869
|
+
break;
|
|
2870
|
+
} else {
|
|
2871
|
+
/*
|
|
2872
|
+
* Treat any other error as fatal - best to be
|
|
2873
|
+
* paranoid here.
|
|
2874
|
+
* Note: This effectively disables deep
|
|
2875
|
+
* directory support when security checks are
|
|
2876
|
+
* enabled. Otherwise, very long pathnames that
|
|
2877
|
+
* trigger an error here could evade the
|
|
2878
|
+
* sandbox.
|
|
2879
|
+
* TODO: We could do better, but it would
|
|
2880
|
+
* probably require merging the symlink checks
|
|
2881
|
+
* with the deep-directory editing.
|
|
2882
|
+
*/
|
|
2883
|
+
fsobj_error(a_eno, a_estr, errno,
|
|
2884
|
+
"Could not stat ", path);
|
|
2885
|
+
res = ARCHIVE_FAILED;
|
|
2886
|
+
break;
|
|
2887
|
+
}
|
|
2888
|
+
} else if (S_ISDIR(st.st_mode)) {
|
|
2889
|
+
if (!last) {
|
|
2890
|
+
#if defined(HAVE_OPENAT) && defined(HAVE_FSTATAT) && defined(HAVE_UNLINKAT)
|
|
2891
|
+
fd = la_opendirat(chdir_fd, head);
|
|
2892
|
+
if (fd < 0)
|
|
2893
|
+
r = -1;
|
|
2894
|
+
else {
|
|
2895
|
+
r = 0;
|
|
2896
|
+
close(chdir_fd);
|
|
2897
|
+
chdir_fd = fd;
|
|
2898
|
+
}
|
|
2899
|
+
#else
|
|
2900
|
+
r = chdir(head);
|
|
2901
|
+
#endif
|
|
2902
|
+
if (r != 0) {
|
|
2903
|
+
tail[0] = c;
|
|
2904
|
+
fsobj_error(a_eno, a_estr, errno,
|
|
2905
|
+
"Could not chdir ", path);
|
|
2906
|
+
res = (ARCHIVE_FATAL);
|
|
2907
|
+
break;
|
|
2908
|
+
}
|
|
2909
|
+
/* Our view is now from inside this dir: */
|
|
2910
|
+
head = tail + 1;
|
|
2911
|
+
}
|
|
2912
|
+
} else if (S_ISLNK(st.st_mode)) {
|
|
2913
|
+
if (last && checking_linkname) {
|
|
2914
|
+
#ifdef HAVE_LINKAT
|
|
2915
|
+
/*
|
|
2916
|
+
* Hardlinks to symlinks are safe to write
|
|
2917
|
+
* if linkat() is supported as it does not
|
|
2918
|
+
* follow symlinks.
|
|
2919
|
+
*/
|
|
2920
|
+
res = ARCHIVE_OK;
|
|
2921
|
+
#else
|
|
2922
|
+
/*
|
|
2923
|
+
* We return ARCHIVE_FAILED here as we are
|
|
2924
|
+
* not able to safely write hardlinks
|
|
2925
|
+
* to symlinks.
|
|
2926
|
+
*/
|
|
2927
|
+
tail[0] = c;
|
|
2928
|
+
fsobj_error(a_eno, a_estr, errno,
|
|
2929
|
+
"Cannot write hardlink to symlink ",
|
|
2930
|
+
path);
|
|
2931
|
+
res = ARCHIVE_FAILED;
|
|
2932
|
+
#endif
|
|
2933
|
+
break;
|
|
2934
|
+
} else
|
|
2935
|
+
if (last) {
|
|
2936
|
+
/*
|
|
2937
|
+
* Last element is symlink; remove it
|
|
2938
|
+
* so we can overwrite it with the
|
|
2939
|
+
* item being extracted.
|
|
2940
|
+
*/
|
|
2941
|
+
#if defined(HAVE_OPENAT) && defined(HAVE_FSTATAT) && defined(HAVE_UNLINKAT)
|
|
2942
|
+
r = unlinkat(chdir_fd, head, 0);
|
|
2943
|
+
#else
|
|
2944
|
+
r = unlink(head);
|
|
2945
|
+
#endif
|
|
2946
|
+
if (r != 0) {
|
|
2947
|
+
tail[0] = c;
|
|
2948
|
+
fsobj_error(a_eno, a_estr, errno,
|
|
2949
|
+
"Could not remove symlink ",
|
|
2950
|
+
path);
|
|
2951
|
+
res = ARCHIVE_FAILED;
|
|
2952
|
+
break;
|
|
2953
|
+
}
|
|
2954
|
+
/*
|
|
2955
|
+
* Even if we did remove it, a warning
|
|
2956
|
+
* is in order. The warning is silly,
|
|
2957
|
+
* though, if we're just replacing one
|
|
2958
|
+
* symlink with another symlink.
|
|
2959
|
+
*/
|
|
2960
|
+
tail[0] = c;
|
|
2961
|
+
/*
|
|
2962
|
+
* FIXME: not sure how important this is to
|
|
2963
|
+
* restore
|
|
2964
|
+
*/
|
|
2965
|
+
/*
|
|
2966
|
+
if (!S_ISLNK(path)) {
|
|
2967
|
+
fsobj_error(a_eno, a_estr, 0,
|
|
2968
|
+
"Removing symlink ", path);
|
|
2969
|
+
}
|
|
2970
|
+
*/
|
|
2971
|
+
/* Symlink gone. No more problem! */
|
|
2972
|
+
res = ARCHIVE_OK;
|
|
2973
|
+
break;
|
|
2974
|
+
} else if (flags & ARCHIVE_EXTRACT_UNLINK) {
|
|
2975
|
+
/* User asked us to remove problems. */
|
|
2976
|
+
#if defined(HAVE_OPENAT) && defined(HAVE_FSTATAT) && defined(HAVE_UNLINKAT)
|
|
2977
|
+
r = unlinkat(chdir_fd, head, 0);
|
|
2978
|
+
#else
|
|
2979
|
+
r = unlink(head);
|
|
2980
|
+
#endif
|
|
2981
|
+
if (r != 0) {
|
|
2982
|
+
tail[0] = c;
|
|
2983
|
+
fsobj_error(a_eno, a_estr, 0,
|
|
2984
|
+
"Cannot remove intervening "
|
|
2985
|
+
"symlink ", path);
|
|
2986
|
+
res = ARCHIVE_FAILED;
|
|
2987
|
+
break;
|
|
2988
|
+
}
|
|
2989
|
+
tail[0] = c;
|
|
2990
|
+
} else if ((flags &
|
|
2991
|
+
ARCHIVE_EXTRACT_SECURE_SYMLINKS) == 0) {
|
|
2992
|
+
/*
|
|
2993
|
+
* We are not the last element and we want to
|
|
2994
|
+
* follow symlinks if they are a directory.
|
|
2995
|
+
*
|
|
2996
|
+
* This is needed to extract hardlinks over
|
|
2997
|
+
* symlinks.
|
|
2998
|
+
*/
|
|
2999
|
+
#if defined(HAVE_OPENAT) && defined(HAVE_FSTATAT) && defined(HAVE_UNLINKAT)
|
|
3000
|
+
r = fstatat(chdir_fd, head, &st, 0);
|
|
3001
|
+
#else
|
|
3002
|
+
r = la_stat(head, &st);
|
|
3003
|
+
#endif
|
|
3004
|
+
if (r != 0) {
|
|
3005
|
+
tail[0] = c;
|
|
3006
|
+
if (errno == ENOENT) {
|
|
3007
|
+
break;
|
|
3008
|
+
} else {
|
|
3009
|
+
fsobj_error(a_eno, a_estr,
|
|
3010
|
+
errno,
|
|
3011
|
+
"Could not stat ", path);
|
|
3012
|
+
res = (ARCHIVE_FAILED);
|
|
3013
|
+
break;
|
|
3014
|
+
}
|
|
3015
|
+
} else if (S_ISDIR(st.st_mode)) {
|
|
3016
|
+
#if defined(HAVE_OPENAT) && defined(HAVE_FSTATAT) && defined(HAVE_UNLINKAT)
|
|
3017
|
+
fd = la_opendirat(chdir_fd, head);
|
|
3018
|
+
if (fd < 0)
|
|
3019
|
+
r = -1;
|
|
3020
|
+
else {
|
|
3021
|
+
r = 0;
|
|
3022
|
+
close(chdir_fd);
|
|
3023
|
+
chdir_fd = fd;
|
|
3024
|
+
}
|
|
3025
|
+
#else
|
|
3026
|
+
r = chdir(head);
|
|
3027
|
+
#endif
|
|
3028
|
+
if (r != 0) {
|
|
3029
|
+
tail[0] = c;
|
|
3030
|
+
fsobj_error(a_eno, a_estr,
|
|
3031
|
+
errno,
|
|
3032
|
+
"Could not chdir ", path);
|
|
3033
|
+
res = (ARCHIVE_FATAL);
|
|
3034
|
+
break;
|
|
3035
|
+
}
|
|
3036
|
+
/*
|
|
3037
|
+
* Our view is now from inside
|
|
3038
|
+
* this dir:
|
|
3039
|
+
*/
|
|
3040
|
+
head = tail + 1;
|
|
3041
|
+
} else {
|
|
3042
|
+
tail[0] = c;
|
|
3043
|
+
fsobj_error(a_eno, a_estr, 0,
|
|
3044
|
+
"Cannot extract through "
|
|
3045
|
+
"symlink ", path);
|
|
3046
|
+
res = ARCHIVE_FAILED;
|
|
3047
|
+
break;
|
|
3048
|
+
}
|
|
3049
|
+
} else {
|
|
3050
|
+
tail[0] = c;
|
|
3051
|
+
fsobj_error(a_eno, a_estr, 0,
|
|
3052
|
+
"Cannot extract through symlink ", path);
|
|
3053
|
+
res = ARCHIVE_FAILED;
|
|
3054
|
+
break;
|
|
3055
|
+
}
|
|
3056
|
+
}
|
|
3057
|
+
/* be sure to always maintain this */
|
|
3058
|
+
tail[0] = c;
|
|
3059
|
+
if (tail[0] != '\0')
|
|
3060
|
+
tail++; /* Advance to the next segment. */
|
|
3061
|
+
}
|
|
3062
|
+
/* Catches loop exits via break */
|
|
3063
|
+
tail[0] = c;
|
|
3064
|
+
#if defined(HAVE_OPENAT) && defined(HAVE_FSTATAT) && defined(HAVE_UNLINKAT)
|
|
3065
|
+
/* If we operate with openat(), fstatat() and unlinkat() there was
|
|
3066
|
+
* no chdir(), so just close the fd */
|
|
3067
|
+
if (chdir_fd >= 0)
|
|
3068
|
+
close(chdir_fd);
|
|
3069
|
+
#elif HAVE_FCHDIR
|
|
3070
|
+
/* If we changed directory above, restore it here. */
|
|
3071
|
+
if (chdir_fd >= 0) {
|
|
3072
|
+
r = fchdir(chdir_fd);
|
|
3073
|
+
if (r != 0) {
|
|
3074
|
+
fsobj_error(a_eno, a_estr, errno,
|
|
3075
|
+
"chdir() failure", "");
|
|
3076
|
+
}
|
|
3077
|
+
close(chdir_fd);
|
|
3078
|
+
chdir_fd = -1;
|
|
3079
|
+
if (r != 0) {
|
|
3080
|
+
res = (ARCHIVE_FATAL);
|
|
3081
|
+
}
|
|
3082
|
+
}
|
|
3083
|
+
#endif
|
|
3084
|
+
/* TODO: reintroduce a safe cache here? */
|
|
3085
|
+
return res;
|
|
3086
|
+
#endif
|
|
3087
|
+
}
|
|
3088
|
+
|
|
3089
|
+
/*
|
|
3090
|
+
* Check a->name for symlinks, returning ARCHIVE_OK if its clean, otherwise
|
|
3091
|
+
* calls archive_set_error and returns ARCHIVE_{FATAL,FAILED}
|
|
3092
|
+
*/
|
|
3093
|
+
static int
|
|
3094
|
+
check_symlinks(struct archive_write_disk *a)
|
|
3095
|
+
{
|
|
3096
|
+
struct archive_string error_string;
|
|
3097
|
+
int error_number;
|
|
3098
|
+
int rc;
|
|
3099
|
+
archive_string_init(&error_string);
|
|
3100
|
+
rc = check_symlinks_fsobj(a->name, &error_number, &error_string,
|
|
3101
|
+
a->flags, 0);
|
|
3102
|
+
if (rc != ARCHIVE_OK) {
|
|
3103
|
+
archive_set_error(&a->archive, error_number, "%s",
|
|
3104
|
+
error_string.s);
|
|
3105
|
+
}
|
|
3106
|
+
archive_string_free(&error_string);
|
|
3107
|
+
a->pst = NULL; /* to be safe */
|
|
3108
|
+
return rc;
|
|
3109
|
+
}
|
|
3110
|
+
|
|
3111
|
+
|
|
3112
|
+
#if defined(__CYGWIN__)
|
|
3113
|
+
/*
|
|
3114
|
+
* 1. Convert a path separator from '\' to '/' .
|
|
3115
|
+
* We shouldn't check multibyte character directly because some
|
|
3116
|
+
* character-set have been using the '\' character for a part of
|
|
3117
|
+
* its multibyte character code.
|
|
3118
|
+
* 2. Replace unusable characters in Windows with underscore('_').
|
|
3119
|
+
* See also : http://msdn.microsoft.com/en-us/library/aa365247.aspx
|
|
3120
|
+
*/
|
|
3121
|
+
static void
|
|
3122
|
+
cleanup_pathname_win(char *path)
|
|
3123
|
+
{
|
|
3124
|
+
wchar_t wc;
|
|
3125
|
+
char *p;
|
|
3126
|
+
size_t alen, l;
|
|
3127
|
+
int mb, complete, utf8;
|
|
3128
|
+
|
|
3129
|
+
alen = 0;
|
|
3130
|
+
mb = 0;
|
|
3131
|
+
complete = 1;
|
|
3132
|
+
utf8 = (strcmp(nl_langinfo(CODESET), "UTF-8") == 0)? 1: 0;
|
|
3133
|
+
for (p = path; *p != '\0'; p++) {
|
|
3134
|
+
++alen;
|
|
3135
|
+
if (*p == '\\') {
|
|
3136
|
+
/* If previous byte is smaller than 128,
|
|
3137
|
+
* this is not second byte of multibyte characters,
|
|
3138
|
+
* so we can replace '\' with '/'. */
|
|
3139
|
+
if (utf8 || !mb)
|
|
3140
|
+
*p = '/';
|
|
3141
|
+
else
|
|
3142
|
+
complete = 0;/* uncompleted. */
|
|
3143
|
+
} else if (*(unsigned char *)p > 127)
|
|
3144
|
+
mb = 1;
|
|
3145
|
+
else
|
|
3146
|
+
mb = 0;
|
|
3147
|
+
/* Rewrite the path name if its next character is unusable. */
|
|
3148
|
+
if (*p == ':' || *p == '*' || *p == '?' || *p == '"' ||
|
|
3149
|
+
*p == '<' || *p == '>' || *p == '|')
|
|
3150
|
+
*p = '_';
|
|
3151
|
+
}
|
|
3152
|
+
if (complete)
|
|
3153
|
+
return;
|
|
3154
|
+
|
|
3155
|
+
/*
|
|
3156
|
+
* Convert path separator in wide-character.
|
|
3157
|
+
*/
|
|
3158
|
+
p = path;
|
|
3159
|
+
while (*p != '\0' && alen) {
|
|
3160
|
+
l = mbtowc(&wc, p, alen);
|
|
3161
|
+
if (l == (size_t)-1) {
|
|
3162
|
+
while (*p != '\0') {
|
|
3163
|
+
if (*p == '\\')
|
|
3164
|
+
*p = '/';
|
|
3165
|
+
++p;
|
|
3166
|
+
}
|
|
3167
|
+
break;
|
|
3168
|
+
}
|
|
3169
|
+
if (l == 1 && wc == L'\\')
|
|
3170
|
+
*p = '/';
|
|
3171
|
+
p += l;
|
|
3172
|
+
alen -= l;
|
|
3173
|
+
}
|
|
3174
|
+
}
|
|
3175
|
+
#endif
|
|
3176
|
+
|
|
3177
|
+
/*
|
|
3178
|
+
* Canonicalize the pathname. In particular, this strips duplicate
|
|
3179
|
+
* '/' characters, '.' elements, and trailing '/'. It also raises an
|
|
3180
|
+
* error for an empty path, a trailing '..', (if _SECURE_NODOTDOT is
|
|
3181
|
+
* set) any '..' in the path or (if ARCHIVE_EXTRACT_SECURE_NOABSOLUTEPATHS
|
|
3182
|
+
* is set) if the path is absolute.
|
|
3183
|
+
*/
|
|
3184
|
+
static int
|
|
3185
|
+
cleanup_pathname_fsobj(char *path, int *a_eno, struct archive_string *a_estr,
|
|
3186
|
+
int flags)
|
|
3187
|
+
{
|
|
3188
|
+
char *dest, *src;
|
|
3189
|
+
char separator = '\0';
|
|
3190
|
+
|
|
3191
|
+
dest = src = path;
|
|
3192
|
+
if (*src == '\0') {
|
|
3193
|
+
fsobj_error(a_eno, a_estr, ARCHIVE_ERRNO_MISC,
|
|
3194
|
+
"Invalid empty ", "pathname");
|
|
3195
|
+
return (ARCHIVE_FAILED);
|
|
3196
|
+
}
|
|
3197
|
+
|
|
3198
|
+
#if defined(__CYGWIN__)
|
|
3199
|
+
cleanup_pathname_win(path);
|
|
3200
|
+
#endif
|
|
3201
|
+
/* Skip leading '/'. */
|
|
3202
|
+
if (*src == '/') {
|
|
3203
|
+
if (flags & ARCHIVE_EXTRACT_SECURE_NOABSOLUTEPATHS) {
|
|
3204
|
+
fsobj_error(a_eno, a_estr, ARCHIVE_ERRNO_MISC,
|
|
3205
|
+
"Path is ", "absolute");
|
|
3206
|
+
return (ARCHIVE_FAILED);
|
|
3207
|
+
}
|
|
3208
|
+
|
|
3209
|
+
separator = *src++;
|
|
3210
|
+
}
|
|
3211
|
+
|
|
3212
|
+
/* Scan the pathname one element at a time. */
|
|
3213
|
+
for (;;) {
|
|
3214
|
+
/* src points to first char after '/' */
|
|
3215
|
+
if (src[0] == '\0') {
|
|
3216
|
+
break;
|
|
3217
|
+
} else if (src[0] == '/') {
|
|
3218
|
+
/* Found '//', ignore second one. */
|
|
3219
|
+
src++;
|
|
3220
|
+
continue;
|
|
3221
|
+
} else if (src[0] == '.') {
|
|
3222
|
+
if (src[1] == '\0') {
|
|
3223
|
+
/* Ignore trailing '.' */
|
|
3224
|
+
break;
|
|
3225
|
+
} else if (src[1] == '/') {
|
|
3226
|
+
/* Skip './'. */
|
|
3227
|
+
src += 2;
|
|
3228
|
+
continue;
|
|
3229
|
+
} else if (src[1] == '.') {
|
|
3230
|
+
if (src[2] == '/' || src[2] == '\0') {
|
|
3231
|
+
/* Conditionally warn about '..' */
|
|
3232
|
+
if (flags
|
|
3233
|
+
& ARCHIVE_EXTRACT_SECURE_NODOTDOT) {
|
|
3234
|
+
fsobj_error(a_eno, a_estr,
|
|
3235
|
+
ARCHIVE_ERRNO_MISC,
|
|
3236
|
+
"Path contains ", "'..'");
|
|
3237
|
+
return (ARCHIVE_FAILED);
|
|
3238
|
+
}
|
|
3239
|
+
}
|
|
3240
|
+
/*
|
|
3241
|
+
* Note: Under no circumstances do we
|
|
3242
|
+
* remove '..' elements. In
|
|
3243
|
+
* particular, restoring
|
|
3244
|
+
* '/foo/../bar/' should create the
|
|
3245
|
+
* 'foo' dir as a side-effect.
|
|
3246
|
+
*/
|
|
3247
|
+
}
|
|
3248
|
+
}
|
|
3249
|
+
|
|
3250
|
+
/* Copy current element, including leading '/'. */
|
|
3251
|
+
if (separator)
|
|
3252
|
+
*dest++ = '/';
|
|
3253
|
+
while (*src != '\0' && *src != '/') {
|
|
3254
|
+
*dest++ = *src++;
|
|
3255
|
+
}
|
|
3256
|
+
|
|
3257
|
+
if (*src == '\0')
|
|
3258
|
+
break;
|
|
3259
|
+
|
|
3260
|
+
/* Skip '/' separator. */
|
|
3261
|
+
separator = *src++;
|
|
3262
|
+
}
|
|
3263
|
+
/*
|
|
3264
|
+
* We've just copied zero or more path elements, not including the
|
|
3265
|
+
* final '/'.
|
|
3266
|
+
*/
|
|
3267
|
+
if (dest == path) {
|
|
3268
|
+
/*
|
|
3269
|
+
* Nothing got copied. The path must have been something
|
|
3270
|
+
* like '.' or '/' or './' or '/././././/./'.
|
|
3271
|
+
*/
|
|
3272
|
+
if (separator)
|
|
3273
|
+
*dest++ = '/';
|
|
3274
|
+
else
|
|
3275
|
+
*dest++ = '.';
|
|
3276
|
+
}
|
|
3277
|
+
/* Terminate the result. */
|
|
3278
|
+
*dest = '\0';
|
|
3279
|
+
return (ARCHIVE_OK);
|
|
3280
|
+
}
|
|
3281
|
+
|
|
3282
|
+
static int
|
|
3283
|
+
cleanup_pathname(struct archive_write_disk *a)
|
|
3284
|
+
{
|
|
3285
|
+
struct archive_string error_string;
|
|
3286
|
+
int error_number;
|
|
3287
|
+
int rc;
|
|
3288
|
+
archive_string_init(&error_string);
|
|
3289
|
+
rc = cleanup_pathname_fsobj(a->name, &error_number, &error_string,
|
|
3290
|
+
a->flags);
|
|
3291
|
+
if (rc != ARCHIVE_OK) {
|
|
3292
|
+
archive_set_error(&a->archive, error_number, "%s",
|
|
3293
|
+
error_string.s);
|
|
3294
|
+
}
|
|
3295
|
+
archive_string_free(&error_string);
|
|
3296
|
+
return rc;
|
|
3297
|
+
}
|
|
3298
|
+
|
|
3299
|
+
/*
|
|
3300
|
+
* Create the parent directory of the specified path, assuming path
|
|
3301
|
+
* is already in mutable storage.
|
|
3302
|
+
*/
|
|
3303
|
+
static int
|
|
3304
|
+
create_parent_dir(struct archive_write_disk *a, char *path)
|
|
3305
|
+
{
|
|
3306
|
+
char *slash;
|
|
3307
|
+
int r;
|
|
3308
|
+
|
|
3309
|
+
/* Remove tail element to obtain parent name. */
|
|
3310
|
+
slash = strrchr(path, '/');
|
|
3311
|
+
if (slash == NULL)
|
|
3312
|
+
return (ARCHIVE_OK);
|
|
3313
|
+
*slash = '\0';
|
|
3314
|
+
r = create_dir(a, path);
|
|
3315
|
+
*slash = '/';
|
|
3316
|
+
return (r);
|
|
3317
|
+
}
|
|
3318
|
+
|
|
3319
|
+
/*
|
|
3320
|
+
* Create the specified dir, recursing to create parents as necessary.
|
|
3321
|
+
*
|
|
3322
|
+
* Returns ARCHIVE_OK if the path exists when we're done here.
|
|
3323
|
+
* Otherwise, returns ARCHIVE_FAILED.
|
|
3324
|
+
* Assumes path is in mutable storage; path is unchanged on exit.
|
|
3325
|
+
*/
|
|
3326
|
+
static int
|
|
3327
|
+
create_dir(struct archive_write_disk *a, char *path)
|
|
3328
|
+
{
|
|
3329
|
+
struct stat st;
|
|
3330
|
+
struct fixup_entry *le;
|
|
3331
|
+
char *slash, *base;
|
|
3332
|
+
mode_t mode_final, mode;
|
|
3333
|
+
int r;
|
|
3334
|
+
|
|
3335
|
+
/* Check for special names and just skip them. */
|
|
3336
|
+
slash = strrchr(path, '/');
|
|
3337
|
+
if (slash == NULL)
|
|
3338
|
+
base = path;
|
|
3339
|
+
else
|
|
3340
|
+
base = slash + 1;
|
|
3341
|
+
|
|
3342
|
+
if (base[0] == '\0' ||
|
|
3343
|
+
(base[0] == '.' && base[1] == '\0') ||
|
|
3344
|
+
(base[0] == '.' && base[1] == '.' && base[2] == '\0')) {
|
|
3345
|
+
/* Don't bother trying to create null path, '.', or '..'. */
|
|
3346
|
+
if (slash != NULL) {
|
|
3347
|
+
*slash = '\0';
|
|
3348
|
+
r = create_dir(a, path);
|
|
3349
|
+
*slash = '/';
|
|
3350
|
+
return (r);
|
|
3351
|
+
}
|
|
3352
|
+
return (ARCHIVE_OK);
|
|
3353
|
+
}
|
|
3354
|
+
|
|
3355
|
+
/*
|
|
3356
|
+
* Yes, this should be stat() and not lstat(). Using lstat()
|
|
3357
|
+
* here loses the ability to extract through symlinks. Also note
|
|
3358
|
+
* that this should not use the a->st cache.
|
|
3359
|
+
*/
|
|
3360
|
+
if (la_stat(path, &st) == 0) {
|
|
3361
|
+
if (S_ISDIR(st.st_mode))
|
|
3362
|
+
return (ARCHIVE_OK);
|
|
3363
|
+
if ((a->flags & ARCHIVE_EXTRACT_NO_OVERWRITE)) {
|
|
3364
|
+
archive_set_error(&a->archive, EEXIST,
|
|
3365
|
+
"Can't create directory '%s'", path);
|
|
3366
|
+
return (ARCHIVE_FAILED);
|
|
3367
|
+
}
|
|
3368
|
+
if (unlink(path) != 0) {
|
|
3369
|
+
archive_set_error(&a->archive, errno,
|
|
3370
|
+
"Can't create directory '%s': "
|
|
3371
|
+
"Conflicting file cannot be removed",
|
|
3372
|
+
path);
|
|
3373
|
+
return (ARCHIVE_FAILED);
|
|
3374
|
+
}
|
|
3375
|
+
} else if (errno != ENOENT && errno != ENOTDIR) {
|
|
3376
|
+
/* Stat failed? */
|
|
3377
|
+
archive_set_error(&a->archive, errno,
|
|
3378
|
+
"Can't test directory '%s'", path);
|
|
3379
|
+
return (ARCHIVE_FAILED);
|
|
3380
|
+
} else if (slash != NULL) {
|
|
3381
|
+
*slash = '\0';
|
|
3382
|
+
r = create_dir(a, path);
|
|
3383
|
+
*slash = '/';
|
|
3384
|
+
if (r != ARCHIVE_OK)
|
|
3385
|
+
return (r);
|
|
3386
|
+
}
|
|
3387
|
+
|
|
3388
|
+
/*
|
|
3389
|
+
* Mode we want for the final restored directory. Per POSIX,
|
|
3390
|
+
* implicitly-created dirs must be created obeying the umask.
|
|
3391
|
+
* There's no mention whether this is different for privileged
|
|
3392
|
+
* restores (which the rest of this code handles by pretending
|
|
3393
|
+
* umask=0). I've chosen here to always obey the user's umask for
|
|
3394
|
+
* implicit dirs, even if _EXTRACT_PERM was specified.
|
|
3395
|
+
*/
|
|
3396
|
+
mode_final = DEFAULT_DIR_MODE & ~a->user_umask;
|
|
3397
|
+
/* Mode we want on disk during the restore process. */
|
|
3398
|
+
mode = mode_final;
|
|
3399
|
+
mode |= MINIMUM_DIR_MODE;
|
|
3400
|
+
mode &= MAXIMUM_DIR_MODE;
|
|
3401
|
+
if (mkdir(path, mode) == 0) {
|
|
3402
|
+
if (mode != mode_final) {
|
|
3403
|
+
le = new_fixup(a, path);
|
|
3404
|
+
if (le == NULL)
|
|
3405
|
+
return (ARCHIVE_FATAL);
|
|
3406
|
+
le->fixup |=TODO_MODE_BASE;
|
|
3407
|
+
le->mode = mode_final;
|
|
3408
|
+
}
|
|
3409
|
+
return (ARCHIVE_OK);
|
|
3410
|
+
}
|
|
3411
|
+
|
|
3412
|
+
/*
|
|
3413
|
+
* Without the following check, a/b/../b/c/d fails at the
|
|
3414
|
+
* second visit to 'b', so 'd' can't be created. Note that we
|
|
3415
|
+
* don't add it to the fixup list here, as it's already been
|
|
3416
|
+
* added.
|
|
3417
|
+
*/
|
|
3418
|
+
if (la_stat(path, &st) == 0 && S_ISDIR(st.st_mode))
|
|
3419
|
+
return (ARCHIVE_OK);
|
|
3420
|
+
|
|
3421
|
+
archive_set_error(&a->archive, errno, "Failed to create dir '%s'",
|
|
3422
|
+
path);
|
|
3423
|
+
return (ARCHIVE_FAILED);
|
|
3424
|
+
}
|
|
3425
|
+
|
|
3426
|
+
/*
|
|
3427
|
+
* Note: Although we can skip setting the user id if the desired user
|
|
3428
|
+
* id matches the current user, we cannot skip setting the group, as
|
|
3429
|
+
* many systems set the gid based on the containing directory. So
|
|
3430
|
+
* we have to perform a chown syscall if we want to set the SGID
|
|
3431
|
+
* bit. (The alternative is to stat() and then possibly chown(); it's
|
|
3432
|
+
* more efficient to skip the stat() and just always chown().) Note
|
|
3433
|
+
* that a successful chown() here clears the TODO_SGID_CHECK bit, which
|
|
3434
|
+
* allows set_mode to skip the stat() check for the GID.
|
|
3435
|
+
*/
|
|
3436
|
+
static int
|
|
3437
|
+
set_ownership(struct archive_write_disk *a)
|
|
3438
|
+
{
|
|
3439
|
+
#if !defined(__CYGWIN__) && !defined(__linux__)
|
|
3440
|
+
/*
|
|
3441
|
+
* On Linux, a process may have the CAP_CHOWN capability.
|
|
3442
|
+
* On Windows there is no 'root' user with uid 0.
|
|
3443
|
+
* Elsewhere we can skip calling chown if we are not root and the desired
|
|
3444
|
+
* user id does not match the current user.
|
|
3445
|
+
*/
|
|
3446
|
+
if (a->user_uid != 0 && a->user_uid != a->uid) {
|
|
3447
|
+
archive_set_error(&a->archive, errno,
|
|
3448
|
+
"Can't set UID=%jd", (intmax_t)a->uid);
|
|
3449
|
+
return (ARCHIVE_WARN);
|
|
3450
|
+
}
|
|
3451
|
+
#endif
|
|
3452
|
+
|
|
3453
|
+
#ifdef HAVE_FCHOWN
|
|
3454
|
+
/* If we have an fd, we can avoid a race. */
|
|
3455
|
+
if (a->fd >= 0 && fchown(a->fd, a->uid, a->gid) == 0) {
|
|
3456
|
+
/* We've set owner and know uid/gid are correct. */
|
|
3457
|
+
a->todo &= ~(TODO_OWNER | TODO_SGID_CHECK | TODO_SUID_CHECK);
|
|
3458
|
+
return (ARCHIVE_OK);
|
|
3459
|
+
}
|
|
3460
|
+
#endif
|
|
3461
|
+
|
|
3462
|
+
/* We prefer lchown() but will use chown() if that's all we have. */
|
|
3463
|
+
/* Of course, if we have neither, this will always fail. */
|
|
3464
|
+
#ifdef HAVE_LCHOWN
|
|
3465
|
+
if (lchown(a->name, a->uid, a->gid) == 0) {
|
|
3466
|
+
/* We've set owner and know uid/gid are correct. */
|
|
3467
|
+
a->todo &= ~(TODO_OWNER | TODO_SGID_CHECK | TODO_SUID_CHECK);
|
|
3468
|
+
return (ARCHIVE_OK);
|
|
3469
|
+
}
|
|
3470
|
+
#elif HAVE_CHOWN
|
|
3471
|
+
if (!S_ISLNK(a->mode) && chown(a->name, a->uid, a->gid) == 0) {
|
|
3472
|
+
/* We've set owner and know uid/gid are correct. */
|
|
3473
|
+
a->todo &= ~(TODO_OWNER | TODO_SGID_CHECK | TODO_SUID_CHECK);
|
|
3474
|
+
return (ARCHIVE_OK);
|
|
3475
|
+
}
|
|
3476
|
+
#endif
|
|
3477
|
+
|
|
3478
|
+
archive_set_error(&a->archive, errno,
|
|
3479
|
+
"Can't set user=%jd/group=%jd for %s",
|
|
3480
|
+
(intmax_t)a->uid, (intmax_t)a->gid, a->name);
|
|
3481
|
+
return (ARCHIVE_WARN);
|
|
3482
|
+
}
|
|
3483
|
+
|
|
3484
|
+
/*
|
|
3485
|
+
* Note: Returns 0 on success, non-zero on failure.
|
|
3486
|
+
*/
|
|
3487
|
+
static int
|
|
3488
|
+
set_time(int fd, int mode, const char *name,
|
|
3489
|
+
time_t atime, long atime_nsec,
|
|
3490
|
+
time_t mtime, long mtime_nsec)
|
|
3491
|
+
{
|
|
3492
|
+
/* Select the best implementation for this platform. */
|
|
3493
|
+
#if defined(HAVE_UTIMENSAT) && defined(HAVE_FUTIMENS)
|
|
3494
|
+
/*
|
|
3495
|
+
* utimensat() and futimens() are defined in
|
|
3496
|
+
* POSIX.1-2008. They support ns resolution and setting times
|
|
3497
|
+
* on fds and symlinks.
|
|
3498
|
+
*/
|
|
3499
|
+
struct timespec ts[2];
|
|
3500
|
+
(void)mode; /* UNUSED */
|
|
3501
|
+
ts[0].tv_sec = atime;
|
|
3502
|
+
ts[0].tv_nsec = atime_nsec;
|
|
3503
|
+
ts[1].tv_sec = mtime;
|
|
3504
|
+
ts[1].tv_nsec = mtime_nsec;
|
|
3505
|
+
if (fd >= 0)
|
|
3506
|
+
return futimens(fd, ts);
|
|
3507
|
+
return utimensat(AT_FDCWD, name, ts, AT_SYMLINK_NOFOLLOW);
|
|
3508
|
+
|
|
3509
|
+
#elif HAVE_UTIMES
|
|
3510
|
+
/*
|
|
3511
|
+
* The utimes()-family functions support µs-resolution and
|
|
3512
|
+
* setting times fds and symlinks. utimes() is documented as
|
|
3513
|
+
* LEGACY by POSIX, futimes() and lutimes() are not described
|
|
3514
|
+
* in POSIX.
|
|
3515
|
+
*/
|
|
3516
|
+
struct timeval times[2];
|
|
3517
|
+
|
|
3518
|
+
times[0].tv_sec = atime;
|
|
3519
|
+
times[0].tv_usec = atime_nsec / 1000;
|
|
3520
|
+
times[1].tv_sec = mtime;
|
|
3521
|
+
times[1].tv_usec = mtime_nsec / 1000;
|
|
3522
|
+
|
|
3523
|
+
#ifdef HAVE_FUTIMES
|
|
3524
|
+
if (fd >= 0)
|
|
3525
|
+
return (futimes(fd, times));
|
|
3526
|
+
#else
|
|
3527
|
+
(void)fd; /* UNUSED */
|
|
3528
|
+
#endif
|
|
3529
|
+
#ifdef HAVE_LUTIMES
|
|
3530
|
+
(void)mode; /* UNUSED */
|
|
3531
|
+
return (lutimes(name, times));
|
|
3532
|
+
#else
|
|
3533
|
+
if (S_ISLNK(mode))
|
|
3534
|
+
return (0);
|
|
3535
|
+
return (utimes(name, times));
|
|
3536
|
+
#endif
|
|
3537
|
+
|
|
3538
|
+
#elif defined(HAVE_UTIME)
|
|
3539
|
+
/*
|
|
3540
|
+
* utime() is POSIX-standard but only supports 1s resolution and
|
|
3541
|
+
* does not support fds or symlinks.
|
|
3542
|
+
*/
|
|
3543
|
+
struct utimbuf times;
|
|
3544
|
+
(void)fd; /* UNUSED */
|
|
3545
|
+
(void)name; /* UNUSED */
|
|
3546
|
+
(void)atime_nsec; /* UNUSED */
|
|
3547
|
+
(void)mtime_nsec; /* UNUSED */
|
|
3548
|
+
times.actime = atime;
|
|
3549
|
+
times.modtime = mtime;
|
|
3550
|
+
if (S_ISLNK(mode))
|
|
3551
|
+
return (ARCHIVE_OK);
|
|
3552
|
+
return (utime(name, ×));
|
|
3553
|
+
|
|
3554
|
+
#else
|
|
3555
|
+
/*
|
|
3556
|
+
* We don't know how to set the time on this platform.
|
|
3557
|
+
*/
|
|
3558
|
+
(void)fd; /* UNUSED */
|
|
3559
|
+
(void)mode; /* UNUSED */
|
|
3560
|
+
(void)name; /* UNUSED */
|
|
3561
|
+
(void)atime_nsec; /* UNUSED */
|
|
3562
|
+
(void)mtime_nsec; /* UNUSED */
|
|
3563
|
+
return (ARCHIVE_WARN);
|
|
3564
|
+
#endif
|
|
3565
|
+
}
|
|
3566
|
+
|
|
3567
|
+
#ifdef F_SETTIMES
|
|
3568
|
+
static int
|
|
3569
|
+
set_time_tru64(int fd, int mode, const char *name,
|
|
3570
|
+
time_t atime, long atime_nsec,
|
|
3571
|
+
time_t mtime, long mtime_nsec,
|
|
3572
|
+
time_t ctime, long ctime_nsec)
|
|
3573
|
+
{
|
|
3574
|
+
struct attr_timbuf tstamp;
|
|
3575
|
+
tstamp.atime.tv_sec = atime;
|
|
3576
|
+
tstamp.mtime.tv_sec = mtime;
|
|
3577
|
+
tstamp.ctime.tv_sec = ctime;
|
|
3578
|
+
#if defined (__hpux) && defined (__ia64)
|
|
3579
|
+
tstamp.atime.tv_nsec = atime_nsec;
|
|
3580
|
+
tstamp.mtime.tv_nsec = mtime_nsec;
|
|
3581
|
+
tstamp.ctime.tv_nsec = ctime_nsec;
|
|
3582
|
+
#else
|
|
3583
|
+
tstamp.atime.tv_usec = atime_nsec / 1000;
|
|
3584
|
+
tstamp.mtime.tv_usec = mtime_nsec / 1000;
|
|
3585
|
+
tstamp.ctime.tv_usec = ctime_nsec / 1000;
|
|
3586
|
+
#endif
|
|
3587
|
+
return (fcntl(fd,F_SETTIMES,&tstamp));
|
|
3588
|
+
}
|
|
3589
|
+
#endif /* F_SETTIMES */
|
|
3590
|
+
|
|
3591
|
+
static int
|
|
3592
|
+
set_times(struct archive_write_disk *a,
|
|
3593
|
+
int fd, int mode, const char *name,
|
|
3594
|
+
time_t atime, long atime_nanos,
|
|
3595
|
+
time_t birthtime, long birthtime_nanos,
|
|
3596
|
+
time_t mtime, long mtime_nanos,
|
|
3597
|
+
time_t cctime, long ctime_nanos)
|
|
3598
|
+
{
|
|
3599
|
+
/* Note: set_time doesn't use libarchive return conventions!
|
|
3600
|
+
* It uses syscall conventions. So 0 here instead of ARCHIVE_OK. */
|
|
3601
|
+
int r1 = 0, r2 = 0;
|
|
3602
|
+
|
|
3603
|
+
#ifdef F_SETTIMES
|
|
3604
|
+
/*
|
|
3605
|
+
* on Tru64 try own fcntl first which can restore even the
|
|
3606
|
+
* ctime, fall back to default code path below if it fails
|
|
3607
|
+
* or if we are not running as root
|
|
3608
|
+
*/
|
|
3609
|
+
if (a->user_uid == 0 &&
|
|
3610
|
+
set_time_tru64(fd, mode, name,
|
|
3611
|
+
atime, atime_nanos, mtime,
|
|
3612
|
+
mtime_nanos, cctime, ctime_nanos) == 0) {
|
|
3613
|
+
return (ARCHIVE_OK);
|
|
3614
|
+
}
|
|
3615
|
+
#else /* Tru64 */
|
|
3616
|
+
(void)cctime; /* UNUSED */
|
|
3617
|
+
(void)ctime_nanos; /* UNUSED */
|
|
3618
|
+
#endif /* Tru64 */
|
|
3619
|
+
|
|
3620
|
+
#ifdef HAVE_STRUCT_STAT_ST_BIRTHTIME
|
|
3621
|
+
/*
|
|
3622
|
+
* If you have struct stat.st_birthtime, we assume BSD
|
|
3623
|
+
* birthtime semantics, in which {f,l,}utimes() updates
|
|
3624
|
+
* birthtime to earliest mtime. So we set the time twice,
|
|
3625
|
+
* first using the birthtime, then using the mtime. If
|
|
3626
|
+
* birthtime == mtime, this isn't necessary, so we skip it.
|
|
3627
|
+
* If birthtime > mtime, then this won't work, so we skip it.
|
|
3628
|
+
*/
|
|
3629
|
+
if (birthtime < mtime
|
|
3630
|
+
|| (birthtime == mtime && birthtime_nanos < mtime_nanos))
|
|
3631
|
+
r1 = set_time(fd, mode, name,
|
|
3632
|
+
atime, atime_nanos,
|
|
3633
|
+
birthtime, birthtime_nanos);
|
|
3634
|
+
#else
|
|
3635
|
+
(void)birthtime; /* UNUSED */
|
|
3636
|
+
(void)birthtime_nanos; /* UNUSED */
|
|
3637
|
+
#endif
|
|
3638
|
+
r2 = set_time(fd, mode, name,
|
|
3639
|
+
atime, atime_nanos,
|
|
3640
|
+
mtime, mtime_nanos);
|
|
3641
|
+
if (r1 != 0 || r2 != 0) {
|
|
3642
|
+
archive_set_error(&a->archive, errno,
|
|
3643
|
+
"Can't restore time");
|
|
3644
|
+
return (ARCHIVE_WARN);
|
|
3645
|
+
}
|
|
3646
|
+
return (ARCHIVE_OK);
|
|
3647
|
+
}
|
|
3648
|
+
|
|
3649
|
+
static int
|
|
3650
|
+
set_times_from_entry(struct archive_write_disk *a)
|
|
3651
|
+
{
|
|
3652
|
+
time_t atime, birthtime, mtime, cctime;
|
|
3653
|
+
long atime_nsec, birthtime_nsec, mtime_nsec, ctime_nsec;
|
|
3654
|
+
|
|
3655
|
+
/* Suitable defaults. */
|
|
3656
|
+
atime = birthtime = mtime = cctime = a->start_time;
|
|
3657
|
+
atime_nsec = birthtime_nsec = mtime_nsec = ctime_nsec = 0;
|
|
3658
|
+
|
|
3659
|
+
/* If no time was provided, we're done. */
|
|
3660
|
+
if (!archive_entry_atime_is_set(a->entry)
|
|
3661
|
+
#if HAVE_STRUCT_STAT_ST_BIRTHTIME
|
|
3662
|
+
&& !archive_entry_birthtime_is_set(a->entry)
|
|
3663
|
+
#endif
|
|
3664
|
+
&& !archive_entry_mtime_is_set(a->entry))
|
|
3665
|
+
return (ARCHIVE_OK);
|
|
3666
|
+
|
|
3667
|
+
if (archive_entry_atime_is_set(a->entry)) {
|
|
3668
|
+
atime = archive_entry_atime(a->entry);
|
|
3669
|
+
atime_nsec = archive_entry_atime_nsec(a->entry);
|
|
3670
|
+
}
|
|
3671
|
+
if (archive_entry_birthtime_is_set(a->entry)) {
|
|
3672
|
+
birthtime = archive_entry_birthtime(a->entry);
|
|
3673
|
+
birthtime_nsec = archive_entry_birthtime_nsec(a->entry);
|
|
3674
|
+
}
|
|
3675
|
+
if (archive_entry_mtime_is_set(a->entry)) {
|
|
3676
|
+
mtime = archive_entry_mtime(a->entry);
|
|
3677
|
+
mtime_nsec = archive_entry_mtime_nsec(a->entry);
|
|
3678
|
+
}
|
|
3679
|
+
if (archive_entry_ctime_is_set(a->entry)) {
|
|
3680
|
+
cctime = archive_entry_ctime(a->entry);
|
|
3681
|
+
ctime_nsec = archive_entry_ctime_nsec(a->entry);
|
|
3682
|
+
}
|
|
3683
|
+
|
|
3684
|
+
return set_times(a, a->fd, a->mode, a->name,
|
|
3685
|
+
atime, atime_nsec,
|
|
3686
|
+
birthtime, birthtime_nsec,
|
|
3687
|
+
mtime, mtime_nsec,
|
|
3688
|
+
cctime, ctime_nsec);
|
|
3689
|
+
}
|
|
3690
|
+
|
|
3691
|
+
static int
|
|
3692
|
+
set_mode(struct archive_write_disk *a, int mode)
|
|
3693
|
+
{
|
|
3694
|
+
int r = ARCHIVE_OK;
|
|
3695
|
+
int r2;
|
|
3696
|
+
mode &= 07777; /* Strip off file type bits. */
|
|
3697
|
+
|
|
3698
|
+
if (a->todo & TODO_SGID_CHECK) {
|
|
3699
|
+
/*
|
|
3700
|
+
* If we don't know the GID is right, we must stat()
|
|
3701
|
+
* to verify it. We can't just check the GID of this
|
|
3702
|
+
* process, since systems sometimes set GID from
|
|
3703
|
+
* the enclosing dir or based on ACLs.
|
|
3704
|
+
*/
|
|
3705
|
+
if ((r = lazy_stat(a)) != ARCHIVE_OK)
|
|
3706
|
+
return (r);
|
|
3707
|
+
if (a->pst->st_gid != a->gid) {
|
|
3708
|
+
mode &= ~ S_ISGID;
|
|
3709
|
+
if (a->flags & ARCHIVE_EXTRACT_OWNER) {
|
|
3710
|
+
/*
|
|
3711
|
+
* This is only an error if you
|
|
3712
|
+
* requested owner restore. If you
|
|
3713
|
+
* didn't, we'll try to restore
|
|
3714
|
+
* sgid/suid, but won't consider it a
|
|
3715
|
+
* problem if we can't.
|
|
3716
|
+
*/
|
|
3717
|
+
archive_set_error(&a->archive, -1,
|
|
3718
|
+
"Can't restore SGID bit");
|
|
3719
|
+
r = ARCHIVE_WARN;
|
|
3720
|
+
}
|
|
3721
|
+
}
|
|
3722
|
+
/* While we're here, double-check the UID. */
|
|
3723
|
+
if (a->pst->st_uid != a->uid
|
|
3724
|
+
&& (a->todo & TODO_SUID)) {
|
|
3725
|
+
mode &= ~ S_ISUID;
|
|
3726
|
+
if (a->flags & ARCHIVE_EXTRACT_OWNER) {
|
|
3727
|
+
archive_set_error(&a->archive, -1,
|
|
3728
|
+
"Can't restore SUID bit");
|
|
3729
|
+
r = ARCHIVE_WARN;
|
|
3730
|
+
}
|
|
3731
|
+
}
|
|
3732
|
+
a->todo &= ~TODO_SGID_CHECK;
|
|
3733
|
+
a->todo &= ~TODO_SUID_CHECK;
|
|
3734
|
+
} else if (a->todo & TODO_SUID_CHECK) {
|
|
3735
|
+
/*
|
|
3736
|
+
* If we don't know the UID is right, we can just check
|
|
3737
|
+
* the user, since all systems set the file UID from
|
|
3738
|
+
* the process UID.
|
|
3739
|
+
*/
|
|
3740
|
+
if (a->user_uid != a->uid) {
|
|
3741
|
+
mode &= ~ S_ISUID;
|
|
3742
|
+
if (a->flags & ARCHIVE_EXTRACT_OWNER) {
|
|
3743
|
+
archive_set_error(&a->archive, -1,
|
|
3744
|
+
"Can't make file SUID");
|
|
3745
|
+
r = ARCHIVE_WARN;
|
|
3746
|
+
}
|
|
3747
|
+
}
|
|
3748
|
+
a->todo &= ~TODO_SUID_CHECK;
|
|
3749
|
+
}
|
|
3750
|
+
|
|
3751
|
+
if (S_ISLNK(a->mode)) {
|
|
3752
|
+
#ifdef HAVE_LCHMOD
|
|
3753
|
+
/*
|
|
3754
|
+
* If this is a symlink, use lchmod(). If the
|
|
3755
|
+
* platform doesn't support lchmod(), just skip it. A
|
|
3756
|
+
* platform that doesn't provide a way to set
|
|
3757
|
+
* permissions on symlinks probably ignores
|
|
3758
|
+
* permissions on symlinks, so a failure here has no
|
|
3759
|
+
* impact.
|
|
3760
|
+
*/
|
|
3761
|
+
if (lchmod(a->name, mode) != 0) {
|
|
3762
|
+
switch (errno) {
|
|
3763
|
+
case ENOTSUP:
|
|
3764
|
+
case ENOSYS:
|
|
3765
|
+
#if ENOTSUP != EOPNOTSUPP
|
|
3766
|
+
case EOPNOTSUPP:
|
|
3767
|
+
#endif
|
|
3768
|
+
/*
|
|
3769
|
+
* if lchmod is defined but the platform
|
|
3770
|
+
* doesn't support it, silently ignore
|
|
3771
|
+
* error
|
|
3772
|
+
*/
|
|
3773
|
+
break;
|
|
3774
|
+
default:
|
|
3775
|
+
archive_set_error(&a->archive, errno,
|
|
3776
|
+
"Can't set permissions to 0%o", (int)mode);
|
|
3777
|
+
r = ARCHIVE_WARN;
|
|
3778
|
+
}
|
|
3779
|
+
}
|
|
3780
|
+
#endif
|
|
3781
|
+
} else if (!S_ISDIR(a->mode)) {
|
|
3782
|
+
/*
|
|
3783
|
+
* If it's not a symlink and not a dir, then use
|
|
3784
|
+
* fchmod() or chmod(), depending on whether we have
|
|
3785
|
+
* an fd. Dirs get their perms set during the
|
|
3786
|
+
* post-extract fixup, which is handled elsewhere.
|
|
3787
|
+
*/
|
|
3788
|
+
#ifdef HAVE_FCHMOD
|
|
3789
|
+
if (a->fd >= 0)
|
|
3790
|
+
r2 = fchmod(a->fd, mode);
|
|
3791
|
+
else
|
|
3792
|
+
#endif
|
|
3793
|
+
/* If this platform lacks fchmod(), then
|
|
3794
|
+
* we'll just use chmod(). */
|
|
3795
|
+
r2 = chmod(a->name, mode);
|
|
3796
|
+
|
|
3797
|
+
if (r2 != 0) {
|
|
3798
|
+
archive_set_error(&a->archive, errno,
|
|
3799
|
+
"Can't set permissions to 0%o", (int)mode);
|
|
3800
|
+
r = ARCHIVE_WARN;
|
|
3801
|
+
}
|
|
3802
|
+
}
|
|
3803
|
+
return (r);
|
|
3804
|
+
}
|
|
3805
|
+
|
|
3806
|
+
static int
|
|
3807
|
+
set_fflags(struct archive_write_disk *a)
|
|
3808
|
+
{
|
|
3809
|
+
struct fixup_entry *le;
|
|
3810
|
+
unsigned long set, clear;
|
|
3811
|
+
int r;
|
|
3812
|
+
mode_t mode = archive_entry_mode(a->entry);
|
|
3813
|
+
/*
|
|
3814
|
+
* Make 'critical_flags' hold all file flags that can't be
|
|
3815
|
+
* immediately restored. For example, on BSD systems,
|
|
3816
|
+
* SF_IMMUTABLE prevents hardlinks from being created, so
|
|
3817
|
+
* should not be set until after any hardlinks are created. To
|
|
3818
|
+
* preserve some semblance of portability, this uses #ifdef
|
|
3819
|
+
* extensively. Ugly, but it works.
|
|
3820
|
+
*
|
|
3821
|
+
* Yes, Virginia, this does create a security race. It's mitigated
|
|
3822
|
+
* somewhat by the practice of creating dirs 0700 until the extract
|
|
3823
|
+
* is done, but it would be nice if we could do more than that.
|
|
3824
|
+
* People restoring critical file systems should be wary of
|
|
3825
|
+
* other programs that might try to muck with files as they're
|
|
3826
|
+
* being restored.
|
|
3827
|
+
*/
|
|
3828
|
+
const int critical_flags = 0
|
|
3829
|
+
#ifdef SF_IMMUTABLE
|
|
3830
|
+
| SF_IMMUTABLE
|
|
3831
|
+
#endif
|
|
3832
|
+
#ifdef UF_IMMUTABLE
|
|
3833
|
+
| UF_IMMUTABLE
|
|
3834
|
+
#endif
|
|
3835
|
+
#ifdef SF_APPEND
|
|
3836
|
+
| SF_APPEND
|
|
3837
|
+
#endif
|
|
3838
|
+
#ifdef UF_APPEND
|
|
3839
|
+
| UF_APPEND
|
|
3840
|
+
#endif
|
|
3841
|
+
#if defined(FS_APPEND_FL)
|
|
3842
|
+
| FS_APPEND_FL
|
|
3843
|
+
#elif defined(EXT2_APPEND_FL)
|
|
3844
|
+
| EXT2_APPEND_FL
|
|
3845
|
+
#endif
|
|
3846
|
+
#if defined(FS_IMMUTABLE_FL)
|
|
3847
|
+
| FS_IMMUTABLE_FL
|
|
3848
|
+
#elif defined(EXT2_IMMUTABLE_FL)
|
|
3849
|
+
| EXT2_IMMUTABLE_FL
|
|
3850
|
+
#endif
|
|
3851
|
+
#ifdef FS_JOURNAL_DATA_FL
|
|
3852
|
+
| FS_JOURNAL_DATA_FL
|
|
3853
|
+
#endif
|
|
3854
|
+
;
|
|
3855
|
+
|
|
3856
|
+
if (a->todo & TODO_FFLAGS) {
|
|
3857
|
+
archive_entry_fflags(a->entry, &set, &clear);
|
|
3858
|
+
|
|
3859
|
+
/*
|
|
3860
|
+
* The first test encourages the compiler to eliminate
|
|
3861
|
+
* all of this if it's not necessary.
|
|
3862
|
+
*/
|
|
3863
|
+
if ((critical_flags != 0) && (set & critical_flags)) {
|
|
3864
|
+
le = current_fixup(a, a->name);
|
|
3865
|
+
if (le == NULL)
|
|
3866
|
+
return (ARCHIVE_FATAL);
|
|
3867
|
+
le->filetype = archive_entry_filetype(a->entry);
|
|
3868
|
+
le->fixup |= TODO_FFLAGS;
|
|
3869
|
+
le->fflags_set = set;
|
|
3870
|
+
/* Store the mode if it's not already there. */
|
|
3871
|
+
if ((le->fixup & TODO_MODE) == 0)
|
|
3872
|
+
le->mode = mode;
|
|
3873
|
+
} else {
|
|
3874
|
+
r = set_fflags_platform(a, a->fd,
|
|
3875
|
+
a->name, mode, set, clear);
|
|
3876
|
+
if (r != ARCHIVE_OK)
|
|
3877
|
+
return (r);
|
|
3878
|
+
}
|
|
3879
|
+
}
|
|
3880
|
+
return (ARCHIVE_OK);
|
|
3881
|
+
}
|
|
3882
|
+
|
|
3883
|
+
static int
|
|
3884
|
+
clear_nochange_fflags(struct archive_write_disk *a)
|
|
3885
|
+
{
|
|
3886
|
+
mode_t mode = archive_entry_mode(a->entry);
|
|
3887
|
+
const int nochange_flags = 0
|
|
3888
|
+
#ifdef SF_IMMUTABLE
|
|
3889
|
+
| SF_IMMUTABLE
|
|
3890
|
+
#endif
|
|
3891
|
+
#ifdef UF_IMMUTABLE
|
|
3892
|
+
| UF_IMMUTABLE
|
|
3893
|
+
#endif
|
|
3894
|
+
#ifdef SF_APPEND
|
|
3895
|
+
| SF_APPEND
|
|
3896
|
+
#endif
|
|
3897
|
+
#ifdef UF_APPEND
|
|
3898
|
+
| UF_APPEND
|
|
3899
|
+
#endif
|
|
3900
|
+
#ifdef EXT2_APPEND_FL
|
|
3901
|
+
| EXT2_APPEND_FL
|
|
3902
|
+
#endif
|
|
3903
|
+
#ifdef EXT2_IMMUTABLE_FL
|
|
3904
|
+
| EXT2_IMMUTABLE_FL
|
|
3905
|
+
#endif
|
|
3906
|
+
;
|
|
3907
|
+
|
|
3908
|
+
return (set_fflags_platform(a, a->fd, a->name, mode, 0,
|
|
3909
|
+
nochange_flags));
|
|
3910
|
+
}
|
|
3911
|
+
|
|
3912
|
+
|
|
3913
|
+
#if ( defined(HAVE_LCHFLAGS) || defined(HAVE_CHFLAGS) || defined(HAVE_FCHFLAGS) ) && defined(HAVE_STRUCT_STAT_ST_FLAGS)
|
|
3914
|
+
/*
|
|
3915
|
+
* BSD reads flags using stat() and sets them with one of {f,l,}chflags()
|
|
3916
|
+
*/
|
|
3917
|
+
static int
|
|
3918
|
+
set_fflags_platform(struct archive_write_disk *a, int fd, const char *name,
|
|
3919
|
+
mode_t mode, unsigned long set, unsigned long clear)
|
|
3920
|
+
{
|
|
3921
|
+
int r;
|
|
3922
|
+
const int sf_mask = 0
|
|
3923
|
+
#ifdef SF_APPEND
|
|
3924
|
+
| SF_APPEND
|
|
3925
|
+
#endif
|
|
3926
|
+
#ifdef SF_ARCHIVED
|
|
3927
|
+
| SF_ARCHIVED
|
|
3928
|
+
#endif
|
|
3929
|
+
#ifdef SF_IMMUTABLE
|
|
3930
|
+
| SF_IMMUTABLE
|
|
3931
|
+
#endif
|
|
3932
|
+
#ifdef SF_NOUNLINK
|
|
3933
|
+
| SF_NOUNLINK
|
|
3934
|
+
#endif
|
|
3935
|
+
;
|
|
3936
|
+
(void)mode; /* UNUSED */
|
|
3937
|
+
|
|
3938
|
+
if (set == 0 && clear == 0)
|
|
3939
|
+
return (ARCHIVE_OK);
|
|
3940
|
+
|
|
3941
|
+
/*
|
|
3942
|
+
* XXX Is the stat here really necessary? Or can I just use
|
|
3943
|
+
* the 'set' flags directly? In particular, I'm not sure
|
|
3944
|
+
* about the correct approach if we're overwriting an existing
|
|
3945
|
+
* file that already has flags on it. XXX
|
|
3946
|
+
*/
|
|
3947
|
+
if ((r = lazy_stat(a)) != ARCHIVE_OK)
|
|
3948
|
+
return (r);
|
|
3949
|
+
|
|
3950
|
+
a->st.st_flags &= ~clear;
|
|
3951
|
+
a->st.st_flags |= set;
|
|
3952
|
+
|
|
3953
|
+
/* Only super-user may change SF_* flags */
|
|
3954
|
+
|
|
3955
|
+
if (a->user_uid != 0)
|
|
3956
|
+
a->st.st_flags &= ~sf_mask;
|
|
3957
|
+
|
|
3958
|
+
#ifdef HAVE_FCHFLAGS
|
|
3959
|
+
/* If platform has fchflags() and we were given an fd, use it. */
|
|
3960
|
+
if (fd >= 0 && fchflags(fd, a->st.st_flags) == 0)
|
|
3961
|
+
return (ARCHIVE_OK);
|
|
3962
|
+
#endif
|
|
3963
|
+
/*
|
|
3964
|
+
* If we can't use the fd to set the flags, we'll use the
|
|
3965
|
+
* pathname to set flags. We prefer lchflags() but will use
|
|
3966
|
+
* chflags() if we must.
|
|
3967
|
+
*/
|
|
3968
|
+
#ifdef HAVE_LCHFLAGS
|
|
3969
|
+
if (lchflags(name, a->st.st_flags) == 0)
|
|
3970
|
+
return (ARCHIVE_OK);
|
|
3971
|
+
#elif defined(HAVE_CHFLAGS)
|
|
3972
|
+
if (S_ISLNK(a->st.st_mode)) {
|
|
3973
|
+
archive_set_error(&a->archive, errno,
|
|
3974
|
+
"Can't set file flags on symlink.");
|
|
3975
|
+
return (ARCHIVE_WARN);
|
|
3976
|
+
}
|
|
3977
|
+
if (chflags(name, a->st.st_flags) == 0)
|
|
3978
|
+
return (ARCHIVE_OK);
|
|
3979
|
+
#endif
|
|
3980
|
+
archive_set_error(&a->archive, errno,
|
|
3981
|
+
"Failed to set file flags");
|
|
3982
|
+
return (ARCHIVE_WARN);
|
|
3983
|
+
}
|
|
3984
|
+
|
|
3985
|
+
#elif (defined(FS_IOC_GETFLAGS) && defined(FS_IOC_SETFLAGS) && \
|
|
3986
|
+
defined(HAVE_WORKING_FS_IOC_GETFLAGS)) || \
|
|
3987
|
+
(defined(EXT2_IOC_GETFLAGS) && defined(EXT2_IOC_SETFLAGS) && \
|
|
3988
|
+
defined(HAVE_WORKING_EXT2_IOC_GETFLAGS))
|
|
3989
|
+
/*
|
|
3990
|
+
* Linux uses ioctl() to read and write file flags.
|
|
3991
|
+
*/
|
|
3992
|
+
static int
|
|
3993
|
+
set_fflags_platform(struct archive_write_disk *a, int fd, const char *name,
|
|
3994
|
+
mode_t mode, unsigned long set, unsigned long clear)
|
|
3995
|
+
{
|
|
3996
|
+
int ret;
|
|
3997
|
+
int myfd = fd;
|
|
3998
|
+
int newflags, oldflags;
|
|
3999
|
+
/*
|
|
4000
|
+
* Linux has no define for the flags that are only settable by
|
|
4001
|
+
* the root user. This code may seem a little complex, but
|
|
4002
|
+
* there seem to be some Linux systems that lack these
|
|
4003
|
+
* defines. (?) The code below degrades reasonably gracefully
|
|
4004
|
+
* if sf_mask is incomplete.
|
|
4005
|
+
*/
|
|
4006
|
+
const int sf_mask = 0
|
|
4007
|
+
#if defined(FS_IMMUTABLE_FL)
|
|
4008
|
+
| FS_IMMUTABLE_FL
|
|
4009
|
+
#elif defined(EXT2_IMMUTABLE_FL)
|
|
4010
|
+
| EXT2_IMMUTABLE_FL
|
|
4011
|
+
#endif
|
|
4012
|
+
#if defined(FS_APPEND_FL)
|
|
4013
|
+
| FS_APPEND_FL
|
|
4014
|
+
#elif defined(EXT2_APPEND_FL)
|
|
4015
|
+
| EXT2_APPEND_FL
|
|
4016
|
+
#endif
|
|
4017
|
+
#if defined(FS_JOURNAL_DATA_FL)
|
|
4018
|
+
| FS_JOURNAL_DATA_FL
|
|
4019
|
+
#endif
|
|
4020
|
+
;
|
|
4021
|
+
|
|
4022
|
+
if (set == 0 && clear == 0)
|
|
4023
|
+
return (ARCHIVE_OK);
|
|
4024
|
+
/* Only regular files and dirs can have flags. */
|
|
4025
|
+
if (!S_ISREG(mode) && !S_ISDIR(mode))
|
|
4026
|
+
return (ARCHIVE_OK);
|
|
4027
|
+
|
|
4028
|
+
/* If we weren't given an fd, open it ourselves. */
|
|
4029
|
+
if (myfd < 0) {
|
|
4030
|
+
myfd = open(name, O_RDONLY | O_NONBLOCK | O_BINARY |
|
|
4031
|
+
O_CLOEXEC | O_NOFOLLOW);
|
|
4032
|
+
__archive_ensure_cloexec_flag(myfd);
|
|
4033
|
+
}
|
|
4034
|
+
if (myfd < 0)
|
|
4035
|
+
return (ARCHIVE_OK);
|
|
4036
|
+
|
|
4037
|
+
/*
|
|
4038
|
+
* XXX As above, this would be way simpler if we didn't have
|
|
4039
|
+
* to read the current flags from disk. XXX
|
|
4040
|
+
*/
|
|
4041
|
+
ret = ARCHIVE_OK;
|
|
4042
|
+
|
|
4043
|
+
/* Read the current file flags. */
|
|
4044
|
+
if (ioctl(myfd,
|
|
4045
|
+
#ifdef FS_IOC_GETFLAGS
|
|
4046
|
+
FS_IOC_GETFLAGS,
|
|
4047
|
+
#else
|
|
4048
|
+
EXT2_IOC_GETFLAGS,
|
|
4049
|
+
#endif
|
|
4050
|
+
&oldflags) < 0)
|
|
4051
|
+
goto fail;
|
|
4052
|
+
|
|
4053
|
+
/* Try setting the flags as given. */
|
|
4054
|
+
newflags = (oldflags & ~clear) | set;
|
|
4055
|
+
if (ioctl(myfd,
|
|
4056
|
+
#ifdef FS_IOC_SETFLAGS
|
|
4057
|
+
FS_IOC_SETFLAGS,
|
|
4058
|
+
#else
|
|
4059
|
+
EXT2_IOC_SETFLAGS,
|
|
4060
|
+
#endif
|
|
4061
|
+
&newflags) >= 0)
|
|
4062
|
+
goto cleanup;
|
|
4063
|
+
if (errno != EPERM)
|
|
4064
|
+
goto fail;
|
|
4065
|
+
|
|
4066
|
+
/* If we couldn't set all the flags, try again with a subset. */
|
|
4067
|
+
newflags &= ~sf_mask;
|
|
4068
|
+
oldflags &= sf_mask;
|
|
4069
|
+
newflags |= oldflags;
|
|
4070
|
+
if (ioctl(myfd,
|
|
4071
|
+
#ifdef FS_IOC_SETFLAGS
|
|
4072
|
+
FS_IOC_SETFLAGS,
|
|
4073
|
+
#else
|
|
4074
|
+
EXT2_IOC_SETFLAGS,
|
|
4075
|
+
#endif
|
|
4076
|
+
&newflags) >= 0)
|
|
4077
|
+
goto cleanup;
|
|
4078
|
+
|
|
4079
|
+
/* We couldn't set the flags, so report the failure. */
|
|
4080
|
+
fail:
|
|
4081
|
+
archive_set_error(&a->archive, errno,
|
|
4082
|
+
"Failed to set file flags");
|
|
4083
|
+
ret = ARCHIVE_WARN;
|
|
4084
|
+
cleanup:
|
|
4085
|
+
if (fd < 0)
|
|
4086
|
+
close(myfd);
|
|
4087
|
+
return (ret);
|
|
4088
|
+
}
|
|
4089
|
+
|
|
4090
|
+
#else
|
|
4091
|
+
|
|
4092
|
+
/*
|
|
4093
|
+
* Of course, some systems have neither BSD chflags() nor Linux' flags
|
|
4094
|
+
* support through ioctl().
|
|
4095
|
+
*/
|
|
4096
|
+
static int
|
|
4097
|
+
set_fflags_platform(struct archive_write_disk *a, int fd, const char *name,
|
|
4098
|
+
mode_t mode, unsigned long set, unsigned long clear)
|
|
4099
|
+
{
|
|
4100
|
+
(void)a; /* UNUSED */
|
|
4101
|
+
(void)fd; /* UNUSED */
|
|
4102
|
+
(void)name; /* UNUSED */
|
|
4103
|
+
(void)mode; /* UNUSED */
|
|
4104
|
+
(void)set; /* UNUSED */
|
|
4105
|
+
(void)clear; /* UNUSED */
|
|
4106
|
+
return (ARCHIVE_OK);
|
|
4107
|
+
}
|
|
4108
|
+
|
|
4109
|
+
#endif /* __linux */
|
|
4110
|
+
|
|
4111
|
+
#ifndef HAVE_COPYFILE_H
|
|
4112
|
+
/* Default is to simply drop Mac extended metadata. */
|
|
4113
|
+
static int
|
|
4114
|
+
set_mac_metadata(struct archive_write_disk *a, const char *pathname,
|
|
4115
|
+
const void *metadata, size_t metadata_size)
|
|
4116
|
+
{
|
|
4117
|
+
(void)a; /* UNUSED */
|
|
4118
|
+
(void)pathname; /* UNUSED */
|
|
4119
|
+
(void)metadata; /* UNUSED */
|
|
4120
|
+
(void)metadata_size; /* UNUSED */
|
|
4121
|
+
return (ARCHIVE_OK);
|
|
4122
|
+
}
|
|
4123
|
+
|
|
4124
|
+
static int
|
|
4125
|
+
fixup_appledouble(struct archive_write_disk *a, const char *pathname)
|
|
4126
|
+
{
|
|
4127
|
+
(void)a; /* UNUSED */
|
|
4128
|
+
(void)pathname; /* UNUSED */
|
|
4129
|
+
return (ARCHIVE_OK);
|
|
4130
|
+
}
|
|
4131
|
+
#else
|
|
4132
|
+
|
|
4133
|
+
/*
|
|
4134
|
+
* On Mac OS, we use copyfile() to unpack the metadata and
|
|
4135
|
+
* apply it to the target file.
|
|
4136
|
+
*/
|
|
4137
|
+
|
|
4138
|
+
#if defined(HAVE_SYS_XATTR_H)
|
|
4139
|
+
static int
|
|
4140
|
+
copy_xattrs(struct archive_write_disk *a, int tmpfd, int dffd)
|
|
4141
|
+
{
|
|
4142
|
+
ssize_t xattr_size;
|
|
4143
|
+
char *xattr_names = NULL, *xattr_val = NULL;
|
|
4144
|
+
int ret = ARCHIVE_OK, xattr_i;
|
|
4145
|
+
|
|
4146
|
+
xattr_size = flistxattr(tmpfd, NULL, 0, 0);
|
|
4147
|
+
if (xattr_size == -1) {
|
|
4148
|
+
archive_set_error(&a->archive, errno,
|
|
4149
|
+
"Failed to read metadata(xattr)");
|
|
4150
|
+
ret = ARCHIVE_WARN;
|
|
4151
|
+
goto exit_xattr;
|
|
4152
|
+
}
|
|
4153
|
+
xattr_names = malloc(xattr_size);
|
|
4154
|
+
if (xattr_names == NULL) {
|
|
4155
|
+
archive_set_error(&a->archive, ENOMEM,
|
|
4156
|
+
"Can't allocate memory for metadata(xattr)");
|
|
4157
|
+
ret = ARCHIVE_FATAL;
|
|
4158
|
+
goto exit_xattr;
|
|
4159
|
+
}
|
|
4160
|
+
xattr_size = flistxattr(tmpfd, xattr_names, xattr_size, 0);
|
|
4161
|
+
if (xattr_size == -1) {
|
|
4162
|
+
archive_set_error(&a->archive, errno,
|
|
4163
|
+
"Failed to read metadata(xattr)");
|
|
4164
|
+
ret = ARCHIVE_WARN;
|
|
4165
|
+
goto exit_xattr;
|
|
4166
|
+
}
|
|
4167
|
+
for (xattr_i = 0; xattr_i < xattr_size;
|
|
4168
|
+
xattr_i += strlen(xattr_names + xattr_i) + 1) {
|
|
4169
|
+
char *xattr_val_saved;
|
|
4170
|
+
ssize_t s;
|
|
4171
|
+
int f;
|
|
4172
|
+
|
|
4173
|
+
s = fgetxattr(tmpfd, xattr_names + xattr_i, NULL, 0, 0, 0);
|
|
4174
|
+
if (s == -1) {
|
|
4175
|
+
archive_set_error(&a->archive, errno,
|
|
4176
|
+
"Failed to get metadata(xattr)");
|
|
4177
|
+
ret = ARCHIVE_WARN;
|
|
4178
|
+
goto exit_xattr;
|
|
4179
|
+
}
|
|
4180
|
+
xattr_val_saved = xattr_val;
|
|
4181
|
+
xattr_val = realloc(xattr_val, s);
|
|
4182
|
+
if (xattr_val == NULL) {
|
|
4183
|
+
archive_set_error(&a->archive, ENOMEM,
|
|
4184
|
+
"Failed to get metadata(xattr)");
|
|
4185
|
+
ret = ARCHIVE_WARN;
|
|
4186
|
+
free(xattr_val_saved);
|
|
4187
|
+
goto exit_xattr;
|
|
4188
|
+
}
|
|
4189
|
+
s = fgetxattr(tmpfd, xattr_names + xattr_i, xattr_val, s, 0, 0);
|
|
4190
|
+
if (s == -1) {
|
|
4191
|
+
archive_set_error(&a->archive, errno,
|
|
4192
|
+
"Failed to get metadata(xattr)");
|
|
4193
|
+
ret = ARCHIVE_WARN;
|
|
4194
|
+
goto exit_xattr;
|
|
4195
|
+
}
|
|
4196
|
+
f = fsetxattr(dffd, xattr_names + xattr_i, xattr_val, s, 0, 0);
|
|
4197
|
+
if (f == -1) {
|
|
4198
|
+
archive_set_error(&a->archive, errno,
|
|
4199
|
+
"Failed to get metadata(xattr)");
|
|
4200
|
+
ret = ARCHIVE_WARN;
|
|
4201
|
+
goto exit_xattr;
|
|
4202
|
+
}
|
|
4203
|
+
}
|
|
4204
|
+
exit_xattr:
|
|
4205
|
+
free(xattr_names);
|
|
4206
|
+
free(xattr_val);
|
|
4207
|
+
return (ret);
|
|
4208
|
+
}
|
|
4209
|
+
#endif
|
|
4210
|
+
|
|
4211
|
+
static int
|
|
4212
|
+
copy_acls(struct archive_write_disk *a, int tmpfd, int dffd)
|
|
4213
|
+
{
|
|
4214
|
+
#ifndef HAVE_SYS_ACL_H
|
|
4215
|
+
return 0;
|
|
4216
|
+
#else
|
|
4217
|
+
acl_t acl, dfacl = NULL;
|
|
4218
|
+
int acl_r, ret = ARCHIVE_OK;
|
|
4219
|
+
|
|
4220
|
+
acl = acl_get_fd(tmpfd);
|
|
4221
|
+
if (acl == NULL) {
|
|
4222
|
+
if (errno == ENOENT)
|
|
4223
|
+
/* There are not any ACLs. */
|
|
4224
|
+
return (ret);
|
|
4225
|
+
archive_set_error(&a->archive, errno,
|
|
4226
|
+
"Failed to get metadata(acl)");
|
|
4227
|
+
ret = ARCHIVE_WARN;
|
|
4228
|
+
goto exit_acl;
|
|
4229
|
+
}
|
|
4230
|
+
dfacl = acl_dup(acl);
|
|
4231
|
+
acl_r = acl_set_fd(dffd, dfacl);
|
|
4232
|
+
if (acl_r == -1) {
|
|
4233
|
+
archive_set_error(&a->archive, errno,
|
|
4234
|
+
"Failed to get metadata(acl)");
|
|
4235
|
+
ret = ARCHIVE_WARN;
|
|
4236
|
+
goto exit_acl;
|
|
4237
|
+
}
|
|
4238
|
+
exit_acl:
|
|
4239
|
+
if (acl)
|
|
4240
|
+
acl_free(acl);
|
|
4241
|
+
if (dfacl)
|
|
4242
|
+
acl_free(dfacl);
|
|
4243
|
+
return (ret);
|
|
4244
|
+
#endif
|
|
4245
|
+
}
|
|
4246
|
+
|
|
4247
|
+
static int
|
|
4248
|
+
create_tempdatafork(struct archive_write_disk *a, const char *pathname)
|
|
4249
|
+
{
|
|
4250
|
+
struct archive_string tmpdatafork;
|
|
4251
|
+
int tmpfd;
|
|
4252
|
+
|
|
4253
|
+
archive_string_init(&tmpdatafork);
|
|
4254
|
+
archive_strcpy(&tmpdatafork, "tar.md.XXXXXX");
|
|
4255
|
+
tmpfd = mkstemp(tmpdatafork.s);
|
|
4256
|
+
if (tmpfd < 0) {
|
|
4257
|
+
archive_set_error(&a->archive, errno,
|
|
4258
|
+
"Failed to mkstemp");
|
|
4259
|
+
archive_string_free(&tmpdatafork);
|
|
4260
|
+
return (-1);
|
|
4261
|
+
}
|
|
4262
|
+
if (copyfile(pathname, tmpdatafork.s, 0,
|
|
4263
|
+
COPYFILE_UNPACK | COPYFILE_NOFOLLOW
|
|
4264
|
+
| COPYFILE_ACL | COPYFILE_XATTR) < 0) {
|
|
4265
|
+
archive_set_error(&a->archive, errno,
|
|
4266
|
+
"Failed to restore metadata");
|
|
4267
|
+
close(tmpfd);
|
|
4268
|
+
tmpfd = -1;
|
|
4269
|
+
}
|
|
4270
|
+
unlink(tmpdatafork.s);
|
|
4271
|
+
archive_string_free(&tmpdatafork);
|
|
4272
|
+
return (tmpfd);
|
|
4273
|
+
}
|
|
4274
|
+
|
|
4275
|
+
static int
|
|
4276
|
+
copy_metadata(struct archive_write_disk *a, const char *metadata,
|
|
4277
|
+
const char *datafork, int datafork_compressed)
|
|
4278
|
+
{
|
|
4279
|
+
int ret = ARCHIVE_OK;
|
|
4280
|
+
|
|
4281
|
+
if (datafork_compressed) {
|
|
4282
|
+
int dffd, tmpfd;
|
|
4283
|
+
|
|
4284
|
+
tmpfd = create_tempdatafork(a, metadata);
|
|
4285
|
+
if (tmpfd == -1)
|
|
4286
|
+
return (ARCHIVE_WARN);
|
|
4287
|
+
|
|
4288
|
+
/*
|
|
4289
|
+
* Do not open the data fork compressed by HFS+ compression
|
|
4290
|
+
* with at least a writing mode(O_RDWR or O_WRONLY). it
|
|
4291
|
+
* makes the data fork uncompressed.
|
|
4292
|
+
*/
|
|
4293
|
+
dffd = open(datafork, 0);
|
|
4294
|
+
if (dffd == -1) {
|
|
4295
|
+
archive_set_error(&a->archive, errno,
|
|
4296
|
+
"Failed to open the data fork for metadata");
|
|
4297
|
+
close(tmpfd);
|
|
4298
|
+
return (ARCHIVE_WARN);
|
|
4299
|
+
}
|
|
4300
|
+
|
|
4301
|
+
#if defined(HAVE_SYS_XATTR_H)
|
|
4302
|
+
ret = copy_xattrs(a, tmpfd, dffd);
|
|
4303
|
+
if (ret == ARCHIVE_OK)
|
|
4304
|
+
#endif
|
|
4305
|
+
ret = copy_acls(a, tmpfd, dffd);
|
|
4306
|
+
close(tmpfd);
|
|
4307
|
+
close(dffd);
|
|
4308
|
+
} else {
|
|
4309
|
+
if (copyfile(metadata, datafork, 0,
|
|
4310
|
+
COPYFILE_UNPACK | COPYFILE_NOFOLLOW
|
|
4311
|
+
| COPYFILE_ACL | COPYFILE_XATTR) < 0) {
|
|
4312
|
+
archive_set_error(&a->archive, errno,
|
|
4313
|
+
"Failed to restore metadata");
|
|
4314
|
+
ret = ARCHIVE_WARN;
|
|
4315
|
+
}
|
|
4316
|
+
}
|
|
4317
|
+
return (ret);
|
|
4318
|
+
}
|
|
4319
|
+
|
|
4320
|
+
static int
|
|
4321
|
+
set_mac_metadata(struct archive_write_disk *a, const char *pathname,
|
|
4322
|
+
const void *metadata, size_t metadata_size)
|
|
4323
|
+
{
|
|
4324
|
+
struct archive_string tmp;
|
|
4325
|
+
ssize_t written;
|
|
4326
|
+
int fd;
|
|
4327
|
+
int ret = ARCHIVE_OK;
|
|
4328
|
+
|
|
4329
|
+
/* This would be simpler if copyfile() could just accept the
|
|
4330
|
+
* metadata as a block of memory; then we could sidestep this
|
|
4331
|
+
* silly dance of writing the data to disk just so that
|
|
4332
|
+
* copyfile() can read it back in again. */
|
|
4333
|
+
archive_string_init(&tmp);
|
|
4334
|
+
archive_strcpy(&tmp, pathname);
|
|
4335
|
+
archive_strcat(&tmp, ".XXXXXX");
|
|
4336
|
+
fd = mkstemp(tmp.s);
|
|
4337
|
+
|
|
4338
|
+
if (fd < 0) {
|
|
4339
|
+
archive_set_error(&a->archive, errno,
|
|
4340
|
+
"Failed to restore metadata");
|
|
4341
|
+
archive_string_free(&tmp);
|
|
4342
|
+
return (ARCHIVE_WARN);
|
|
4343
|
+
}
|
|
4344
|
+
written = write(fd, metadata, metadata_size);
|
|
4345
|
+
close(fd);
|
|
4346
|
+
if ((size_t)written != metadata_size) {
|
|
4347
|
+
archive_set_error(&a->archive, errno,
|
|
4348
|
+
"Failed to restore metadata");
|
|
4349
|
+
ret = ARCHIVE_WARN;
|
|
4350
|
+
} else {
|
|
4351
|
+
int compressed;
|
|
4352
|
+
|
|
4353
|
+
#if defined(UF_COMPRESSED)
|
|
4354
|
+
if ((a->todo & TODO_HFS_COMPRESSION) != 0 &&
|
|
4355
|
+
(ret = lazy_stat(a)) == ARCHIVE_OK)
|
|
4356
|
+
compressed = a->st.st_flags & UF_COMPRESSED;
|
|
4357
|
+
else
|
|
4358
|
+
#endif
|
|
4359
|
+
compressed = 0;
|
|
4360
|
+
ret = copy_metadata(a, tmp.s, pathname, compressed);
|
|
4361
|
+
}
|
|
4362
|
+
unlink(tmp.s);
|
|
4363
|
+
archive_string_free(&tmp);
|
|
4364
|
+
return (ret);
|
|
4365
|
+
}
|
|
4366
|
+
|
|
4367
|
+
static int
|
|
4368
|
+
fixup_appledouble(struct archive_write_disk *a, const char *pathname)
|
|
4369
|
+
{
|
|
4370
|
+
char buff[8];
|
|
4371
|
+
struct stat st;
|
|
4372
|
+
const char *p;
|
|
4373
|
+
struct archive_string datafork;
|
|
4374
|
+
int fd = -1, ret = ARCHIVE_OK;
|
|
4375
|
+
|
|
4376
|
+
archive_string_init(&datafork);
|
|
4377
|
+
/* Check if the current file name is a type of the resource
|
|
4378
|
+
* fork file. */
|
|
4379
|
+
p = strrchr(pathname, '/');
|
|
4380
|
+
if (p == NULL)
|
|
4381
|
+
p = pathname;
|
|
4382
|
+
else
|
|
4383
|
+
p++;
|
|
4384
|
+
if (p[0] != '.' || p[1] != '_')
|
|
4385
|
+
goto skip_appledouble;
|
|
4386
|
+
|
|
4387
|
+
/*
|
|
4388
|
+
* Check if the data fork file exists.
|
|
4389
|
+
*
|
|
4390
|
+
* TODO: Check if this write disk object has handled it.
|
|
4391
|
+
*/
|
|
4392
|
+
archive_strncpy(&datafork, pathname, p - pathname);
|
|
4393
|
+
archive_strcat(&datafork, p + 2);
|
|
4394
|
+
if (lstat(datafork.s, &st) == -1 ||
|
|
4395
|
+
(st.st_mode & AE_IFMT) != AE_IFREG)
|
|
4396
|
+
goto skip_appledouble;
|
|
4397
|
+
|
|
4398
|
+
/*
|
|
4399
|
+
* Check if the file is in the AppleDouble form.
|
|
4400
|
+
*/
|
|
4401
|
+
fd = open(pathname, O_RDONLY | O_BINARY | O_CLOEXEC);
|
|
4402
|
+
__archive_ensure_cloexec_flag(fd);
|
|
4403
|
+
if (fd == -1) {
|
|
4404
|
+
archive_set_error(&a->archive, errno,
|
|
4405
|
+
"Failed to open a restoring file");
|
|
4406
|
+
ret = ARCHIVE_WARN;
|
|
4407
|
+
goto skip_appledouble;
|
|
4408
|
+
}
|
|
4409
|
+
if (read(fd, buff, 8) == -1) {
|
|
4410
|
+
archive_set_error(&a->archive, errno,
|
|
4411
|
+
"Failed to read a restoring file");
|
|
4412
|
+
close(fd);
|
|
4413
|
+
ret = ARCHIVE_WARN;
|
|
4414
|
+
goto skip_appledouble;
|
|
4415
|
+
}
|
|
4416
|
+
close(fd);
|
|
4417
|
+
/* Check AppleDouble Magic Code. */
|
|
4418
|
+
if (archive_be32dec(buff) != 0x00051607)
|
|
4419
|
+
goto skip_appledouble;
|
|
4420
|
+
/* Check AppleDouble Version. */
|
|
4421
|
+
if (archive_be32dec(buff+4) != 0x00020000)
|
|
4422
|
+
goto skip_appledouble;
|
|
4423
|
+
|
|
4424
|
+
ret = copy_metadata(a, pathname, datafork.s,
|
|
4425
|
+
#if defined(UF_COMPRESSED)
|
|
4426
|
+
st.st_flags & UF_COMPRESSED);
|
|
4427
|
+
#else
|
|
4428
|
+
0);
|
|
4429
|
+
#endif
|
|
4430
|
+
if (ret == ARCHIVE_OK) {
|
|
4431
|
+
unlink(pathname);
|
|
4432
|
+
ret = ARCHIVE_EOF;
|
|
4433
|
+
}
|
|
4434
|
+
skip_appledouble:
|
|
4435
|
+
archive_string_free(&datafork);
|
|
4436
|
+
return (ret);
|
|
4437
|
+
}
|
|
4438
|
+
#endif
|
|
4439
|
+
|
|
4440
|
+
#if ARCHIVE_XATTR_LINUX || ARCHIVE_XATTR_DARWIN || ARCHIVE_XATTR_AIX
|
|
4441
|
+
/*
|
|
4442
|
+
* Restore extended attributes - Linux, Darwin and AIX implementations:
|
|
4443
|
+
* AIX' ea interface is syntaxwise identical to the Linux xattr interface.
|
|
4444
|
+
*/
|
|
4445
|
+
static int
|
|
4446
|
+
set_xattrs(struct archive_write_disk *a)
|
|
4447
|
+
{
|
|
4448
|
+
struct archive_entry *entry = a->entry;
|
|
4449
|
+
struct archive_string errlist;
|
|
4450
|
+
int ret = ARCHIVE_OK;
|
|
4451
|
+
int i = archive_entry_xattr_reset(entry);
|
|
4452
|
+
short fail = 0;
|
|
4453
|
+
|
|
4454
|
+
archive_string_init(&errlist);
|
|
4455
|
+
|
|
4456
|
+
while (i--) {
|
|
4457
|
+
const char *name;
|
|
4458
|
+
const void *value;
|
|
4459
|
+
size_t size;
|
|
4460
|
+
int e;
|
|
4461
|
+
|
|
4462
|
+
archive_entry_xattr_next(entry, &name, &value, &size);
|
|
4463
|
+
|
|
4464
|
+
if (name == NULL)
|
|
4465
|
+
continue;
|
|
4466
|
+
#if ARCHIVE_XATTR_LINUX
|
|
4467
|
+
/* Linux: quietly skip POSIX.1e ACL extended attributes */
|
|
4468
|
+
if (strncmp(name, "system.", 7) == 0 &&
|
|
4469
|
+
(strcmp(name + 7, "posix_acl_access") == 0 ||
|
|
4470
|
+
strcmp(name + 7, "posix_acl_default") == 0))
|
|
4471
|
+
continue;
|
|
4472
|
+
if (strncmp(name, "trusted.SGI_", 12) == 0 &&
|
|
4473
|
+
(strcmp(name + 12, "ACL_DEFAULT") == 0 ||
|
|
4474
|
+
strcmp(name + 12, "ACL_FILE") == 0))
|
|
4475
|
+
continue;
|
|
4476
|
+
|
|
4477
|
+
/* Linux: xfsroot namespace is obsolete and unsupported */
|
|
4478
|
+
if (strncmp(name, "xfsroot.", 8) == 0) {
|
|
4479
|
+
fail = 1;
|
|
4480
|
+
archive_strcat(&errlist, name);
|
|
4481
|
+
archive_strappend_char(&errlist, ' ');
|
|
4482
|
+
continue;
|
|
4483
|
+
}
|
|
4484
|
+
#endif
|
|
4485
|
+
|
|
4486
|
+
if (a->fd >= 0) {
|
|
4487
|
+
#if ARCHIVE_XATTR_LINUX
|
|
4488
|
+
e = fsetxattr(a->fd, name, value, size, 0);
|
|
4489
|
+
#elif ARCHIVE_XATTR_DARWIN
|
|
4490
|
+
e = fsetxattr(a->fd, name, value, size, 0, 0);
|
|
4491
|
+
#elif ARCHIVE_XATTR_AIX
|
|
4492
|
+
e = fsetea(a->fd, name, value, size, 0);
|
|
4493
|
+
#endif
|
|
4494
|
+
} else {
|
|
4495
|
+
#if ARCHIVE_XATTR_LINUX
|
|
4496
|
+
e = lsetxattr(archive_entry_pathname(entry),
|
|
4497
|
+
name, value, size, 0);
|
|
4498
|
+
#elif ARCHIVE_XATTR_DARWIN
|
|
4499
|
+
e = setxattr(archive_entry_pathname(entry),
|
|
4500
|
+
name, value, size, 0, XATTR_NOFOLLOW);
|
|
4501
|
+
#elif ARCHIVE_XATTR_AIX
|
|
4502
|
+
e = lsetea(archive_entry_pathname(entry),
|
|
4503
|
+
name, value, size, 0);
|
|
4504
|
+
#endif
|
|
4505
|
+
}
|
|
4506
|
+
if (e == -1) {
|
|
4507
|
+
ret = ARCHIVE_WARN;
|
|
4508
|
+
archive_strcat(&errlist, name);
|
|
4509
|
+
archive_strappend_char(&errlist, ' ');
|
|
4510
|
+
if (errno != ENOTSUP && errno != ENOSYS)
|
|
4511
|
+
fail = 1;
|
|
4512
|
+
}
|
|
4513
|
+
}
|
|
4514
|
+
|
|
4515
|
+
if (ret == ARCHIVE_WARN) {
|
|
4516
|
+
if (fail && errlist.length > 0) {
|
|
4517
|
+
errlist.length--;
|
|
4518
|
+
errlist.s[errlist.length] = '\0';
|
|
4519
|
+
archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
|
|
4520
|
+
"Cannot restore extended attributes: %s",
|
|
4521
|
+
errlist.s);
|
|
4522
|
+
} else
|
|
4523
|
+
archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
|
|
4524
|
+
"Cannot restore extended "
|
|
4525
|
+
"attributes on this file system.");
|
|
4526
|
+
}
|
|
4527
|
+
|
|
4528
|
+
archive_string_free(&errlist);
|
|
4529
|
+
return (ret);
|
|
4530
|
+
}
|
|
4531
|
+
#elif ARCHIVE_XATTR_FREEBSD
|
|
4532
|
+
/*
|
|
4533
|
+
* Restore extended attributes - FreeBSD implementation
|
|
4534
|
+
*/
|
|
4535
|
+
static int
|
|
4536
|
+
set_xattrs(struct archive_write_disk *a)
|
|
4537
|
+
{
|
|
4538
|
+
struct archive_entry *entry = a->entry;
|
|
4539
|
+
struct archive_string errlist;
|
|
4540
|
+
int ret = ARCHIVE_OK;
|
|
4541
|
+
int i = archive_entry_xattr_reset(entry);
|
|
4542
|
+
short fail = 0;
|
|
4543
|
+
|
|
4544
|
+
archive_string_init(&errlist);
|
|
4545
|
+
|
|
4546
|
+
while (i--) {
|
|
4547
|
+
const char *name;
|
|
4548
|
+
const void *value;
|
|
4549
|
+
size_t size;
|
|
4550
|
+
archive_entry_xattr_next(entry, &name, &value, &size);
|
|
4551
|
+
if (name != NULL) {
|
|
4552
|
+
int e;
|
|
4553
|
+
int namespace;
|
|
4554
|
+
|
|
4555
|
+
namespace = EXTATTR_NAMESPACE_USER;
|
|
4556
|
+
|
|
4557
|
+
if (strncmp(name, "user.", 5) == 0) {
|
|
4558
|
+
/* "user." attributes go to user namespace */
|
|
4559
|
+
name += 5;
|
|
4560
|
+
namespace = EXTATTR_NAMESPACE_USER;
|
|
4561
|
+
} else if (strncmp(name, "system.", 7) == 0) {
|
|
4562
|
+
name += 7;
|
|
4563
|
+
namespace = EXTATTR_NAMESPACE_SYSTEM;
|
|
4564
|
+
if (!strcmp(name, "nfs4.acl") ||
|
|
4565
|
+
!strcmp(name, "posix1e.acl_access") ||
|
|
4566
|
+
!strcmp(name, "posix1e.acl_default"))
|
|
4567
|
+
continue;
|
|
4568
|
+
} else {
|
|
4569
|
+
/* Other namespaces are unsupported */
|
|
4570
|
+
archive_strcat(&errlist, name);
|
|
4571
|
+
archive_strappend_char(&errlist, ' ');
|
|
4572
|
+
fail = 1;
|
|
4573
|
+
ret = ARCHIVE_WARN;
|
|
4574
|
+
continue;
|
|
4575
|
+
}
|
|
4576
|
+
|
|
4577
|
+
if (a->fd >= 0) {
|
|
4578
|
+
/*
|
|
4579
|
+
* On FreeBSD, extattr_set_fd does not
|
|
4580
|
+
* return the same as
|
|
4581
|
+
* extattr_set_file. It returns zero
|
|
4582
|
+
* on success, non-zero on failure.
|
|
4583
|
+
*
|
|
4584
|
+
* We can detect the failure by
|
|
4585
|
+
* manually setting errno prior to the
|
|
4586
|
+
* call and checking after.
|
|
4587
|
+
*
|
|
4588
|
+
* If errno remains zero, fake the
|
|
4589
|
+
* return value by setting e to size.
|
|
4590
|
+
*
|
|
4591
|
+
* This is a hack for now until I
|
|
4592
|
+
* (Shawn Webb) get FreeBSD to fix the
|
|
4593
|
+
* issue, if that's even possible.
|
|
4594
|
+
*/
|
|
4595
|
+
errno = 0;
|
|
4596
|
+
e = extattr_set_fd(a->fd, namespace, name,
|
|
4597
|
+
value, size);
|
|
4598
|
+
if (e == 0 && errno == 0) {
|
|
4599
|
+
e = size;
|
|
4600
|
+
}
|
|
4601
|
+
} else {
|
|
4602
|
+
e = extattr_set_link(
|
|
4603
|
+
archive_entry_pathname(entry), namespace,
|
|
4604
|
+
name, value, size);
|
|
4605
|
+
}
|
|
4606
|
+
if (e != (int)size) {
|
|
4607
|
+
archive_strcat(&errlist, name);
|
|
4608
|
+
archive_strappend_char(&errlist, ' ');
|
|
4609
|
+
ret = ARCHIVE_WARN;
|
|
4610
|
+
if (errno != ENOTSUP && errno != ENOSYS)
|
|
4611
|
+
fail = 1;
|
|
4612
|
+
}
|
|
4613
|
+
}
|
|
4614
|
+
}
|
|
4615
|
+
|
|
4616
|
+
if (ret == ARCHIVE_WARN) {
|
|
4617
|
+
if (fail && errlist.length > 0) {
|
|
4618
|
+
errlist.length--;
|
|
4619
|
+
errlist.s[errlist.length] = '\0';
|
|
4620
|
+
|
|
4621
|
+
archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
|
|
4622
|
+
"Cannot restore extended attributes: %s",
|
|
4623
|
+
errlist.s);
|
|
4624
|
+
} else
|
|
4625
|
+
archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
|
|
4626
|
+
"Cannot restore extended "
|
|
4627
|
+
"attributes on this file system.");
|
|
4628
|
+
}
|
|
4629
|
+
|
|
4630
|
+
archive_string_free(&errlist);
|
|
4631
|
+
return (ret);
|
|
4632
|
+
}
|
|
4633
|
+
#else
|
|
4634
|
+
/*
|
|
4635
|
+
* Restore extended attributes - stub implementation for unsupported systems
|
|
4636
|
+
*/
|
|
4637
|
+
static int
|
|
4638
|
+
set_xattrs(struct archive_write_disk *a)
|
|
4639
|
+
{
|
|
4640
|
+
static int warning_done = 0;
|
|
4641
|
+
|
|
4642
|
+
/* If there aren't any extended attributes, then it's okay not
|
|
4643
|
+
* to extract them, otherwise, issue a single warning. */
|
|
4644
|
+
if (archive_entry_xattr_count(a->entry) != 0 && !warning_done) {
|
|
4645
|
+
warning_done = 1;
|
|
4646
|
+
archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,
|
|
4647
|
+
"Cannot restore extended attributes on this system");
|
|
4648
|
+
return (ARCHIVE_WARN);
|
|
4649
|
+
}
|
|
4650
|
+
/* Warning was already emitted; suppress further warnings. */
|
|
4651
|
+
return (ARCHIVE_OK);
|
|
4652
|
+
}
|
|
4653
|
+
#endif
|
|
4654
|
+
|
|
4655
|
+
/*
|
|
4656
|
+
* Test if file on disk is older than entry.
|
|
4657
|
+
*/
|
|
4658
|
+
static int
|
|
4659
|
+
older(struct stat *st, struct archive_entry *entry)
|
|
4660
|
+
{
|
|
4661
|
+
/* First, test the seconds and return if we have a definite answer. */
|
|
4662
|
+
/* Definitely older. */
|
|
4663
|
+
if (to_int64_time(st->st_mtime) < to_int64_time(archive_entry_mtime(entry)))
|
|
4664
|
+
return (1);
|
|
4665
|
+
/* Definitely younger. */
|
|
4666
|
+
if (to_int64_time(st->st_mtime) > to_int64_time(archive_entry_mtime(entry)))
|
|
4667
|
+
return (0);
|
|
4668
|
+
/* If this platform supports fractional seconds, try those. */
|
|
4669
|
+
#if HAVE_STRUCT_STAT_ST_MTIMESPEC_TV_NSEC
|
|
4670
|
+
/* Definitely older. */
|
|
4671
|
+
if (st->st_mtimespec.tv_nsec < archive_entry_mtime_nsec(entry))
|
|
4672
|
+
return (1);
|
|
4673
|
+
#elif HAVE_STRUCT_STAT_ST_MTIM_TV_NSEC
|
|
4674
|
+
/* Definitely older. */
|
|
4675
|
+
if (st->st_mtim.tv_nsec < archive_entry_mtime_nsec(entry))
|
|
4676
|
+
return (1);
|
|
4677
|
+
#elif HAVE_STRUCT_STAT_ST_MTIME_N
|
|
4678
|
+
/* older. */
|
|
4679
|
+
if (st->st_mtime_n < archive_entry_mtime_nsec(entry))
|
|
4680
|
+
return (1);
|
|
4681
|
+
#elif HAVE_STRUCT_STAT_ST_UMTIME
|
|
4682
|
+
/* older. */
|
|
4683
|
+
if (st->st_umtime * 1000 < archive_entry_mtime_nsec(entry))
|
|
4684
|
+
return (1);
|
|
4685
|
+
#elif HAVE_STRUCT_STAT_ST_MTIME_USEC
|
|
4686
|
+
/* older. */
|
|
4687
|
+
if (st->st_mtime_usec * 1000 < archive_entry_mtime_nsec(entry))
|
|
4688
|
+
return (1);
|
|
4689
|
+
#else
|
|
4690
|
+
/* This system doesn't have high-res timestamps. */
|
|
4691
|
+
#endif
|
|
4692
|
+
/* Same age or newer, so not older. */
|
|
4693
|
+
return (0);
|
|
4694
|
+
}
|
|
4695
|
+
|
|
4696
|
+
#ifndef ARCHIVE_ACL_SUPPORT
|
|
4697
|
+
int
|
|
4698
|
+
archive_write_disk_set_acls(struct archive *a, int fd, const char *name,
|
|
4699
|
+
struct archive_acl *abstract_acl, __LA_MODE_T mode)
|
|
4700
|
+
{
|
|
4701
|
+
(void)a; /* UNUSED */
|
|
4702
|
+
(void)fd; /* UNUSED */
|
|
4703
|
+
(void)name; /* UNUSED */
|
|
4704
|
+
(void)abstract_acl; /* UNUSED */
|
|
4705
|
+
(void)mode; /* UNUSED */
|
|
4706
|
+
return (ARCHIVE_OK);
|
|
4707
|
+
}
|
|
4708
|
+
#endif
|
|
4709
|
+
|
|
4710
|
+
#endif /* !_WIN32 || __CYGWIN__ */
|
|
4711
|
+
|