carlos / platform Public

Clone
git clone https://amadan.net/carlos/platform

Plain git — no account needed to clone.

Download

Download this file

1//go:build linux
2
3package host
4
5import "golang.org/x/sys/unix"
6
7// walkNoFollowDir is the one descriptor walk behind consoleDir and the root
8// migration's floor repair. It opens base, then each name beneath it in
9// turn with O_NOFOLLOW|O_DIRECTORY, so no symlink is followed below base.
10// check sees every directory on the way (last false) before anything
11// beneath it is opened or made, and the final directory (last true) once it
12// is open. A missing name is made only when create(last) allows it: Mkdirat
13// 0755 then Fchmodat 0755 beneath its checked parent, the parent fsynced,
14// and the name opened again with O_NOFOLLOW. It returns the checked final
15// directory's descriptor; errors are the system call's or check's own.
16func walkNoFollowDir(base string, names []string, create func(last bool) bool, check func(fd int, last bool) error) (int, error) {
17 if len(names) == 0 {
18 return -1, unix.EINVAL
19 }
20 fd, err := unix.Open(base, unix.O_RDONLY|unix.O_DIRECTORY|unix.O_CLOEXEC, 0)
21 if err != nil {
22 return -1, err
23 }
24 for i, name := range names {
25 last := i == len(names)-1
26 if err = check(fd, false); err != nil {
27 unix.Close(fd)
28 return -1, err
29 }
30 next, e := unix.Openat(fd, name, unix.O_RDONLY|unix.O_DIRECTORY|unix.O_NOFOLLOW|unix.O_CLOEXEC, 0)
31 if e == unix.ENOENT && create(last) {
32 e = unix.Mkdirat(fd, name, 0o755)
33 if e == nil {
34 e = unix.Fchmodat(fd, name, 0o755, 0)
35 }
36 if e == nil || e == unix.EEXIST {
37 if e = unix.Fsync(fd); e == nil {
38 next, e = unix.Openat(fd, name, unix.O_RDONLY|unix.O_DIRECTORY|unix.O_NOFOLLOW|unix.O_CLOEXEC, 0)
39 }
40 }
41 }
42 unix.Close(fd)
43 if e != nil {
44 return -1, e
45 }
46 fd = next
47 if last {
48 if err = check(fd, true); err != nil {
49 unix.Close(fd)
50 return -1, err
51 }
52 }
53 }
54 return fd, nil
55}
56