Skip to content

Commit

Permalink
Implement free space check
Browse files Browse the repository at this point in the history
  • Loading branch information
Enrico204 committed Sep 6, 2021
1 parent bd13001 commit 3c1b00f
Show file tree
Hide file tree
Showing 3 changed files with 76 additions and 6 deletions.
28 changes: 23 additions & 5 deletions repo/repo.go
Original file line number Diff line number Diff line change
Expand Up @@ -151,9 +151,9 @@ func (h *Handler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
err := h.RepoHealth()
if err != nil {
if h.opt.Debug {
log.Println("health check error: ", err)
log.Println("health check error:", err)
}
w.WriteHeader(http.StatusInternalServerError)
h.internalServerError(w, err)
} else {
w.WriteHeader(http.StatusOK)
}
Expand Down Expand Up @@ -773,13 +773,31 @@ func (h *Handler) RepoHealth() error {
// Check if the repo is writable [Linux/UNIX only code]
pathIsWritable, err := isWritable(h.path)
if err != nil {
if h.opt.Debug {
log.Println("repository path check error:", err)
}
return err
} else if !pathIsWritable {
return errors.New("Repository path is not writable")
return errors.New("repository path is not writable")
}
if h.opt.Debug {
log.Println("repository path is writable")
}

// Check if there is free space left
// TODO
// Check if there is some free space left
freeBytes, err := getFreeSpace(h.path)
if err != nil {
if h.opt.Debug {
log.Println("free space check error:", err)
}
return err
}
if h.opt.Debug {
log.Println("free space in bytes:", freeBytes)
}
if freeBytes < 8*1024*1024 {
return errors.New("free space is too low")
}

return nil
}
25 changes: 24 additions & 1 deletion repo/repo_health_unix.go
Original file line number Diff line number Diff line change
@@ -1,10 +1,33 @@
//go:build !windows
// +build !windows

package repo

import "golang.org/x/sys/unix"
import (
"errors"
"io/fs"
"syscall"

"golang.org/x/sys/unix"
)

func isWritable(path string) (bool, error) {
err := unix.Access(path, unix.W_OK)
var err2 syscall.Errno
if errors.As(err, &err2) && err2.Is(fs.ErrPermission) {
return false, nil
}
return err == nil, err
}

func getFreeSpace(path string) (uint64, error) {
var stat unix.Statfs_t

err := unix.Statfs(path, &stat)
if err != nil {
return 0, err
}

// Available blocks * size per block = available space in bytes
return stat.Bavail * uint64(stat.Bsize), nil
}
29 changes: 29 additions & 0 deletions repo/repo_health_windows.go
Original file line number Diff line number Diff line change
@@ -1,15 +1,21 @@
package repo

import (
"errors"
"syscall"
"unsafe"

"github.com/itchio/ox/syscallex"
"github.com/itchio/ox/winox"
"golang.org/x/sys/windows"
)

var (
advapi32DLL = syscall.NewLazyDLL("advapi32.dll")
impersonateSelfProc = advapi32DLL.NewProc("ImpersonateSelf")

kernel32DLL = syscall.NewLazyDLL("kernel32.dll")
getDiskFreeSpaceExWProc = kernel32DLL.NewProc("GetDiskFreeSpaceExW")
)

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

func GetDiskFreeSpaceExW(path string) (int64, error) {
var freeBytes int64

_, _, err := getDiskFreeSpaceExWProc.Call(
uintptr(unsafe.Pointer(windows.StringToUTF16Ptr(path))),
uintptr(unsafe.Pointer(&freeBytes)),
0,
0,
)
if err != syscall.Errno(0) {
return 0, err
}
return freeBytes, nil
}

func isWritable(path string) (bool, error) {
if _, err := ImpersonateSelf(syscallex.SecurityImpersonation); err != nil {
return false, err
Expand All @@ -45,3 +66,11 @@ func isWritable(path string) (bool, error) {

return winox.UserHasPermission(impersonationToken, winox.RightsRead|winox.RightsWrite, path)
}

func getFreeSpace(path string) (uint64, error) {
freeBytes, err := GetDiskFreeSpaceExW(path)
if err == nil && freeBytes < 0 {
return 0, errors.New("free space can't be negative")
}
return uint64(freeBytes), err
}

0 comments on commit 3c1b00f

Please sign in to comment.