auto generate ioctl structs and definitions from scoutfs headers

This commit is contained in:
Ben McClelland
2019-06-28 12:17:29 -07:00
parent 16911b5b0a
commit 92e719d578
6 changed files with 227 additions and 374 deletions

1
.gitignore vendored
View File

@@ -4,6 +4,7 @@
*.dll
*.so
*.dylib
_obj
# Test binary, build with `go test -c`
*.test

78
c_defs_linux.go Normal file
View File

@@ -0,0 +1,78 @@
// +build ignore
// 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 scoutfs
// use this to generate the types for scoutfs:
// go tool cgo -godefs c_defs.go >scoutfsdefs.go
// #include <unistd.h>
// #include <stdio.h>
// #include <stdlib.h>
// #include <sys/types.h>
// #include <sys/stat.h>
// #include <sys/ioctl.h>
// #include <fcntl.h>
// #include <errno.h>
// #include <string.h>
// #include <getopt.h>
// #include <ctype.h>
// #include <stdint.h>
// typedef uint8_t __u8;
// typedef uint16_t __u16;
// typedef uint32_t __u32;
// typedef uint64_t __u64;
// typedef uint16_t __le16;
// typedef uint32_t __le32;
// typedef uint64_t __le64;
// typedef int32_t __s32;
// #define __packed
// #include "/usr/include/scoutfs/ioctl.h"
// typedef struct scoutfs_ioctl_walk_inodes_entry scoutfs_ioctl_walk_inodes_entry_t;
// typedef struct scoutfs_ioctl_walk_inodes scoutfs_ioctl_walk_inodes_t;
// typedef struct scoutfs_ioctl_ino_path scoutfs_ioctl_ino_path_t;
// typedef struct scoutfs_ioctl_ino_path_result scoutfs_ioctl_ino_path_result_t;
// typedef struct scoutfs_ioctl_release scoutfs_ioctl_release_t;
// typedef struct scoutfs_ioctl_stage scoutfs_ioctl_stage_t;
// typedef struct scoutfs_ioctl_stat_more scoutfs_ioctl_stat_more_t;
// typedef struct scoutfs_fid scoutfs_fid_t;
// typedef struct scoutfs_ioctl_data_waiting_entry scoutfs_ioctl_data_waiting_entry_t;
// typedef struct scoutfs_ioctl_data_waiting scoutfs_ioctl_data_waiting_t;
// typedef struct scoutfs_ioctl_setattr_more scoutfs_ioctl_setattr_more_t;
// typedef struct scoutfs_ioctl_listxattr_hidden scoutfs_ioctl_listxattr_hidden_t;
// typedef struct scoutfs_ioctl_find_xattrs scoutfs_ioctl_find_xattrs_t;
import "C"
const IOCQUERYINODES = C.SCOUTFS_IOC_WALK_INODES
const IOCINOPATH = C.SCOUTFS_IOC_INO_PATH
const IOCRELEASE = C.SCOUTFS_IOC_RELEASE
const IOCSTAGE = C.SCOUTFS_IOC_STAGE
const IOCSTATMORE = C.SCOUTFS_IOC_STAT_MORE
const IOCDATAWAITING = C.SCOUTFS_IOC_DATA_WAITING
const IOCSETATTRMORE = C.SCOUTFS_IOC_SETATTR_MORE
const IOCLISTXATTRHIDDEN = C.SCOUTFS_IOC_LISTXATTR_HIDDEN
const IOCFINDXATTRS = C.SCOUTFS_IOC_FIND_XATTRS
const QUERYINODESMETASEQ = C.SCOUTFS_IOC_WALK_INODES_META_SEQ
const QUERYINODESDATASEQ = C.SCOUTFS_IOC_WALK_INODES_DATA_SEQ
const DATAWAITOPREAD = C.SCOUTFS_IOC_DWO_READ
const DATAWAITOPWRITE = C.SCOUTFS_IOC_DWO_WRITE
const DATAWAITOPCHANGESIZE = C.SCOUTFS_IOC_DWO_CHANGE_SIZE
type InodesEntry C.scoutfs_ioctl_walk_inodes_entry_t
type queryInodes C.scoutfs_ioctl_walk_inodes_t
type inoPath C.scoutfs_ioctl_ino_path_t
type iocRelease C.scoutfs_ioctl_release_t
type iocStage C.scoutfs_ioctl_stage_t
type Stat C.scoutfs_ioctl_stat_more_t
type DataWaitingEntry C.scoutfs_ioctl_data_waiting_entry_t
type dataWaiting C.scoutfs_ioctl_data_waiting_t
type setattrMore C.scoutfs_ioctl_setattr_more_t
type listXattrHidden C.scoutfs_ioctl_listxattr_hidden_t
type findXattrs C.scoutfs_ioctl_find_xattrs_t

