From 458723a7daa42ae0be7e84f13ab395b628be1a70 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Reynir=20Bj=C3=B6rnsson?= Date: Wed, 6 Sep 2023 10:15:36 +0200 Subject: [PATCH 1/3] Move backwards compatibility code We need to apply the "fix" when GNU LongLink/LongName is used, too. Reported and fixed by @gravicappa --- lib/tar.ml | 30 ++++++++++++++++++------------ 1 file changed, 18 insertions(+), 12 deletions(-) diff --git a/lib/tar.ml b/lib/tar.ml index 1ab57bf..c44e6cb 100644 --- a/lib/tar.ml +++ b/lib/tar.ml @@ -562,17 +562,7 @@ module Header = struct let mod_time = match extended.Extended.mod_time with | None -> get_hdr_mod_time c | Some x -> x in - let link_indicator = - let link_indicator = get_hdr_link_indicator c in - (* For backward compatibility we treat normal files ending in slash - as directories. Because [Link.of_char] treats unrecognized link - indicator values as normal files we check directly *) - if String.length file_name > 0 && file_name.[String.length file_name - 1] = '/' && - (link_indicator = '0' || link_indicator = '\000') then - Link.Directory - else - Link.of_char ~level link_indicator - in + let link_indicator = Link.of_char ~level (get_hdr_link_indicator c) in let uname = match extended.Extended.uname with | None -> if ustar then get_hdr_uname c else "" | Some x -> x in @@ -763,6 +753,21 @@ module HeaderReader(Async: ASYNC)(Reader: READER with type 'a t = 'a Async.t) = | None -> return (Error `Eof) end in + let true_link_indicator link_indicator file_name = + (* For backward compatibility we treat normal files ending in slash + as directories. Because [Link.of_char] treats unrecognized link + indicator values as normal files we check directly. This is not + completely correct as [Header.Link.of_char] turns unknown link + indicators into [Header.Link.Normal]. Ideally, it should only be + done for '0' and '\000'. *) + if String.length file_name > 0 + && file_name.[String.length file_name - 1] = '/' + && link_indicator = Header.Link.Normal then + Header.Link.Directory + else + link_indicator + in + let rec read_header global (file_name, link_name, hdr) : (Header.t * Header.Extended.t option, [`Eof]) result Async.t = let raw_link_indicator = Header.get_hdr_link_indicator buffer in if (raw_link_indicator = 'K' || raw_link_indicator = 'L') && level = Header.GNU then @@ -783,7 +788,8 @@ module HeaderReader(Async: ASYNC)(Reader: READER with type 'a t = 'a Async.t) = else begin let link_name = if link_name = "" then hdr.Header.link_name else link_name in let file_name = if file_name = "" then hdr.Header.file_name else file_name in - return (Ok ({hdr with Header.link_name; file_name }, global)) + let link_indicator = true_link_indicator hdr.Header.link_indicator file_name in + return (Ok ({hdr with Header.link_name; file_name; link_indicator }, global)) end in get_hdr global () From ed63bd964652ea9846bed6822b479e4b425c7356 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Reynir=20Bj=C3=B6rnsson?= Date: Thu, 7 Sep 2023 10:47:51 +0200 Subject: [PATCH 2/3] Add test case for @LongLink implicit dir --- lib_test/long-implicit-dir.tar | Bin 0 -> 2560 bytes lib_test/parse_test.ml | 21 +++++++++++++++++++++ 2 files changed, 21 insertions(+) create mode 100644 lib_test/long-implicit-dir.tar diff --git a/lib_test/long-implicit-dir.tar b/lib_test/long-implicit-dir.tar new file mode 100644 index 0000000000000000000000000000000000000000..98f0d13e72895509aa190380e82e8f17affcbec5 GIT binary patch literal 2560 zcmdPX*VA|K$ zP(T$NIlSWh+*JJ>VEpUnB?4J#`9=DP`YD-3smUezMV0y^Cm=?sPf_EaHh}=j)Ohnh lqD+A1e?tQkBQpjA+BgT*)DfQlQ3GR?HyQ$?Auy6c002oPEnxrv literal 0 HcmV?d00001 diff --git a/lib_test/parse_test.ml b/lib_test/parse_test.ml index 2ce146f..e54b660 100644 --- a/lib_test/parse_test.ml +++ b/lib_test/parse_test.ml @@ -171,6 +171,26 @@ let can_list_pax_implicit_dir () = Alcotest.(check link) "is directory" Tar.Header.Link.Directory hdr.link_indicator; Alcotest.(check string) "filename is patched" "clearly/a/directory/" hdr.file_name) +(* Sample tar generated with commit 1583f71ea33b2836d3fb996ac7dc35d55abe2777: + [let buf = + let long_name = "some/long/name/for/a/directory/" in + let long_hdr = Tar.Header.make ~link_indicator:Tar.Header.Link.LongName "././@LongLink" Int64.(succ (of_int (String.length long_name))) in + let hdr = Tar.Header.make "some/long/name" 0L in + let buf = Cstruct.create ((3+2) * 512) in + let level = Tar.Header.GNU in + Tar.Header.marshal ~level buf long_hdr; + Cstruct.blit_from_string long_name 0 buf 512 (String.length long_name); + Tar.Header.marshal ~level (Cstruct.shift buf 1024) hdr; + buf] *) +let can_list_longlink_implicit_dir () = + let fd = Unix.openfile "lib_test/long-implicit-dir.tar" [ O_RDONLY; O_CLOEXEC ] 0x0 in + Fun.protect ~finally:(fun () -> Unix.close fd) + (fun () -> + let (hdr, _global) = Tar_unix.get_next_header ~global:None fd in + Alcotest.(check link) "is directory" Tar.Header.Link.Directory hdr.link_indicator; + Alcotest.(check string) "filename is patched" "some/long/name/for/a/directory/" hdr.file_name) + + let starts_with ~prefix s = let len_s = String.length s and len_pre = String.length prefix in @@ -344,6 +364,7 @@ let () = "can read pax long names and links" >:: can_list_long_pax_tar; "can read pax header with implicit directory" >:: can_list_pax_implicit_dir; "can transform tars" >:: can_transform_tar; + "can read @LongLink with implicit directory" >:: can_list_longlink_implicit_dir; ] in let ( >:: ) desc f = Alcotest_lwt.test_case desc `Quick f in From 8d3533b137f34c3376c83ca810b798ec4b89075f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Reynir=20Bj=C3=B6rnsson?= Date: Thu, 7 Sep 2023 11:09:39 +0200 Subject: [PATCH 3/3] Add constraint on eio In order to fix CI --- dune-project | 2 +- tar-eio.opam | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/dune-project b/dune-project index a3f6da8..3e43e53 100644 --- a/dune-project +++ b/dune-project @@ -91,7 +91,7 @@ (tags ("org:xapi-project" "org:mirage")) (depends (ocaml (>= 4.08.0)) - (eio (>= 0.10.0)) + (eio (and (>= 0.10.0) (< 0.12))) (tar (= :version)) ) ) diff --git a/tar-eio.opam b/tar-eio.opam index 259ce87..697f742 100644 --- a/tar-eio.opam +++ b/tar-eio.opam @@ -15,7 +15,7 @@ bug-reports: "https://github.com/mirage/ocaml-tar/issues" depends: [ "dune" {>= "2.9"} "ocaml" {>= "4.08.0"} - "eio" {>= "0.10.0"} + "eio" {>= "0.10.0" & < "0.12"} "tar" {= version} "odoc" {with-doc} ]