- Add platform-specific implementations for Windows, BSD systems - Create platform-specific disk space checking with proper syscalls - Add Windows process cleanup using tasklist/taskkill - Add BSD-specific Statfs_t field handling (F_blocks, F_bavail, F_bsize) - Support 9/10 target platforms (Linux, Windows, macOS, FreeBSD, OpenBSD) - Process cleanup now works on all Unix-like systems and Windows - Phase 2 TUI improvements compatible across platforms
132 lines
3.2 KiB
Go
132 lines
3.2 KiB
Go
//go:build windows
|
|
// +build windows
|
|
|
|
package checks
|
|
|
|
import (
|
|
"fmt"
|
|
"path/filepath"
|
|
"syscall"
|
|
"unsafe"
|
|
)
|
|
|
|
var (
|
|
kernel32 = syscall.NewLazyDLL("kernel32.dll")
|
|
getDiskFreeSpaceEx = kernel32.NewProc("GetDiskFreeSpaceExW")
|
|
)
|
|
|
|
// CheckDiskSpace checks available disk space for a given path (Windows implementation)
|
|
func CheckDiskSpace(path string) *DiskSpaceCheck {
|
|
// Get absolute path
|
|
absPath, err := filepath.Abs(path)
|
|
if err != nil {
|
|
absPath = path
|
|
}
|
|
|
|
// Get the drive root (e.g., "C:\")
|
|
vol := filepath.VolumeName(absPath)
|
|
if vol == "" {
|
|
// If no volume, try current directory
|
|
vol = "."
|
|
}
|
|
|
|
var freeBytesAvailable, totalNumberOfBytes, totalNumberOfFreeBytes uint64
|
|
|
|
// Call Windows API
|
|
pathPtr, _ := syscall.UTF16PtrFromString(vol)
|
|
ret, _, _ := getDiskFreeSpaceEx.Call(
|
|
uintptr(unsafe.Pointer(pathPtr)),
|
|
uintptr(unsafe.Pointer(&freeBytesAvailable)),
|
|
uintptr(unsafe.Pointer(&totalNumberOfBytes)),
|
|
uintptr(unsafe.Pointer(&totalNumberOfFreeBytes)))
|
|
|
|
if ret == 0 {
|
|
// API call failed, return error state
|
|
return &DiskSpaceCheck{
|
|
Path: absPath,
|
|
Critical: true,
|
|
Sufficient: false,
|
|
}
|
|
}
|
|
|
|
// Calculate usage
|
|
usedBytes := totalNumberOfBytes - totalNumberOfFreeBytes
|
|
usedPercent := float64(usedBytes) / float64(totalNumberOfBytes) * 100
|
|
|
|
check := &DiskSpaceCheck{
|
|
Path: absPath,
|
|
TotalBytes: totalNumberOfBytes,
|
|
AvailableBytes: freeBytesAvailable,
|
|
UsedBytes: usedBytes,
|
|
UsedPercent: usedPercent,
|
|
}
|
|
|
|
// Determine status thresholds
|
|
check.Critical = usedPercent >= 95
|
|
check.Warning = usedPercent >= 80 && !check.Critical
|
|
check.Sufficient = !check.Critical && !check.Warning
|
|
|
|
return check
|
|
}
|
|
|
|
// CheckDiskSpaceForRestore checks if there's enough space for restore (needs 4x archive size)
|
|
func CheckDiskSpaceForRestore(path string, archiveSize int64) *DiskSpaceCheck {
|
|
check := CheckDiskSpace(path)
|
|
requiredBytes := uint64(archiveSize) * 4 // Account for decompression
|
|
|
|
// Override status based on required space
|
|
if check.AvailableBytes < requiredBytes {
|
|
check.Critical = true
|
|
check.Sufficient = false
|
|
check.Warning = false
|
|
} else if check.AvailableBytes < requiredBytes*2 {
|
|
check.Warning = true
|
|
check.Sufficient = false
|
|
}
|
|
|
|
return check
|
|
}
|
|
|
|
// FormatDiskSpaceMessage creates a user-friendly disk space message
|
|
func FormatDiskSpaceMessage(check *DiskSpaceCheck) string {
|
|
var status string
|
|
var icon string
|
|
|
|
if check.Critical {
|
|
status = "CRITICAL"
|
|
icon = "❌"
|
|
} else if check.Warning {
|
|
status = "WARNING"
|
|
icon = "⚠️ "
|
|
} else {
|
|
status = "OK"
|
|
icon = "✓"
|
|
}
|
|
|
|
msg := fmt.Sprintf(`📊 Disk Space Check (%s):
|
|
Path: %s
|
|
Total: %s
|
|
Available: %s (%.1f%% used)
|
|
%s Status: %s`,
|
|
status,
|
|
check.Path,
|
|
formatBytes(check.TotalBytes),
|
|
formatBytes(check.AvailableBytes),
|
|
check.UsedPercent,
|
|
icon,
|
|
status)
|
|
|
|
if check.Critical {
|
|
msg += "\n \n ⚠️ CRITICAL: Insufficient disk space!"
|
|
msg += "\n Operation blocked. Free up space before continuing."
|
|
} else if check.Warning {
|
|
msg += "\n \n ⚠️ WARNING: Low disk space!"
|
|
msg += "\n Backup may fail if database is larger than estimated."
|
|
} else {
|
|
msg += "\n \n ✓ Sufficient space available"
|
|
}
|
|
|
|
return msg
|
|
}
|
|
|