Blame src/FileUtilTEST.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 FileUtilSize
Packit 9ff65e
open FileUtilSTAT
Packit 9ff65e
Packit 9ff65e
Packit 9ff65e
let compile_filter ?(match_compile=(fun s fn -> s = fn)) flt =
Packit 9ff65e
  let cflt =
Packit 9ff65e
    let rec cc =
Packit 9ff65e
      function
Packit 9ff65e
      | True                   -> `Val true
Packit 9ff65e
      | False                  -> `Val false
Packit 9ff65e
      | Is_dev_block           -> `Stat (`Kind Dev_block)
Packit 9ff65e
      | Is_dev_char            -> `Stat (`Kind Dev_char)
Packit 9ff65e
      | Is_dir                 -> `Stat (`Kind Dir)
Packit 9ff65e
      | Is_file                -> `Stat (`Kind File)
Packit 9ff65e
      | Is_socket              -> `Stat (`Kind Socket)
Packit 9ff65e
      | Is_pipe                -> `Stat (`Kind Fifo)
Packit 9ff65e
      | Is_link                -> `Is_link
Packit 9ff65e
      | Is_set_group_ID        -> `Stat `Is_set_group_ID
Packit 9ff65e
      | Has_sticky_bit         -> `Stat `Has_sticky_bit
Packit 9ff65e
      | Has_set_user_ID        -> `Stat `Has_set_user_ID
Packit 9ff65e
      | Is_readable            -> `Stat `Is_readable
Packit 9ff65e
      | Is_writeable           -> `Stat `Is_writeable
Packit 9ff65e
      | Is_exec                -> `Stat `Is_exec
Packit 9ff65e
      | Size_not_null          -> `Stat (`Size (`Bigger, B 0L))
Packit 9ff65e
      | Size_bigger_than sz    -> `Stat (`Size (`Bigger, sz))
Packit 9ff65e
      | Size_smaller_than sz   -> `Stat (`Size (`Smaller, sz))
Packit 9ff65e
      | Size_equal_to sz       -> `Stat (`Size (`Equal, sz))
Packit 9ff65e
      | Size_fuzzy_equal_to sz -> `Stat (`Size (`FuzzyEqual, sz))
Packit 9ff65e
      | Is_owned_by_user_ID ->
Packit 9ff65e
          `Stat (`Is_owned_by_user_ID (Unix.geteuid ()))
Packit 9ff65e
      | Is_owned_by_group_ID ->
Packit 9ff65e
          `Stat (`Is_owned_by_group_ID (Unix.getegid ()))
Packit 9ff65e
      | Exists                 -> `Stat `Exists
Packit 9ff65e
      | Is_newer_than fn1      -> `Stat (`Newer (stat fn1).modification_time)
Packit 9ff65e
      | Is_older_than fn1      -> `Stat (`Older (stat fn1).modification_time)
Packit 9ff65e
      | Is_newer_than_date(dt) -> `Stat (`Newer dt)
Packit 9ff65e
      | Is_older_than_date(dt) -> `Stat (`Older dt)
Packit 9ff65e
      | Has_extension ext      -> `Has_extension ext
Packit 9ff65e
      | Has_no_extension       -> `Has_no_extension
Packit 9ff65e
      | Is_current_dir         -> `Is_current_dir
Packit 9ff65e
      | Is_parent_dir          -> `Is_parent_dir
Packit 9ff65e
      | Basename_is s          -> `Basename_is s
Packit 9ff65e
      | Dirname_is s           -> `Dirname_is s
Packit 9ff65e
      | Custom f               -> `Custom f
Packit 9ff65e
      | Match str              -> `Custom (match_compile str)
Packit 9ff65e
      | And(flt1, flt2) ->
Packit 9ff65e
          begin
Packit 9ff65e
            match cc flt1, cc flt2 with
Packit 9ff65e
              | `Val true, cflt | cflt, `Val true -> cflt
Packit 9ff65e
              | `Val false, _ | _,  `Val false -> `Val false
Packit 9ff65e
              | cflt1, cflt2 -> `And (cflt1, cflt2)
