mirror of
https://github.com/golang/sys.git
synced 2026-02-08 11:46:04 +03:00
unix: add openat2 for linux
openat2 is a new syscall added to Linux 5.6. It provides a superset of openat(2) functionality, extending it with flags telling the kernel how to resolve the paths. For more info, see https://lwn.net/Articles/803237/ NOTE that this is a second attempt to add the call; the previous one (https://golang.org/cl/227280) was reverted (https://golang.org/cl/227846) due to the test case failure on ARM (https://golang.org/issue/38357). This CL has the test case reworked to be less assumptive to the testing environment. In particular, it first tries if the most simplistic openat2() call succeeds, and skips the test otherwise. It is done that way because CI can be under under different kernels and in various envrionments -- in particular, Docker+seccomp can result in EPERM from a system call (which is not expected otherwise). For previous discussions about the test case, see https://golang.org/cl/227865. Change-Id: I4276cf13dc29ecbdbdc9c58da0f76270f585a67f Reviewed-on: https://go-review.googlesource.com/c/sys/+/253057 Run-TryBot: Ian Lance Taylor <iant@golang.org> TryBot-Result: Gobot Gobot <gobot@golang.org> Reviewed-by: Tobias Klauser <tobias.klauser@gmail.com>
This commit is contained in:
committed by
Tobias Klauser
parent
d2e65c121b
commit
eff7692f90
@@ -111,6 +111,7 @@ struct termios2 {
|
||||
#include <linux/netfilter.h>
|
||||
#include <linux/netlink.h>
|
||||
#include <linux/nexthop.h>
|
||||
#include <linux/openat2.h>
|
||||
#include <linux/perf_event.h>
|
||||
#include <linux/random.h>
|
||||
#include <linux/rtc.h>
|
||||
@@ -874,6 +875,18 @@ const (
|
||||
AT_EACCESS = C.AT_EACCESS
|
||||
)
|
||||
|
||||
type OpenHow C.struct_open_how
|
||||
|
||||
const SizeofOpenHow = C.sizeof_struct_open_how
|
||||
|
||||
const (
|
||||
RESOLVE_BENEATH = C.RESOLVE_BENEATH
|
||||
RESOLVE_IN_ROOT = C.RESOLVE_IN_ROOT
|
||||
RESOLVE_NO_MAGICLINKS = C.RESOLVE_NO_MAGICLINKS
|
||||
RESOLVE_NO_SYMLINKS = C.RESOLVE_NO_SYMLINKS
|
||||
RESOLVE_NO_XDEV = C.RESOLVE_NO_XDEV
|
||||
)
|
||||
|
||||
type PollFd C.struct_pollfd
|
||||
|
||||
const (
|
||||
|
||||
@@ -136,6 +136,12 @@ func Openat(dirfd int, path string, flags int, mode uint32) (fd int, err error)
|
||||
return openat(dirfd, path, flags|O_LARGEFILE, mode)
|
||||
}
|
||||
|
||||
//sys openat2(dirfd int, path string, open_how *OpenHow, size int) (fd int, err error)
|
||||
|
||||
func Openat2(dirfd int, path string, how *OpenHow) (fd int, err error) {
|
||||
return openat2(dirfd, path, how, SizeofOpenHow)
|
||||
}
|
||||
|
||||
//sys ppoll(fds *PollFd, nfds int, timeout *Timespec, sigmask *Sigset_t) (n int, err error)
|
||||
|
||||
func Ppoll(fds []PollFd, timeout *Timespec, sigmask *Sigset_t) (n int, err error) {
|
||||
|
||||
@@ -13,6 +13,7 @@ import (
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"runtime"
|
||||
"runtime/debug"
|
||||
"strconv"
|
||||
@@ -730,3 +731,62 @@ func TestTimerfd(t *testing.T) {
|
||||
count += *(*uint64)(unsafe.Pointer(&buffer))
|
||||
}
|
||||
}
|
||||
|
||||
func TestOpenat2(t *testing.T) {
|
||||
how := &unix.OpenHow{
|
||||
Flags: unix.O_RDONLY,
|
||||
}
|
||||
fd, err := unix.Openat2(unix.AT_FDCWD, ".", how)
|
||||
if err != nil {
|
||||
if err == unix.ENOSYS || err == unix.EPERM {
|
||||
t.Skipf("openat2: %v (old kernel? need Linux >= 5.6)", err)
|
||||
}
|
||||
t.Fatalf("openat2: %v", err)
|
||||
}
|
||||
if err := unix.Close(fd); err != nil {
|
||||
t.Fatalf("close: %v", err)
|
||||
}
|
||||
|
||||
// prepare
|
||||
tempDir, err := ioutil.TempDir("", t.Name())
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
defer os.RemoveAll(tempDir)
|
||||
|
||||
subdir := filepath.Join(tempDir, "dir")
|
||||
if err := os.Mkdir(subdir, 0755); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
symlink := filepath.Join(subdir, "symlink")
|
||||
if err := os.Symlink("../", symlink); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
dirfd, err := unix.Open(subdir, unix.O_RDONLY, 0)
|
||||
if err != nil {
|
||||
t.Fatalf("open(%q): %v", subdir, err)
|
||||
}
|
||||
defer unix.Close(dirfd)
|
||||
|
||||
// openat2 with no extra flags -- should succeed
|
||||
fd, err = unix.Openat2(dirfd, "symlink", how)
|
||||
if err != nil {
|
||||
t.Errorf("Openat2 should succeed, got %v", err)
|
||||
}
|
||||
if err := unix.Close(fd); err != nil {
|
||||
t.Fatalf("close: %v", err)
|
||||
}
|
||||
|
||||
// open with RESOLVE_BENEATH, should result in EXDEV
|
||||
how.Resolve = unix.RESOLVE_BENEATH
|
||||
fd, err = unix.Openat2(dirfd, "symlink", how)
|
||||
if err == nil {
|
||||
if err := unix.Close(fd); err != nil {
|
||||
t.Fatalf("close: %v", err)
|
||||
}
|
||||
}
|
||||
if err != unix.EXDEV {
|
||||
t.Errorf("Openat2 should fail with EXDEV, got %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -83,6 +83,22 @@ func openat(dirfd int, path string, flags int, mode uint32) (fd int, err error)
|
||||
|
||||
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
|
||||
|
||||
func openat2(dirfd int, path string, open_how *OpenHow, size int) (fd int, err error) {
|
||||
var _p0 *byte
|
||||
_p0, err = BytePtrFromString(path)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
r0, _, e1 := Syscall6(SYS_OPENAT2, uintptr(dirfd), uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(open_how)), uintptr(size), 0, 0)
|
||||
fd = int(r0)
|
||||
if e1 != 0 {
|
||||
err = errnoErr(e1)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
|
||||
|
||||
func ppoll(fds *PollFd, nfds int, timeout *Timespec, sigmask *Sigset_t) (n int, err error) {
|
||||
r0, _, e1 := Syscall6(SYS_PPOLL, uintptr(unsafe.Pointer(fds)), uintptr(nfds), uintptr(unsafe.Pointer(timeout)), uintptr(unsafe.Pointer(sigmask)), 0, 0)
|
||||
n = int(r0)
|
||||
|
||||
@@ -752,6 +752,22 @@ const (
|
||||
AT_EACCESS = 0x200
|
||||
)
|
||||
|
||||
type OpenHow struct {
|
||||
Flags uint64
|
||||
Mode uint64
|
||||
Resolve uint64
|
||||
}
|
||||
|
||||
const SizeofOpenHow = 0x18
|
||||
|
||||
const (
|
||||
RESOLVE_BENEATH = 0x8
|
||||
RESOLVE_IN_ROOT = 0x10
|
||||
RESOLVE_NO_MAGICLINKS = 0x2
|
||||
RESOLVE_NO_SYMLINKS = 0x4
|
||||
RESOLVE_NO_XDEV = 0x1
|
||||
)
|
||||
|
||||
type PollFd struct {
|
||||
Fd int32
|
||||
Events int16
|
||||
|
||||
Reference in New Issue
Block a user