Source file carton_git_unix.ml
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
open Lwt.Infix
module Store = struct
type 'a rd = < rd : unit ; .. > as 'a
type 'a wr = < wr : unit ; .. > as 'a
type 'a mode =
| Rd : < rd : unit > mode
| Wr : < wr : unit > mode
| RdWr : < rd : unit ; wr : unit > mode
type t = Fpath.t
type uid = Fpath.t
type 'a fd = Lwt_unix.file_descr
type error = [ `Not_found of uid ]
type +'a fiber = 'a Lwt.t
let pp_error : error Fmt.t =
fun ppf -> function
| `Not_found uid -> Fmt.pf ppf "%a not found" Fpath.pp uid
let create :
type a.
?trunc:bool -> mode:a mode -> t -> uid -> (a fd, error) result fiber =
fun ?(trunc = true) ~mode root path ->
let flags, perm =
match mode with
| Rd -> Unix.[ O_RDONLY ], 0o400
| Wr -> Unix.[ O_WRONLY; O_CREAT; O_APPEND ], 0o600
| RdWr -> Unix.[ O_RDWR; O_CREAT; O_APPEND ], 0o600
in
let flags = if trunc then Unix.O_TRUNC :: flags else flags in
let path = Fpath.(root // path) in
let process () =
Lwt_unix.openfile (Fpath.to_string path) flags perm >>= fun fd ->
Lwt.return_ok fd
in
let error = function
| Unix.Unix_error (Unix.EACCES, _, _) ->
Lwt.return_error (`Not_found path)
| exn -> Lwt.fail exn
in
Lwt.catch process error
let map : t -> 'm rd fd -> pos:int64 -> int -> Bigstringaf.t =
fun _ fd ~pos len ->
let fd = Lwt_unix.unix_file_descr fd in
let payload =
Unix.map_file fd ~pos Bigarray.char Bigarray.c_layout false [| len |]
in
Bigarray.array1_of_genarray payload
let close _ fd = Lwt_unix.close fd >>= fun () -> Lwt.return_ok ()
let length fd =
Lwt_unix.LargeFile.fstat fd >>= fun st ->
Lwt.return st.Unix.LargeFile.st_size
let list root =
Lwt_unix.opendir (Fpath.to_string root) >>= fun dh ->
let rec go acc =
Lwt.catch
(fun () ->
Lwt_unix.readdir dh >>= function
| "." | ".." -> go acc
| entry -> (
match Fpath.of_string entry with
| Ok x -> if Fpath.has_ext "pack" x then go (x :: acc) else go acc
| Error (`Msg _) -> go acc))
(function End_of_file -> Lwt.return acc | exn -> Lwt.fail exn)
in
go []
end
module Make (Uid : sig
include Carton.UID
val of_hex : string -> t
val to_hex : t -> string
end) =
struct
include Carton_git.Make (Carton_lwt.Scheduler) (Lwt) (Store) (Uid)
let idx_major_uid_of_uid root uid =
Fpath.(root / Fmt.str "pack-%s.idx" (Uid.to_hex uid))
let uid_of_major_uid path =
let str = Fpath.basename (Fpath.rem_ext path) in
match Astring.String.cut ~sep:"pack-" str with
| Some ("", uid) -> Uid.of_hex uid
| _ -> Fmt.failwith "Invalid path of major file: %a" Fpath.pp path
let make store = make ~uid_of_major_uid ~idx_major_uid_of_uid store
end