Blame src/FileUtilMKDIR.ml

Packit 9ff65e
(******************************************************************************)
Packit 9ff65e
(*  ocaml-fileutils: files and filenames common operations                    *)
Packit 9ff65e
(*                                                                            *)
Packit 9ff65e
(*  Copyright (C) 2003-2014, Sylvain Le Gall                                  *)
Packit 9ff65e
(*                                                                            *)
Packit 9ff65e
(*  This library is free software; you can redistribute it and/or modify it   *)
Packit 9ff65e
(*  under the terms of the GNU Lesser General Public License as published by  *)
Packit 9ff65e
(*  the Free Software Foundation; either version 2.1 of the License, or (at   *)
Packit 9ff65e
(*  your option) any later version, with the OCaml static compilation         *)
Packit 9ff65e
(*  exception.                                                                *)
Packit 9ff65e
(*                                                                            *)
Packit 9ff65e
(*  This library is distributed in the hope that it will be useful, but       *)
Packit 9ff65e
(*  WITHOUT ANY WARRANTY; without even the implied warranty of                *)
Packit 9ff65e
(*  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the file         *)
Packit 9ff65e
(*  COPYING for more details.                                                 *)
Packit 9ff65e
(*                                                                            *)
Packit 9ff65e
(*  You should have received a copy of the GNU Lesser General Public License  *)
Packit 9ff65e
(*  along with this library; if not, write to the Free Software Foundation,   *)
Packit 9ff65e
(*  Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301 USA             *)
Packit 9ff65e
(******************************************************************************)
Packit 9ff65e
Packit 9ff65e
open FileUtilTypes
Packit 9ff65e
open FilePath
Packit 9ff65e
open FileUtilMisc
Packit 9ff65e
open FileUtilTEST
Packit 9ff65e
open FileUtilUMASK
Packit 9ff65e
open FileUtilCHMOD
Packit 9ff65e
Packit 9ff65e
exception MkdirError of string
Packit 9ff65e
Packit 9ff65e
type mkdir_error =
Packit 9ff65e
  [ `DirnameAlreadyUsed of filename
Packit 9ff65e
  | `Exc of exn
Packit 9ff65e
  | `MissingComponentPath of filename
Packit 9ff65e
  | `MkdirChmod of filename * Unix.file_perm * string * exc ]
Packit 9ff65e
Packit 9ff65e
Packit 9ff65e
let mkdir
Packit 9ff65e
      ?(error=(fun str _ -> raise (MkdirError str)))
Packit 9ff65e
      ?(parent=false)
Packit 9ff65e
      ?mode dn =
Packit 9ff65e
  let handle_error, handle_exception =
Packit 9ff65e
    handle_error_gen "mkdir" error
Packit 9ff65e
      (function
Packit 9ff65e
         | `DirnameAlreadyUsed fn ->
Packit 9ff65e
             Printf.sprintf "Directory %s already exists and is a file." fn
Packit 9ff65e
         | `MissingComponentPath fn ->
Packit 9ff65e
             Printf.sprintf
Packit 9ff65e
               "Unable to create directory %s, an upper directory is missing."
Packit 9ff65e
               fn
Packit 9ff65e
         | `MkdirChmod (dn, mode, str, e) ->
Packit 9ff65e
             Printf.sprintf
Packit 9ff65e
               "Recursive error in 'mkdir %s' in 'chmod %04o %s': %s"
Packit 9ff65e
               dn mode dn str
Packit 9ff65e
         | #exc -> "")
Packit 9ff65e
  in
Packit 9ff65e
  let mode_apply =
Packit 9ff65e
    FileUtilMode.apply ~is_dir:true ~umask:(umask (`Octal (fun i -> i)))
Packit 9ff65e
  in
Packit 9ff65e
  let mode_self =
Packit 9ff65e
    match mode with
Packit 9ff65e
      | Some (`Octal m) -> m
Packit 9ff65e
      | Some (`Symbolic t) -> mode_apply 0o777 t
Packit 9ff65e
      | None -> umask_apply 0o0777
Packit 9ff65e
  in
Packit 9ff65e
  let mode_parent =
Packit 9ff65e
    umask
Packit 9ff65e
      (`Symbolic
Packit 9ff65e
         (fun t ->
Packit 9ff65e
            mode_apply 0 (t @ [`User (`Add (`List [`Write; `Exec]))])))
Packit 9ff65e
  in
Packit 9ff65e
  let rec mkdir_simple mode dn =
Packit 9ff65e
    if test_exists dn then begin
Packit 9ff65e
      if test (Not Is_dir) dn then
Packit 9ff65e
        handle_error ~fatal:true (`DirnameAlreadyUsed dn);
Packit 9ff65e
    end else begin
Packit 9ff65e
      if parent then
Packit 9ff65e
        mkdir_simple mode_parent (dirname dn);
Packit 9ff65e
      try
Packit 9ff65e
        Unix.mkdir dn mode;
Packit 9ff65e
        chmod
Packit 9ff65e
          ~error:(fun str e ->
Packit 9ff65e
                    handle_error ~fatal:true
Packit 9ff65e
                      (`MkdirChmod (dn, mode, str, e)))
Packit 9ff65e
          (`Octal mode) [dn]
Packit 9ff65e
      with Unix.Unix_error(Unix.ENOENT, _, _)
Packit 9ff65e
        | Unix.Unix_error(Unix.ENOTDIR, _, _) ->
Packit 9ff65e
            handle_error ~fatal:true (`MissingComponentPath dn)
Packit 9ff65e
        | e -> handle_exception ~fatal:true e
Packit 9ff65e
    end
Packit 9ff65e
  in
Packit 9ff65e
    mkdir_simple mode_self dn