Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

irmin-pack: add context for corrupted control file #2224

Merged
merged 1 commit into from
Mar 27, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
44 changes: 23 additions & 21 deletions src/irmin-pack/unix/control_file.ml
Original file line number Diff line number Diff line change
Expand Up @@ -41,35 +41,37 @@ module Serde = struct
type raw_payload

val of_bin_string :
string ->
string ->
( payload,
[> `Corrupted_control_file | `Unknown_major_pack_version of string ] )
[> `Corrupted_control_file of string
| `Unknown_major_pack_version of string ] )
result

val raw_of_bin_string :
string ->
string ->
( raw_payload,
[> `Corrupted_control_file | `Unknown_major_pack_version of string ] )
[> `Corrupted_control_file of string
| `Unknown_major_pack_version of string ] )
result

val to_bin_string : payload -> string
end

let extract_version_and_payload s =
let extract_version_and_payload ctx s =
let open Result_syntax in
let len = String.length s in
let* left, right =
try Ok (String.sub s 0 8, String.sub s 8 (len - 8))
with Invalid_argument _ -> Error `Corrupted_control_file
with Invalid_argument _ -> Error (`Corrupted_control_file ctx)
in
let+ version =
match Version.of_bin left with
| None -> Error (`Unknown_major_pack_version left)
| Some (`V1 | `V2) -> assert false (* TODO: create specific error *)
| Some ((`V3 | `V4 | `V5) as x) ->
if len > Io.Unix.page_size then
(* TODO: make this a more specific error *)
Error `Corrupted_control_file
if len > Io.Unix.page_size then Error (`Corrupted_control_file ctx)
else Ok x
in
(version, right)
Expand Down Expand Up @@ -131,9 +133,9 @@ module Serde = struct
let payload = Plv5.set_checksum payload in
Version.to_bin `V5 ^ Plv5.to_bin_string payload

let of_bin_string s =
let of_bin_string ctx s =
let open Result_syntax in
let* version, payload = extract_version_and_payload s in
let* version, payload = extract_version_and_payload ctx s in
let route_version () =
match version with
| `V3 ->
Expand All @@ -154,7 +156,7 @@ module Serde = struct
in
match route_version () with
| Ok _ as x -> x
| Error _ -> Error `Corrupted_control_file
| Error _ -> Error (`Corrupted_control_file ctx)
end

module Latest = Data.Plv5
Expand Down Expand Up @@ -210,11 +212,11 @@ module Serde = struct
volume_num = 0;
}

let of_bin_string string =
let of_bin_string ctx string =
let open Result_syntax in
let* payload = Data.of_bin_string string in
let* payload = Data.of_bin_string ctx string in
match payload with
| Invalid _ -> Error `Corrupted_control_file
| Invalid _ -> Error (`Corrupted_control_file ctx)
| Valid (V3 payload) -> Ok (upgrade_from_v3 payload)
| Valid (V4 payload) -> Ok (upgrade_from_v4 payload)
| Valid (V5 payload) -> Ok payload
Expand Down Expand Up @@ -260,9 +262,9 @@ module Serde = struct
let payload = Plv5.set_checksum payload in
Version.to_bin `V5 ^ Plv5.to_bin_string payload

let of_bin_string s =
let of_bin_string ctx s =
let open Result_syntax in
let* version, payload = extract_version_and_payload s in
let* version, payload = extract_version_and_payload ctx s in
let route_version () =
match version with
| `V3 | `V4 -> assert false
Expand All @@ -275,19 +277,19 @@ module Serde = struct
in
match route_version () with
| Ok _ as x -> x
| Error _ -> Error `Corrupted_control_file
| Error _ -> Error (`Corrupted_control_file ctx)
end

module Payload = Data.Plv5

type payload = Payload.t
type raw_payload = Data.t

let of_bin_string string =
let of_bin_string ctx string =
let open Result_syntax in
let* payload = Data.of_bin_string string in
let* payload = Data.of_bin_string ctx string in
match payload with
| Invalid _ -> Error `Corrupted_control_file
| Invalid _ -> Error (`Corrupted_control_file ctx)
| Valid (V5 payload) -> Ok payload

let raw_of_bin_string = Data.of_bin_string
Expand Down Expand Up @@ -328,7 +330,7 @@ module Make (Serde : Serde.S) (Io : Io.S) = struct
let read io =
let open Result_syntax in
let* string = Io.read_all_to_string io in
Serde.of_bin_string string
Serde.of_bin_string (Io.path io) string

let create_rw ~path ~tmp_path ~overwrite (payload : payload) =
let open Result_syntax in
Expand Down Expand Up @@ -367,7 +369,7 @@ module Make (Serde : Serde.S) (Io : Io.S) = struct
let open Result_syntax in
let* io = Io.open_ ~path ~readonly:true in
let* string = Io.read_all_to_string io in
let* payload = Serde.raw_of_bin_string string in
let* payload = Serde.raw_of_bin_string path string in
let+ () = Io.close io in
payload

Expand Down
11 changes: 2 additions & 9 deletions src/irmin-pack/unix/control_file_intf.ml
Original file line number Diff line number Diff line change
Expand Up @@ -309,7 +309,7 @@ module type S = sig
(** Create a rw instance of [t] by creating a control file. *)

type open_error :=
[ `Corrupted_control_file
[ `Corrupted_control_file of string
| `Io_misc of Io.misc_error
| `No_such_file_or_directory of string
| `Not_a_file
Expand Down Expand Up @@ -350,14 +350,7 @@ module type S = sig
[payload t] is the [payload], as it was seen during [open_] or during the
most recent [reload]. *)

type reload_error :=
[ `Corrupted_control_file
| `Io_misc of Io.misc_error
| `Closed
| `Rw_not_allowed
| `Unknown_major_pack_version of string
| open_error
| Io.close_error ]
type reload_error := [ `Rw_not_allowed | open_error | Io.close_error ]

val reload : t -> (unit, [> reload_error ]) result
(** {3 RW mode}
Expand Down
2 changes: 1 addition & 1 deletion src/irmin-pack/unix/errors.ml
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@ type base_error =
| `Rw_not_allowed
| `Migration_needed
| `Migration_to_lower_not_allowed
| `Corrupted_control_file
| `Corrupted_control_file of string
| `Sys_error of string
| `V3_store_from_the_future
| `Gc_forbidden_during_batch
Expand Down
2 changes: 1 addition & 1 deletion src/irmin-pack/unix/file_manager.ml
Original file line number Diff line number Diff line change
Expand Up @@ -809,7 +809,7 @@ struct
| Error `Not_a_file -> Error `Invalid_layout
| Error `Closed -> assert false
| Error
( `Io_misc _ | `Corrupted_control_file
( `Io_misc _ | `Corrupted_control_file _
| `Unknown_major_pack_version _ ) as e ->
e)

Expand Down
8 changes: 4 additions & 4 deletions src/irmin-pack/unix/file_manager_intf.ml
Original file line number Diff line number Diff line change
Expand Up @@ -84,7 +84,7 @@ module type S = sig
| Io.open_error
| Io.mkdir_error
| `Corrupted_mapping_file of string
| `Corrupted_control_file
| `Corrupted_control_file of string
| `Double_close
| `Unknown_major_pack_version of string
| `Volume_missing of string
Expand All @@ -108,7 +108,7 @@ module type S = sig
undefined state and some file descriptors might not be closed. *)

