v0.12.5: drive-type-aware cross-drive backup validation
Fix cross-drive backup failing for system-drive destinations. The /mnt/hdd_placeholder folder is on the internal SSD, so IsMountPoint() returned false and the old code hard-blocked it. - ValidateDestination() (crossdrive.go): onSystemDrive flag replaces boolean-only check; system drives require ≥10 GB free and <90% usage to protect OS stability; external drives just need ≥100 MB free. - CheckBackupDestination() (mounts_linux.go): Tier 4 now branches on h.SystemDrive; system drive blocks at <10 GB free or ≥90% usage (matches runner enforcement); external drive unchanged (warn 90%, block 95%). Removes the && h.Severity == "ok" guard that was preventing system-drive critical messages from overriding warnings. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -159,9 +159,9 @@ func (r *CrossDriveRunner) IsRunning(stackName string) bool {
|
||||
}
|
||||
|
||||
// ValidateDestination checks that the destination path exists, is writable,
|
||||
// and has sufficient free space (at least 100MB).
|
||||
// A non-mount-point destination (e.g. a folder on the system drive) is allowed
|
||||
// with a logged warning — consistent with the web UI's CheckBackupDestination.
|
||||
// and has sufficient free space. System-drive destinations get stricter limits
|
||||
// (≥10 GB free, <90% used) to protect OS stability; external drives just need
|
||||
// ≥100 MB. Non-mount-point destinations are allowed with a logged warning.
|
||||
func (r *CrossDriveRunner) ValidateDestination(path string) error {
|
||||
if path == "" {
|
||||
return fmt.Errorf("destination path is empty")
|
||||
@@ -169,15 +169,28 @@ func (r *CrossDriveRunner) ValidateDestination(path string) error {
|
||||
if _, err := os.Stat(path); os.IsNotExist(err) {
|
||||
return fmt.Errorf("destination %s does not exist", path)
|
||||
}
|
||||
if !system.IsMountPoint(path) {
|
||||
onSystemDrive := !system.IsMountPoint(path)
|
||||
if onSystemDrive {
|
||||
r.logger.Printf("[WARN] Destination %s is not a separate mount point (system drive) — backup will proceed but data is not protected against drive failure", path)
|
||||
}
|
||||
if !system.IsWritable(path) {
|
||||
return fmt.Errorf("destination %s is not writable", path)
|
||||
}
|
||||
di := system.GetDiskUsage(path)
|
||||
if di != nil && di.AvailGB < 0.1 {
|
||||
return fmt.Errorf("destination %s has insufficient free space (%.1f GB)", path, di.AvailGB)
|
||||
if di := system.GetDiskUsage(path); di != nil {
|
||||
if onSystemDrive {
|
||||
// System drive: protect OS stability — require ≥10 GB free and <90% used
|
||||
if di.AvailGB < 10 {
|
||||
return fmt.Errorf("destination %s is on the system drive with only %.1f GB free — at least 10 GB required to protect OS stability", path, di.AvailGB)
|
||||
}
|
||||
if di.UsedPercent >= 90 {
|
||||
return fmt.Errorf("destination %s is on the system drive at %.0f%% capacity — maximum 90%% allowed", path, di.UsedPercent)
|
||||
}
|
||||
} else {
|
||||
// External drive: just ensure it's not completely full
|
||||
if di.AvailGB < 0.1 {
|
||||
return fmt.Errorf("destination %s has insufficient free space (%.1f GB free)", path, di.AvailGB)
|
||||
}
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -172,13 +172,28 @@ func CheckBackupDestination(path string) DestinationHealth {
|
||||
if di := GetDiskUsage(path); di != nil {
|
||||
h.UsedPercent = di.UsedPercent
|
||||
h.FreeGB = di.AvailGB
|
||||
if di.UsedPercent >= 95 {
|
||||
h.Warning = fmt.Sprintf("A mentési meghajtó megtelt (%.0f%% használt)!", di.UsedPercent)
|
||||
h.Blocked = true
|
||||
h.Severity = "critical"
|
||||
} else if di.UsedPercent >= 90 && h.Severity == "ok" {
|
||||
h.Warning = fmt.Sprintf("A mentési meghajtó majdnem megtelt (%.0f%% használt).", di.UsedPercent)
|
||||
h.Severity = "warning"
|
||||
if h.SystemDrive {
|
||||
// System drive: stricter limits to protect OS stability
|
||||
if di.AvailGB < 10 {
|
||||
h.Warning = fmt.Sprintf("A rendszermeghajtón csak %.1f GB szabad — legalább 10 GB szükséges a rendszer stabilitásához!", di.AvailGB)
|
||||
h.Blocked = true
|
||||
h.Severity = "critical"
|
||||
} else if di.UsedPercent >= 90 {
|
||||
h.Warning = fmt.Sprintf("A rendszermeghajtó %.0f%%-ban megtelt — maximum 90%% megengedett.", di.UsedPercent)
|
||||
h.Blocked = true
|
||||
h.Severity = "critical"
|
||||
}
|
||||
// If neither triggers, keep the Tier 3 system-drive warning
|
||||
} else {
|
||||
// External drive: original thresholds
|
||||
if di.UsedPercent >= 95 {
|
||||
h.Warning = fmt.Sprintf("A mentési meghajtó megtelt (%.0f%% használt)!", di.UsedPercent)
|
||||
h.Blocked = true
|
||||
h.Severity = "critical"
|
||||
} else if di.UsedPercent >= 90 {
|
||||
h.Warning = fmt.Sprintf("A mentési meghajtó majdnem megtelt (%.0f%% használt).", di.UsedPercent)
|
||||
h.Severity = "warning"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user