Get filesystem stats for files on Windows

This commit is contained in:
James Sturtevant
2021-02-18 17:03:58 -08:00
parent 269d62d895
commit c9eff4e906
6 changed files with 142 additions and 15 deletions

View File

@@ -21,6 +21,7 @@ package fs
import (
"fmt"
"os"
"path/filepath"
"syscall"
"unsafe"
@@ -40,6 +41,11 @@ func Info(path string) (int64, int64, int64, int64, int64, int64, error) {
var freeBytesAvailable, totalNumberOfBytes, totalNumberOfFreeBytes int64
var err error
// The equivalent linux call supports calls against files but the syscall for windows
// fails for files with error code: The directory name is invalid. (#99173)
// https://docs.microsoft.com/en-us/windows/win32/debug/system-error-codes--0-499-
// By always ensuring the directory path we meet all uses cases of this function
path = filepath.Dir(path)
ret, _, err := syscall.Syscall6(
procGetDiskFreeSpaceEx.Addr(),
4,

View File

@@ -21,8 +21,9 @@ import (
"io/ioutil"
"os"
"k8s.io/apimachinery/pkg/api/resource"
"testing"
"k8s.io/apimachinery/pkg/api/resource"
)
func TestDiskUsage(t *testing.T) {
@@ -54,8 +55,8 @@ func TestDiskUsage(t *testing.T) {
if err != nil {
t.Fatalf("TestDiskUsage failed: %s", err.Error())
}
file1 := dir1 + "/" + "test"
file2 := dir2 + "/" + "test"
file1 := tmpfile1.Name()
file2 := tmpfile2.Name()
fileInfo1, err := os.Lstat(file1)
if err != nil {
t.Fatalf("TestDiskUsage failed: %s", err.Error())
@@ -74,8 +75,55 @@ func TestDiskUsage(t *testing.T) {
if err != nil {
t.Fatalf("TestDiskUsage failed: %s", err.Error())
}
if size.Cmp(used) != 1 {
t.Fatalf("TestDiskUsage failed: %s", err.Error())
if size.Cmp(used) != 0 {
t.Fatalf("TestDiskUsage failed: expected 0, got %d", size.Cmp(used))
}
}
func TestInfo(t *testing.T) {
dir1, err := ioutil.TempDir("", "dir_1")
if err != nil {
t.Fatalf("TestInfo failed: %s", err.Error())
}
defer os.RemoveAll(dir1)
// should pass for folder path
availablebytes, capacity, usage, inodesTotal, inodesFree, inodeUsage, err := Info(dir1)
if err != nil {
t.Errorf("Info() should not error = %v", err)
return
}
validateInfo(t, availablebytes, capacity, usage, inodesTotal, inodeUsage, inodesFree)
// should pass for file
tmpfile1, err := ioutil.TempFile(dir1, "test")
if _, err = tmpfile1.WriteString("just for testing"); err != nil {
t.Fatalf("TestInfo failed: %s", err.Error())
}
availablebytes, capacity, usage, inodesTotal, inodesFree, inodeUsage, err = Info(tmpfile1.Name())
validateInfo(t, availablebytes, capacity, usage, inodesTotal, inodeUsage, inodesFree)
}
func validateInfo(t *testing.T, availablebytes int64, capacity int64, usage int64, inodesTotal int64, inodeUsage int64, inodesFree int64) {
// All of these should be greater than zero on a real system
if availablebytes <= 0 {
t.Errorf("Info() availablebytes should be greater than 0, got %v", availablebytes)
}
if capacity <= 0 {
t.Errorf("Info() capacity should be greater than 0, got %v", capacity)
}
if usage <= 0 {
t.Errorf("Info() got usage should be greater than 0, got %v", usage)
}
// inodes will always be zero for Windows
if inodesTotal != 0 {
t.Errorf("Info() inodesTotal = %v, want %v", inodeUsage, 0)
}
if inodesFree != 0 {
t.Errorf("Info() inodesFree = %v, want %v", inodesFree, 0)
}
if inodeUsage != 0 {
t.Errorf("Info() inodeUsage = %v, want %v", inodeUsage, 0)
}
}