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
95
96
97
98
99
open Eio.Std
type tristate = No | Yes | Unknown
type t = {
fd : Rcfd.t;
mutable blocking : tristate;
mutable seekable : tristate;
close_unix : bool;
mutable release_hook : Eio.Switch.hook;
}
let err_closed op = Invalid_argument (op ^ ": file descriptor used after calling close!")
let use t f ~if_closed = Rcfd.use t.fd f ~if_closed
let use_exn op t f =
Rcfd.use t.fd f ~if_closed:(fun () -> raise (err_closed op))
let close t =
Switch.remove_hook t.release_hook;
if t.close_unix then (
ignore (Rcfd.close t.fd : bool)
) else (
ignore (Rcfd.remove t.fd : Unix.file_descr option)
)
let remove t =
Switch.remove_hook t.release_hook;
Rcfd.remove t.fd
let tristate_of_bool_opt = function
| None -> Unknown
| Some true -> Yes
| Some false -> No
let of_unix_no_hook ?(close_unix=true) ?blocking ?seekable fd =
let seekable = tristate_of_bool_opt seekable in
let blocking = tristate_of_bool_opt blocking in
{ fd = Rcfd.make fd; blocking; seekable; close_unix; release_hook = Switch.null_hook }
let of_unix ~sw ?blocking ?seekable ~close_unix fd =
let t = of_unix_no_hook ?blocking ?seekable ~close_unix fd in
t.release_hook <- Switch.on_release_cancellable sw (fun () -> close t);
t
let of_unix_list ~sw fds =
match Switch.get_error sw with
| Some e -> List.iter Unix.close fds; raise e
| None -> List.map (of_unix ~sw ~close_unix:true) fds
external eio_is_blocking : Unix.file_descr -> bool = "eio_unix_is_blocking"
let is_blocking t =
match t.blocking with
| No -> false
| Yes -> true
| Unknown ->
use t ~if_closed:(Fun.const false) @@ fun fd ->
let blocking = eio_is_blocking fd in
t.blocking <- if blocking then Yes else No;
blocking
let is_seekable t =
match t.seekable with
| No -> false
| Yes -> true
| Unknown ->
use t ~if_closed:(Fun.const false) @@ fun fd ->
let seekable =
match Unix.lseek fd 0 Unix.SEEK_CUR with
| (_ : int) -> true
| exception Unix.Unix_error (Unix.ESPIPE, "lseek", "") -> false
in
t.seekable <- if seekable then Yes else No;
seekable
let is_open t = Rcfd.is_open t.fd
let rec use_exn_list op xs k =
match xs with
| [] -> k []
| x :: xs ->
use_exn op x @@ fun x ->
use_exn_list op xs @@ fun xs ->
k (x :: xs)
let use_exn_opt op x f =
match x with
| None -> f None
| Some x -> use_exn op x (fun x -> f (Some x))
let stdin = of_unix_no_hook Unix.stdin
let stdout = of_unix_no_hook Unix.stdout
let stderr= of_unix_no_hook Unix.stderr
let pp f t = Rcfd.pp f t.fd