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
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
open Eio.Std
module Fd = Eio_unix.Fd
type (_, _, _) Eio.Resource.pi += Posix_dir : ('t, 't -> Low_level.dir_fd, [> `Posix_dir]) Eio.Resource.pi
let as_posix_dir (Eio.Resource.T (t, ops)) =
match Eio.Resource.get_opt ops Posix_dir with
| None -> None
| Some fn -> Some (fn t)
module rec Dir : sig
include Eio.Fs.Pi.DIR
val v : label:string -> path:string -> Low_level.dir_fd -> t
val fd : t -> Low_level.dir_fd
end = struct
type t = {
fd : Low_level.dir_fd;
dir_path : string;
label : string;
}
let fd t = t.fd
let v ~label ~path:dir_path fd = { fd; dir_path; label }
let open_in t ~sw path =
let fd = Err.run (Low_level.openat ~mode:0 ~sw t.fd path) Low_level.Open_flags.rdonly in
(Flow.of_fd fd :> Eio.File.ro_ty Eio.Resource.t)
let open_out t ~sw ~append ~create path =
let mode, flags =
match create with
| `Never -> 0, Low_level.Open_flags.empty
| `If_missing perm -> perm, Low_level.Open_flags.creat
| `Or_truncate perm -> perm, Low_level.Open_flags.(creat + trunc)
| `Exclusive perm -> perm, Low_level.Open_flags.(creat + excl)
in
let flags = if append then Low_level.Open_flags.(flags + append) else flags in
let flags = Low_level.Open_flags.(flags + rdwr) in
match Low_level.openat ~sw ~mode t.fd path flags with
| fd -> (Flow.of_fd fd :> Eio.File.rw_ty r)
| exception Unix.Unix_error (code, name, arg) ->
raise (Err.wrap code name arg)
let mkdir t ~perm path =
Err.run (Low_level.mkdir ~mode:perm t.fd) path
let unlink t path =
Err.run (Low_level.unlink ~dir:false t.fd) path
let rmdir t path =
Err.run (Low_level.unlink ~dir:true t.fd) path
let stat t ~follow path =
let buf = Low_level.create_stat () in
Err.run (Low_level.fstatat ~buf ~follow t.fd) path;
Flow.eio_of_stat buf
let read_dir t path =
Err.run (Low_level.readdir t.fd) path
|> Array.to_list
let read_link t path =
Err.run (Low_level.read_link t.fd) path
let rename t old_path new_dir new_path =
match as_posix_dir new_dir with
| None -> invalid_arg "Target is not an eio_posix directory!"
| Some new_dir -> Err.run (Low_level.rename t.fd old_path new_dir) new_path
let symlink ~link_to t path =
Err.run (Low_level.symlink ~link_to t.fd) path
let open_dir t ~sw path =
let flags = Low_level.Open_flags.(rdonly + directory +? path) in
let fd = Err.run (Low_level.openat ~sw ~mode:0 t.fd path) flags in
let label = Filename.basename path in
let full_path = if Filename.is_relative path then Filename.concat t.dir_path path else path in
let d = v ~label ~path:full_path (Fd fd) in
Eio.Resource.T (d, Handler.v)
let pp f t = Fmt.string f (String.escaped t.label)
let native_internal t path =
if Filename.is_relative path then (
let p =
if t.dir_path = "." then path
else Filename.concat t.dir_path path
in
if p = "" then "."
else if p = "." then p
else if Filename.is_implicit p then "./" ^ p
else p
) else path
let native t path =
Some (native_internal t path)
end
and Handler : sig
val v : (Dir.t, [`Dir | `Close]) Eio.Resource.handler
end = struct
let v = Eio.Resource.handler [
H (Eio.Fs.Pi.Dir, (module Dir));
H (Posix_dir, Dir.fd);
]
end
let fs = Eio.Resource.T (Dir.v ~label:"fs" ~path:"." Fs, Handler.v)
let cwd = Eio.Resource.T (Dir.v ~label:"cwd" ~path:"." Cwd, Handler.v)