libarchive-static 1.0.6 → 1.1.0

Sign up to get free protection for your applications and to get access to all the features.
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
+