Packit 9ff65e
          end
Packit 9ff65e
      | Or(flt1, flt2) ->
Packit 9ff65e
          begin
Packit 9ff65e
            match cc flt1, cc flt2 with
Packit 9ff65e
              | `Val true, _ | _, `Val true -> `Val true
Packit 9ff65e
              | `Val false, cflt | cflt,  `Val false -> cflt
Packit 9ff65e
              | cflt1, cflt2 -> `Or (cflt1, cflt2)
Packit 9ff65e
          end
Packit 9ff65e
      | Not flt ->
Packit 9ff65e
          begin
Packit 9ff65e
            match cc flt with
Packit 9ff65e
              | `Val b -> `Val (not b)
Packit 9ff65e
              | cflt -> `Not cflt
Packit 9ff65e
          end
Packit 9ff65e
    in
Packit 9ff65e
    cc flt
Packit 9ff65e
  in
Packit 9ff65e
  let need_statL, need_stat =
Packit 9ff65e
    let rec dfs =
Packit 9ff65e
      function
Packit 9ff65e
        | `Val _ | `Has_extension _ | `Has_no_extension | `Is_current_dir
Packit 9ff65e
        | `Is_parent_dir | `Basename_is _ | `Dirname_is _
Packit 9ff65e
        | `Custom _ ->
Packit 9ff65e
            false, false
Packit 9ff65e
        | `Stat _ ->
Packit 9ff65e
            true, false
Packit 9ff65e
        | `Is_link ->
Packit 9ff65e
            false, true
Packit 9ff65e
        | `And (cflt1, cflt2) | `Or (cflt1, cflt2) ->
Packit 9ff65e
            let need_stat1, need_statL1 = dfs cflt1 in
Packit 9ff65e
            let need_stat2, need_statL2 = dfs cflt2 in
Packit 9ff65e
              need_stat1 || need_stat2, need_statL1 || need_statL2
Packit 9ff65e
        | `Not cflt ->
Packit 9ff65e
            dfs cflt
Packit 9ff65e
    in
Packit 9ff65e
      dfs cflt
Packit 9ff65e
  in
Packit 9ff65e
    (* Compiled function to return. *)
Packit 9ff65e
    fun ?st_opt ?stL_opt fn ->
Packit 9ff65e
      let st_opt =
Packit 9ff65e
        if need_stat && st_opt = None then begin
Packit 9ff65e
          try
Packit 9ff65e
            match stL_opt with
Packit 9ff65e
              | Some st when not st.is_link -> stL_opt
Packit 9ff65e
              | _ -> Some (stat fn)
Packit 9ff65e
          with FileDoesntExist _ ->
Packit 9ff65e
            None
Packit 9ff65e
        end else
Packit 9ff65e
          st_opt
Packit 9ff65e
      in
Packit 9ff65e
      let stL_opt =
Packit 9ff65e
        if need_statL && stL_opt = None then begin
Packit 9ff65e
          try
Packit 9ff65e
            match st_opt with
Packit 9ff65e
              | Some st when not st.is_link -> st_opt
Packit 9ff65e
              | _ -> Some (stat ~dereference:true fn)
Packit 9ff65e
          with FileDoesntExist _ ->
Packit 9ff65e
            None
Packit 9ff65e
        end else
Packit 9ff65e
          stL_opt
Packit 9ff65e
      in
Packit 9ff65e
      let rec eval =
Packit 9ff65e
        function
Packit 9ff65e
        | `Val b -> b
Packit 9ff65e
        | `Has_extension ext ->
Packit 9ff65e
            begin
Packit 9ff65e
              try
Packit 9ff65e
                check_extension fn ext
Packit 9ff65e
              with FilePath.NoExtension _ ->
Packit 9ff65e
                false
Packit 9ff65e
            end
Packit 9ff65e
        | `Has_no_extension ->
Packit 9ff65e
            begin
Packit 9ff65e
              try
Packit 9ff65e
                let _str: filename = chop_extension fn in
Packit 9ff65e
                  false
Packit 9ff65e
              with FilePath.NoExtension _ ->
Packit 9ff65e
                true
Packit 9ff65e
            end
Packit 9ff65e
        | `Is_current_dir -> is_current (basename fn)
