Work on making partitions start-end calculate properly. Specifically 2mb at start and -33 sectors GPT reserved at the end.

This commit is contained in:
2026-09-28 00:13:12 +02:00
parent fa5c3d3aec
commit 3b086605cf
2 changed files with 108 additions and 43 deletions
+76 -22
View File
@@ -20,7 +20,7 @@
use crate::kira_size::KiraSize;
use log;
use std::{collections::HashMap};
use std::collections::HashMap;
///
/// size - device size in bytes
/// sector size - default 4096
@@ -117,20 +117,25 @@ impl BlkDev {
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct BcachefsProp {
pub struct BcachefsProp {
pub password: Option<String>,
pub comp_alg: Option<String>,
}
impl BcachefsProp {
pub fn new(password: Option<String>, comp_alg: Option<String>) -> Self {
Self { password:password, comp_alg: comp_alg }
Self {
password: password,
comp_alg: comp_alg,
}
}
pub fn default() -> Self {
Self { password: None, comp_alg: None }
Self {
password: None,
comp_alg: None,
}
}
}
#[derive(Debug, Clone, PartialEq, Eq)]
@@ -208,7 +213,7 @@ impl FSType {
pub enum PartRole {
EFI,
ROOT,
SWAP
SWAP,
}
#[derive(Debug, Clone, PartialEq, Eq)]
@@ -230,6 +235,22 @@ impl std::fmt::Display for PartInfo {
}
impl PartInfo {
///
/// calculate par end byte as 0 starting bytes index (for parted and such)
///
pub fn part_end(&self) -> KiraSize {
// important to shift here by 1 because disk index is starting from 0, and part end pointing to last byte of the partition.
(self.start + self.size) - KiraSize::new_b(1)
}
///
/// Returns zero based byte index of start of next (right after this one) partition
///
pub fn next_part_start(&self) -> KiraSize {
// important to shift here by 1 because disk index is starting from 0, and part end pointing to last byte of the partition.
self.start + self.size
}
pub fn from_hash_map(data: &HashMap<String, String>) -> Option<Self> {
Some(Self {
name: data.get("NAME")?.clone(),
@@ -250,7 +271,9 @@ impl PartInfo {
}
pub fn partlabel_dev(&self) -> Option<String> {
self.gpt_label.as_ref().and_then(|l| Some(format!("/dev/disk/by-partlabel/{}", l)))
self.gpt_label
.as_ref()
.and_then(|l| Some(format!("/dev/disk/by-partlabel/{}", l)))
}
}
@@ -329,7 +352,7 @@ pub fn align_part(size: u64, start: u64, align: u64) -> Option<(u64, u64, u64)>
// decreasing end if not align
let part_end = align_start + size;
let end_mod = part_end % align;
log::debug!("part_end: {} end_mod: {}", part_end, end_mod);
let align_end = part_end - end_mod - 1;
let align_size = align_end - align_start + 1;
@@ -342,7 +365,13 @@ pub fn align_part(size: u64, start: u64, align: u64) -> Option<(u64, u64, u64)>
);
return None;
}
log::debug!(
"align_size: {}, align_start:{}, align_end: {} end_mod: {}",
align_size,
align_start,
align_end,
end_mod
);
Some((align_size, align_start, align_end))
}
@@ -353,10 +382,16 @@ pub struct PartLayout {
pub part_list: Vec<PartInfo>,
}
///
/// GPT requires 33x512 sectors at the very end of the disk (16,896 bytes = 16.5 KiB):
/// 32 sectors — backup Partition Entry Array (128 entries × 128 bytes = 16,384 bytes)
/// 1 sector — backup GPT header
impl PartLayout {
pub fn new(dev: BlkDev) -> Self {
// 16896 - reserved space at the dev end for gpt
let usable_space = dev.size - KiraSize::new_b(16896);
Self {
empty_space: dev.size,
empty_space: usable_space,
dev: dev,
part_list: Vec::new(),
}
@@ -374,11 +409,11 @@ impl PartLayout {
})
}
pub fn new_table(mut self) -> Self {
self.empty_space = self.dev.size;
self.part_list = Vec::new();
self
}
// 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,
@@ -390,19 +425,29 @@ impl PartLayout {
role: Option<PartRole>,
) -> Self {
let part_start = if self.part_list.is_empty() {
// need to substract 2 mb offset from disk start.
self.empty_space = self.empty_space - KiraSize::new_mb(2);
KiraSize::new_mb(2)
} else {
self.dev.size - self.empty_space
// last part end + 1
self.part_list.last().unwrap().next_part_start()
};
let (size, start, _) =
let (a_size, a_start, _) =
align_part(part_size.b(), part_start.b(), self.dev.sector_size.b()).unwrap();
log::debug!(
"PartLayout.add_part gpt_label{:?}, size_asked:{}, size_al:{}",
gpt_label,
part_size,
a_size
);
let part_name = format!("{}p{}", self.dev.name, self.part_list.len() + 1);
self.part_list.push(PartInfo {
name: part_name,
size: KiraSize::new_b(size),
start: KiraSize::new_b(start),
size: KiraSize::new_b(a_size),
start: KiraSize::new_b(a_start),
fs_type: fs_type,
gpt_label: gpt_label,
fs_label: fs_label,
@@ -410,10 +455,14 @@ impl PartLayout {
role: role,
});
self.empty_space = self.empty_space - KiraSize::new_b(size);
self.empty_space = self.empty_space - KiraSize::new_b(a_size);
self
}
///
/// Use this to add partition of (disk_empty_space - reserve_space)
/// Specifically to leave some space at the end for SWAP and such
///
pub fn add_part_reserve(
self,
reserve_space: KiraSize,
@@ -427,7 +476,13 @@ impl PartLayout {
self.add_part(p_size, fs_type, gpt_label, fs_label, mount_point, role)
}
pub fn gen_kira_layout(dev: BlkDev, efi_size: KiraSize, swap_size: KiraSize, maybe_password: Option<String>, maybe_compr: Option<String>) -> Self {
pub fn gen_kira_layout(
dev: BlkDev,
efi_size: KiraSize,
swap_size: KiraSize,
maybe_password: Option<String>,
maybe_compr: Option<String>,
) -> Self {
let mut res: PartLayout = PartLayout::new(dev);
// UEFI partition
@@ -465,7 +520,6 @@ impl PartLayout {
}
}
#[cfg(test)]
mod tests {
use rand::RngExt;
+32 -21
View File
@@ -19,18 +19,25 @@
*/
use crate::kira_disk_layout::*;
use std::process::Command;
use crate::kira_size::KiraSize;
use std::fs;
use std::process::Command;
#[derive(Debug)]
pub struct CommandFailed{
pub struct CommandFailed {
stderr: Vec<u8>,
cmd: String,
}
impl std::fmt::Display for CommandFailed {
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
write!(f, "Command failed! Command: {}; Stderr: {}", self.cmd, String::from_utf8(self.stderr.clone()).unwrap_or_else(|_|{"STDEER IS NOT VALID UTF-8".to_string()}))
write!(
f,
"Command failed! Command: {}; Stderr: {}",
self.cmd,
String::from_utf8(self.stderr.clone())
.unwrap_or_else(|_| { "STDEER IS NOT VALID UTF-8".to_string() })
)
}
}
@@ -124,7 +131,10 @@ pub fn dinit_sync_time_chrony() -> Result<(), ExecCommandError> {
/// Install base system
/// basestrap /mnt base base-devel dinit elogind-dinit
pub fn basestrap_dinit(root_dir: &str) -> Result<(), ExecCommandError> {
exec_command("basestrap", &vec![root_dir, "base", "base-devel", "dinit", "elogind-dinit"])
exec_command(
"basestrap",
&vec![root_dir, "base", "base-devel", "dinit", "elogind-dinit"],
)
}
/// Executes parted command with given arguments
@@ -151,12 +161,7 @@ fn parted_get_last_part_num(dev: &BlkDev) -> Result<u32, ExecCommandError> {
/// Its blocking function
pub fn parted_init_gpt_part_table(dev: &BlkDev) -> Result<(), ExecCommandError> {
let dev_full_name = dev.full_name();
let args = vec![
"--script",
&dev_full_name,
"mklabel",
"gpt",
];
let args = vec!["--script", &dev_full_name, "mklabel", "gpt"];
exec_command("parted", &args)
}
@@ -166,7 +171,8 @@ const LINUX_ROOT_X86_64_TYPE: &str = "4F68BCE3-E8CD-4DB1-96E7-FBCAF984B709";
/// It assumes that we add partitions sequentially to empty space (for part attributes settings)
/// Otherwise can produce bonkers layout
pub fn parted_mkpart(dev: &BlkDev, part: &PartInfo) -> Result<(), ExecCommandError> {
let part_end = part.start + part.size;
// important to shift here by 1 because disk index is starting from 0, and part end pointing to last byte of the partition.
let part_end = part.part_end();
// gpt label should be in double qutes
let gpt_label = if let Some(s) = &part.gpt_label {
@@ -174,6 +180,14 @@ pub fn parted_mkpart(dev: &BlkDev, part: &PartInfo) -> Result<(), ExecCommandErr
} else {
"\"\"".to_string()
};
log::debug!(
"Creatin partition dev:{}, label:{}, fs_type:{}, start:{}, end:{}",
dev.full_name(),
gpt_label,
part.fs_type.to_parted_str(),
part.start.to_parted_bytes_str(),
part_end.to_parted_bytes_str()
);
// creating partition
exec_parted(&vec![
"--script",
@@ -218,7 +232,7 @@ pub fn parted_mkpart(dev: &BlkDev, part: &PartInfo) -> Result<(), ExecCommandErr
}
/// creating single drive bcachefs volume
/// compression: lz4, zstd
/// compression: lz4, zstd
pub fn bcachefs_format(
dev_name: &str,
compression: Option<String>,
@@ -255,13 +269,11 @@ pub fn bcachefs_format(
/// unlok encrypted bcache volume
pub fn bcachefs_unlock(dev_name: &str, pass: &str) -> Result<(), ExecCommandError> {
// bcachefs unlock --file=/tmp/bzzpsspass.txt /dev/loop0
let arg = vec!["unlock", "--file=/tmp/bzzpsspass.txt ", dev_name];
// creating tmp file with password
fs::write("/tmp/bzzpsspass.txt", &pass)?;
let out = exec_command("bcachefs", &arg);
// ignore any errors while deleting pass tmp file
let _ = fs::remove_file("/tmp/bzzpsspass.txt");
@@ -292,10 +304,10 @@ pub fn mkfs_fat32(dev: &str, maybe_label: Option<&str>) -> Result<(), ExecComman
// if need to set label
if let Some(label) = maybe_label {
fatlabel(dev, label)
} else {
Ok(())
}
fatlabel(dev, label)
} else {
Ok(())
}
}
/// mkfs.fat -F 32 /dev/sda1
@@ -304,8 +316,7 @@ pub fn mkfs_esp(dev: &str) -> Result<(), ExecCommandError> {
mkfs_fat32(dev, Some("ESP"))
}
pub fn mkswap(dev: &str) -> Result<(), ExecCommandError> {
//mkswap -L SWAP /dev/sda4
//mkswap -L SWAP /dev/sda4
exec_command("mkswap", &vec!["L", "SWAP", dev])
}
}