@@ -6,6 +6,7 @@ use std::{
6
6
fs,
7
7
path:: { Path , PathBuf } ,
8
8
time:: SystemTime ,
9
+ vec:: Vec ,
9
10
} ;
10
11
11
12
use libafl_bolts:: { current_time, shmem:: ShMemProvider , Named } ;
@@ -33,15 +34,20 @@ use crate::{
33
34
pub struct SyncFromDiskMetadata {
34
35
/// The last time the sync was done
35
36
pub last_time : SystemTime ,
37
+ /// The paths that are left to sync
38
+ pub left_to_sync : Vec < PathBuf > ,
36
39
}
37
40
38
41
libafl_bolts:: impl_serdeany!( SyncFromDiskMetadata ) ;
39
42
40
43
impl SyncFromDiskMetadata {
41
44
/// Create a new [`struct@SyncFromDiskMetadata`]
42
45
#[ must_use]
43
- pub fn new ( last_time : SystemTime ) -> Self {
44
- Self { last_time }
46
+ pub fn new ( last_time : SystemTime , left_to_sync : Vec < PathBuf > ) -> Self {
47
+ Self {
48
+ last_time,
49
+ left_to_sync,
50
+ }
45
51
}
46
52
}
47
53
@@ -89,24 +95,53 @@ where
89
95
state : & mut Z :: State ,
90
96
manager : & mut EM ,
91
97
) -> Result < ( ) , Error > {
98
+ log:: debug!( "Syncing from disk: {:?}" , self . sync_dir) ;
92
99
let last = state
93
100
. metadata_map ( )
94
101
. get :: < SyncFromDiskMetadata > ( )
95
102
. map ( |m| m. last_time ) ;
96
- let path = self . sync_dir . clone ( ) ;
97
- if let Some ( max_time) =
98
- self . load_from_directory ( & path, & last, fuzzer, executor, state, manager) ?
99
- {
103
+
104
+ if let ( Some ( max_time) , mut new_files) = self . load_from_directory ( & last) ? {
100
105
if last. is_none ( ) {
101
106
state
102
107
. metadata_map_mut ( )
103
- . insert ( SyncFromDiskMetadata :: new ( max_time) ) ;
108
+ . insert ( SyncFromDiskMetadata :: new ( max_time, new_files ) ) ;
104
109
} else {
105
110
state
106
111
. metadata_map_mut ( )
107
112
. get_mut :: < SyncFromDiskMetadata > ( )
108
113
. unwrap ( )
109
114
. last_time = max_time;
115
+ state
116
+ . metadata_map_mut ( )
117
+ . get_mut :: < SyncFromDiskMetadata > ( )
118
+ . unwrap ( )
119
+ . left_to_sync
120
+ . append ( & mut new_files) ;
121
+ }
122
+ }
123
+
124
+ if let Some ( sync_from_disk_metadata) =
125
+ state. metadata_map_mut ( ) . get_mut :: < SyncFromDiskMetadata > ( )
126
+ {
127
+ // Iterate over the paths of files left to sync.
128
+ // By keeping track of these files, we ensure that no file is missed during synchronization,
129
+ // even in the event of a target restart.
130
+ let to_sync = sync_from_disk_metadata. left_to_sync . clone ( ) ;
131
+ log:: debug!( "Number of files to sync: {:?}" , to_sync. len( ) ) ;
132
+ for path in to_sync {
133
+ let input = ( self . load_callback ) ( fuzzer, state, & path) ?;
134
+ // Removing each path from the `left_to_sync` Vec before evaluating
135
+ // prevents duplicate processing and ensures that each file is evaluated only once. This approach helps
136
+ // avoid potential infinite loops that may occur if a file is an objective.
137
+ state
138
+ . metadata_map_mut ( )
139
+ . get_mut :: < SyncFromDiskMetadata > ( )
140
+ . unwrap ( )
141
+ . left_to_sync
142
+ . retain ( |p| p != & path) ;
143
+ log:: debug!( "Evaluating: {:?}" , path) ;
144
+ fuzzer. evaluate_input ( state, executor, manager, input) ?;
110
145
}
111
146
}
112
147
@@ -149,15 +184,13 @@ where
149
184
}
150
185
151
186
fn load_from_directory (
152
- & mut self ,
153
- in_dir : & Path ,
187
+ & self ,
154
188
last : & Option < SystemTime > ,
155
- fuzzer : & mut Z ,
156
- executor : & mut E ,
157
- state : & mut Z :: State ,
158
- manager : & mut EM ,
159
- ) -> Result < Option < SystemTime > , Error > {
189
+ ) -> Result < ( Option < SystemTime > , Vec < PathBuf > ) , Error > {
160
190
let mut max_time = None ;
191
+ let mut left_to_sync = Vec :: < PathBuf > :: new ( ) ;
192
+ let in_dir = self . sync_dir . clone ( ) ;
193
+
161
194
for entry in fs:: read_dir ( in_dir) ? {
162
195
let entry = entry?;
163
196
let path = entry. path ( ) ;
@@ -172,24 +205,24 @@ where
172
205
if attr. is_file ( ) && attr. len ( ) > 0 {
173
206
if let Ok ( time) = attr. modified ( ) {
174
207
if let Some ( l) = last {
175
- if time. duration_since ( * l) . is_err ( ) {
208
+ if time. duration_since ( * l) . is_err ( ) || time == * l {
176
209
continue ;
177
210
}
178
211
}
179
212
max_time = Some ( max_time. map_or ( time, |t : SystemTime | t. max ( time) ) ) ;
180
- let input = ( self . load_callback ) ( fuzzer , state , & path) ? ;
181
- fuzzer . evaluate_input ( state , executor , manager , input ) ? ;
213
+ log :: info! ( "Syncing file: {:?}" , path) ;
214
+ left_to_sync . push ( path . clone ( ) ) ;
182
215
}
183
216
} else if attr. is_dir ( ) {
184
- let dir_max_time =
185
- self . load_from_directory ( & path, last, fuzzer, executor, state, manager) ?;
217
+ let ( dir_max_time, dir_left_to_sync) = self . load_from_directory ( last) ?;
186
218
if let Some ( time) = dir_max_time {
187
219
max_time = Some ( max_time. map_or ( time, |t : SystemTime | t. max ( time) ) ) ;
188
220
}
221
+ left_to_sync. extend ( dir_left_to_sync) ;
189
222
}
190
223
}
191
224
192
- Ok ( max_time)
225
+ Ok ( ( max_time, left_to_sync ) )
193
226
}
194
227
}
195
228
0 commit comments