-
Notifications
You must be signed in to change notification settings - Fork 10
/
files.ml
71 lines (64 loc) · 2.18 KB
/
files.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
open Prelude
open Control
let enum_dir d = Enum.from (fun () -> try Unix.readdir d with End_of_file -> raise Enum.No_more_elements)
let with_readdir dirname = bracket (Unix.opendir dirname) Unix.closedir
let iter_names dirname f =
let rec loop path rel =
with_readdir path (fun d ->
enum_dir d |>
Enum.iter (function
| "." | ".." -> ()
| name ->
let path = Filename.concat path name in
match try Some (Unix.openfile path [Unix.O_RDONLY] 0) with _ -> None with
| None -> ()
| Some fd ->
bracket fd (Exn.suppress Unix.close) (fun fd ->
let rel = Filename.concat rel name in
match (Unix.fstat fd).Unix.st_kind with
| Unix.S_REG -> f fd path rel
| Unix.S_DIR -> loop path rel
| _ -> ()
)
)
)
in loop dirname ""
let iter_names_q dirname f =
let rec loop path rel =
with_readdir path (fun d ->
enum_dir d |>
Enum.iter (function
| "." | ".." -> ()
| name ->
let path = Filename.concat path name in
let rel = Filename.concat rel name in
match try Some (Unix.stat path).Unix.st_kind with _ -> None with
| Some Unix.S_REG -> f path rel
| Some Unix.S_DIR -> loop path rel
| _ -> ()
)
)
in loop dirname ""
let iter_files dirname f =
iter_names dirname (fun fd path _ ->
bracket (Unix.in_channel_of_descr fd) close_in_noerr (fun ch -> f path ch))
let open_out_append_text = open_out_gen [Open_wronly;Open_append;Open_creat;Open_text] 0o644
let open_out_append_bin = open_out_gen [Open_wronly;Open_append;Open_creat;Open_binary] 0o644
(*
let () =
iter_files "/etc" (fun s _ -> print_endline s)
*)
let save_as name ?(mode=0o644) f =
(* not using make_temp_file cause same dir is needed for atomic rename *)
let temp = Printf.sprintf "%s.save.%d.tmp" name (U.gettid ()) in
bracket (Unix.openfile temp [Unix.O_WRONLY;Unix.O_CREAT] mode) Unix.close begin fun fd ->
try
let ch = Unix.out_channel_of_descr fd in
(* Unix.fchmod fd mode; *)
f ch;
flush ch;
U.fsync fd;
Unix.rename temp name
with
exn -> Exn.suppress Unix.unlink temp; raise exn
end