type open_rw_error :=
[ `Corrupted_control_file
[ `Corrupted_control_file of string
| `Corrupted_mapping_file of string
| `Double_close
| `Closed
Expand Down Expand Up @@ -158,7 +158,7 @@ module type S = sig
is unaffected. Anyhow, some file descriptors might not be closed. *)

type open_ro_error :=
[ `Corrupted_control_file
[ `Corrupted_control_file of string
| `Corrupted_mapping_file of string
| `Io_misc of Io.misc_error
| `Migration_needed
Expand Down Expand Up @@ -246,7 +246,7 @@ module type S = sig
val register_suffix_consumer : t -> after_flush:(unit -> unit) -> unit

type version_error :=
[ `Corrupted_control_file
[ `Corrupted_control_file of string
| `Corrupted_legacy_file
| `Invalid_layout
| `Io_misc of Io.misc_error
Expand Down
2 changes: 1 addition & 1 deletion src/irmin-pack/unix/io_errors.ml
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,7 @@ module Make (Io : Io.S) : S with module Io = Io = struct
| `Rw_not_allowed
| `Migration_needed
| `Migration_to_lower_not_allowed
| `Corrupted_control_file
| `Corrupted_control_file of string
| `Sys_error of string
| `V3_store_from_the_future
| `Gc_forbidden_during_batch
Expand Down
2 changes: 1 addition & 1 deletion src/irmin-pack/unix/lower.ml
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ module Make_volume (Io : Io.S) (Errs : Io_errors.S with module Io = Io) = struct
[ Io.open_error
| `Closed
| `Double_close
| `Corrupted_control_file
| `Corrupted_control_file of string
| `Unknown_major_pack_version of string ]

let v volume_path =
Expand Down
2 changes: 1 addition & 1 deletion src/irmin-pack/unix/lower_intf.ml
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ module type Volume = sig
[ Io.open_error
| `Closed
| `Double_close
| `Corrupted_control_file
| `Corrupted_control_file of string
| `Unknown_major_pack_version of string ]

val v : string -> (t, [> open_error ]) result
Expand Down
8 changes: 5 additions & 3 deletions test/irmin-pack/test_corrupted.ml
Original file line number Diff line number Diff line change
Expand Up @@ -75,9 +75,11 @@ let test_corrupted_control_file () =
Ok r)
(fun exn -> Lwt.return (Error exn))
in
Alcotest.(check bool)
"is corrupted" true
(error = Error (Irmin_pack_unix.Errors.Pack_error `Corrupted_control_file));
(match error with
| Error (Irmin_pack_unix.Errors.Pack_error (`Corrupted_control_file s)) ->
Alcotest.(check string)
"path is corrupted" s "_build/test-corrupted/store.control"
| _ -> Alcotest.fail "unexpected error");
Lwt.return_unit

let tests =
Expand Down