diff options
Diffstat (limited to 'utils')
-rw-r--r-- | utils/misc.ml | 25 | ||||
-rw-r--r-- | utils/misc.mli | 9 |
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*) |