summaryrefslogtreecommitdiff
path: root/utils
diff options
context:
space:
mode:
Diffstat (limited to 'utils')
-rw-r--r--utils/misc.ml25
-rw-r--r--utils/misc.mli9
2 files changed, 34 insertions, 0 deletions
diff --git a/utils/misc.ml b/utils/misc.ml
index cc641df54b..052eea2a49 100644
--- a/utils/misc.ml
+++ b/utils/misc.ml
@@ -271,6 +271,31 @@ let string_of_file ic =
(Buffer.add_subbytes b buff 0 n; copy())
in copy()
+let output_to_file_via_temporary ?(mode = [Open_text]) filename fn =
+ let (temp_filename, oc) =
+ Filename.open_temp_file
+ ~mode ~perms:0o666 ~temp_dir:(Filename.dirname filename)
+ (Filename.basename filename) ".tmp" in
+ (* The 0o666 permissions will be modified by the umask. It's just
+ like what [open_out] and [open_out_bin] do.
+ With temp_dir = dirname filename, we ensure that the returned
+ temp file is in the same directory as filename itself, making
+ it safe to rename temp_filename to filename later.
+ With prefix = basename filename, we are almost certain that
+ the first generated name will be unique. A fixed prefix
+ would work too but might generate more collisions if many
+ files are being produced simultaneously in the same directory. *)
+ match fn temp_filename oc with
+ | res ->
+ close_out oc;
+ begin try
+ Sys.rename temp_filename filename; res
+ with exn ->
+ remove_file temp_filename; raise exn
+ end
+ | exception exn ->
+ close_out oc; remove_file temp_filename; raise exn
+
(* Integer operations *)
let rec log2 n =
diff --git a/utils/misc.mli b/utils/misc.mli
index 127b612547..b05f9aa135 100644
--- a/utils/misc.mli
+++ b/utils/misc.mli
@@ -127,6 +127,15 @@ val copy_file_chunk: in_channel -> out_channel -> int -> unit
val string_of_file: in_channel -> string
(* [string_of_file ic] reads the contents of file [ic] and copies
them to a string. It stops when encountering EOF on [ic]. *)
+val output_to_file_via_temporary:
+ ?mode:open_flag list -> string -> (string -> out_channel -> 'a) -> 'a
+ (* Produce output in temporary file, then rename it
+ (as atomically as possible) to the desired output file name.
+ [output_to_file_via_temporary filename fn] opens a temporary file
+ which is passed to [fn] (name + output channel). When [fn] returns,
+ the channel is closed and the temporary file is renamed to
+ [filename]. *)
+
val log2: int -> int
(* [log2 n] returns [s] such that [n = 1 lsl s]
if [n] is a power of 2*)