1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
|
package misc
import (
"os"
"errors"
"strings"
"syscall"
"path"
)
type Dir_t struct {
fd int
name string
}
var (
Err_illegal_filename = errors.New("illegal filename")
Err_invalid_file_descriptor = errors.New("invalid file descriptor")
)
// Open a file at exactly the given directory.
func Open_file_at(dir Dir_t, filename string, flags int, perms os.FileMode) (*os.File, error) {
if strings.IndexByte(filename, '/') != -1 {
return nil, Err_illegal_filename
}
return Open_file_beneath(dir, filename, flags, perms)
}
// Open a file at or beneath the given directory.
func Open_file_beneath(dir Dir_t, filename string, flags int, perms os.FileMode) (*os.File, error) {
fd, err := Openat2(dir.fd, filename, &Open_how_t{
Flags: uint64(flags),
Mode: uint64(syscallMode(perms)),
Resolve: RESOLVE_BENEATH|RESOLVE_NO_SYMLINKS,
})
if err != nil {
return nil, err
}
file := os.NewFile(uintptr(fd), path.Join(dir.name, filename))
if file == nil {
return nil, Err_invalid_file_descriptor
} else {
return file, nil
}
}
// Open a directory as read-only and return a Dir_t to it. The caller is
// responsible for closing the directory with [[Close_directory]].
func Open_directory_readonly(path string) (Dir_t, error) {
_fd, err := syscall.Open(path, os.O_RDONLY|syscall.O_DIRECTORY, 0)
return Dir_t{fd: _fd, name: path}, err
}
// Close a directory returned by [[Open_directory_readonly]].
func Close_directory(dir Dir_t) error {
return syscall.Close(dir.fd)
}
// syscallMode returns the syscall-specific mode flags from Go's portable mode flags.
func syscallMode(i os.FileMode) (o uint32) {
// This part actually came from Go's os/file_posix.go but IMO it's too
// small and should fall under fair use.
o |= uint32(i.Perm())
if i&os.ModeSetuid != 0 {
o |= syscall.S_ISUID
}
if i&os.ModeSetgid != 0 {
o |= syscall.S_ISGID
}
if i&os.ModeSticky != 0 {
o |= syscall.S_ISVTX
}
// No mapping for Go's ModeTemporary (plan9 only).
return
}
|