Skip to content

Commit 3c1b00f

Browse files
committed
Implement free space check
1 parent bd13001 commit 3c1b00f

File tree

3 files changed

+76
-6
lines changed

3 files changed

+76
-6
lines changed

repo/repo.go

Lines changed: 23 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -151,9 +151,9 @@ func (h *Handler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
151151
err := h.RepoHealth()
152152
if err != nil {
153153
if h.opt.Debug {
154-
log.Println("health check error: ", err)
154+
log.Println("health check error:", err)
155155
}
156-
w.WriteHeader(http.StatusInternalServerError)
156+
h.internalServerError(w, err)
157157
} else {
158158
w.WriteHeader(http.StatusOK)
159159
}
@@ -773,13 +773,31 @@ func (h *Handler) RepoHealth() error {
773773
// Check if the repo is writable [Linux/UNIX only code]
774774
pathIsWritable, err := isWritable(h.path)
775775
if err != nil {
776+
if h.opt.Debug {
777+
log.Println("repository path check error:", err)
778+
}
776779
return err
777780
} else if !pathIsWritable {
778-
return errors.New("Repository path is not writable")
781+
return errors.New("repository path is not writable")
782+
}
783+
if h.opt.Debug {
784+
log.Println("repository path is writable")
779785
}
780786

781-
// Check if there is free space left
782-
// TODO
787+
// Check if there is some free space left
788+
freeBytes, err := getFreeSpace(h.path)
789+
if err != nil {
790+
if h.opt.Debug {
791+
log.Println("free space check error:", err)
792+
}
793+
return err
794+
}
795+
if h.opt.Debug {
796+
log.Println("free space in bytes:", freeBytes)
797+
}
798+
if freeBytes < 8*1024*1024 {
799+
return errors.New("free space is too low")
800+
}
783801

784802
return nil
785803
}

repo/repo_health_unix.go

Lines changed: 24 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,33 @@
1+
//go:build !windows
12
// +build !windows
23

34
package repo
45

5-
import "golang.org/x/sys/unix"
6+
import (
7+
"errors"
8+
"io/fs"
9+
"syscall"
10+
11+
"golang.org/x/sys/unix"
12+
)
613

714
func isWritable(path string) (bool, error) {
815
err := unix.Access(path, unix.W_OK)
16+
var err2 syscall.Errno
17+
if errors.As(err, &err2) && err2.Is(fs.ErrPermission) {
18+
return false, nil
19+
}
920
return err == nil, err
1021
}
22+
23+
func getFreeSpace(path string) (uint64, error) {
24+
var stat unix.Statfs_t
25+
26+
err := unix.Statfs(path, &stat)
27+
if err != nil {
28+
return 0, err
29+
}
30+
31+
// Available blocks * size per block = available space in bytes
32+
return stat.Bavail * uint64(stat.Bsize), nil
33+
}

repo/repo_health_windows.go

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,21 @@
11
package repo
22

33
import (
4+
"errors"
45
"syscall"
6+
"unsafe"
57

68
"github.com/itchio/ox/syscallex"
79
"github.com/itchio/ox/winox"
10+
"golang.org/x/sys/windows"
811
)
912

1013
var (
1114
advapi32DLL = syscall.NewLazyDLL("advapi32.dll")
1215
impersonateSelfProc = advapi32DLL.NewProc("ImpersonateSelf")
16+
17+
kernel32DLL = syscall.NewLazyDLL("kernel32.dll")
18+
getDiskFreeSpaceExWProc = kernel32DLL.NewProc("GetDiskFreeSpaceExW")
1319
)
1420

1521
func ImpersonateSelf(impersonationLevel uint64) (bool, error) {
@@ -22,6 +28,21 @@ func ImpersonateSelf(impersonationLevel uint64) (bool, error) {
2228
return syscall.Handle(r1) == 1, nil
2329
}
2430

31+
func GetDiskFreeSpaceExW(path string) (int64, error) {
32+
var freeBytes int64
33+
34+
_, _, err := getDiskFreeSpaceExWProc.Call(
35+
uintptr(unsafe.Pointer(windows.StringToUTF16Ptr(path))),
36+
uintptr(unsafe.Pointer(&freeBytes)),
37+
0,
38+
0,
39+
)
40+
if err != syscall.Errno(0) {
41+
return 0, err
42+
}
43+
return freeBytes, nil
44+
}
45+
2546
func isWritable(path string) (bool, error) {
2647
if _, err := ImpersonateSelf(syscallex.SecurityImpersonation); err != nil {
2748
return false, err
@@ -45,3 +66,11 @@ func isWritable(path string) (bool, error) {
4566

4667
return winox.UserHasPermission(impersonationToken, winox.RightsRead|winox.RightsWrite, path)
4768
}
69+
70+
func getFreeSpace(path string) (uint64, error) {
71+
freeBytes, err := GetDiskFreeSpaceExW(path)
72+
if err == nil && freeBytes < 0 {
73+
return 0, errors.New("free space can't be negative")
74+
}
75+
return uint64(freeBytes), err
76+
}

0 commit comments

Comments
 (0)