1// Copyright 2023 The Go Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style
3// license that can be found in the LICENSE file.
4
5//go:build unix || (js && wasm)
6
7package poll
8
9import "syscall"
10
11type SysFile struct {
12	// Writev cache.
13	iovecs *[]syscall.Iovec
14}
15
16func (s *SysFile) init() {}
17
18func (s *SysFile) destroy(fd int) error {
19	// We don't use ignoringEINTR here because POSIX does not define
20	// whether the descriptor is closed if close returns EINTR.
21	// If the descriptor is indeed closed, using a loop would race
22	// with some other goroutine opening a new descriptor.
23	// (The Linux kernel guarantees that it is closed on an EINTR error.)
24	return CloseFunc(fd)
25}
26
27// dupCloseOnExecOld is the traditional way to dup an fd and
28// set its O_CLOEXEC bit, using two system calls.
29func dupCloseOnExecOld(fd int) (int, string, error) {
30	syscall.ForkLock.RLock()
31	defer syscall.ForkLock.RUnlock()
32	newfd, err := syscall.Dup(fd)
33	if err != nil {
34		return -1, "dup", err
35	}
36	syscall.CloseOnExec(newfd)
37	return newfd, "", nil
38}
39
40// Fchdir wraps syscall.Fchdir.
41func (fd *FD) Fchdir() error {
42	if err := fd.incref(); err != nil {
43		return err
44	}
45	defer fd.decref()
46	return syscall.Fchdir(fd.Sysfd)
47}
48
49// ReadDirent wraps syscall.ReadDirent.
50// We treat this like an ordinary system call rather than a call
51// that tries to fill the buffer.
52func (fd *FD) ReadDirent(buf []byte) (int, error) {
53	if err := fd.incref(); err != nil {
54		return 0, err
55	}
56	defer fd.decref()
57	for {
58		n, err := ignoringEINTRIO(syscall.ReadDirent, fd.Sysfd, buf)
59		if err != nil {
60			n = 0
61			if err == syscall.EAGAIN && fd.pd.pollable() {
62				if err = fd.pd.waitRead(fd.isFile); err == nil {
63					continue
64				}
65			}
66		}
67		// Do not call eofError; caller does not expect to see io.EOF.
68		return n, err
69	}
70}
71
72// Seek wraps syscall.Seek.
73func (fd *FD) Seek(offset int64, whence int) (int64, error) {
74	if err := fd.incref(); err != nil {
75		return 0, err
76	}
77	defer fd.decref()
78	return syscall.Seek(fd.Sysfd, offset, whence)
79}
80