forked from pisilinux-rs/yali-rs
fix(partition): silinen alandan açılan "/", boş alan satırını gizlemiyordu
Kullanıcı raporu: "boş alan sorunu geri gelmiş bir alanı sildim boş
alan olarak doğru oku, sonrasında o boş alanı yeni bölüm diyerek /
dizin yaptım biçimlendir seçtim kaydettim ama boş alan duruyor
yerinde, yeni oluşturduğumda duruyor."
## Sebep — koşul YER YER yazılmıştı
Bu tablodaki bir hata üçüncü kez yaşanıyor ve üçü de aynı sebepten:
`has_symbolic` kontrolü satırın YALNIZCA BİR basış yerine eklenmişti.
1. `else if` dalı vardı → tanım varsa satır hiç basılmıyordu
2. `else if` düzeltildi, DÖNGÜ İÇİ basış unutuldu
3. döngü içi de ayrı ayrı yazıldı → yine kaçırılabilir
Senaryo: sdb2 silindi → boş alan DOĞRU göründü → o alandan "Yeni
Bölüm" ile `/` açıldı. `/` "Kalan Alan" olduğu için SEMBOLİKTİR ve
alanın tamamını alır. Ama silinen bölümün yerine basılan satır
sembolik tanımı görmüyordu ve diskin tamamını "boş" göstermeye
devam etti — kullanıcının o satırın sağında gördüğü.
## Düzeltme — koşul tek yerde
let show_free = free_total_mb > 0 && !has_symbolic;
`show_free` artık ÜÇ basış yerinin de ortak koşulu:
döngü içi (silinen grubun sonu), döngü sonu (sonda işaretli), sondaki
`else if` (disk sonu).
Koşulu üç yere ayrı ayrı yazmayı bırakmak bu sınıf hatayı
kaçınılmaz kılıyordu; aynı hatanın üçüncü kez yaşanması bunun
kanıtı.
## Testler (143 → 145)
- ⭐ kullanıcının senaryosu: silinen bölümün yerine sembolik `/`
açıldı → boş alan satırı KAYBOLUR, 2 satır kalır
- aynı senaryo ama SABİT boyutlu bölüm → boş alan satırı kalır ve
miktar doğru düşer (500000 − 50000 = 450000)
İkinci test önemli: satırın kaybolmaması da bir hata olurdu —
sabit boyutlu bölüm gerçekten yer bırakıyor.
cargo check --all-targets : 0 hata, 0 uyarı
cargo test : 145/145
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -319,7 +319,7 @@ boş alandan düşmedi"* — 20 GB'lik disk 39 GB kullanıyor gibi görünüyord
|
|||||||
| Yer | Kural |
|
| Yer | Kural |
|
||||||
|---|---|
|
|---|---|
|
||||||
| `has_symbolic_remaining(parts, disk)` | **TEK KAYNAK.** `!delete && size_mb == 0 && orig_device.is_empty()` |
|
| `has_symbolic_remaining(parts, disk)` | **TEK KAYNAK.** `!delete && size_mb == 0 && orig_device.is_empty()` |
|
||||||
| tablo (`build_table_rows`) | sembolik varsa boş alan satırı **çizilmez** — o alan o tanıma ait |
|
| tablo (`build_table_rows`) | sembolik varsa boş alan satırı **çizilmez** — o alan o tanıma ait. Koşul **`show_free`** adıyla TEK yerde tanımlı ve **üç basış yerinin de** ortak koşulu (aşağıdaki REGRESYON 3'e bak) |
|
||||||
| çubuk (`manual_dual_bars`) | sembolik varsa serbest segment **eklenmez** |
|
| çubuk (`manual_dual_bars`) | sembolik varsa serbest segment **eklenmez** |
|
||||||
| `manual_capacity_error` | sembolik varsa `fixed_mb >= cap_mb` reddedilir |
|
| `manual_capacity_error` | sembolik varsa `fixed_mb >= cap_mb` reddedilir |
|
||||||
|
|
||||||
@@ -331,6 +331,28 @@ kalanın tamamını alır, ikincisine hiç yer kalmaz.
|
|||||||
`orig_device` dolu (taranmış) 0 boyutlu bölüm sembolik **DEĞİLDİR**:
|
`orig_device` dolu (taranmış) 0 boyutlu bölüm sembolik **DEĞİLDİR**:
|
||||||
sıfır boyut "kalanın tamamı" anlamına gelmez.
|
sıfır boyut "kalanın tamamı" anlamına gelmez.
|
||||||
|
|
||||||
|
#### ⭐ Koşul YER YER yazılırsa bu sınıf hata tekrarlar
|
||||||
|
|
||||||
|
Bu tabloda bir hata **üç kez** yaşandı ve üçü de aynı sebepten:
|
||||||
|
`has_symbolic` kontrolü satırın **yalnızca bir** basış yerine
|
||||||
|
eklenmişti.
|
||||||
|
|
||||||
|
1. `else if` dalı vardı, diskte tanım yokken çalışıyordu →
|
||||||
|
tanım varsa satır hiç basılmıyordu (`sda1` + 15 GB boş)
|
||||||
|
2. `else if` düzeltildi, **döngü içindeki** basış unutuldu →
|
||||||
|
`19.8 GB` bölüm + `19.8 GB` boş alan
|
||||||
|
3. döngü içi de düzeltildi ama **koşul üç yere ayrı ayrı yazıldı**
|
||||||
|
|
||||||
|
**Ders:** aynı koşulu birden çok yerde yazma. Tek bir
|
||||||
|
`show_free = free_total_mb > 0 && !has_symbolic` değişkeni hesaplanıp
|
||||||
|
**üç basış yerinin de** koşulu olarak kullanılıyor. Kural tek
|
||||||
|
yerde; onu atlamak ya da çoğaltmak imkânsız.
|
||||||
|
|
||||||
|
> Bu, "sabit bir sayıyı 3 yere yazma" değil — "bir *koşulu* 3
|
||||||
|
> yere yazma". Sabit sayıyı çoğaltmak hataya açıktır ama en azından
|
||||||
|
> yanlışsa sayı yanlış görünür; koşulu çoğaltmak bazı basış
|
||||||
|
> yerlerinde **sessizce yanlış** davranış üretir.
|
||||||
|
|
||||||
### ⭐ Bağlanmayan dosya sistemleri — mountpoint isteğe bağlı
|
### ⭐ Bağlanmayan dosya sistemleri — mountpoint isteğe bağlı
|
||||||
|
|
||||||
`mountpoint_required(editing, fstype)` üç dosya sisteminde `false`
|
`mountpoint_required(editing, fstype)` üç dosya sisteminde `false`
|
||||||
@@ -669,11 +691,11 @@ nedeni yorumla sabitlendi. Log bile "MiB" derken argüman "MB" gönderiyordu.
|
|||||||
|
|
||||||
```
|
```
|
||||||
cargo check --all-targets : 0 hata, 0 uyarı
|
cargo check --all-targets : 0 hata, 0 uyarı
|
||||||
cargo test : 143/143 (test modülü sayısı arttıkça güncel tut)
|
cargo test : 145/145 (test modülü sayısı arttıkça güncel tut)
|
||||||
cargo clippy : ~77 uyarı, tamamı stil (collapsed_if, replace zinciri)
|
cargo clippy : ~77 uyarı, tamamı stil (collapsed_if, replace zinciri)
|
||||||
```
|
```
|
||||||
|
|
||||||
Bu oturumda 1 → 143 test. Test modülü olmayan dosyalar (`users.rs`,
|
Bu oturumda 1 → 145 test. Test modülü olmayan dosyalar (`users.rs`,
|
||||||
`location.rs`, `rescue.rs`, `funct.rs`, `autoinstall/mod.rs`, `main.rs`)
|
`location.rs`, `rescue.rs`, `funct.rs`, `autoinstall/mod.rs`, `main.rs`)
|
||||||
içine modüller eklendi. Çoklu test modülü paylaşılan yardımcıları
|
içine modüller eklendi. Çoklu test modülü paylaşılan yardımcıları
|
||||||
`steps/partition.rs::testutil` altındadır (`disk()`, `part()`).
|
`steps/partition.rs::testutil` altındadır (`disk()`, `part()`).
|
||||||
|
|||||||
+82
-10
@@ -762,8 +762,12 @@ fn build_table_rows<'a>(
|
|||||||
.map(|p| p.size_mb)
|
.map(|p| p.size_mb)
|
||||||
.sum();
|
.sum();
|
||||||
let free_total_mb = disk_mb.saturating_sub(used_total);
|
let free_total_mb = disk_mb.saturating_sub(used_total);
|
||||||
// "Kalan Alan" tanımı kalanın tamamını alır → boş alan satırı çizilmez.
|
// "Kalan Alan" tanımı kalanın tamamını alır → boş alan satırı
|
||||||
|
// çizilmez. ⚠️ Bu koşul ÜÇ basış yerinin de ORTAK koşuludur.
|
||||||
|
// Sadece sondakine uygulanırsa diğer ikisi sembolik tanımı
|
||||||
|
// görmez (aşağıdaki REGRESYON 3).
|
||||||
let has_symbolic = has_symbolic_remaining(parts, active_disk);
|
let has_symbolic = has_symbolic_remaining(parts, active_disk);
|
||||||
|
let show_free = free_total_mb > 0 && !has_symbolic;
|
||||||
|
|
||||||
let mut fs_first: Option<usize> = None;
|
let mut fs_first: Option<usize> = None;
|
||||||
// Boş alan satırı disk başına TEK'tir (GParted tarzı: silinenler
|
// Boş alan satırı disk başına TEK'tir (GParted tarzı: silinenler
|
||||||
@@ -779,7 +783,7 @@ fn build_table_rows<'a>(
|
|||||||
}
|
}
|
||||||
// İşaret bloğunun bittiği yerde boş-alan satırını bas
|
// İşaret bloğunun bittiği yerde boş-alan satırını bas
|
||||||
if let Some(first) = fs_first.take() {
|
if let Some(first) = fs_first.take() {
|
||||||
if free_total_mb > 0 {
|
if show_free {
|
||||||
visible_rows.push(TableRow::FreeSpace {
|
visible_rows.push(TableRow::FreeSpace {
|
||||||
disk: active_disk.to_string(),
|
disk: active_disk.to_string(),
|
||||||
total_mb: free_total_mb,
|
total_mb: free_total_mb,
|
||||||
@@ -794,14 +798,14 @@ fn build_table_rows<'a>(
|
|||||||
if let Some(first) = fs_first.take() {
|
if let Some(first) = fs_first.take() {
|
||||||
// Son ifade olduğu için `free_row_shown` burada güncellenmez;
|
// Son ifade olduğu için `free_row_shown` burada güncellenmez;
|
||||||
// zaten sonrasında okunacak bir dal yok.
|
// zaten sonrasında okunacak bir dal yok.
|
||||||
if free_total_mb > 0 {
|
if show_free {
|
||||||
visible_rows.push(TableRow::FreeSpace {
|
visible_rows.push(TableRow::FreeSpace {
|
||||||
disk: active_disk.to_string(),
|
disk: active_disk.to_string(),
|
||||||
total_mb: free_total_mb,
|
total_mb: free_total_mb,
|
||||||
first_idx: Some(first),
|
first_idx: Some(first),
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
} else if free_total_mb > 0 && !free_row_shown && !has_symbolic {
|
} else if show_free && !free_row_shown {
|
||||||
// Disk SONUNDAKİ boş alan — diskte tanım olsun ya da olmasın.
|
// Disk SONUNDAKİ boş alan — diskte tanım olsun ya da olmasın.
|
||||||
//
|
//
|
||||||
// REGRESYON: koşul `all(|p| p.disk != active_disk)` idi, yani
|
// REGRESYON: koşul `all(|p| p.disk != active_disk)` idi, yani
|
||||||
@@ -809,14 +813,27 @@ fn build_table_rows<'a>(
|
|||||||
// Diskte tanım var ama hiçbiri silinmek işaretli değilse
|
// Diskte tanım var ama hiçbiri silinmek işaretli değilse
|
||||||
// (`sda1` + 15 GB boş) satır hiç basılmıyordu.
|
// (`sda1` + 15 GB boş) satır hiç basılmıyordu.
|
||||||
//
|
//
|
||||||
// `has_symbolic` kuralı: "Kalan Alan" tanımı varsa boş alan o
|
// REGRESYON 2: sembolik tanım (`size_mb == 0`) hiçbir hesaba
|
||||||
// tanıma aittir. REGRESYON 2: sembolik tanım (`size_mb == 0`)
|
// katılmadığı için hem bölüm satırı hem boş alan satırı
|
||||||
// hiçbir hesaba katılmadığı için hem bölüm satırı hem boş alan
|
// kalanın tamamını gösteriyordu — 20 GB'lik disk 39 GB
|
||||||
// satırı kalanın tamamını gösteriyordu — 20 GB'lik disk
|
// kullanıyor gibi görünüyordu. Kullanıcı raporu:
|
||||||
// 39 GB kullanıyormuş gibi görünüyordu. Kullanıcı raporu:
|
|
||||||
// "eklenen bölümün 19.8 gb demesine rağmen bunu boş alandan
|
|
||||||
// düşmedi".
|
// düşmedi".
|
||||||
//
|
//
|
||||||
|
// düşmedi".
|
||||||
|
//
|
||||||
|
// REGRESYON 3 (kullanıcı: "bir alanı sildim boş alan olarak
|
||||||
|
// doğru okudu, sonrasında o boş alanı yeni bölüm diyerek /
|
||||||
|
// dizin yaptım… ama boş alan duruyor yerinde, yeni oluşturduğumda
|
||||||
|
// duruyor"): REGRESYON 2'nin düzeltmesi YALNIZCA bu `else if`
|
||||||
|
// dalına uygulanmıştı. Silinen bölümün yerine **döngü içinde**
|
||||||
|
// basılan satır `has_symbolic`'e BAKMIYORDU. `/` "Kalan Alan"
|
||||||
|
// olduğu için semboliktir ve alanın tamamını alır; buna rağmen
|
||||||
|
// satır diskin tamamını "boş" gösteriyordu.
|
||||||
|
//
|
||||||
|
// Çözüm: `show_free` TEK koşul ve üç basış yerinin de ortak
|
||||||
|
// koşulu. Koşulu yer yer yazmak bu sınıf hatayı kaçınılmaz
|
||||||
|
// kılıyordu — üçüncü kez düzeltmek zorunda kaldık.
|
||||||
|
//
|
||||||
// `first_idx: None` burada "seçilemez" DEĞİL demektir; yalnızca
|
// `first_idx: None` burada "seçilemez" DEĞİL demektir; yalnızca
|
||||||
// temsil ettiği silinmiş bir tanım yoktur. Tıklanabilirdir
|
// temsil ettiği silinmiş bir tanım yoktur. Tıklanabilirdir
|
||||||
// (`global_idx == None` dalı `selected_free` tutar ve
|
// (`global_idx == None` dalı `selected_free` tutar ve
|
||||||
@@ -4027,6 +4044,61 @@ mod free_space_tests {
|
|||||||
|
|
||||||
// ── "Kalan Alan" (sembolik) tanımlar ───────────────────────
|
// ── "Kalan Alan" (sembolik) tanımlar ───────────────────────
|
||||||
|
|
||||||
|
/// ⭐ Kullanıcının senaryosu: bir alanı sildi → boş alan DOĞRU
|
||||||
|
/// göründü → o boş alandan "Yeni Bölüm" ile `/` yaptı → boş alan
|
||||||
|
/// **yerinde durdu**, hem de yeni bölümün yanında.
|
||||||
|
///
|
||||||
|
/// REGRESYON: sembolik tanım kuralı (`has_symbolic`) yalnızca
|
||||||
|
/// sondaki `else if` dalına uygulanmıştı. Silinen bölümün yerine
|
||||||
|
/// **döngü içinde** basılan satır kuralı görmüyordu. `/` "Kalan
|
||||||
|
/// Alan" olduğu için semboliktir (alanın tamamını alır) ama satır
|
||||||
|
/// yine de diskin tamamını "boş" gösteriyordu.
|
||||||
|
#[test]
|
||||||
|
fn creating_root_in_a_freed_area_consumes_the_free_row() {
|
||||||
|
let mut dead = part("/dev/sdb2", 100_000, FsType::Ext4, "/");
|
||||||
|
dead.delete = true; // kullanıcı sildi
|
||||||
|
let mut root = part("/dev/sdb3", 0, FsType::Ext4, "/");
|
||||||
|
root.orig_device = String::new(); // "Kalan Alan" → sembolik
|
||||||
|
let parts = vec![
|
||||||
|
part("/dev/sdb1", 1_024, FsType::Fat32, "/boot/efi"),
|
||||||
|
dead,
|
||||||
|
root,
|
||||||
|
];
|
||||||
|
let rows = build_table_rows(&parts, "/dev/sdb", 500_000);
|
||||||
|
|
||||||
|
assert!(
|
||||||
|
free_mb_of(&rows).is_empty(),
|
||||||
|
"sembolik / alanın tamamını alıyor, boş alan satırı kalmamalı: {:?}",
|
||||||
|
free_mb_of(&rows)
|
||||||
|
);
|
||||||
|
assert_eq!(
|
||||||
|
rows.len(),
|
||||||
|
2,
|
||||||
|
"sdb1 + yeni / olmalı, boş alan satırı olmamalı: {}",
|
||||||
|
rows.len()
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Aynı senaryo ama yerine SABİT boyutlu bölüm konursa boş alan
|
||||||
|
/// **kalır** ve miktar doğru düşer — sembolik değil, gerçek yer
|
||||||
|
/// vardır.
|
||||||
|
#[test]
|
||||||
|
fn fixed_size_partition_in_a_freed_area_keeps_a_correct_free_row() {
|
||||||
|
let mut dead = part("/dev/sdb2", 100_000, FsType::Ext4, "/");
|
||||||
|
dead.delete = true;
|
||||||
|
let mut data = part("/dev/sdb3", 50_000, FsType::Ntfs, "");
|
||||||
|
data.orig_device = String::new();
|
||||||
|
let parts = vec![dead, data];
|
||||||
|
let rows = build_table_rows(&parts, "/dev/sdb", 500_000);
|
||||||
|
|
||||||
|
// 500_000 − 50_000 = 450_000 boş kalmalı
|
||||||
|
assert_eq!(
|
||||||
|
free_mb_of(&rows),
|
||||||
|
vec![450_000],
|
||||||
|
"sabit boyutlu bölüm boş alanı düşürmeli, satır kalmalı"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
/// Kullanıcı raporu: "eklenen bölümün 19.8 gb demesine rağmen
|
/// Kullanıcı raporu: "eklenen bölümün 19.8 gb demesine rağmen
|
||||||
/// bunu boş alandan düşmedi".
|
/// bunu boş alandan düşmedi".
|
||||||
///
|
///
|
||||||
|
|||||||
Reference in New Issue
Block a user