mirror of
https://github.com/versity/scoutfs-go.git
synced 2026-08-15 10:26:02 +00:00
add inode to path and open by id
This commit is contained in:
@@ -27,13 +27,18 @@ type server struct {
|
||||
}
|
||||
|
||||
func queryPopulation(basedir string, update chan<- int) error {
|
||||
f, err := os.Open(path)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer f.Close()
|
||||
|
||||
h, err := scoutfs.NewQuery(basedir,
|
||||
scoutfs.ByMSeq(scoutfs.InodesEntry{},
|
||||
scoutfs.InodesEntry{Major: max64, Minor: max32, Ino: max64}))
|
||||
if err != nil {
|
||||
return fmt.Errorf("scoutfs new handle: %v", err)
|
||||
}
|
||||
defer h.Close()
|
||||
|
||||
count := 0
|
||||
for {
|
||||
|
||||
@@ -0,0 +1,37 @@
|
||||
// Copyright (c) 2018 Versity Software, Inc.
|
||||
//
|
||||
// Use of this source code is governed by a BSD-3-Clause license
|
||||
// that can be found in the LICENSE file in the root of the source
|
||||
// tree.
|
||||
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"log"
|
||||
"os"
|
||||
"strconv"
|
||||
|
||||
scoutfs "github.com/versity/scoutfs-go"
|
||||
)
|
||||
|
||||
func main() {
|
||||
if len(os.Args) != 3 || os.Args[1] == "-h" {
|
||||
fmt.Fprintln(os.Stderr, "usage:", os.Args[0], "<scoutfs mount point> <inode>")
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
f, err := os.Open(os.Args[1])
|
||||
if err != nil {
|
||||
log.Fatalln("error open mount:", err)
|
||||
}
|
||||
defer f.Close()
|
||||
|
||||
u, err := strconv.ParseUint(os.Args[2], 10, 64)
|
||||
if err != nil {
|
||||
log.Fatalln("error parsing inode:", err)
|
||||
}
|
||||
|
||||
s, err := scoutfs.InoToPath(f, u)
|
||||
fmt.Println(s)
|
||||
}
|
||||
@@ -0,0 +1,48 @@
|
||||
// Copyright (c) 2018 Versity Software, Inc.
|
||||
//
|
||||
// Use of this source code is governed by a BSD-3-Clause license
|
||||
// that can be found in the LICENSE file in the root of the source
|
||||
// tree.
|
||||
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"log"
|
||||
"os"
|
||||
"strconv"
|
||||
|
||||
scoutfs "github.com/versity/scoutfs-go"
|
||||
)
|
||||
|
||||
func main() {
|
||||
if len(os.Args) != 3 || os.Args[1] == "-h" {
|
||||
fmt.Fprintln(os.Stderr, "usage:", os.Args[0], "<scoutfs mount point> <inode>")
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
dirf, err := os.Open(os.Args[1])
|
||||
if err != nil {
|
||||
log.Fatalln("error open mount:", err)
|
||||
}
|
||||
defer dirf.Close()
|
||||
|
||||
u, err := strconv.ParseUint(os.Args[2], 10, 64)
|
||||
if err != nil {
|
||||
log.Fatalln("error parsing inode:", err)
|
||||
}
|
||||
|
||||
f, err := scoutfs.OpenByID(dirf, u, os.O_RDONLY)
|
||||
if err != nil {
|
||||
log.Fatalln("error open by id:", err)
|
||||
}
|
||||
|
||||
fi, err := f.Stat()
|
||||
if err != nil {
|
||||
log.Fatalln("error stat:", err)
|
||||
}
|
||||
|
||||
fmt.Println("Name:", fi.Name())
|
||||
fmt.Println("Size:", fi.Size())
|
||||
fmt.Println("Mode:", fi.Mode())
|
||||
}
|
||||
+39
-18
@@ -10,7 +10,6 @@ import (
|
||||
"bytes"
|
||||
"encoding/binary"
|
||||
"os"
|
||||
"syscall"
|
||||
"unsafe"
|
||||
)
|
||||
|
||||
@@ -38,12 +37,9 @@ type Time struct {
|
||||
// Specify query type with By*() option
|
||||
// (only 1 allowed, last one wins)
|
||||
// and specify batching with WithBatchSize()
|
||||
func NewQuery(path string, opts ...Option) (*Query, error) {
|
||||
f, err := os.Open(path)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// An open file within scoutfs is supplied for ioctls
|
||||
// (usually just the base mount point directory)
|
||||
func NewQuery(f *os.File, opts ...Option) *Query {
|
||||
q := &Query{
|
||||
//default batch size is 128
|
||||
batch: 128,
|
||||
@@ -54,7 +50,7 @@ func NewQuery(path string, opts ...Option) (*Query, error) {
|
||||
opt(q)
|
||||
}
|
||||
|
||||
return q, nil
|
||||
return q
|
||||
}
|
||||
|
||||
// Option sets various options for NewWalkHandle
|
||||
@@ -146,11 +142,6 @@ func (q *Query) Next() ([]InodesEntry, error) {
|
||||
return inodes, nil
|
||||
}
|
||||
|
||||
// Close queryHandle and cleanup
|
||||
func (q *Query) Close() {
|
||||
q.fsfd.Close()
|
||||
}
|
||||
|
||||
// StatMore returns scoutfs specific metadata for path
|
||||
func StatMore(path string) (Stat, error) {
|
||||
f, err := os.Open(path)
|
||||
@@ -169,10 +160,40 @@ func StatMore(path string) (Stat, error) {
|
||||
return s, nil
|
||||
}
|
||||
|
||||
func scoutfsctl(fd, cmd, ptr uintptr) (int, error) {
|
||||
count, _, err := syscall.Syscall(syscall.SYS_IOCTL, fd, cmd, ptr)
|
||||
if err != 0 {
|
||||
return 0, err
|
||||
// InoToPath converts an inode number to a path in the filesystem
|
||||
// An open file within scoutfs is supplied for ioctls
|
||||
// (usually just the base mount point directory)
|
||||
func InoToPath(dirfd *os.File, ino uint64) (string, error) {
|
||||
var res InoPathResult
|
||||
ip := InoPath{
|
||||
Ino: ino,
|
||||
ResultPtr: uint64(uintptr(unsafe.Pointer(&res))),
|
||||
ResultSize: uint16(unsafe.Sizeof(res)),
|
||||
}
|
||||
return int(count), nil
|
||||
|
||||
_, err := scoutfsctl(dirfd.Fd(), IOCINOPATH, uintptr(unsafe.Pointer(&ip)))
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
return string(res.Path[:res.PathSize]), nil
|
||||
}
|
||||
|
||||
// OpenByID will open a file by inode returning a typical *os.File
|
||||
// An open file within scoutfs is supplied for ioctls
|
||||
// (usually just the base mount point directory)
|
||||
// The filename is available through the *os.File and is populated with
|
||||
// the scoutfs InoToPath
|
||||
func OpenByID(dirfd *os.File, ino uint64, flags int) (*os.File, error) {
|
||||
name, err := InoToPath(dirfd, ino)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
fd, err := OpenByHandle(dirfd, ino, flags)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return os.NewFile(fd, name), nil
|
||||
}
|
||||
|
||||
+47
-11
@@ -16,7 +16,7 @@ const (
|
||||
//IOCQUERYINODES scoutfs ioctl
|
||||
IOCQUERYINODES = 0x40357301
|
||||
//IOCINOPATH scoutfs ioctl
|
||||
IOCINOPATH = 0x401c7302
|
||||
IOCINOPATH = 0x40227302
|
||||
//IOCDATAVERSION scoutfs ioctl
|
||||
IOCDATAVERSION = 0x40087304
|
||||
//IOCRELEASE scoutfs ioctl
|
||||
@@ -30,6 +30,8 @@ const (
|
||||
QUERYINODESMETASEQ = '\u0000'
|
||||
//QUERYINODESDATASEQ find inodes by data sequence
|
||||
QUERYINODESDATASEQ = '\u0001'
|
||||
|
||||
pathmax = 1024
|
||||
)
|
||||
|
||||
/* pahole for scoutfs_ioctl_walk_inodes_entry
|
||||
@@ -128,11 +130,11 @@ struct scoutfs_ioctl_ino_path {
|
||||
|
||||
// InoPath ioctl struct
|
||||
type InoPath struct {
|
||||
Ino uint64
|
||||
DirIno uint64
|
||||
DirPos uint64
|
||||
ResultPtr uint64
|
||||
ResultBytes uint64
|
||||
Ino uint64
|
||||
DirIno uint64
|
||||
DirPos uint64
|
||||
ResultPtr uint64
|
||||
ResultSize uint16
|
||||
}
|
||||
|
||||
/* pahole for scoutfs_ioctl_ino_path_result
|
||||
@@ -149,10 +151,10 @@ struct scoutfs_ioctl_ino_path_result {
|
||||
|
||||
// InoPathResult ioctl struct
|
||||
type InoPathResult struct {
|
||||
DirIno uint64
|
||||
DirPos uint64
|
||||
PathBytes uint16
|
||||
ResultBytes uint64
|
||||
DirIno uint64
|
||||
DirPos uint64
|
||||
PathSize uint16
|
||||
Path [pathmax]byte
|
||||
}
|
||||
|
||||
/* pahole for scoutfs_ioctl_release
|
||||
@@ -207,7 +209,7 @@ struct scoutfs_ioctl_stat_more {
|
||||
};
|
||||
*/
|
||||
|
||||
//Stat holds scoutfs specific per file metadata
|
||||
// Stat holds scoutfs specific per file metadata
|
||||
type Stat struct {
|
||||
ValidBytes uint64
|
||||
MetaSeq uint64
|
||||
@@ -216,3 +218,37 @@ type Stat struct {
|
||||
OnlineBlocks uint64
|
||||
OfflineBlocks uint64
|
||||
}
|
||||
|
||||
/* pahole for scoutfs_fid
|
||||
struct scoutfs_fid {
|
||||
__le64 ino; // 0 8
|
||||
__le64 parent_ino; // 8 8
|
||||
|
||||
// size: 16, cachelines: 1, members: 2
|
||||
// last cacheline: 16 bytes
|
||||
};
|
||||
*/
|
||||
|
||||
// FileID for file by ID operations
|
||||
type FileID struct {
|
||||
Ino uint64
|
||||
ParentIno uint64
|
||||
}
|
||||
|
||||
/* pahole for scoutfs_file_handle
|
||||
struct scoutfs_file_handle {
|
||||
unsigned int handle_bytes; // 0 4
|
||||
int handle_type; // 4 4
|
||||
struct scoutfs_fid fid; // 8 16
|
||||
|
||||
// size: 24, cachelines: 1, members: 3
|
||||
// last cacheline: 24 bytes
|
||||
};
|
||||
*/
|
||||
|
||||
// FileHandle is the scoutfs specific file handle for open by handle operations
|
||||
type FileHandle struct {
|
||||
FidSize uint32
|
||||
HandleType int32
|
||||
FID FileID
|
||||
}
|
||||
|
||||
+69
@@ -0,0 +1,69 @@
|
||||
package scoutfs
|
||||
|
||||
import (
|
||||
"os"
|
||||
"syscall"
|
||||
"unsafe"
|
||||
)
|
||||
|
||||
const (
|
||||
// SYS_OPENBYHANDLEAT linux system call
|
||||
SYS_OPENBYHANDLEAT = 304
|
||||
// FILEID_SCOUTFS for scoutfs file handle
|
||||
FILEID_SCOUTFS = 0x81
|
||||
)
|
||||
|
||||
// OpenByHandle is similar to OpenByID, but returns just the file descriptor
|
||||
// and does not have the added overhead of getting the filename
|
||||
// An open file within scoutfs is supplied for ioctls
|
||||
// (usually just the base mount point directory)
|
||||
func OpenByHandle(dirfd *os.File, ino uint64, flags int) (uintptr, error) {
|
||||
h := &FileHandle{
|
||||
FidSize: uint32(unsafe.Sizeof(FileID{})),
|
||||
HandleType: FILEID_SCOUTFS,
|
||||
FID: FileID{Ino: ino},
|
||||
}
|
||||
return openbyhandleat(dirfd.Fd(), h, flags)
|
||||
}
|
||||
|
||||
func openbyhandleat(dirfd uintptr, handle *FileHandle, flags int) (uintptr, error) {
|
||||
fd, _, e1 := syscall.Syscall6(SYS_OPENBYHANDLEAT, dirfd, uintptr(unsafe.Pointer(handle)), uintptr(flags), 0, 0, 0)
|
||||
var err error
|
||||
if e1 != 0 {
|
||||
err = errnoErr(e1)
|
||||
}
|
||||
return fd, err
|
||||
}
|
||||
|
||||
func scoutfsctl(fd, cmd, ptr uintptr) (int, error) {
|
||||
count, _, e1 := syscall.Syscall(syscall.SYS_IOCTL, fd, cmd, ptr)
|
||||
var err error
|
||||
if e1 != 0 {
|
||||
err = errnoErr(e1)
|
||||
}
|
||||
return int(count), err
|
||||
}
|
||||
|
||||
// Do the interface allocations only once for common
|
||||
// Errno values.
|
||||
var (
|
||||
errEAGAIN error = syscall.EAGAIN
|
||||
errEINVAL error = syscall.EINVAL
|
||||
errENOENT error = syscall.ENOENT
|
||||
)
|
||||
|
||||
// errnoErr returns common boxed Errno values, to prevent
|
||||
// allocations at runtime.
|
||||
func errnoErr(e syscall.Errno) error {
|
||||
switch e {
|
||||
case 0:
|
||||
return nil
|
||||
case syscall.EAGAIN:
|
||||
return errEAGAIN
|
||||
case syscall.EINVAL:
|
||||
return errEINVAL
|
||||
case syscall.ENOENT:
|
||||
return errENOENT
|
||||
}
|
||||
return e
|
||||
}
|
||||
Reference in New Issue
Block a user