Skip to content

Commit 0678174

Browse files
committed
fix: add cross-platform support for disk space checks
Split diskspace.go into platform-specific files: - diskspace_unix.go for Unix/Linux/macOS - diskspace_windows.go for Windows This fixes the release build failure where Windows builds were failing due to undefined syscall.Statfs (Unix-only).
1 parent eb5a4d0 commit 0678174

File tree

2 files changed

+113
-0
lines changed

2 files changed

+113
-0
lines changed
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
//go:build unix
2+
13
// ABOUTME: Disk space checking and management utilities.
24
// ABOUTME: Ensures sufficient disk space before downloads with configurable buffer.
35
package pivnet

pkg/pivnet/diskspace_windows.go

Lines changed: 111 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,111 @@
1+
//go:build windows
2+
3+
// ABOUTME: Disk space checking and management utilities for Windows.
4+
// ABOUTME: Ensures sufficient disk space before downloads with configurable buffer.
5+
package pivnet
6+
7+
import (
8+
"fmt"
9+
"os"
10+
"path/filepath"
11+
"unsafe"
12+
13+
"golang.org/x/sys/windows"
14+
)
15+
16+
// DiskManager handles disk space checks
17+
type DiskManager struct {
18+
minFreeSpaceGB int64
19+
}
20+
21+
// NewDiskManager creates a new disk space manager
22+
func NewDiskManager(minFreeSpaceGB int64) *DiskManager {
23+
return &DiskManager{
24+
minFreeSpaceGB: minFreeSpaceGB,
25+
}
26+
}
27+
28+
// HasEnoughSpace checks if there's enough disk space for a download
29+
func (d *DiskManager) HasEnoughSpace(path string, fileSize int64) (bool, error) {
30+
// If path doesn't exist, check parent directory
31+
checkPath := path
32+
if _, err := os.Stat(path); os.IsNotExist(err) {
33+
checkPath = filepath.Dir(path)
34+
// Keep going up until we find an existing directory
35+
for {
36+
if _, err := os.Stat(checkPath); err == nil {
37+
break
38+
}
39+
parent := filepath.Dir(checkPath)
40+
if parent == checkPath {
41+
// Reached root without finding existing dir
42+
return false, fmt.Errorf("no existing directory found in path hierarchy")
43+
}
44+
checkPath = parent
45+
}
46+
}
47+
48+
availableBytes, err := d.getAvailableSpaceWindows(checkPath)
49+
if err != nil {
50+
return false, err
51+
}
52+
53+
// Required space: file size + minimum buffer
54+
requiredBytes := d.calculateRequired(fileSize)
55+
56+
return availableBytes >= uint64(requiredBytes), nil
57+
}
58+
59+
// GetAvailableSpace returns available space in bytes
60+
func (d *DiskManager) GetAvailableSpace(path string) (int64, error) {
61+
// If path doesn't exist, check parent directory
62+
checkPath := path
63+
if _, err := os.Stat(path); os.IsNotExist(err) {
64+
checkPath = filepath.Dir(path)
65+
for {
66+
if _, err := os.Stat(checkPath); err == nil {
67+
break
68+
}
69+
parent := filepath.Dir(checkPath)
70+
if parent == checkPath {
71+
return 0, fmt.Errorf("no existing directory found in path hierarchy")
72+
}
73+
checkPath = parent
74+
}
75+
}
76+
77+
availableBytes, err := d.getAvailableSpaceWindows(checkPath)
78+
if err != nil {
79+
return 0, err
80+
}
81+
82+
return int64(availableBytes), nil
83+
}
84+
85+
// getAvailableSpaceWindows uses Windows API to get disk space
86+
func (d *DiskManager) getAvailableSpaceWindows(path string) (uint64, error) {
87+
var freeBytesAvailable, totalBytes, totalFreeBytes uint64
88+
89+
pathPtr, err := windows.UTF16PtrFromString(path)
90+
if err != nil {
91+
return 0, fmt.Errorf("failed to convert path: %w", err)
92+
}
93+
94+
err = windows.GetDiskFreeSpaceEx(
95+
pathPtr,
96+
(*uint64)(unsafe.Pointer(&freeBytesAvailable)),
97+
(*uint64)(unsafe.Pointer(&totalBytes)),
98+
(*uint64)(unsafe.Pointer(&totalFreeBytes)),
99+
)
100+
if err != nil {
101+
return 0, fmt.Errorf("failed to check disk space: %w", err)
102+
}
103+
104+
return freeBytesAvailable, nil
105+
}
106+
107+
// calculateRequired calculates total space needed (file + buffer)
108+
func (d *DiskManager) calculateRequired(fileSize int64) int64 {
109+
bufferBytes := d.minFreeSpaceGB * 1024 * 1024 * 1024
110+
return fileSize + bufferBytes
111+
}

0 commit comments

Comments
 (0)