let find on_error on_path follow depth roots =
      let rec find_rec depth visiting filename =
        try
          let infos = (if follow then stat else lstat) filename in
          let continue = hide_exn (on_path filename) infos in
          let id = infos.st_dev, infos.st_ino in
          if infos.st_kind = S_DIR && depth > 0 && continue &&
            (not follow || not (List.mem id visiting))
          then
            let process_child child =
              if (child <> Filename.current_dir_name &&
                  child <> Filename.parent_dir_name) then
                let child_name = Filename.concat filename child in
                let visiting =
                  if follow then id :: visiting else visiting in
                 find_rec (depth-1) visiting child_name in
                 iter_dir process_child filename
        with Unix_error (e, b, c) -> hide_exn on_error (e, b, c) in
      reveal_exn (List.iter (find_rec depth [])) roots