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.

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

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