Skip to content

Instantly share code, notes, and snippets.

@dbuenzli
Created May 5, 2017 16:44
Show Gist options
  • Save dbuenzli/ff42499522fec449ddfcad656cf95cbe to your computer and use it in GitHub Desktop.
Save dbuenzli/ff42499522fec449ddfcad656cf95cbe to your computer and use it in GitHub Desktop.
rm -r
let delete ?(must_exist = false) ~contents d =
let err d msg =
raise_notrace (Failure (strf "delete %a: %s" B0_fpath.pp d msg))
in
let try_unlink file = match Unix.unlink (B0_fpath.to_string file) with
| () -> true
| exception Unix.Unix_error (e, _, _) ->
match e with
| Unix.ENOENT -> true
| Unix.EISDIR (* Linux *) | Unix.EPERM (* POSIX *) -> false
| Unix.EACCES when Sys.win32 -> false (* FIXME need to check dir ? *)
| e -> err file (uerror e)
in
let rec delete_contents d dh todo = match Unix.readdir dh with
| exception End_of_file -> d :: todo
| ".." | "." -> delete_contents d dh todo
| file ->
let file = B0_fpath.(d / file) in
if try_unlink file then delete_contents d dh todo else
file :: d :: todo (* file is a dir we'll come back later for [d] *)
in
let rec try_delete d todo = match Unix.opendir (B0_fpath.to_string d) with
| dh -> doit @@ apply (delete_contents d dh) todo ~finally:Unix.closedir dh
| exception Unix.Unix_error (e, _, _) ->
match e with
| Unix.ENOENT | Unix.ENOTDIR -> doit todo
| e -> err d (uerror e)
and doit = function
| [] -> ()
| d :: ds ->
match Unix.rmdir (B0_fpath.to_string d) with
| () -> doit ds
| exception Unix.Unix_error (e, _, _) ->
match e with
| Unix.ENOTEMPTY -> try_delete d ds
| Unix.ENOENT | Unix.ENOTDIR -> doit ds
| e -> err d (uerror e)
in
try match Unix.rmdir (B0_fpath.to_string d) with
| () -> Ok ()
| exception Unix.Unix_error (e, _, _) ->
match e with
| Unix.ENOTEMPTY when contents -> Ok (try_delete d [])
| Unix.ENOENT when not must_exist -> Ok ()
| Unix.ENOENT -> err d "No such directory"
| e -> err d (uerror e)
with
| Failure msg -> R.error_msg msg
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment