-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathdirtools.ml
48 lines (44 loc) · 1.55 KB
/
dirtools.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
open Unix
(** Creates temporary directory and in the most safe manner with given permissions and returns its name. Could raise Unix_error. *)
let rec make_tmp_dir ?root ?max_retries:(r=10) ?prefix ?suffix dir_perm =
let open Option in
let root' = default (Filename.get_temp_dir_name ()) root
and prefix' = default "" prefix
and suffix' = default "" suffix in
let d = Filename.temp_file ~temp_dir:root' prefix' suffix' in
try
unlink d; mkdir d dir_perm; d
with
Unix_error (err, fun_name, arg) ->
if r>0 then
make_tmp_dir ?root ~max_retries:(r-1) ?prefix ?suffix dir_perm
else
(* re-raise last exception *)
raise (Unix_error (err, fun_name, arg))
(** Removes directory along with all it's contents recursively. Inspired by https://ocaml.org/learn/tutorials/if_statements_loops_and_recursion.html but we try to minimize the number of open file handes at price of keeping a queue of directories to be removed in memory.
*)
let rec rmrf path =
let readdir_no_ex dirh =
try
Some (readdir dirh)
with
End_of_file -> None
in
let dirh = opendir path in
let rec scan () =
let filename = readdir_no_ex dirh in
match filename with
None -> []
| Some "." | Some ".." -> scan ()
| Some filename ->
let pathname = path ^ "/" ^ filename in
let stat = lstat pathname in
if stat.st_kind = S_DIR then
pathname :: (scan ())
else
(unlink pathname ; scan ())
in
let subdirs = scan () in
closedir dirh ;
ignore (List.map rmrf subdirs) ;
rmdir path