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