Function bodies 35 total
run function · rust · L100-L144 (45 LOC)src/cli/mod.rs
pub async fn run() -> Result<(), Box<dyn std::error::Error>> {
let cli = Cli::parse();
let mode = if cli.json {
OutputMode::Json
} else {
OutputMode::Human
};
match cli.command {
Commands::List => cmd_list(mode).await,
Commands::Info { drive } => cmd_info(mode, &drive).await,
Commands::Test {
mount,
capacity,
speed,
badblock,
thermal,
all,
no_save,
export_html,
test_size_mb,
} => {
cmd_test(
mode,
&cli.db,
&mount,
capacity || all,
speed || all,
badblock || all,
if all { Some(120) } else { thermal },
no_save,
export_html.as_deref(),
test_size_mb,
)
.await
}
Commands::Report { action } => match action {
cmd_list function · rust · L145-L180 (36 LOC)src/cli/mod.rs
async fn cmd_list(mode: OutputMode) -> Result<(), Box<dyn std::error::Error>> {
let drives = tokio::task::spawn_blocking(detect::list_usb_drives)
.await?
.map_err(|e| e)?;
match mode {
OutputMode::Json => {
print_success(mode, &drives);
}
OutputMode::Human => {
if drives.is_empty() {
println!("No USB drives found.");
return Ok(());
}
let mut table = Table::new();
table.load_preset(UTF8_FULL);
table.set_header(vec![
"Name", "Path", "Mount", "Capacity", "Free", "FS", "Serial",
]);
for d in &drives {
table.add_row(vec![
&d.name,
&d.path,
&d.mount_point,
&info::format_capacity(d.capacity_bytes),
&info::format_capacity(d.free_bytes),
&d.file_system,
cmd_info function · rust · L181-L212 (32 LOC)src/cli/mod.rs
async fn cmd_info(mode: OutputMode, drive: &str) -> Result<(), Box<dyn std::error::Error>> {
let drive_str = drive.to_string();
let drives = tokio::task::spawn_blocking(detect::list_usb_drives)
.await?
.map_err(|e| e)?;
let found = drives
.into_iter()
.find(|d| d.path == drive_str || d.mount_point == drive_str)
.ok_or_else(|| format!("Drive not found: {}", drive_str))?;
match mode {
OutputMode::Json => {
print_success(mode, &found);
}
OutputMode::Human => {
println!("{}", info::drive_summary(&found));
println!(" Path: {}", found.path);
println!(" Mount: {}", found.mount_point);
println!(
" Capacity: {}",
info::format_capacity(found.capacity_bytes)
);
println!(" Free: {}", info::format_capacity(found.free_bytes));
println!(" FS: {}", found.file_syscmd_test function · rust · L215-L532 (318 LOC)src/cli/mod.rs
async fn cmd_test(
mode: OutputMode,
db_path: &str,
mount: &str,
test_capacity: bool,
test_speed: bool,
test_badblock: bool,
test_thermal: Option<u64>,
no_save: bool,
export_html: Option<&str>,
test_size_mb: u64,
) -> Result<(), Box<dyn std::error::Error>> {
if !test_capacity && !test_speed && !test_badblock && test_thermal.is_none() {
let msg = "No test selected. Use --capacity, --speed, --badblock, --thermal SECS, or --all";
print_error(mode, msg);
return Err(msg.into());
}
STOP_FLAG.store(false, Ordering::Relaxed);
let start_time = std::time::Instant::now();
// Get drive info
let mount_str = mount.to_string();
let drives = tokio::task::spawn_blocking(detect::list_usb_drives)
.await?
.map_err(|e| e)?;
let drive_info = drives
.into_iter()
.find(|d| d.path == mount_str || d.mount_point == mount_str)
.ok_or_else(|| format!("Drive not found at mount cmd_report_list function · rust · L533-L562 (30 LOC)src/cli/mod.rs
fn cmd_report_list(mode: OutputMode, db_path: &str) -> Result<(), Box<dyn std::error::Error>> {
let db = Database::open(db_path)?;
let reports = db.list_reports()?;
match mode {
OutputMode::Json => {
print_success(mode, &reports);
}
OutputMode::Human => {
if reports.is_empty() {
println!("No reports found.");
return Ok(());
}
let mut table = Table::new();
table.load_preset(UTF8_FULL);
table.set_header(vec!["ID", "Drive", "Date", "Score"]);
for r in &reports {
table.add_row(vec![
&r.id[..8],
&r.drive_name,
&r.test_date,
&r.total_score.to_string(),
]);
}
println!("{table}");
}
}
Ok(())
}cmd_report_show function · rust · L563-L620 (58 LOC)src/cli/mod.rs
fn cmd_report_show(
mode: OutputMode,
db_path: &str,
id: &str,
) -> Result<(), Box<dyn std::error::Error>> {
let db = Database::open(db_path)?;
let report = db.get_report(id)?;
match mode {
OutputMode::Json => {
print_success(mode, &report);
}
OutputMode::Human => {
println!("Report: {}", report.id);
println!("Drive: {} ({})", report.drive_name, report.drive_serial);
println!("Date: {}", report.test_date);
println!("Score: {}/100", report.total_score);
println!(
" Capacity: {}/35 Speed: {}/25 Stability: {}/15 BadBlock: {}/25",
report.capacity_score, report.speed_score, report.stability_score, report.badblock_score
);
if let Some(real) = report.real_capacity_bytes {
println!(
"Capacity: {} real / {} claimed",
info::format_capacity(real),
cmd_report_export function · rust · L621-L660 (40 LOC)src/cli/mod.rs
fn cmd_report_export(
mode: OutputMode,
db_path: &str,
id: &str,
html_path: &str,
) -> Result<(), Box<dyn std::error::Error>> {
let db = Database::open(db_path)?;
let report = db.get_report(id)?;
let speed_samples = report.details_json.as_deref().unwrap_or("[]");
let html = crate::report::html::generate_html_report(
&report.drive_name,
&report.test_date,
report.claimed_capacity_bytes as f64 / 1_000_000_000.0,
report.real_capacity_bytes.map(|v| v as f64 / 1_000_000_000.0),
report.seq_read_speed,
report.seq_write_speed,
report.random_read_iops,
report.random_write_iops,
report.speed_stability,
report.bad_block_count.unwrap_or(0),
report.total_blocks.unwrap_or(0),
report.total_score,
speed_samples,
"[]",
);
std::fs::write(html_path, &html)?;
match mode {
OutputMode::Json => {
print_success(mode, &serde_json::jsoRepobility — the code-quality scanner for AI-generated software · https://repobility.com
cmd_report_delete function · rust · L661-L679 (19 LOC)src/cli/mod.rs
fn cmd_report_delete(
mode: OutputMode,
db_path: &str,
id: &str,
) -> Result<(), Box<dyn std::error::Error>> {
let db = Database::open(db_path)?;
db.delete_report(id)?;
match mode {
OutputMode::Json => {
print_success(mode, &serde_json::json!({"deleted": id}));
}
OutputMode::Human => {
println!("Report {} deleted.", id);
}
}
Ok(())
}make_progress_bar function · rust · L680-L699 (20 LOC)src/cli/mod.rs
fn make_progress_bar(mode: OutputMode, prefix: &str) -> Option<ProgressBar> {
match mode {
OutputMode::Human => {
let pb = ProgressBar::new(100);
pb.set_style(
ProgressStyle::default_bar()
.template(&format!(
"{{spinner:.green}} {} [{{bar:40.cyan/blue}}] {{pos}}% {{msg}}",
prefix
))
.unwrap()
.progress_chars("#>-"),
);
pb.set_draw_target(indicatif::ProgressDrawTarget::stderr());
Some(pb)
}
OutputMode::Json => None,
}
}eprint_progress function · rust · L700-L709 (10 LOC)src/cli/mod.rs
fn eprint_progress(pb: &Option<ProgressBar>, progress: f64, msg: &str) {
if let Some(pb) = pb {
pb.set_position((progress * 100.0) as u64);
pb.set_message(msg.to_string());
if progress >= 1.0 {
pb.finish_and_clear();
}
}
}print_success function · rust · L17-L30 (14 LOC)src/cli/output.rs
pub fn print_success<T: Serialize>(mode: OutputMode, data: &T) {
match mode {
OutputMode::Human => {}
OutputMode::Json => {
let envelope = JsonEnvelope {
success: true,
data: Some(data),
error: None,
};
println!("{}", serde_json::to_string(&envelope).unwrap());
}
}
}print_error function · rust · L31-L46 (16 LOC)src/cli/output.rs
pub fn print_error(mode: OutputMode, msg: &str) {
match mode {
OutputMode::Human => {
eprintln!("Error: {}", msg);
}
OutputMode::Json => {
let envelope: JsonEnvelope<()> = JsonEnvelope {
success: false,
data: None,
error: Some(msg.to_string()),
};
println!("{}", serde_json::to_string(&envelope).unwrap());
}
}
}new function · rust · L19-L21 (3 LOC)src/db.rs
pub fn new() -> Result<Self, DbError> {
Self::open("udisk_reports.db")
}open function · rust · L22-L28 (7 LOC)src/db.rs
pub fn open(path: &str) -> Result<Self, DbError> {
let conn = Connection::open(path)?;
let db = Self { conn };
db.init_tables()?;
Ok(db)
}init_tables function · rust · L29-L56 (28 LOC)src/db.rs
fn init_tables(&self) -> Result<(), DbError> {
self.conn.execute_batch(
"CREATE TABLE IF NOT EXISTS reports (
id TEXT PRIMARY KEY,
drive_name TEXT NOT NULL,
drive_serial TEXT NOT NULL DEFAULT '',
claimed_capacity_bytes INTEGER NOT NULL DEFAULT 0,
test_date TEXT NOT NULL,
total_score INTEGER NOT NULL DEFAULT 0,
capacity_score INTEGER NOT NULL DEFAULT 0,
speed_score INTEGER NOT NULL DEFAULT 0,
stability_score INTEGER NOT NULL DEFAULT 0,
badblock_score INTEGER NOT NULL DEFAULT 0,
real_capacity_bytes INTEGER,
seq_read_speed REAL,
seq_write_speed REAL,
random_read_iops REAL,
random_write_iops REAL,
speed_stability REAL,
bad_block_count INTEGER,
total_blocks INTEGER,
tRepobility · code-quality intelligence · https://repobility.com
save_report function · rust · L57-L93 (37 LOC)src/db.rs
pub fn save_report(&self, report: &ReportDetail) -> Result<(), String> {
self.conn
.execute(
"INSERT OR REPLACE INTO reports (
id, drive_name, drive_serial, claimed_capacity_bytes, test_date,
total_score, capacity_score, speed_score, stability_score, badblock_score,
real_capacity_bytes, seq_read_speed, seq_write_speed,
random_read_iops, random_write_iops, speed_stability,
bad_block_count, total_blocks, test_duration_secs, details_json
) VALUES (?1,?2,?3,?4,?5,?6,?7,?8,?9,?10,?11,?12,?13,?14,?15,?16,?17,?18,?19,?20)",
params![
report.id,
report.drive_name,
report.drive_serial,
report.claimed_capacity_bytes,
report.test_date,
report.total_score,
report.capacity_score,
get_report function · rust · L94-L134 (41 LOC)src/db.rs
pub fn get_report(&self, id: &str) -> Result<ReportDetail, String> {
self.conn
.query_row(
"SELECT id, drive_name, drive_serial, claimed_capacity_bytes, test_date,
total_score, capacity_score, speed_score, stability_score, badblock_score,
real_capacity_bytes, seq_read_speed, seq_write_speed,
random_read_iops, random_write_iops, speed_stability,
bad_block_count, total_blocks, test_duration_secs, details_json
FROM reports WHERE id = ?1",
params![id],
|row| {
Ok(ReportDetail {
id: row.get(0)?,
drive_name: row.get(1)?,
drive_serial: row.get(2)?,
claimed_capacity_bytes: row.get::<_, i64>(3)? as u64,
test_date: row.get(4)?,
total_score: row.get::<_list_reports function · rust · L135-L158 (24 LOC)src/db.rs
pub fn list_reports(&self) -> Result<Vec<ReportSummary>, String> {
let mut stmt = self
.conn
.prepare("SELECT id, drive_name, test_date, total_score FROM reports ORDER BY test_date DESC")
.map_err(|e| format!("Database error: {}", e))?;
let rows = stmt
.query_map([], |row| {
Ok(ReportSummary {
id: row.get(0)?,
drive_name: row.get(1)?,
test_date: row.get(2)?,
total_score: row.get::<_, i64>(3)? as u32,
})
})
.map_err(|e| format!("Database error: {}", e))?;
let mut reports = Vec::new();
for row in rows {
reports.push(row.map_err(|e| format!("Database error: {}", e))?);
}
Ok(reports)
}delete_report function · rust · L159-L171 (13 LOC)src/db.rs
pub fn delete_report(&self, id: &str) -> Result<(), String> {
let affected = self
.conn
.execute("DELETE FROM reports WHERE id = ?1", params![id])
.map_err(|e| format!("Failed to delete report: {}", e))?;
if affected == 0 {
Err(format!("Report not found: {}", id))
} else {
Ok(())
}
}list_usb_drives function · rust · L14-L28 (15 LOC)src/disk/detect.rs
pub fn list_usb_drives() -> Result<Vec<DriveInfo>, String> {
#[cfg(target_os = "windows")]
{
list_usb_drives_windows()
}
#[cfg(target_os = "macos")]
{
list_usb_drives_macos()
}
#[cfg(not(any(target_os = "windows", target_os = "macos")))]
{
Err("Unsupported platform".to_string())
}
}list_usb_drives_windows function · rust · L31-L52 (22 LOC)src/disk/detect.rs
fn list_usb_drives_windows() -> Result<Vec<DriveInfo>, String> {
// Use wmic first (more stable, no COM issues), WMI only as enhancement
let mut drives = list_usb_drives_wmic_fallback().unwrap_or_default();
// Try WMI to get better device names/serials, but don't fail if it errors
if let Ok(wmi_drives) = std::panic::catch_unwind(|| list_usb_drives_wmi()) {
if let Ok(wmi_drives) = wmi_drives {
for wmi_drive in &wmi_drives {
if let Some(existing) = drives.iter_mut().find(|d| d.path == wmi_drive.path) {
if !wmi_drive.name.is_empty() && wmi_drive.name != "Removable Disk" {
existing.name = wmi_drive.name.clone();
}
if !wmi_drive.serial.is_empty() && existing.serial.is_empty() {
existing.serial = wmi_drive.serial.clone();
}
}
}
}
}
Ok(drives)
}list_usb_drives_wmi function · rust · L55-L225 (171 LOC)src/disk/detect.rs
fn list_usb_drives_wmi() -> Result<Vec<DriveInfo>, String> {
use std::collections::HashMap;
use wmi::{COMLibrary, WMIConnection};
#[derive(Deserialize, Debug)]
#[serde(rename_all = "PascalCase")]
#[allow(dead_code)]
struct Win32DiskDrive {
#[serde(default)]
caption: Option<String>,
#[serde(default)]
device_id: Option<String>,
#[serde(default)]
interface_type: Option<String>,
#[serde(default)]
serial_number: Option<String>,
#[serde(default)]
size: Option<String>,
}
#[derive(Deserialize, Debug)]
#[serde(rename_all = "PascalCase")]
struct Win32DiskDriveToDiskPartition {
#[serde(default)]
antecedent: Option<String>,
#[serde(default)]
dependent: Option<String>,
}
#[derive(Deserialize, Debug)]
#[serde(rename_all = "PascalCase")]
struct Win32LogicalDiskToPartition {
#[serde(default)]
antecedent: Option<Stringlist_usb_drives_wmic_fallback function · rust · L228-L326 (99 LOC)src/disk/detect.rs
fn list_usb_drives_wmic_fallback() -> Result<Vec<DriveInfo>, String> {
use std::process::Command;
let output = Command::new("wmic")
.args([
"logicaldisk",
"where",
"drivetype=2",
"get",
"Caption,Description,FileSystem,FreeSpace,Size,VolumeName,VolumeSerialNumber",
"/format:csv",
])
.output()
.map_err(|e| format!("Failed to run wmic: {}", e))?;
let stdout = String::from_utf8_lossy(&output.stdout);
let mut drives = Vec::new();
for line in stdout.lines().skip(1) {
let line = line.trim();
if line.is_empty() {
continue;
}
let parts: Vec<&str> = line.split(',').collect();
// CSV format: Node,Caption,Description,FileSystem,FreeSpace,Size,VolumeName,VolumeSerialNumber
if parts.len() < 8 {
continue;
}
let caption = parts[1].trim();
let description = parts[2].trim();
Want fix-PRs on findings? Install Repobility's GitHub App · github.com/apps/repobility-bot
list_usb_drives_macos function · rust · L329-L458 (130 LOC)src/disk/detect.rs
fn list_usb_drives_macos() -> Result<Vec<DriveInfo>, String> {
use std::process::Command;
// Get list of external disks
let output = Command::new("diskutil")
.args(["list", "-plist", "external"])
.output()
.map_err(|e| format!("Failed to run diskutil: {}", e))?;
let stdout = String::from_utf8_lossy(&output.stdout);
// Simple plist XML parsing to extract disk identifiers
let mut disk_ids: Vec<String> = Vec::new();
let mut in_whole_disks = false;
for line in stdout.lines() {
let trimmed = line.trim();
if trimmed.contains("WholeDisks") {
in_whole_disks = true;
continue;
}
if in_whole_disks {
if trimmed == "</array>" {
in_whole_disks = false;
continue;
}
if trimmed.starts_with("<string>") && trimmed.ends_with("</string>") {
let disk_id = trimmed
.trim_start_matches("<string>extract_plist_string function · rust · L461-L483 (23 LOC)src/disk/detect.rs
fn extract_plist_string(plist: &str, key: &str) -> Option<String> {
let key_tag = format!("<key>{}</key>", key);
let mut found_key = false;
for line in plist.lines() {
let trimmed = line.trim();
if trimmed == key_tag {
found_key = true;
continue;
}
if found_key {
if trimmed.starts_with("<string>") && trimmed.ends_with("</string>") {
return Some(
trimmed
.trim_start_matches("<string>")
.trim_end_matches("</string>")
.to_string(),
);
}
return None;
}
}
None
}extract_plist_integer function · rust · L486-L507 (22 LOC)src/disk/detect.rs
fn extract_plist_integer(plist: &str, key: &str) -> Option<u64> {
let key_tag = format!("<key>{}</key>", key);
let mut found_key = false;
for line in plist.lines() {
let trimmed = line.trim();
if trimmed == key_tag {
found_key = true;
continue;
}
if found_key {
if trimmed.starts_with("<integer>") && trimmed.ends_with("</integer>") {
return trimmed
.trim_start_matches("<integer>")
.trim_end_matches("</integer>")
.parse()
.ok();
}
return None;
}
}
None
}extract_plist_bool function · rust · L510-L530 (21 LOC)src/disk/detect.rs
fn extract_plist_bool(plist: &str, key: &str) -> Option<bool> {
let key_tag = format!("<key>{}</key>", key);
let mut found_key = false;
for line in plist.lines() {
let trimmed = line.trim();
if trimmed == key_tag {
found_key = true;
continue;
}
if found_key {
if trimmed == "<true/>" {
return Some(true);
}
if trimmed == "<false/>" {
return Some(false);
}
return None;
}
}
None
}format_capacity function · rust · L2-L13 (12 LOC)src/disk/info.rs
pub fn format_capacity(bytes: u64) -> String {
if bytes >= 1_000_000_000_000 {
format!("{:.1} TB", bytes as f64 / 1_000_000_000_000.0)
} else if bytes >= 1_000_000_000 {
format!("{:.1} GB", bytes as f64 / 1_000_000_000.0)
} else if bytes >= 1_000_000 {
format!("{:.1} MB", bytes as f64 / 1_000_000.0)
} else {
format!("{:.1} KB", bytes as f64 / 1_000.0)
}
}drive_summary function · rust · L14-L23 (10 LOC)src/disk/info.rs
pub fn drive_summary(info: &DriveInfo) -> String {
format!(
"{} ({}) - {} [{}]",
info.name,
info.path,
format_capacity(info.capacity_bytes),
info.file_system
)
}write_block function · rust · L10-L23 (14 LOC)src/disk/io.rs
pub fn write_block(path: &Path, offset: u64, data: &[u8]) -> Result<(), String> {
let block_index = offset / BLOCK_SIZE as u64;
let file_path = path.join(format!("_udisk_test_block_{:06}.dat", block_index));
let mut file =
fs::File::create(&file_path).map_err(|e| format!("Failed to create block file: {}", e))?;
file.write_all(data)
.map_err(|e| format!("Failed to write block: {}", e))?;
file.sync_all()
.map_err(|e| format!("Failed to sync block: {}", e))?;
drop(file);
Ok(())
}read_block function · rust · L27-L40 (14 LOC)src/disk/io.rs
pub fn read_block(path: &Path, offset: u64, size: usize) -> Result<Vec<u8>, String> {
let block_index = offset / BLOCK_SIZE as u64;
let file_path = path.join(format!("_udisk_test_block_{:06}.dat", block_index));
// Open fresh handle to bypass read cache
let mut file =
fs::File::open(&file_path).map_err(|e| format!("Failed to open block file: {}", e))?;
let mut buf = vec![0u8; size];
file.read_exact(&mut buf)
.map_err(|e| format!("Failed to read block: {}", e))?;
drop(file);
Ok(buf)
}Source: Repobility analyzer · https://repobility.com
sync_drive function · rust · L43-L60 (18 LOC)src/disk/io.rs
pub fn sync_drive(path: &Path) -> Result<(), String> {
#[cfg(target_os = "windows")]
{
// On Windows, we rely on File::sync_all() per file.
// Optionally call FlushFileBuffers on the volume handle, but that requires admin.
let _ = path;
Ok(())
}
#[cfg(not(target_os = "windows"))]
{
use std::process::Command;
let _ = path;
Command::new("sync")
.output()
.map_err(|e| format!("sync failed: {}", e))?;
Ok(())
}
}main function · rust · L5-L27 (23 LOC)src/main.rs
async fn main() {
env_logger::init();
ctrlc::set_handler(move || {
eprintln!("\nStopping test...");
udisk_inspector_lib::STOP_FLAG.store(true, Ordering::Relaxed);
})
.ok();
if let Err(e) = cli::run().await {
let json_mode = std::env::args().any(|a| a == "--json");
if json_mode {
let envelope = serde_json::json!({
"success": false,
"error": e.to_string()
});
println!("{}", envelope);
} else {
eprintln!("Error: {}", e);
}
std::process::exit(1);
}
}generate_html_report function · rust · L1-L210 (210 LOC)src/report/html.rs
pub fn generate_html_report(
drive_name: &str,
test_date: &str,
claimed_capacity_gb: f64,
real_capacity_gb: Option<f64>,
seq_read: Option<f64>,
seq_write: Option<f64>,
random_read_iops: Option<f64>,
random_write_iops: Option<f64>,
stability: Option<f64>,
bad_blocks: u64,
_total_blocks: u64,
total_score: u32,
speed_samples_json: &str,
bad_block_positions_json: &str,
) -> String {
let score_class = if total_score >= 90 {
"excellent"
} else if total_score >= 70 {
"good"
} else if total_score >= 50 {
"fair"
} else {
"poor"
};
let grade_text = if total_score >= 90 {
"优秀"
} else if total_score >= 70 {
"良好"
} else if total_score >= 50 {
"一般"
} else {
"差"
};
let real_gb = match real_capacity_gb {
Some(v) => format!("{:.1} GB", v),
None => "未测试".to_string(),
};
let seq_read_str = match seq_read {
Socalculate_score function · rust · L18-L104 (87 LOC)src/report/score.rs
pub fn calculate_score(
claimed_capacity: u64,
real_capacity: Option<u64>,
seq_read_speed: Option<f64>,
seq_write_speed: Option<f64>,
stability: Option<f64>,
speed_drops: Option<u32>,
bad_block_count: Option<u64>,
total_blocks: Option<u64>,
) -> QualityScore {
// Capacity score (35 points)
let capacity_score = match real_capacity {
Some(real) => {
let ratio = real as f64 / claimed_capacity.max(1) as f64;
if ratio >= 0.95 {
35
} else if ratio < 0.50 {
0
} else {
((ratio - 0.50) / 0.45 * 35.0) as u32
}
}
None => 0,
};
// Speed score (25 points)
let read_score = match seq_read_speed {
Some(speed) => ((speed / 100.0).min(1.0) * 12.0) as u32,
None => 0,
};
let write_score = match seq_write_speed {
Some(speed) => ((speed / 50.0).min(1.0) * 13.0) as u32,
None => 0,
}