1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79
open Conex_utils let exists = Sys.file_exists let guard_unix f x = try Ok (f x) with | Unix.Unix_error (e, f, arg) -> let msg = Unix.error_message e in Error (Printf.sprintf "error %s while %s (%s)" msg f arg) | _ -> Error "unknown error" let mkdir ?(mode = 0o755) name = guard_unix (Unix.mkdir name) mode let guard_sys f x = try Ok (f x) with | Sys_error msg -> Error msg | _ -> Error "unknown error" let remove a = guard_sys Sys.remove a let rename a b = guard_sys (Sys.rename a) b let file_type filename = guard_unix Unix.stat filename >>= fun stat -> match stat.Unix.st_kind with | Unix.S_REG -> Ok File | Unix.S_DIR -> Ok Directory | _ -> Error "unsupported file type" let read_file filename = guard_unix (fun file -> let open Unix in let fd = openfile file [ O_RDONLY ] 0 in let len = (fstat fd).st_size in let buf = Bytes.create len in let rec rread idx = let r = read fd buf idx (len - idx) in if r + idx = len then close fd else rread (r + idx) in rread 0 ; Bytes.to_string buf) filename let write_file ?(mode = 0o644) filename data = guard_unix (fun file -> let open Unix in let fd = openfile file [ O_WRONLY ; O_EXCL ; O_CREAT ] mode in let bytes = Bytes.of_string data in let length = Bytes.length bytes in let written = write fd bytes 0 length in assert (length = written) ; close fd) filename let write_replace ?mode filename data = if exists filename then let tmp = filename ^ ".tmp" in (if exists tmp then remove tmp else Ok ()) >>= fun () -> write_file ?mode tmp data >>= fun () -> rename tmp filename else write_file ?mode filename data let collect_dir dir = guard_unix (fun dir -> let open Unix in let dh = opendir dir in let next () = try Some (readdir dh) with End_of_file -> None in let rec doone acc = function | Some "." | Some ".." -> doone acc (next ()) | Some s -> doone (s :: acc) (next ()) | None -> acc in let res = doone [] (next ()) in closedir dh ; res) dir