diff --git a/src/c#/DrivelutionTest/GeneralDrivelutionTests.cs b/src/c#/DrivelutionTest/GeneralDrivelutionTests.cs index cd22a06d..87973a42 100644 --- a/src/c#/DrivelutionTest/GeneralDrivelutionTests.cs +++ b/src/c#/DrivelutionTest/GeneralDrivelutionTests.cs @@ -327,4 +327,185 @@ public void GetPlatformInfo_ReportsCorrectSupportStatus() Assert.False(platformInfo.IsSupported); // MacOS not yet implemented } } + + /// + /// Tests that GetDriversFromDirectoryAsync returns empty list for non-existent directory. + /// + [Fact] + public async Task GetDriversFromDirectoryAsync_WithNonExistentDirectory_ReturnsEmptyList() + { + // Arrange + var nonExistentPath = Path.Combine(Path.GetTempPath(), $"nonexistent_{Guid.NewGuid()}"); + + // Act + var result = await GeneralDrivelution.GetDriversFromDirectoryAsync(nonExistentPath); + + // Assert + Assert.NotNull(result); + Assert.Empty(result); + } + + /// + /// Tests that GetDriversFromDirectoryAsync returns empty list for empty directory. + /// + [Fact] + public async Task GetDriversFromDirectoryAsync_WithEmptyDirectory_ReturnsEmptyList() + { + // Arrange + var emptyDir = Path.Combine(Path.GetTempPath(), $"empty_{Guid.NewGuid()}"); + Directory.CreateDirectory(emptyDir); + + try + { + // Act + var result = await GeneralDrivelution.GetDriversFromDirectoryAsync(emptyDir); + + // Assert + Assert.NotNull(result); + Assert.Empty(result); + } + finally + { + if (Directory.Exists(emptyDir)) + { + Directory.Delete(emptyDir, true); + } + } + } + + /// + /// Tests that GetDriversFromDirectoryAsync discovers driver files in directory. + /// + [Fact] + public async Task GetDriversFromDirectoryAsync_WithDriverFiles_ReturnsDriverInfoList() + { + // Arrange + var testDir = Path.Combine(Path.GetTempPath(), $"drivers_{Guid.NewGuid()}"); + Directory.CreateDirectory(testDir); + + try + { + // Create test driver files based on platform + var platformInfo = GeneralDrivelution.GetPlatformInfo(); + var testFiles = new List(); + + if (platformInfo.Platform == "Windows") + { + // Create mock .inf file + var infFile = Path.Combine(testDir, "test_driver.inf"); + File.WriteAllText(infFile, @" +[Version] +Signature=""$Windows NT$"" +DriverVer=01/15/2024,1.0.0.0 + +[DriverInfo] +DriverDesc=""Test Driver"" +"); + testFiles.Add(infFile); + } + else if (platformInfo.Platform == "Linux") + { + // Create mock .ko file + var koFile = Path.Combine(testDir, "test_driver.ko"); + File.WriteAllText(koFile, "Mock kernel module content"); + testFiles.Add(koFile); + } + + // Act + var result = await GeneralDrivelution.GetDriversFromDirectoryAsync(testDir); + + // Assert + Assert.NotNull(result); + + // Should find at least one driver if platform is supported + if (platformInfo.IsSupported && testFiles.Any()) + { + Assert.NotEmpty(result); + + // Check that driver info has expected properties + var driver = result.First(); + Assert.NotNull(driver.Name); + Assert.NotEmpty(driver.Name); + Assert.NotNull(driver.FilePath); + Assert.NotEmpty(driver.FilePath); + Assert.NotNull(driver.Version); + Assert.NotEmpty(driver.Version); + Assert.NotNull(driver.Hash); + Assert.NotEmpty(driver.Hash); + } + } + finally + { + if (Directory.Exists(testDir)) + { + Directory.Delete(testDir, true); + } + } + } + + /// + /// Tests that GetDriversFromDirectoryAsync with search pattern filters correctly. + /// + [Fact] + public async Task GetDriversFromDirectoryAsync_WithSearchPattern_FiltersCorrectly() + { + // Arrange + var testDir = Path.Combine(Path.GetTempPath(), $"drivers_{Guid.NewGuid()}"); + Directory.CreateDirectory(testDir); + + try + { + // Create different types of files + var infFile = Path.Combine(testDir, "driver1.inf"); + var txtFile = Path.Combine(testDir, "readme.txt"); + File.WriteAllText(infFile, "INF content"); + File.WriteAllText(txtFile, "Text content"); + + // Act + var result = await GeneralDrivelution.GetDriversFromDirectoryAsync(testDir, "*.inf"); + + // Assert + Assert.NotNull(result); + + // Should only find .inf files + // The count depends on whether the platform supports parsing .inf files + } + finally + { + if (Directory.Exists(testDir)) + { + Directory.Delete(testDir, true); + } + } + } + + /// + /// Tests that GetDriversFromDirectoryAsync handles cancellation. + /// + [Fact] + public async Task GetDriversFromDirectoryAsync_WithCancellation_HandlesCancellation() + { + // Arrange + var testDir = Path.Combine(Path.GetTempPath(), $"drivers_{Guid.NewGuid()}"); + Directory.CreateDirectory(testDir); + + try + { + var cts = new CancellationTokenSource(); + cts.Cancel(); + + // Act + var result = await GeneralDrivelution.GetDriversFromDirectoryAsync(testDir, null, cts.Token); + + // Assert - Should complete without throwing or return empty list + Assert.NotNull(result); + } + finally + { + if (Directory.Exists(testDir)) + { + Directory.Delete(testDir, true); + } + } + } } diff --git a/src/c#/GeneralUpdate.Drivelution/Abstractions/IGeneralDrivelution.cs b/src/c#/GeneralUpdate.Drivelution/Abstractions/IGeneralDrivelution.cs index e43aa145..093e0360 100644 --- a/src/c#/GeneralUpdate.Drivelution/Abstractions/IGeneralDrivelution.cs +++ b/src/c#/GeneralUpdate.Drivelution/Abstractions/IGeneralDrivelution.cs @@ -4,19 +4,17 @@ namespace GeneralUpdate.Drivelution.Abstractions; /// -/// 驱动更新器核心接口 /// Core interface for driver updater /// public interface IGeneralDrivelution { /// - /// 异步更新驱动 /// Updates driver asynchronously /// - /// 驱动信息 / Driver information - /// 更新策略 / Update strategy - /// 取消令牌 / Cancellation token - /// 更新结果 / Update result + /// Driver information + /// Update strategy + /// Cancellation token + /// Update result /// /// Note: Update process may include signature validation that requires reflection on some platforms. /// @@ -25,12 +23,11 @@ public interface IGeneralDrivelution Task UpdateAsync(DriverInfo driverInfo, UpdateStrategy strategy, CancellationToken cancellationToken = default); /// - /// 异步验证驱动 /// Validates driver asynchronously /// - /// 驱动信息 / Driver information - /// 取消令牌 / Cancellation token - /// 验证是否通过 / Validation result + /// Driver information + /// Cancellation token + /// Validation result /// /// Note: Includes signature validation that may require reflection on some platforms. /// @@ -39,21 +36,28 @@ public interface IGeneralDrivelution Task ValidateAsync(DriverInfo driverInfo, CancellationToken cancellationToken = default); /// - /// 异步备份驱动 /// Backs up driver asynchronously /// - /// 驱动信息 / Driver information - /// 备份路径 / Backup path - /// 取消令牌 / Cancellation token - /// 备份结果 / Backup result + /// Driver information + /// Backup path + /// Cancellation token + /// Backup result Task BackupAsync(DriverInfo driverInfo, string backupPath, CancellationToken cancellationToken = default); /// - /// 异步回滚驱动 /// Rolls back driver asynchronously /// - /// 备份路径 / Backup path - /// 取消令牌 / Cancellation token - /// 回滚结果 / Rollback result + /// Backup path + /// Cancellation token + /// Rollback result Task RollbackAsync(string backupPath, CancellationToken cancellationToken = default); + + /// + /// Reads driver information from local directory + /// + /// Directory path + /// Search pattern (optional, e.g., "*.inf", "*.ko") + /// Cancellation token + /// List of driver information + Task> GetDriversFromDirectoryAsync(string directoryPath, string? searchPattern = null, CancellationToken cancellationToken = default); } diff --git a/src/c#/GeneralUpdate.Drivelution/GeneralDrivelution.cs b/src/c#/GeneralUpdate.Drivelution/GeneralDrivelution.cs index fd2dd2df..bcdb417b 100644 --- a/src/c#/GeneralUpdate.Drivelution/GeneralDrivelution.cs +++ b/src/c#/GeneralUpdate.Drivelution/GeneralDrivelution.cs @@ -8,18 +8,15 @@ namespace GeneralUpdate.Drivelution; /// -/// 驱动更新器统一入口类 - 提供优雅的API,自动适配平台 /// Unified driver updater entry point - Provides elegant API with automatic platform adaptation /// /// -/// 使用示例 / Usage example: +/// Usage example: /// -/// // 简单使用 - 自动检测平台 /// // Simple usage - automatic platform detection /// var updater = GeneralDrivelution.Create(); /// var result = await updater.UpdateAsync(driverInfo, strategy); /// -/// // 带配置使用 /// // With configuration /// var options = new DrivelutionOptions { LogLevel = "Info" }; /// var updater = GeneralDrivelution.Create(options); @@ -29,12 +26,11 @@ namespace GeneralUpdate.Drivelution; public static class GeneralDrivelution { /// - /// 创建驱动更新器实例(自动检测当前平台) /// Creates a driver updater instance (automatically detects current platform) /// - /// 配置选项(可选)/ Configuration options (optional) - /// 适配当前平台的驱动更新器 / Platform-adapted driver updater - /// 当前平台不支持时抛出 / Thrown when platform is not supported + /// Configuration options (optional) + /// Platform-adapted driver updater + /// Thrown when platform is not supported public static IGeneralDrivelution Create(DrivelutionOptions? options = null) { var logger = options != null @@ -45,24 +41,22 @@ public static IGeneralDrivelution Create(DrivelutionOptions? options = null) } /// - /// 创建驱动更新器实例(使用自定义日志记录器) /// Creates a driver updater instance (with custom logger) /// - /// 自定义日志记录器 / Custom logger - /// 配置选项(可选)/ Configuration options (optional) - /// 适配当前平台的驱动更新器 / Platform-adapted driver updater + /// Custom logger + /// Configuration options (optional) + /// Platform-adapted driver updater public static IGeneralDrivelution Create(ILogger logger, DrivelutionOptions? options = null) { return Core.DrivelutionFactory.Create(logger, options); } /// - /// 快速更新驱动(使用默认配置) /// Quick driver update (with default configuration) /// - /// 驱动信息 / Driver information - /// 取消令牌 / Cancellation token - /// 更新结果 / Update result + /// Driver information + /// Cancellation token + /// Update result public static async Task QuickUpdateAsync( DriverInfo driverInfo, CancellationToken cancellationToken = default) @@ -79,13 +73,12 @@ public static async Task QuickUpdateAsync( } /// - /// 快速更新驱动(带自定义策略) /// Quick driver update (with custom strategy) /// - /// 驱动信息 / Driver information - /// 更新策略 / Update strategy - /// 取消令牌 / Cancellation token - /// 更新结果 / Update result + /// Driver information + /// Update strategy + /// Cancellation token + /// Update result public static async Task QuickUpdateAsync( DriverInfo driverInfo, UpdateStrategy strategy, @@ -96,12 +89,11 @@ public static async Task QuickUpdateAsync( } /// - /// 验证驱动文件(自动选择平台验证器) /// Validates driver file (automatically selects platform validator) /// - /// 驱动信息 / Driver information - /// 取消令牌 / Cancellation token - /// 是否验证通过 / Whether validation passed + /// Driver information + /// Cancellation token + /// Whether validation passed public static async Task ValidateAsync( DriverInfo driverInfo, CancellationToken cancellationToken = default) @@ -111,10 +103,9 @@ public static async Task ValidateAsync( } /// - /// 获取当前平台信息 /// Gets current platform information /// - /// 平台信息 / Platform information + /// Platform information public static PlatformInfo GetPlatformInfo() { return new PlatformInfo @@ -126,31 +117,45 @@ public static PlatformInfo GetPlatformInfo() SystemVersion = CompatibilityChecker.GetSystemVersion() }; } + + /// + /// Reads driver information from local directory + /// + /// Directory path + /// Search pattern (optional, e.g., "*.inf", "*.ko") + /// Cancellation token + /// List of driver information + public static async Task> GetDriversFromDirectoryAsync( + string directoryPath, + string? searchPattern = null, + CancellationToken cancellationToken = default) + { + var updater = Create(); + return await updater.GetDriversFromDirectoryAsync(directoryPath, searchPattern, cancellationToken); + } } /// -/// 平台信息 /// Platform information /// public class PlatformInfo { - /// 平台名称 / Platform name + /// Platform name public string Platform { get; set; } = string.Empty; - /// 是否支持 / Is supported + /// Is supported public bool IsSupported { get; set; } - /// 操作系统 / Operating system + /// Operating system public string OperatingSystem { get; set; } = string.Empty; - /// 系统架构 / Architecture + /// Architecture public string Architecture { get; set; } = string.Empty; - /// 系统版本 / System version + /// System version public string SystemVersion { get; set; } = string.Empty; /// - /// 返回平台信息的字符串表示 /// Returns string representation of platform information /// public override string ToString() diff --git a/src/c#/GeneralUpdate.Drivelution/Linux/Implementation/LinuxGeneralDrivelution.cs b/src/c#/GeneralUpdate.Drivelution/Linux/Implementation/LinuxGeneralDrivelution.cs index 710df524..fa6f5058 100644 --- a/src/c#/GeneralUpdate.Drivelution/Linux/Implementation/LinuxGeneralDrivelution.cs +++ b/src/c#/GeneralUpdate.Drivelution/Linux/Implementation/LinuxGeneralDrivelution.cs @@ -359,4 +359,243 @@ private string GenerateBackupPath(DriverInfo driverInfo, string baseBackupPath) var fileName = Path.GetFileName(driverInfo.FilePath); return Path.Combine(baseBackupPath, fileName); } + + /// + public async Task> GetDriversFromDirectoryAsync( + string directoryPath, + string? searchPattern = null, + CancellationToken cancellationToken = default) + { + var driverInfoList = new List(); + + try + { + _logger.Information("Reading driver information from directory: {DirectoryPath}", directoryPath); + + if (!Directory.Exists(directoryPath)) + { + _logger.Warning("Directory not found: {DirectoryPath}", directoryPath); + return driverInfoList; + } + + // Default to kernel modules for Linux + var pattern = searchPattern ?? "*.ko"; + var driverFiles = Directory.GetFiles(directoryPath, pattern, SearchOption.AllDirectories); + + // Also look for .deb and .rpm packages if no specific pattern was provided + if (searchPattern == null) + { + var debFiles = Directory.GetFiles(directoryPath, "*.deb", SearchOption.AllDirectories); + var rpmFiles = Directory.GetFiles(directoryPath, "*.rpm", SearchOption.AllDirectories); + driverFiles = driverFiles.Concat(debFiles).Concat(rpmFiles).ToArray(); + } + + _logger.Information("Found {Count} driver files matching pattern: {Pattern}", driverFiles.Length, pattern); + + foreach (var filePath in driverFiles) + { + if (cancellationToken.IsCancellationRequested) + break; + + try + { + var driverInfo = await ParseDriverFileAsync(filePath, cancellationToken); + if (driverInfo != null) + { + driverInfoList.Add(driverInfo); + _logger.Information("Parsed driver: {DriverName} v{Version}", driverInfo.Name, driverInfo.Version); + } + } + catch (Exception ex) + { + _logger.Warning(ex, "Failed to parse driver file: {FilePath}", filePath); + } + } + + _logger.Information("Successfully loaded {Count} driver(s) from directory", driverInfoList.Count); + } + catch (Exception ex) + { + _logger.Error(ex, "Error reading drivers from directory: {DirectoryPath}", directoryPath); + } + + return driverInfoList; + } + + /// + /// Parses driver file information + /// + private async Task ParseDriverFileAsync(string filePath, CancellationToken cancellationToken) + { + try + { + var fileInfo = new FileInfo(filePath); + var fileName = Path.GetFileNameWithoutExtension(filePath); + var extension = Path.GetExtension(filePath).ToLowerInvariant(); + + var driverInfo = new DriverInfo + { + Name = fileName, + FilePath = filePath, + TargetOS = "Linux", + Architecture = Environment.Is64BitOperatingSystem ? "x64" : "x86" + }; + + // Parse based on file type + if (extension == ".ko") + { + await ParseKernelModuleAsync(filePath, driverInfo, cancellationToken); + } + else if (extension == ".deb") + { + await ParseDebPackageAsync(filePath, driverInfo, cancellationToken); + } + else if (extension == ".rpm") + { + await ParseRpmPackageAsync(filePath, driverInfo, cancellationToken); + } + + // Get file hash for integrity validation + driverInfo.Hash = await HashValidator.ComputeHashAsync(filePath, "SHA256", cancellationToken); + driverInfo.HashAlgorithm = "SHA256"; + + return driverInfo; + } + catch (Exception ex) + { + _logger.Warning(ex, "Failed to parse driver file: {FilePath}", filePath); + return null; + } + } + + /// + /// Parses kernel module + /// + private async Task ParseKernelModuleAsync(string koPath, DriverInfo driverInfo, CancellationToken cancellationToken) + { + try + { + // Try to get module info using modinfo command + var output = await ExecuteCommandAsync("modinfo", koPath, cancellationToken); + var lines = output.Split('\n'); + + foreach (var line in lines) + { + var trimmedLine = line.Trim(); + + if (trimmedLine.StartsWith("version:", StringComparison.OrdinalIgnoreCase)) + { + driverInfo.Version = trimmedLine.Substring(8).Trim(); + } + else if (trimmedLine.StartsWith("description:", StringComparison.OrdinalIgnoreCase)) + { + driverInfo.Description = trimmedLine.Substring(12).Trim(); + } + else if (trimmedLine.StartsWith("alias:", StringComparison.OrdinalIgnoreCase)) + { + var alias = trimmedLine.Substring(6).Trim(); + if (string.IsNullOrEmpty(driverInfo.HardwareId)) + { + driverInfo.HardwareId = alias; + } + } + } + + if (string.IsNullOrEmpty(driverInfo.Version)) + { + driverInfo.Version = "1.0.0"; + } + } + catch (Exception ex) + { + _logger.Debug(ex, "Could not get module info for: {KoPath}", koPath); + driverInfo.Version = "1.0.0"; + } + } + + /// + /// Parses Debian package + /// + private async Task ParseDebPackageAsync(string debPath, DriverInfo driverInfo, CancellationToken cancellationToken) + { + try + { + // Try to get package info using dpkg-deb command + // Use proper argument passing to avoid injection issues + var escapedPath = debPath.Replace("'", "'\\''"); + var output = await ExecuteCommandAsync("dpkg-deb", $"-I '{escapedPath}'", cancellationToken); + var lines = output.Split('\n'); + + foreach (var line in lines) + { + var trimmedLine = line.Trim(); + + if (trimmedLine.StartsWith("Version:", StringComparison.OrdinalIgnoreCase)) + { + driverInfo.Version = trimmedLine.Substring(8).Trim(); + } + else if (trimmedLine.StartsWith("Description:", StringComparison.OrdinalIgnoreCase)) + { + driverInfo.Description = trimmedLine.Substring(12).Trim(); + } + } + + if (string.IsNullOrEmpty(driverInfo.Version)) + { + driverInfo.Version = "1.0.0"; + } + } + catch (Exception ex) + { + _logger.Debug(ex, "Could not get package info for: {DebPath}", debPath); + driverInfo.Version = "1.0.0"; + } + } + + /// + /// Parses RPM package + /// + private async Task ParseRpmPackageAsync(string rpmPath, DriverInfo driverInfo, CancellationToken cancellationToken) + { + try + { + // Try to get package info using rpm command + // Use proper argument passing to avoid injection issues + var escapedPath = rpmPath.Replace("'", "'\\''"); + var output = await ExecuteCommandAsync("rpm", $"-qip '{escapedPath}'", cancellationToken); + var lines = output.Split('\n'); + + foreach (var line in lines) + { + var trimmedLine = line.Trim(); + + if (trimmedLine.StartsWith("Version", StringComparison.OrdinalIgnoreCase)) + { + var parts = trimmedLine.Split(':'); + if (parts.Length > 1) + { + driverInfo.Version = parts[1].Trim(); + } + } + else if (trimmedLine.StartsWith("Summary", StringComparison.OrdinalIgnoreCase)) + { + var parts = trimmedLine.Split(':'); + if (parts.Length > 1) + { + driverInfo.Description = parts[1].Trim(); + } + } + } + + if (string.IsNullOrEmpty(driverInfo.Version)) + { + driverInfo.Version = "1.0.0"; + } + } + catch (Exception ex) + { + _logger.Debug(ex, "Could not get package info for: {RpmPath}", rpmPath); + driverInfo.Version = "1.0.0"; + } + } } diff --git a/src/c#/GeneralUpdate.Drivelution/MacOS/Implementation/MacOsGeneralDrivelution.cs b/src/c#/GeneralUpdate.Drivelution/MacOS/Implementation/MacOsGeneralDrivelution.cs index bf581403..2cfd84a6 100644 --- a/src/c#/GeneralUpdate.Drivelution/MacOS/Implementation/MacOsGeneralDrivelution.cs +++ b/src/c#/GeneralUpdate.Drivelution/MacOS/Implementation/MacOsGeneralDrivelution.cs @@ -65,6 +65,16 @@ public Task RollbackAsync( throw new PlatformNotSupportedException( "MacOS driver rollback is not yet implemented."); } + + /// + public Task> GetDriversFromDirectoryAsync( + string directoryPath, + string? searchPattern = null, + CancellationToken cancellationToken = default) + { + throw new PlatformNotSupportedException( + "MacOS driver directory reading is not yet implemented."); + } } /// diff --git a/src/c#/GeneralUpdate.Drivelution/Windows/Implementation/WindowsGeneralDrivelution.cs b/src/c#/GeneralUpdate.Drivelution/Windows/Implementation/WindowsGeneralDrivelution.cs index 0e8ff2be..df7ba8fe 100644 --- a/src/c#/GeneralUpdate.Drivelution/Windows/Implementation/WindowsGeneralDrivelution.cs +++ b/src/c#/GeneralUpdate.Drivelution/Windows/Implementation/WindowsGeneralDrivelution.cs @@ -457,4 +457,198 @@ private string GetSuggestedResolution(ErrorType type) _ => "Contact support for assistance" }; } + + /// + public async Task> GetDriversFromDirectoryAsync( + string directoryPath, + string? searchPattern = null, + CancellationToken cancellationToken = default) + { + var driverInfoList = new List(); + + try + { + _logger.Information("Reading driver information from directory: {DirectoryPath}", directoryPath); + + if (!Directory.Exists(directoryPath)) + { + _logger.Warning("Directory not found: {DirectoryPath}", directoryPath); + return driverInfoList; + } + + // Default to .inf files for Windows + var pattern = searchPattern ?? "*.inf"; + var driverFiles = Directory.GetFiles(directoryPath, pattern, SearchOption.AllDirectories); + + _logger.Information("Found {Count} driver files matching pattern: {Pattern}", driverFiles.Length, pattern); + + foreach (var filePath in driverFiles) + { + if (cancellationToken.IsCancellationRequested) + break; + + try + { + var driverInfo = await ParseDriverFileAsync(filePath, cancellationToken); + if (driverInfo != null) + { + driverInfoList.Add(driverInfo); + _logger.Information("Parsed driver: {DriverName} v{Version}", driverInfo.Name, driverInfo.Version); + } + } + catch (Exception ex) + { + _logger.Warning(ex, "Failed to parse driver file: {FilePath}", filePath); + } + } + + _logger.Information("Successfully loaded {Count} driver(s) from directory", driverInfoList.Count); + } + catch (Exception ex) + { + _logger.Error(ex, "Error reading drivers from directory: {DirectoryPath}", directoryPath); + } + + return driverInfoList; + } + + /// + /// Parses driver file information + /// + private async Task ParseDriverFileAsync(string filePath, CancellationToken cancellationToken) + { + try + { + var fileInfo = new FileInfo(filePath); + var fileName = Path.GetFileNameWithoutExtension(filePath); + + var driverInfo = new DriverInfo + { + Name = fileName, + FilePath = filePath, + TargetOS = "Windows", + Architecture = Environment.Is64BitOperatingSystem ? "x64" : "x86" + }; + + // For .inf files, try to parse version and other metadata + if (filePath.EndsWith(".inf", StringComparison.OrdinalIgnoreCase)) + { + await ParseInfFileAsync(filePath, driverInfo, cancellationToken); + } + + // Get file hash for integrity validation + driverInfo.Hash = await HashValidator.ComputeHashAsync(filePath, "SHA256", cancellationToken); + driverInfo.HashAlgorithm = "SHA256"; + + // Get signature information if available + try + { + if (WindowsSignatureHelper.IsFileSigned(filePath)) + { + // Try to extract publisher from certificate + using var cert2 = new System.Security.Cryptography.X509Certificates.X509Certificate2(filePath); + var subject = cert2.Subject; + + // Extract CN (Common Name) from subject + var cnIndex = subject.IndexOf("CN="); + if (cnIndex >= 0) + { + var cnStart = cnIndex + 3; + var cnEnd = subject.IndexOf(',', cnStart); + + string publisher; + if (cnEnd > cnStart) + { + publisher = subject.Substring(cnStart, cnEnd - cnStart); + } + else + { + // No comma after CN, take the rest of the string + publisher = subject.Substring(cnStart); + } + + if (!string.IsNullOrEmpty(publisher)) + { + driverInfo.TrustedPublishers.Add(publisher); + } + } + } + } + catch (Exception ex) + { + _logger.Debug(ex, "Could not get signature for file: {FilePath}", filePath); + } + + return driverInfo; + } + catch (Exception ex) + { + _logger.Warning(ex, "Failed to parse driver file: {FilePath}", filePath); + return null; + } + } + + /// + /// Parses INF file + /// + private async Task ParseInfFileAsync(string infPath, DriverInfo driverInfo, CancellationToken cancellationToken) + { + try + { + var content = await File.ReadAllTextAsync(infPath, cancellationToken); + var lines = content.Split('\n'); + + foreach (var line in lines) + { + var trimmedLine = line.Trim(); + + // Parse version + if (trimmedLine.StartsWith("DriverVer", StringComparison.OrdinalIgnoreCase)) + { + var parts = trimmedLine.Split('='); + if (parts.Length > 1) + { + var verParts = parts[1].Split(','); + if (verParts.Length > 1) + { + driverInfo.Version = verParts[1].Trim(); + } + if (verParts.Length > 0 && DateTime.TryParse(verParts[0].Trim(), out var releaseDate)) + { + driverInfo.ReleaseDate = releaseDate; + } + } + } + // Parse description + else if (trimmedLine.StartsWith("DriverDesc", StringComparison.OrdinalIgnoreCase)) + { + var parts = trimmedLine.Split('='); + if (parts.Length > 1) + { + driverInfo.Description = parts[1].Trim().Trim('"', '%'); + } + } + // Parse hardware ID + else if (trimmedLine.StartsWith("HardwareId", StringComparison.OrdinalIgnoreCase) || + trimmedLine.Contains("HW_ID", StringComparison.OrdinalIgnoreCase)) + { + var parts = trimmedLine.Split('='); + if (parts.Length > 1) + { + driverInfo.HardwareId = parts[1].Trim().Trim('"'); + } + } + } + + // If version is still empty, try to infer from filename or use default + if (string.IsNullOrEmpty(driverInfo.Version)) + { + driverInfo.Version = "1.0.0"; + } + } + catch (Exception ex) + { + _logger.Debug(ex, "Could not parse INF file: {InfPath}", infPath); + } + } }