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,2479 @@
|
|
|
1
|
+
/*-
|
|
2
|
+
* Copyright (c) 2003-2009 Tim Kientzle
|
|
3
|
+
* Copyright (c) 2010-2012 Michihiro NAKAJIMA
|
|
4
|
+
* All rights reserved.
|
|
5
|
+
*
|
|
6
|
+
* Redistribution and use in source and binary forms, with or without
|
|
7
|
+
* modification, are permitted provided that the following conditions
|
|
8
|
+
* are met:
|
|
9
|
+
* 1. Redistributions of source code must retain the above copyright
|
|
10
|
+
* notice, this list of conditions and the following disclaimer
|
|
11
|
+
* 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
|
+
#include "archive_platform.h"
|
|
28
|
+
__FBSDID("$FreeBSD$");
|
|
29
|
+
|
|
30
|
+
#if defined(_WIN32) && !defined(__CYGWIN__)
|
|
31
|
+
|
|
32
|
+
#ifdef HAVE_ERRNO_H
|
|
33
|
+
#include <errno.h>
|
|
34
|
+
#endif
|
|
35
|
+
#ifdef HAVE_STDLIB_H
|
|
36
|
+
#include <stdlib.h>
|
|
37
|
+
#endif
|
|
38
|
+
#include <winioctl.h>
|
|
39
|
+
|
|
40
|
+
#include "archive.h"
|
|
41
|
+
#include "archive_string.h"
|
|
42
|
+
#include "archive_entry.h"
|
|
43
|
+
#include "archive_private.h"
|
|
44
|
+
#include "archive_read_disk_private.h"
|
|
45
|
+
|
|
46
|
+
#ifndef O_BINARY
|
|
47
|
+
#define O_BINARY 0
|
|
48
|
+
#endif
|
|
49
|
+
#ifndef IO_REPARSE_TAG_SYMLINK
|
|
50
|
+
/* Old SDKs do not provide IO_REPARSE_TAG_SYMLINK */
|
|
51
|
+
#define IO_REPARSE_TAG_SYMLINK 0xA000000CL
|
|
52
|
+
#endif
|
|
53
|
+
|
|
54
|
+
/*-
|
|
55
|
+
* This is a new directory-walking system that addresses a number
|
|
56
|
+
* of problems I've had with fts(3). In particular, it has no
|
|
57
|
+
* pathname-length limits (other than the size of 'int'), handles
|
|
58
|
+
* deep logical traversals, uses considerably less memory, and has
|
|
59
|
+
* an opaque interface (easier to modify in the future).
|
|
60
|
+
*
|
|
61
|
+
* Internally, it keeps a single list of "tree_entry" items that
|
|
62
|
+
* represent filesystem objects that require further attention.
|
|
63
|
+
* Non-directories are not kept in memory: they are pulled from
|
|
64
|
+
* readdir(), returned to the client, then freed as soon as possible.
|
|
65
|
+
* Any directory entry to be traversed gets pushed onto the stack.
|
|
66
|
+
*
|
|
67
|
+
* There is surprisingly little information that needs to be kept for
|
|
68
|
+
* each item on the stack. Just the name, depth (represented here as the
|
|
69
|
+
* string length of the parent directory's pathname), and some markers
|
|
70
|
+
* indicating how to get back to the parent (via chdir("..") for a
|
|
71
|
+
* regular dir or via fchdir(2) for a symlink).
|
|
72
|
+
*/
|
|
73
|
+
|
|
74
|
+
struct restore_time {
|
|
75
|
+
const wchar_t *full_path;
|
|
76
|
+
FILETIME lastWriteTime;
|
|
77
|
+
FILETIME lastAccessTime;
|
|
78
|
+
mode_t filetype;
|
|
79
|
+
};
|
|
80
|
+
|
|
81
|
+
struct tree_entry {
|
|
82
|
+
int depth;
|
|
83
|
+
struct tree_entry *next;
|
|
84
|
+
struct tree_entry *parent;
|
|
85
|
+
size_t full_path_dir_length;
|
|
86
|
+
struct archive_wstring name;
|
|
87
|
+
struct archive_wstring full_path;
|
|
88
|
+
size_t dirname_length;
|
|
89
|
+
int64_t dev;
|
|
90
|
+
int64_t ino;
|
|
91
|
+
int flags;
|
|
92
|
+
int filesystem_id;
|
|
93
|
+
/* How to restore time of a directory. */
|
|
94
|
+
struct restore_time restore_time;
|
|
95
|
+
};
|
|
96
|
+
|
|
97
|
+
struct filesystem {
|
|
98
|
+
int64_t dev;
|
|
99
|
+
int synthetic;
|
|
100
|
+
int remote;
|
|
101
|
+
DWORD bytesPerSector;
|
|
102
|
+
};
|
|
103
|
+
|
|
104
|
+
/* Definitions for tree_entry.flags bitmap. */
|
|
105
|
+
#define isDir 1 /* This entry is a regular directory. */
|
|
106
|
+
#define isDirLink 2 /* This entry is a symbolic link to a directory. */
|
|
107
|
+
#define needsFirstVisit 4 /* This is an initial entry. */
|
|
108
|
+
#define needsDescent 8 /* This entry needs to be previsited. */
|
|
109
|
+
#define needsOpen 16 /* This is a directory that needs to be opened. */
|
|
110
|
+
#define needsAscent 32 /* This entry needs to be postvisited. */
|
|
111
|
+
|
|
112
|
+
/*
|
|
113
|
+
* On Windows, "first visit" is handled as a pattern to be handed to
|
|
114
|
+
* _findfirst(). This is consistent with Windows conventions that
|
|
115
|
+
* file patterns are handled within the application. On Posix,
|
|
116
|
+
* "first visit" is just returned to the client.
|
|
117
|
+
*/
|
|
118
|
+
|
|
119
|
+
#define MAX_OVERLAPPED 8
|
|
120
|
+
#define READ_BUFFER_SIZE (1024 * 64) /* Default to 64KB per https://technet.microsoft.com/en-us/library/cc938632.aspx */
|
|
121
|
+
#define DIRECT_IO 0/* Disabled */
|
|
122
|
+
#define ASYNC_IO 1/* Enabled */
|
|
123
|
+
|
|
124
|
+
/*
|
|
125
|
+
* Local data for this package.
|
|
126
|
+
*/
|
|
127
|
+
struct tree {
|
|
128
|
+
struct tree_entry *stack;
|
|
129
|
+
struct tree_entry *current;
|
|
130
|
+
HANDLE d;
|
|
131
|
+
WIN32_FIND_DATAW _findData;
|
|
132
|
+
WIN32_FIND_DATAW *findData;
|
|
133
|
+
int flags;
|
|
134
|
+
int visit_type;
|
|
135
|
+
/* Error code from last failed operation. */
|
|
136
|
+
int tree_errno;
|
|
137
|
+
|
|
138
|
+
/* A full path with "\\?\" prefix. */
|
|
139
|
+
struct archive_wstring full_path;
|
|
140
|
+
size_t full_path_dir_length;
|
|
141
|
+
/* Dynamically-sized buffer for holding path */
|
|
142
|
+
struct archive_wstring path;
|
|
143
|
+
|
|
144
|
+
/* Last path element */
|
|
145
|
+
const wchar_t *basename;
|
|
146
|
+
/* Leading dir length */
|
|
147
|
+
size_t dirname_length;
|
|
148
|
+
|
|
149
|
+
int depth;
|
|
150
|
+
|
|
151
|
+
BY_HANDLE_FILE_INFORMATION lst;
|
|
152
|
+
BY_HANDLE_FILE_INFORMATION st;
|
|
153
|
+
int descend;
|
|
154
|
+
/* How to restore time of a file. */
|
|
155
|
+
struct restore_time restore_time;
|
|
156
|
+
|
|
157
|
+
struct entry_sparse {
|
|
158
|
+
int64_t length;
|
|
159
|
+
int64_t offset;
|
|
160
|
+
} *sparse_list, *current_sparse;
|
|
161
|
+
int sparse_count;
|
|
162
|
+
int sparse_list_size;
|
|
163
|
+
|
|
164
|
+
char initial_symlink_mode;
|
|
165
|
+
char symlink_mode;
|
|
166
|
+
struct filesystem *current_filesystem;
|
|
167
|
+
struct filesystem *filesystem_table;
|
|
168
|
+
int initial_filesystem_id;
|
|
169
|
+
int current_filesystem_id;
|
|
170
|
+
int max_filesystem_id;
|
|
171
|
+
int allocated_filesystem;
|
|
172
|
+
|
|
173
|
+
HANDLE entry_fh;
|
|
174
|
+
int entry_eof;
|
|
175
|
+
int64_t entry_remaining_bytes;
|
|
176
|
+
int64_t entry_total;
|
|
177
|
+
|
|
178
|
+
int ol_idx_doing;
|
|
179
|
+
int ol_idx_done;
|
|
180
|
+
int ol_num_doing;
|
|
181
|
+
int ol_num_done;
|
|
182
|
+
int64_t ol_remaining_bytes;
|
|
183
|
+
int64_t ol_total;
|
|
184
|
+
struct la_overlapped {
|
|
185
|
+
OVERLAPPED ol;
|
|
186
|
+
struct archive * _a;
|
|
187
|
+
unsigned char *buff;
|
|
188
|
+
size_t buff_size;
|
|
189
|
+
int64_t offset;
|
|
190
|
+
size_t bytes_expected;
|
|
191
|
+
size_t bytes_transferred;
|
|
192
|
+
} ol[MAX_OVERLAPPED];
|
|
193
|
+
int direct_io;
|
|
194
|
+
int async_io;
|
|
195
|
+
};
|
|
196
|
+
|
|
197
|
+
#define bhfi_dev(bhfi) ((bhfi)->dwVolumeSerialNumber)
|
|
198
|
+
/* Treat FileIndex as i-node. We should remove a sequence number
|
|
199
|
+
* which is high-16-bits of nFileIndexHigh. */
|
|
200
|
+
#define bhfi_ino(bhfi) \
|
|
201
|
+
((((int64_t)((bhfi)->nFileIndexHigh & 0x0000FFFFUL)) << 32) \
|
|
202
|
+
+ (bhfi)->nFileIndexLow)
|
|
203
|
+
|
|
204
|
+
/* Definitions for tree.flags bitmap. */
|
|
205
|
+
#define hasStat 16 /* The st entry is valid. */
|
|
206
|
+
#define hasLstat 32 /* The lst entry is valid. */
|
|
207
|
+
#define needsRestoreTimes 128
|
|
208
|
+
|
|
209
|
+
static int
|
|
210
|
+
tree_dir_next_windows(struct tree *t, const wchar_t *pattern);
|
|
211
|
+
|
|
212
|
+
/* Initiate/terminate a tree traversal. */
|
|
213
|
+
static struct tree *tree_open(const wchar_t *, int, int);
|
|
214
|
+
static struct tree *tree_reopen(struct tree *, const wchar_t *, int);
|
|
215
|
+
static void tree_close(struct tree *);
|
|
216
|
+
static void tree_free(struct tree *);
|
|
217
|
+
static void tree_push(struct tree *, const wchar_t *, const wchar_t *,
|
|
218
|
+
int, int64_t, int64_t, struct restore_time *);
|
|
219
|
+
|
|
220
|
+
/*
|
|
221
|
+
* tree_next() returns Zero if there is no next entry, non-zero if
|
|
222
|
+
* there is. Note that directories are visited three times.
|
|
223
|
+
* Directories are always visited first as part of enumerating their
|
|
224
|
+
* parent; that is a "regular" visit. If tree_descend() is invoked at
|
|
225
|
+
* that time, the directory is added to a work list and will
|
|
226
|
+
* subsequently be visited two more times: once just after descending
|
|
227
|
+
* into the directory ("postdescent") and again just after ascending
|
|
228
|
+
* back to the parent ("postascent").
|
|
229
|
+
*
|
|
230
|
+
* TREE_ERROR_DIR is returned if the descent failed (because the
|
|
231
|
+
* directory couldn't be opened, for instance). This is returned
|
|
232
|
+
* instead of TREE_POSTDESCENT/TREE_POSTASCENT. TREE_ERROR_DIR is not a
|
|
233
|
+
* fatal error, but it does imply that the relevant subtree won't be
|
|
234
|
+
* visited. TREE_ERROR_FATAL is returned for an error that left the
|
|
235
|
+
* traversal completely hosed. Right now, this is only returned for
|
|
236
|
+
* chdir() failures during ascent.
|
|
237
|
+
*/
|
|
238
|
+
#define TREE_REGULAR 1
|
|
239
|
+
#define TREE_POSTDESCENT 2
|
|
240
|
+
#define TREE_POSTASCENT 3
|
|
241
|
+
#define TREE_ERROR_DIR -1
|
|
242
|
+
#define TREE_ERROR_FATAL -2
|
|
243
|
+
|
|
244
|
+
static int tree_next(struct tree *);
|
|
245
|
+
|
|
246
|
+
/*
|
|
247
|
+
* Return information about the current entry.
|
|
248
|
+
*/
|
|
249
|
+
|
|
250
|
+
/*
|
|
251
|
+
* The current full pathname, length of the full pathname, and a name
|
|
252
|
+
* that can be used to access the file. Because tree does use chdir
|
|
253
|
+
* extensively, the access path is almost never the same as the full
|
|
254
|
+
* current path.
|
|
255
|
+
*
|
|
256
|
+
*/
|
|
257
|
+
static const wchar_t *tree_current_path(struct tree *);
|
|
258
|
+
static const wchar_t *tree_current_access_path(struct tree *);
|
|
259
|
+
|
|
260
|
+
/*
|
|
261
|
+
* Request the lstat() or stat() data for the current path. Since the
|
|
262
|
+
* tree package needs to do some of this anyway, and caches the
|
|
263
|
+
* results, you should take advantage of it here if you need it rather
|
|
264
|
+
* than make a redundant stat() or lstat() call of your own.
|
|
265
|
+
*/
|
|
266
|
+
static const BY_HANDLE_FILE_INFORMATION *tree_current_stat(struct tree *);
|
|
267
|
+
static const BY_HANDLE_FILE_INFORMATION *tree_current_lstat(struct tree *);
|
|
268
|
+
|
|
269
|
+
/* The following functions use tricks to avoid a certain number of
|
|
270
|
+
* stat()/lstat() calls. */
|
|
271
|
+
/* "is_physical_dir" is equivalent to S_ISDIR(tree_current_lstat()->st_mode) */
|
|
272
|
+
static int tree_current_is_physical_dir(struct tree *);
|
|
273
|
+
/* "is_physical_link" is equivalent to S_ISLNK(tree_current_lstat()->st_mode) */
|
|
274
|
+
static int tree_current_is_physical_link(struct tree *);
|
|
275
|
+
/* Instead of archive_entry_copy_stat for BY_HANDLE_FILE_INFORMATION */
|
|
276
|
+
static void tree_archive_entry_copy_bhfi(struct archive_entry *,
|
|
277
|
+
struct tree *, const BY_HANDLE_FILE_INFORMATION *);
|
|
278
|
+
/* "is_dir" is equivalent to S_ISDIR(tree_current_stat()->st_mode) */
|
|
279
|
+
static int tree_current_is_dir(struct tree *);
|
|
280
|
+
static int update_current_filesystem(struct archive_read_disk *a,
|
|
281
|
+
int64_t dev);
|
|
282
|
+
static int setup_current_filesystem(struct archive_read_disk *);
|
|
283
|
+
static int tree_target_is_same_as_parent(struct tree *,
|
|
284
|
+
const BY_HANDLE_FILE_INFORMATION *);
|
|
285
|
+
|
|
286
|
+
static int _archive_read_disk_open_w(struct archive *, const wchar_t *);
|
|
287
|
+
static int _archive_read_free(struct archive *);
|
|
288
|
+
static int _archive_read_close(struct archive *);
|
|
289
|
+
static int _archive_read_data_block(struct archive *,
|
|
290
|
+
const void **, size_t *, int64_t *);
|
|
291
|
+
static int _archive_read_next_header(struct archive *,
|
|
292
|
+
struct archive_entry **);
|
|
293
|
+
static int _archive_read_next_header2(struct archive *,
|
|
294
|
+
struct archive_entry *);
|
|
295
|
+
static const char *trivial_lookup_gname(void *, int64_t gid);
|
|
296
|
+
static const char *trivial_lookup_uname(void *, int64_t uid);
|
|
297
|
+
static int setup_sparse(struct archive_read_disk *, struct archive_entry *);
|
|
298
|
+
static int close_and_restore_time(HANDLE, struct tree *,
|
|
299
|
+
struct restore_time *);
|
|
300
|
+
static int setup_sparse_from_disk(struct archive_read_disk *,
|
|
301
|
+
struct archive_entry *, HANDLE);
|
|
302
|
+
static int la_linkname_from_handle(HANDLE, wchar_t **, int *);
|
|
303
|
+
static int la_linkname_from_pathw(const wchar_t *, wchar_t **, int *);
|
|
304
|
+
static void entry_symlink_from_pathw(struct archive_entry *,
|
|
305
|
+
const wchar_t *path);
|
|
306
|
+
|
|
307
|
+
typedef struct _REPARSE_DATA_BUFFER {
|
|
308
|
+
ULONG ReparseTag;
|
|
309
|
+
USHORT ReparseDataLength;
|
|
310
|
+
USHORT Reserved;
|
|
311
|
+
union {
|
|
312
|
+
struct {
|
|
313
|
+
USHORT SubstituteNameOffset;
|
|
314
|
+
USHORT SubstituteNameLength;
|
|
315
|
+
USHORT PrintNameOffset;
|
|
316
|
+
USHORT PrintNameLength;
|
|
317
|
+
ULONG Flags;
|
|
318
|
+
WCHAR PathBuffer[1];
|
|
319
|
+
} SymbolicLinkReparseBuffer;
|
|
320
|
+
struct {
|
|
321
|
+
USHORT SubstituteNameOffset;
|
|
322
|
+
USHORT SubstituteNameLength;
|
|
323
|
+
USHORT PrintNameOffset;
|
|
324
|
+
USHORT PrintNameLength;
|
|
325
|
+
WCHAR PathBuffer[1];
|
|
326
|
+
} MountPointReparseBuffer;
|
|
327
|
+
struct {
|
|
328
|
+
UCHAR DataBuffer[1];
|
|
329
|
+
} GenericReparseBuffer;
|
|
330
|
+
} DUMMYUNIONNAME;
|
|
331
|
+
} REPARSE_DATA_BUFFER, *PREPARSE_DATA_BUFFER;
|
|
332
|
+
|
|
333
|
+
/*
|
|
334
|
+
* Reads the target of a symbolic link
|
|
335
|
+
*
|
|
336
|
+
* Returns 0 on success and -1 on failure
|
|
337
|
+
* outbuf is allocated in the function
|
|
338
|
+
*/
|
|
339
|
+
static int
|
|
340
|
+
la_linkname_from_handle(HANDLE h, wchar_t **linkname, int *linktype)
|
|
341
|
+
{
|
|
342
|
+
DWORD inbytes;
|
|
343
|
+
REPARSE_DATA_BUFFER *buf;
|
|
344
|
+
BY_HANDLE_FILE_INFORMATION st;
|
|
345
|
+
size_t len;
|
|
346
|
+
BOOL ret;
|
|
347
|
+
BYTE *indata;
|
|
348
|
+
wchar_t *tbuf;
|
|
349
|
+
|
|
350
|
+
ret = GetFileInformationByHandle(h, &st);
|
|
351
|
+
if (ret == 0 ||
|
|
352
|
+
(st.dwFileAttributes & FILE_ATTRIBUTE_REPARSE_POINT) == 0) {
|
|
353
|
+
return (-1);
|
|
354
|
+
}
|
|
355
|
+
|
|
356
|
+
indata = malloc(MAXIMUM_REPARSE_DATA_BUFFER_SIZE);
|
|
357
|
+
ret = DeviceIoControl(h, FSCTL_GET_REPARSE_POINT, NULL, 0, indata,
|
|
358
|
+
1024, &inbytes, NULL);
|
|
359
|
+
if (ret == 0) {
|
|
360
|
+
la_dosmaperr(GetLastError());
|
|
361
|
+
free(indata);
|
|
362
|
+
return (-1);
|
|
363
|
+
}
|
|
364
|
+
|
|
365
|
+
buf = (REPARSE_DATA_BUFFER *) indata;
|
|
366
|
+
if (buf->ReparseTag != IO_REPARSE_TAG_SYMLINK) {
|
|
367
|
+
free(indata);
|
|
368
|
+
/* File is not a symbolic link */
|
|
369
|
+
errno = EINVAL;
|
|
370
|
+
return (-1);
|
|
371
|
+
}
|
|
372
|
+
|
|
373
|
+
len = buf->SymbolicLinkReparseBuffer.SubstituteNameLength;
|
|
374
|
+
if (len <= 0) {
|
|
375
|
+
free(indata);
|
|
376
|
+
return (-1);
|
|
377
|
+
}
|
|
378
|
+
|
|
379
|
+
tbuf = malloc(len + 1 * sizeof(wchar_t));
|
|
380
|
+
if (tbuf == NULL) {
|
|
381
|
+
free(indata);
|
|
382
|
+
return (-1);
|
|
383
|
+
}
|
|
384
|
+
|
|
385
|
+
memcpy(tbuf, &((BYTE *)buf->SymbolicLinkReparseBuffer.PathBuffer)
|
|
386
|
+
[buf->SymbolicLinkReparseBuffer.SubstituteNameOffset], len);
|
|
387
|
+
free(indata);
|
|
388
|
+
|
|
389
|
+
tbuf[len / sizeof(wchar_t)] = L'\0';
|
|
390
|
+
|
|
391
|
+
*linkname = tbuf;
|
|
392
|
+
|
|
393
|
+
/*
|
|
394
|
+
* Translate backslashes to slashes for libarchive internal use
|
|
395
|
+
*/
|
|
396
|
+
while(*tbuf != L'\0') {
|
|
397
|
+
if (*tbuf == L'\\')
|
|
398
|
+
*tbuf = L'/';
|
|
399
|
+
tbuf++;
|
|
400
|
+
}
|
|
401
|
+
|
|
402
|
+
if ((st.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) == 0)
|
|
403
|
+
*linktype = AE_SYMLINK_TYPE_FILE;
|
|
404
|
+
else
|
|
405
|
+
*linktype = AE_SYMLINK_TYPE_DIRECTORY;
|
|
406
|
+
|
|
407
|
+
return (0);
|
|
408
|
+
}
|
|
409
|
+
|
|
410
|
+
/*
|
|
411
|
+
* Returns AE_SYMLINK_TYPE_FILE, AE_SYMLINK_TYPE_DIRECTORY or -1 on error
|
|
412
|
+
*/
|
|
413
|
+
static int
|
|
414
|
+
la_linkname_from_pathw(const wchar_t *path, wchar_t **outbuf, int *linktype)
|
|
415
|
+
{
|
|
416
|
+
HANDLE h;
|
|
417
|
+
const DWORD flag = FILE_FLAG_BACKUP_SEMANTICS |
|
|
418
|
+
FILE_FLAG_OPEN_REPARSE_POINT;
|
|
419
|
+
int ret;
|
|
420
|
+
|
|
421
|
+
h = CreateFileW(path, 0,
|
|
422
|
+
FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, NULL,
|
|
423
|
+
OPEN_EXISTING, flag, NULL);
|
|
424
|
+
if (h == INVALID_HANDLE_VALUE) {
|
|
425
|
+
la_dosmaperr(GetLastError());
|
|
426
|
+
return (-1);
|
|
427
|
+
}
|
|
428
|
+
|
|
429
|
+
ret = la_linkname_from_handle(h, outbuf, linktype);
|
|
430
|
+
CloseHandle(h);
|
|
431
|
+
|
|
432
|
+
return (ret);
|
|
433
|
+
}
|
|
434
|
+
|
|
435
|
+
static void
|
|
436
|
+
entry_symlink_from_pathw(struct archive_entry *entry, const wchar_t *path)
|
|
437
|
+
{
|
|
438
|
+
wchar_t *linkname = NULL;
|
|
439
|
+
int ret, linktype;
|
|
440
|
+
|
|
441
|
+
ret = la_linkname_from_pathw(path, &linkname, &linktype);
|
|
442
|
+
if (ret != 0)
|
|
443
|
+
return;
|
|
444
|
+
if (linktype >= 0) {
|
|
445
|
+
archive_entry_copy_symlink_w(entry, linkname);
|
|
446
|
+
archive_entry_set_symlink_type(entry, linktype);
|
|
447
|
+
}
|
|
448
|
+
free(linkname);
|
|
449
|
+
|
|
450
|
+
return;
|
|
451
|
+
}
|
|
452
|
+
|
|
453
|
+
static const struct archive_vtable
|
|
454
|
+
archive_read_disk_vtable = {
|
|
455
|
+
.archive_free = _archive_read_free,
|
|
456
|
+
.archive_close = _archive_read_close,
|
|
457
|
+
.archive_read_data_block = _archive_read_data_block,
|
|
458
|
+
.archive_read_next_header = _archive_read_next_header,
|
|
459
|
+
.archive_read_next_header2 = _archive_read_next_header2,
|
|
460
|
+
};
|
|
461
|
+
|
|
462
|
+
const char *
|
|
463
|
+
archive_read_disk_gname(struct archive *_a, la_int64_t gid)
|
|
464
|
+
{
|
|
465
|
+
struct archive_read_disk *a = (struct archive_read_disk *)_a;
|
|
466
|
+
if (ARCHIVE_OK != __archive_check_magic(_a, ARCHIVE_READ_DISK_MAGIC,
|
|
467
|
+
ARCHIVE_STATE_ANY, "archive_read_disk_gname"))
|
|
468
|
+
return (NULL);
|
|
469
|
+
if (a->lookup_gname == NULL)
|
|
470
|
+
return (NULL);
|
|
471
|
+
return ((*a->lookup_gname)(a->lookup_gname_data, gid));
|
|
472
|
+
}
|
|
473
|
+
|
|
474
|
+
const char *
|
|
475
|
+
archive_read_disk_uname(struct archive *_a, la_int64_t uid)
|
|
476
|
+
{
|
|
477
|
+
struct archive_read_disk *a = (struct archive_read_disk *)_a;
|
|
478
|
+
if (ARCHIVE_OK != __archive_check_magic(_a, ARCHIVE_READ_DISK_MAGIC,
|
|
479
|
+
ARCHIVE_STATE_ANY, "archive_read_disk_uname"))
|
|
480
|
+
return (NULL);
|
|
481
|
+
if (a->lookup_uname == NULL)
|
|
482
|
+
return (NULL);
|
|
483
|
+
return ((*a->lookup_uname)(a->lookup_uname_data, uid));
|
|
484
|
+
}
|
|
485
|
+
|
|
486
|
+
int
|
|
487
|
+
archive_read_disk_set_gname_lookup(struct archive *_a,
|
|
488
|
+
void *private_data,
|
|
489
|
+
const char * (*lookup_gname)(void *private, la_int64_t gid),
|
|
490
|
+
void (*cleanup_gname)(void *private))
|
|
491
|
+
{
|
|
492
|
+
struct archive_read_disk *a = (struct archive_read_disk *)_a;
|
|
493
|
+
archive_check_magic(&a->archive, ARCHIVE_READ_DISK_MAGIC,
|
|
494
|
+
ARCHIVE_STATE_ANY, "archive_read_disk_set_gname_lookup");
|
|
495
|
+
|
|
496
|
+
if (a->cleanup_gname != NULL && a->lookup_gname_data != NULL)
|
|
497
|
+
(a->cleanup_gname)(a->lookup_gname_data);
|
|
498
|
+
|
|
499
|
+
a->lookup_gname = lookup_gname;
|
|
500
|
+
a->cleanup_gname = cleanup_gname;
|
|
501
|
+
a->lookup_gname_data = private_data;
|
|
502
|
+
return (ARCHIVE_OK);
|
|
503
|
+
}
|
|
504
|
+
|
|
505
|
+
int
|
|
506
|
+
archive_read_disk_set_uname_lookup(struct archive *_a,
|
|
507
|
+
void *private_data,
|
|
508
|
+
const char * (*lookup_uname)(void *private, int64_t uid),
|
|
509
|
+
void (*cleanup_uname)(void *private))
|
|
510
|
+
{
|
|
511
|
+
struct archive_read_disk *a = (struct archive_read_disk *)_a;
|
|
512
|
+
archive_check_magic(&a->archive, ARCHIVE_READ_DISK_MAGIC,
|
|
513
|
+
ARCHIVE_STATE_ANY, "archive_read_disk_set_uname_lookup");
|
|
514
|
+
|
|
515
|
+
if (a->cleanup_uname != NULL && a->lookup_uname_data != NULL)
|
|
516
|
+
(a->cleanup_uname)(a->lookup_uname_data);
|
|
517
|
+
|
|
518
|
+
a->lookup_uname = lookup_uname;
|
|
519
|
+
a->cleanup_uname = cleanup_uname;
|
|
520
|
+
a->lookup_uname_data = private_data;
|
|
521
|
+
return (ARCHIVE_OK);
|
|
522
|
+
}
|
|
523
|
+
|
|
524
|
+
/*
|
|
525
|
+
* Create a new archive_read_disk object and initialize it with global state.
|
|
526
|
+
*/
|
|
527
|
+
struct archive *
|
|
528
|
+
archive_read_disk_new(void)
|
|
529
|
+
{
|
|
530
|
+
struct archive_read_disk *a;
|
|
531
|
+
|
|
532
|
+
a = (struct archive_read_disk *)calloc(1, sizeof(*a));
|
|
533
|
+
if (a == NULL)
|
|
534
|
+
return (NULL);
|
|
535
|
+
a->archive.magic = ARCHIVE_READ_DISK_MAGIC;
|
|
536
|
+
a->archive.state = ARCHIVE_STATE_NEW;
|
|
537
|
+
a->archive.vtable = &archive_read_disk_vtable;
|
|
538
|
+
a->entry = archive_entry_new2(&a->archive);
|
|
539
|
+
a->lookup_uname = trivial_lookup_uname;
|
|
540
|
+
a->lookup_gname = trivial_lookup_gname;
|
|
541
|
+
a->flags = ARCHIVE_READDISK_MAC_COPYFILE;
|
|
542
|
+
return (&a->archive);
|
|
543
|
+
}
|
|
544
|
+
|
|
545
|
+
static int
|
|
546
|
+
_archive_read_free(struct archive *_a)
|
|
547
|
+
{
|
|
548
|
+
struct archive_read_disk *a = (struct archive_read_disk *)_a;
|
|
549
|
+
int r;
|
|
550
|
+
|
|
551
|
+
if (_a == NULL)
|
|
552
|
+
return (ARCHIVE_OK);
|
|
553
|
+
archive_check_magic(_a, ARCHIVE_READ_DISK_MAGIC,
|
|
554
|
+
ARCHIVE_STATE_ANY | ARCHIVE_STATE_FATAL, "archive_read_free");
|
|
555
|
+
|
|
556
|
+
if (a->archive.state != ARCHIVE_STATE_CLOSED)
|
|
557
|
+
r = _archive_read_close(&a->archive);
|
|
558
|
+
else
|
|
559
|
+
r = ARCHIVE_OK;
|
|
560
|
+
|
|
561
|
+
tree_free(a->tree);
|
|
562
|
+
if (a->cleanup_gname != NULL && a->lookup_gname_data != NULL)
|
|
563
|
+
(a->cleanup_gname)(a->lookup_gname_data);
|
|
564
|
+
if (a->cleanup_uname != NULL && a->lookup_uname_data != NULL)
|
|
565
|
+
(a->cleanup_uname)(a->lookup_uname_data);
|
|
566
|
+
archive_string_free(&a->archive.error_string);
|
|
567
|
+
archive_entry_free(a->entry);
|
|
568
|
+
a->archive.magic = 0;
|
|
569
|
+
free(a);
|
|
570
|
+
return (r);
|
|
571
|
+
}
|
|
572
|
+
|
|
573
|
+
static int
|
|
574
|
+
_archive_read_close(struct archive *_a)
|
|
575
|
+
{
|
|
576
|
+
struct archive_read_disk *a = (struct archive_read_disk *)_a;
|
|
577
|
+
|
|
578
|
+
archive_check_magic(_a, ARCHIVE_READ_DISK_MAGIC,
|
|
579
|
+
ARCHIVE_STATE_ANY | ARCHIVE_STATE_FATAL, "archive_read_close");
|
|
580
|
+
|
|
581
|
+
if (a->archive.state != ARCHIVE_STATE_FATAL)
|
|
582
|
+
a->archive.state = ARCHIVE_STATE_CLOSED;
|
|
583
|
+
|
|
584
|
+
tree_close(a->tree);
|
|
585
|
+
|
|
586
|
+
return (ARCHIVE_OK);
|
|
587
|
+
}
|
|
588
|
+
|
|
589
|
+
static void
|
|
590
|
+
setup_symlink_mode(struct archive_read_disk *a, char symlink_mode,
|
|
591
|
+
int follow_symlinks)
|
|
592
|
+
{
|
|
593
|
+
a->symlink_mode = symlink_mode;
|
|
594
|
+
a->follow_symlinks = follow_symlinks;
|
|
595
|
+
if (a->tree != NULL) {
|
|
596
|
+
a->tree->initial_symlink_mode = a->symlink_mode;
|
|
597
|
+
a->tree->symlink_mode = a->symlink_mode;
|
|
598
|
+
}
|
|
599
|
+
}
|
|
600
|
+
|
|
601
|
+
int
|
|
602
|
+
archive_read_disk_set_symlink_logical(struct archive *_a)
|
|
603
|
+
{
|
|
604
|
+
struct archive_read_disk *a = (struct archive_read_disk *)_a;
|
|
605
|
+
archive_check_magic(_a, ARCHIVE_READ_DISK_MAGIC,
|
|
606
|
+
ARCHIVE_STATE_ANY, "archive_read_disk_set_symlink_logical");
|
|
607
|
+
setup_symlink_mode(a, 'L', 1);
|
|
608
|
+
return (ARCHIVE_OK);
|
|
609
|
+
}
|
|
610
|
+
|
|
611
|
+
int
|
|
612
|
+
archive_read_disk_set_symlink_physical(struct archive *_a)
|
|
613
|
+
{
|
|
614
|
+
struct archive_read_disk *a = (struct archive_read_disk *)_a;
|
|
615
|
+
archive_check_magic(_a, ARCHIVE_READ_DISK_MAGIC,
|
|
616
|
+
ARCHIVE_STATE_ANY, "archive_read_disk_set_symlink_physical");
|
|
617
|
+
setup_symlink_mode(a, 'P', 0);
|
|
618
|
+
return (ARCHIVE_OK);
|
|
619
|
+
}
|
|
620
|
+
|
|
621
|
+
int
|
|
622
|
+
archive_read_disk_set_symlink_hybrid(struct archive *_a)
|
|
623
|
+
{
|
|
624
|
+
struct archive_read_disk *a = (struct archive_read_disk *)_a;
|
|
625
|
+
archive_check_magic(_a, ARCHIVE_READ_DISK_MAGIC,
|
|
626
|
+
ARCHIVE_STATE_ANY, "archive_read_disk_set_symlink_hybrid");
|
|
627
|
+
setup_symlink_mode(a, 'H', 1);/* Follow symlinks initially. */
|
|
628
|
+
return (ARCHIVE_OK);
|
|
629
|
+
}
|
|
630
|
+
|
|
631
|
+
int
|
|
632
|
+
archive_read_disk_set_atime_restored(struct archive *_a)
|
|
633
|
+
{
|
|
634
|
+
struct archive_read_disk *a = (struct archive_read_disk *)_a;
|
|
635
|
+
archive_check_magic(_a, ARCHIVE_READ_DISK_MAGIC,
|
|
636
|
+
ARCHIVE_STATE_ANY, "archive_read_disk_restore_atime");
|
|
637
|
+
a->flags |= ARCHIVE_READDISK_RESTORE_ATIME;
|
|
638
|
+
if (a->tree != NULL)
|
|
639
|
+
a->tree->flags |= needsRestoreTimes;
|
|
640
|
+
return (ARCHIVE_OK);
|
|
641
|
+
}
|
|
642
|
+
|
|
643
|
+
int
|
|
644
|
+
archive_read_disk_set_behavior(struct archive *_a, int flags)
|
|
645
|
+
{
|
|
646
|
+
struct archive_read_disk *a = (struct archive_read_disk *)_a;
|
|
647
|
+
int r = ARCHIVE_OK;
|
|
648
|
+
|
|
649
|
+
archive_check_magic(_a, ARCHIVE_READ_DISK_MAGIC,
|
|
650
|
+
ARCHIVE_STATE_ANY, "archive_read_disk_honor_nodump");
|
|
651
|
+
|
|
652
|
+
a->flags = flags;
|
|
653
|
+
|
|
654
|
+
if (flags & ARCHIVE_READDISK_RESTORE_ATIME)
|
|
655
|
+
r = archive_read_disk_set_atime_restored(_a);
|
|
656
|
+
else {
|
|
657
|
+
if (a->tree != NULL)
|
|
658
|
+
a->tree->flags &= ~needsRestoreTimes;
|
|
659
|
+
}
|
|
660
|
+
return (r);
|
|
661
|
+
}
|
|
662
|
+
|
|
663
|
+
/*
|
|
664
|
+
* Trivial implementations of gname/uname lookup functions.
|
|
665
|
+
* These are normally overridden by the client, but these stub
|
|
666
|
+
* versions ensure that we always have something that works.
|
|
667
|
+
*/
|
|
668
|
+
static const char *
|
|
669
|
+
trivial_lookup_gname(void *private_data, int64_t gid)
|
|
670
|
+
{
|
|
671
|
+
(void)private_data; /* UNUSED */
|
|
672
|
+
(void)gid; /* UNUSED */
|
|
673
|
+
return (NULL);
|
|
674
|
+
}
|
|
675
|
+
|
|
676
|
+
static const char *
|
|
677
|
+
trivial_lookup_uname(void *private_data, int64_t uid)
|
|
678
|
+
{
|
|
679
|
+
(void)private_data; /* UNUSED */
|
|
680
|
+
(void)uid; /* UNUSED */
|
|
681
|
+
return (NULL);
|
|
682
|
+
}
|
|
683
|
+
|
|
684
|
+
static int64_t
|
|
685
|
+
align_num_per_sector(struct tree *t, int64_t size)
|
|
686
|
+
{
|
|
687
|
+
int64_t surplus;
|
|
688
|
+
|
|
689
|
+
size += t->current_filesystem->bytesPerSector -1;
|
|
690
|
+
surplus = size % t->current_filesystem->bytesPerSector;
|
|
691
|
+
size -= surplus;
|
|
692
|
+
return (size);
|
|
693
|
+
}
|
|
694
|
+
|
|
695
|
+
static int
|
|
696
|
+
start_next_async_read(struct archive_read_disk *a, struct tree *t)
|
|
697
|
+
{
|
|
698
|
+
struct la_overlapped *olp;
|
|
699
|
+
DWORD buffbytes, rbytes;
|
|
700
|
+
|
|
701
|
+
if (t->ol_remaining_bytes == 0)
|
|
702
|
+
return (ARCHIVE_EOF);
|
|
703
|
+
|
|
704
|
+
olp = &(t->ol[t->ol_idx_doing]);
|
|
705
|
+
t->ol_idx_doing = (t->ol_idx_doing + 1) % MAX_OVERLAPPED;
|
|
706
|
+
|
|
707
|
+
/* Allocate read buffer. */
|
|
708
|
+
if (olp->buff == NULL) {
|
|
709
|
+
void *p;
|
|
710
|
+
size_t s = (size_t)align_num_per_sector(t, READ_BUFFER_SIZE);
|
|
711
|
+
p = VirtualAlloc(NULL, s, MEM_COMMIT, PAGE_READWRITE);
|
|
712
|
+
if (p == NULL) {
|
|
713
|
+
archive_set_error(&a->archive, ENOMEM,
|
|
714
|
+
"Couldn't allocate memory");
|
|
715
|
+
a->archive.state = ARCHIVE_STATE_FATAL;
|
|
716
|
+
return (ARCHIVE_FATAL);
|
|
717
|
+
}
|
|
718
|
+
olp->buff = p;
|
|
719
|
+
olp->buff_size = s;
|
|
720
|
+
olp->_a = &a->archive;
|
|
721
|
+
olp->ol.hEvent = CreateEventW(NULL, TRUE, FALSE, NULL);
|
|
722
|
+
if (olp->ol.hEvent == NULL) {
|
|
723
|
+
la_dosmaperr(GetLastError());
|
|
724
|
+
archive_set_error(&a->archive, errno,
|
|
725
|
+
"CreateEvent failed");
|
|
726
|
+
a->archive.state = ARCHIVE_STATE_FATAL;
|
|
727
|
+
return (ARCHIVE_FATAL);
|
|
728
|
+
}
|
|
729
|
+
} else
|
|
730
|
+
ResetEvent(olp->ol.hEvent);
|
|
731
|
+
|
|
732
|
+
buffbytes = (DWORD)olp->buff_size;
|
|
733
|
+
if (buffbytes > t->current_sparse->length)
|
|
734
|
+
buffbytes = (DWORD)t->current_sparse->length;
|
|
735
|
+
|
|
736
|
+
/* Skip hole. */
|
|
737
|
+
if (t->current_sparse->offset > t->ol_total) {
|
|
738
|
+
t->ol_remaining_bytes -=
|
|
739
|
+
t->current_sparse->offset - t->ol_total;
|
|
740
|
+
}
|
|
741
|
+
|
|
742
|
+
olp->offset = t->current_sparse->offset;
|
|
743
|
+
olp->ol.Offset = (DWORD)(olp->offset & 0xffffffff);
|
|
744
|
+
olp->ol.OffsetHigh = (DWORD)(olp->offset >> 32);
|
|
745
|
+
|
|
746
|
+
if (t->ol_remaining_bytes > buffbytes) {
|
|
747
|
+
olp->bytes_expected = buffbytes;
|
|
748
|
+
t->ol_remaining_bytes -= buffbytes;
|
|
749
|
+
} else {
|
|
750
|
+
olp->bytes_expected = (size_t)t->ol_remaining_bytes;
|
|
751
|
+
t->ol_remaining_bytes = 0;
|
|
752
|
+
}
|
|
753
|
+
olp->bytes_transferred = 0;
|
|
754
|
+
t->current_sparse->offset += buffbytes;
|
|
755
|
+
t->current_sparse->length -= buffbytes;
|
|
756
|
+
t->ol_total = t->current_sparse->offset;
|
|
757
|
+
if (t->current_sparse->length == 0 && t->ol_remaining_bytes > 0)
|
|
758
|
+
t->current_sparse++;
|
|
759
|
+
|
|
760
|
+
if (!ReadFile(t->entry_fh, olp->buff, buffbytes, &rbytes, &(olp->ol))) {
|
|
761
|
+
DWORD lasterr;
|
|
762
|
+
|
|
763
|
+
lasterr = GetLastError();
|
|
764
|
+
if (lasterr == ERROR_HANDLE_EOF) {
|
|
765
|
+
archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
|
|
766
|
+
"Reading file truncated");
|
|
767
|
+
a->archive.state = ARCHIVE_STATE_FATAL;
|
|
768
|
+
return (ARCHIVE_FATAL);
|
|
769
|
+
} else if (lasterr != ERROR_IO_PENDING) {
|
|
770
|
+
if (lasterr == ERROR_NO_DATA)
|
|
771
|
+
errno = EAGAIN;
|
|
772
|
+
else if (lasterr == ERROR_ACCESS_DENIED)
|
|
773
|
+
errno = EBADF;
|
|
774
|
+
else
|
|
775
|
+
la_dosmaperr(lasterr);
|
|
776
|
+
archive_set_error(&a->archive, errno, "Read error");
|
|
777
|
+
a->archive.state = ARCHIVE_STATE_FATAL;
|
|
778
|
+
return (ARCHIVE_FATAL);
|
|
779
|
+
}
|
|
780
|
+
} else
|
|
781
|
+
olp->bytes_transferred = rbytes;
|
|
782
|
+
t->ol_num_doing++;
|
|
783
|
+
|
|
784
|
+
return (t->ol_remaining_bytes == 0)? ARCHIVE_EOF: ARCHIVE_OK;
|
|
785
|
+
}
|
|
786
|
+
|
|
787
|
+
static void
|
|
788
|
+
cancel_async(struct tree *t)
|
|
789
|
+
{
|
|
790
|
+
if (t->ol_num_doing != t->ol_num_done) {
|
|
791
|
+
CancelIo(t->entry_fh);
|
|
792
|
+
t->ol_num_doing = t->ol_num_done = 0;
|
|
793
|
+
}
|
|
794
|
+
}
|
|
795
|
+
|
|
796
|
+
static int
|
|
797
|
+
_archive_read_data_block(struct archive *_a, const void **buff,
|
|
798
|
+
size_t *size, int64_t *offset)
|
|
799
|
+
{
|
|
800
|
+
struct archive_read_disk *a = (struct archive_read_disk *)_a;
|
|
801
|
+
struct tree *t = a->tree;
|
|
802
|
+
struct la_overlapped *olp;
|
|
803
|
+
DWORD bytes_transferred;
|
|
804
|
+
int r = ARCHIVE_FATAL;
|
|
805
|
+
|
|
806
|
+
archive_check_magic(_a, ARCHIVE_READ_DISK_MAGIC, ARCHIVE_STATE_DATA,
|
|
807
|
+
"archive_read_data_block");
|
|
808
|
+
|
|
809
|
+
if (t->entry_eof || t->entry_remaining_bytes <= 0) {
|
|
810
|
+
r = ARCHIVE_EOF;
|
|
811
|
+
goto abort_read_data;
|
|
812
|
+
}
|
|
813
|
+
|
|
814
|
+
/*
|
|
815
|
+
* Make a request to read the file in asynchronous.
|
|
816
|
+
*/
|
|
817
|
+
if (t->ol_num_doing == 0) {
|
|
818
|
+
do {
|
|
819
|
+
r = start_next_async_read(a, t);
|
|
820
|
+
if (r == ARCHIVE_FATAL)
|
|
821
|
+
goto abort_read_data;
|
|
822
|
+
if (!t->async_io)
|
|
823
|
+
break;
|
|
824
|
+
} while (r == ARCHIVE_OK && t->ol_num_doing < MAX_OVERLAPPED);
|
|
825
|
+
} else {
|
|
826
|
+
if ((r = start_next_async_read(a, t)) == ARCHIVE_FATAL)
|
|
827
|
+
goto abort_read_data;
|
|
828
|
+
}
|
|
829
|
+
|
|
830
|
+
olp = &(t->ol[t->ol_idx_done]);
|
|
831
|
+
t->ol_idx_done = (t->ol_idx_done + 1) % MAX_OVERLAPPED;
|
|
832
|
+
if (olp->bytes_transferred)
|
|
833
|
+
bytes_transferred = (DWORD)olp->bytes_transferred;
|
|
834
|
+
else if (!GetOverlappedResult(t->entry_fh, &(olp->ol),
|
|
835
|
+
&bytes_transferred, TRUE)) {
|
|
836
|
+
la_dosmaperr(GetLastError());
|
|
837
|
+
archive_set_error(&a->archive, errno,
|
|
838
|
+
"GetOverlappedResult failed");
|
|
839
|
+
a->archive.state = ARCHIVE_STATE_FATAL;
|
|
840
|
+
r = ARCHIVE_FATAL;
|
|
841
|
+
goto abort_read_data;
|
|
842
|
+
}
|
|
843
|
+
t->ol_num_done++;
|
|
844
|
+
|
|
845
|
+
if (bytes_transferred == 0 ||
|
|
846
|
+
olp->bytes_expected != bytes_transferred) {
|
|
847
|
+
archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
|
|
848
|
+
"Reading file truncated");
|
|
849
|
+
a->archive.state = ARCHIVE_STATE_FATAL;
|
|
850
|
+
r = ARCHIVE_FATAL;
|
|
851
|
+
goto abort_read_data;
|
|
852
|
+
}
|
|
853
|
+
|
|
854
|
+
*buff = olp->buff;
|
|
855
|
+
*size = bytes_transferred;
|
|
856
|
+
*offset = olp->offset;
|
|
857
|
+
if (olp->offset > t->entry_total)
|
|
858
|
+
t->entry_remaining_bytes -= olp->offset - t->entry_total;
|
|
859
|
+
t->entry_total = olp->offset + *size;
|
|
860
|
+
t->entry_remaining_bytes -= *size;
|
|
861
|
+
if (t->entry_remaining_bytes == 0) {
|
|
862
|
+
/* Close the current file descriptor */
|
|
863
|
+
close_and_restore_time(t->entry_fh, t, &t->restore_time);
|
|
864
|
+
t->entry_fh = INVALID_HANDLE_VALUE;
|
|
865
|
+
t->entry_eof = 1;
|
|
866
|
+
}
|
|
867
|
+
return (ARCHIVE_OK);
|
|
868
|
+
|
|
869
|
+
abort_read_data:
|
|
870
|
+
*buff = NULL;
|
|
871
|
+
*size = 0;
|
|
872
|
+
*offset = t->entry_total;
|
|
873
|
+
if (t->entry_fh != INVALID_HANDLE_VALUE) {
|
|
874
|
+
cancel_async(t);
|
|
875
|
+
/* Close the current file descriptor */
|
|
876
|
+
close_and_restore_time(t->entry_fh, t, &t->restore_time);
|
|
877
|
+
t->entry_fh = INVALID_HANDLE_VALUE;
|
|
878
|
+
}
|
|
879
|
+
return (r);
|
|
880
|
+
}
|
|
881
|
+
|
|
882
|
+
static int
|
|
883
|
+
next_entry(struct archive_read_disk *a, struct tree *t,
|
|
884
|
+
struct archive_entry *entry)
|
|
885
|
+
{
|
|
886
|
+
const BY_HANDLE_FILE_INFORMATION *st;
|
|
887
|
+
const BY_HANDLE_FILE_INFORMATION *lst;
|
|
888
|
+
const char*name;
|
|
889
|
+
int descend, r;
|
|
890
|
+
|
|
891
|
+
st = NULL;
|
|
892
|
+
lst = NULL;
|
|
893
|
+
t->descend = 0;
|
|
894
|
+
do {
|
|
895
|
+
switch (tree_next(t)) {
|
|
896
|
+
case TREE_ERROR_FATAL:
|
|
897
|
+
archive_set_error(&a->archive, t->tree_errno,
|
|
898
|
+
"%ls: Unable to continue traversing directory tree",
|
|
899
|
+
tree_current_path(t));
|
|
900
|
+
a->archive.state = ARCHIVE_STATE_FATAL;
|
|
901
|
+
return (ARCHIVE_FATAL);
|
|
902
|
+
case TREE_ERROR_DIR:
|
|
903
|
+
archive_set_error(&a->archive, t->tree_errno,
|
|
904
|
+
"%ls: Couldn't visit directory",
|
|
905
|
+
tree_current_path(t));
|
|
906
|
+
return (ARCHIVE_FAILED);
|
|
907
|
+
case 0:
|
|
908
|
+
return (ARCHIVE_EOF);
|
|
909
|
+
case TREE_POSTDESCENT:
|
|
910
|
+
case TREE_POSTASCENT:
|
|
911
|
+
break;
|
|
912
|
+
case TREE_REGULAR:
|
|
913
|
+
lst = tree_current_lstat(t);
|
|
914
|
+
if (lst == NULL) {
|
|
915
|
+
archive_set_error(&a->archive, t->tree_errno,
|
|
916
|
+
"%ls: Cannot stat",
|
|
917
|
+
tree_current_path(t));
|
|
918
|
+
return (ARCHIVE_FAILED);
|
|
919
|
+
}
|
|
920
|
+
break;
|
|
921
|
+
}
|
|
922
|
+
} while (lst == NULL);
|
|
923
|
+
|
|
924
|
+
archive_entry_copy_pathname_w(entry, tree_current_path(t));
|
|
925
|
+
|
|
926
|
+
/*
|
|
927
|
+
* Perform path matching.
|
|
928
|
+
*/
|
|
929
|
+
if (a->matching) {
|
|
930
|
+
r = archive_match_path_excluded(a->matching, entry);
|
|
931
|
+
if (r < 0) {
|
|
932
|
+
archive_set_error(&(a->archive), errno,
|
|
933
|
+
"Failed : %s", archive_error_string(a->matching));
|
|
934
|
+
return (r);
|
|
935
|
+
}
|
|
936
|
+
if (r) {
|
|
937
|
+
if (a->excluded_cb_func)
|
|
938
|
+
a->excluded_cb_func(&(a->archive),
|
|
939
|
+
a->excluded_cb_data, entry);
|
|
940
|
+
return (ARCHIVE_RETRY);
|
|
941
|
+
}
|
|
942
|
+
}
|
|
943
|
+
|
|
944
|
+
/*
|
|
945
|
+
* Distinguish 'L'/'P'/'H' symlink following.
|
|
946
|
+
*/
|
|
947
|
+
switch(t->symlink_mode) {
|
|
948
|
+
case 'H':
|
|
949
|
+
/* 'H': After the first item, rest like 'P'. */
|
|
950
|
+
t->symlink_mode = 'P';
|
|
951
|
+
/* 'H': First item (from command line) like 'L'. */
|
|
952
|
+
/* FALLTHROUGH */
|
|
953
|
+
case 'L':
|
|
954
|
+
/* 'L': Do descend through a symlink to dir. */
|
|
955
|
+
descend = tree_current_is_dir(t);
|
|
956
|
+
/* 'L': Follow symlinks to files. */
|
|
957
|
+
a->symlink_mode = 'L';
|
|
958
|
+
a->follow_symlinks = 1;
|
|
959
|
+
/* 'L': Archive symlinks as targets, if we can. */
|
|
960
|
+
st = tree_current_stat(t);
|
|
961
|
+
if (st != NULL && !tree_target_is_same_as_parent(t, st))
|
|
962
|
+
break;
|
|
963
|
+
/* If stat fails, we have a broken symlink;
|
|
964
|
+
* in that case, don't follow the link. */
|
|
965
|
+
/* FALLTHROUGH */
|
|
966
|
+
default:
|
|
967
|
+
/* 'P': Don't descend through a symlink to dir. */
|
|
968
|
+
descend = tree_current_is_physical_dir(t);
|
|
969
|
+
/* 'P': Don't follow symlinks to files. */
|
|
970
|
+
a->symlink_mode = 'P';
|
|
971
|
+
a->follow_symlinks = 0;
|
|
972
|
+
/* 'P': Archive symlinks as symlinks. */
|
|
973
|
+
st = lst;
|
|
974
|
+
break;
|
|
975
|
+
}
|
|
976
|
+
|
|
977
|
+
if (update_current_filesystem(a, bhfi_dev(st)) != ARCHIVE_OK) {
|
|
978
|
+
a->archive.state = ARCHIVE_STATE_FATAL;
|
|
979
|
+
return (ARCHIVE_FATAL);
|
|
980
|
+
}
|
|
981
|
+
if (t->initial_filesystem_id == -1)
|
|
982
|
+
t->initial_filesystem_id = t->current_filesystem_id;
|
|
983
|
+
if (a->flags & ARCHIVE_READDISK_NO_TRAVERSE_MOUNTS) {
|
|
984
|
+
if (t->initial_filesystem_id != t->current_filesystem_id)
|
|
985
|
+
return (ARCHIVE_RETRY);
|
|
986
|
+
}
|
|
987
|
+
t->descend = descend;
|
|
988
|
+
|
|
989
|
+
tree_archive_entry_copy_bhfi(entry, t, st);
|
|
990
|
+
|
|
991
|
+
/* Save the times to be restored. This must be in before
|
|
992
|
+
* calling archive_read_disk_descend() or any chance of it,
|
|
993
|
+
* especially, invoking a callback. */
|
|
994
|
+
t->restore_time.lastWriteTime = st->ftLastWriteTime;
|
|
995
|
+
t->restore_time.lastAccessTime = st->ftLastAccessTime;
|
|
996
|
+
t->restore_time.filetype = archive_entry_filetype(entry);
|
|
997
|
+
|
|
998
|
+
/*
|
|
999
|
+
* Perform time matching.
|
|
1000
|
+
*/
|
|
1001
|
+
if (a->matching) {
|
|
1002
|
+
r = archive_match_time_excluded(a->matching, entry);
|
|
1003
|
+
if (r < 0) {
|
|
1004
|
+
archive_set_error(&(a->archive), errno,
|
|
1005
|
+
"Failed : %s", archive_error_string(a->matching));
|
|
1006
|
+
return (r);
|
|
1007
|
+
}
|
|
1008
|
+
if (r) {
|
|
1009
|
+
if (a->excluded_cb_func)
|
|
1010
|
+
a->excluded_cb_func(&(a->archive),
|
|
1011
|
+
a->excluded_cb_data, entry);
|
|
1012
|
+
return (ARCHIVE_RETRY);
|
|
1013
|
+
}
|
|
1014
|
+
}
|
|
1015
|
+
|
|
1016
|
+
/* Lookup uname/gname */
|
|
1017
|
+
name = archive_read_disk_uname(&(a->archive), archive_entry_uid(entry));
|
|
1018
|
+
if (name != NULL)
|
|
1019
|
+
archive_entry_copy_uname(entry, name);
|
|
1020
|
+
name = archive_read_disk_gname(&(a->archive), archive_entry_gid(entry));
|
|
1021
|
+
if (name != NULL)
|
|
1022
|
+
archive_entry_copy_gname(entry, name);
|
|
1023
|
+
|
|
1024
|
+
/*
|
|
1025
|
+
* Perform owner matching.
|
|
1026
|
+
*/
|
|
1027
|
+
if (a->matching) {
|
|
1028
|
+
r = archive_match_owner_excluded(a->matching, entry);
|
|
1029
|
+
if (r < 0) {
|
|
1030
|
+
archive_set_error(&(a->archive), errno,
|
|
1031
|
+
"Failed : %s", archive_error_string(a->matching));
|
|
1032
|
+
return (r);
|
|
1033
|
+
}
|
|
1034
|
+
if (r) {
|
|
1035
|
+
if (a->excluded_cb_func)
|
|
1036
|
+
a->excluded_cb_func(&(a->archive),
|
|
1037
|
+
a->excluded_cb_data, entry);
|
|
1038
|
+
return (ARCHIVE_RETRY);
|
|
1039
|
+
}
|
|
1040
|
+
}
|
|
1041
|
+
|
|
1042
|
+
/*
|
|
1043
|
+
* File attributes
|
|
1044
|
+
*/
|
|
1045
|
+
if ((a->flags & ARCHIVE_READDISK_NO_FFLAGS) == 0) {
|
|
1046
|
+
const int supported_attrs =
|
|
1047
|
+
FILE_ATTRIBUTE_READONLY |
|
|
1048
|
+
FILE_ATTRIBUTE_HIDDEN |
|
|
1049
|
+
FILE_ATTRIBUTE_SYSTEM;
|
|
1050
|
+
DWORD file_attrs = st->dwFileAttributes & supported_attrs;
|
|
1051
|
+
if (file_attrs != 0)
|
|
1052
|
+
archive_entry_set_fflags(entry, file_attrs, 0);
|
|
1053
|
+
}
|
|
1054
|
+
|
|
1055
|
+
/*
|
|
1056
|
+
* Invoke a meta data filter callback.
|
|
1057
|
+
*/
|
|
1058
|
+
if (a->metadata_filter_func) {
|
|
1059
|
+
if (!a->metadata_filter_func(&(a->archive),
|
|
1060
|
+
a->metadata_filter_data, entry))
|
|
1061
|
+
return (ARCHIVE_RETRY);
|
|
1062
|
+
}
|
|
1063
|
+
|
|
1064
|
+
archive_entry_copy_sourcepath_w(entry, tree_current_access_path(t));
|
|
1065
|
+
|
|
1066
|
+
r = ARCHIVE_OK;
|
|
1067
|
+
if (archive_entry_filetype(entry) == AE_IFREG &&
|
|
1068
|
+
archive_entry_size(entry) > 0) {
|
|
1069
|
+
DWORD flags = FILE_FLAG_BACKUP_SEMANTICS;
|
|
1070
|
+
if (t->async_io)
|
|
1071
|
+
flags |= FILE_FLAG_OVERLAPPED;
|
|
1072
|
+
if (t->direct_io)
|
|
1073
|
+
flags |= FILE_FLAG_NO_BUFFERING;
|
|
1074
|
+
else
|
|
1075
|
+
flags |= FILE_FLAG_SEQUENTIAL_SCAN;
|
|
1076
|
+
t->entry_fh = CreateFileW(tree_current_access_path(t),
|
|
1077
|
+
GENERIC_READ,
|
|
1078
|
+
FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
|
|
1079
|
+
NULL, OPEN_EXISTING, flags, NULL);
|
|
1080
|
+
if (t->entry_fh == INVALID_HANDLE_VALUE) {
|
|
1081
|
+
la_dosmaperr(GetLastError());
|
|
1082
|
+
archive_set_error(&a->archive, errno,
|
|
1083
|
+
"Couldn't open %ls", tree_current_path(a->tree));
|
|
1084
|
+
return (ARCHIVE_FAILED);
|
|
1085
|
+
}
|
|
1086
|
+
|
|
1087
|
+
/* Find sparse data from the disk. */
|
|
1088
|
+
if ((a->flags & ARCHIVE_READDISK_NO_SPARSE) == 0) {
|
|
1089
|
+
if (archive_entry_hardlink(entry) == NULL &&
|
|
1090
|
+
(st->dwFileAttributes & FILE_ATTRIBUTE_SPARSE_FILE) != 0)
|
|
1091
|
+
r = setup_sparse_from_disk(a, entry, t->entry_fh);
|
|
1092
|
+
}
|
|
1093
|
+
}
|
|
1094
|
+
return (r);
|
|
1095
|
+
}
|
|
1096
|
+
|
|
1097
|
+
static int
|
|
1098
|
+
_archive_read_next_header(struct archive *_a, struct archive_entry **entryp)
|
|
1099
|
+
{
|
|
1100
|
+
int ret;
|
|
1101
|
+
struct archive_read_disk *a = (struct archive_read_disk *)_a;
|
|
1102
|
+
*entryp = NULL;
|
|
1103
|
+
ret = _archive_read_next_header2(_a, a->entry);
|
|
1104
|
+
*entryp = a->entry;
|
|
1105
|
+
return ret;
|
|
1106
|
+
}
|
|
1107
|
+
|
|
1108
|
+
static int
|
|
1109
|
+
_archive_read_next_header2(struct archive *_a, struct archive_entry *entry)
|
|
1110
|
+
{
|
|
1111
|
+
struct archive_read_disk *a = (struct archive_read_disk *)_a;
|
|
1112
|
+
struct tree *t;
|
|
1113
|
+
int r;
|
|
1114
|
+
|
|
1115
|
+
archive_check_magic(_a, ARCHIVE_READ_DISK_MAGIC,
|
|
1116
|
+
ARCHIVE_STATE_HEADER | ARCHIVE_STATE_DATA,
|
|
1117
|
+
"archive_read_next_header2");
|
|
1118
|
+
|
|
1119
|
+
t = a->tree;
|
|
1120
|
+
if (t->entry_fh != INVALID_HANDLE_VALUE) {
|
|
1121
|
+
cancel_async(t);
|
|
1122
|
+
close_and_restore_time(t->entry_fh, t, &t->restore_time);
|
|
1123
|
+
t->entry_fh = INVALID_HANDLE_VALUE;
|
|
1124
|
+
}
|
|
1125
|
+
|
|
1126
|
+
archive_entry_clear(entry);
|
|
1127
|
+
|
|
1128
|
+
while ((r = next_entry(a, t, entry)) == ARCHIVE_RETRY)
|
|
1129
|
+
archive_entry_clear(entry);
|
|
1130
|
+
|
|
1131
|
+
/*
|
|
1132
|
+
* EOF and FATAL are persistent at this layer. By
|
|
1133
|
+
* modifying the state, we guarantee that future calls to
|
|
1134
|
+
* read a header or read data will fail.
|
|
1135
|
+
*/
|
|
1136
|
+
switch (r) {
|
|
1137
|
+
case ARCHIVE_EOF:
|
|
1138
|
+
a->archive.state = ARCHIVE_STATE_EOF;
|
|
1139
|
+
break;
|
|
1140
|
+
case ARCHIVE_OK:
|
|
1141
|
+
case ARCHIVE_WARN:
|
|
1142
|
+
t->entry_total = 0;
|
|
1143
|
+
if (archive_entry_filetype(entry) == AE_IFREG) {
|
|
1144
|
+
t->entry_remaining_bytes = archive_entry_size(entry);
|
|
1145
|
+
t->entry_eof = (t->entry_remaining_bytes == 0)? 1: 0;
|
|
1146
|
+
if (!t->entry_eof &&
|
|
1147
|
+
setup_sparse(a, entry) != ARCHIVE_OK)
|
|
1148
|
+
return (ARCHIVE_FATAL);
|
|
1149
|
+
} else {
|
|
1150
|
+
t->entry_remaining_bytes = 0;
|
|
1151
|
+
t->entry_eof = 1;
|
|
1152
|
+
}
|
|
1153
|
+
t->ol_idx_doing = t->ol_idx_done = 0;
|
|
1154
|
+
t->ol_num_doing = t->ol_num_done = 0;
|
|
1155
|
+
t->ol_remaining_bytes = t->entry_remaining_bytes;
|
|
1156
|
+
t->ol_total = 0;
|
|
1157
|
+
a->archive.state = ARCHIVE_STATE_DATA;
|
|
1158
|
+
break;
|
|
1159
|
+
case ARCHIVE_RETRY:
|
|
1160
|
+
break;
|
|
1161
|
+
case ARCHIVE_FATAL:
|
|
1162
|
+
a->archive.state = ARCHIVE_STATE_FATAL;
|
|
1163
|
+
break;
|
|
1164
|
+
}
|
|
1165
|
+
|
|
1166
|
+
__archive_reset_read_data(&a->archive);
|
|
1167
|
+
return (r);
|
|
1168
|
+
}
|
|
1169
|
+
|
|
1170
|
+
static int
|
|
1171
|
+
setup_sparse(struct archive_read_disk *a, struct archive_entry *entry)
|
|
1172
|
+
{
|
|
1173
|
+
struct tree *t = a->tree;
|
|
1174
|
+
int64_t aligned, length, offset;
|
|
1175
|
+
int i;
|
|
1176
|
+
|
|
1177
|
+
t->sparse_count = archive_entry_sparse_reset(entry);
|
|
1178
|
+
if (t->sparse_count+1 > t->sparse_list_size) {
|
|
1179
|
+
free(t->sparse_list);
|
|
1180
|
+
t->sparse_list_size = t->sparse_count + 1;
|
|
1181
|
+
t->sparse_list = malloc(sizeof(t->sparse_list[0]) *
|
|
1182
|
+
t->sparse_list_size);
|
|
1183
|
+
if (t->sparse_list == NULL) {
|
|
1184
|
+
t->sparse_list_size = 0;
|
|
1185
|
+
archive_set_error(&a->archive, ENOMEM,
|
|
1186
|
+
"Can't allocate data");
|
|
1187
|
+
a->archive.state = ARCHIVE_STATE_FATAL;
|
|
1188
|
+
return (ARCHIVE_FATAL);
|
|
1189
|
+
}
|
|
1190
|
+
}
|
|
1191
|
+
/*
|
|
1192
|
+
* Get sparse list and make sure those offsets and lengths are
|
|
1193
|
+
* aligned by a sector size.
|
|
1194
|
+
*/
|
|
1195
|
+
for (i = 0; i < t->sparse_count; i++) {
|
|
1196
|
+
archive_entry_sparse_next(entry, &offset, &length);
|
|
1197
|
+
aligned = align_num_per_sector(t, offset);
|
|
1198
|
+
if (aligned != offset) {
|
|
1199
|
+
aligned -= t->current_filesystem->bytesPerSector;
|
|
1200
|
+
length += offset - aligned;
|
|
1201
|
+
}
|
|
1202
|
+
t->sparse_list[i].offset = aligned;
|
|
1203
|
+
aligned = align_num_per_sector(t, length);
|
|
1204
|
+
t->sparse_list[i].length = aligned;
|
|
1205
|
+
}
|
|
1206
|
+
|
|
1207
|
+
aligned = align_num_per_sector(t, archive_entry_size(entry));
|
|
1208
|
+
if (i == 0) {
|
|
1209
|
+
t->sparse_list[i].offset = 0;
|
|
1210
|
+
t->sparse_list[i].length = aligned;
|
|
1211
|
+
} else {
|
|
1212
|
+
int j, last = i;
|
|
1213
|
+
|
|
1214
|
+
t->sparse_list[i].offset = aligned;
|
|
1215
|
+
t->sparse_list[i].length = 0;
|
|
1216
|
+
for (i = 0; i < last; i++) {
|
|
1217
|
+
if ((t->sparse_list[i].offset +
|
|
1218
|
+
t->sparse_list[i].length) <=
|
|
1219
|
+
t->sparse_list[i+1].offset)
|
|
1220
|
+
continue;
|
|
1221
|
+
/*
|
|
1222
|
+
* Now sparse_list[i+1] is overlapped by sparse_list[i].
|
|
1223
|
+
* Merge those two.
|
|
1224
|
+
*/
|
|
1225
|
+
length = t->sparse_list[i+1].offset -
|
|
1226
|
+
t->sparse_list[i].offset;
|
|
1227
|
+
t->sparse_list[i+1].offset = t->sparse_list[i].offset;
|
|
1228
|
+
t->sparse_list[i+1].length += length;
|
|
1229
|
+
/* Remove sparse_list[i]. */
|
|
1230
|
+
for (j = i; j < last; j++) {
|
|
1231
|
+
t->sparse_list[j].offset =
|
|
1232
|
+
t->sparse_list[j+1].offset;
|
|
1233
|
+
t->sparse_list[j].length =
|
|
1234
|
+
t->sparse_list[j+1].length;
|
|
1235
|
+
}
|
|
1236
|
+
last--;
|
|
1237
|
+
}
|
|
1238
|
+
}
|
|
1239
|
+
t->current_sparse = t->sparse_list;
|
|
1240
|
+
|
|
1241
|
+
return (ARCHIVE_OK);
|
|
1242
|
+
}
|
|
1243
|
+
|
|
1244
|
+
int
|
|
1245
|
+
archive_read_disk_set_matching(struct archive *_a, struct archive *_ma,
|
|
1246
|
+
void (*_excluded_func)(struct archive *, void *, struct archive_entry *),
|
|
1247
|
+
void *_client_data)
|
|
1248
|
+
{
|
|
1249
|
+
struct archive_read_disk *a = (struct archive_read_disk *)_a;
|
|
1250
|
+
archive_check_magic(_a, ARCHIVE_READ_DISK_MAGIC,
|
|
1251
|
+
ARCHIVE_STATE_ANY, "archive_read_disk_set_matching");
|
|
1252
|
+
a->matching = _ma;
|
|
1253
|
+
a->excluded_cb_func = _excluded_func;
|
|
1254
|
+
a->excluded_cb_data = _client_data;
|
|
1255
|
+
return (ARCHIVE_OK);
|
|
1256
|
+
}
|
|
1257
|
+
|
|
1258
|
+
int
|
|
1259
|
+
archive_read_disk_set_metadata_filter_callback(struct archive *_a,
|
|
1260
|
+
int (*_metadata_filter_func)(struct archive *, void *,
|
|
1261
|
+
struct archive_entry *), void *_client_data)
|
|
1262
|
+
{
|
|
1263
|
+
struct archive_read_disk *a = (struct archive_read_disk *)_a;
|
|
1264
|
+
|
|
1265
|
+
archive_check_magic(_a, ARCHIVE_READ_DISK_MAGIC, ARCHIVE_STATE_ANY,
|
|
1266
|
+
"archive_read_disk_set_metadata_filter_callback");
|
|
1267
|
+
|
|
1268
|
+
a->metadata_filter_func = _metadata_filter_func;
|
|
1269
|
+
a->metadata_filter_data = _client_data;
|
|
1270
|
+
return (ARCHIVE_OK);
|
|
1271
|
+
}
|
|
1272
|
+
|
|
1273
|
+
int
|
|
1274
|
+
archive_read_disk_can_descend(struct archive *_a)
|
|
1275
|
+
{
|
|
1276
|
+
struct archive_read_disk *a = (struct archive_read_disk *)_a;
|
|
1277
|
+
struct tree *t = a->tree;
|
|
1278
|
+
|
|
1279
|
+
archive_check_magic(_a, ARCHIVE_READ_DISK_MAGIC,
|
|
1280
|
+
ARCHIVE_STATE_HEADER | ARCHIVE_STATE_DATA,
|
|
1281
|
+
"archive_read_disk_can_descend");
|
|
1282
|
+
|
|
1283
|
+
return (t->visit_type == TREE_REGULAR && t->descend);
|
|
1284
|
+
}
|
|
1285
|
+
|
|
1286
|
+
/*
|
|
1287
|
+
* Called by the client to mark the directory just returned from
|
|
1288
|
+
* tree_next() as needing to be visited.
|
|
1289
|
+
*/
|
|
1290
|
+
int
|
|
1291
|
+
archive_read_disk_descend(struct archive *_a)
|
|
1292
|
+
{
|
|
1293
|
+
struct archive_read_disk *a = (struct archive_read_disk *)_a;
|
|
1294
|
+
struct tree *t = a->tree;
|
|
1295
|
+
|
|
1296
|
+
archive_check_magic(_a, ARCHIVE_READ_DISK_MAGIC,
|
|
1297
|
+
ARCHIVE_STATE_HEADER | ARCHIVE_STATE_DATA,
|
|
1298
|
+
"archive_read_disk_descend");
|
|
1299
|
+
|
|
1300
|
+
if (!archive_read_disk_can_descend(_a))
|
|
1301
|
+
return (ARCHIVE_OK);
|
|
1302
|
+
|
|
1303
|
+
if (tree_current_is_physical_dir(t)) {
|
|
1304
|
+
tree_push(t, t->basename, t->full_path.s,
|
|
1305
|
+
t->current_filesystem_id,
|
|
1306
|
+
bhfi_dev(&(t->lst)), bhfi_ino(&(t->lst)),
|
|
1307
|
+
&t->restore_time);
|
|
1308
|
+
t->stack->flags |= isDir;
|
|
1309
|
+
} else if (tree_current_is_dir(t)) {
|
|
1310
|
+
tree_push(t, t->basename, t->full_path.s,
|
|
1311
|
+
t->current_filesystem_id,
|
|
1312
|
+
bhfi_dev(&(t->st)), bhfi_ino(&(t->st)),
|
|
1313
|
+
&t->restore_time);
|
|
1314
|
+
t->stack->flags |= isDirLink;
|
|
1315
|
+
}
|
|
1316
|
+
t->descend = 0;
|
|
1317
|
+
return (ARCHIVE_OK);
|
|
1318
|
+
}
|
|
1319
|
+
|
|
1320
|
+
int
|
|
1321
|
+
archive_read_disk_open(struct archive *_a, const char *pathname)
|
|
1322
|
+
{
|
|
1323
|
+
struct archive_read_disk *a = (struct archive_read_disk *)_a;
|
|
1324
|
+
struct archive_wstring wpath;
|
|
1325
|
+
int ret;
|
|
1326
|
+
|
|
1327
|
+
archive_check_magic(_a, ARCHIVE_READ_DISK_MAGIC,
|
|
1328
|
+
ARCHIVE_STATE_NEW | ARCHIVE_STATE_CLOSED,
|
|
1329
|
+
"archive_read_disk_open");
|
|
1330
|
+
archive_clear_error(&a->archive);
|
|
1331
|
+
|
|
1332
|
+
/* Make a wchar_t string from a char string. */
|
|
1333
|
+
archive_string_init(&wpath);
|
|
1334
|
+
if (archive_wstring_append_from_mbs(&wpath, pathname,
|
|
1335
|
+
strlen(pathname)) != 0) {
|
|
1336
|
+
if (errno == ENOMEM)
|
|
1337
|
+
archive_set_error(&a->archive, ENOMEM,
|
|
1338
|
+
"Can't allocate memory");
|
|
1339
|
+
else
|
|
1340
|
+
archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
|
|
1341
|
+
"Can't convert a path to a wchar_t string");
|
|
1342
|
+
a->archive.state = ARCHIVE_STATE_FATAL;
|
|
1343
|
+
ret = ARCHIVE_FATAL;
|
|
1344
|
+
} else
|
|
1345
|
+
ret = _archive_read_disk_open_w(_a, wpath.s);
|
|
1346
|
+
|
|
1347
|
+
archive_wstring_free(&wpath);
|
|
1348
|
+
return (ret);
|
|
1349
|
+
}
|
|
1350
|
+
|
|
1351
|
+
int
|
|
1352
|
+
archive_read_disk_open_w(struct archive *_a, const wchar_t *pathname)
|
|
1353
|
+
{
|
|
1354
|
+
struct archive_read_disk *a = (struct archive_read_disk *)_a;
|
|
1355
|
+
|
|
1356
|
+
archive_check_magic(_a, ARCHIVE_READ_DISK_MAGIC,
|
|
1357
|
+
ARCHIVE_STATE_NEW | ARCHIVE_STATE_CLOSED,
|
|
1358
|
+
"archive_read_disk_open_w");
|
|
1359
|
+
archive_clear_error(&a->archive);
|
|
1360
|
+
|
|
1361
|
+
return (_archive_read_disk_open_w(_a, pathname));
|
|
1362
|
+
}
|
|
1363
|
+
|
|
1364
|
+
static int
|
|
1365
|
+
_archive_read_disk_open_w(struct archive *_a, const wchar_t *pathname)
|
|
1366
|
+
{
|
|
1367
|
+
struct archive_read_disk *a = (struct archive_read_disk *)_a;
|
|
1368
|
+
|
|
1369
|
+
if (a->tree != NULL)
|
|
1370
|
+
a->tree = tree_reopen(a->tree, pathname,
|
|
1371
|
+
a->flags & ARCHIVE_READDISK_RESTORE_ATIME);
|
|
1372
|
+
else
|
|
1373
|
+
a->tree = tree_open(pathname, a->symlink_mode,
|
|
1374
|
+
a->flags & ARCHIVE_READDISK_RESTORE_ATIME);
|
|
1375
|
+
if (a->tree == NULL) {
|
|
1376
|
+
archive_set_error(&a->archive, ENOMEM,
|
|
1377
|
+
"Can't allocate directory traversal data");
|
|
1378
|
+
a->archive.state = ARCHIVE_STATE_FATAL;
|
|
1379
|
+
return (ARCHIVE_FATAL);
|
|
1380
|
+
}
|
|
1381
|
+
a->archive.state = ARCHIVE_STATE_HEADER;
|
|
1382
|
+
|
|
1383
|
+
return (ARCHIVE_OK);
|
|
1384
|
+
}
|
|
1385
|
+
|
|
1386
|
+
/*
|
|
1387
|
+
* Return a current filesystem ID which is index of the filesystem entry
|
|
1388
|
+
* you've visited through archive_read_disk.
|
|
1389
|
+
*/
|
|
1390
|
+
int
|
|
1391
|
+
archive_read_disk_current_filesystem(struct archive *_a)
|
|
1392
|
+
{
|
|
1393
|
+
struct archive_read_disk *a = (struct archive_read_disk *)_a;
|
|
1394
|
+
|
|
1395
|
+
archive_check_magic(_a, ARCHIVE_READ_DISK_MAGIC, ARCHIVE_STATE_DATA,
|
|
1396
|
+
"archive_read_disk_current_filesystem");
|
|
1397
|
+
|
|
1398
|
+
return (a->tree->current_filesystem_id);
|
|
1399
|
+
}
|
|
1400
|
+
|
|
1401
|
+
static int
|
|
1402
|
+
update_current_filesystem(struct archive_read_disk *a, int64_t dev)
|
|
1403
|
+
{
|
|
1404
|
+
struct tree *t = a->tree;
|
|
1405
|
+
int i, fid;
|
|
1406
|
+
|
|
1407
|
+
if (t->current_filesystem != NULL &&
|
|
1408
|
+
t->current_filesystem->dev == dev)
|
|
1409
|
+
return (ARCHIVE_OK);
|
|
1410
|
+
|
|
1411
|
+
for (i = 0; i < t->max_filesystem_id; i++) {
|
|
1412
|
+
if (t->filesystem_table[i].dev == dev) {
|
|
1413
|
+
/* There is the filesystem ID we've already generated. */
|
|
1414
|
+
t->current_filesystem_id = i;
|
|
1415
|
+
t->current_filesystem = &(t->filesystem_table[i]);
|
|
1416
|
+
return (ARCHIVE_OK);
|
|
1417
|
+
}
|
|
1418
|
+
}
|
|
1419
|
+
|
|
1420
|
+
/*
|
|
1421
|
+
* There is a new filesystem, we generate a new ID for.
|
|
1422
|
+
*/
|
|
1423
|
+
fid = t->max_filesystem_id++;
|
|
1424
|
+
if (t->max_filesystem_id > t->allocated_filesystem) {
|
|
1425
|
+
size_t s;
|
|
1426
|
+
void *p;
|
|
1427
|
+
|
|
1428
|
+
s = t->max_filesystem_id * 2;
|
|
1429
|
+
p = realloc(t->filesystem_table,
|
|
1430
|
+
s * sizeof(*t->filesystem_table));
|
|
1431
|
+
if (p == NULL) {
|
|
1432
|
+
archive_set_error(&a->archive, ENOMEM,
|
|
1433
|
+
"Can't allocate tar data");
|
|
1434
|
+
return (ARCHIVE_FATAL);
|
|
1435
|
+
}
|
|
1436
|
+
t->filesystem_table = (struct filesystem *)p;
|
|
1437
|
+
t->allocated_filesystem = (int)s;
|
|
1438
|
+
}
|
|
1439
|
+
t->current_filesystem_id = fid;
|
|
1440
|
+
t->current_filesystem = &(t->filesystem_table[fid]);
|
|
1441
|
+
t->current_filesystem->dev = dev;
|
|
1442
|
+
|
|
1443
|
+
return (setup_current_filesystem(a));
|
|
1444
|
+
}
|
|
1445
|
+
|
|
1446
|
+
/*
|
|
1447
|
+
* Returns 1 if current filesystem is generated filesystem, 0 if it is not
|
|
1448
|
+
* or -1 if it is unknown.
|
|
1449
|
+
*/
|
|
1450
|
+
int
|
|
1451
|
+
archive_read_disk_current_filesystem_is_synthetic(struct archive *_a)
|
|
1452
|
+
{
|
|
1453
|
+
struct archive_read_disk *a = (struct archive_read_disk *)_a;
|
|
1454
|
+
|
|
1455
|
+
archive_check_magic(_a, ARCHIVE_READ_DISK_MAGIC, ARCHIVE_STATE_DATA,
|
|
1456
|
+
"archive_read_disk_current_filesystem");
|
|
1457
|
+
|
|
1458
|
+
return (a->tree->current_filesystem->synthetic);
|
|
1459
|
+
}
|
|
1460
|
+
|
|
1461
|
+
/*
|
|
1462
|
+
* Returns 1 if current filesystem is remote filesystem, 0 if it is not
|
|
1463
|
+
* or -1 if it is unknown.
|
|
1464
|
+
*/
|
|
1465
|
+
int
|
|
1466
|
+
archive_read_disk_current_filesystem_is_remote(struct archive *_a)
|
|
1467
|
+
{
|
|
1468
|
+
struct archive_read_disk *a = (struct archive_read_disk *)_a;
|
|
1469
|
+
|
|
1470
|
+
archive_check_magic(_a, ARCHIVE_READ_DISK_MAGIC, ARCHIVE_STATE_DATA,
|
|
1471
|
+
"archive_read_disk_current_filesystem");
|
|
1472
|
+
|
|
1473
|
+
return (a->tree->current_filesystem->remote);
|
|
1474
|
+
}
|
|
1475
|
+
|
|
1476
|
+
/*
|
|
1477
|
+
* If symlink is broken, statfs or statvfs will fail.
|
|
1478
|
+
* Use its directory path instead.
|
|
1479
|
+
*/
|
|
1480
|
+
static wchar_t *
|
|
1481
|
+
safe_path_for_statfs(struct tree *t)
|
|
1482
|
+
{
|
|
1483
|
+
const wchar_t *path;
|
|
1484
|
+
wchar_t *cp, *p = NULL;
|
|
1485
|
+
|
|
1486
|
+
path = tree_current_access_path(t);
|
|
1487
|
+
if (tree_current_stat(t) == NULL) {
|
|
1488
|
+
p = _wcsdup(path);
|
|
1489
|
+
cp = wcsrchr(p, '/');
|
|
1490
|
+
if (cp != NULL && wcslen(cp) >= 2) {
|
|
1491
|
+
cp[1] = '.';
|
|
1492
|
+
cp[2] = '\0';
|
|
1493
|
+
path = p;
|
|
1494
|
+
}
|
|
1495
|
+
} else
|
|
1496
|
+
p = _wcsdup(path);
|
|
1497
|
+
return (p);
|
|
1498
|
+
}
|
|
1499
|
+
|
|
1500
|
+
/*
|
|
1501
|
+
* Get conditions of synthetic and remote on Windows
|
|
1502
|
+
*/
|
|
1503
|
+
static int
|
|
1504
|
+
setup_current_filesystem(struct archive_read_disk *a)
|
|
1505
|
+
{
|
|
1506
|
+
struct tree *t = a->tree;
|
|
1507
|
+
wchar_t vol[256];
|
|
1508
|
+
wchar_t *path;
|
|
1509
|
+
|
|
1510
|
+
t->current_filesystem->synthetic = -1;/* Not supported */
|
|
1511
|
+
path = safe_path_for_statfs(t);
|
|
1512
|
+
if (!GetVolumePathNameW(path, vol, sizeof(vol)/sizeof(vol[0]))) {
|
|
1513
|
+
free(path);
|
|
1514
|
+
t->current_filesystem->remote = -1;
|
|
1515
|
+
t->current_filesystem->bytesPerSector = 0;
|
|
1516
|
+
archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
|
|
1517
|
+
"GetVolumePathName failed: %d", (int)GetLastError());
|
|
1518
|
+
return (ARCHIVE_FAILED);
|
|
1519
|
+
}
|
|
1520
|
+
free(path);
|
|
1521
|
+
switch (GetDriveTypeW(vol)) {
|
|
1522
|
+
case DRIVE_UNKNOWN:
|
|
1523
|
+
case DRIVE_NO_ROOT_DIR:
|
|
1524
|
+
t->current_filesystem->remote = -1;
|
|
1525
|
+
break;
|
|
1526
|
+
case DRIVE_REMOTE:
|
|
1527
|
+
t->current_filesystem->remote = 1;
|
|
1528
|
+
break;
|
|
1529
|
+
default:
|
|
1530
|
+
t->current_filesystem->remote = 0;
|
|
1531
|
+
break;
|
|
1532
|
+
}
|
|
1533
|
+
|
|
1534
|
+
if (!GetDiskFreeSpaceW(vol, NULL,
|
|
1535
|
+
&(t->current_filesystem->bytesPerSector), NULL, NULL)) {
|
|
1536
|
+
t->current_filesystem->bytesPerSector = 0;
|
|
1537
|
+
archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
|
|
1538
|
+
"GetDiskFreeSpace failed: %d", (int)GetLastError());
|
|
1539
|
+
return (ARCHIVE_FAILED);
|
|
1540
|
+
}
|
|
1541
|
+
|
|
1542
|
+
return (ARCHIVE_OK);
|
|
1543
|
+
}
|
|
1544
|
+
|
|
1545
|
+
static int
|
|
1546
|
+
close_and_restore_time(HANDLE h, struct tree *t, struct restore_time *rt)
|
|
1547
|
+
{
|
|
1548
|
+
HANDLE handle;
|
|
1549
|
+
int r = 0;
|
|
1550
|
+
|
|
1551
|
+
if (h == INVALID_HANDLE_VALUE && AE_IFLNK == rt->filetype)
|
|
1552
|
+
return (0);
|
|
1553
|
+
|
|
1554
|
+
/* Close a file descriptor.
|
|
1555
|
+
* It will not be used for SetFileTime() because it has been opened
|
|
1556
|
+
* by a read only mode.
|
|
1557
|
+
*/
|
|
1558
|
+
if (h != INVALID_HANDLE_VALUE)
|
|
1559
|
+
CloseHandle(h);
|
|
1560
|
+
if ((t->flags & needsRestoreTimes) == 0)
|
|
1561
|
+
return (r);
|
|
1562
|
+
|
|
1563
|
+
handle = CreateFileW(rt->full_path, FILE_WRITE_ATTRIBUTES,
|
|
1564
|
+
0, NULL, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, NULL);
|
|
1565
|
+
if (handle == INVALID_HANDLE_VALUE) {
|
|
1566
|
+
errno = EINVAL;
|
|
1567
|
+
return (-1);
|
|
1568
|
+
}
|
|
1569
|
+
|
|
1570
|
+
if (SetFileTime(handle, NULL, &rt->lastAccessTime,
|
|
1571
|
+
&rt->lastWriteTime) == 0) {
|
|
1572
|
+
errno = EINVAL;
|
|
1573
|
+
r = -1;
|
|
1574
|
+
} else
|
|
1575
|
+
r = 0;
|
|
1576
|
+
CloseHandle(handle);
|
|
1577
|
+
return (r);
|
|
1578
|
+
}
|
|
1579
|
+
|
|
1580
|
+
/*
|
|
1581
|
+
* Add a directory path to the current stack.
|
|
1582
|
+
*/
|
|
1583
|
+
static void
|
|
1584
|
+
tree_push(struct tree *t, const wchar_t *path, const wchar_t *full_path,
|
|
1585
|
+
int filesystem_id, int64_t dev, int64_t ino, struct restore_time *rt)
|
|
1586
|
+
{
|
|
1587
|
+
struct tree_entry *te;
|
|
1588
|
+
|
|
1589
|
+
te = calloc(1, sizeof(*te));
|
|
1590
|
+
te->next = t->stack;
|
|
1591
|
+
te->parent = t->current;
|
|
1592
|
+
if (te->parent)
|
|
1593
|
+
te->depth = te->parent->depth + 1;
|
|
1594
|
+
t->stack = te;
|
|
1595
|
+
archive_string_init(&te->name);
|
|
1596
|
+
archive_wstrcpy(&te->name, path);
|
|
1597
|
+
archive_string_init(&te->full_path);
|
|
1598
|
+
archive_wstrcpy(&te->full_path, full_path);
|
|
1599
|
+
te->flags = needsDescent | needsOpen | needsAscent;
|
|
1600
|
+
te->filesystem_id = filesystem_id;
|
|
1601
|
+
te->dev = dev;
|
|
1602
|
+
te->ino = ino;
|
|
1603
|
+
te->dirname_length = t->dirname_length;
|
|
1604
|
+
te->full_path_dir_length = t->full_path_dir_length;
|
|
1605
|
+
te->restore_time.full_path = te->full_path.s;
|
|
1606
|
+
if (rt != NULL) {
|
|
1607
|
+
te->restore_time.lastWriteTime = rt->lastWriteTime;
|
|
1608
|
+
te->restore_time.lastAccessTime = rt->lastAccessTime;
|
|
1609
|
+
te->restore_time.filetype = rt->filetype;
|
|
1610
|
+
}
|
|
1611
|
+
}
|
|
1612
|
+
|
|
1613
|
+
/*
|
|
1614
|
+
* Append a name to the current dir path.
|
|
1615
|
+
*/
|
|
1616
|
+
static void
|
|
1617
|
+
tree_append(struct tree *t, const wchar_t *name, size_t name_length)
|
|
1618
|
+
{
|
|
1619
|
+
size_t size_needed;
|
|
1620
|
+
|
|
1621
|
+
t->path.s[t->dirname_length] = L'\0';
|
|
1622
|
+
t->path.length = t->dirname_length;
|
|
1623
|
+
/* Strip trailing '/' from name, unless entire name is "/". */
|
|
1624
|
+
while (name_length > 1 && name[name_length - 1] == L'/')
|
|
1625
|
+
name_length--;
|
|
1626
|
+
|
|
1627
|
+
/* Resize pathname buffer as needed. */
|
|
1628
|
+
size_needed = name_length + t->dirname_length + 2;
|
|
1629
|
+
archive_wstring_ensure(&t->path, size_needed);
|
|
1630
|
+
/* Add a separating '/' if it's needed. */
|
|
1631
|
+
if (t->dirname_length > 0 &&
|
|
1632
|
+
t->path.s[archive_strlen(&t->path)-1] != L'/')
|
|
1633
|
+
archive_wstrappend_wchar(&t->path, L'/');
|
|
1634
|
+
t->basename = t->path.s + archive_strlen(&t->path);
|
|
1635
|
+
archive_wstrncat(&t->path, name, name_length);
|
|
1636
|
+
t->restore_time.full_path = t->basename;
|
|
1637
|
+
if (t->full_path_dir_length > 0) {
|
|
1638
|
+
t->full_path.s[t->full_path_dir_length] = L'\0';
|
|
1639
|
+
t->full_path.length = t->full_path_dir_length;
|
|
1640
|
+
size_needed = name_length + t->full_path_dir_length + 2;
|
|
1641
|
+
archive_wstring_ensure(&t->full_path, size_needed);
|
|
1642
|
+
/* Add a separating '\' if it's needed. */
|
|
1643
|
+
if (t->full_path.s[archive_strlen(&t->full_path)-1] != L'\\')
|
|
1644
|
+
archive_wstrappend_wchar(&t->full_path, L'\\');
|
|
1645
|
+
archive_wstrncat(&t->full_path, name, name_length);
|
|
1646
|
+
t->restore_time.full_path = t->full_path.s;
|
|
1647
|
+
}
|
|
1648
|
+
}
|
|
1649
|
+
|
|
1650
|
+
/*
|
|
1651
|
+
* Open a directory tree for traversal.
|
|
1652
|
+
*/
|
|
1653
|
+
static struct tree *
|
|
1654
|
+
tree_open(const wchar_t *path, int symlink_mode, int restore_time)
|
|
1655
|
+
{
|
|
1656
|
+
struct tree *t;
|
|
1657
|
+
|
|
1658
|
+
t = calloc(1, sizeof(*t));
|
|
1659
|
+
archive_string_init(&(t->full_path));
|
|
1660
|
+
archive_string_init(&t->path);
|
|
1661
|
+
archive_wstring_ensure(&t->path, 15);
|
|
1662
|
+
t->initial_symlink_mode = symlink_mode;
|
|
1663
|
+
return (tree_reopen(t, path, restore_time));
|
|
1664
|
+
}
|
|
1665
|
+
|
|
1666
|
+
static struct tree *
|
|
1667
|
+
tree_reopen(struct tree *t, const wchar_t *path, int restore_time)
|
|
1668
|
+
{
|
|
1669
|
+
struct archive_wstring ws;
|
|
1670
|
+
wchar_t *pathname, *p, *base;
|
|
1671
|
+
|
|
1672
|
+
t->flags = (restore_time != 0)?needsRestoreTimes:0;
|
|
1673
|
+
t->visit_type = 0;
|
|
1674
|
+
t->tree_errno = 0;
|
|
1675
|
+
t->full_path_dir_length = 0;
|
|
1676
|
+
t->dirname_length = 0;
|
|
1677
|
+
t->depth = 0;
|
|
1678
|
+
t->descend = 0;
|
|
1679
|
+
t->current = NULL;
|
|
1680
|
+
t->d = INVALID_HANDLE_VALUE;
|
|
1681
|
+
t->symlink_mode = t->initial_symlink_mode;
|
|
1682
|
+
archive_string_empty(&(t->full_path));
|
|
1683
|
+
archive_string_empty(&t->path);
|
|
1684
|
+
t->entry_fh = INVALID_HANDLE_VALUE;
|
|
1685
|
+
t->entry_eof = 0;
|
|
1686
|
+
t->entry_remaining_bytes = 0;
|
|
1687
|
+
t->initial_filesystem_id = -1;
|
|
1688
|
+
|
|
1689
|
+
/* Get wchar_t strings from char strings. */
|
|
1690
|
+
archive_string_init(&ws);
|
|
1691
|
+
archive_wstrcpy(&ws, path);
|
|
1692
|
+
pathname = ws.s;
|
|
1693
|
+
/* Get a full-path-name. */
|
|
1694
|
+
p = __la_win_permissive_name_w(pathname);
|
|
1695
|
+
if (p == NULL)
|
|
1696
|
+
goto failed;
|
|
1697
|
+
archive_wstrcpy(&(t->full_path), p);
|
|
1698
|
+
free(p);
|
|
1699
|
+
|
|
1700
|
+
/* Convert path separators from '\' to '/' */
|
|
1701
|
+
for (p = pathname; *p != L'\0'; ++p) {
|
|
1702
|
+
if (*p == L'\\')
|
|
1703
|
+
*p = L'/';
|
|
1704
|
+
}
|
|
1705
|
+
base = pathname;
|
|
1706
|
+
|
|
1707
|
+
/* First item is set up a lot like a symlink traversal. */
|
|
1708
|
+
/* printf("Looking for wildcard in %s\n", path); */
|
|
1709
|
+
if ((base[0] == L'/' && base[1] == L'/' &&
|
|
1710
|
+
base[2] == L'?' && base[3] == L'/' &&
|
|
1711
|
+
(wcschr(base+4, L'*') || wcschr(base+4, L'?'))) ||
|
|
1712
|
+
(!(base[0] == L'/' && base[1] == L'/' &&
|
|
1713
|
+
base[2] == L'?' && base[3] == L'/') &&
|
|
1714
|
+
(wcschr(base, L'*') || wcschr(base, L'?')))) {
|
|
1715
|
+
// It has a wildcard in it...
|
|
1716
|
+
// Separate the last element.
|
|
1717
|
+
p = wcsrchr(base, L'/');
|
|
1718
|
+
if (p != NULL) {
|
|
1719
|
+
*p = L'\0';
|
|
1720
|
+
tree_append(t, base, p - base);
|
|
1721
|
+
t->dirname_length = archive_strlen(&t->path);
|
|
1722
|
+
base = p + 1;
|
|
1723
|
+
}
|
|
1724
|
+
p = wcsrchr(t->full_path.s, L'\\');
|
|
1725
|
+
if (p != NULL) {
|
|
1726
|
+
*p = L'\0';
|
|
1727
|
+
t->full_path.length = wcslen(t->full_path.s);
|
|
1728
|
+
t->full_path_dir_length = archive_strlen(&t->full_path);
|
|
1729
|
+
}
|
|
1730
|
+
}
|
|
1731
|
+
tree_push(t, base, t->full_path.s, 0, 0, 0, NULL);
|
|
1732
|
+
archive_wstring_free(&ws);
|
|
1733
|
+
t->stack->flags = needsFirstVisit;
|
|
1734
|
+
/*
|
|
1735
|
+
* Debug flag for Direct IO(No buffering) or Async IO.
|
|
1736
|
+
* Those dependent on environment variable switches
|
|
1737
|
+
* will be removed until next release.
|
|
1738
|
+
*/
|
|
1739
|
+
{
|
|
1740
|
+
const char *e;
|
|
1741
|
+
if ((e = getenv("LIBARCHIVE_DIRECT_IO")) != NULL) {
|
|
1742
|
+
if (e[0] == '0')
|
|
1743
|
+
t->direct_io = 0;
|
|
1744
|
+
else
|
|
1745
|
+
t->direct_io = 1;
|
|
1746
|
+
fprintf(stderr, "LIBARCHIVE_DIRECT_IO=%s\n",
|
|
1747
|
+
(t->direct_io)?"Enabled":"Disabled");
|
|
1748
|
+
} else
|
|
1749
|
+
t->direct_io = DIRECT_IO;
|
|
1750
|
+
if ((e = getenv("LIBARCHIVE_ASYNC_IO")) != NULL) {
|
|
1751
|
+
if (e[0] == '0')
|
|
1752
|
+
t->async_io = 0;
|
|
1753
|
+
else
|
|
1754
|
+
t->async_io = 1;
|
|
1755
|
+
fprintf(stderr, "LIBARCHIVE_ASYNC_IO=%s\n",
|
|
1756
|
+
(t->async_io)?"Enabled":"Disabled");
|
|
1757
|
+
} else
|
|
1758
|
+
t->async_io = ASYNC_IO;
|
|
1759
|
+
}
|
|
1760
|
+
return (t);
|
|
1761
|
+
failed:
|
|
1762
|
+
archive_wstring_free(&ws);
|
|
1763
|
+
tree_free(t);
|
|
1764
|
+
return (NULL);
|
|
1765
|
+
}
|
|
1766
|
+
|
|
1767
|
+
static int
|
|
1768
|
+
tree_descent(struct tree *t)
|
|
1769
|
+
{
|
|
1770
|
+
t->dirname_length = archive_strlen(&t->path);
|
|
1771
|
+
t->full_path_dir_length = archive_strlen(&t->full_path);
|
|
1772
|
+
t->depth++;
|
|
1773
|
+
return (0);
|
|
1774
|
+
}
|
|
1775
|
+
|
|
1776
|
+
/*
|
|
1777
|
+
* We've finished a directory; ascend back to the parent.
|
|
1778
|
+
*/
|
|
1779
|
+
static int
|
|
1780
|
+
tree_ascend(struct tree *t)
|
|
1781
|
+
{
|
|
1782
|
+
struct tree_entry *te;
|
|
1783
|
+
|
|
1784
|
+
te = t->stack;
|
|
1785
|
+
t->depth--;
|
|
1786
|
+
close_and_restore_time(INVALID_HANDLE_VALUE, t, &te->restore_time);
|
|
1787
|
+
return (0);
|
|
1788
|
+
}
|
|
1789
|
+
|
|
1790
|
+
/*
|
|
1791
|
+
* Pop the working stack.
|
|
1792
|
+
*/
|
|
1793
|
+
static void
|
|
1794
|
+
tree_pop(struct tree *t)
|
|
1795
|
+
{
|
|
1796
|
+
struct tree_entry *te;
|
|
1797
|
+
|
|
1798
|
+
t->full_path.s[t->full_path_dir_length] = L'\0';
|
|
1799
|
+
t->full_path.length = t->full_path_dir_length;
|
|
1800
|
+
t->path.s[t->dirname_length] = L'\0';
|
|
1801
|
+
t->path.length = t->dirname_length;
|
|
1802
|
+
if (t->stack == t->current && t->current != NULL)
|
|
1803
|
+
t->current = t->current->parent;
|
|
1804
|
+
te = t->stack;
|
|
1805
|
+
t->stack = te->next;
|
|
1806
|
+
t->dirname_length = te->dirname_length;
|
|
1807
|
+
t->basename = t->path.s + t->dirname_length;
|
|
1808
|
+
t->full_path_dir_length = te->full_path_dir_length;
|
|
1809
|
+
while (t->basename[0] == L'/')
|
|
1810
|
+
t->basename++;
|
|
1811
|
+
archive_wstring_free(&te->name);
|
|
1812
|
+
archive_wstring_free(&te->full_path);
|
|
1813
|
+
free(te);
|
|
1814
|
+
}
|
|
1815
|
+
|
|
1816
|
+
/*
|
|
1817
|
+
* Get the next item in the tree traversal.
|
|
1818
|
+
*/
|
|
1819
|
+
static int
|
|
1820
|
+
tree_next(struct tree *t)
|
|
1821
|
+
{
|
|
1822
|
+
int r;
|
|
1823
|
+
|
|
1824
|
+
while (t->stack != NULL) {
|
|
1825
|
+
/* If there's an open dir, get the next entry from there. */
|
|
1826
|
+
if (t->d != INVALID_HANDLE_VALUE) {
|
|
1827
|
+
r = tree_dir_next_windows(t, NULL);
|
|
1828
|
+
if (r == 0)
|
|
1829
|
+
continue;
|
|
1830
|
+
return (r);
|
|
1831
|
+
}
|
|
1832
|
+
|
|
1833
|
+
if (t->stack->flags & needsFirstVisit) {
|
|
1834
|
+
wchar_t *d = t->stack->name.s;
|
|
1835
|
+
t->stack->flags &= ~needsFirstVisit;
|
|
1836
|
+
if (!(d[0] == L'/' && d[1] == L'/' &&
|
|
1837
|
+
d[2] == L'?' && d[3] == L'/') &&
|
|
1838
|
+
(wcschr(d, L'*') || wcschr(d, L'?'))) {
|
|
1839
|
+
r = tree_dir_next_windows(t, d);
|
|
1840
|
+
if (r == 0)
|
|
1841
|
+
continue;
|
|
1842
|
+
return (r);
|
|
1843
|
+
} else {
|
|
1844
|
+
HANDLE h = FindFirstFileW(t->stack->full_path.s, &t->_findData);
|
|
1845
|
+
if (h == INVALID_HANDLE_VALUE) {
|
|
1846
|
+
la_dosmaperr(GetLastError());
|
|
1847
|
+
t->tree_errno = errno;
|
|
1848
|
+
t->visit_type = TREE_ERROR_DIR;
|
|
1849
|
+
return (t->visit_type);
|
|
1850
|
+
}
|
|
1851
|
+
t->findData = &t->_findData;
|
|
1852
|
+
FindClose(h);
|
|
1853
|
+
}
|
|
1854
|
+
/* Top stack item needs a regular visit. */
|
|
1855
|
+
t->current = t->stack;
|
|
1856
|
+
tree_append(t, t->stack->name.s,
|
|
1857
|
+
archive_strlen(&(t->stack->name)));
|
|
1858
|
+
//t->dirname_length = t->path_length;
|
|
1859
|
+
//tree_pop(t);
|
|
1860
|
+
t->stack->flags &= ~needsFirstVisit;
|
|
1861
|
+
return (t->visit_type = TREE_REGULAR);
|
|
1862
|
+
} else if (t->stack->flags & needsDescent) {
|
|
1863
|
+
/* Top stack item is dir to descend into. */
|
|
1864
|
+
t->current = t->stack;
|
|
1865
|
+
tree_append(t, t->stack->name.s,
|
|
1866
|
+
archive_strlen(&(t->stack->name)));
|
|
1867
|
+
t->stack->flags &= ~needsDescent;
|
|
1868
|
+
r = tree_descent(t);
|
|
1869
|
+
if (r != 0) {
|
|
1870
|
+
tree_pop(t);
|
|
1871
|
+
t->visit_type = r;
|
|
1872
|
+
} else
|
|
1873
|
+
t->visit_type = TREE_POSTDESCENT;
|
|
1874
|
+
return (t->visit_type);
|
|
1875
|
+
} else if (t->stack->flags & needsOpen) {
|
|
1876
|
+
t->stack->flags &= ~needsOpen;
|
|
1877
|
+
r = tree_dir_next_windows(t, L"*");
|
|
1878
|
+
if (r == 0)
|
|
1879
|
+
continue;
|
|
1880
|
+
return (r);
|
|
1881
|
+
} else if (t->stack->flags & needsAscent) {
|
|
1882
|
+
/* Top stack item is dir and we're done with it. */
|
|
1883
|
+
r = tree_ascend(t);
|
|
1884
|
+
tree_pop(t);
|
|
1885
|
+
t->visit_type = r != 0 ? r : TREE_POSTASCENT;
|
|
1886
|
+
return (t->visit_type);
|
|
1887
|
+
} else {
|
|
1888
|
+
/* Top item on stack is dead. */
|
|
1889
|
+
tree_pop(t);
|
|
1890
|
+
t->flags &= ~hasLstat;
|
|
1891
|
+
t->flags &= ~hasStat;
|
|
1892
|
+
}
|
|
1893
|
+
}
|
|
1894
|
+
return (t->visit_type = 0);
|
|
1895
|
+
}
|
|
1896
|
+
|
|
1897
|
+
static int
|
|
1898
|
+
tree_dir_next_windows(struct tree *t, const wchar_t *pattern)
|
|
1899
|
+
{
|
|
1900
|
+
const wchar_t *name;
|
|
1901
|
+
size_t namelen;
|
|
1902
|
+
int r;
|
|
1903
|
+
|
|
1904
|
+
for (;;) {
|
|
1905
|
+
if (pattern != NULL) {
|
|
1906
|
+
struct archive_wstring pt;
|
|
1907
|
+
|
|
1908
|
+
archive_string_init(&pt);
|
|
1909
|
+
archive_wstring_ensure(&pt,
|
|
1910
|
+
archive_strlen(&(t->full_path))
|
|
1911
|
+
+ 2 + wcslen(pattern));
|
|
1912
|
+
archive_wstring_copy(&pt, &(t->full_path));
|
|
1913
|
+
archive_wstrappend_wchar(&pt, L'\\');
|
|
1914
|
+
archive_wstrcat(&pt, pattern);
|
|
1915
|
+
t->d = FindFirstFileW(pt.s, &t->_findData);
|
|
1916
|
+
archive_wstring_free(&pt);
|
|
1917
|
+
if (t->d == INVALID_HANDLE_VALUE) {
|
|
1918
|
+
la_dosmaperr(GetLastError());
|
|
1919
|
+
t->tree_errno = errno;
|
|
1920
|
+
r = tree_ascend(t); /* Undo "chdir" */
|
|
1921
|
+
tree_pop(t);
|
|
1922
|
+
t->visit_type = r != 0 ? r : TREE_ERROR_DIR;
|
|
1923
|
+
return (t->visit_type);
|
|
1924
|
+
}
|
|
1925
|
+
t->findData = &t->_findData;
|
|
1926
|
+
pattern = NULL;
|
|
1927
|
+
} else if (!FindNextFileW(t->d, &t->_findData)) {
|
|
1928
|
+
FindClose(t->d);
|
|
1929
|
+
t->d = INVALID_HANDLE_VALUE;
|
|
1930
|
+
t->findData = NULL;
|
|
1931
|
+
return (0);
|
|
1932
|
+
}
|
|
1933
|
+
name = t->findData->cFileName;
|
|
1934
|
+
namelen = wcslen(name);
|
|
1935
|
+
t->flags &= ~hasLstat;
|
|
1936
|
+
t->flags &= ~hasStat;
|
|
1937
|
+
if (name[0] == L'.' && name[1] == L'\0')
|
|
1938
|
+
continue;
|
|
1939
|
+
if (name[0] == L'.' && name[1] == L'.' && name[2] == L'\0')
|
|
1940
|
+
continue;
|
|
1941
|
+
tree_append(t, name, namelen);
|
|
1942
|
+
return (t->visit_type = TREE_REGULAR);
|
|
1943
|
+
}
|
|
1944
|
+
}
|
|
1945
|
+
|
|
1946
|
+
#define EPOC_TIME ARCHIVE_LITERAL_ULL(116444736000000000)
|
|
1947
|
+
static void
|
|
1948
|
+
fileTimeToUtc(const FILETIME *filetime, time_t *t, long *ns)
|
|
1949
|
+
{
|
|
1950
|
+
ULARGE_INTEGER utc;
|
|
1951
|
+
|
|
1952
|
+
utc.HighPart = filetime->dwHighDateTime;
|
|
1953
|
+
utc.LowPart = filetime->dwLowDateTime;
|
|
1954
|
+
if (utc.QuadPart >= EPOC_TIME) {
|
|
1955
|
+
utc.QuadPart -= EPOC_TIME;
|
|
1956
|
+
/* milli seconds base */
|
|
1957
|
+
*t = (time_t)(utc.QuadPart / 10000000);
|
|
1958
|
+
/* nano seconds base */
|
|
1959
|
+
*ns = (long)(utc.QuadPart % 10000000) * 100;
|
|
1960
|
+
} else {
|
|
1961
|
+
*t = 0;
|
|
1962
|
+
*ns = 0;
|
|
1963
|
+
}
|
|
1964
|
+
}
|
|
1965
|
+
|
|
1966
|
+
static void
|
|
1967
|
+
entry_copy_bhfi(struct archive_entry *entry, const wchar_t *path,
|
|
1968
|
+
const WIN32_FIND_DATAW *findData,
|
|
1969
|
+
const BY_HANDLE_FILE_INFORMATION *bhfi)
|
|
1970
|
+
{
|
|
1971
|
+
time_t secs;
|
|
1972
|
+
long nsecs;
|
|
1973
|
+
mode_t mode;
|
|
1974
|
+
|
|
1975
|
+
fileTimeToUtc(&bhfi->ftLastAccessTime, &secs, &nsecs);
|
|
1976
|
+
archive_entry_set_atime(entry, secs, nsecs);
|
|
1977
|
+
fileTimeToUtc(&bhfi->ftLastWriteTime, &secs, &nsecs);
|
|
1978
|
+
archive_entry_set_mtime(entry, secs, nsecs);
|
|
1979
|
+
fileTimeToUtc(&bhfi->ftCreationTime, &secs, &nsecs);
|
|
1980
|
+
archive_entry_set_birthtime(entry, secs, nsecs);
|
|
1981
|
+
archive_entry_set_ctime(entry, secs, nsecs);
|
|
1982
|
+
archive_entry_set_dev(entry, bhfi_dev(bhfi));
|
|
1983
|
+
archive_entry_set_ino64(entry, bhfi_ino(bhfi));
|
|
1984
|
+
if (bhfi->dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
|
|
1985
|
+
archive_entry_set_nlink(entry, bhfi->nNumberOfLinks + 1);
|
|
1986
|
+
else
|
|
1987
|
+
archive_entry_set_nlink(entry, bhfi->nNumberOfLinks);
|
|
1988
|
+
archive_entry_set_size(entry,
|
|
1989
|
+
(((int64_t)bhfi->nFileSizeHigh) << 32)
|
|
1990
|
+
+ bhfi->nFileSizeLow);
|
|
1991
|
+
archive_entry_set_uid(entry, 0);
|
|
1992
|
+
archive_entry_set_gid(entry, 0);
|
|
1993
|
+
archive_entry_set_rdev(entry, 0);
|
|
1994
|
+
|
|
1995
|
+
mode = S_IRUSR | S_IRGRP | S_IROTH;
|
|
1996
|
+
if ((bhfi->dwFileAttributes & FILE_ATTRIBUTE_READONLY) == 0)
|
|
1997
|
+
mode |= S_IWUSR | S_IWGRP | S_IWOTH;
|
|
1998
|
+
if ((bhfi->dwFileAttributes & FILE_ATTRIBUTE_REPARSE_POINT) &&
|
|
1999
|
+
findData != NULL &&
|
|
2000
|
+
findData->dwReserved0 == IO_REPARSE_TAG_SYMLINK) {
|
|
2001
|
+
mode |= S_IFLNK;
|
|
2002
|
+
entry_symlink_from_pathw(entry, path);
|
|
2003
|
+
} else if (bhfi->dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
|
|
2004
|
+
mode |= S_IFDIR | S_IXUSR | S_IXGRP | S_IXOTH;
|
|
2005
|
+
else {
|
|
2006
|
+
const wchar_t *p;
|
|
2007
|
+
|
|
2008
|
+
mode |= S_IFREG;
|
|
2009
|
+
p = wcsrchr(path, L'.');
|
|
2010
|
+
if (p != NULL && wcslen(p) == 4) {
|
|
2011
|
+
switch (p[1]) {
|
|
2012
|
+
case L'B': case L'b':
|
|
2013
|
+
if ((p[2] == L'A' || p[2] == L'a' ) &&
|
|
2014
|
+
(p[3] == L'T' || p[3] == L't' ))
|
|
2015
|
+
mode |= S_IXUSR | S_IXGRP | S_IXOTH;
|
|
2016
|
+
break;
|
|
2017
|
+
case L'C': case L'c':
|
|
2018
|
+
if (((p[2] == L'M' || p[2] == L'm' ) &&
|
|
2019
|
+
(p[3] == L'D' || p[3] == L'd' )))
|
|
2020
|
+
mode |= S_IXUSR | S_IXGRP | S_IXOTH;
|
|
2021
|
+
break;
|
|
2022
|
+
case L'E': case L'e':
|
|
2023
|
+
if ((p[2] == L'X' || p[2] == L'x' ) &&
|
|
2024
|
+
(p[3] == L'E' || p[3] == L'e' ))
|
|
2025
|
+
mode |= S_IXUSR | S_IXGRP | S_IXOTH;
|
|
2026
|
+
break;
|
|
2027
|
+
default:
|
|
2028
|
+
break;
|
|
2029
|
+
}
|
|
2030
|
+
}
|
|
2031
|
+
}
|
|
2032
|
+
archive_entry_set_mode(entry, mode);
|
|
2033
|
+
}
|
|
2034
|
+
|
|
2035
|
+
static void
|
|
2036
|
+
tree_archive_entry_copy_bhfi(struct archive_entry *entry, struct tree *t,
|
|
2037
|
+
const BY_HANDLE_FILE_INFORMATION *bhfi)
|
|
2038
|
+
{
|
|
2039
|
+
entry_copy_bhfi(entry, tree_current_path(t), t->findData, bhfi);
|
|
2040
|
+
}
|
|
2041
|
+
|
|
2042
|
+
static int
|
|
2043
|
+
tree_current_file_information(struct tree *t, BY_HANDLE_FILE_INFORMATION *st,
|
|
2044
|
+
int sim_lstat)
|
|
2045
|
+
{
|
|
2046
|
+
HANDLE h;
|
|
2047
|
+
int r;
|
|
2048
|
+
DWORD flag = FILE_FLAG_BACKUP_SEMANTICS;
|
|
2049
|
+
|
|
2050
|
+
if (sim_lstat && tree_current_is_physical_link(t))
|
|
2051
|
+
flag |= FILE_FLAG_OPEN_REPARSE_POINT;
|
|
2052
|
+
h = CreateFileW(tree_current_access_path(t), 0,
|
|
2053
|
+
FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, NULL,
|
|
2054
|
+
OPEN_EXISTING, flag, NULL);
|
|
2055
|
+
if (h == INVALID_HANDLE_VALUE) {
|
|
2056
|
+
la_dosmaperr(GetLastError());
|
|
2057
|
+
t->tree_errno = errno;
|
|
2058
|
+
return (0);
|
|
2059
|
+
}
|
|
2060
|
+
r = GetFileInformationByHandle(h, st);
|
|
2061
|
+
CloseHandle(h);
|
|
2062
|
+
return (r);
|
|
2063
|
+
}
|
|
2064
|
+
|
|
2065
|
+
/*
|
|
2066
|
+
* Get the stat() data for the entry just returned from tree_next().
|
|
2067
|
+
*/
|
|
2068
|
+
static const BY_HANDLE_FILE_INFORMATION *
|
|
2069
|
+
tree_current_stat(struct tree *t)
|
|
2070
|
+
{
|
|
2071
|
+
if (!(t->flags & hasStat)) {
|
|
2072
|
+
if (!tree_current_file_information(t, &t->st, 0))
|
|
2073
|
+
return NULL;
|
|
2074
|
+
t->flags |= hasStat;
|
|
2075
|
+
}
|
|
2076
|
+
return (&t->st);
|
|
2077
|
+
}
|
|
2078
|
+
|
|
2079
|
+
/*
|
|
2080
|
+
* Get the lstat() data for the entry just returned from tree_next().
|
|
2081
|
+
*/
|
|
2082
|
+
static const BY_HANDLE_FILE_INFORMATION *
|
|
2083
|
+
tree_current_lstat(struct tree *t)
|
|
2084
|
+
{
|
|
2085
|
+
if (!(t->flags & hasLstat)) {
|
|
2086
|
+
if (!tree_current_file_information(t, &t->lst, 1))
|
|
2087
|
+
return NULL;
|
|
2088
|
+
t->flags |= hasLstat;
|
|
2089
|
+
}
|
|
2090
|
+
return (&t->lst);
|
|
2091
|
+
}
|
|
2092
|
+
|
|
2093
|
+
/*
|
|
2094
|
+
* Test whether current entry is a dir or link to a dir.
|
|
2095
|
+
*/
|
|
2096
|
+
static int
|
|
2097
|
+
tree_current_is_dir(struct tree *t)
|
|
2098
|
+
{
|
|
2099
|
+
if (t->findData)
|
|
2100
|
+
return (t->findData->dwFileAttributes
|
|
2101
|
+
& FILE_ATTRIBUTE_DIRECTORY);
|
|
2102
|
+
return (0);
|
|
2103
|
+
}
|
|
2104
|
+
|
|
2105
|
+
/*
|
|
2106
|
+
* Test whether current entry is a physical directory. Usually, we
|
|
2107
|
+
* already have at least one of stat() or lstat() in memory, so we
|
|
2108
|
+
* use tricks to try to avoid an extra trip to the disk.
|
|
2109
|
+
*/
|
|
2110
|
+
static int
|
|
2111
|
+
tree_current_is_physical_dir(struct tree *t)
|
|
2112
|
+
{
|
|
2113
|
+
if (tree_current_is_physical_link(t))
|
|
2114
|
+
return (0);
|
|
2115
|
+
return (tree_current_is_dir(t));
|
|
2116
|
+
}
|
|
2117
|
+
|
|
2118
|
+
/*
|
|
2119
|
+
* Test whether current entry is a symbolic link.
|
|
2120
|
+
*/
|
|
2121
|
+
static int
|
|
2122
|
+
tree_current_is_physical_link(struct tree *t)
|
|
2123
|
+
{
|
|
2124
|
+
if (t->findData)
|
|
2125
|
+
return ((t->findData->dwFileAttributes
|
|
2126
|
+
& FILE_ATTRIBUTE_REPARSE_POINT) &&
|
|
2127
|
+
(t->findData->dwReserved0
|
|
2128
|
+
== IO_REPARSE_TAG_SYMLINK));
|
|
2129
|
+
return (0);
|
|
2130
|
+
}
|
|
2131
|
+
|
|
2132
|
+
/*
|
|
2133
|
+
* Test whether the same file has been in the tree as its parent.
|
|
2134
|
+
*/
|
|
2135
|
+
static int
|
|
2136
|
+
tree_target_is_same_as_parent(struct tree *t,
|
|
2137
|
+
const BY_HANDLE_FILE_INFORMATION *st)
|
|
2138
|
+
{
|
|
2139
|
+
struct tree_entry *te;
|
|
2140
|
+
int64_t dev = bhfi_dev(st);
|
|
2141
|
+
int64_t ino = bhfi_ino(st);
|
|
2142
|
+
|
|
2143
|
+
for (te = t->current->parent; te != NULL; te = te->parent) {
|
|
2144
|
+
if (te->dev == dev && te->ino == ino)
|
|
2145
|
+
return (1);
|
|
2146
|
+
}
|
|
2147
|
+
return (0);
|
|
2148
|
+
}
|
|
2149
|
+
|
|
2150
|
+
/*
|
|
2151
|
+
* Return the access path for the entry just returned from tree_next().
|
|
2152
|
+
*/
|
|
2153
|
+
static const wchar_t *
|
|
2154
|
+
tree_current_access_path(struct tree *t)
|
|
2155
|
+
{
|
|
2156
|
+
return (t->full_path.s);
|
|
2157
|
+
}
|
|
2158
|
+
|
|
2159
|
+
/*
|
|
2160
|
+
* Return the full path for the entry just returned from tree_next().
|
|
2161
|
+
*/
|
|
2162
|
+
static const wchar_t *
|
|
2163
|
+
tree_current_path(struct tree *t)
|
|
2164
|
+
{
|
|
2165
|
+
return (t->path.s);
|
|
2166
|
+
}
|
|
2167
|
+
|
|
2168
|
+
/*
|
|
2169
|
+
* Terminate the traversal.
|
|
2170
|
+
*/
|
|
2171
|
+
static void
|
|
2172
|
+
tree_close(struct tree *t)
|
|
2173
|
+
{
|
|
2174
|
+
|
|
2175
|
+
if (t == NULL)
|
|
2176
|
+
return;
|
|
2177
|
+
if (t->entry_fh != INVALID_HANDLE_VALUE) {
|
|
2178
|
+
cancel_async(t);
|
|
2179
|
+
close_and_restore_time(t->entry_fh, t, &t->restore_time);
|
|
2180
|
+
t->entry_fh = INVALID_HANDLE_VALUE;
|
|
2181
|
+
}
|
|
2182
|
+
/* Close the handle of FindFirstFileW */
|
|
2183
|
+
if (t->d != INVALID_HANDLE_VALUE) {
|
|
2184
|
+
FindClose(t->d);
|
|
2185
|
+
t->d = INVALID_HANDLE_VALUE;
|
|
2186
|
+
t->findData = NULL;
|
|
2187
|
+
}
|
|
2188
|
+
/* Release anything remaining in the stack. */
|
|
2189
|
+
while (t->stack != NULL)
|
|
2190
|
+
tree_pop(t);
|
|
2191
|
+
}
|
|
2192
|
+
|
|
2193
|
+
/*
|
|
2194
|
+
* Release any resources.
|
|
2195
|
+
*/
|
|
2196
|
+
static void
|
|
2197
|
+
tree_free(struct tree *t)
|
|
2198
|
+
{
|
|
2199
|
+
int i;
|
|
2200
|
+
|
|
2201
|
+
if (t == NULL)
|
|
2202
|
+
return;
|
|
2203
|
+
archive_wstring_free(&t->path);
|
|
2204
|
+
archive_wstring_free(&t->full_path);
|
|
2205
|
+
free(t->sparse_list);
|
|
2206
|
+
free(t->filesystem_table);
|
|
2207
|
+
for (i = 0; i < MAX_OVERLAPPED; i++) {
|
|
2208
|
+
if (t->ol[i].buff)
|
|
2209
|
+
VirtualFree(t->ol[i].buff, 0, MEM_RELEASE);
|
|
2210
|
+
CloseHandle(t->ol[i].ol.hEvent);
|
|
2211
|
+
}
|
|
2212
|
+
free(t);
|
|
2213
|
+
}
|
|
2214
|
+
|
|
2215
|
+
|
|
2216
|
+
/*
|
|
2217
|
+
* Populate the archive_entry with metadata from the disk.
|
|
2218
|
+
*/
|
|
2219
|
+
int
|
|
2220
|
+
archive_read_disk_entry_from_file(struct archive *_a,
|
|
2221
|
+
struct archive_entry *entry, int fd, const struct stat *st)
|
|
2222
|
+
{
|
|
2223
|
+
struct archive_read_disk *a = (struct archive_read_disk *)_a;
|
|
2224
|
+
const wchar_t *path;
|
|
2225
|
+
const wchar_t *wname;
|
|
2226
|
+
const char *name;
|
|
2227
|
+
HANDLE h;
|
|
2228
|
+
BY_HANDLE_FILE_INFORMATION bhfi;
|
|
2229
|
+
DWORD fileAttributes = 0;
|
|
2230
|
+
int r;
|
|
2231
|
+
|
|
2232
|
+
archive_clear_error(_a);
|
|
2233
|
+
wname = archive_entry_sourcepath_w(entry);
|
|
2234
|
+
if (wname == NULL)
|
|
2235
|
+
wname = archive_entry_pathname_w(entry);
|
|
2236
|
+
if (wname == NULL) {
|
|
2237
|
+
archive_set_error(&a->archive, EINVAL,
|
|
2238
|
+
"Can't get a wide character version of the path");
|
|
2239
|
+
return (ARCHIVE_FAILED);
|
|
2240
|
+
}
|
|
2241
|
+
path = __la_win_permissive_name_w(wname);
|
|
2242
|
+
|
|
2243
|
+
if (st == NULL) {
|
|
2244
|
+
/*
|
|
2245
|
+
* Get metadata through GetFileInformationByHandle().
|
|
2246
|
+
*/
|
|
2247
|
+
if (fd >= 0) {
|
|
2248
|
+
h = (HANDLE)_get_osfhandle(fd);
|
|
2249
|
+
r = GetFileInformationByHandle(h, &bhfi);
|
|
2250
|
+
if (r == 0) {
|
|
2251
|
+
la_dosmaperr(GetLastError());
|
|
2252
|
+
archive_set_error(&a->archive, errno,
|
|
2253
|
+
"Can't GetFileInformationByHandle");
|
|
2254
|
+
return (ARCHIVE_FAILED);
|
|
2255
|
+
}
|
|
2256
|
+
entry_copy_bhfi(entry, path, NULL, &bhfi);
|
|
2257
|
+
} else {
|
|
2258
|
+
WIN32_FIND_DATAW findData;
|
|
2259
|
+
DWORD flag, desiredAccess;
|
|
2260
|
+
|
|
2261
|
+
h = FindFirstFileW(path, &findData);
|
|
2262
|
+
if (h == INVALID_HANDLE_VALUE) {
|
|
2263
|
+
la_dosmaperr(GetLastError());
|
|
2264
|
+
archive_set_error(&a->archive, errno,
|
|
2265
|
+
"Can't FindFirstFileW");
|
|
2266
|
+
return (ARCHIVE_FAILED);
|
|
2267
|
+
}
|
|
2268
|
+
FindClose(h);
|
|
2269
|
+
|
|
2270
|
+
flag = FILE_FLAG_BACKUP_SEMANTICS;
|
|
2271
|
+
if (!a->follow_symlinks &&
|
|
2272
|
+
(findData.dwFileAttributes
|
|
2273
|
+
& FILE_ATTRIBUTE_REPARSE_POINT) &&
|
|
2274
|
+
(findData.dwReserved0 == IO_REPARSE_TAG_SYMLINK)) {
|
|
2275
|
+
flag |= FILE_FLAG_OPEN_REPARSE_POINT;
|
|
2276
|
+
desiredAccess = 0;
|
|
2277
|
+
} else if (findData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) {
|
|
2278
|
+
desiredAccess = 0;
|
|
2279
|
+
} else
|
|
2280
|
+
desiredAccess = GENERIC_READ;
|
|
2281
|
+
|
|
2282
|
+
h = CreateFileW(path, desiredAccess,
|
|
2283
|
+
FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, NULL,
|
|
2284
|
+
OPEN_EXISTING, flag, NULL);
|
|
2285
|
+
if (h == INVALID_HANDLE_VALUE) {
|
|
2286
|
+
la_dosmaperr(GetLastError());
|
|
2287
|
+
archive_set_error(&a->archive, errno,
|
|
2288
|
+
"Can't CreateFileW");
|
|
2289
|
+
return (ARCHIVE_FAILED);
|
|
2290
|
+
}
|
|
2291
|
+
r = GetFileInformationByHandle(h, &bhfi);
|
|
2292
|
+
if (r == 0) {
|
|
2293
|
+
la_dosmaperr(GetLastError());
|
|
2294
|
+
archive_set_error(&a->archive, errno,
|
|
2295
|
+
"Can't GetFileInformationByHandle");
|
|
2296
|
+
CloseHandle(h);
|
|
2297
|
+
return (ARCHIVE_FAILED);
|
|
2298
|
+
}
|
|
2299
|
+
entry_copy_bhfi(entry, path, &findData, &bhfi);
|
|
2300
|
+
}
|
|
2301
|
+
fileAttributes = bhfi.dwFileAttributes;
|
|
2302
|
+
} else {
|
|
2303
|
+
archive_entry_copy_stat(entry, st);
|
|
2304
|
+
if (st->st_mode & S_IFLNK)
|
|
2305
|
+
entry_symlink_from_pathw(entry, path);
|
|
2306
|
+
h = INVALID_HANDLE_VALUE;
|
|
2307
|
+
}
|
|
2308
|
+
|
|
2309
|
+
/* Lookup uname/gname */
|
|
2310
|
+
name = archive_read_disk_uname(_a, archive_entry_uid(entry));
|
|
2311
|
+
if (name != NULL)
|
|
2312
|
+
archive_entry_copy_uname(entry, name);
|
|
2313
|
+
name = archive_read_disk_gname(_a, archive_entry_gid(entry));
|
|
2314
|
+
if (name != NULL)
|
|
2315
|
+
archive_entry_copy_gname(entry, name);
|
|
2316
|
+
|
|
2317
|
+
/*
|
|
2318
|
+
* File attributes
|
|
2319
|
+
*/
|
|
2320
|
+
if ((a->flags & ARCHIVE_READDISK_NO_FFLAGS) == 0) {
|
|
2321
|
+
const int supported_attrs =
|
|
2322
|
+
FILE_ATTRIBUTE_READONLY |
|
|
2323
|
+
FILE_ATTRIBUTE_HIDDEN |
|
|
2324
|
+
FILE_ATTRIBUTE_SYSTEM;
|
|
2325
|
+
DWORD file_attrs = fileAttributes & supported_attrs;
|
|
2326
|
+
if (file_attrs != 0)
|
|
2327
|
+
archive_entry_set_fflags(entry, file_attrs, 0);
|
|
2328
|
+
}
|
|
2329
|
+
|
|
2330
|
+
/*
|
|
2331
|
+
* Can this file be sparse file ?
|
|
2332
|
+
*/
|
|
2333
|
+
if (archive_entry_filetype(entry) != AE_IFREG
|
|
2334
|
+
|| archive_entry_size(entry) <= 0
|
|
2335
|
+
|| archive_entry_hardlink(entry) != NULL) {
|
|
2336
|
+
if (h != INVALID_HANDLE_VALUE && fd < 0)
|
|
2337
|
+
CloseHandle(h);
|
|
2338
|
+
return (ARCHIVE_OK);
|
|
2339
|
+
}
|
|
2340
|
+
|
|
2341
|
+
if (h == INVALID_HANDLE_VALUE) {
|
|
2342
|
+
if (fd >= 0) {
|
|
2343
|
+
h = (HANDLE)_get_osfhandle(fd);
|
|
2344
|
+
} else {
|
|
2345
|
+
h = CreateFileW(path, GENERIC_READ,
|
|
2346
|
+
FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, NULL,
|
|
2347
|
+
OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, NULL);
|
|
2348
|
+
if (h == INVALID_HANDLE_VALUE) {
|
|
2349
|
+
la_dosmaperr(GetLastError());
|
|
2350
|
+
archive_set_error(&a->archive, errno,
|
|
2351
|
+
"Can't CreateFileW");
|
|
2352
|
+
return (ARCHIVE_FAILED);
|
|
2353
|
+
}
|
|
2354
|
+
}
|
|
2355
|
+
r = GetFileInformationByHandle(h, &bhfi);
|
|
2356
|
+
if (r == 0) {
|
|
2357
|
+
la_dosmaperr(GetLastError());
|
|
2358
|
+
archive_set_error(&a->archive, errno,
|
|
2359
|
+
"Can't GetFileInformationByHandle");
|
|
2360
|
+
if (h != INVALID_HANDLE_VALUE && fd < 0)
|
|
2361
|
+
CloseHandle(h);
|
|
2362
|
+
return (ARCHIVE_FAILED);
|
|
2363
|
+
}
|
|
2364
|
+
fileAttributes = bhfi.dwFileAttributes;
|
|
2365
|
+
}
|
|
2366
|
+
|
|
2367
|
+
/* Sparse file must be set a mark, FILE_ATTRIBUTE_SPARSE_FILE */
|
|
2368
|
+
if ((fileAttributes & FILE_ATTRIBUTE_SPARSE_FILE) == 0) {
|
|
2369
|
+
if (fd < 0)
|
|
2370
|
+
CloseHandle(h);
|
|
2371
|
+
return (ARCHIVE_OK);
|
|
2372
|
+
}
|
|
2373
|
+
|
|
2374
|
+
if ((a->flags & ARCHIVE_READDISK_NO_SPARSE) == 0) {
|
|
2375
|
+
r = setup_sparse_from_disk(a, entry, h);
|
|
2376
|
+
if (fd < 0)
|
|
2377
|
+
CloseHandle(h);
|
|
2378
|
+
}
|
|
2379
|
+
|
|
2380
|
+
return (r);
|
|
2381
|
+
}
|
|
2382
|
+
|
|
2383
|
+
/*
|
|
2384
|
+
* Windows sparse interface.
|
|
2385
|
+
*/
|
|
2386
|
+
#if defined(__MINGW32__) && !defined(FSCTL_QUERY_ALLOCATED_RANGES)
|
|
2387
|
+
#define FSCTL_QUERY_ALLOCATED_RANGES 0x940CF
|
|
2388
|
+
typedef struct {
|
|
2389
|
+
LARGE_INTEGER FileOffset;
|
|
2390
|
+
LARGE_INTEGER Length;
|
|
2391
|
+
} FILE_ALLOCATED_RANGE_BUFFER;
|
|
2392
|
+
#endif
|
|
2393
|
+
|
|
2394
|
+
static int
|
|
2395
|
+
setup_sparse_from_disk(struct archive_read_disk *a,
|
|
2396
|
+
struct archive_entry *entry, HANDLE handle)
|
|
2397
|
+
{
|
|
2398
|
+
FILE_ALLOCATED_RANGE_BUFFER range, *outranges = NULL;
|
|
2399
|
+
size_t outranges_size;
|
|
2400
|
+
int64_t entry_size = archive_entry_size(entry);
|
|
2401
|
+
int exit_sts = ARCHIVE_OK;
|
|
2402
|
+
|
|
2403
|
+
range.FileOffset.QuadPart = 0;
|
|
2404
|
+
range.Length.QuadPart = entry_size;
|
|
2405
|
+
outranges_size = 2048;
|
|
2406
|
+
outranges = (FILE_ALLOCATED_RANGE_BUFFER *)malloc(outranges_size);
|
|
2407
|
+
if (outranges == NULL) {
|
|
2408
|
+
archive_set_error(&a->archive, ENOMEM,
|
|
2409
|
+
"Couldn't allocate memory");
|
|
2410
|
+
exit_sts = ARCHIVE_FATAL;
|
|
2411
|
+
goto exit_setup_sparse;
|
|
2412
|
+
}
|
|
2413
|
+
|
|
2414
|
+
for (;;) {
|
|
2415
|
+
DWORD retbytes;
|
|
2416
|
+
BOOL ret;
|
|
2417
|
+
|
|
2418
|
+
for (;;) {
|
|
2419
|
+
ret = DeviceIoControl(handle,
|
|
2420
|
+
FSCTL_QUERY_ALLOCATED_RANGES,
|
|
2421
|
+
&range, sizeof(range), outranges,
|
|
2422
|
+
(DWORD)outranges_size, &retbytes, NULL);
|
|
2423
|
+
if (ret == 0 && GetLastError() == ERROR_MORE_DATA) {
|
|
2424
|
+
free(outranges);
|
|
2425
|
+
outranges_size *= 2;
|
|
2426
|
+
outranges = (FILE_ALLOCATED_RANGE_BUFFER *)
|
|
2427
|
+
malloc(outranges_size);
|
|
2428
|
+
if (outranges == NULL) {
|
|
2429
|
+
archive_set_error(&a->archive, ENOMEM,
|
|
2430
|
+
"Couldn't allocate memory");
|
|
2431
|
+
exit_sts = ARCHIVE_FATAL;
|
|
2432
|
+
goto exit_setup_sparse;
|
|
2433
|
+
}
|
|
2434
|
+
continue;
|
|
2435
|
+
} else
|
|
2436
|
+
break;
|
|
2437
|
+
}
|
|
2438
|
+
if (ret != 0) {
|
|
2439
|
+
if (retbytes > 0) {
|
|
2440
|
+
DWORD i, n;
|
|
2441
|
+
|
|
2442
|
+
n = retbytes / sizeof(outranges[0]);
|
|
2443
|
+
if (n == 1 &&
|
|
2444
|
+
outranges[0].FileOffset.QuadPart == 0 &&
|
|
2445
|
+
outranges[0].Length.QuadPart == entry_size)
|
|
2446
|
+
break;/* This is not sparse. */
|
|
2447
|
+
for (i = 0; i < n; i++)
|
|
2448
|
+
archive_entry_sparse_add_entry(entry,
|
|
2449
|
+
outranges[i].FileOffset.QuadPart,
|
|
2450
|
+
outranges[i].Length.QuadPart);
|
|
2451
|
+
range.FileOffset.QuadPart =
|
|
2452
|
+
outranges[n-1].FileOffset.QuadPart
|
|
2453
|
+
+ outranges[n-1].Length.QuadPart;
|
|
2454
|
+
range.Length.QuadPart =
|
|
2455
|
+
entry_size - range.FileOffset.QuadPart;
|
|
2456
|
+
if (range.Length.QuadPart > 0)
|
|
2457
|
+
continue;
|
|
2458
|
+
} else {
|
|
2459
|
+
/* The entire file is a hole. Add one data block of size 0 at the end. */
|
|
2460
|
+
archive_entry_sparse_add_entry(entry,
|
|
2461
|
+
entry_size,
|
|
2462
|
+
0);
|
|
2463
|
+
}
|
|
2464
|
+
break;
|
|
2465
|
+
} else {
|
|
2466
|
+
la_dosmaperr(GetLastError());
|
|
2467
|
+
archive_set_error(&a->archive, errno,
|
|
2468
|
+
"DeviceIoControl Failed: %lu", GetLastError());
|
|
2469
|
+
exit_sts = ARCHIVE_FAILED;
|
|
2470
|
+
goto exit_setup_sparse;
|
|
2471
|
+
}
|
|
2472
|
+
}
|
|
2473
|
+
exit_setup_sparse:
|
|
2474
|
+
free(outranges);
|
|
2475
|
+
|
|
2476
|
+
return (exit_sts);
|
|
2477
|
+
}
|
|
2478
|
+
|
|
2479
|
+
#endif
|