11use crate :: util:: Platform ;
22use serde:: Deserialize ;
33use std:: collections:: HashMap ;
4+ use std:: fs;
5+ use std:: path:: Path ;
46use wmi:: * ;
57
68/// Driver configuration loaded from TOML
@@ -9,6 +11,8 @@ struct DriversConfig {
911 pnp_drivers : HashMap < String , String > ,
1012 products : HashMap < String , String > ,
1113 system_drivers : HashMap < String , String > ,
14+ #[ serde( default ) ]
15+ inf_drivers : HashMap < String , String > ,
1216}
1317
1418/// Platform-specific baseline configuration
@@ -47,6 +51,93 @@ fn load_baseline_for_platform(platform: &Platform) -> BaselineConfig {
4751 toml:: from_str ( config_str) . unwrap_or_default ( )
4852}
4953
54+ const DRIVER_STORE_PATH : & str = r"C:\Windows\System32\DriverStore\FileRepository" ;
55+
56+ /// Find driver INF file in the driver store and extract version
57+ fn find_inf_driver_version ( inf_name : & str ) -> Option < String > {
58+ let driver_store = Path :: new ( DRIVER_STORE_PATH ) ;
59+ if !driver_store. exists ( ) {
60+ return None ;
61+ }
62+
63+ // Look for directories matching the INF name pattern (e.g., amddrtm.inf_amd64_*)
64+ let pattern = format ! ( "{}.inf_" , inf_name) ;
65+ let mut best_match: Option < ( String , std:: time:: SystemTime ) > = None ;
66+
67+ if let Ok ( entries) = fs:: read_dir ( driver_store) {
68+ for entry in entries. flatten ( ) {
69+ if let Ok ( name) = entry. file_name ( ) . into_string ( ) {
70+ if name. starts_with ( & pattern) {
71+ // Only consider directories, not files like .ini
72+ if let Ok ( metadata) = entry. metadata ( ) {
73+ if !metadata. is_dir ( ) {
74+ continue ;
75+ }
76+ // Get the modification time to find the newest version
77+ if let Ok ( modified) = metadata. modified ( ) {
78+ let should_update = match & best_match {
79+ None => true ,
80+ Some ( ( _, prev_time) ) => modified > * prev_time,
81+ } ;
82+ if should_update {
83+ best_match =
84+ Some ( ( entry. path ( ) . to_string_lossy ( ) . to_string ( ) , modified) ) ;
85+ }
86+ }
87+ }
88+ }
89+ }
90+ }
91+ }
92+
93+ // If we found a matching directory, read the INF file and extract version
94+ if let Some ( ( dir_path, _) ) = best_match {
95+ let inf_file = Path :: new ( & dir_path) . join ( format ! ( "{}.inf" , inf_name) ) ;
96+ if inf_file. exists ( ) {
97+ return parse_inf_version ( & inf_file) ;
98+ }
99+ }
100+
101+ None
102+ }
103+
104+ /// Parse INF file and extract DriverVer version number
105+ fn parse_inf_version ( inf_path : & Path ) -> Option < String > {
106+ // Try reading as UTF-8 first, then as UTF-16 LE (common for Windows INF files)
107+ let content = match fs:: read_to_string ( inf_path) {
108+ Ok ( c) => c,
109+ Err ( _) => {
110+ // Try reading as UTF-16 LE
111+ let bytes = fs:: read ( inf_path) . ok ( ) ?;
112+ // Skip BOM if present and convert UTF-16 LE to String
113+ let start = if bytes. len ( ) >= 2 && bytes[ 0 ] == 0xFF && bytes[ 1 ] == 0xFE {
114+ 2
115+ } else {
116+ 0
117+ } ;
118+ let u16_chars: Vec < u16 > = bytes[ start..]
119+ . chunks_exact ( 2 )
120+ . map ( |chunk| u16:: from_le_bytes ( [ chunk[ 0 ] , chunk[ 1 ] ] ) )
121+ . collect ( ) ;
122+ String :: from_utf16 ( & u16_chars) . ok ( ) ?
123+ }
124+ } ;
125+
126+ // Look for DriverVer line, e.g.: DriverVer = 11/11/2024,1.0.18.4
127+ for line in content. lines ( ) {
128+ let trimmed = line. trim ( ) ;
129+ if trimmed. to_lowercase ( ) . starts_with ( "driverver" ) {
130+ // Extract version after the comma
131+ if let Some ( comma_pos) = trimmed. find ( ',' ) {
132+ let version = trimmed[ comma_pos + 1 ..] . trim ( ) ;
133+ return Some ( version. to_string ( ) ) ;
134+ }
135+ }
136+ }
137+
138+ None
139+ }
140+
50141/// Collected driver information for baseline updates
51142#[ derive( Debug , Default ) ]
52143pub struct DetectedDrivers {
@@ -257,6 +348,14 @@ pub fn print_drivers_with_baseline(platform: Option<&Platform>) {
257348 print_version_with_baseline ( & version, alias, & baseline) ;
258349 }
259350 }
351+
352+ // INF Drivers (boot-only drivers from driver store)
353+ for ( inf_name, alias) in & config. inf_drivers {
354+ if let Some ( version) = find_inf_driver_version ( inf_name) {
355+ println ! ( " {}" , alias) ;
356+ print_version_with_baseline ( & version, alias, & baseline) ;
357+ }
358+ }
260359}
261360
262361/// Print version with baseline comparison
@@ -362,5 +461,12 @@ pub fn collect_drivers() -> DetectedDrivers {
362461 }
363462 }
364463
464+ // INF Drivers (boot-only drivers from driver store)
465+ for ( inf_name, alias) in & config. inf_drivers {
466+ if let Some ( version) = find_inf_driver_version ( inf_name) {
467+ detected. drivers . insert ( alias. clone ( ) , version) ;
468+ }
469+ }
470+
365471 detected
366472}
0 commit comments