Blame src/FileUtilMode.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
type who = [`User | `Group | `Other | `All]
Packit 9ff65e
type wholist = [ who | `List of who list ]
Packit 9ff65e
type permcopy = [`User | `Group | `Other]
Packit 9ff65e
type perm = [ `Read | `Write | `Exec | `ExecX | `Sticky | `StickyO ]
Packit 9ff65e
type permlist = [ perm | `List of perm list ]
Packit 9ff65e
type actionarg = [ permlist | permcopy ]
Packit 9ff65e
type action = [ `Set of actionarg | `Add of actionarg | `Remove of actionarg]
Packit 9ff65e
type actionlist = [ action | `List of action list ]
Packit 9ff65e
type clause = [ `User of actionlist | `Group of actionlist
Packit 9ff65e
              | `Other of actionlist | `All of actionlist
Packit 9ff65e
              | `None of actionlist ]
Packit 9ff65e
Packit 9ff65e
type t = clause list
Packit 9ff65e
Packit 9ff65e
Packit 9ff65e
let all_masks =
Packit 9ff65e
  [
Packit 9ff65e
    `User,  `Sticky,  0o4000;
Packit 9ff65e
    `User,  `Exec,    0o0100;
Packit 9ff65e
    `User,  `Write,   0o0200;
Packit 9ff65e
    `User,  `Read,    0o0400;
Packit 9ff65e
    `Group, `Sticky,  0o2000;
Packit 9ff65e
    `Group, `Exec,    0o0010;
Packit 9ff65e
    `Group, `Write,   0o0020;
Packit 9ff65e
    `Group, `Read,    0o0040;
Packit 9ff65e
    `Other, `StickyO, 0o1000;
Packit 9ff65e
    `Other, `Exec,    0o0001;
Packit 9ff65e
    `Other, `Write,   0o0002;
Packit 9ff65e
    `Other, `Read,    0o0004;
Packit 9ff65e
  ]
Packit 9ff65e
Packit 9ff65e
Packit 9ff65e
let mask =
Packit 9ff65e
  let module M =
Packit 9ff65e
    Map.Make
Packit 9ff65e
      (struct
Packit 9ff65e
         type t = who * perm
Packit 9ff65e
         let compare = Pervasives.compare
Packit 9ff65e
       end)
Packit 9ff65e
  in
Packit 9ff65e
  let m =
Packit 9ff65e
    List.fold_left
Packit 9ff65e
      (fun m (who, prm, msk) -> M.add (who, prm) msk m)
Packit 9ff65e
      M.empty all_masks
Packit 9ff65e
  in
Packit 9ff65e
    fun who prm ->
Packit 9ff65e
      try
Packit 9ff65e
        M.find (who, prm) m
Packit 9ff65e
      with Not_found ->
Packit 9ff65e
        0
Packit 9ff65e
Packit 9ff65e
Packit 9ff65e
let of_int i =
Packit 9ff65e
  let user, group, other =
Packit 9ff65e
    List.fold_left
Packit 9ff65e
      (fun (user, group, other) (who, perm, mask) ->
Packit 9ff65e
         if (i land mask) <> 0 then begin
Packit 9ff65e
           match who with
Packit 9ff65e
           | `User -> perm :: user, group, other
Packit 9ff65e
           | `Group -> user, perm :: group, other
Packit 9ff65e
           | `Other -> user, group, perm :: other
Packit 9ff65e
         end else begin
Packit 9ff65e
           (user, group, other)
Packit 9ff65e
         end)
Packit 9ff65e
      ([], [], [])
Packit 9ff65e
      all_masks
Packit 9ff65e
  in
Packit 9ff65e
    [`User (`Set (`List user));
Packit 9ff65e
     `Group (`Set (`List group));
Packit 9ff65e
     `Other (`Set (`List other))]
Packit 9ff65e
Packit 9ff65e
Packit 9ff65e
let to_string =
Packit 9ff65e
  let perm =
Packit 9ff65e
    function
Packit 9ff65e
    | `Read -> "r"
Packit 9ff65e
    | `Write -> "w"
Packit 9ff65e
    | `Exec -> "x"
Packit 9ff65e
    | `Sticky -> "s"
Packit 9ff65e
    | `ExecX -> "X"
Packit 9ff65e
    | `StickyO -> "t"
Packit 9ff65e
  in
Packit 9ff65e
  let permlist =
Packit 9ff65e
    function
Packit 9ff65e
    | `List lst -> String.concat "" (List.map perm lst)
Packit 9ff65e
    | #perm as prm -> perm prm
Packit 9ff65e
  in
Packit 9ff65e
  let permcopy =
Packit 9ff65e
    function
Packit 9ff65e
    | `User -> "u"
Packit 9ff65e
    | `Group -> "g"
Packit 9ff65e
    | `Other -> "o"
Packit 9ff65e
  in
Packit 9ff65e
  let action act =
Packit 9ff65e
    let sact, arg =
Packit 9ff65e
      match act with
Packit 9ff65e
      | `Set arg -> "=", arg
Packit 9ff65e
      | `Add arg -> "+", arg
Packit 9ff65e
      | `Remove arg -> "-", arg
Packit 9ff65e
    in
Packit 9ff65e
    let sarg =
Packit 9ff65e
      match arg with
Packit 9ff65e
      | #permlist as lst -> permlist lst
Packit 9ff65e
      | #permcopy as prm -> permcopy prm
Packit 9ff65e
    in
Packit 9ff65e
      sact^sarg
Packit 9ff65e
  in
Packit 9ff65e
  let actionlist =
Packit 9ff65e
    function
Packit 9ff65e
    | `List lst -> String.concat "" (List.map action lst)