View File

@@ -30,12 +30,12 @@ func main() {
os.Exit(1)
}
f, err := os.Open(os.Args[1])
f, err := os.OpenFile(os.Args[1], os.O_RDWR, 0)
if err != nil {
log.Fatalf("open %v: %v", os.Args[1], err)
}
lxr := scoutfs.NewListXattrRaw(f)
lxr := scoutfs.NewListXattrHidden(f)
for {
attrs, err := lxr.Next()

View File

@@ -18,6 +18,7 @@ import (
const (
max64 = 0xffffffffffffffff
max32 = 0xffffffff
pathmax = 1024
)
// Query to keep track of in-process query
@@ -87,11 +88,11 @@ func WithBatchSize(size uint32) Option {
func (q *Query) Next() ([]InodesEntry, error) {
buf := make([]byte, int(unsafe.Sizeof(InodesEntry{}))*int(q.batch))
query := queryInodes{
first: q.first,
last: q.last,
entries: uintptr(unsafe.Pointer(&buf[0])),
count: q.batch,
index: q.index,
First: q.first,
Last: q.last,
Entries_ptr: uint64(uintptr(unsafe.Pointer(&buf[0]))),
Nr_entries: q.batch,
Index: q.index,
}
n, err := scoutfsctl(q.fsfd.Fd(), IOCQUERYINODES, uintptr(unsafe.Pointer(&query)))
@@ -141,7 +142,7 @@ func StatMore(path string) (Stat, error) {
// FStatMore returns scoutfs specific metadata for file handle
func FStatMore(f *os.File) (Stat, error) {
s := Stat{ValidBytes: uint64(unsafe.Sizeof(Stat{}))}
s := Stat{Valid_bytes: uint64(unsafe.Sizeof(Stat{}))}
_, err := scoutfsctl(f.Fd(), IOCSTATMORE, uintptr(unsafe.Pointer(&s)))
if err != nil {
@@ -169,26 +170,34 @@ func FSetAttrMore(f *os.File, version, size, flags uint64, ctime time.Time) erro
nsec = int32(ctime.UnixNano())
}
s := setattrMore{
dataVersion: version,
iSize: size,
flags: flags,
ctimesec: uint64(ctime.Unix()),
ctimensec: uint32(nsec),
Data_version: version,
I_size: size,
Flags: flags,
Ctime_sec: uint64(ctime.Unix()),
Ctime_nsec: uint32(nsec),
}
_, err := scoutfsctl(f.Fd(), IOCSETATTRMORE, uintptr(unsafe.Pointer(&s)))
return err
}
type inoPathResult struct {
DirIno uint64
DirPos uint64
PathSize uint16
_ [6]uint8
Path [pathmax]byte
}
// 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{
var res inoPathResult
ip := inoPath{
Ino: ino,
ResultPtr: uint64(uintptr(unsafe.Pointer(&res))),
ResultSize: uint16(unsafe.Sizeof(res)),
Result_ptr: uint64(uintptr(unsafe.Pointer(&res))),
Result_bytes: uint16(unsafe.Sizeof(res)),
}
_, err := scoutfsctl(dirfd.Fd(), IOCINOPATH, uintptr(unsafe.Pointer(&ip)))
@@ -228,9 +237,9 @@ func ReleaseFile(path string, version uint64) error {
// FReleaseFile marks file offline and frees associated extents
func FReleaseFile(f *os.File, version uint64) error {
r := IocRelease{
r := iocRelease{
Count: math.MaxUint64,
DataVersion: version,
Version: version,
}
_, err := scoutfsctl(f.Fd(), IOCRELEASE, uintptr(unsafe.Pointer(&r)))
@@ -250,11 +259,11 @@ func StageFile(path string, version, offset uint64, b []byte) error {
// FStageFile rehydrates offline file
func FStageFile(f *os.File, version, offset uint64, b []byte) error {
r := IocStage{
DataVersion: version,
BufPtr: uint64(uintptr(unsafe.Pointer(&b[0]))),
r := iocStage{
Data_version: version,
Buf_ptr: uint64(uintptr(unsafe.Pointer(&b[0]))),
Offset: offset,
count: int32(len(b)),
Count: int32(len(b)),
}
_, err := scoutfsctl(f.Fd(), IOCSTAGE, uintptr(unsafe.Pointer(&r)))
@@ -300,10 +309,10 @@ func WithWaitersCount(size uint16) WOption {
func (w *Waiters) Next() ([]DataWaitingEntry, error) {
buf := make([]byte, int(unsafe.Sizeof(DataWaitingEntry{}))*int(w.batch))
dataWaiting := dataWaiting{
afterIno: w.ino,
afterIblock: w.iblock,
entries: uintptr(unsafe.Pointer(&buf[0])),
count: w.batch,
After_ino: w.ino,
After_iblock: w.iblock,
Ents_ptr: uint64(uintptr(unsafe.Pointer(&buf[0]))),
Ents_nr: w.batch,
}
n, err := scoutfsctl(w.fsfd.Fd(), IOCDATAWAITING, uintptr(unsafe.Pointer(&dataWaiting)))
@@ -392,11 +401,11 @@ func (q *XattrQuery) Next() ([]uint64, error) {
buf := make([]byte, 8*int(q.batch))
name := []byte(q.key)
query := findXattrs{
nextIno: q.next,
name: uintptr(unsafe.Pointer(&name[0])),
inodesBuf: uintptr(unsafe.Pointer(&buf[0])),
nameSize: uint16(len(name)),
inodeCount: uint16(q.batch),
Next_ino: q.next,
Name_ptr: uint64(uintptr(unsafe.Pointer(&name[0]))),
Inodes_ptr: uint64(uintptr(unsafe.Pointer(&buf[0]))),
Name_bytes: uint16(len(name)),
Nr_inodes: uint16(q.batch),
}
n, err := scoutfsctl(q.fsfd.Fd(), IOCFINDXATTRS, uintptr(unsafe.Pointer(&query)))
@@ -427,27 +436,27 @@ func (q *XattrQuery) Next() ([]uint64, error) {
return inodes, nil
}
// ListXattrRaw holds info for iterating on xattrs
type ListXattrRaw struct {
lxr *listXattrRaw
// ListXattrHidden holds info for iterating on xattrs
type ListXattrHidden struct {
lxr *listXattrHidden
f *os.File
}
// NewListXattrRaw will list all scoutfs xattrs (including hidden) for file
func NewListXattrRaw(f *os.File) *ListXattrRaw {
return &ListXattrRaw{
// NewListXattrHidden will list all scoutfs xattrs (including hidden) for file
func NewListXattrHidden(f *os.File) *ListXattrHidden {
return &ListXattrHidden{
f: f,
lxr: &listXattrRaw{},
lxr: &listXattrHidden{},
}
}
// Next gets next set of results, complete when string slice is nil
func (l *ListXattrRaw) Next() ([]string, error) {
l.lxr.bufSize = 256 * 1024
func (l *ListXattrHidden) Next() ([]string, error) {
l.lxr.Buf_bytes = 256 * 1024
buf := make([]byte, 256*1024)
l.lxr.buf = uintptr(unsafe.Pointer(&buf[0]))
l.lxr.Buf_ptr = uint64(uintptr(unsafe.Pointer(&buf[0])))
n, err := scoutfsctl(l.f.Fd(), IOCLISTXATTRRAW, uintptr(unsafe.Pointer(l.lxr)))
n, err := scoutfsctl(l.f.Fd(), IOCLISTXATTRHIDDEN, uintptr(unsafe.Pointer(l.lxr)))
if err != nil {
return nil, err
}

View File

@@ -1,346 +1,100 @@
// 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.
// The _ struct members are not necessary, but just there to be explicit
// in the matching up with the C struct alignment. The Go structs follow
// the same alignment rules, so should be compatible without these fields.
// Code generated by cmd/cgo -godefs; DO NOT EDIT.
// cgo -godefs c_defs_linux.go
package scoutfs
const (
// IOCQUERYINODES scoutfs ioctl
IOCQUERYINODES = 0x40487301
// IOCINOPATH scoutfs ioctl
IOCINOPATH = 0x40287302
// IOCDATAVERSION scoutfs ioctl
IOCDATAVERSION = 0x40087304
// IOCRELEASE scoutfs ioctl
IOCRELEASE = 0x40187305
// IOCSTAGE scoutfs ioctl
IOCSTAGE = 0x40207306
// IOCSTATMORE scoutfs ioctl
IOCSTATMORE = 0x40307307
// IOCDATAWAITING scoutfs ioctl
IOCDATAWAITING = 0x40287309
// IOCSETATTRMORE scoutfs ioctl
IOCSETATTRMORE = 0x4028730a
// IOCLISTXATTRRAW scoutfs ioctl
IOCLISTXATTRRAW = 0x4018730b
// IOCFINDXATTRS scoutfs ioctl
IOCFINDXATTRS = 0x4020730c
const IOCQUERYINODES = 0x80487301
const IOCINOPATH = 0x80287302
const IOCRELEASE = 0x40187303
const IOCSTAGE = 0x40207304
const IOCSTATMORE = 0x80307305
const IOCDATAWAITING = 0x80287307
const IOCSETATTRMORE = 0x40287308
const IOCLISTXATTRHIDDEN = 0x80187309
const IOCFINDXATTRS = 0x8020730a
// QUERYINODESMETASEQ find inodes by metadata sequence
QUERYINODESMETASEQ = '\u0000'
// QUERYINODESDATASEQ find inodes by data sequence
QUERYINODESDATASEQ = '\u0001'
const QUERYINODESMETASEQ = 0x0
const QUERYINODESDATASEQ = 0x1
// DATAWAITOPREAD waiting operation read
DATAWAITOPREAD = 1 << 0
// DATAWAITOPWRITE waiting operation write
DATAWAITOPWRITE = 1 << 1
// DATAWAITOPCHANGESIZE waiting operation truncate
DATAWAITOPCHANGESIZE = 1 << 2
const DATAWAITOPREAD = 0x1
const DATAWAITOPWRITE = 0x2
const DATAWAITOPCHANGESIZE = 0x4
pathmax = 1024
)
/* pahole for scoutfs_ioctl_walk_inodes_entry
struct scoutfs_ioctl_walk_inodes_entry {
__u64 major; // 0 8
__u64 ino; // 8 8
__u32 minor; // 16 4
__u8 _pad[4]; // 20 4
// size: 24, cachelines: 1, members: 4
// last cacheline: 24 bytes
};
*/
// InodesEntry is scoutfs entry for inode iteration
type InodesEntry struct {
Major uint64
Ino uint64
Minor uint32
_ [4]uint8
X_pad [4]uint8
}
/* pahole for scoutfs_ioctl_walk_inodes
struct scoutfs_ioctl_walk_inodes {
struct scoutfs_ioctl_walk_inodes_entry first; // 0 24
struct scoutfs_ioctl_walk_inodes_entry last; // 24 24
__u64 entries_ptr; // 48 8
__u32 nr_entries; // 56 4
__u8 index; // 60 1
__u8 _pad[11]; // 61 11
// --- cacheline 1 boundary (64 bytes) was 8 bytes ago ---
// size: 72, cachelines: 2, members: 6
// last cacheline: 8 bytes
};
*/
// queryInodes is scoutfs request structure for IOCQUERYINODES
type queryInodes struct {
first InodesEntry
last InodesEntry
entries uintptr
count uint32
index uint8
_ [11]uint8
First InodesEntry
Last InodesEntry
Entries_ptr uint64
Nr_entries uint32
Index uint8
X_pad [11]uint8
}
/* pahole for scoutfs_ioctl_ino_path
struct scoutfs_ioctl_ino_path {
__u64 ino; // 0 8
__u64 dir_ino; // 8 8
__u64 dir_pos; // 16 8
__u64 result_ptr; // 24 8
__u16 result_bytes; // 32 2
__u8 _pad[6]; // 34 6
// size: 40, cachelines: 1, members: 6
// last cacheline: 40 bytes
};
*/
// InoPath ioctl struct
type InoPath struct {
type inoPath struct {
Ino uint64
DirIno uint64
DirPos uint64
ResultPtr uint64
ResultSize uint16
_ [6]uint8
Dir_ino uint64
Dir_pos uint64
Result_ptr uint64
Result_bytes uint16
X_pad [6]uint8
}
/* pahole for scoutfs_ioctl_ino_path_result
struct scoutfs_ioctl_ino_path_result {
__u64 dir_ino; // 0 8
__u64 dir_pos; // 8 8
__u16 path_bytes; // 16 2
__u8 _pad[6]; // 18 6
__u8 path[0]; // 24 0
// size: 24, cachelines: 1, members: 5
// last cacheline: 24 bytes
};
*/
// InoPathResult ioctl struct
type InoPathResult struct {
DirIno uint64
DirPos uint64
PathSize uint16
_ [6]uint8
Path [pathmax]byte
}
/* pahole for scoutfs_ioctl_release
struct scoutfs_ioctl_release {
__u64 block; // 0 8
__u64 count; // 8 8
__u64 data_version; // 16 8
// size: 24, cachelines: 1, members: 3
// last cacheline: 24 bytes
};
*/
// IocRelease ioctl struct
type IocRelease struct {
type iocRelease struct {
Block uint64
Count uint64
DataVersion uint64
Version uint64
}
/* pahole for scoutfs_ioctl_stage
struct scoutfs_ioctl_stage {
__u64 data_version; // 0 8
__u64 buf_ptr; // 8 8
__u64 offset; // 16 8
__s32 count; // 24 4
__u32 _pad; // 28 4
// size: 32, cachelines: 1, members: 5
// last cacheline: 32 bytes
};
*/
// IocStage ioctl struct
type IocStage struct {
DataVersion uint64
BufPtr uint64
type iocStage struct {
Data_version uint64
Buf_ptr uint64
Offset uint64
count int32
_ uint32
Count int32
X_pad uint32
}
/* pahole for scoutfs_ioctl_stat_more
struct scoutfs_ioctl_stat_more {
__u64 valid_bytes; // 0 8
__u64 meta_seq; // 8 8
__u64 data_seq; // 16 8
__u64 data_version; // 24 8
__u64 online_blocks; // 32 8
__u64 offline_blocks; // 40 8
// size: 48, cachelines: 1, members: 6
// last cacheline: 48 bytes
};
*/
// Stat holds scoutfs specific per file metadata
type Stat struct {
ValidBytes uint64
MetaSeq uint64
DataSeq uint64
DataVersion uint64
OnlineBlocks uint64
OfflineBlocks uint64
Valid_bytes uint64
Meta_seq uint64
Data_seq uint64
Data_version uint64
Online_blocks uint64
Offline_blocks 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
}
/* pahole for scoutfs_ioctl_data_waiting_entry
struct scoutfs_ioctl_data_waiting_entry {
__u64 ino; // 0 8
__u64 iblock; // 8 8
__u8 op; // 16 1
__u8 _pad[7]; // 17 7
// size: 24, cachelines: 1, members: 4
// last cacheline: 24 bytes
};
*/
// DataWaitingEntry is an entry returned when a process is waiting on
// access of offline block
type DataWaitingEntry struct {
Ino uint64
Iblock uint64
Op uint8
_ [7]uint8
X_pad [7]uint8
}
/* pahole for scoutfs_ioctl_data_waiting
struct scoutfs_ioctl_data_waiting {
__u64 flags; // 0 8
__u64 after_ino; // 8 8
__u64 after_iblock; // 16 8
__u64 ents_ptr; // 24 8
__u16 ents_nr; // 32 2
__u8 _pad[6]; // 34 6
// size: 40, cachelines: 1, members: 6
// last cacheline: 40 bytes
};
*/
type dataWaiting struct {
flags uint64
afterIno uint64
afterIblock uint64
entries uintptr
count uint16
_ [6]uint8
Flags uint64
After_ino uint64
After_iblock uint64
Ents_ptr uint64
Ents_nr uint16
X_pad [6]uint8
}
/* pahole for scoutfs_ioctl_setattr_more
struct scoutfs_ioctl_setattr_more {
__u64 data_version; // 0 8
__u64 i_size; // 8 8
__u64 flags; // 16 8
__u64 ctime_sec; // 24 8
__u32 ctime_nsec; // 32 4
__u8 _pad[4]; // 36 4
// size: 40, cachelines: 1, members: 6
// last cacheline: 40 bytes
};
*/
type setattrMore struct {
dataVersion uint64
iSize uint64
flags uint64
ctimesec uint64
ctimensec uint32
_ [4]uint8
Data_version uint64
I_size uint64
Flags uint64
Ctime_sec uint64
Ctime_nsec uint32
X_pad [4]uint8
}
/* pahole for scoutfs_ioctl_listxattr_raw
struct scoutfs_ioctl_listxattr_raw {
__u64 id_pos; // 0 8
__u64 buf_ptr; // 8 8
__u32 buf_bytes; // 16 4
__u32 hash_pos; // 20 4
// size: 24, cachelines: 1, members: 4
// last cacheline: 24 bytes
};
*/
type listXattrRaw struct {
idPos uint64
buf uintptr
bufSize uint32
hashPos uint32
type listXattrHidden struct {
Id_pos uint64
Buf_ptr uint64
Buf_bytes uint32
Hash_pos uint32
}
/* pahole for scoutfs_ioctl_find_xattrs
struct scoutfs_ioctl_find_xattrs {
__u64 next_ino; // 0 8
__u64 name_ptr; // 8 8
__u64 inodes_ptr; // 16 8
__u16 name_bytes; // 24 2
__u16 nr_inodes; // 26 2
__u8 _pad[4]; // 28 4
// size: 32, cachelines: 1, members: 6
// last cacheline: 32 bytes
};
*/
type findXattrs struct {
nextIno uint64
name uintptr
inodesBuf uintptr
nameSize uint16
inodeCount uint16
_ [4]uint8
Next_ino uint64
Name_ptr uint64
Inodes_ptr uint64
Name_bytes uint16
Nr_inodes uint16
X_pad [4]uint8
}

View File

@@ -13,20 +13,31 @@ const (
FILEID_SCOUTFS = 0x81
)
type fileID struct {
Ino uint64
ParentIno uint64
}
type fileHandle struct {
FidSize uint32
HandleType int32
FID fileID
}
// 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{})),
h := &fileHandle{
FidSize: uint32(unsafe.Sizeof(fileID{})),
HandleType: FILEID_SCOUTFS,
FID: FileID{Ino: ino},
FID: fileID{Ino: ino},
}
return openbyhandleat(dirfd.Fd(), h, flags)
}
func openbyhandleat(dirfd uintptr, handle *FileHandle, flags int) (uintptr, error) {
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 {