cri-o/utils/filesystem.go
Bo Zhao bfaf35b063 Implement the stats for the image_fs_info command
Signed-off-by: Bo Zhao <bzhao@lyft.com>
2018-01-29 10:01:19 -08:00

109 lines
2.5 KiB
Go

package utils
import (
"fmt"
"golang.org/x/sys/unix"
"io/ioutil"
"os"
"path/filepath"
"strings"
"syscall"
"github.com/docker/docker/pkg/mount"
)
// GetDiskUsageStats accepts a path to a directory or file
// and returns the number of bytes and inodes used by the path
func GetDiskUsageStats(path string) (uint64, uint64, error) {
var dirSize, inodeCount uint64
err := filepath.Walk(path, func(path string, info os.FileInfo, err error) error {
fileStat, error := os.Lstat(path)
if error != nil {
if fileStat.Mode()&os.ModeSymlink != 0 {
// Is a symlink; no error should be returned
return nil
}
return error
}
dirSize += uint64(info.Size())
inodeCount++
return nil
})
if err != nil {
return 0, 0, err
}
return dirSize, inodeCount, err
}
// GetDeviceUUIDFromPath accepts a path, and will find the device
// corresponding to the path and return the UUID of that device
func GetDeviceUUIDFromPath(devicePath string) (string, error) {
const dir = "/dev/disk/by-uuid"
if _, err := os.Stat(dir); os.IsNotExist(err) {
return "", nil
}
files, err := ioutil.ReadDir(dir)
if err != nil {
return "", err
}
for _, file := range files {
path := filepath.Join(dir, file.Name())
target, err := os.Readlink(path)
if err != nil {
continue
}
device, err := filepath.Abs(filepath.Join(dir, target))
if err != nil {
return "", fmt.Errorf("failed to resolve the absolute path of %q", filepath.Join(dir, target))
}
if strings.Compare(device, devicePath) == 0 {
return file.Name(), nil
}
}
return "", fmt.Errorf("device path %s not found", devicePath)
}
// GetStattFromPath is a helper function that returns the Stat_t
// object for a given path
func GetStattFromPath(path string) (syscall.Stat_t, error) {
statInfo := syscall.Stat_t{}
err := syscall.Lstat(path, &statInfo)
if err != nil {
return statInfo, err
}
return statInfo, nil
}
// GetDeviceNameFromPath iterates through the mounts and matches
// the one that the provided path is on
func GetDeviceNameFromPath(path string) (string, error) {
statInfo, err := GetStattFromPath(path)
if err != nil {
return "", err
}
mounts, err := mount.GetMounts()
if err != nil {
return "", err
}
queryMajor := int(unix.Major(uint64(statInfo.Dev)))
queryMinor := int(unix.Minor(uint64(statInfo.Dev)))
for _, mount := range mounts {
if mount.Minor == queryMinor && mount.Major == queryMajor {
return mount.Source, nil
}
}
return "", fmt.Errorf("no match found")
}