Packit 9ff65e
    | #action as act -> action act
Packit 9ff65e
  in
Packit 9ff65e
  let clause cls =
Packit 9ff65e
    let swho, lst =
Packit 9ff65e
      match cls with
Packit 9ff65e
      | `User lst -> "u", lst
Packit 9ff65e
      | `Group lst -> "g", lst
Packit 9ff65e
      | `Other lst -> "o", lst
Packit 9ff65e
      | `All lst -> "a", lst
Packit 9ff65e
      | `None lst -> "", lst
Packit 9ff65e
    in
Packit 9ff65e
      swho^(actionlist lst)
Packit 9ff65e
  in
Packit 9ff65e
    fun t -> String.concat "," (List.map clause t)
Packit 9ff65e
Packit 9ff65e
Packit 9ff65e
let apply ~is_dir ~umask i (t: t) =
Packit 9ff65e
  let set who prm b i =
Packit 9ff65e
    let m = mask who prm in
Packit 9ff65e
      if b then i lor m else i land (lnot m)
Packit 9ff65e
  in
Packit 9ff65e
  let get who prm i =
Packit 9ff65e
    let m = mask who prm in
Packit 9ff65e
      (i land m) <> 0
Packit 9ff65e
  in
Packit 9ff65e
  let permlist _who i lst =
Packit 9ff65e
    List.fold_left
Packit 9ff65e
      (fun acc ->
Packit 9ff65e
         function
Packit 9ff65e
         | `Exec | `Read | `Write | `Sticky | `StickyO as a -> a :: acc
Packit 9ff65e
         | `ExecX ->
Packit 9ff65e
             if is_dir ||
Packit 9ff65e
                List.exists (fun who -> get who `Exec i)
Packit 9ff65e
                  [`User; `Group; `Other] then
Packit 9ff65e
               `Exec :: acc
Packit 9ff65e
             else
Packit 9ff65e
               acc)
Packit 9ff65e
      []
Packit 9ff65e
      (match lst with
Packit 9ff65e
       | `List lst -> lst
Packit 9ff65e
       | #perm as prm -> [prm])
Packit 9ff65e
  in
Packit 9ff65e
  let permcopy _who i =
Packit 9ff65e
    List.fold_left
Packit 9ff65e
      (fun acc (who, prm, _) ->
Packit 9ff65e
         if get who prm i then
Packit 9ff65e
           prm :: acc
Packit 9ff65e
         else
Packit 9ff65e
           acc)
Packit 9ff65e
      [] all_masks
Packit 9ff65e
  in
Packit 9ff65e
  let args who i =
Packit 9ff65e
    function
Packit 9ff65e
    | #permlist as lst -> permlist who i lst
Packit 9ff65e
    | #permcopy as who -> permcopy who i
Packit 9ff65e
  in
Packit 9ff65e
  let rec action who i act =
Packit 9ff65e
    match act with
Packit 9ff65e
    | `Set arg ->
Packit 9ff65e
        action who
Packit 9ff65e
          (action who i (`Remove (`List (permcopy who i))))
Packit 9ff65e
          (`Add arg)
Packit 9ff65e
    | `Add arg ->
Packit 9ff65e
        List.fold_left (fun i prm -> set who prm true i) i (args who i arg)
Packit 9ff65e
    | `Remove arg ->
Packit 9ff65e
        List.fold_left (fun i prm -> set who prm false i) i (args who i arg) 
Packit 9ff65e
  in
Packit 9ff65e
  let actionlist who i lst =
Packit 9ff65e
    match lst with
Packit 9ff65e
    | `List lst -> List.fold_left (action who) i lst
Packit 9ff65e
    | #action as act -> action who i act
Packit 9ff65e
  in
Packit 9ff65e
  let actionlist_none i lst =
Packit 9ff65e
    let numask = lnot umask in
Packit 9ff65e
    let arg_set_if_mask who i arg b =
Packit 9ff65e
      List.fold_left
Packit 9ff65e
        (fun i prm ->
Packit 9ff65e
           if get who prm numask then
Packit 9ff65e
             set who prm b i
Packit 9ff65e
           else
Packit 9ff65e
             i)
Packit 9ff65e
        i (args who i arg)
Packit 9ff65e
    in
Packit 9ff65e
      List.fold_left
Packit 9ff65e
        (fun i who ->
Packit 9ff65e
           List.fold_left
Packit 9ff65e
             (fun i ->
Packit 9ff65e
                function
Packit 9ff65e
                | `Set _ -> i
Packit 9ff65e
                | `Add arg -> arg_set_if_mask who i arg true
Packit 9ff65e
                | `Remove arg -> arg_set_if_mask who i arg false)
Packit 9ff65e
             i
Packit 9ff65e
             (match lst with
Packit 9ff65e
              | `List lst -> lst
Packit 9ff65e
              | #action as act -> [act]))
Packit 9ff65e
        i [`User; `Group; `Other]
Packit 9ff65e
  in
Packit 9ff65e
Packit 9ff65e
  let rec clause i cls =
Packit 9ff65e
    match cls with
Packit 9ff65e
    | `User lst -> actionlist `User i lst
Packit 9ff65e
    | `Group lst -> actionlist `Group i lst
Packit 9ff65e
    | `Other lst -> actionlist `Other i lst
Packit 9ff65e
    | `All lst -> 
Packit 9ff65e
        List.fold_left clause i [`User lst; `Group lst; `Other lst]
Packit 9ff65e
    | `None lst -> actionlist_none i lst
Packit 9ff65e
  in
Packit 9ff65e
    List.fold_left clause i t