let save_of_output ?perm output_function file sexp =
  let tmp_name, oc =
    let temp_dir =
      if Filename.is_relative file then "."
      else Filename.dir_sep
    in
    Filename.open_temp_file ~temp_dir file "tmp"
  in
  try
    output_function oc sexp;
    close_out oc;
    let perm =
      match perm with
      | Some perm -> perm
      | None ->
          let umask = Unix.umask 0 in
          ignore (Unix.umask umask);
          umask lxor 0o666
    in
    if perm <> 0o600 then Unix.chmod tmp_name perm;
    Sys.rename tmp_name file
  with
    e ->
      close_out_noerr oc;
      raise e