Working on partitions stuff related to issue #2

This commit is contained in:
2026-05-19 23:52:20 +02:00
parent cf916eb508
commit edfd57d5d5
7 changed files with 307 additions and 7 deletions
+302
View File
@@ -0,0 +1,302 @@
use std::collections::HashMap;
pub fn format_bytes_size(size: u64) -> String {
let suffixs: [&str; 5] = ["KB", "MB", "GB", "TB", "PB"];
if size < 1000 {
format!("{}B", size)
} else {
let mut s = size as f64;
let mut idx = 0;
for i in 0..5 {
s = s / 1024.0;
idx = i;
if s < 1000.0 {
break;
}
}
format!("{:.2}{}", s, suffixs[idx])
}
}
///
/// size - device size in bytes
/// sector size - default 4096
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct BlkDev {
name: String,
size: u64,
sector_size: u32,
}
impl std::fmt::Display for BlkDev {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "{} ({})", &self.name, format_bytes_size(self.size))
}
}
impl BlkDev {
pub fn new(name: String, size: u64) -> Self {
Self {
name: name,
size: size,
sector_size: 4096,
}
}
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum FSType {
VFAT,
XFS,
LUKS,
SWAP,
EXT4,
BTRFS,
BCACHEFS,
UNKNOWN,
}
impl std::fmt::Display for FSType {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
Self::VFAT => write!(f, "vfat"),
Self::XFS => write!(f, "xfs"),
Self::LUKS => write!(f, "luks"),
Self::SWAP => write!(f, "swap"),
Self::EXT4 => write!(f, "ext4"),
Self::BTRFS => write!(f, "btrfs"),
Self::BCACHEFS => write!(f, "bcachefs"),
Self::UNKNOWN => write!(f, "unknown"),
}
}
}
impl FSType {
pub fn from_str(s: &str) -> Self {
let s_low = s.to_lowercase();
match s_low.as_str() {
"vfat" => Self::VFAT,
"xfs" => Self::XFS,
"crypto_luks" => Self::LUKS,
"swap" => Self::SWAP,
"ext4" => Self::EXT4,
"btrfs" => Self::BTRFS,
"bcachefs" => Self::BCACHEFS,
_ => Self::UNKNOWN,
}
}
}
// fn part_type_to_color(t: &str) -> Color {
// match t {
// "vfat" => Color::from_rgb8(204, 121, 167),
// "xfs" => Color::from_rgb8(0, 158, 115),
// "crypto_LUKS" => Color::from_rgb8(240, 228, 66),
// "swap" => Color::from_rgb8(213, 94, 0),
// "ext4" => Color::from_rgb8(0, 114, 178),
// "btrfs" => Color::from_rgb8(86, 180, 233),
// _ => Color::from_rgb8(230, 159, 0),
// }
// }
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct PartInfo {
name: String,
size: u64,
fs_type: FSType,
gpt_label: Option<String>,
fs_label: Option<String>,
mount_point: Option<String>,
}
impl std::fmt::Display for PartInfo {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(
f,
"{} {} {}",
&self.name,
&self.fs_type,
format_bytes_size(self.size)
)
}
}
impl PartInfo {
pub fn from_hash_map(data: &HashMap<String, String>) -> Option<Self> {
Some(Self {
name: data.get("NAME")?.clone(),
size: u64::from_str_radix(data.get("SIZE")?, 10).ok()?,
fs_type: FSType::from_str(data.get("FSTYPE")?),
gpt_label: data
.get("PARTLABEL")
.and_then(|v| if v.is_empty() { None } else { Some(v.clone()) }),
fs_label: data
.get("LABEL")
.and_then(|v| if v.is_empty() { None } else { Some(v.clone()) }),
mount_point: data
.get("MOUNTPOINT")
.and_then(|v| if v.is_empty() { None } else { Some(v.clone()) }),
})
}
}
/// getting list of device partitions
fn get_dev_part_blocking(dev_name: &str) -> Result<Vec<PartInfo>, String> {
use std::process::Command;
//"lsblk -o NAME,SIZE,FSTYPE -l -n /dev/nvme0n1"
// lsblk -o NAME,SIZE,FSTYPE,TYPE,PARTLABEL,LABEL,PARTFLAGS -b -P
match Command::new("lsblk")
.args([
"-o",
"NAME,SIZE,FSTYPE,TYPE,PARTLABEL,LABEL,MOUNTPOINT,PARTFLAGS",
"-b",
"-P",
format!("/dev/{}", dev_name).as_str(),
])
.output()
{
Ok(cmd_output) => {
if cmd_output.status.success() {
match String::from_utf8(cmd_output.stdout) {
Ok(raw_str_list) => Ok(raw_str_list
.lines()
.map(|l| {
l.split_whitespace()
.filter_map(|pair| {
pair.split_once("=").and_then(|kv| {
Some((
kv.0.trim_matches('"').to_string(),
kv.1.trim_matches('"').to_string(),
))
})
})
.collect::<HashMap<String, String>>()
})
.filter(|mp| mp.get("TYPE").is_some_and(|v| v == "part"))
.filter_map(|mp| PartInfo::from_hash_map(&mp))
.collect()),
Err(ex) => Err(format!(
"Exception while converting partition info to UTF8 {}",
ex
)),
}
} else {
Err(format!(
"Error getting device partitions list: {}",
String::from_utf8(cmd_output.stderr).unwrap_or("UNKNOWN".into())
))
}
}
Err(ex) => Err(ex.to_string()),
}
}
///
/// size - size in bytes
/// start - start byte of partition, inclusive index.
/// returns tuple of aligned size, start index, and end index
/// return none if aligment is not possibe (size of partition is less than align)
pub fn align_part(size: u64, start: u64, align: u64) -> Option<(u64, u64, u64)> {
if size < align {
println!("if size < align !!!!!!!");
return None;
}
let start_mod = start % align;
// increasing start if not align
let align_start = if start_mod > 0 {
start + (align - start_mod)
} else {
start
};
// decreasing end if not align
let part_end = align_start + size;
let end_mod = part_end % align;
println!("part_end: {} end_mod: {}", part_end, end_mod);
let align_end = part_end - end_mod - 1;
let align_size = align_end - align_start + 1;
if align_size < align {
println!("if align_size < align !!!!!!! align_size: {} align: {}",align_size,align);
return None;
}
Some((align_size, align_start, align_end))
}
pub struct PartLayout {
dev: BlkDev,
empty_space: u64,
part_list: Vec<PartInfo>,
}
impl PartLayout {
pub fn new(dev: BlkDev) -> Self {
Self {
empty_space: dev.size,
dev: dev,
part_list: Vec::new(),
}
}
pub fn read_from_dev(dev: &BlkDev) -> Result<Self, String> {
let part_list = get_dev_part_blocking(&dev.name)?;
let parts_size = part_list.iter().fold(0, |acc, part| acc + part.size);
Ok(Self {
dev: dev.clone(),
empty_space: dev.size - parts_size,
part_list: part_list,
})
}
pub fn new_table(mut self) -> Self {
self.empty_space = self.dev.size;
self.part_list = Vec::new();
self
}
pub fn add_part(
mut self,
part_size: u64,
fs_type: FSType,
gpt_label: Option<String>,
fs_label: Option<String>,
mount_point: Option<String>,
) -> Self {
self
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_align_part_fn() {
//START (S),SIZE (Z),ALIGNMENT (A),ALIGNED_START (Salign),ALIGNED_END (Ealign),Effektive Größe (Zalign)
let joes_test_data: Vec<(u64, u64, u64, u64, u64, u64)> = vec![
(0, 10000, 4096, 0, 8191, 8192),
(5000, 20000, 4096, 8192, 24575, 16384),
(4096, 4096, 4096, 4096, 8191, 4096),
(1000000, 5000000, 1048576, 1048576, 5242879, 4194304),
(2097152, 1050000, 1048576, 2097152, 3145727, 1048576),
];
for test_data in joes_test_data {
let res = align_part(test_data.1,test_data.0,test_data.2).unwrap();
let test_res = (test_data.5, test_data.3, test_data.4);
assert_eq!(res, test_res);
}
}
}
// fn add_part(part_list: Vec<PartInfo>, rem_size: u64, part_t: PartType, )
// fn gen_layout(dev: &BlkDev, swap_size: u64) -> Vec<PartInfo> {
// Vec::new()
// }
+1
View File
@@ -35,6 +35,7 @@ rust_i18n::i18n!("src/locales", fallback = "en");
mod kira_theming; mod kira_theming;
mod kira_scroll_list; mod kira_scroll_list;
mod kira_color_bar; mod kira_color_bar;
mod kira_disk_layout;
mod stage; mod stage;
mod stages; mod stages;
+1 -1
View File
@@ -19,7 +19,7 @@
*/ */
use crate::kira_scroll_list::{self, ListViewMessage}; use crate::kira_scroll_list::{self, ListViewMessage};
use crate::stage::{ConfigValue, StageAction, StageResult}; use crate::stage::{StageAction, StageResult};
use iced::{Alignment, Length, widget}; use iced::{Alignment, Length, widget};
use rust_i18n::t; use rust_i18n::t;
use std::collections::HashMap; use std::collections::HashMap;
-1
View File
@@ -22,7 +22,6 @@
use iced::{Alignment, Task, widget}; use iced::{Alignment, Task, widget};
use iced_moving_picture::widget::apng; use iced_moving_picture::widget::apng;
use rust_i18n::t; use rust_i18n::t;
use std::collections::HashMap;
use toml::Table; use toml::Table;
use crate::stage; use crate::stage;
+1 -2
View File
@@ -18,12 +18,11 @@
This is partition stage! This is partition stage!
*/ */
use crate::stage::{ConfigValue, StageAction, StageResult}; use crate::stage::{StageAction, StageResult};
use crate::kira_color_bar; use crate::kira_color_bar;
use iced::{Alignment, Color, Length, widget}; use iced::{Alignment, Color, Length, widget};
use rust_i18n::t; use rust_i18n::t;
use std::collections::HashMap;
#[derive(Debug, Clone, Copy, PartialEq, Eq)] #[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum SwapMode { pub enum SwapMode {
+1 -1
View File
@@ -18,7 +18,7 @@
This is TimeZone stage, used to select timezone This is TimeZone stage, used to select timezone
*/ */
use crate::stage::{ConfigValue, StageAction, StageResult}; use crate::stage::{StageAction, StageResult};
use iced::{Alignment, Length, widget}; use iced::{Alignment, Length, widget};
use rust_i18n::t; use rust_i18n::t;
use std::collections::HashMap; use std::collections::HashMap;
+1 -2
View File
@@ -20,10 +20,9 @@
*/ */
use crate::{stage::{ConfigValue, StageAction, StageResult}, kira_theming}; use crate::{stage::{StageAction, StageResult}, kira_theming};
use iced::{Alignment, widget}; use iced::{Alignment, widget};
use rust_i18n::t; use rust_i18n::t;
use std::collections::HashMap;
#[derive(Debug, Clone, PartialEq, Eq)] #[derive(Debug, Clone, PartialEq, Eq)]
pub struct LocData { pub struct LocData {