Restructure solution layout by module
This commit is contained in:
@@ -0,0 +1,122 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Threading;
|
||||
using Microsoft.Data.Sqlite;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using StellaOps.Scanner.Analyzers.OS.Rpm.Internal;
|
||||
|
||||
namespace StellaOps.Scanner.Analyzers.OS.Rpm;
|
||||
|
||||
internal sealed class RpmDatabaseReader : IRpmDatabaseReader
|
||||
{
|
||||
private readonly ILogger _logger;
|
||||
private readonly RpmHeaderParser _parser = new();
|
||||
|
||||
public RpmDatabaseReader(ILogger logger)
|
||||
{
|
||||
_logger = logger;
|
||||
}
|
||||
|
||||
public IReadOnlyList<RpmHeader> ReadHeaders(string rootPath, CancellationToken cancellationToken)
|
||||
{
|
||||
var sqlitePath = ResolveSqlitePath(rootPath);
|
||||
if (sqlitePath is null)
|
||||
{
|
||||
_logger.LogWarning("rpmdb.sqlite not found under root {RootPath}; rpm analyzer will skip.", rootPath);
|
||||
return Array.Empty<RpmHeader>();
|
||||
}
|
||||
|
||||
var headers = new List<RpmHeader>();
|
||||
try
|
||||
{
|
||||
var connectionString = new SqliteConnectionStringBuilder
|
||||
{
|
||||
DataSource = sqlitePath,
|
||||
Mode = SqliteOpenMode.ReadOnly,
|
||||
}.ToString();
|
||||
|
||||
using var connection = new SqliteConnection(connectionString);
|
||||
connection.Open();
|
||||
|
||||
using var command = connection.CreateCommand();
|
||||
command.CommandText = "SELECT * FROM Packages";
|
||||
|
||||
using var reader = command.ExecuteReader();
|
||||
while (reader.Read())
|
||||
{
|
||||
cancellationToken.ThrowIfCancellationRequested();
|
||||
var blob = ExtractHeaderBlob(reader);
|
||||
if (blob is null)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
headers.Add(_parser.Parse(blob));
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
_logger.LogWarning(ex, "Failed to parse RPM header record (pkgKey={PkgKey}).", TryGetPkgKey(reader));
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
_logger.LogWarning(ex, "Unable to read rpmdb.sqlite at {Path}.", sqlitePath);
|
||||
return Array.Empty<RpmHeader>();
|
||||
}
|
||||
|
||||
return headers;
|
||||
}
|
||||
|
||||
private static string? ResolveSqlitePath(string rootPath)
|
||||
{
|
||||
var candidates = new[]
|
||||
{
|
||||
Path.Combine(rootPath, "var", "lib", "rpm", "rpmdb.sqlite"),
|
||||
Path.Combine(rootPath, "usr", "lib", "sysimage", "rpm", "rpmdb.sqlite"),
|
||||
};
|
||||
|
||||
foreach (var candidate in candidates)
|
||||
{
|
||||
if (File.Exists(candidate))
|
||||
{
|
||||
return candidate;
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
private static byte[]? ExtractHeaderBlob(SqliteDataReader reader)
|
||||
{
|
||||
for (var i = 0; i < reader.FieldCount; i++)
|
||||
{
|
||||
if (reader.GetFieldType(i) == typeof(byte[]))
|
||||
{
|
||||
return reader.GetFieldValue<byte[]>(i);
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
private static object? TryGetPkgKey(SqliteDataReader reader)
|
||||
{
|
||||
try
|
||||
{
|
||||
var ordinal = reader.GetOrdinal("pkgKey");
|
||||
if (ordinal >= 0)
|
||||
{
|
||||
return reader.GetValue(ordinal);
|
||||
}
|
||||
}
|
||||
catch
|
||||
{
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user