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,2842 @@
|
|
|
1
|
+
/*-
|
|
2
|
+
* Copyright (c) 2003-2010 Tim Kientzle
|
|
3
|
+
* Copyright (c) 2011-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_UTIME_H
|
|
37
|
+
#include <sys/utime.h>
|
|
38
|
+
#endif
|
|
39
|
+
#ifdef HAVE_ERRNO_H
|
|
40
|
+
#include <errno.h>
|
|
41
|
+
#endif
|
|
42
|
+
#ifdef HAVE_FCNTL_H
|
|
43
|
+
#include <fcntl.h>
|
|
44
|
+
#endif
|
|
45
|
+
#ifdef HAVE_LIMITS_H
|
|
46
|
+
#include <limits.h>
|
|
47
|
+
#endif
|
|
48
|
+
#ifdef HAVE_STDLIB_H
|
|
49
|
+
#include <stdlib.h>
|
|
50
|
+
#endif
|
|
51
|
+
#include <winioctl.h>
|
|
52
|
+
|
|
53
|
+
/* TODO: Support Mac OS 'quarantine' feature. This is really just a
|
|
54
|
+
* standard tag to mark files that have been downloaded as "tainted".
|
|
55
|
+
* On Mac OS, we should mark the extracted files as tainted if the
|
|
56
|
+
* archive being read was tainted. Windows has a similar feature; we
|
|
57
|
+
* should investigate ways to support this generically. */
|
|
58
|
+
|
|
59
|
+
#include "archive.h"
|
|
60
|
+
#include "archive_acl_private.h"
|
|
61
|
+
#include "archive_string.h"
|
|
62
|
+
#include "archive_entry.h"
|
|
63
|
+
#include "archive_private.h"
|
|
64
|
+
|
|
65
|
+
#ifndef O_BINARY
|
|
66
|
+
#define O_BINARY 0
|
|
67
|
+
#endif
|
|
68
|
+
#ifndef IO_REPARSE_TAG_SYMLINK
|
|
69
|
+
/* Old SDKs do not provide IO_REPARSE_TAG_SYMLINK */
|
|
70
|
+
#define IO_REPARSE_TAG_SYMLINK 0xA000000CL
|
|
71
|
+
#endif
|
|
72
|
+
|
|
73
|
+
static BOOL SetFilePointerEx_perso(HANDLE hFile,
|
|
74
|
+
LARGE_INTEGER liDistanceToMove,
|
|
75
|
+
PLARGE_INTEGER lpNewFilePointer,
|
|
76
|
+
DWORD dwMoveMethod)
|
|
77
|
+
{
|
|
78
|
+
LARGE_INTEGER li;
|
|
79
|
+
li.QuadPart = liDistanceToMove.QuadPart;
|
|
80
|
+
li.LowPart = SetFilePointer(
|
|
81
|
+
hFile, li.LowPart, &li.HighPart, dwMoveMethod);
|
|
82
|
+
if(lpNewFilePointer) {
|
|
83
|
+
lpNewFilePointer->QuadPart = li.QuadPart;
|
|
84
|
+
}
|
|
85
|
+
return li.LowPart != (DWORD)-1 || GetLastError() == NO_ERROR;
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
struct fixup_entry {
|
|
89
|
+
struct fixup_entry *next;
|
|
90
|
+
struct archive_acl acl;
|
|
91
|
+
mode_t mode;
|
|
92
|
+
int64_t atime;
|
|
93
|
+
int64_t birthtime;
|
|
94
|
+
int64_t mtime;
|
|
95
|
+
int64_t ctime;
|
|
96
|
+
unsigned long atime_nanos;
|
|
97
|
+
unsigned long birthtime_nanos;
|
|
98
|
+
unsigned long mtime_nanos;
|
|
99
|
+
unsigned long ctime_nanos;
|
|
100
|
+
unsigned long fflags_set;
|
|
101
|
+
int fixup; /* bitmask of what needs fixing */
|
|
102
|
+
wchar_t *name;
|
|
103
|
+
};
|
|
104
|
+
|
|
105
|
+
/*
|
|
106
|
+
* We use a bitmask to track which operations remain to be done for
|
|
107
|
+
* this file. In particular, this helps us avoid unnecessary
|
|
108
|
+
* operations when it's possible to take care of one step as a
|
|
109
|
+
* side-effect of another. For example, mkdir() can specify the mode
|
|
110
|
+
* for the newly-created object but symlink() cannot. This means we
|
|
111
|
+
* can skip chmod() if mkdir() succeeded, but we must explicitly
|
|
112
|
+
* chmod() if we're trying to create a directory that already exists
|
|
113
|
+
* (mkdir() failed) or if we're restoring a symlink. Similarly, we
|
|
114
|
+
* need to verify UID/GID before trying to restore SUID/SGID bits;
|
|
115
|
+
* that verification can occur explicitly through a stat() call or
|
|
116
|
+
* implicitly because of a successful chown() call.
|
|
117
|
+
*/
|
|
118
|
+
#define TODO_MODE_FORCE 0x40000000
|
|
119
|
+
#define TODO_MODE_BASE 0x20000000
|
|
120
|
+
#define TODO_SUID 0x10000000
|
|
121
|
+
#define TODO_SUID_CHECK 0x08000000
|
|
122
|
+
#define TODO_SGID 0x04000000
|
|
123
|
+
#define TODO_SGID_CHECK 0x02000000
|
|
124
|
+
#define TODO_MODE (TODO_MODE_BASE|TODO_SUID|TODO_SGID)
|
|
125
|
+
#define TODO_TIMES ARCHIVE_EXTRACT_TIME
|
|
126
|
+
#define TODO_OWNER ARCHIVE_EXTRACT_OWNER
|
|
127
|
+
#define TODO_FFLAGS ARCHIVE_EXTRACT_FFLAGS
|
|
128
|
+
#define TODO_ACLS ARCHIVE_EXTRACT_ACL
|
|
129
|
+
#define TODO_XATTR ARCHIVE_EXTRACT_XATTR
|
|
130
|
+
#define TODO_MAC_METADATA ARCHIVE_EXTRACT_MAC_METADATA
|
|
131
|
+
|
|
132
|
+
struct archive_write_disk {
|
|
133
|
+
struct archive archive;
|
|
134
|
+
|
|
135
|
+
mode_t user_umask;
|
|
136
|
+
struct fixup_entry *fixup_list;
|
|
137
|
+
struct fixup_entry *current_fixup;
|
|
138
|
+
int64_t user_uid;
|
|
139
|
+
int skip_file_set;
|
|
140
|
+
int64_t skip_file_dev;
|
|
141
|
+
int64_t skip_file_ino;
|
|
142
|
+
time_t start_time;
|
|
143
|
+
|
|
144
|
+
int64_t (*lookup_gid)(void *private, const char *gname, int64_t gid);
|
|
145
|
+
void (*cleanup_gid)(void *private);
|
|
146
|
+
void *lookup_gid_data;
|
|
147
|
+
int64_t (*lookup_uid)(void *private, const char *uname, int64_t uid);
|
|
148
|
+
void (*cleanup_uid)(void *private);
|
|
149
|
+
void *lookup_uid_data;
|
|
150
|
+
|
|
151
|
+
/*
|
|
152
|
+
* Full path of last file to satisfy symlink checks.
|
|
153
|
+
*/
|
|
154
|
+
struct archive_wstring path_safe;
|
|
155
|
+
|
|
156
|
+
/*
|
|
157
|
+
* Cached stat data from disk for the current entry.
|
|
158
|
+
* If this is valid, pst points to st. Otherwise,
|
|
159
|
+
* pst is null.
|
|
160
|
+
*/
|
|
161
|
+
BY_HANDLE_FILE_INFORMATION st;
|
|
162
|
+
BY_HANDLE_FILE_INFORMATION *pst;
|
|
163
|
+
|
|
164
|
+
/* Information about the object being restored right now. */
|
|
165
|
+
struct archive_entry *entry; /* Entry being extracted. */
|
|
166
|
+
wchar_t *name; /* Name of entry, possibly edited. */
|
|
167
|
+
struct archive_wstring _name_data; /* backing store for 'name' */
|
|
168
|
+
wchar_t *tmpname; /* Temporary name */
|
|
169
|
+
struct archive_wstring _tmpname_data; /* backing store for 'tmpname' */
|
|
170
|
+
/* Tasks remaining for this object. */
|
|
171
|
+
int todo;
|
|
172
|
+
/* Tasks deferred until end-of-archive. */
|
|
173
|
+
int deferred;
|
|
174
|
+
/* Options requested by the client. */
|
|
175
|
+
int flags;
|
|
176
|
+
/* Handle for the file we're restoring. */
|
|
177
|
+
HANDLE fh;
|
|
178
|
+
/* Current offset for writing data to the file. */
|
|
179
|
+
int64_t offset;
|
|
180
|
+
/* Last offset actually written to disk. */
|
|
181
|
+
int64_t fd_offset;
|
|
182
|
+
/* Total bytes actually written to files. */
|
|
183
|
+
int64_t total_bytes_written;
|
|
184
|
+
/* Maximum size of file, -1 if unknown. */
|
|
185
|
+
int64_t filesize;
|
|
186
|
+
/* Dir we were in before this restore; only for deep paths. */
|
|
187
|
+
int restore_pwd;
|
|
188
|
+
/* Mode we should use for this entry; affected by _PERM and umask. */
|
|
189
|
+
mode_t mode;
|
|
190
|
+
/* UID/GID to use in restoring this entry. */
|
|
191
|
+
int64_t uid;
|
|
192
|
+
int64_t gid;
|
|
193
|
+
};
|
|
194
|
+
|
|
195
|
+
/*
|
|
196
|
+
* Default mode for dirs created automatically (will be modified by umask).
|
|
197
|
+
* Note that POSIX specifies 0777 for implicitly-created dirs, "modified
|
|
198
|
+
* by the process' file creation mask."
|
|
199
|
+
*/
|
|
200
|
+
#define DEFAULT_DIR_MODE 0777
|
|
201
|
+
/*
|
|
202
|
+
* Dir modes are restored in two steps: During the extraction, the permissions
|
|
203
|
+
* in the archive are modified to match the following limits. During
|
|
204
|
+
* the post-extract fixup pass, the permissions from the archive are
|
|
205
|
+
* applied.
|
|
206
|
+
*/
|
|
207
|
+
#define MINIMUM_DIR_MODE 0700
|
|
208
|
+
#define MAXIMUM_DIR_MODE 0775
|
|
209
|
+
|
|
210
|
+
static int disk_unlink(const wchar_t *);
|
|
211
|
+
static int disk_rmdir(const wchar_t *);
|
|
212
|
+
static int check_symlinks(struct archive_write_disk *);
|
|
213
|
+
static int create_filesystem_object(struct archive_write_disk *);
|
|
214
|
+
static struct fixup_entry *current_fixup(struct archive_write_disk *,
|
|
215
|
+
const wchar_t *pathname);
|
|
216
|
+
static int cleanup_pathname(struct archive_write_disk *, wchar_t *);
|
|
217
|
+
static int create_dir(struct archive_write_disk *, wchar_t *);
|
|
218
|
+
static int create_parent_dir(struct archive_write_disk *, wchar_t *);
|
|
219
|
+
static int la_chmod(const wchar_t *, mode_t);
|
|
220
|
+
static int la_mktemp(struct archive_write_disk *);
|
|
221
|
+
static int older(BY_HANDLE_FILE_INFORMATION *, struct archive_entry *);
|
|
222
|
+
static int permissive_name_w(struct archive_write_disk *);
|
|
223
|
+
static int restore_entry(struct archive_write_disk *);
|
|
224
|
+
static int set_acls(struct archive_write_disk *, HANDLE h,
|
|
225
|
+
const wchar_t *, struct archive_acl *);
|
|
226
|
+
static int set_xattrs(struct archive_write_disk *);
|
|
227
|
+
static int clear_nochange_fflags(struct archive_write_disk *);
|
|
228
|
+
static int set_fflags(struct archive_write_disk *);
|
|
229
|
+
static int set_fflags_platform(const wchar_t *, unsigned long,
|
|
230
|
+
unsigned long);
|
|
231
|
+
static int set_ownership(struct archive_write_disk *);
|
|
232
|
+
static int set_mode(struct archive_write_disk *, int mode);
|
|
233
|
+
static int set_times(struct archive_write_disk *, HANDLE, int,
|
|
234
|
+
const wchar_t *, time_t, long, time_t, long, time_t,
|
|
235
|
+
long, time_t, long);
|
|
236
|
+
static int set_times_from_entry(struct archive_write_disk *);
|
|
237
|
+
static struct fixup_entry *sort_dir_list(struct fixup_entry *p);
|
|
238
|
+
static ssize_t write_data_block(struct archive_write_disk *,
|
|
239
|
+
const char *, size_t);
|
|
240
|
+
|
|
241
|
+
static int _archive_write_disk_close(struct archive *);
|
|
242
|
+
static int _archive_write_disk_free(struct archive *);
|
|
243
|
+
static int _archive_write_disk_header(struct archive *,
|
|
244
|
+
struct archive_entry *);
|
|
245
|
+
static int64_t _archive_write_disk_filter_bytes(struct archive *, int);
|
|
246
|
+
static int _archive_write_disk_finish_entry(struct archive *);
|
|
247
|
+
static ssize_t _archive_write_disk_data(struct archive *, const void *,
|
|
248
|
+
size_t);
|
|
249
|
+
static ssize_t _archive_write_disk_data_block(struct archive *, const void *,
|
|
250
|
+
size_t, int64_t);
|
|
251
|
+
|
|
252
|
+
#define bhfi_dev(bhfi) ((bhfi)->dwVolumeSerialNumber)
|
|
253
|
+
/* Treat FileIndex as i-node. We should remove a sequence number
|
|
254
|
+
* which is high-16-bits of nFileIndexHigh. */
|
|
255
|
+
#define bhfi_ino(bhfi) \
|
|
256
|
+
((((int64_t)((bhfi)->nFileIndexHigh & 0x0000FFFFUL)) << 32) \
|
|
257
|
+
+ (bhfi)->nFileIndexLow)
|
|
258
|
+
#define bhfi_size(bhfi) \
|
|
259
|
+
((((int64_t)(bhfi)->nFileSizeHigh) << 32) + (bhfi)->nFileSizeLow)
|
|
260
|
+
|
|
261
|
+
static int
|
|
262
|
+
file_information(struct archive_write_disk *a, wchar_t *path,
|
|
263
|
+
BY_HANDLE_FILE_INFORMATION *st, mode_t *mode, int sim_lstat)
|
|
264
|
+
{
|
|
265
|
+
HANDLE h;
|
|
266
|
+
int r;
|
|
267
|
+
DWORD flag = FILE_FLAG_BACKUP_SEMANTICS;
|
|
268
|
+
WIN32_FIND_DATAW findData;
|
|
269
|
+
|
|
270
|
+
if (sim_lstat || mode != NULL) {
|
|
271
|
+
h = FindFirstFileW(path, &findData);
|
|
272
|
+
if (h == INVALID_HANDLE_VALUE &&
|
|
273
|
+
GetLastError() == ERROR_INVALID_NAME) {
|
|
274
|
+
wchar_t *full;
|
|
275
|
+
full = __la_win_permissive_name_w(path);
|
|
276
|
+
h = FindFirstFileW(full, &findData);
|
|
277
|
+
free(full);
|
|
278
|
+
}
|
|
279
|
+
if (h == INVALID_HANDLE_VALUE) {
|
|
280
|
+
la_dosmaperr(GetLastError());
|
|
281
|
+
return (-1);
|
|
282
|
+
}
|
|
283
|
+
FindClose(h);
|
|
284
|
+
}
|
|
285
|
+
|
|
286
|
+
/* Is symlink file ? */
|
|
287
|
+
if (sim_lstat &&
|
|
288
|
+
((findData.dwFileAttributes
|
|
289
|
+
& FILE_ATTRIBUTE_REPARSE_POINT) &&
|
|
290
|
+
(findData.dwReserved0 == IO_REPARSE_TAG_SYMLINK)))
|
|
291
|
+
flag |= FILE_FLAG_OPEN_REPARSE_POINT;
|
|
292
|
+
|
|
293
|
+
h = CreateFileW(a->name, 0, 0, NULL,
|
|
294
|
+
OPEN_EXISTING, flag, NULL);
|
|
295
|
+
if (h == INVALID_HANDLE_VALUE &&
|
|
296
|
+
GetLastError() == ERROR_INVALID_NAME) {
|
|
297
|
+
wchar_t *full;
|
|
298
|
+
full = __la_win_permissive_name_w(path);
|
|
299
|
+
h = CreateFileW(full, 0, 0, NULL,
|
|
300
|
+
OPEN_EXISTING, flag, NULL);
|
|
301
|
+
free(full);
|
|
302
|
+
}
|
|
303
|
+
if (h == INVALID_HANDLE_VALUE) {
|
|
304
|
+
la_dosmaperr(GetLastError());
|
|
305
|
+
return (-1);
|
|
306
|
+
}
|
|
307
|
+
r = GetFileInformationByHandle(h, st);
|
|
308
|
+
CloseHandle(h);
|
|
309
|
+
if (r == 0) {
|
|
310
|
+
la_dosmaperr(GetLastError());
|
|
311
|
+
return (-1);
|
|
312
|
+
}
|
|
313
|
+
|
|
314
|
+
if (mode == NULL)
|
|
315
|
+
return (0);
|
|
316
|
+
|
|
317
|
+
*mode = S_IRUSR | S_IRGRP | S_IROTH;
|
|
318
|
+
if ((st->dwFileAttributes & FILE_ATTRIBUTE_READONLY) == 0)
|
|
319
|
+
*mode |= S_IWUSR | S_IWGRP | S_IWOTH;
|
|
320
|
+
if ((st->dwFileAttributes & FILE_ATTRIBUTE_REPARSE_POINT) &&
|
|
321
|
+
findData.dwReserved0 == IO_REPARSE_TAG_SYMLINK)
|
|
322
|
+
*mode |= S_IFLNK;
|
|
323
|
+
else if (st->dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
|
|
324
|
+
*mode |= S_IFDIR | S_IXUSR | S_IXGRP | S_IXOTH;
|
|
325
|
+
else {
|
|
326
|
+
const wchar_t *p;
|
|
327
|
+
|
|
328
|
+
*mode |= S_IFREG;
|
|
329
|
+
p = wcsrchr(path, L'.');
|
|
330
|
+
if (p != NULL && wcslen(p) == 4) {
|
|
331
|
+
switch (p[1]) {
|
|
332
|
+
case L'B': case L'b':
|
|
333
|
+
if ((p[2] == L'A' || p[2] == L'a' ) &&
|
|
334
|
+
(p[3] == L'T' || p[3] == L't' ))
|
|
335
|
+
*mode |= S_IXUSR | S_IXGRP | S_IXOTH;
|
|
336
|
+
break;
|
|
337
|
+
case L'C': case L'c':
|
|
338
|
+
if (((p[2] == L'M' || p[2] == L'm' ) &&
|
|
339
|
+
(p[3] == L'D' || p[3] == L'd' )))
|
|
340
|
+
*mode |= S_IXUSR | S_IXGRP | S_IXOTH;
|
|
341
|
+
break;
|
|
342
|
+
case L'E': case L'e':
|
|
343
|
+
if ((p[2] == L'X' || p[2] == L'x' ) &&
|
|
344
|
+
(p[3] == L'E' || p[3] == L'e' ))
|
|
345
|
+
*mode |= S_IXUSR | S_IXGRP | S_IXOTH;
|
|
346
|
+
break;
|
|
347
|
+
default:
|
|
348
|
+
break;
|
|
349
|
+
}
|
|
350
|
+
}
|
|
351
|
+
}
|
|
352
|
+
return (0);
|
|
353
|
+
}
|
|
354
|
+
|
|
355
|
+
/*
|
|
356
|
+
* Note: The path, for example, "aa/a/../b../c" will be converted to "aa/c"
|
|
357
|
+
* by GetFullPathNameW() W32 API, which __la_win_permissive_name_w uses.
|
|
358
|
+
* It means we cannot handle multiple dirs in one archive_entry.
|
|
359
|
+
* So we have to make the full-pathname in another way, which does not
|
|
360
|
+
* break "../" path string.
|
|
361
|
+
*/
|
|
362
|
+
static int
|
|
363
|
+
permissive_name_w(struct archive_write_disk *a)
|
|
364
|
+
{
|
|
365
|
+
wchar_t *wn, *wnp;
|
|
366
|
+
wchar_t *ws, *wsp;
|
|
367
|
+
DWORD l;
|
|
368
|
+
|
|
369
|
+
wnp = a->name;
|
|
370
|
+
if (wnp[0] == L'\\' && wnp[1] == L'\\' &&
|
|
371
|
+
wnp[2] == L'?' && wnp[3] == L'\\')
|
|
372
|
+
/* We have already a permissive name. */
|
|
373
|
+
return (0);
|
|
374
|
+
|
|
375
|
+
if (wnp[0] == L'\\' && wnp[1] == L'\\' &&
|
|
376
|
+
wnp[2] == L'.' && wnp[3] == L'\\') {
|
|
377
|
+
/* This is a device name */
|
|
378
|
+
if (((wnp[4] >= L'a' && wnp[4] <= L'z') ||
|
|
379
|
+
(wnp[4] >= L'A' && wnp[4] <= L'Z')) &&
|
|
380
|
+
wnp[5] == L':' && wnp[6] == L'\\') {
|
|
381
|
+
wnp[2] = L'?';/* Not device name. */
|
|
382
|
+
return (0);
|
|
383
|
+
}
|
|
384
|
+
}
|
|
385
|
+
|
|
386
|
+
/*
|
|
387
|
+
* A full-pathname starting with a drive name like "C:\abc".
|
|
388
|
+
*/
|
|
389
|
+
if (((wnp[0] >= L'a' && wnp[0] <= L'z') ||
|
|
390
|
+
(wnp[0] >= L'A' && wnp[0] <= L'Z')) &&
|
|
391
|
+
wnp[1] == L':' && wnp[2] == L'\\') {
|
|
392
|
+
wn = _wcsdup(wnp);
|
|
393
|
+
if (wn == NULL)
|
|
394
|
+
return (-1);
|
|
395
|
+
archive_wstring_ensure(&(a->_name_data), 4 + wcslen(wn) + 1);
|
|
396
|
+
a->name = a->_name_data.s;
|
|
397
|
+
/* Prepend "\\?\" */
|
|
398
|
+
archive_wstrncpy(&(a->_name_data), L"\\\\?\\", 4);
|
|
399
|
+
archive_wstrcat(&(a->_name_data), wn);
|
|
400
|
+
free(wn);
|
|
401
|
+
return (0);
|
|
402
|
+
}
|
|
403
|
+
|
|
404
|
+
/*
|
|
405
|
+
* A full-pathname pointing to a network drive
|
|
406
|
+
* like "\\<server-name>\<share-name>\file".
|
|
407
|
+
*/
|
|
408
|
+
if (wnp[0] == L'\\' && wnp[1] == L'\\' && wnp[2] != L'\\') {
|
|
409
|
+
const wchar_t *p = &wnp[2];
|
|
410
|
+
|
|
411
|
+
/* Skip server-name letters. */
|
|
412
|
+
while (*p != L'\\' && *p != L'\0')
|
|
413
|
+
++p;
|
|
414
|
+
if (*p == L'\\') {
|
|
415
|
+
const wchar_t *rp = ++p;
|
|
416
|
+
/* Skip share-name letters. */
|
|
417
|
+
while (*p != L'\\' && *p != L'\0')
|
|
418
|
+
++p;
|
|
419
|
+
if (*p == L'\\' && p != rp) {
|
|
420
|
+
/* Now, match patterns such as
|
|
421
|
+
* "\\server-name\share-name\" */
|
|
422
|
+
wn = _wcsdup(wnp);
|
|
423
|
+
if (wn == NULL)
|
|
424
|
+
return (-1);
|
|
425
|
+
archive_wstring_ensure(&(a->_name_data),
|
|
426
|
+
8 + wcslen(wn) + 1);
|
|
427
|
+
a->name = a->_name_data.s;
|
|
428
|
+
/* Prepend "\\?\UNC\" */
|
|
429
|
+
archive_wstrncpy(&(a->_name_data),
|
|
430
|
+
L"\\\\?\\UNC\\", 8);
|
|
431
|
+
archive_wstrcat(&(a->_name_data), wn+2);
|
|
432
|
+
free(wn);
|
|
433
|
+
return (0);
|
|
434
|
+
}
|
|
435
|
+
}
|
|
436
|
+
return (0);
|
|
437
|
+
}
|
|
438
|
+
|
|
439
|
+
/*
|
|
440
|
+
* Get current working directory.
|
|
441
|
+
*/
|
|
442
|
+
l = GetCurrentDirectoryW(0, NULL);
|
|
443
|
+
if (l == 0)
|
|
444
|
+
return (-1);
|
|
445
|
+
ws = malloc(l * sizeof(wchar_t));
|
|
446
|
+
l = GetCurrentDirectoryW(l, ws);
|
|
447
|
+
if (l == 0) {
|
|
448
|
+
free(ws);
|
|
449
|
+
return (-1);
|
|
450
|
+
}
|
|
451
|
+
wsp = ws;
|
|
452
|
+
|
|
453
|
+
/*
|
|
454
|
+
* A full-pathname starting without a drive name like "\abc".
|
|
455
|
+
*/
|
|
456
|
+
if (wnp[0] == L'\\') {
|
|
457
|
+
wn = _wcsdup(wnp);
|
|
458
|
+
if (wn == NULL)
|
|
459
|
+
return (-1);
|
|
460
|
+
archive_wstring_ensure(&(a->_name_data),
|
|
461
|
+
4 + 2 + wcslen(wn) + 1);
|
|
462
|
+
a->name = a->_name_data.s;
|
|
463
|
+
/* Prepend "\\?\" and drive name. */
|
|
464
|
+
archive_wstrncpy(&(a->_name_data), L"\\\\?\\", 4);
|
|
465
|
+
archive_wstrncat(&(a->_name_data), wsp, 2);
|
|
466
|
+
archive_wstrcat(&(a->_name_data), wn);
|
|
467
|
+
free(wsp);
|
|
468
|
+
free(wn);
|
|
469
|
+
return (0);
|
|
470
|
+
}
|
|
471
|
+
|
|
472
|
+
wn = _wcsdup(wnp);
|
|
473
|
+
if (wn == NULL)
|
|
474
|
+
return (-1);
|
|
475
|
+
archive_wstring_ensure(&(a->_name_data), 4 + l + 1 + wcslen(wn) + 1);
|
|
476
|
+
a->name = a->_name_data.s;
|
|
477
|
+
/* Prepend "\\?\" and drive name if not already added. */
|
|
478
|
+
if (l > 3 && wsp[0] == L'\\' && wsp[1] == L'\\' &&
|
|
479
|
+
wsp[2] == L'?' && wsp[3] == L'\\')
|
|
480
|
+
{
|
|
481
|
+
archive_wstrncpy(&(a->_name_data), wsp, l);
|
|
482
|
+
}
|
|
483
|
+
else if (l > 2 && wsp[0] == L'\\' && wsp[1] == L'\\' && wsp[2] != L'\\')
|
|
484
|
+
{
|
|
485
|
+
archive_wstrncpy(&(a->_name_data), L"\\\\?\\UNC\\", 8);
|
|
486
|
+
archive_wstrncat(&(a->_name_data), wsp+2, l-2);
|
|
487
|
+
}
|
|
488
|
+
else
|
|
489
|
+
{
|
|
490
|
+
archive_wstrncpy(&(a->_name_data), L"\\\\?\\", 4);
|
|
491
|
+
archive_wstrncat(&(a->_name_data), wsp, l);
|
|
492
|
+
}
|
|
493
|
+
archive_wstrncat(&(a->_name_data), L"\\", 1);
|
|
494
|
+
archive_wstrcat(&(a->_name_data), wn);
|
|
495
|
+
a->name = a->_name_data.s;
|
|
496
|
+
free(wsp);
|
|
497
|
+
free(wn);
|
|
498
|
+
return (0);
|
|
499
|
+
}
|
|
500
|
+
|
|
501
|
+
static int
|
|
502
|
+
la_chmod(const wchar_t *path, mode_t mode)
|
|
503
|
+
{
|
|
504
|
+
DWORD attr;
|
|
505
|
+
BOOL r;
|
|
506
|
+
wchar_t *fullname;
|
|
507
|
+
int ret = 0;
|
|
508
|
+
|
|
509
|
+
fullname = NULL;
|
|
510
|
+
attr = GetFileAttributesW(path);
|
|
511
|
+
if (attr == (DWORD)-1 &&
|
|
512
|
+
GetLastError() == ERROR_INVALID_NAME) {
|
|
513
|
+
fullname = __la_win_permissive_name_w(path);
|
|
514
|
+
attr = GetFileAttributesW(fullname);
|
|
515
|
+
}
|
|
516
|
+
if (attr == (DWORD)-1) {
|
|
517
|
+
la_dosmaperr(GetLastError());
|
|
518
|
+
ret = -1;
|
|
519
|
+
goto exit_chmode;
|
|
520
|
+
}
|
|
521
|
+
if (mode & _S_IWRITE)
|
|
522
|
+
attr &= ~FILE_ATTRIBUTE_READONLY;
|
|
523
|
+
else
|
|
524
|
+
attr |= FILE_ATTRIBUTE_READONLY;
|
|
525
|
+
if (fullname != NULL)
|
|
526
|
+
r = SetFileAttributesW(fullname, attr);
|
|
527
|
+
else
|
|
528
|
+
r = SetFileAttributesW(path, attr);
|
|
529
|
+
if (r == 0) {
|
|
530
|
+
la_dosmaperr(GetLastError());
|
|
531
|
+
ret = -1;
|
|
532
|
+
}
|
|
533
|
+
exit_chmode:
|
|
534
|
+
free(fullname);
|
|
535
|
+
return (ret);
|
|
536
|
+
}
|
|
537
|
+
|
|
538
|
+
static int
|
|
539
|
+
la_mktemp(struct archive_write_disk *a)
|
|
540
|
+
{
|
|
541
|
+
int fd;
|
|
542
|
+
mode_t mode;
|
|
543
|
+
|
|
544
|
+
archive_wstring_empty(&(a->_tmpname_data));
|
|
545
|
+
archive_wstrcpy(&(a->_tmpname_data), a->name);
|
|
546
|
+
archive_wstrcat(&(a->_tmpname_data), L".XXXXXX");
|
|
547
|
+
a->tmpname = a->_tmpname_data.s;
|
|
548
|
+
|
|
549
|
+
fd = __archive_mkstemp(a->tmpname);
|
|
550
|
+
if (fd == -1)
|
|
551
|
+
return -1;
|
|
552
|
+
|
|
553
|
+
mode = a->mode & 0777 & ~a->user_umask;
|
|
554
|
+
if (la_chmod(a->tmpname, mode) == -1) {
|
|
555
|
+
la_dosmaperr(GetLastError());
|
|
556
|
+
_close(fd);
|
|
557
|
+
return -1;
|
|
558
|
+
}
|
|
559
|
+
return (fd);
|
|
560
|
+
}
|
|
561
|
+
|
|
562
|
+
static void *
|
|
563
|
+
la_GetFunctionKernel32(const char *name)
|
|
564
|
+
{
|
|
565
|
+
static HINSTANCE lib;
|
|
566
|
+
static int set;
|
|
567
|
+
if (!set) {
|
|
568
|
+
set = 1;
|
|
569
|
+
lib = LoadLibrary(TEXT("kernel32.dll"));
|
|
570
|
+
}
|
|
571
|
+
if (lib == NULL) {
|
|
572
|
+
fprintf(stderr, "Can't load kernel32.dll?!\n");
|
|
573
|
+
exit(1);
|
|
574
|
+
}
|
|
575
|
+
return (void *)GetProcAddress(lib, name);
|
|
576
|
+
}
|
|
577
|
+
|
|
578
|
+
static int
|
|
579
|
+
la_CreateHardLinkW(wchar_t *linkname, wchar_t *target)
|
|
580
|
+
{
|
|
581
|
+
static BOOLEAN (WINAPI *f)(LPWSTR, LPWSTR, LPSECURITY_ATTRIBUTES);
|
|
582
|
+
static int set;
|
|
583
|
+
BOOL ret;
|
|
584
|
+
|
|
585
|
+
if (!set) {
|
|
586
|
+
set = 1;
|
|
587
|
+
f = la_GetFunctionKernel32("CreateHardLinkW");
|
|
588
|
+
}
|
|
589
|
+
if (!f) {
|
|
590
|
+
errno = ENOTSUP;
|
|
591
|
+
return (0);
|
|
592
|
+
}
|
|
593
|
+
ret = (*f)(linkname, target, NULL);
|
|
594
|
+
if (!ret) {
|
|
595
|
+
/* Under windows 2000, it is necessary to remove
|
|
596
|
+
* the "\\?\" prefix. */
|
|
597
|
+
#define IS_UNC(name) ((name[0] == L'U' || name[0] == L'u') && \
|
|
598
|
+
(name[1] == L'N' || name[1] == L'n') && \
|
|
599
|
+
(name[2] == L'C' || name[2] == L'c') && \
|
|
600
|
+
name[3] == L'\\')
|
|
601
|
+
if (!wcsncmp(linkname,L"\\\\?\\", 4)) {
|
|
602
|
+
linkname += 4;
|
|
603
|
+
if (IS_UNC(linkname))
|
|
604
|
+
linkname += 4;
|
|
605
|
+
}
|
|
606
|
+
if (!wcsncmp(target,L"\\\\?\\", 4)) {
|
|
607
|
+
target += 4;
|
|
608
|
+
if (IS_UNC(target))
|
|
609
|
+
target += 4;
|
|
610
|
+
}
|
|
611
|
+
#undef IS_UNC
|
|
612
|
+
ret = (*f)(linkname, target, NULL);
|
|
613
|
+
}
|
|
614
|
+
return (ret);
|
|
615
|
+
}
|
|
616
|
+
|
|
617
|
+
/*
|
|
618
|
+
* Create file or directory symolic link
|
|
619
|
+
*
|
|
620
|
+
* If linktype is AE_SYMLINK_TYPE_UNDEFINED (or unknown), guess linktype from
|
|
621
|
+
* the link target
|
|
622
|
+
*/
|
|
623
|
+
static int
|
|
624
|
+
la_CreateSymbolicLinkW(const wchar_t *linkname, const wchar_t *target,
|
|
625
|
+
int linktype) {
|
|
626
|
+
static BOOLEAN (WINAPI *f)(LPCWSTR, LPCWSTR, DWORD);
|
|
627
|
+
static int set;
|
|
628
|
+
wchar_t *ttarget, *p;
|
|
629
|
+
size_t len;
|
|
630
|
+
DWORD attrs = 0;
|
|
631
|
+
DWORD flags = 0;
|
|
632
|
+
DWORD newflags = 0;
|
|
633
|
+
BOOL ret = 0;
|
|
634
|
+
|
|
635
|
+
if (!set) {
|
|
636
|
+
set = 1;
|
|
637
|
+
f = la_GetFunctionKernel32("CreateSymbolicLinkW");
|
|
638
|
+
}
|
|
639
|
+
if (!f)
|
|
640
|
+
return (0);
|
|
641
|
+
|
|
642
|
+
len = wcslen(target);
|
|
643
|
+
if (len == 0) {
|
|
644
|
+
errno = EINVAL;
|
|
645
|
+
return(0);
|
|
646
|
+
}
|
|
647
|
+
/*
|
|
648
|
+
* When writing path targets, we need to translate slashes
|
|
649
|
+
* to backslashes
|
|
650
|
+
*/
|
|
651
|
+
ttarget = malloc((len + 1) * sizeof(wchar_t));
|
|
652
|
+
if (ttarget == NULL)
|
|
653
|
+
return(0);
|
|
654
|
+
|
|
655
|
+
p = ttarget;
|
|
656
|
+
|
|
657
|
+
while(*target != L'\0') {
|
|
658
|
+
if (*target == L'/')
|
|
659
|
+
*p = L'\\';
|
|
660
|
+
else
|
|
661
|
+
*p = *target;
|
|
662
|
+
target++;
|
|
663
|
+
p++;
|
|
664
|
+
}
|
|
665
|
+
*p = L'\0';
|
|
666
|
+
|
|
667
|
+
/*
|
|
668
|
+
* In case of undefined symlink type we guess it from the target.
|
|
669
|
+
* If the target equals ".", "..", ends with a backslash or a
|
|
670
|
+
* backslash followed by "." or ".." we assume it is a directory
|
|
671
|
+
* symlink. In all other cases we assume a file symlink.
|
|
672
|
+
*/
|
|
673
|
+
if (linktype != AE_SYMLINK_TYPE_FILE && (
|
|
674
|
+
linktype == AE_SYMLINK_TYPE_DIRECTORY ||
|
|
675
|
+
*(p - 1) == L'\\' || (*(p - 1) == L'.' && (
|
|
676
|
+
len == 1 || *(p - 2) == L'\\' || ( *(p - 2) == L'.' && (
|
|
677
|
+
len == 2 || *(p - 3) == L'\\')))))) {
|
|
678
|
+
#if defined(SYMBOLIC_LINK_FLAG_DIRECTORY)
|
|
679
|
+
flags |= SYMBOLIC_LINK_FLAG_DIRECTORY;
|
|
680
|
+
#else
|
|
681
|
+
flags |= 0x1;
|
|
682
|
+
#endif
|
|
683
|
+
}
|
|
684
|
+
|
|
685
|
+
#if defined(SYMBOLIC_LINK_FLAG_ALLOW_UNPRIVILEGED_CREATE)
|
|
686
|
+
newflags = flags | SYMBOLIC_LINK_FLAG_ALLOW_UNPRIVILEGED_CREATE;
|
|
687
|
+
#else
|
|
688
|
+
newflags = flags | 0x2;
|
|
689
|
+
#endif
|
|
690
|
+
|
|
691
|
+
/*
|
|
692
|
+
* Windows won't overwrite existing links
|
|
693
|
+
*/
|
|
694
|
+
attrs = GetFileAttributesW(linkname);
|
|
695
|
+
if (attrs != INVALID_FILE_ATTRIBUTES) {
|
|
696
|
+
if (attrs & FILE_ATTRIBUTE_DIRECTORY)
|
|
697
|
+
disk_rmdir(linkname);
|
|
698
|
+
else
|
|
699
|
+
disk_unlink(linkname);
|
|
700
|
+
}
|
|
701
|
+
|
|
702
|
+
ret = (*f)(linkname, ttarget, newflags);
|
|
703
|
+
/*
|
|
704
|
+
* Prior to Windows 10 calling CreateSymbolicLinkW() will fail
|
|
705
|
+
* if SYMBOLIC_LINK_FLAG_ALLOW_UNPRIVILEGED_CREATE is set
|
|
706
|
+
*/
|
|
707
|
+
if (!ret) {
|
|
708
|
+
ret = (*f)(linkname, ttarget, flags);
|
|
709
|
+
}
|
|
710
|
+
free(ttarget);
|
|
711
|
+
return (ret);
|
|
712
|
+
}
|
|
713
|
+
|
|
714
|
+
static int
|
|
715
|
+
la_ftruncate(HANDLE handle, int64_t length)
|
|
716
|
+
{
|
|
717
|
+
LARGE_INTEGER distance;
|
|
718
|
+
|
|
719
|
+
if (GetFileType(handle) != FILE_TYPE_DISK) {
|
|
720
|
+
errno = EBADF;
|
|
721
|
+
return (-1);
|
|
722
|
+
}
|
|
723
|
+
distance.QuadPart = length;
|
|
724
|
+
if (!SetFilePointerEx_perso(handle, distance, NULL, FILE_BEGIN)) {
|
|
725
|
+
la_dosmaperr(GetLastError());
|
|
726
|
+
return (-1);
|
|
727
|
+
}
|
|
728
|
+
if (!SetEndOfFile(handle)) {
|
|
729
|
+
la_dosmaperr(GetLastError());
|
|
730
|
+
return (-1);
|
|
731
|
+
}
|
|
732
|
+
return (0);
|
|
733
|
+
}
|
|
734
|
+
|
|
735
|
+
static int
|
|
736
|
+
lazy_stat(struct archive_write_disk *a)
|
|
737
|
+
{
|
|
738
|
+
if (a->pst != NULL) {
|
|
739
|
+
/* Already have stat() data available. */
|
|
740
|
+
return (ARCHIVE_OK);
|
|
741
|
+
}
|
|
742
|
+
if (a->fh != INVALID_HANDLE_VALUE &&
|
|
743
|
+
GetFileInformationByHandle(a->fh, &a->st) == 0) {
|
|
744
|
+
a->pst = &a->st;
|
|
745
|
+
return (ARCHIVE_OK);
|
|
746
|
+
}
|
|
747
|
+
|
|
748
|
+
/*
|
|
749
|
+
* XXX At this point, symlinks should not be hit, otherwise
|
|
750
|
+
* XXX a race occurred. Do we want to check explicitly for that?
|
|
751
|
+
*/
|
|
752
|
+
if (file_information(a, a->name, &a->st, NULL, 1) == 0) {
|
|
753
|
+
a->pst = &a->st;
|
|
754
|
+
return (ARCHIVE_OK);
|
|
755
|
+
}
|
|
756
|
+
archive_set_error(&a->archive, errno, "Couldn't stat file");
|
|
757
|
+
return (ARCHIVE_WARN);
|
|
758
|
+
}
|
|
759
|
+
|
|
760
|
+
static const struct archive_vtable
|
|
761
|
+
archive_write_disk_vtable = {
|
|
762
|
+
.archive_close = _archive_write_disk_close,
|
|
763
|
+
.archive_filter_bytes = _archive_write_disk_filter_bytes,
|
|
764
|
+
.archive_free = _archive_write_disk_free,
|
|
765
|
+
.archive_write_header = _archive_write_disk_header,
|
|
766
|
+
.archive_write_finish_entry = _archive_write_disk_finish_entry,
|
|
767
|
+
.archive_write_data = _archive_write_disk_data,
|
|
768
|
+
.archive_write_data_block = _archive_write_disk_data_block,
|
|
769
|
+
};
|
|
770
|
+
|
|
771
|
+
static int64_t
|
|
772
|
+
_archive_write_disk_filter_bytes(struct archive *_a, int n)
|
|
773
|
+
{
|
|
774
|
+
struct archive_write_disk *a = (struct archive_write_disk *)_a;
|
|
775
|
+
(void)n; /* UNUSED */
|
|
776
|
+
if (n == -1 || n == 0)
|
|
777
|
+
return (a->total_bytes_written);
|
|
778
|
+
return (-1);
|
|
779
|
+
}
|
|
780
|
+
|
|
781
|
+
|
|
782
|
+
int
|
|
783
|
+
archive_write_disk_set_options(struct archive *_a, int flags)
|
|
784
|
+
{
|
|
785
|
+
struct archive_write_disk *a = (struct archive_write_disk *)_a;
|
|
786
|
+
|
|
787
|
+
a->flags = flags;
|
|
788
|
+
return (ARCHIVE_OK);
|
|
789
|
+
}
|
|
790
|
+
|
|
791
|
+
|
|
792
|
+
/*
|
|
793
|
+
* Extract this entry to disk.
|
|
794
|
+
*
|
|
795
|
+
* TODO: Validate hardlinks. According to the standards, we're
|
|
796
|
+
* supposed to check each extracted hardlink and squawk if it refers
|
|
797
|
+
* to a file that we didn't restore. I'm not entirely convinced this
|
|
798
|
+
* is a good idea, but more importantly: Is there any way to validate
|
|
799
|
+
* hardlinks without keeping a complete list of filenames from the
|
|
800
|
+
* entire archive?? Ugh.
|
|
801
|
+
*
|
|
802
|
+
*/
|
|
803
|
+
static int
|
|
804
|
+
_archive_write_disk_header(struct archive *_a, struct archive_entry *entry)
|
|
805
|
+
{
|
|
806
|
+
struct archive_write_disk *a = (struct archive_write_disk *)_a;
|
|
807
|
+
struct fixup_entry *fe;
|
|
808
|
+
int ret, r;
|
|
809
|
+
|
|
810
|
+
archive_check_magic(&a->archive, ARCHIVE_WRITE_DISK_MAGIC,
|
|
811
|
+
ARCHIVE_STATE_HEADER | ARCHIVE_STATE_DATA,
|
|
812
|
+
"archive_write_disk_header");
|
|
813
|
+
archive_clear_error(&a->archive);
|
|
814
|
+
if (a->archive.state & ARCHIVE_STATE_DATA) {
|
|
815
|
+
r = _archive_write_disk_finish_entry(&a->archive);
|
|
816
|
+
if (r == ARCHIVE_FATAL)
|
|
817
|
+
return (r);
|
|
818
|
+
}
|
|
819
|
+
|
|
820
|
+
/* Set up for this particular entry. */
|
|
821
|
+
a->pst = NULL;
|
|
822
|
+
a->current_fixup = NULL;
|
|
823
|
+
a->deferred = 0;
|
|
824
|
+
archive_entry_free(a->entry);
|
|
825
|
+
a->entry = NULL;
|
|
826
|
+
a->entry = archive_entry_clone(entry);
|
|
827
|
+
a->fh = INVALID_HANDLE_VALUE;
|
|
828
|
+
a->fd_offset = 0;
|
|
829
|
+
a->offset = 0;
|
|
830
|
+
a->restore_pwd = -1;
|
|
831
|
+
a->uid = a->user_uid;
|
|
832
|
+
a->mode = archive_entry_mode(a->entry);
|
|
833
|
+
if (archive_entry_size_is_set(a->entry))
|
|
834
|
+
a->filesize = archive_entry_size(a->entry);
|
|
835
|
+
else
|
|
836
|
+
a->filesize = -1;
|
|
837
|
+
archive_wstrcpy(&(a->_name_data), archive_entry_pathname_w(a->entry));
|
|
838
|
+
a->name = a->_name_data.s;
|
|
839
|
+
archive_clear_error(&a->archive);
|
|
840
|
+
|
|
841
|
+
/*
|
|
842
|
+
* Clean up the requested path. This is necessary for correct
|
|
843
|
+
* dir restores; the dir restore logic otherwise gets messed
|
|
844
|
+
* up by nonsense like "dir/.".
|
|
845
|
+
*/
|
|
846
|
+
ret = cleanup_pathname(a, a->name);
|
|
847
|
+
if (ret != ARCHIVE_OK)
|
|
848
|
+
return (ret);
|
|
849
|
+
|
|
850
|
+
/*
|
|
851
|
+
* Generate a full-pathname and use it from here.
|
|
852
|
+
*/
|
|
853
|
+
if (permissive_name_w(a) < 0) {
|
|
854
|
+
errno = EINVAL;
|
|
855
|
+
return (ARCHIVE_FAILED);
|
|
856
|
+
}
|
|
857
|
+
|
|
858
|
+
/*
|
|
859
|
+
* Query the umask so we get predictable mode settings.
|
|
860
|
+
* This gets done on every call to _write_header in case the
|
|
861
|
+
* user edits their umask during the extraction for some
|
|
862
|
+
* reason.
|
|
863
|
+
*/
|
|
864
|
+
umask(a->user_umask = umask(0));
|
|
865
|
+
|
|
866
|
+
/* Figure out what we need to do for this entry. */
|
|
867
|
+
a->todo = TODO_MODE_BASE;
|
|
868
|
+
if (a->flags & ARCHIVE_EXTRACT_PERM) {
|
|
869
|
+
a->todo |= TODO_MODE_FORCE; /* Be pushy about permissions. */
|
|
870
|
+
/*
|
|
871
|
+
* SGID requires an extra "check" step because we
|
|
872
|
+
* cannot easily predict the GID that the system will
|
|
873
|
+
* assign. (Different systems assign GIDs to files
|
|
874
|
+
* based on a variety of criteria, including process
|
|
875
|
+
* credentials and the gid of the enclosing
|
|
876
|
+
* directory.) We can only restore the SGID bit if
|
|
877
|
+
* the file has the right GID, and we only know the
|
|
878
|
+
* GID if we either set it (see set_ownership) or if
|
|
879
|
+
* we've actually called stat() on the file after it
|
|
880
|
+
* was restored. Since there are several places at
|
|
881
|
+
* which we might verify the GID, we need a TODO bit
|
|
882
|
+
* to keep track.
|
|
883
|
+
*/
|
|
884
|
+
if (a->mode & S_ISGID)
|
|
885
|
+
a->todo |= TODO_SGID | TODO_SGID_CHECK;
|
|
886
|
+
/*
|
|
887
|
+
* Verifying the SUID is simpler, but can still be
|
|
888
|
+
* done in multiple ways, hence the separate "check" bit.
|
|
889
|
+
*/
|
|
890
|
+
if (a->mode & S_ISUID)
|
|
891
|
+
a->todo |= TODO_SUID | TODO_SUID_CHECK;
|
|
892
|
+
} else {
|
|
893
|
+
/*
|
|
894
|
+
* User didn't request full permissions, so don't
|
|
895
|
+
* restore SUID, SGID bits and obey umask.
|
|
896
|
+
*/
|
|
897
|
+
a->mode &= ~S_ISUID;
|
|
898
|
+
a->mode &= ~S_ISGID;
|
|
899
|
+
a->mode &= ~S_ISVTX;
|
|
900
|
+
a->mode &= ~a->user_umask;
|
|
901
|
+
}
|
|
902
|
+
#if 0
|
|
903
|
+
if (a->flags & ARCHIVE_EXTRACT_OWNER)
|
|
904
|
+
a->todo |= TODO_OWNER;
|
|
905
|
+
#endif
|
|
906
|
+
if (a->flags & ARCHIVE_EXTRACT_TIME)
|
|
907
|
+
a->todo |= TODO_TIMES;
|
|
908
|
+
if (a->flags & ARCHIVE_EXTRACT_ACL) {
|
|
909
|
+
if (archive_entry_filetype(a->entry) == AE_IFDIR)
|
|
910
|
+
a->deferred |= TODO_ACLS;
|
|
911
|
+
else
|
|
912
|
+
a->todo |= TODO_ACLS;
|
|
913
|
+
}
|
|
914
|
+
if (a->flags & ARCHIVE_EXTRACT_XATTR)
|
|
915
|
+
a->todo |= TODO_XATTR;
|
|
916
|
+
if (a->flags & ARCHIVE_EXTRACT_FFLAGS)
|
|
917
|
+
a->todo |= TODO_FFLAGS;
|
|
918
|
+
if (a->flags & ARCHIVE_EXTRACT_SECURE_SYMLINKS) {
|
|
919
|
+
ret = check_symlinks(a);
|
|
920
|
+
if (ret != ARCHIVE_OK)
|
|
921
|
+
return (ret);
|
|
922
|
+
}
|
|
923
|
+
|
|
924
|
+
ret = restore_entry(a);
|
|
925
|
+
|
|
926
|
+
/*
|
|
927
|
+
* TODO: There are rumours that some extended attributes must
|
|
928
|
+
* be restored before file data is written. If this is true,
|
|
929
|
+
* then we either need to write all extended attributes both
|
|
930
|
+
* before and after restoring the data, or find some rule for
|
|
931
|
+
* determining which must go first and which last. Due to the
|
|
932
|
+
* many ways people are using xattrs, this may prove to be an
|
|
933
|
+
* intractable problem.
|
|
934
|
+
*/
|
|
935
|
+
|
|
936
|
+
/*
|
|
937
|
+
* Fixup uses the unedited pathname from archive_entry_pathname(),
|
|
938
|
+
* because it is relative to the base dir and the edited path
|
|
939
|
+
* might be relative to some intermediate dir as a result of the
|
|
940
|
+
* deep restore logic.
|
|
941
|
+
*/
|
|
942
|
+
if (a->deferred & TODO_MODE) {
|
|
943
|
+
fe = current_fixup(a, archive_entry_pathname_w(entry));
|
|
944
|
+
fe->fixup |= TODO_MODE_BASE;
|
|
945
|
+
fe->mode = a->mode;
|
|
946
|
+
}
|
|
947
|
+
|
|
948
|
+
if ((a->deferred & TODO_TIMES)
|
|
949
|
+
&& (archive_entry_mtime_is_set(entry)
|
|
950
|
+
|| archive_entry_atime_is_set(entry))) {
|
|
951
|
+
fe = current_fixup(a, archive_entry_pathname_w(entry));
|
|
952
|
+
fe->mode = a->mode;
|
|
953
|
+
fe->fixup |= TODO_TIMES;
|
|
954
|
+
if (archive_entry_atime_is_set(entry)) {
|
|
955
|
+
fe->atime = archive_entry_atime(entry);
|
|
956
|
+
fe->atime_nanos = archive_entry_atime_nsec(entry);
|
|
957
|
+
} else {
|
|
958
|
+
/* If atime is unset, use start time. */
|
|
959
|
+
fe->atime = a->start_time;
|
|
960
|
+
fe->atime_nanos = 0;
|
|
961
|
+
}
|
|
962
|
+
if (archive_entry_mtime_is_set(entry)) {
|
|
963
|
+
fe->mtime = archive_entry_mtime(entry);
|
|
964
|
+
fe->mtime_nanos = archive_entry_mtime_nsec(entry);
|
|
965
|
+
} else {
|
|
966
|
+
/* If mtime is unset, use start time. */
|
|
967
|
+
fe->mtime = a->start_time;
|
|
968
|
+
fe->mtime_nanos = 0;
|
|
969
|
+
}
|
|
970
|
+
if (archive_entry_birthtime_is_set(entry)) {
|
|
971
|
+
fe->birthtime = archive_entry_birthtime(entry);
|
|
972
|
+
fe->birthtime_nanos = archive_entry_birthtime_nsec(entry);
|
|
973
|
+
} else {
|
|
974
|
+
/* If birthtime is unset, use mtime. */
|
|
975
|
+
fe->birthtime = fe->mtime;
|
|
976
|
+
fe->birthtime_nanos = fe->mtime_nanos;
|
|
977
|
+
}
|
|
978
|
+
}
|
|
979
|
+
|
|
980
|
+
if (a->deferred & TODO_ACLS) {
|
|
981
|
+
fe = current_fixup(a, archive_entry_pathname_w(entry));
|
|
982
|
+
archive_acl_copy(&fe->acl, archive_entry_acl(entry));
|
|
983
|
+
}
|
|
984
|
+
|
|
985
|
+
if (a->deferred & TODO_FFLAGS) {
|
|
986
|
+
unsigned long set, clear;
|
|
987
|
+
|
|
988
|
+
fe = current_fixup(a, archive_entry_pathname_w(entry));
|
|
989
|
+
archive_entry_fflags(entry, &set, &clear);
|
|
990
|
+
fe->fflags_set = set;
|
|
991
|
+
}
|
|
992
|
+
|
|
993
|
+
/*
|
|
994
|
+
* On Windows, A creating sparse file requires a special mark.
|
|
995
|
+
*/
|
|
996
|
+
if (a->fh != INVALID_HANDLE_VALUE &&
|
|
997
|
+
archive_entry_sparse_count(entry) > 0) {
|
|
998
|
+
int64_t base = 0, offset, length;
|
|
999
|
+
int i, cnt = archive_entry_sparse_reset(entry);
|
|
1000
|
+
int sparse = 0;
|
|
1001
|
+
|
|
1002
|
+
for (i = 0; i < cnt; i++) {
|
|
1003
|
+
archive_entry_sparse_next(entry, &offset, &length);
|
|
1004
|
+
if (offset - base >= 4096) {
|
|
1005
|
+
sparse = 1;/* we have a hole. */
|
|
1006
|
+
break;
|
|
1007
|
+
}
|
|
1008
|
+
base = offset + length;
|
|
1009
|
+
}
|
|
1010
|
+
if (sparse) {
|
|
1011
|
+
DWORD dmy;
|
|
1012
|
+
/* Mark this file as sparse. */
|
|
1013
|
+
DeviceIoControl(a->fh, FSCTL_SET_SPARSE,
|
|
1014
|
+
NULL, 0, NULL, 0, &dmy, NULL);
|
|
1015
|
+
}
|
|
1016
|
+
}
|
|
1017
|
+
|
|
1018
|
+
/* We've created the object and are ready to pour data into it. */
|
|
1019
|
+
if (ret >= ARCHIVE_WARN)
|
|
1020
|
+
a->archive.state = ARCHIVE_STATE_DATA;
|
|
1021
|
+
/*
|
|
1022
|
+
* If it's not open, tell our client not to try writing.
|
|
1023
|
+
* In particular, dirs, links, etc, don't get written to.
|
|
1024
|
+
*/
|
|
1025
|
+
if (a->fh == INVALID_HANDLE_VALUE) {
|
|
1026
|
+
archive_entry_set_size(entry, 0);
|
|
1027
|
+
a->filesize = 0;
|
|
1028
|
+
}
|
|
1029
|
+
|
|
1030
|
+
return (ret);
|
|
1031
|
+
}
|
|
1032
|
+
|
|
1033
|
+
int
|
|
1034
|
+
archive_write_disk_set_skip_file(struct archive *_a, la_int64_t d, la_int64_t i)
|
|
1035
|
+
{
|
|
1036
|
+
struct archive_write_disk *a = (struct archive_write_disk *)_a;
|
|
1037
|
+
archive_check_magic(&a->archive, ARCHIVE_WRITE_DISK_MAGIC,
|
|
1038
|
+
ARCHIVE_STATE_ANY, "archive_write_disk_set_skip_file");
|
|
1039
|
+
a->skip_file_set = 1;
|
|
1040
|
+
a->skip_file_dev = d;
|
|
1041
|
+
a->skip_file_ino = i;
|
|
1042
|
+
return (ARCHIVE_OK);
|
|
1043
|
+
}
|
|
1044
|
+
|
|
1045
|
+
static ssize_t
|
|
1046
|
+
write_data_block(struct archive_write_disk *a, const char *buff, size_t size)
|
|
1047
|
+
{
|
|
1048
|
+
OVERLAPPED ol;
|
|
1049
|
+
uint64_t start_size = size;
|
|
1050
|
+
DWORD bytes_written = 0;
|
|
1051
|
+
ssize_t block_size = 0, bytes_to_write;
|
|
1052
|
+
|
|
1053
|
+
if (size == 0)
|
|
1054
|
+
return (ARCHIVE_OK);
|
|
1055
|
+
|
|
1056
|
+
if (a->filesize == 0 || a->fh == INVALID_HANDLE_VALUE) {
|
|
1057
|
+
archive_set_error(&a->archive, 0,
|
|
1058
|
+
"Attempt to write to an empty file");
|
|
1059
|
+
return (ARCHIVE_WARN);
|
|
1060
|
+
}
|
|
1061
|
+
|
|
1062
|
+
if (a->flags & ARCHIVE_EXTRACT_SPARSE) {
|
|
1063
|
+
/* XXX TODO XXX Is there a more appropriate choice here ? */
|
|
1064
|
+
/* This needn't match the filesystem allocation size. */
|
|
1065
|
+
block_size = 16*1024;
|
|
1066
|
+
}
|
|
1067
|
+
|
|
1068
|
+
/* If this write would run beyond the file size, truncate it. */
|
|
1069
|
+
if (a->filesize >= 0 && (int64_t)(a->offset + size) > a->filesize)
|
|
1070
|
+
start_size = size = (size_t)(a->filesize - a->offset);
|
|
1071
|
+
|
|
1072
|
+
/* Write the data. */
|
|
1073
|
+
while (size > 0) {
|
|
1074
|
+
if (block_size == 0) {
|
|
1075
|
+
bytes_to_write = size;
|
|
1076
|
+
} else {
|
|
1077
|
+
/* We're sparsifying the file. */
|
|
1078
|
+
const char *p, *end;
|
|
1079
|
+
int64_t block_end;
|
|
1080
|
+
|
|
1081
|
+
/* Skip leading zero bytes. */
|
|
1082
|
+
for (p = buff, end = buff + size; p < end; ++p) {
|
|
1083
|
+
if (*p != '\0')
|
|
1084
|
+
break;
|
|
1085
|
+
}
|
|
1086
|
+
a->offset += p - buff;
|
|
1087
|
+
size -= p - buff;
|
|
1088
|
+
buff = p;
|
|
1089
|
+
if (size == 0)
|
|
1090
|
+
break;
|
|
1091
|
+
|
|
1092
|
+
/* Calculate next block boundary after offset. */
|
|
1093
|
+
block_end
|
|
1094
|
+
= (a->offset / block_size + 1) * block_size;
|
|
1095
|
+
|
|
1096
|
+
/* If the adjusted write would cross block boundary,
|
|
1097
|
+
* truncate it to the block boundary. */
|
|
1098
|
+
bytes_to_write = size;
|
|
1099
|
+
if (a->offset + bytes_to_write > block_end)
|
|
1100
|
+
bytes_to_write = (DWORD)(block_end - a->offset);
|
|
1101
|
+
}
|
|
1102
|
+
memset(&ol, 0, sizeof(ol));
|
|
1103
|
+
ol.Offset = (DWORD)(a->offset & 0xFFFFFFFF);
|
|
1104
|
+
ol.OffsetHigh = (DWORD)(a->offset >> 32);
|
|
1105
|
+
if (!WriteFile(a->fh, buff, (uint32_t)bytes_to_write,
|
|
1106
|
+
&bytes_written, &ol)) {
|
|
1107
|
+
DWORD lasterr;
|
|
1108
|
+
|
|
1109
|
+
lasterr = GetLastError();
|
|
1110
|
+
if (lasterr == ERROR_ACCESS_DENIED)
|
|
1111
|
+
errno = EBADF;
|
|
1112
|
+
else
|
|
1113
|
+
la_dosmaperr(lasterr);
|
|
1114
|
+
archive_set_error(&a->archive, errno, "Write failed");
|
|
1115
|
+
return (ARCHIVE_WARN);
|
|
1116
|
+
}
|
|
1117
|
+
buff += bytes_written;
|
|
1118
|
+
size -= bytes_written;
|
|
1119
|
+
a->total_bytes_written += bytes_written;
|
|
1120
|
+
a->offset += bytes_written;
|
|
1121
|
+
a->fd_offset = a->offset;
|
|
1122
|
+
}
|
|
1123
|
+
return ((ssize_t)(start_size - size));
|
|
1124
|
+
}
|
|
1125
|
+
|
|
1126
|
+
static ssize_t
|
|
1127
|
+
_archive_write_disk_data_block(struct archive *_a,
|
|
1128
|
+
const void *buff, size_t size, int64_t offset)
|
|
1129
|
+
{
|
|
1130
|
+
struct archive_write_disk *a = (struct archive_write_disk *)_a;
|
|
1131
|
+
ssize_t r;
|
|
1132
|
+
|
|
1133
|
+
archive_check_magic(&a->archive, ARCHIVE_WRITE_DISK_MAGIC,
|
|
1134
|
+
ARCHIVE_STATE_DATA, "archive_write_data_block");
|
|
1135
|
+
|
|
1136
|
+
a->offset = offset;
|
|
1137
|
+
r = write_data_block(a, buff, size);
|
|
1138
|
+
if (r < ARCHIVE_OK)
|
|
1139
|
+
return (r);
|
|
1140
|
+
if ((size_t)r < size) {
|
|
1141
|
+
archive_set_error(&a->archive, 0,
|
|
1142
|
+
"Write request too large");
|
|
1143
|
+
return (ARCHIVE_WARN);
|
|
1144
|
+
}
|
|
1145
|
+
#if ARCHIVE_VERSION_NUMBER < 3999000
|
|
1146
|
+
return (ARCHIVE_OK);
|
|
1147
|
+
#else
|
|
1148
|
+
return (size);
|
|
1149
|
+
#endif
|
|
1150
|
+
}
|
|
1151
|
+
|
|
1152
|
+
static ssize_t
|
|
1153
|
+
_archive_write_disk_data(struct archive *_a, const void *buff, size_t size)
|
|
1154
|
+
{
|
|
1155
|
+
struct archive_write_disk *a = (struct archive_write_disk *)_a;
|
|
1156
|
+
|
|
1157
|
+
archive_check_magic(&a->archive, ARCHIVE_WRITE_DISK_MAGIC,
|
|
1158
|
+
ARCHIVE_STATE_DATA, "archive_write_data");
|
|
1159
|
+
|
|
1160
|
+
return (write_data_block(a, buff, size));
|
|
1161
|
+
}
|
|
1162
|
+
|
|
1163
|
+
static int
|
|
1164
|
+
_archive_write_disk_finish_entry(struct archive *_a)
|
|
1165
|
+
{
|
|
1166
|
+
struct archive_write_disk *a = (struct archive_write_disk *)_a;
|
|
1167
|
+
int ret = ARCHIVE_OK;
|
|
1168
|
+
|
|
1169
|
+
archive_check_magic(&a->archive, ARCHIVE_WRITE_DISK_MAGIC,
|
|
1170
|
+
ARCHIVE_STATE_HEADER | ARCHIVE_STATE_DATA,
|
|
1171
|
+
"archive_write_finish_entry");
|
|
1172
|
+
if (a->archive.state & ARCHIVE_STATE_HEADER)
|
|
1173
|
+
return (ARCHIVE_OK);
|
|
1174
|
+
archive_clear_error(&a->archive);
|
|
1175
|
+
|
|
1176
|
+
/* Pad or truncate file to the right size. */
|
|
1177
|
+
if (a->fh == INVALID_HANDLE_VALUE) {
|
|
1178
|
+
/* There's no file. */
|
|
1179
|
+
} else if (a->filesize < 0) {
|
|
1180
|
+
/* File size is unknown, so we can't set the size. */
|
|
1181
|
+
} else if (a->fd_offset == a->filesize) {
|
|
1182
|
+
/* Last write ended at exactly the filesize; we're done. */
|
|
1183
|
+
/* Hopefully, this is the common case. */
|
|
1184
|
+
} else {
|
|
1185
|
+
if (la_ftruncate(a->fh, a->filesize) == -1) {
|
|
1186
|
+
archive_set_error(&a->archive, errno,
|
|
1187
|
+
"File size could not be restored");
|
|
1188
|
+
return (ARCHIVE_FAILED);
|
|
1189
|
+
}
|
|
1190
|
+
}
|
|
1191
|
+
|
|
1192
|
+
/* Restore metadata. */
|
|
1193
|
+
|
|
1194
|
+
/*
|
|
1195
|
+
* Look up the "real" UID only if we're going to need it.
|
|
1196
|
+
* TODO: the TODO_SGID condition can be dropped here, can't it?
|
|
1197
|
+
*/
|
|
1198
|
+
if (a->todo & (TODO_OWNER | TODO_SUID | TODO_SGID)) {
|
|
1199
|
+
a->uid = archive_write_disk_uid(&a->archive,
|
|
1200
|
+
archive_entry_uname(a->entry),
|
|
1201
|
+
archive_entry_uid(a->entry));
|
|
1202
|
+
}
|
|
1203
|
+
/* Look up the "real" GID only if we're going to need it. */
|
|
1204
|
+
/* TODO: the TODO_SUID condition can be dropped here, can't it? */
|
|
1205
|
+
if (a->todo & (TODO_OWNER | TODO_SGID | TODO_SUID)) {
|
|
1206
|
+
a->gid = archive_write_disk_gid(&a->archive,
|
|
1207
|
+
archive_entry_gname(a->entry),
|
|
1208
|
+
archive_entry_gid(a->entry));
|
|
1209
|
+
}
|
|
1210
|
+
|
|
1211
|
+
/*
|
|
1212
|
+
* Restore ownership before set_mode tries to restore suid/sgid
|
|
1213
|
+
* bits. If we set the owner, we know what it is and can skip
|
|
1214
|
+
* a stat() call to examine the ownership of the file on disk.
|
|
1215
|
+
*/
|
|
1216
|
+
if (a->todo & TODO_OWNER)
|
|
1217
|
+
ret = set_ownership(a);
|
|
1218
|
+
|
|
1219
|
+
/*
|
|
1220
|
+
* set_mode must precede ACLs on systems such as Solaris and
|
|
1221
|
+
* FreeBSD where setting the mode implicitly clears extended ACLs
|
|
1222
|
+
*/
|
|
1223
|
+
if (a->todo & TODO_MODE) {
|
|
1224
|
+
int r2 = set_mode(a, a->mode);
|
|
1225
|
+
if (r2 < ret) ret = r2;
|
|
1226
|
+
}
|
|
1227
|
+
|
|
1228
|
+
/*
|
|
1229
|
+
* Security-related extended attributes (such as
|
|
1230
|
+
* security.capability on Linux) have to be restored last,
|
|
1231
|
+
* since they're implicitly removed by other file changes.
|
|
1232
|
+
*/
|
|
1233
|
+
if (a->todo & TODO_XATTR) {
|
|
1234
|
+
int r2 = set_xattrs(a);
|
|
1235
|
+
if (r2 < ret) ret = r2;
|
|
1236
|
+
}
|
|
1237
|
+
|
|
1238
|
+
/*
|
|
1239
|
+
* Some flags prevent file modification; they must be restored after
|
|
1240
|
+
* file contents are written.
|
|
1241
|
+
*/
|
|
1242
|
+
if (a->todo & TODO_FFLAGS) {
|
|
1243
|
+
int r2 = set_fflags(a);
|
|
1244
|
+
if (r2 < ret) ret = r2;
|
|
1245
|
+
}
|
|
1246
|
+
|
|
1247
|
+
/*
|
|
1248
|
+
* Time must follow most other metadata;
|
|
1249
|
+
* otherwise atime will get changed.
|
|
1250
|
+
*/
|
|
1251
|
+
if (a->todo & TODO_TIMES) {
|
|
1252
|
+
int r2 = set_times_from_entry(a);
|
|
1253
|
+
if (r2 < ret) ret = r2;
|
|
1254
|
+
}
|
|
1255
|
+
|
|
1256
|
+
/*
|
|
1257
|
+
* ACLs must be restored after timestamps because there are
|
|
1258
|
+
* ACLs that prevent attribute changes (including time).
|
|
1259
|
+
*/
|
|
1260
|
+
if (a->todo & TODO_ACLS) {
|
|
1261
|
+
int r2 = set_acls(a, a->fh,
|
|
1262
|
+
archive_entry_pathname_w(a->entry),
|
|
1263
|
+
archive_entry_acl(a->entry));
|
|
1264
|
+
if (r2 < ret) ret = r2;
|
|
1265
|
+
}
|
|
1266
|
+
|
|
1267
|
+
/* If there's an fd, we can close it now. */
|
|
1268
|
+
if (a->fh != INVALID_HANDLE_VALUE) {
|
|
1269
|
+
CloseHandle(a->fh);
|
|
1270
|
+
a->fh = INVALID_HANDLE_VALUE;
|
|
1271
|
+
if (a->tmpname) {
|
|
1272
|
+
/* Windows does not support atomic rename */
|
|
1273
|
+
disk_unlink(a->name);
|
|
1274
|
+
if (_wrename(a->tmpname, a->name) != 0) {
|
|
1275
|
+
la_dosmaperr(GetLastError());
|
|
1276
|
+
archive_set_error(&a->archive, errno,
|
|
1277
|
+
"Failed to rename temporary file");
|
|
1278
|
+
ret = ARCHIVE_FAILED;
|
|
1279
|
+
disk_unlink(a->tmpname);
|
|
1280
|
+
}
|
|
1281
|
+
a->tmpname = NULL;
|
|
1282
|
+
}
|
|
1283
|
+
}
|
|
1284
|
+
/* If there's an entry, we can release it now. */
|
|
1285
|
+
archive_entry_free(a->entry);
|
|
1286
|
+
a->entry = NULL;
|
|
1287
|
+
a->archive.state = ARCHIVE_STATE_HEADER;
|
|
1288
|
+
return (ret);
|
|
1289
|
+
}
|
|
1290
|
+
|
|
1291
|
+
int
|
|
1292
|
+
archive_write_disk_set_group_lookup(struct archive *_a,
|
|
1293
|
+
void *private_data,
|
|
1294
|
+
la_int64_t (*lookup_gid)(void *private, const char *gname, la_int64_t gid),
|
|
1295
|
+
void (*cleanup_gid)(void *private))
|
|
1296
|
+
{
|
|
1297
|
+
struct archive_write_disk *a = (struct archive_write_disk *)_a;
|
|
1298
|
+
archive_check_magic(&a->archive, ARCHIVE_WRITE_DISK_MAGIC,
|
|
1299
|
+
ARCHIVE_STATE_ANY, "archive_write_disk_set_group_lookup");
|
|
1300
|
+
|
|
1301
|
+
if (a->cleanup_gid != NULL && a->lookup_gid_data != NULL)
|
|
1302
|
+
(a->cleanup_gid)(a->lookup_gid_data);
|
|
1303
|
+
|
|
1304
|
+
a->lookup_gid = lookup_gid;
|
|
1305
|
+
a->cleanup_gid = cleanup_gid;
|
|
1306
|
+
a->lookup_gid_data = private_data;
|
|
1307
|
+
return (ARCHIVE_OK);
|
|
1308
|
+
}
|
|
1309
|
+
|
|
1310
|
+
int
|
|
1311
|
+
archive_write_disk_set_user_lookup(struct archive *_a,
|
|
1312
|
+
void *private_data,
|
|
1313
|
+
int64_t (*lookup_uid)(void *private, const char *uname, int64_t uid),
|
|
1314
|
+
void (*cleanup_uid)(void *private))
|
|
1315
|
+
{
|
|
1316
|
+
struct archive_write_disk *a = (struct archive_write_disk *)_a;
|
|
1317
|
+
archive_check_magic(&a->archive, ARCHIVE_WRITE_DISK_MAGIC,
|
|
1318
|
+
ARCHIVE_STATE_ANY, "archive_write_disk_set_user_lookup");
|
|
1319
|
+
|
|
1320
|
+
if (a->cleanup_uid != NULL && a->lookup_uid_data != NULL)
|
|
1321
|
+
(a->cleanup_uid)(a->lookup_uid_data);
|
|
1322
|
+
|
|
1323
|
+
a->lookup_uid = lookup_uid;
|
|
1324
|
+
a->cleanup_uid = cleanup_uid;
|
|
1325
|
+
a->lookup_uid_data = private_data;
|
|
1326
|
+
return (ARCHIVE_OK);
|
|
1327
|
+
}
|
|
1328
|
+
|
|
1329
|
+
int64_t
|
|
1330
|
+
archive_write_disk_gid(struct archive *_a, const char *name, la_int64_t id)
|
|
1331
|
+
{
|
|
1332
|
+
struct archive_write_disk *a = (struct archive_write_disk *)_a;
|
|
1333
|
+
archive_check_magic(&a->archive, ARCHIVE_WRITE_DISK_MAGIC,
|
|
1334
|
+
ARCHIVE_STATE_ANY, "archive_write_disk_gid");
|
|
1335
|
+
if (a->lookup_gid)
|
|
1336
|
+
return (a->lookup_gid)(a->lookup_gid_data, name, id);
|
|
1337
|
+
return (id);
|
|
1338
|
+
}
|
|
1339
|
+
|
|
1340
|
+
int64_t
|
|
1341
|
+
archive_write_disk_uid(struct archive *_a, const char *name, la_int64_t id)
|
|
1342
|
+
{
|
|
1343
|
+
struct archive_write_disk *a = (struct archive_write_disk *)_a;
|
|
1344
|
+
archive_check_magic(&a->archive, ARCHIVE_WRITE_DISK_MAGIC,
|
|
1345
|
+
ARCHIVE_STATE_ANY, "archive_write_disk_uid");
|
|
1346
|
+
if (a->lookup_uid)
|
|
1347
|
+
return (a->lookup_uid)(a->lookup_uid_data, name, id);
|
|
1348
|
+
return (id);
|
|
1349
|
+
}
|
|
1350
|
+
|
|
1351
|
+
/*
|
|
1352
|
+
* Create a new archive_write_disk object and initialize it with global state.
|
|
1353
|
+
*/
|
|
1354
|
+
struct archive *
|
|
1355
|
+
archive_write_disk_new(void)
|
|
1356
|
+
{
|
|
1357
|
+
struct archive_write_disk *a;
|
|
1358
|
+
|
|
1359
|
+
a = (struct archive_write_disk *)calloc(1, sizeof(*a));
|
|
1360
|
+
if (a == NULL)
|
|
1361
|
+
return (NULL);
|
|
1362
|
+
a->archive.magic = ARCHIVE_WRITE_DISK_MAGIC;
|
|
1363
|
+
/* We're ready to write a header immediately. */
|
|
1364
|
+
a->archive.state = ARCHIVE_STATE_HEADER;
|
|
1365
|
+
a->archive.vtable = &archive_write_disk_vtable;
|
|
1366
|
+
a->start_time = time(NULL);
|
|
1367
|
+
/* Query and restore the umask. */
|
|
1368
|
+
umask(a->user_umask = umask(0));
|
|
1369
|
+
if (archive_wstring_ensure(&a->path_safe, 512) == NULL) {
|
|
1370
|
+
free(a);
|
|
1371
|
+
return (NULL);
|
|
1372
|
+
}
|
|
1373
|
+
a->path_safe.s[0] = 0;
|
|
1374
|
+
return (&a->archive);
|
|
1375
|
+
}
|
|
1376
|
+
|
|
1377
|
+
static int
|
|
1378
|
+
disk_unlink(const wchar_t *path)
|
|
1379
|
+
{
|
|
1380
|
+
wchar_t *fullname;
|
|
1381
|
+
int r;
|
|
1382
|
+
|
|
1383
|
+
r = _wunlink(path);
|
|
1384
|
+
if (r != 0 && GetLastError() == ERROR_INVALID_NAME) {
|
|
1385
|
+
fullname = __la_win_permissive_name_w(path);
|
|
1386
|
+
r = _wunlink(fullname);
|
|
1387
|
+
free(fullname);
|
|
1388
|
+
}
|
|
1389
|
+
return (r);
|
|
1390
|
+
}
|
|
1391
|
+
|
|
1392
|
+
static int
|
|
1393
|
+
disk_rmdir(const wchar_t *path)
|
|
1394
|
+
{
|
|
1395
|
+
wchar_t *fullname;
|
|
1396
|
+
int r;
|
|
1397
|
+
|
|
1398
|
+
r = _wrmdir(path);
|
|
1399
|
+
if (r != 0 && GetLastError() == ERROR_INVALID_NAME) {
|
|
1400
|
+
fullname = __la_win_permissive_name_w(path);
|
|
1401
|
+
r = _wrmdir(fullname);
|
|
1402
|
+
free(fullname);
|
|
1403
|
+
}
|
|
1404
|
+
return (r);
|
|
1405
|
+
}
|
|
1406
|
+
|
|
1407
|
+
/*
|
|
1408
|
+
* The main restore function.
|
|
1409
|
+
*/
|
|
1410
|
+
static int
|
|
1411
|
+
restore_entry(struct archive_write_disk *a)
|
|
1412
|
+
{
|
|
1413
|
+
int ret = ARCHIVE_OK, en;
|
|
1414
|
+
|
|
1415
|
+
if (a->flags & ARCHIVE_EXTRACT_UNLINK && !S_ISDIR(a->mode)) {
|
|
1416
|
+
/*
|
|
1417
|
+
* TODO: Fix this. Apparently, there are platforms
|
|
1418
|
+
* that still allow root to hose the entire filesystem
|
|
1419
|
+
* by unlinking a dir. The S_ISDIR() test above
|
|
1420
|
+
* prevents us from using unlink() here if the new
|
|
1421
|
+
* object is a dir, but that doesn't mean the old
|
|
1422
|
+
* object isn't a dir.
|
|
1423
|
+
*/
|
|
1424
|
+
if (a->flags & ARCHIVE_EXTRACT_CLEAR_NOCHANGE_FFLAGS)
|
|
1425
|
+
(void)clear_nochange_fflags(a);
|
|
1426
|
+
if (disk_unlink(a->name) == 0) {
|
|
1427
|
+
/* We removed it, reset cached stat. */
|
|
1428
|
+
a->pst = NULL;
|
|
1429
|
+
} else if (errno == ENOENT) {
|
|
1430
|
+
/* File didn't exist, that's just as good. */
|
|
1431
|
+
} else if (disk_rmdir(a->name) == 0) {
|
|
1432
|
+
/* It was a dir, but now it's gone. */
|
|
1433
|
+
a->pst = NULL;
|
|
1434
|
+
} else {
|
|
1435
|
+
/* We tried, but couldn't get rid of it. */
|
|
1436
|
+
archive_set_error(&a->archive, errno,
|
|
1437
|
+
"Could not unlink");
|
|
1438
|
+
return(ARCHIVE_FAILED);
|
|
1439
|
+
}
|
|
1440
|
+
}
|
|
1441
|
+
|
|
1442
|
+
/* Try creating it first; if this fails, we'll try to recover. */
|
|
1443
|
+
en = create_filesystem_object(a);
|
|
1444
|
+
|
|
1445
|
+
if ((en == ENOTDIR || en == ENOENT)
|
|
1446
|
+
&& !(a->flags & ARCHIVE_EXTRACT_NO_AUTODIR)) {
|
|
1447
|
+
wchar_t *full;
|
|
1448
|
+
/* If the parent dir doesn't exist, try creating it. */
|
|
1449
|
+
create_parent_dir(a, a->name);
|
|
1450
|
+
/* Now try to create the object again. */
|
|
1451
|
+
full = __la_win_permissive_name_w(a->name);
|
|
1452
|
+
if (full == NULL) {
|
|
1453
|
+
en = EINVAL;
|
|
1454
|
+
} else {
|
|
1455
|
+
/* Remove multiple directories such as "a/../b../c" */
|
|
1456
|
+
archive_wstrcpy(&(a->_name_data), full);
|
|
1457
|
+
a->name = a->_name_data.s;
|
|
1458
|
+
free(full);
|
|
1459
|
+
en = create_filesystem_object(a);
|
|
1460
|
+
}
|
|
1461
|
+
}
|
|
1462
|
+
|
|
1463
|
+
if ((en == ENOENT) && (archive_entry_hardlink(a->entry) != NULL)) {
|
|
1464
|
+
archive_set_error(&a->archive, en,
|
|
1465
|
+
"Hard-link target '%s' does not exist.",
|
|
1466
|
+
archive_entry_hardlink(a->entry));
|
|
1467
|
+
return (ARCHIVE_FAILED);
|
|
1468
|
+
}
|
|
1469
|
+
|
|
1470
|
+
if ((en == EISDIR || en == EEXIST)
|
|
1471
|
+
&& (a->flags & ARCHIVE_EXTRACT_NO_OVERWRITE)) {
|
|
1472
|
+
/* If we're not overwriting, we're done. */
|
|
1473
|
+
if (S_ISDIR(a->mode)) {
|
|
1474
|
+
/* Don't overwrite any settings on existing directories. */
|
|
1475
|
+
a->todo = 0;
|
|
1476
|
+
}
|
|
1477
|
+
archive_entry_unset_size(a->entry);
|
|
1478
|
+
return (ARCHIVE_OK);
|
|
1479
|
+
}
|
|
1480
|
+
|
|
1481
|
+
/*
|
|
1482
|
+
* Some platforms return EISDIR if you call
|
|
1483
|
+
* open(O_WRONLY | O_EXCL | O_CREAT) on a directory, some
|
|
1484
|
+
* return EEXIST. POSIX is ambiguous, requiring EISDIR
|
|
1485
|
+
* for open(O_WRONLY) on a dir and EEXIST for open(O_EXCL | O_CREAT)
|
|
1486
|
+
* on an existing item.
|
|
1487
|
+
*/
|
|
1488
|
+
if (en == EISDIR) {
|
|
1489
|
+
/* A dir is in the way of a non-dir, rmdir it. */
|
|
1490
|
+
if (disk_rmdir(a->name) != 0) {
|
|
1491
|
+
archive_set_error(&a->archive, errno,
|
|
1492
|
+
"Can't remove already-existing dir");
|
|
1493
|
+
return (ARCHIVE_FAILED);
|
|
1494
|
+
}
|
|
1495
|
+
a->pst = NULL;
|
|
1496
|
+
/* Try again. */
|
|
1497
|
+
en = create_filesystem_object(a);
|
|
1498
|
+
} else if (en == EEXIST) {
|
|
1499
|
+
mode_t st_mode;
|
|
1500
|
+
mode_t lst_mode;
|
|
1501
|
+
BY_HANDLE_FILE_INFORMATION lst;
|
|
1502
|
+
/*
|
|
1503
|
+
* We know something is in the way, but we don't know what;
|
|
1504
|
+
* we need to find out before we go any further.
|
|
1505
|
+
*/
|
|
1506
|
+
int r = 0;
|
|
1507
|
+
int dirlnk = 0;
|
|
1508
|
+
|
|
1509
|
+
/*
|
|
1510
|
+
* The SECURE_SYMLINK logic has already removed a
|
|
1511
|
+
* symlink to a dir if the client wants that. So
|
|
1512
|
+
* follow the symlink if we're creating a dir.
|
|
1513
|
+
* If it's not a dir (or it's a broken symlink),
|
|
1514
|
+
* then don't follow it.
|
|
1515
|
+
*
|
|
1516
|
+
* Windows distinguishes file and directory symlinks.
|
|
1517
|
+
* A file symlink may erroneously point to a directory
|
|
1518
|
+
* and a directory symlink to a file. Windows does not follow
|
|
1519
|
+
* such symlinks. We always need both source and target
|
|
1520
|
+
* information.
|
|
1521
|
+
*/
|
|
1522
|
+
r = file_information(a, a->name, &lst, &lst_mode, 1);
|
|
1523
|
+
if (r != 0) {
|
|
1524
|
+
archive_set_error(&a->archive, errno,
|
|
1525
|
+
"Can't stat existing object");
|
|
1526
|
+
return (ARCHIVE_FAILED);
|
|
1527
|
+
} else if (S_ISLNK(lst_mode)) {
|
|
1528
|
+
if (lst.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
|
|
1529
|
+
dirlnk = 1;
|
|
1530
|
+
/* In case of a symlink we need target information */
|
|
1531
|
+
r = file_information(a, a->name, &a->st, &st_mode, 0);
|
|
1532
|
+
if (r != 0) {
|
|
1533
|
+
a->st = lst;
|
|
1534
|
+
st_mode = lst_mode;
|
|
1535
|
+
}
|
|
1536
|
+
} else {
|
|
1537
|
+
a->st = lst;
|
|
1538
|
+
st_mode = lst_mode;
|
|
1539
|
+
}
|
|
1540
|
+
|
|
1541
|
+
/*
|
|
1542
|
+
* NO_OVERWRITE_NEWER doesn't apply to directories.
|
|
1543
|
+
*/
|
|
1544
|
+
if ((a->flags & ARCHIVE_EXTRACT_NO_OVERWRITE_NEWER)
|
|
1545
|
+
&& !S_ISDIR(st_mode)) {
|
|
1546
|
+
if (!older(&(a->st), a->entry)) {
|
|
1547
|
+
archive_entry_unset_size(a->entry);
|
|
1548
|
+
return (ARCHIVE_OK);
|
|
1549
|
+
}
|
|
1550
|
+
}
|
|
1551
|
+
|
|
1552
|
+
/* If it's our archive, we're done. */
|
|
1553
|
+
if (a->skip_file_set &&
|
|
1554
|
+
bhfi_dev(&a->st) == a->skip_file_dev &&
|
|
1555
|
+
bhfi_ino(&a->st) == a->skip_file_ino) {
|
|
1556
|
+
archive_set_error(&a->archive, 0,
|
|
1557
|
+
"Refusing to overwrite archive");
|
|
1558
|
+
return (ARCHIVE_FAILED);
|
|
1559
|
+
}
|
|
1560
|
+
|
|
1561
|
+
if (!S_ISDIR(st_mode)) {
|
|
1562
|
+
if (a->flags &
|
|
1563
|
+
ARCHIVE_EXTRACT_CLEAR_NOCHANGE_FFLAGS) {
|
|
1564
|
+
(void)clear_nochange_fflags(a);
|
|
1565
|
+
}
|
|
1566
|
+
if ((a->flags & ARCHIVE_EXTRACT_SAFE_WRITES) &&
|
|
1567
|
+
S_ISREG(st_mode)) {
|
|
1568
|
+
int fd = la_mktemp(a);
|
|
1569
|
+
|
|
1570
|
+
if (fd == -1) {
|
|
1571
|
+
la_dosmaperr(GetLastError());
|
|
1572
|
+
archive_set_error(&a->archive, errno,
|
|
1573
|
+
"Can't create temporary file");
|
|
1574
|
+
return (ARCHIVE_FAILED);
|
|
1575
|
+
}
|
|
1576
|
+
a->fh = (HANDLE)_get_osfhandle(fd);
|
|
1577
|
+
if (a->fh == INVALID_HANDLE_VALUE) {
|
|
1578
|
+
la_dosmaperr(GetLastError());
|
|
1579
|
+
return (ARCHIVE_FAILED);
|
|
1580
|
+
}
|
|
1581
|
+
a->pst = NULL;
|
|
1582
|
+
en = 0;
|
|
1583
|
+
} else {
|
|
1584
|
+
if (dirlnk) {
|
|
1585
|
+
/* Edge case: dir symlink pointing
|
|
1586
|
+
* to a file */
|
|
1587
|
+
if (disk_rmdir(a->name) != 0) {
|
|
1588
|
+
archive_set_error(&a->archive,
|
|
1589
|
+
errno, "Can't unlink "
|
|
1590
|
+
"directory symlink");
|
|
1591
|
+
return (ARCHIVE_FAILED);
|
|
1592
|
+
}
|
|
1593
|
+
} else {
|
|
1594
|
+
if (disk_unlink(a->name) != 0) {
|
|
1595
|
+
/* A non-dir is in the way,
|
|
1596
|
+
* unlink it. */
|
|
1597
|
+
archive_set_error(&a->archive,
|
|
1598
|
+
errno, "Can't unlink "
|
|
1599
|
+
"already-existing object");
|
|
1600
|
+
return (ARCHIVE_FAILED);
|
|
1601
|
+
}
|
|
1602
|
+
}
|
|
1603
|
+
a->pst = NULL;
|
|
1604
|
+
/* Try again. */
|
|
1605
|
+
en = create_filesystem_object(a);
|
|
1606
|
+
}
|
|
1607
|
+
} else if (!S_ISDIR(a->mode)) {
|
|
1608
|
+
/* A dir is in the way of a non-dir, rmdir it. */
|
|
1609
|
+
if (a->flags & ARCHIVE_EXTRACT_CLEAR_NOCHANGE_FFLAGS)
|
|
1610
|
+
(void)clear_nochange_fflags(a);
|
|
1611
|
+
if (disk_rmdir(a->name) != 0) {
|
|
1612
|
+
archive_set_error(&a->archive, errno,
|
|
1613
|
+
"Can't remove already-existing dir");
|
|
1614
|
+
return (ARCHIVE_FAILED);
|
|
1615
|
+
}
|
|
1616
|
+
/* Try again. */
|
|
1617
|
+
en = create_filesystem_object(a);
|
|
1618
|
+
} else {
|
|
1619
|
+
/*
|
|
1620
|
+
* There's a dir in the way of a dir. Don't
|
|
1621
|
+
* waste time with rmdir()/mkdir(), just fix
|
|
1622
|
+
* up the permissions on the existing dir.
|
|
1623
|
+
* Note that we don't change perms on existing
|
|
1624
|
+
* dirs unless _EXTRACT_PERM is specified.
|
|
1625
|
+
*/
|
|
1626
|
+
if ((a->mode != st_mode)
|
|
1627
|
+
&& (a->todo & TODO_MODE_FORCE))
|
|
1628
|
+
a->deferred |= (a->todo & TODO_MODE);
|
|
1629
|
+
/* Ownership doesn't need deferred fixup. */
|
|
1630
|
+
en = 0; /* Forget the EEXIST. */
|
|
1631
|
+
}
|
|
1632
|
+
}
|
|
1633
|
+
|
|
1634
|
+
if (en) {
|
|
1635
|
+
/* Everything failed; give up here. */
|
|
1636
|
+
archive_set_error(&a->archive, en, "Can't create '%ls'",
|
|
1637
|
+
a->name);
|
|
1638
|
+
return (ARCHIVE_FAILED);
|
|
1639
|
+
}
|
|
1640
|
+
|
|
1641
|
+
a->pst = NULL; /* Cached stat data no longer valid. */
|
|
1642
|
+
return (ret);
|
|
1643
|
+
}
|
|
1644
|
+
|
|
1645
|
+
/*
|
|
1646
|
+
* Returns 0 if creation succeeds, or else returns errno value from
|
|
1647
|
+
* the failed system call. Note: This function should only ever perform
|
|
1648
|
+
* a single system call.
|
|
1649
|
+
*/
|
|
1650
|
+
static int
|
|
1651
|
+
create_filesystem_object(struct archive_write_disk *a)
|
|
1652
|
+
{
|
|
1653
|
+
/* Create the entry. */
|
|
1654
|
+
const wchar_t *linkname;
|
|
1655
|
+
wchar_t *fullname;
|
|
1656
|
+
mode_t final_mode, mode;
|
|
1657
|
+
int r;
|
|
1658
|
+
DWORD attrs = 0;
|
|
1659
|
+
|
|
1660
|
+
/* We identify hard/symlinks according to the link names. */
|
|
1661
|
+
/* Since link(2) and symlink(2) don't handle modes, we're done here. */
|
|
1662
|
+
linkname = archive_entry_hardlink_w(a->entry);
|
|
1663
|
+
if (linkname != NULL) {
|
|
1664
|
+
wchar_t *linksanitized, *linkfull, *namefull;
|
|
1665
|
+
size_t l = (wcslen(linkname) + 1) * sizeof(wchar_t);
|
|
1666
|
+
linksanitized = malloc(l);
|
|
1667
|
+
if (linksanitized == NULL) {
|
|
1668
|
+
archive_set_error(&a->archive, ENOMEM,
|
|
1669
|
+
"Can't allocate memory for hardlink target");
|
|
1670
|
+
return (-1);
|
|
1671
|
+
}
|
|
1672
|
+
memcpy(linksanitized, linkname, l);
|
|
1673
|
+
r = cleanup_pathname(a, linksanitized);
|
|
1674
|
+
if (r != ARCHIVE_OK) {
|
|
1675
|
+
free(linksanitized);
|
|
1676
|
+
return (r);
|
|
1677
|
+
}
|
|
1678
|
+
linkfull = __la_win_permissive_name_w(linksanitized);
|
|
1679
|
+
free(linksanitized);
|
|
1680
|
+
namefull = __la_win_permissive_name_w(a->name);
|
|
1681
|
+
if (linkfull == NULL || namefull == NULL) {
|
|
1682
|
+
errno = EINVAL;
|
|
1683
|
+
r = -1;
|
|
1684
|
+
} else {
|
|
1685
|
+
/*
|
|
1686
|
+
* Unlinking and linking here is really not atomic,
|
|
1687
|
+
* but doing it right, would require us to construct
|
|
1688
|
+
* an mktemplink() function, and then use _wrename().
|
|
1689
|
+
*/
|
|
1690
|
+
if (a->flags & ARCHIVE_EXTRACT_SAFE_WRITES) {
|
|
1691
|
+
attrs = GetFileAttributesW(namefull);
|
|
1692
|
+
if (attrs != INVALID_FILE_ATTRIBUTES) {
|
|
1693
|
+
if (attrs & FILE_ATTRIBUTE_DIRECTORY)
|
|
1694
|
+
disk_rmdir(namefull);
|
|
1695
|
+
else
|
|
1696
|
+
disk_unlink(namefull);
|
|
1697
|
+
}
|
|
1698
|
+
}
|
|
1699
|
+
r = la_CreateHardLinkW(namefull, linkfull);
|
|
1700
|
+
if (r == 0) {
|
|
1701
|
+
la_dosmaperr(GetLastError());
|
|
1702
|
+
r = errno;
|
|
1703
|
+
} else
|
|
1704
|
+
r = 0;
|
|
1705
|
+
}
|
|
1706
|
+
/*
|
|
1707
|
+
* New cpio and pax formats allow hardlink entries
|
|
1708
|
+
* to carry data, so we may have to open the file
|
|
1709
|
+
* for hardlink entries.
|
|
1710
|
+
*
|
|
1711
|
+
* If the hardlink was successfully created and
|
|
1712
|
+
* the archive doesn't have carry data for it,
|
|
1713
|
+
* consider it to be non-authoritative for meta data.
|
|
1714
|
+
* This is consistent with GNU tar and BSD pax.
|
|
1715
|
+
* If the hardlink does carry data, let the last
|
|
1716
|
+
* archive entry decide ownership.
|
|
1717
|
+
*/
|
|
1718
|
+
if (r == 0 && a->filesize <= 0) {
|
|
1719
|
+
a->todo = 0;
|
|
1720
|
+
a->deferred = 0;
|
|
1721
|
+
} else if (r == 0 && a->filesize > 0) {
|
|
1722
|
+
a->fh = CreateFileW(namefull, GENERIC_WRITE, 0, NULL,
|
|
1723
|
+
TRUNCATE_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
|
|
1724
|
+
if (a->fh == INVALID_HANDLE_VALUE) {
|
|
1725
|
+
la_dosmaperr(GetLastError());
|
|
1726
|
+
r = errno;
|
|
1727
|
+
}
|
|
1728
|
+
}
|
|
1729
|
+
free(linkfull);
|
|
1730
|
+
free(namefull);
|
|
1731
|
+
return (r);
|
|
1732
|
+
}
|
|
1733
|
+
linkname = archive_entry_symlink_w(a->entry);
|
|
1734
|
+
if (linkname != NULL) {
|
|
1735
|
+
/*
|
|
1736
|
+
* Unlinking and linking here is really not atomic,
|
|
1737
|
+
* but doing it right, would require us to construct
|
|
1738
|
+
* an mktemplink() function, and then use _wrename().
|
|
1739
|
+
*/
|
|
1740
|
+
attrs = GetFileAttributesW(a->name);
|
|
1741
|
+
if (attrs != INVALID_FILE_ATTRIBUTES) {
|
|
1742
|
+
if (attrs & FILE_ATTRIBUTE_DIRECTORY)
|
|
1743
|
+
disk_rmdir(a->name);
|
|
1744
|
+
else
|
|
1745
|
+
disk_unlink(a->name);
|
|
1746
|
+
}
|
|
1747
|
+
#if HAVE_SYMLINK
|
|
1748
|
+
return symlink(linkname, a->name) ? errno : 0;
|
|
1749
|
+
#else
|
|
1750
|
+
errno = 0;
|
|
1751
|
+
r = la_CreateSymbolicLinkW((const wchar_t *)a->name, linkname,
|
|
1752
|
+
archive_entry_symlink_type(a->entry));
|
|
1753
|
+
if (r == 0) {
|
|
1754
|
+
if (errno == 0)
|
|
1755
|
+
la_dosmaperr(GetLastError());
|
|
1756
|
+
r = errno;
|
|
1757
|
+
} else
|
|
1758
|
+
r = 0;
|
|
1759
|
+
return (r);
|
|
1760
|
+
#endif
|
|
1761
|
+
}
|
|
1762
|
+
|
|
1763
|
+
/*
|
|
1764
|
+
* The remaining system calls all set permissions, so let's
|
|
1765
|
+
* try to take advantage of that to avoid an extra chmod()
|
|
1766
|
+
* call. (Recall that umask is set to zero right now!)
|
|
1767
|
+
*/
|
|
1768
|
+
|
|
1769
|
+
/* Mode we want for the final restored object (w/o file type bits). */
|
|
1770
|
+
final_mode = a->mode & 07777;
|
|
1771
|
+
/*
|
|
1772
|
+
* The mode that will actually be restored in this step. Note
|
|
1773
|
+
* that SUID, SGID, etc, require additional work to ensure
|
|
1774
|
+
* security, so we never restore them at this point.
|
|
1775
|
+
*/
|
|
1776
|
+
mode = final_mode & 0777 & ~a->user_umask;
|
|
1777
|
+
|
|
1778
|
+
switch (a->mode & AE_IFMT) {
|
|
1779
|
+
default:
|
|
1780
|
+
/* POSIX requires that we fall through here. */
|
|
1781
|
+
/* FALLTHROUGH */
|
|
1782
|
+
case AE_IFREG:
|
|
1783
|
+
a->tmpname = NULL;
|
|
1784
|
+
fullname = a->name;
|
|
1785
|
+
/* O_WRONLY | O_CREAT | O_EXCL */
|
|
1786
|
+
a->fh = CreateFileW(fullname, GENERIC_WRITE, 0, NULL,
|
|
1787
|
+
CREATE_NEW, FILE_ATTRIBUTE_NORMAL, NULL);
|
|
1788
|
+
if (a->fh == INVALID_HANDLE_VALUE &&
|
|
1789
|
+
GetLastError() == ERROR_INVALID_NAME &&
|
|
1790
|
+
fullname == a->name) {
|
|
1791
|
+
fullname = __la_win_permissive_name_w(a->name);
|
|
1792
|
+
a->fh = CreateFileW(fullname, GENERIC_WRITE, 0, NULL,
|
|
1793
|
+
CREATE_NEW, FILE_ATTRIBUTE_NORMAL, NULL);
|
|
1794
|
+
}
|
|
1795
|
+
if (a->fh == INVALID_HANDLE_VALUE) {
|
|
1796
|
+
if (GetLastError() == ERROR_ACCESS_DENIED) {
|
|
1797
|
+
DWORD attr;
|
|
1798
|
+
/* Simulate an errno of POSIX system. */
|
|
1799
|
+
attr = GetFileAttributesW(fullname);
|
|
1800
|
+
if (attr == (DWORD)-1)
|
|
1801
|
+
la_dosmaperr(GetLastError());
|
|
1802
|
+
else if (attr & FILE_ATTRIBUTE_DIRECTORY)
|
|
1803
|
+
errno = EISDIR;
|
|
1804
|
+
else
|
|
1805
|
+
errno = EACCES;
|
|
1806
|
+
} else
|
|
1807
|
+
la_dosmaperr(GetLastError());
|
|
1808
|
+
r = 1;
|
|
1809
|
+
} else
|
|
1810
|
+
r = 0;
|
|
1811
|
+
if (fullname != a->name)
|
|
1812
|
+
free(fullname);
|
|
1813
|
+
break;
|
|
1814
|
+
case AE_IFCHR:
|
|
1815
|
+
case AE_IFBLK:
|
|
1816
|
+
/* TODO: Find a better way to warn about our inability
|
|
1817
|
+
* to restore a block device node. */
|
|
1818
|
+
return (EINVAL);
|
|
1819
|
+
case AE_IFDIR:
|
|
1820
|
+
mode = (mode | MINIMUM_DIR_MODE) & MAXIMUM_DIR_MODE;
|
|
1821
|
+
fullname = a->name;
|
|
1822
|
+
r = CreateDirectoryW(fullname, NULL);
|
|
1823
|
+
if (r == 0 && GetLastError() == ERROR_INVALID_NAME &&
|
|
1824
|
+
fullname == a->name) {
|
|
1825
|
+
fullname = __la_win_permissive_name_w(a->name);
|
|
1826
|
+
r = CreateDirectoryW(fullname, NULL);
|
|
1827
|
+
}
|
|
1828
|
+
if (r != 0) {
|
|
1829
|
+
r = 0;
|
|
1830
|
+
/* Defer setting dir times. */
|
|
1831
|
+
a->deferred |= (a->todo & TODO_TIMES);
|
|
1832
|
+
a->todo &= ~TODO_TIMES;
|
|
1833
|
+
/* Never use an immediate chmod(). */
|
|
1834
|
+
/* We can't avoid the chmod() entirely if EXTRACT_PERM
|
|
1835
|
+
* because of SysV SGID inheritance. */
|
|
1836
|
+
if ((mode != final_mode)
|
|
1837
|
+
|| (a->flags & ARCHIVE_EXTRACT_PERM))
|
|
1838
|
+
a->deferred |= (a->todo & TODO_MODE);
|
|
1839
|
+
a->todo &= ~TODO_MODE;
|
|
1840
|
+
} else {
|
|
1841
|
+
la_dosmaperr(GetLastError());
|
|
1842
|
+
r = -1;
|
|
1843
|
+
}
|
|
1844
|
+
if (fullname != a->name)
|
|
1845
|
+
free(fullname);
|
|
1846
|
+
break;
|
|
1847
|
+
case AE_IFIFO:
|
|
1848
|
+
/* TODO: Find a better way to warn about our inability
|
|
1849
|
+
* to restore a fifo. */
|
|
1850
|
+
return (EINVAL);
|
|
1851
|
+
}
|
|
1852
|
+
|
|
1853
|
+
/* All the system calls above set errno on failure. */
|
|
1854
|
+
if (r)
|
|
1855
|
+
return (errno);
|
|
1856
|
+
|
|
1857
|
+
/* If we managed to set the final mode, we've avoided a chmod(). */
|
|
1858
|
+
if (mode == final_mode)
|
|
1859
|
+
a->todo &= ~TODO_MODE;
|
|
1860
|
+
return (0);
|
|
1861
|
+
}
|
|
1862
|
+
|
|
1863
|
+
/*
|
|
1864
|
+
* Cleanup function for archive_extract. Mostly, this involves processing
|
|
1865
|
+
* the fixup list, which is used to address a number of problems:
|
|
1866
|
+
* * Dir permissions might prevent us from restoring a file in that
|
|
1867
|
+
* dir, so we restore the dir with minimum 0700 permissions first,
|
|
1868
|
+
* then correct the mode at the end.
|
|
1869
|
+
* * Similarly, the act of restoring a file touches the directory
|
|
1870
|
+
* and changes the timestamp on the dir, so we have to touch-up dir
|
|
1871
|
+
* timestamps at the end as well.
|
|
1872
|
+
* * Some file flags can interfere with the restore by, for example,
|
|
1873
|
+
* preventing the creation of hardlinks to those files.
|
|
1874
|
+
* * Mac OS extended metadata includes ACLs, so must be deferred on dirs.
|
|
1875
|
+
*
|
|
1876
|
+
* Note that tar/cpio do not require that archives be in a particular
|
|
1877
|
+
* order; there is no way to know when the last file has been restored
|
|
1878
|
+
* within a directory, so there's no way to optimize the memory usage
|
|
1879
|
+
* here by fixing up the directory any earlier than the
|
|
1880
|
+
* end-of-archive.
|
|
1881
|
+
*
|
|
1882
|
+
* XXX TODO: Directory ACLs should be restored here, for the same
|
|
1883
|
+
* reason we set directory perms here. XXX
|
|
1884
|
+
*/
|
|
1885
|
+
static int
|
|
1886
|
+
_archive_write_disk_close(struct archive *_a)
|
|
1887
|
+
{
|
|
1888
|
+
struct archive_write_disk *a = (struct archive_write_disk *)_a;
|
|
1889
|
+
struct fixup_entry *next, *p;
|
|
1890
|
+
int ret;
|
|
1891
|
+
|
|
1892
|
+
archive_check_magic(&a->archive, ARCHIVE_WRITE_DISK_MAGIC,
|
|
1893
|
+
ARCHIVE_STATE_HEADER | ARCHIVE_STATE_DATA,
|
|
1894
|
+
"archive_write_disk_close");
|
|
1895
|
+
ret = _archive_write_disk_finish_entry(&a->archive);
|
|
1896
|
+
|
|
1897
|
+
/* Sort dir list so directories are fixed up in depth-first order. */
|
|
1898
|
+
p = sort_dir_list(a->fixup_list);
|
|
1899
|
+
|
|
1900
|
+
while (p != NULL) {
|
|
1901
|
+
a->pst = NULL; /* Mark stat cache as out-of-date. */
|
|
1902
|
+
if (p->fixup & TODO_TIMES) {
|
|
1903
|
+
set_times(a, INVALID_HANDLE_VALUE, p->mode, p->name,
|
|
1904
|
+
p->atime, p->atime_nanos,
|
|
1905
|
+
p->birthtime, p->birthtime_nanos,
|
|
1906
|
+
p->mtime, p->mtime_nanos,
|
|
1907
|
+
p->ctime, p->ctime_nanos);
|
|
1908
|
+
}
|
|
1909
|
+
if (p->fixup & TODO_MODE_BASE)
|
|
1910
|
+
la_chmod(p->name, p->mode);
|
|
1911
|
+
if (p->fixup & TODO_ACLS)
|
|
1912
|
+
set_acls(a, INVALID_HANDLE_VALUE, p->name, &p->acl);
|
|
1913
|
+
if (p->fixup & TODO_FFLAGS)
|
|
1914
|
+
set_fflags_platform(p->name, p->fflags_set, 0);
|
|
1915
|
+
next = p->next;
|
|
1916
|
+
archive_acl_clear(&p->acl);
|
|
1917
|
+
free(p->name);
|
|
1918
|
+
free(p);
|
|
1919
|
+
p = next;
|
|
1920
|
+
}
|
|
1921
|
+
a->fixup_list = NULL;
|
|
1922
|
+
return (ret);
|
|
1923
|
+
}
|
|
1924
|
+
|
|
1925
|
+
static int
|
|
1926
|
+
_archive_write_disk_free(struct archive *_a)
|
|
1927
|
+
{
|
|
1928
|
+
struct archive_write_disk *a;
|
|
1929
|
+
int ret;
|
|
1930
|
+
if (_a == NULL)
|
|
1931
|
+
return (ARCHIVE_OK);
|
|
1932
|
+
archive_check_magic(_a, ARCHIVE_WRITE_DISK_MAGIC,
|
|
1933
|
+
ARCHIVE_STATE_ANY | ARCHIVE_STATE_FATAL, "archive_write_disk_free");
|
|
1934
|
+
a = (struct archive_write_disk *)_a;
|
|
1935
|
+
ret = _archive_write_disk_close(&a->archive);
|
|
1936
|
+
archive_write_disk_set_group_lookup(&a->archive, NULL, NULL, NULL);
|
|
1937
|
+
archive_write_disk_set_user_lookup(&a->archive, NULL, NULL, NULL);
|
|
1938
|
+
archive_entry_free(a->entry);
|
|
1939
|
+
archive_wstring_free(&a->_name_data);
|
|
1940
|
+
archive_wstring_free(&a->_tmpname_data);
|
|
1941
|
+
archive_string_free(&a->archive.error_string);
|
|
1942
|
+
archive_wstring_free(&a->path_safe);
|
|
1943
|
+
a->archive.magic = 0;
|
|
1944
|
+
__archive_clean(&a->archive);
|
|
1945
|
+
free(a);
|
|
1946
|
+
return (ret);
|
|
1947
|
+
}
|
|
1948
|
+
|
|
1949
|
+
/*
|
|
1950
|
+
* Simple O(n log n) merge sort to order the fixup list. In
|
|
1951
|
+
* particular, we want to restore dir timestamps depth-first.
|
|
1952
|
+
*/
|
|
1953
|
+
static struct fixup_entry *
|
|
1954
|
+
sort_dir_list(struct fixup_entry *p)
|
|
1955
|
+
{
|
|
1956
|
+
struct fixup_entry *a, *b, *t;
|
|
1957
|
+
|
|
1958
|
+
if (p == NULL)
|
|
1959
|
+
return (NULL);
|
|
1960
|
+
/* A one-item list is already sorted. */
|
|
1961
|
+
if (p->next == NULL)
|
|
1962
|
+
return (p);
|
|
1963
|
+
|
|
1964
|
+
/* Step 1: split the list. */
|
|
1965
|
+
t = p;
|
|
1966
|
+
a = p->next->next;
|
|
1967
|
+
while (a != NULL) {
|
|
1968
|
+
/* Step a twice, t once. */
|
|
1969
|
+
a = a->next;
|
|
1970
|
+
if (a != NULL)
|
|
1971
|
+
a = a->next;
|
|
1972
|
+
t = t->next;
|
|
1973
|
+
}
|
|
1974
|
+
/* Now, t is at the mid-point, so break the list here. */
|
|
1975
|
+
b = t->next;
|
|
1976
|
+
t->next = NULL;
|
|
1977
|
+
a = p;
|
|
1978
|
+
|
|
1979
|
+
/* Step 2: Recursively sort the two sub-lists. */
|
|
1980
|
+
a = sort_dir_list(a);
|
|
1981
|
+
b = sort_dir_list(b);
|
|
1982
|
+
|
|
1983
|
+
/* Step 3: Merge the returned lists. */
|
|
1984
|
+
/* Pick the first element for the merged list. */
|
|
1985
|
+
if (wcscmp(a->name, b->name) > 0) {
|
|
1986
|
+
t = p = a;
|
|
1987
|
+
a = a->next;
|
|
1988
|
+
} else {
|
|
1989
|
+
t = p = b;
|
|
1990
|
+
b = b->next;
|
|
1991
|
+
}
|
|
1992
|
+
|
|
1993
|
+
/* Always put the later element on the list first. */
|
|
1994
|
+
while (a != NULL && b != NULL) {
|
|
1995
|
+
if (wcscmp(a->name, b->name) > 0) {
|
|
1996
|
+
t->next = a;
|
|
1997
|
+
a = a->next;
|
|
1998
|
+
} else {
|
|
1999
|
+
t->next = b;
|
|
2000
|
+
b = b->next;
|
|
2001
|
+
}
|
|
2002
|
+
t = t->next;
|
|
2003
|
+
}
|
|
2004
|
+
|
|
2005
|
+
/* Only one list is non-empty, so just splice it on. */
|
|
2006
|
+
if (a != NULL)
|
|
2007
|
+
t->next = a;
|
|
2008
|
+
if (b != NULL)
|
|
2009
|
+
t->next = b;
|
|
2010
|
+
|
|
2011
|
+
return (p);
|
|
2012
|
+
}
|
|
2013
|
+
|
|
2014
|
+
/*
|
|
2015
|
+
* Returns a new, initialized fixup entry.
|
|
2016
|
+
*
|
|
2017
|
+
* TODO: Reduce the memory requirements for this list by using a tree
|
|
2018
|
+
* structure rather than a simple list of names.
|
|
2019
|
+
*/
|
|
2020
|
+
static struct fixup_entry *
|
|
2021
|
+
new_fixup(struct archive_write_disk *a, const wchar_t *pathname)
|
|
2022
|
+
{
|
|
2023
|
+
struct fixup_entry *fe;
|
|
2024
|
+
|
|
2025
|
+
fe = (struct fixup_entry *)calloc(1, sizeof(struct fixup_entry));
|
|
2026
|
+
if (fe == NULL)
|
|
2027
|
+
return (NULL);
|
|
2028
|
+
fe->next = a->fixup_list;
|
|
2029
|
+
a->fixup_list = fe;
|
|
2030
|
+
fe->fixup = 0;
|
|
2031
|
+
fe->name = _wcsdup(pathname);
|
|
2032
|
+
fe->fflags_set = 0;
|
|
2033
|
+
return (fe);
|
|
2034
|
+
}
|
|
2035
|
+
|
|
2036
|
+
/*
|
|
2037
|
+
* Returns a fixup structure for the current entry.
|
|
2038
|
+
*/
|
|
2039
|
+
static struct fixup_entry *
|
|
2040
|
+
current_fixup(struct archive_write_disk *a, const wchar_t *pathname)
|
|
2041
|
+
{
|
|
2042
|
+
if (a->current_fixup == NULL)
|
|
2043
|
+
a->current_fixup = new_fixup(a, pathname);
|
|
2044
|
+
return (a->current_fixup);
|
|
2045
|
+
}
|
|
2046
|
+
|
|
2047
|
+
/*
|
|
2048
|
+
* TODO: The deep-directory support bypasses this; disable deep directory
|
|
2049
|
+
* support if we're doing symlink checks.
|
|
2050
|
+
*/
|
|
2051
|
+
/*
|
|
2052
|
+
* TODO: Someday, integrate this with the deep dir support; they both
|
|
2053
|
+
* scan the path and both can be optimized by comparing against other
|
|
2054
|
+
* recent paths.
|
|
2055
|
+
*/
|
|
2056
|
+
static int
|
|
2057
|
+
check_symlinks(struct archive_write_disk *a)
|
|
2058
|
+
{
|
|
2059
|
+
wchar_t *pn, *p;
|
|
2060
|
+
wchar_t c;
|
|
2061
|
+
int r;
|
|
2062
|
+
BY_HANDLE_FILE_INFORMATION st;
|
|
2063
|
+
mode_t st_mode;
|
|
2064
|
+
|
|
2065
|
+
/*
|
|
2066
|
+
* Guard against symlink tricks. Reject any archive entry whose
|
|
2067
|
+
* destination would be altered by a symlink.
|
|
2068
|
+
*/
|
|
2069
|
+
/* Whatever we checked last time doesn't need to be re-checked. */
|
|
2070
|
+
pn = a->name;
|
|
2071
|
+
p = a->path_safe.s;
|
|
2072
|
+
while ((*pn != '\0') && (*p == *pn))
|
|
2073
|
+
++p, ++pn;
|
|
2074
|
+
/* Skip leading backslashes */
|
|
2075
|
+
while (*pn == '\\')
|
|
2076
|
+
++pn;
|
|
2077
|
+
c = pn[0];
|
|
2078
|
+
/* Keep going until we've checked the entire name. */
|
|
2079
|
+
while (pn[0] != '\0' && (pn[0] != '\\' || pn[1] != '\0')) {
|
|
2080
|
+
/* Skip the next path element. */
|
|
2081
|
+
while (*pn != '\0' && *pn != '\\')
|
|
2082
|
+
++pn;
|
|
2083
|
+
c = pn[0];
|
|
2084
|
+
pn[0] = '\0';
|
|
2085
|
+
/* Check that we haven't hit a symlink. */
|
|
2086
|
+
r = file_information(a, a->name, &st, &st_mode, 1);
|
|
2087
|
+
if (r != 0) {
|
|
2088
|
+
/* We've hit a dir that doesn't exist; stop now. */
|
|
2089
|
+
if (errno == ENOENT)
|
|
2090
|
+
break;
|
|
2091
|
+
} else if (S_ISLNK(st_mode)) {
|
|
2092
|
+
if (c == '\0') {
|
|
2093
|
+
/*
|
|
2094
|
+
* Last element is a file or directory symlink.
|
|
2095
|
+
* Remove it so we can overwrite it with the
|
|
2096
|
+
* item being extracted.
|
|
2097
|
+
*/
|
|
2098
|
+
if (a->flags &
|
|
2099
|
+
ARCHIVE_EXTRACT_CLEAR_NOCHANGE_FFLAGS) {
|
|
2100
|
+
(void)clear_nochange_fflags(a);
|
|
2101
|
+
}
|
|
2102
|
+
if (st.dwFileAttributes &
|
|
2103
|
+
FILE_ATTRIBUTE_DIRECTORY) {
|
|
2104
|
+
r = disk_rmdir(a->name);
|
|
2105
|
+
} else {
|
|
2106
|
+
r = disk_unlink(a->name);
|
|
2107
|
+
}
|
|
2108
|
+
if (r) {
|
|
2109
|
+
archive_set_error(&a->archive, errno,
|
|
2110
|
+
"Could not remove symlink %ls",
|
|
2111
|
+
a->name);
|
|
2112
|
+
pn[0] = c;
|
|
2113
|
+
return (ARCHIVE_FAILED);
|
|
2114
|
+
}
|
|
2115
|
+
a->pst = NULL;
|
|
2116
|
+
/*
|
|
2117
|
+
* Even if we did remove it, a warning
|
|
2118
|
+
* is in order. The warning is silly,
|
|
2119
|
+
* though, if we're just replacing one
|
|
2120
|
+
* symlink with another symlink.
|
|
2121
|
+
*/
|
|
2122
|
+
if (!S_ISLNK(a->mode)) {
|
|
2123
|
+
archive_set_error(&a->archive, 0,
|
|
2124
|
+
"Removing symlink %ls",
|
|
2125
|
+
a->name);
|
|
2126
|
+
}
|
|
2127
|
+
/* Symlink gone. No more problem! */
|
|
2128
|
+
pn[0] = c;
|
|
2129
|
+
return (0);
|
|
2130
|
+
} else if (a->flags & ARCHIVE_EXTRACT_UNLINK) {
|
|
2131
|
+
/* User asked us to remove problems. */
|
|
2132
|
+
if (a->flags &
|
|
2133
|
+
ARCHIVE_EXTRACT_CLEAR_NOCHANGE_FFLAGS) {
|
|
2134
|
+
(void)clear_nochange_fflags(a);
|
|
2135
|
+
}
|
|
2136
|
+
if (st.dwFileAttributes &
|
|
2137
|
+
FILE_ATTRIBUTE_DIRECTORY) {
|
|
2138
|
+
r = disk_rmdir(a->name);
|
|
2139
|
+
} else {
|
|
2140
|
+
r = disk_unlink(a->name);
|
|
2141
|
+
}
|
|
2142
|
+
if (r != 0) {
|
|
2143
|
+
archive_set_error(&a->archive, 0,
|
|
2144
|
+
"Cannot remove intervening "
|
|
2145
|
+
"symlink %ls", a->name);
|
|
2146
|
+
pn[0] = c;
|
|
2147
|
+
return (ARCHIVE_FAILED);
|
|
2148
|
+
}
|
|
2149
|
+
a->pst = NULL;
|
|
2150
|
+
} else {
|
|
2151
|
+
archive_set_error(&a->archive, 0,
|
|
2152
|
+
"Cannot extract through symlink %ls",
|
|
2153
|
+
a->name);
|
|
2154
|
+
pn[0] = c;
|
|
2155
|
+
return (ARCHIVE_FAILED);
|
|
2156
|
+
}
|
|
2157
|
+
}
|
|
2158
|
+
if (!c)
|
|
2159
|
+
break;
|
|
2160
|
+
pn[0] = c;
|
|
2161
|
+
pn++;
|
|
2162
|
+
}
|
|
2163
|
+
pn[0] = c;
|
|
2164
|
+
/* We've checked and/or cleaned the whole path, so remember it. */
|
|
2165
|
+
archive_wstrcpy(&a->path_safe, a->name);
|
|
2166
|
+
return (ARCHIVE_OK);
|
|
2167
|
+
}
|
|
2168
|
+
|
|
2169
|
+
static int
|
|
2170
|
+
guidword(wchar_t *p, int n)
|
|
2171
|
+
{
|
|
2172
|
+
int i;
|
|
2173
|
+
|
|
2174
|
+
for (i = 0; i < n; i++) {
|
|
2175
|
+
if ((*p >= L'0' && *p <= L'9') ||
|
|
2176
|
+
(*p >= L'a' && *p <= L'f') ||
|
|
2177
|
+
(*p >= L'A' && *p <= L'F'))
|
|
2178
|
+
p++;
|
|
2179
|
+
else
|
|
2180
|
+
return (-1);
|
|
2181
|
+
}
|
|
2182
|
+
return (0);
|
|
2183
|
+
}
|
|
2184
|
+
|
|
2185
|
+
/*
|
|
2186
|
+
* Canonicalize the pathname. In particular, this strips duplicate
|
|
2187
|
+
* '\' characters, '.' elements, and trailing '\'. It also raises an
|
|
2188
|
+
* error for an empty path, a trailing '..' or (if _SECURE_NODOTDOT is
|
|
2189
|
+
* set) any '..' in the path.
|
|
2190
|
+
*/
|
|
2191
|
+
static int
|
|
2192
|
+
cleanup_pathname(struct archive_write_disk *a, wchar_t *name)
|
|
2193
|
+
{
|
|
2194
|
+
wchar_t *dest, *src, *p, *top;
|
|
2195
|
+
wchar_t separator = L'\0';
|
|
2196
|
+
|
|
2197
|
+
p = name;
|
|
2198
|
+
if (*p == L'\0') {
|
|
2199
|
+
archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
|
|
2200
|
+
"Invalid empty pathname");
|
|
2201
|
+
return (ARCHIVE_FAILED);
|
|
2202
|
+
}
|
|
2203
|
+
|
|
2204
|
+
/* Replace '/' by '\' */
|
|
2205
|
+
for (; *p != L'\0'; p++) {
|
|
2206
|
+
if (*p == L'/')
|
|
2207
|
+
*p = L'\\';
|
|
2208
|
+
}
|
|
2209
|
+
p = name;
|
|
2210
|
+
|
|
2211
|
+
/* Skip leading "\\.\" or "\\?\" or "\\?\UNC\" or
|
|
2212
|
+
* "\\?\Volume{GUID}\"
|
|
2213
|
+
* (absolute path prefixes used by Windows API) */
|
|
2214
|
+
if (p[0] == L'\\' && p[1] == L'\\' &&
|
|
2215
|
+
(p[2] == L'.' || p[2] == L'?') && p[3] == L'\\')
|
|
2216
|
+
{
|
|
2217
|
+
/* A path begin with "\\?\UNC\" */
|
|
2218
|
+
if (p[2] == L'?' &&
|
|
2219
|
+
(p[4] == L'U' || p[4] == L'u') &&
|
|
2220
|
+
(p[5] == L'N' || p[5] == L'n') &&
|
|
2221
|
+
(p[6] == L'C' || p[6] == L'c') &&
|
|
2222
|
+
p[7] == L'\\')
|
|
2223
|
+
p += 8;
|
|
2224
|
+
/* A path begin with "\\?\Volume{GUID}\" */
|
|
2225
|
+
else if (p[2] == L'?' &&
|
|
2226
|
+
(p[4] == L'V' || p[4] == L'v') &&
|
|
2227
|
+
(p[5] == L'O' || p[5] == L'o') &&
|
|
2228
|
+
(p[6] == L'L' || p[6] == L'l') &&
|
|
2229
|
+
(p[7] == L'U' || p[7] == L'u') &&
|
|
2230
|
+
(p[8] == L'M' || p[8] == L'm') &&
|
|
2231
|
+
(p[9] == L'E' || p[9] == L'e') &&
|
|
2232
|
+
p[10] == L'{') {
|
|
2233
|
+
if (guidword(p+11, 8) == 0 && p[19] == L'-' &&
|
|
2234
|
+
guidword(p+20, 4) == 0 && p[24] == L'-' &&
|
|
2235
|
+
guidword(p+25, 4) == 0 && p[29] == L'-' &&
|
|
2236
|
+
guidword(p+30, 4) == 0 && p[34] == L'-' &&
|
|
2237
|
+
guidword(p+35, 12) == 0 && p[47] == L'}' &&
|
|
2238
|
+
p[48] == L'\\')
|
|
2239
|
+
p += 49;
|
|
2240
|
+
else
|
|
2241
|
+
p += 4;
|
|
2242
|
+
/* A path begin with "\\.\PhysicalDriveX" */
|
|
2243
|
+
} else if (p[2] == L'.' &&
|
|
2244
|
+
(p[4] == L'P' || p[4] == L'p') &&
|
|
2245
|
+
(p[5] == L'H' || p[5] == L'h') &&
|
|
2246
|
+
(p[6] == L'Y' || p[6] == L'y') &&
|
|
2247
|
+
(p[7] == L'S' || p[7] == L's') &&
|
|
2248
|
+
(p[8] == L'I' || p[8] == L'i') &&
|
|
2249
|
+
(p[9] == L'C' || p[9] == L'c') &&
|
|
2250
|
+
(p[9] == L'A' || p[9] == L'a') &&
|
|
2251
|
+
(p[9] == L'L' || p[9] == L'l') &&
|
|
2252
|
+
(p[9] == L'D' || p[9] == L'd') &&
|
|
2253
|
+
(p[9] == L'R' || p[9] == L'r') &&
|
|
2254
|
+
(p[9] == L'I' || p[9] == L'i') &&
|
|
2255
|
+
(p[9] == L'V' || p[9] == L'v') &&
|
|
2256
|
+
(p[9] == L'E' || p[9] == L'e') &&
|
|
2257
|
+
(p[10] >= L'0' && p[10] <= L'9') &&
|
|
2258
|
+
p[11] == L'\0') {
|
|
2259
|
+
archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
|
|
2260
|
+
"Path is a physical drive name");
|
|
2261
|
+
return (ARCHIVE_FAILED);
|
|
2262
|
+
} else
|
|
2263
|
+
p += 4;
|
|
2264
|
+
/* Network drive path like "\\<server-name>\<share-name>\file" */
|
|
2265
|
+
} else if (p[0] == L'\\' && p[1] == L'\\') {
|
|
2266
|
+
p += 2;
|
|
2267
|
+
}
|
|
2268
|
+
|
|
2269
|
+
/* Skip leading drive letter from archives created
|
|
2270
|
+
* on Windows. */
|
|
2271
|
+
if (((p[0] >= L'a' && p[0] <= L'z') ||
|
|
2272
|
+
(p[0] >= L'A' && p[0] <= L'Z')) &&
|
|
2273
|
+
p[1] == L':') {
|
|
2274
|
+
if (p[2] == L'\0') {
|
|
2275
|
+
archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
|
|
2276
|
+
"Path is a drive name");
|
|
2277
|
+
return (ARCHIVE_FAILED);
|
|
2278
|
+
}
|
|
2279
|
+
if (p[2] == L'\\')
|
|
2280
|
+
p += 2;
|
|
2281
|
+
}
|
|
2282
|
+
|
|
2283
|
+
top = dest = src = p;
|
|
2284
|
+
/* Rewrite the path name if its character is a unusable. */
|
|
2285
|
+
for (; *p != L'\0'; p++) {
|
|
2286
|
+
if (*p == L':' || *p == L'*' || *p == L'?' || *p == L'"' ||
|
|
2287
|
+
*p == L'<' || *p == L'>' || *p == L'|')
|
|
2288
|
+
*p = L'_';
|
|
2289
|
+
}
|
|
2290
|
+
/* Skip leading '\'. */
|
|
2291
|
+
if (*src == L'\\')
|
|
2292
|
+
separator = *src++;
|
|
2293
|
+
|
|
2294
|
+
/* Scan the pathname one element at a time. */
|
|
2295
|
+
for (;;) {
|
|
2296
|
+
/* src points to first char after '\' */
|
|
2297
|
+
if (src[0] == L'\0') {
|
|
2298
|
+
break;
|
|
2299
|
+
} else if (src[0] == L'\\') {
|
|
2300
|
+
/* Found '\\'('//'), ignore second one. */
|
|
2301
|
+
src++;
|
|
2302
|
+
continue;
|
|
2303
|
+
} else if (src[0] == L'.') {
|
|
2304
|
+
if (src[1] == L'\0') {
|
|
2305
|
+
/* Ignore trailing '.' */
|
|
2306
|
+
break;
|
|
2307
|
+
} else if (src[1] == L'\\') {
|
|
2308
|
+
/* Skip '.\'. */
|
|
2309
|
+
src += 2;
|
|
2310
|
+
continue;
|
|
2311
|
+
} else if (src[1] == L'.') {
|
|
2312
|
+
if (src[2] == L'\\' || src[2] == L'\0') {
|
|
2313
|
+
/* Conditionally warn about '..' */
|
|
2314
|
+
if (a->flags &
|
|
2315
|
+
ARCHIVE_EXTRACT_SECURE_NODOTDOT) {
|
|
2316
|
+
archive_set_error(&a->archive,
|
|
2317
|
+
ARCHIVE_ERRNO_MISC,
|
|
2318
|
+
"Path contains '..'");
|
|
2319
|
+
return (ARCHIVE_FAILED);
|
|
2320
|
+
}
|
|
2321
|
+
}
|
|
2322
|
+
/*
|
|
2323
|
+
* Note: Under no circumstances do we
|
|
2324
|
+
* remove '..' elements. In
|
|
2325
|
+
* particular, restoring
|
|
2326
|
+
* '\foo\..\bar\' should create the
|
|
2327
|
+
* 'foo' dir as a side-effect.
|
|
2328
|
+
*/
|
|
2329
|
+
}
|
|
2330
|
+
}
|
|
2331
|
+
|
|
2332
|
+
/* Copy current element, including leading '\'. */
|
|
2333
|
+
if (separator)
|
|
2334
|
+
*dest++ = L'\\';
|
|
2335
|
+
while (*src != L'\0' && *src != L'\\') {
|
|
2336
|
+
*dest++ = *src++;
|
|
2337
|
+
}
|
|
2338
|
+
|
|
2339
|
+
if (*src == L'\0')
|
|
2340
|
+
break;
|
|
2341
|
+
|
|
2342
|
+
/* Skip '\' separator. */
|
|
2343
|
+
separator = *src++;
|
|
2344
|
+
}
|
|
2345
|
+
/*
|
|
2346
|
+
* We've just copied zero or more path elements, not including the
|
|
2347
|
+
* final '\'.
|
|
2348
|
+
*/
|
|
2349
|
+
if (dest == top) {
|
|
2350
|
+
/*
|
|
2351
|
+
* Nothing got copied. The path must have been something
|
|
2352
|
+
* like '.' or '\' or './' or '/././././/./'.
|
|
2353
|
+
*/
|
|
2354
|
+
if (separator)
|
|
2355
|
+
*dest++ = L'\\';
|
|
2356
|
+
else
|
|
2357
|
+
*dest++ = L'.';
|
|
2358
|
+
}
|
|
2359
|
+
/* Terminate the result. */
|
|
2360
|
+
*dest = L'\0';
|
|
2361
|
+
return (ARCHIVE_OK);
|
|
2362
|
+
}
|
|
2363
|
+
|
|
2364
|
+
/*
|
|
2365
|
+
* Create the parent directory of the specified path, assuming path
|
|
2366
|
+
* is already in mutable storage.
|
|
2367
|
+
*/
|
|
2368
|
+
static int
|
|
2369
|
+
create_parent_dir(struct archive_write_disk *a, wchar_t *path)
|
|
2370
|
+
{
|
|
2371
|
+
wchar_t *slash;
|
|
2372
|
+
int r;
|
|
2373
|
+
|
|
2374
|
+
/* Remove tail element to obtain parent name. */
|
|
2375
|
+
slash = wcsrchr(path, L'\\');
|
|
2376
|
+
if (slash == NULL)
|
|
2377
|
+
return (ARCHIVE_OK);
|
|
2378
|
+
*slash = L'\0';
|
|
2379
|
+
r = create_dir(a, path);
|
|
2380
|
+
*slash = L'\\';
|
|
2381
|
+
return (r);
|
|
2382
|
+
}
|
|
2383
|
+
|
|
2384
|
+
/*
|
|
2385
|
+
* Create the specified dir, recursing to create parents as necessary.
|
|
2386
|
+
*
|
|
2387
|
+
* Returns ARCHIVE_OK if the path exists when we're done here.
|
|
2388
|
+
* Otherwise, returns ARCHIVE_FAILED.
|
|
2389
|
+
* Assumes path is in mutable storage; path is unchanged on exit.
|
|
2390
|
+
*/
|
|
2391
|
+
static int
|
|
2392
|
+
create_dir(struct archive_write_disk *a, wchar_t *path)
|
|
2393
|
+
{
|
|
2394
|
+
BY_HANDLE_FILE_INFORMATION st;
|
|
2395
|
+
struct fixup_entry *le;
|
|
2396
|
+
wchar_t *slash, *base, *full;
|
|
2397
|
+
mode_t mode_final, mode, st_mode;
|
|
2398
|
+
int r;
|
|
2399
|
+
|
|
2400
|
+
/* Check for special names and just skip them. */
|
|
2401
|
+
slash = wcsrchr(path, L'\\');
|
|
2402
|
+
if (slash == NULL)
|
|
2403
|
+
base = path;
|
|
2404
|
+
else
|
|
2405
|
+
base = slash + 1;
|
|
2406
|
+
|
|
2407
|
+
if (base[0] == L'\0' ||
|
|
2408
|
+
(base[0] == L'.' && base[1] == L'\0') ||
|
|
2409
|
+
(base[0] == L'.' && base[1] == L'.' && base[2] == L'\0')) {
|
|
2410
|
+
/* Don't bother trying to create null path, '.', or '..'. */
|
|
2411
|
+
if (slash != NULL) {
|
|
2412
|
+
*slash = L'\0';
|
|
2413
|
+
r = create_dir(a, path);
|
|
2414
|
+
*slash = L'\\';
|
|
2415
|
+
return (r);
|
|
2416
|
+
}
|
|
2417
|
+
return (ARCHIVE_OK);
|
|
2418
|
+
}
|
|
2419
|
+
|
|
2420
|
+
/*
|
|
2421
|
+
* Yes, this should be stat() and not lstat(). Using lstat()
|
|
2422
|
+
* here loses the ability to extract through symlinks. Also note
|
|
2423
|
+
* that this should not use the a->st cache.
|
|
2424
|
+
*/
|
|
2425
|
+
if (file_information(a, path, &st, &st_mode, 0) == 0) {
|
|
2426
|
+
if (S_ISDIR(st_mode))
|
|
2427
|
+
return (ARCHIVE_OK);
|
|
2428
|
+
if ((a->flags & ARCHIVE_EXTRACT_NO_OVERWRITE)) {
|
|
2429
|
+
archive_set_error(&a->archive, EEXIST,
|
|
2430
|
+
"Can't create directory '%ls'", path);
|
|
2431
|
+
return (ARCHIVE_FAILED);
|
|
2432
|
+
}
|
|
2433
|
+
if (disk_unlink(path) != 0) {
|
|
2434
|
+
archive_set_error(&a->archive, errno,
|
|
2435
|
+
"Can't create directory '%ls': "
|
|
2436
|
+
"Conflicting file cannot be removed",
|
|
2437
|
+
path);
|
|
2438
|
+
return (ARCHIVE_FAILED);
|
|
2439
|
+
}
|
|
2440
|
+
} else if (errno != ENOENT && errno != ENOTDIR) {
|
|
2441
|
+
/* Stat failed? */
|
|
2442
|
+
archive_set_error(&a->archive, errno,
|
|
2443
|
+
"Can't test directory '%ls'", path);
|
|
2444
|
+
return (ARCHIVE_FAILED);
|
|
2445
|
+
} else if (slash != NULL) {
|
|
2446
|
+
*slash = '\0';
|
|
2447
|
+
r = create_dir(a, path);
|
|
2448
|
+
*slash = '\\';
|
|
2449
|
+
if (r != ARCHIVE_OK)
|
|
2450
|
+
return (r);
|
|
2451
|
+
}
|
|
2452
|
+
|
|
2453
|
+
/*
|
|
2454
|
+
* Mode we want for the final restored directory. Per POSIX,
|
|
2455
|
+
* implicitly-created dirs must be created obeying the umask.
|
|
2456
|
+
* There's no mention whether this is different for privileged
|
|
2457
|
+
* restores (which the rest of this code handles by pretending
|
|
2458
|
+
* umask=0). I've chosen here to always obey the user's umask for
|
|
2459
|
+
* implicit dirs, even if _EXTRACT_PERM was specified.
|
|
2460
|
+
*/
|
|
2461
|
+
mode_final = DEFAULT_DIR_MODE & ~a->user_umask;
|
|
2462
|
+
/* Mode we want on disk during the restore process. */
|
|
2463
|
+
mode = mode_final;
|
|
2464
|
+
mode |= MINIMUM_DIR_MODE;
|
|
2465
|
+
mode &= MAXIMUM_DIR_MODE;
|
|
2466
|
+
/*
|
|
2467
|
+
* Apply __la_win_permissive_name_w to path in order to
|
|
2468
|
+
* remove '../' path string.
|
|
2469
|
+
*/
|
|
2470
|
+
full = __la_win_permissive_name_w(path);
|
|
2471
|
+
if (full == NULL)
|
|
2472
|
+
errno = EINVAL;
|
|
2473
|
+
else if (CreateDirectoryW(full, NULL) != 0) {
|
|
2474
|
+
if (mode != mode_final) {
|
|
2475
|
+
le = new_fixup(a, path);
|
|
2476
|
+
le->fixup |=TODO_MODE_BASE;
|
|
2477
|
+
le->mode = mode_final;
|
|
2478
|
+
}
|
|
2479
|
+
free(full);
|
|
2480
|
+
return (ARCHIVE_OK);
|
|
2481
|
+
} else {
|
|
2482
|
+
la_dosmaperr(GetLastError());
|
|
2483
|
+
}
|
|
2484
|
+
free(full);
|
|
2485
|
+
|
|
2486
|
+
/*
|
|
2487
|
+
* Without the following check, a/b/../b/c/d fails at the
|
|
2488
|
+
* second visit to 'b', so 'd' can't be created. Note that we
|
|
2489
|
+
* don't add it to the fixup list here, as it's already been
|
|
2490
|
+
* added.
|
|
2491
|
+
*/
|
|
2492
|
+
if (file_information(a, path, &st, &st_mode, 0) == 0 &&
|
|
2493
|
+
S_ISDIR(st_mode))
|
|
2494
|
+
return (ARCHIVE_OK);
|
|
2495
|
+
|
|
2496
|
+
archive_set_error(&a->archive, errno, "Failed to create dir '%ls'",
|
|
2497
|
+
path);
|
|
2498
|
+
return (ARCHIVE_FAILED);
|
|
2499
|
+
}
|
|
2500
|
+
|
|
2501
|
+
/*
|
|
2502
|
+
* Note: Although we can skip setting the user id if the desired user
|
|
2503
|
+
* id matches the current user, we cannot skip setting the group, as
|
|
2504
|
+
* many systems set the gid based on the containing directory. So
|
|
2505
|
+
* we have to perform a chown syscall if we want to set the SGID
|
|
2506
|
+
* bit. (The alternative is to stat() and then possibly chown(); it's
|
|
2507
|
+
* more efficient to skip the stat() and just always chown().) Note
|
|
2508
|
+
* that a successful chown() here clears the TODO_SGID_CHECK bit, which
|
|
2509
|
+
* allows set_mode to skip the stat() check for the GID.
|
|
2510
|
+
*/
|
|
2511
|
+
static int
|
|
2512
|
+
set_ownership(struct archive_write_disk *a)
|
|
2513
|
+
{
|
|
2514
|
+
/* unfortunately, on win32 there is no 'root' user with uid 0,
|
|
2515
|
+
so we just have to try the chown and see if it works */
|
|
2516
|
+
|
|
2517
|
+
/* If we know we can't change it, don't bother trying. */
|
|
2518
|
+
if (a->user_uid != 0 && a->user_uid != a->uid) {
|
|
2519
|
+
archive_set_error(&a->archive, errno,
|
|
2520
|
+
"Can't set UID=%jd", (intmax_t)a->uid);
|
|
2521
|
+
return (ARCHIVE_WARN);
|
|
2522
|
+
}
|
|
2523
|
+
|
|
2524
|
+
archive_set_error(&a->archive, errno,
|
|
2525
|
+
"Can't set user=%jd/group=%jd for %ls",
|
|
2526
|
+
(intmax_t)a->uid, (intmax_t)a->gid, a->name);
|
|
2527
|
+
return (ARCHIVE_WARN);
|
|
2528
|
+
}
|
|
2529
|
+
|
|
2530
|
+
static int
|
|
2531
|
+
set_times(struct archive_write_disk *a,
|
|
2532
|
+
HANDLE h, int mode, const wchar_t *name,
|
|
2533
|
+
time_t atime, long atime_nanos,
|
|
2534
|
+
time_t birthtime, long birthtime_nanos,
|
|
2535
|
+
time_t mtime, long mtime_nanos,
|
|
2536
|
+
time_t ctime_sec, long ctime_nanos)
|
|
2537
|
+
{
|
|
2538
|
+
#define EPOC_TIME ARCHIVE_LITERAL_ULL(116444736000000000)
|
|
2539
|
+
#define WINTIME(sec, nsec) ((Int32x32To64(sec, 10000000) + EPOC_TIME)\
|
|
2540
|
+
+ (((nsec)/1000)*10))
|
|
2541
|
+
|
|
2542
|
+
HANDLE hw = 0;
|
|
2543
|
+
ULARGE_INTEGER wintm;
|
|
2544
|
+
FILETIME *pfbtime;
|
|
2545
|
+
FILETIME fatime, fbtime, fmtime;
|
|
2546
|
+
|
|
2547
|
+
(void)ctime_sec; /* UNUSED */
|
|
2548
|
+
(void)ctime_nanos; /* UNUSED */
|
|
2549
|
+
|
|
2550
|
+
if (h != INVALID_HANDLE_VALUE) {
|
|
2551
|
+
hw = NULL;
|
|
2552
|
+
} else {
|
|
2553
|
+
wchar_t *ws;
|
|
2554
|
+
|
|
2555
|
+
if (S_ISLNK(mode))
|
|
2556
|
+
return (ARCHIVE_OK);
|
|
2557
|
+
ws = __la_win_permissive_name_w(name);
|
|
2558
|
+
if (ws == NULL)
|
|
2559
|
+
goto settimes_failed;
|
|
2560
|
+
hw = CreateFileW(ws, FILE_WRITE_ATTRIBUTES,
|
|
2561
|
+
0, NULL, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, NULL);
|
|
2562
|
+
free(ws);
|
|
2563
|
+
if (hw == INVALID_HANDLE_VALUE)
|
|
2564
|
+
goto settimes_failed;
|
|
2565
|
+
h = hw;
|
|
2566
|
+
}
|
|
2567
|
+
|
|
2568
|
+
wintm.QuadPart = WINTIME(atime, atime_nanos);
|
|
2569
|
+
fatime.dwLowDateTime = wintm.LowPart;
|
|
2570
|
+
fatime.dwHighDateTime = wintm.HighPart;
|
|
2571
|
+
wintm.QuadPart = WINTIME(mtime, mtime_nanos);
|
|
2572
|
+
fmtime.dwLowDateTime = wintm.LowPart;
|
|
2573
|
+
fmtime.dwHighDateTime = wintm.HighPart;
|
|
2574
|
+
/*
|
|
2575
|
+
* SetFileTime() supports birthtime.
|
|
2576
|
+
*/
|
|
2577
|
+
if (birthtime > 0 || birthtime_nanos > 0) {
|
|
2578
|
+
wintm.QuadPart = WINTIME(birthtime, birthtime_nanos);
|
|
2579
|
+
fbtime.dwLowDateTime = wintm.LowPart;
|
|
2580
|
+
fbtime.dwHighDateTime = wintm.HighPart;
|
|
2581
|
+
pfbtime = &fbtime;
|
|
2582
|
+
} else
|
|
2583
|
+
pfbtime = NULL;
|
|
2584
|
+
if (SetFileTime(h, pfbtime, &fatime, &fmtime) == 0)
|
|
2585
|
+
goto settimes_failed;
|
|
2586
|
+
CloseHandle(hw);
|
|
2587
|
+
return (ARCHIVE_OK);
|
|
2588
|
+
|
|
2589
|
+
settimes_failed:
|
|
2590
|
+
CloseHandle(hw);
|
|
2591
|
+
archive_set_error(&a->archive, EINVAL, "Can't restore time");
|
|
2592
|
+
return (ARCHIVE_WARN);
|
|
2593
|
+
}
|
|
2594
|
+
|
|
2595
|
+
static int
|
|
2596
|
+
set_times_from_entry(struct archive_write_disk *a)
|
|
2597
|
+
{
|
|
2598
|
+
time_t atime, birthtime, mtime, ctime_sec;
|
|
2599
|
+
long atime_nsec, birthtime_nsec, mtime_nsec, ctime_nsec;
|
|
2600
|
+
|
|
2601
|
+
/* Suitable defaults. */
|
|
2602
|
+
atime = birthtime = mtime = ctime_sec = a->start_time;
|
|
2603
|
+
atime_nsec = birthtime_nsec = mtime_nsec = ctime_nsec = 0;
|
|
2604
|
+
|
|
2605
|
+
/* If no time was provided, we're done. */
|
|
2606
|
+
if (!archive_entry_atime_is_set(a->entry)
|
|
2607
|
+
&& !archive_entry_birthtime_is_set(a->entry)
|
|
2608
|
+
&& !archive_entry_mtime_is_set(a->entry))
|
|
2609
|
+
return (ARCHIVE_OK);
|
|
2610
|
+
|
|
2611
|
+
if (archive_entry_atime_is_set(a->entry)) {
|
|
2612
|
+
atime = archive_entry_atime(a->entry);
|
|
2613
|
+
atime_nsec = archive_entry_atime_nsec(a->entry);
|
|
2614
|
+
}
|
|
2615
|
+
if (archive_entry_birthtime_is_set(a->entry)) {
|
|
2616
|
+
birthtime = archive_entry_birthtime(a->entry);
|
|
2617
|
+
birthtime_nsec = archive_entry_birthtime_nsec(a->entry);
|
|
2618
|
+
}
|
|
2619
|
+
if (archive_entry_mtime_is_set(a->entry)) {
|
|
2620
|
+
mtime = archive_entry_mtime(a->entry);
|
|
2621
|
+
mtime_nsec = archive_entry_mtime_nsec(a->entry);
|
|
2622
|
+
}
|
|
2623
|
+
if (archive_entry_ctime_is_set(a->entry)) {
|
|
2624
|
+
ctime_sec = archive_entry_ctime(a->entry);
|
|
2625
|
+
ctime_nsec = archive_entry_ctime_nsec(a->entry);
|
|
2626
|
+
}
|
|
2627
|
+
|
|
2628
|
+
return set_times(a, a->fh, a->mode, a->name,
|
|
2629
|
+
atime, atime_nsec,
|
|
2630
|
+
birthtime, birthtime_nsec,
|
|
2631
|
+
mtime, mtime_nsec,
|
|
2632
|
+
ctime_sec, ctime_nsec);
|
|
2633
|
+
}
|
|
2634
|
+
|
|
2635
|
+
static int
|
|
2636
|
+
set_mode(struct archive_write_disk *a, int mode)
|
|
2637
|
+
{
|
|
2638
|
+
int r = ARCHIVE_OK;
|
|
2639
|
+
mode &= 07777; /* Strip off file type bits. */
|
|
2640
|
+
|
|
2641
|
+
if (a->todo & TODO_SGID_CHECK) {
|
|
2642
|
+
/*
|
|
2643
|
+
* If we don't know the GID is right, we must stat()
|
|
2644
|
+
* to verify it. We can't just check the GID of this
|
|
2645
|
+
* process, since systems sometimes set GID from
|
|
2646
|
+
* the enclosing dir or based on ACLs.
|
|
2647
|
+
*/
|
|
2648
|
+
if ((r = lazy_stat(a)) != ARCHIVE_OK)
|
|
2649
|
+
return (r);
|
|
2650
|
+
if (0 != a->gid) {
|
|
2651
|
+
mode &= ~ S_ISGID;
|
|
2652
|
+
}
|
|
2653
|
+
/* While we're here, double-check the UID. */
|
|
2654
|
+
if (0 != a->uid
|
|
2655
|
+
&& (a->todo & TODO_SUID)) {
|
|
2656
|
+
mode &= ~ S_ISUID;
|
|
2657
|
+
}
|
|
2658
|
+
a->todo &= ~TODO_SGID_CHECK;
|
|
2659
|
+
a->todo &= ~TODO_SUID_CHECK;
|
|
2660
|
+
} else if (a->todo & TODO_SUID_CHECK) {
|
|
2661
|
+
/*
|
|
2662
|
+
* If we don't know the UID is right, we can just check
|
|
2663
|
+
* the user, since all systems set the file UID from
|
|
2664
|
+
* the process UID.
|
|
2665
|
+
*/
|
|
2666
|
+
if (a->user_uid != a->uid) {
|
|
2667
|
+
mode &= ~ S_ISUID;
|
|
2668
|
+
}
|
|
2669
|
+
a->todo &= ~TODO_SUID_CHECK;
|
|
2670
|
+
}
|
|
2671
|
+
|
|
2672
|
+
if (S_ISLNK(a->mode)) {
|
|
2673
|
+
#ifdef HAVE_LCHMOD
|
|
2674
|
+
/*
|
|
2675
|
+
* If this is a symlink, use lchmod(). If the
|
|
2676
|
+
* platform doesn't support lchmod(), just skip it. A
|
|
2677
|
+
* platform that doesn't provide a way to set
|
|
2678
|
+
* permissions on symlinks probably ignores
|
|
2679
|
+
* permissions on symlinks, so a failure here has no
|
|
2680
|
+
* impact.
|
|
2681
|
+
*/
|
|
2682
|
+
if (lchmod(a->name, mode) != 0) {
|
|
2683
|
+
archive_set_error(&a->archive, errno,
|
|
2684
|
+
"Can't set permissions to 0%o", (int)mode);
|
|
2685
|
+
r = ARCHIVE_WARN;
|
|
2686
|
+
}
|
|
2687
|
+
#endif
|
|
2688
|
+
} else if (!S_ISDIR(a->mode)) {
|
|
2689
|
+
/*
|
|
2690
|
+
* If it's not a symlink and not a dir, then use
|
|
2691
|
+
* fchmod() or chmod(), depending on whether we have
|
|
2692
|
+
* an fd. Dirs get their perms set during the
|
|
2693
|
+
* post-extract fixup, which is handled elsewhere.
|
|
2694
|
+
*/
|
|
2695
|
+
#ifdef HAVE_FCHMOD
|
|
2696
|
+
if (a->fd >= 0) {
|
|
2697
|
+
if (fchmod(a->fd, mode) != 0) {
|
|
2698
|
+
archive_set_error(&a->archive, errno,
|
|
2699
|
+
"Can't set permissions to 0%o", (int)mode);
|
|
2700
|
+
r = ARCHIVE_WARN;
|
|
2701
|
+
}
|
|
2702
|
+
} else
|
|
2703
|
+
#endif
|
|
2704
|
+
/* If this platform lacks fchmod(), then
|
|
2705
|
+
* we'll just use chmod(). */
|
|
2706
|
+
if (la_chmod(a->name, mode) != 0) {
|
|
2707
|
+
archive_set_error(&a->archive, errno,
|
|
2708
|
+
"Can't set permissions to 0%o", (int)mode);
|
|
2709
|
+
r = ARCHIVE_WARN;
|
|
2710
|
+
}
|
|
2711
|
+
}
|
|
2712
|
+
return (r);
|
|
2713
|
+
}
|
|
2714
|
+
|
|
2715
|
+
static int set_fflags_platform(const wchar_t *name, unsigned long fflags_set,
|
|
2716
|
+
unsigned long fflags_clear)
|
|
2717
|
+
{
|
|
2718
|
+
DWORD oldflags, newflags;
|
|
2719
|
+
wchar_t *fullname;
|
|
2720
|
+
|
|
2721
|
+
const DWORD settable_flags =
|
|
2722
|
+
FILE_ATTRIBUTE_ARCHIVE |
|
|
2723
|
+
FILE_ATTRIBUTE_HIDDEN |
|
|
2724
|
+
FILE_ATTRIBUTE_NORMAL |
|
|
2725
|
+
FILE_ATTRIBUTE_NOT_CONTENT_INDEXED |
|
|
2726
|
+
FILE_ATTRIBUTE_OFFLINE |
|
|
2727
|
+
FILE_ATTRIBUTE_READONLY |
|
|
2728
|
+
FILE_ATTRIBUTE_SYSTEM |
|
|
2729
|
+
FILE_ATTRIBUTE_TEMPORARY;
|
|
2730
|
+
|
|
2731
|
+
oldflags = GetFileAttributesW(name);
|
|
2732
|
+
if (oldflags == (DWORD)-1 &&
|
|
2733
|
+
GetLastError() == ERROR_INVALID_NAME) {
|
|
2734
|
+
fullname = __la_win_permissive_name_w(name);
|
|
2735
|
+
oldflags = GetFileAttributesW(fullname);
|
|
2736
|
+
}
|
|
2737
|
+
if (oldflags == (DWORD)-1) {
|
|
2738
|
+
la_dosmaperr(GetLastError());
|
|
2739
|
+
return (ARCHIVE_WARN);
|
|
2740
|
+
}
|
|
2741
|
+
newflags = ((oldflags & ~fflags_clear) | fflags_set) & settable_flags;
|
|
2742
|
+
if(SetFileAttributesW(name, newflags) == 0)
|
|
2743
|
+
return (ARCHIVE_WARN);
|
|
2744
|
+
return (ARCHIVE_OK);
|
|
2745
|
+
}
|
|
2746
|
+
|
|
2747
|
+
static int
|
|
2748
|
+
clear_nochange_fflags(struct archive_write_disk *a)
|
|
2749
|
+
{
|
|
2750
|
+
return (set_fflags_platform(a->name, 0, FILE_ATTRIBUTE_READONLY));
|
|
2751
|
+
}
|
|
2752
|
+
|
|
2753
|
+
static int
|
|
2754
|
+
set_fflags(struct archive_write_disk *a)
|
|
2755
|
+
{
|
|
2756
|
+
unsigned long set, clear;
|
|
2757
|
+
|
|
2758
|
+
if (a->todo & TODO_FFLAGS) {
|
|
2759
|
+
archive_entry_fflags(a->entry, &set, &clear);
|
|
2760
|
+
if (set == 0 && clear == 0)
|
|
2761
|
+
return (ARCHIVE_OK);
|
|
2762
|
+
return (set_fflags_platform(a->name, set, clear));
|
|
2763
|
+
|
|
2764
|
+
}
|
|
2765
|
+
return (ARCHIVE_OK);
|
|
2766
|
+
}
|
|
2767
|
+
|
|
2768
|
+
/* Default empty function body to satisfy mainline code. */
|
|
2769
|
+
static int
|
|
2770
|
+
set_acls(struct archive_write_disk *a, HANDLE h, const wchar_t *name,
|
|
2771
|
+
struct archive_acl *acl)
|
|
2772
|
+
{
|
|
2773
|
+
(void)a; /* UNUSED */
|
|
2774
|
+
(void)h; /* UNUSED */
|
|
2775
|
+
(void)name; /* UNUSED */
|
|
2776
|
+
(void)acl; /* UNUSED */
|
|
2777
|
+
return (ARCHIVE_OK);
|
|
2778
|
+
}
|
|
2779
|
+
|
|
2780
|
+
/*
|
|
2781
|
+
* Restore extended attributes - stub implementation for unsupported systems
|
|
2782
|
+
*/
|
|
2783
|
+
static int
|
|
2784
|
+
set_xattrs(struct archive_write_disk *a)
|
|
2785
|
+
{
|
|
2786
|
+
static int warning_done = 0;
|
|
2787
|
+
|
|
2788
|
+
/* If there aren't any extended attributes, then it's okay not
|
|
2789
|
+
* to extract them, otherwise, issue a single warning. */
|
|
2790
|
+
if (archive_entry_xattr_count(a->entry) != 0 && !warning_done) {
|
|
2791
|
+
warning_done = 1;
|
|
2792
|
+
archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,
|
|
2793
|
+
"Cannot restore extended attributes on this system");
|
|
2794
|
+
return (ARCHIVE_WARN);
|
|
2795
|
+
}
|
|
2796
|
+
/* Warning was already emitted; suppress further warnings. */
|
|
2797
|
+
return (ARCHIVE_OK);
|
|
2798
|
+
}
|
|
2799
|
+
|
|
2800
|
+
static void
|
|
2801
|
+
fileTimeToUtc(const FILETIME *filetime, time_t *t, long *ns)
|
|
2802
|
+
{
|
|
2803
|
+
ULARGE_INTEGER utc;
|
|
2804
|
+
|
|
2805
|
+
utc.HighPart = filetime->dwHighDateTime;
|
|
2806
|
+
utc.LowPart = filetime->dwLowDateTime;
|
|
2807
|
+
if (utc.QuadPart >= EPOC_TIME) {
|
|
2808
|
+
utc.QuadPart -= EPOC_TIME;
|
|
2809
|
+
/* milli seconds base */
|
|
2810
|
+
*t = (time_t)(utc.QuadPart / 10000000);
|
|
2811
|
+
/* nano seconds base */
|
|
2812
|
+
*ns = (long)(utc.QuadPart % 10000000) * 100;
|
|
2813
|
+
} else {
|
|
2814
|
+
*t = 0;
|
|
2815
|
+
*ns = 0;
|
|
2816
|
+
}
|
|
2817
|
+
}
|
|
2818
|
+
/*
|
|
2819
|
+
* Test if file on disk is older than entry.
|
|
2820
|
+
*/
|
|
2821
|
+
static int
|
|
2822
|
+
older(BY_HANDLE_FILE_INFORMATION *st, struct archive_entry *entry)
|
|
2823
|
+
{
|
|
2824
|
+
time_t sec;
|
|
2825
|
+
long nsec;
|
|
2826
|
+
|
|
2827
|
+
fileTimeToUtc(&st->ftLastWriteTime, &sec, &nsec);
|
|
2828
|
+
/* First, test the seconds and return if we have a definite answer. */
|
|
2829
|
+
/* Definitely older. */
|
|
2830
|
+
if (sec < archive_entry_mtime(entry))
|
|
2831
|
+
return (1);
|
|
2832
|
+
/* Definitely younger. */
|
|
2833
|
+
if (sec > archive_entry_mtime(entry))
|
|
2834
|
+
return (0);
|
|
2835
|
+
if (nsec < archive_entry_mtime_nsec(entry))
|
|
2836
|
+
return (1);
|
|
2837
|
+
/* Same age or newer, so not older. */
|
|
2838
|
+
return (0);
|
|
2839
|
+
}
|
|
2840
|
+
|
|
2841
|
+
#endif /* _WIN32 && !__CYGWIN__ */
|
|
2842
|
+
|