1 (***********************************************************************)
4 (* Nicolas Pouillard, Berke Durak, projet Gallium, INRIA Rocquencourt *)
6 (* Copyright 2007 Institut National de Recherche en Informatique et *)
7 (* en Automatique. All rights reserved. This file is distributed *)
8 (* under the terms of the Q Public License version 1.0. *)
10 (***********************************************************************)
13 (* Original author: Berke Durak *)
19 | Dir
of string * string * My_unix.stats
Lazy.t
* 'a
* 'a entry list
Lazy.t
20 | File
of string * string * My_unix.stats
Lazy.t
* 'a
24 let (/) = filename_concat
26 let rec filter predicate
= function
27 | Dir
(path
, name
, st
, attr
, entries
) ->
28 if predicate path name attr
then
29 Dir
(path
, name
, st
, attr
, lazy (List.map
(filter predicate
) !*entries
))
32 | File
(path
, name
, _
, attr
) as f
->
33 if predicate path name attr
then
41 let cwd = Sys.getcwd
() in
42 let abs x
= if Filename.is_implicit x
|| Filename.is_relative x
then cwd/x
else x
in
43 let visited = Hashtbl.create
1024 in
44 let rec scandir path names
=
45 let (file_acc
, dir_acc
) =
46 Array.fold_left
begin fun ((file_acc
, dir_acc
) as acc
) name
->
47 match do_entry
true path name
with
49 | Some
((Dir _
|Error _
) as entry
) -> (file_acc
, entry
:: dir_acc
)
50 | Some
((File _
) as entry
) -> (entry
:: file_acc
, dir_acc
)
57 and do_entry link_mode path name
=
62 Good
(if link_mode
then My_unix.lstat
absfn else My_unix.stat
absfn)
66 | Bad x
-> Some
(Error x
)
68 let key = st
.My_unix.stat_key
in
69 if try Hashtbl.find
visited key with Not_found
-> false
73 Hashtbl.add
visited key true;
75 match st
.My_unix.stat_file_kind
with
77 let fn'
= My_unix.readlink
absfn in
78 if sys_file_exists
(abs fn'
) then
79 do_entry
false path name
81 Some
(File
(path
, name
, lazy st
, ()))
83 (match sys_readdir
absfn with
84 | Good names
-> Some
(Dir
(path
, name
, lazy st
, (), lazy (scandir fn names
)))
85 | Bad exn
-> Some
(Error exn
))
86 | My_unix.FK_other
-> None
87 | My_unix.FK_file
-> Some
(File
(path
, name
, lazy st
, ())) in
88 Hashtbl.replace
visited key false;
92 match do_entry
true "" path
with
93 | None
-> raise Not_found
98 if path
= Filename.current_dir_name
then []
99 else (Filename.basename path
) :: aux (Filename.dirname path
)
100 in List.rev
(aux path
)
106 | x
:: xs
-> x
/(join xs
)
108 let rec add root path entries
=
109 match path
, entries
with
111 | xpath
:: xspath
, (Dir
(dpath
, dname
, dst
, dattr
, dentries
) as d
) :: entries
->
112 if xpath
= dname
then
113 Dir
(dpath
, dname
, dst
, dattr
, lazy (add (root
/xpath
) xspath
!*dentries
)) :: entries
114 else d
:: add root path entries
116 [File
(root
, xpath
, lazy (My_unix.stat
(root
/xpath
)), ())]
117 | xpath
:: xspath
, [] ->
118 [Dir
(root
/(join xspath
), xpath
,
119 lazy (My_unix.stat
(root
/(join path
))), (),
120 lazy (add (root
/xpath
) xspath
[]))]
121 | _
, Nothing
:: entries
-> add root path entries
122 | _
, Error _
:: _
-> entries
123 | [xpath
], (File
(_
, fname
, _
, _
) as f
) :: entries'
->
124 if xpath
= fname
then entries
125 else f
:: add root path entries'
126 | xpath
:: xspath
, (File
(fpath
, fname
, fst
, fattr
) as f
) :: entries'
->
127 if xpath
= fname
then
128 Dir
(fpath
, fname
, fst
, fattr
, lazy (add (root
/xpath
) xspath
[])) :: entries'
129 else f
:: add root path entries'
131 let slurp_with_find path
=
133 My_unix.run_and_open
(Printf.sprintf
"find %s" (Filename.quote path
)) begin fun ic
->
135 try while true do acc := input_line ic
:: !acc done; []
136 with End_of_file
-> !acc
139 List.fold_right
begin fun line
acc ->
140 add path
(split line
) acc
145 | entries
-> Dir
(path
, Filename.basename path
, lazy (My_unix.stat path
), (), lazy entries
)
147 let slurp x
= if !*My_unix.is_degraded
then slurp_with_find x
else real_slurp x
149 let rec print print_attr f entry
=
151 | Dir
(path
, name
, _
, attr
, entries
) ->
152 Format.fprintf f
"@[<2>Dir(%S,@ %S,@ _,@ %a,@ %a)@]"
153 path name print_attr attr
(List.print (print print_attr
)) !*entries
154 | File
(path
, name
, _
, attr
) ->
155 Format.fprintf f
"@[<2>File(%S,@ %S,@ _,@ %a)@]" path name print_attr attr
157 Format.fprintf f
"Nothing"
159 Format.fprintf f
"Error(_)"
161 let rec fold f entry
acc =
163 | Dir
(path
, name
, _
, attr
, contents
) ->
164 f path name attr
(List.fold_right
(fold f
) !*contents
acc)
165 | File
(path
, name
, _
, attr
) ->
167 | Nothing
| Error _
-> acc
172 | Dir
(path
, name
, st
, attr
, contents
) ->
173 Dir
(path
, name
, st
, f path name attr
, lazy (List.map self !*contents
))
174 | File
(path
, name
, st
, attr
) ->
175 File
(path
, name
, st
, f path name attr
)
182 | Dir
(_
, _
, st
, _
, contents
) ->
183 let _ = !*st
in List.iter
force !*contents
184 | File
(_, _, st
, _) ->
186 | Nothing
| Error
_ -> ()