Packit 9ff65e
        | `Is_parent_dir -> is_parent (basename fn)
Packit 9ff65e
        | `Basename_is bn -> (FilePath.compare (basename fn) bn) = 0
Packit 9ff65e
        | `Dirname_is dn -> (FilePath.compare (dirname fn) dn) = 0
Packit 9ff65e
        | `Custom f -> f fn
Packit 9ff65e
        | `Stat e ->
Packit 9ff65e
            begin
Packit 9ff65e
              match stL_opt, e with
Packit 9ff65e
              | Some _, `Exists -> true
Packit 9ff65e
              | Some stL, `Kind knd -> stL.kind = knd
Packit 9ff65e
              | Some stL, `Is_set_group_ID -> stL.permission.group.sticky
Packit 9ff65e
              | Some stL, `Has_sticky_bit -> stL.permission.other.sticky
Packit 9ff65e
              | Some stL, `Has_set_user_ID -> stL.permission.user.sticky
Packit 9ff65e
              | Some stL, `Size (cmp, sz) ->
Packit 9ff65e
                  begin
Packit 9ff65e
                    let diff = size_compare stL.size sz in
Packit 9ff65e
                      match cmp with
Packit 9ff65e
                      | `Bigger -> diff > 0
Packit 9ff65e
                      | `Smaller -> diff < 0
Packit 9ff65e
                      | `Equal -> diff = 0
Packit 9ff65e
                      | `FuzzyEqual ->
Packit 9ff65e
                          (size_compare ~fuzzy:true stL.size sz) = 0
Packit 9ff65e
                  end
Packit 9ff65e
              | Some stL, `Is_owned_by_user_ID uid -> uid = stL.owner
Packit 9ff65e
              | Some stL, `Is_owned_by_group_ID gid -> gid = stL.group_owner
Packit 9ff65e
              | Some stL, `Is_readable ->
Packit 9ff65e
                  let perm = stL.permission in
Packit 9ff65e
                    perm.user.read || perm.group.read || perm.other.read
Packit 9ff65e
              | Some stL, `Is_writeable ->
Packit 9ff65e
                  let perm = stL.permission in
Packit 9ff65e
                    perm.user.write || perm.group.write || perm.other.write
Packit 9ff65e
              | Some stL, `Is_exec ->
Packit 9ff65e
                  let perm = stL.permission in
Packit 9ff65e
                    perm.user.exec || perm.group.exec || perm.other.exec
Packit 9ff65e
              | Some stL, `Newer dt -> stL.modification_time > dt
Packit 9ff65e
              | Some stL, `Older dt -> stL.modification_time < dt
Packit 9ff65e
              | None, _ -> false
Packit 9ff65e
            end
Packit 9ff65e
        | `Is_link ->
Packit 9ff65e
            begin
Packit 9ff65e
              match st_opt with
Packit 9ff65e
                | Some st -> st.is_link
Packit 9ff65e
                | None -> false
Packit 9ff65e
            end
Packit 9ff65e
        | `And (cflt1, cflt2) -> (eval cflt1) && (eval cflt2)
Packit 9ff65e
        | `Or (cflt1, cflt2) -> (eval cflt1) || (eval cflt2)
Packit 9ff65e
        | `Not cflt -> not (eval cflt)
Packit 9ff65e
      in
Packit 9ff65e
      eval cflt
Packit 9ff65e
Packit 9ff65e
Packit 9ff65e
let test ?match_compile tst =
Packit 9ff65e
  let ctst = compile_filter ?match_compile tst in
Packit 9ff65e
  fun fln -> ctst (solve_dirname fln)
Packit 9ff65e
Packit 9ff65e
Packit 9ff65e
let filter flt lst = List.filter (test flt) lst
Packit 9ff65e
Packit 9ff65e
Packit 9ff65e
let test_exists = test (Or(Exists, Is_link))
Packit 9ff65e