@@ -10,8 +10,8 @@ mod entry;
1010mod tokens;
1111
1212use std:: collections:: { HashMap , HashSet } ;
13+ use std:: io;
1314use std:: path:: { Path , PathBuf } ;
14- use std:: { io, mem} ;
1515
1616use crate :: common:: resolve:: resolve_path;
1717use crate :: defaults;
@@ -204,14 +204,18 @@ impl Sudoers {
204204 }
205205}
206206
207+ // a `take_while` variant that does not consume the first non-matching item
208+ fn peeking_take_while < ' a , T > (
209+ iter : & ' a mut std:: iter:: Peekable < impl Iterator < Item = T > > ,
210+ pred : impl Fn ( & T ) -> bool + ' a ,
211+ ) -> impl Iterator < Item = T > + ' a {
212+ std:: iter:: from_fn ( move || iter. next_if ( & pred) )
213+ }
214+
207215fn group_cmd_specs_per_runas < ' a > (
208216 cmnd_specs : impl Iterator < Item = ( Option < & ' a RunAs > , ( Tag , & ' a Spec < Command > ) ) > ,
209217 cmnd_aliases : & ' a [ Def < Command > ] ,
210218) -> impl Iterator < Item = Entry < ' a > > {
211- let mut entries = vec ! [ ] ;
212- let mut last_runas = None ;
213- let mut collected_specs = vec ! [ ] ;
214-
215219 // `distribute_tags` will have given every spec a reference to the "runas specification"
216220 // that applies to it. The output of sudo --list splits the CmndSpec list based on that:
217221 // every line only has a single "runas" specifier. So we need to combine them for that.
@@ -221,24 +225,19 @@ fn group_cmd_specs_per_runas<'a>(
221225 // once a RunAs is parsed, it will have a unique identifier in the form of its address.
222226 let origin = |runas : Option < & RunAs > | runas. map ( |r| r as * const _ ) ;
223227
224- for ( runas, ( tag, spec) ) in cmnd_specs {
225- if origin ( runas) != origin ( last_runas) {
226- if !collected_specs. is_empty ( ) {
227- entries. push ( Entry :: new (
228- last_runas,
229- mem:: take ( & mut collected_specs) ,
230- cmnd_aliases,
231- ) ) ;
232- }
233-
234- last_runas = runas;
235- }
228+ let mut cmnd_specs = cmnd_specs. peekable ( ) ;
229+ let mut entries = vec ! [ ] ;
236230
237- collected_specs. push ( ( tag, spec) ) ;
238- }
231+ while let Some ( & ( cur_runas, _) ) = cmnd_specs. peek ( ) {
232+ let specs = peeking_take_while ( & mut cmnd_specs, |& ( runas, _) | {
233+ origin ( runas) == origin ( cur_runas)
234+ } ) ;
239235
240- if !collected_specs. is_empty ( ) {
241- entries. push ( Entry :: new ( last_runas, collected_specs, cmnd_aliases) ) ;
236+ entries. push ( Entry :: new (
237+ cur_runas,
238+ specs. map ( |x| x. 1 ) . collect ( ) ,
239+ cmnd_aliases,
240+ ) ) ;
242241 }
243242
244243 entries. into_iter ( )
0 commit comments