let real_slurp path =
let cwd = Sys.getcwd () in
let abs x = if Filename.is_implicit x || Filename.is_relative x then cwd/x else x in
let visited = Hashtbl.create 1024 in
let rec scandir path names =
let (file_acc, dir_acc) =
Array.fold_left begin fun ((file_acc, dir_acc) as acc) name ->
match do_entry true path name with
| None -> acc
| Some((Dir _|Error _) as entry) -> (file_acc, entry :: dir_acc)
| Some((File _) as entry) -> (entry :: file_acc, dir_acc)
| Some Nothing -> acc
end
([], [])
names
in
file_acc @ dir_acc
and do_entry link_mode path name =
let fn = path/name in
let absfn = abs fn in
match
try
Good(if link_mode then My_unix.lstat absfn else My_unix.stat absfn)
with
| x -> Bad x
with
| Bad x -> Some(Error x)
| Good st ->
let key = st.My_unix.stat_key in
if try Hashtbl.find visited key with Not_found -> false
then None
else
begin
Hashtbl.add visited key true;
let res =
match st.My_unix.stat_file_kind with
| My_unix.FK_link ->
let fn' = My_unix.readlink absfn in
if sys_file_exists (abs fn') then
do_entry false path name
else
Some(File(path, name, lazy st, ()))
| My_unix.FK_dir ->
(match sys_readdir absfn with
| Good names -> Some(Dir(path, name, lazy st, (), lazy (scandir fn names)))
| Bad exn -> Some(Error exn))
| My_unix.FK_other -> None
| My_unix.FK_file -> Some(File(path, name, lazy st, ())) in
Hashtbl.replace visited key false;
res
end
in
match do_entry true "" path with
| None -> raise Not_found
| Some entry -> entry