1
1
use std:: fs;
2
2
use std:: sync:: Arc ;
3
+ use std:: sync:: Mutex ;
3
4
4
5
use crate :: node:: Node ;
5
6
use crate :: progress:: Operation ;
6
7
use crate :: progress:: PAtomicInfo ;
8
+ use crate :: progress:: RuntimeErrors ;
7
9
use crate :: progress:: ORDERING ;
8
10
use crate :: utils:: is_filtered_out_due_to_invert_regex;
9
11
use crate :: utils:: is_filtered_out_due_to_regex;
@@ -28,16 +30,17 @@ pub struct WalkData<'a> {
28
30
pub ignore_hidden : bool ,
29
31
pub follow_links : bool ,
30
32
pub progress_data : Arc < PAtomicInfo > ,
33
+ pub errors : Arc < Mutex < RuntimeErrors > > ,
31
34
}
32
35
33
- pub fn walk_it ( dirs : HashSet < PathBuf > , walk_data : WalkData ) -> Vec < Node > {
36
+ pub fn walk_it ( dirs : HashSet < PathBuf > , walk_data : & WalkData ) -> Vec < Node > {
34
37
let mut inodes = HashSet :: new ( ) ;
35
38
let top_level_nodes: Vec < _ > = dirs
36
39
. into_iter ( )
37
40
. filter_map ( |d| {
38
41
let prog_data = & walk_data. progress_data ;
39
42
prog_data. clear_state ( & d) ;
40
- let node = walk ( d, & walk_data, 0 ) ?;
43
+ let node = walk ( d, walk_data, 0 ) ?;
41
44
42
45
prog_data. state . store ( Operation :: PREPARING , ORDERING ) ;
43
46
@@ -126,55 +129,83 @@ fn ignore_file(entry: &DirEntry, walk_data: &WalkData) -> bool {
126
129
127
130
fn walk ( dir : PathBuf , walk_data : & WalkData , depth : usize ) -> Option < Node > {
128
131
let prog_data = & walk_data. progress_data ;
129
- let mut children = vec ! [ ] ;
130
-
131
- if let Ok ( entries) = fs:: read_dir ( & dir) {
132
- children = entries
133
- . into_iter ( )
134
- . par_bridge ( )
135
- . filter_map ( |entry| {
136
- if let Ok ( ref entry) = entry {
137
- // uncommenting the below line gives simpler code but
138
- // rayon doesn't parallelize as well giving a 3X performance drop
139
- // hence we unravel the recursion a bit
140
-
141
- // return walk(entry.path(), walk_data, depth)
142
-
143
- if !ignore_file ( entry, walk_data) {
144
- if let Ok ( data) = entry. file_type ( ) {
145
- if data. is_dir ( ) || ( walk_data. follow_links && data. is_symlink ( ) ) {
146
- return walk ( entry. path ( ) , walk_data, depth + 1 ) ;
147
- }
132
+ let errors = & walk_data. errors ;
148
133
149
- let node = build_node (
150
- entry. path ( ) ,
151
- vec ! [ ] ,
152
- walk_data. filter_regex ,
153
- walk_data. invert_filter_regex ,
154
- walk_data. use_apparent_size ,
155
- data. is_symlink ( ) ,
156
- data. is_file ( ) ,
157
- walk_data. by_filecount ,
158
- depth,
159
- ) ;
160
-
161
- prog_data. num_files . fetch_add ( 1 , ORDERING ) ;
162
- if let Some ( ref file) = node {
163
- prog_data. total_file_size . fetch_add ( file. size , ORDERING ) ;
164
- }
134
+ let children = if dir. is_dir ( ) {
135
+ let read_dir = fs:: read_dir ( & dir) ;
136
+ match read_dir {
137
+ Ok ( entries) => {
138
+ entries
139
+ . into_iter ( )
140
+ . par_bridge ( )
141
+ . filter_map ( |entry| {
142
+ if let Ok ( ref entry) = entry {
143
+ // uncommenting the below line gives simpler code but
144
+ // rayon doesn't parallelize as well giving a 3X performance drop
145
+ // hence we unravel the recursion a bit
146
+
147
+ // return walk(entry.path(), walk_data, depth)
148
+
149
+ if !ignore_file ( entry, walk_data) {
150
+ if let Ok ( data) = entry. file_type ( ) {
151
+ if data. is_dir ( )
152
+ || ( walk_data. follow_links && data. is_symlink ( ) )
153
+ {
154
+ return walk ( entry. path ( ) , walk_data, depth + 1 ) ;
155
+ }
165
156
166
- return node;
157
+ let node = build_node (
158
+ entry. path ( ) ,
159
+ vec ! [ ] ,
160
+ walk_data. filter_regex ,
161
+ walk_data. invert_filter_regex ,
162
+ walk_data. use_apparent_size ,
163
+ data. is_symlink ( ) ,
164
+ data. is_file ( ) ,
165
+ walk_data. by_filecount ,
166
+ depth,
167
+ ) ;
168
+
169
+ prog_data. num_files . fetch_add ( 1 , ORDERING ) ;
170
+ if let Some ( ref file) = node {
171
+ prog_data. total_file_size . fetch_add ( file. size , ORDERING ) ;
172
+ }
173
+
174
+ return node;
175
+ }
176
+ }
177
+ } else {
178
+ let mut editable_error = errors. lock ( ) . unwrap ( ) ;
179
+ editable_error. no_permissions = true
167
180
}
181
+ None
182
+ } )
183
+ . collect ( )
184
+ }
185
+ Err ( failed) => {
186
+ let mut editable_error = errors. lock ( ) . unwrap ( ) ;
187
+ match failed. kind ( ) {
188
+ std:: io:: ErrorKind :: PermissionDenied => {
189
+ editable_error. no_permissions = true ;
190
+ }
191
+ std:: io:: ErrorKind :: NotFound => {
192
+ editable_error. file_not_found . insert ( failed. to_string ( ) ) ;
193
+ }
194
+ _ => {
195
+ editable_error. unknown_error . insert ( failed. to_string ( ) ) ;
168
196
}
169
- } else {
170
- prog_data. no_permissions . store ( true , ORDERING )
171
197
}
172
- None
173
- } )
174
- . collect ( ) ;
175
- } else if !dir. is_file ( ) {
176
- walk_data. progress_data . no_permissions . store ( true , ORDERING )
177
- }
198
+ vec ! [ ]
199
+ }
200
+ }
201
+ } else {
202
+ if !dir. is_file ( ) {
203
+ let mut editable_error = errors. lock ( ) . unwrap ( ) ;
204
+ let bad_file = dir. as_os_str ( ) . to_string_lossy ( ) . into ( ) ;
205
+ editable_error. file_not_found . insert ( bad_file) ;
206
+ }
207
+ vec ! [ ]
208
+ } ;
178
209
build_node (
179
210
dir,
180
211
children,
0 commit comments