Files

86 lines
2.5 KiB
Go

package scoutfs
import (
"fmt"
"os"
"unsafe"
)
// SET_ATTR_X mask flags from kmod/src/ioctl.h.
const (
SetAttrDataVersion uint64 = 1 << 0
SetAttrOffline uint64 = 1 << 1
SetAttrSize uint64 = 1 << 2
SetAttrCtime uint64 = 1 << 3
SetAttrCrtime uint64 = 1 << 4
SetAttrBits uint64 = 1 << 5
SetAttrProjectID uint64 = 1 << 6
)
// FetchStatMore retrieves extended inode metadata for the file at the given path.
func (c *Client) FetchStatMore(path string) (*StatMore, error) {
f, err := openPath(path)
if err != nil {
return nil, fmt.Errorf("stat more for %q: %w", path, err)
}
defer f.Close()
var sm StatMore
if err := ioctlRaw(f.Fd(), iocStatMore, unsafe.Pointer(&sm)); err != nil {
return nil, fmt.Errorf("stat more ioctl for %q: %w", path, err)
}
return &sm, nil
}
// FetchStatMoreByFD retrieves extended inode metadata using an open file descriptor.
func (c *Client) FetchStatMoreByFD(fd uintptr) (*StatMore, error) {
var sm StatMore
if err := ioctlRaw(fd, iocStatMore, unsafe.Pointer(&sm)); err != nil {
return nil, fmt.Errorf("stat more ioctl: %w", err)
}
return &sm, nil
}
// FetchAttrX retrieves extended inode attributes with selective masking.
func (c *Client) FetchAttrX(path string, mask uint64) (*InodeAttrX, error) {
f, err := openPath(path)
if err != nil {
return nil, fmt.Errorf("get attr x for %q: %w", path, err)
}
defer f.Close()
attr := InodeAttrX{XMask: mask}
if err := ioctlRaw(f.Fd(), iocGetAttrX, unsafe.Pointer(&attr)); err != nil {
return nil, fmt.Errorf("get attr x ioctl for %q: %w", path, err)
}
return &attr, nil
}
// SetAttrX modifies extended inode attributes with selective masking.
func (c *Client) SetAttrX(path string, attr *InodeAttrX) error {
f, err := openPath(path)
if err != nil {
return fmt.Errorf("set attr x for %q: %w", path, err)
}
defer f.Close()
if err := ioctlRaw(f.Fd(), iocSetAttrX, unsafe.Pointer(attr)); err != nil {
return fmt.Errorf("set attr x ioctl for %q: %w", path, err)
}
return nil
}
// SetFileOffline truncates a regular file to the given size and marks all its
// data blocks as offline via SET_ATTR_X. The file must already exist.
func (c *Client) SetFileOffline(path string, size uint64, dataVersion uint64) error {
if err := os.Truncate(path, int64(size)); err != nil {
return fmt.Errorf("truncating %q to %d: %w", path, size, err)
}
attr := InodeAttrX{
XMask: SetAttrOffline | SetAttrDataVersion,
DataVersion: dataVersion,
}
return c.SetAttrX(path, &attr)
}