How to create a temporary directory in OCaml

I was trying to create a temporary directory in OCaml. I cannot find a function similar to Filename.temp_file, and also I try to avoid calling platform-dependent system commands, so here is a naive version I write:

let mk_temp_dir () =
  let rand_num = Random.int 1000000 |> string_of_int in
  let tmp_dir = Filename.get_temp_dir_name () ^ "/" ^ rand_num in
  try
    Unix.mkdir tmp_dir 0o600;
    tmp_dir
  with _ -> raise (Sys_error "Cannot create temp dir")

It works OK, but I suspect if it is as robust as Filename.temp_file, or if there is already any existing common practice to create temporary directories. Any help will be much appreciated. Thanks!

bos could be a good solution for you, see specially this function.

5 Likes

Your approach is in essence what bos does, with some caveats.

Note that catching all exceptions is not good practice (though it’s very easy to forget) - you may catch Sys.break which you definitely don’t mean to in a library function like this.

Unsurprisingly, the bos code is a textbook demonstration of how exceptions around a Unix syscall should be dealt with: see src/bos_os_dir.ml#L153-155

3 Likes

Thanks you both so much for the help!

Here is a revised version according to the implementation of bos:

let rand_digits () = 
  let rand = Random.State.(bits (make_self_init ()) land 0xFFFFFF) in
  Printf.sprintf "%06x" rand

let mk_temp_dir ?(mode=0o700) ?dir pat = 
  let dir = match dir with 
  | Some d -> d
  | None   -> Filename.get_temp_dir_name ()
  in
  let raise_err msg = raise (Sys_error msg) in
  let rec loop count = 
    if count < 0 then raise_err "mk_temp_dir: too many failing attemps" else
    let dir = Printf.sprintf "%s/%s%s" dir pat (rand_digits ()) in 
    try (Unix.mkdir dir mode; dir) with
    | Unix.Unix_error (Unix.EEXIST, _, _) -> loop (count - 1)
    | Unix.Unix_error (Unix.EINTR, _, _)  -> loop count
    | Unix.Unix_error (e, _, _)           -> 
      raise_err ("mk_temp_dir: " ^ (Unix.error_message e))
  in
  loop 1000

It returns the name of a fresh temporary directory: “/tmp/patXXXXXX”, with permissions 0o700. The temporary directory is guaranteed to be different from any other directory that exists when mk_temp_dir was called; raise Sys_error if the directory could not be created.

There is also this medium post by @lindig with mkdir in ocaml and what can go wrong

3 Likes