86 lines
2.5 KiB
Go
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)
|
|
}
|