Files

45 lines
1.2 KiB
Go

// Copyright (c) 2026 Storm Dragon
// Authors: Storm Dragon, Angus Kola
// SPDX-License-Identifier: GPL-3.0-or-later
package remoteinput
import (
"os"
"syscall"
)
// AdoptPipe transfers an inherited pipe to an owned nonblocking duplicate so
// Go's poller can interrupt blocked I/O on Close. Terminals/regular files and
// wrong-direction descriptors are rejected; a helper must have private control
// pipes. Failure leaves the original file owned by its caller.
func AdoptPipe(file *os.File, write bool) (*os.File, error) {
if file == nil {
return nil, ErrProtocol
}
info, err := file.Stat()
if err != nil || info.Mode()&os.ModeNamedPipe == 0 {
return nil, ErrProtocol
}
flags, _, failure := syscall.Syscall(syscall.SYS_FCNTL, file.Fd(), syscall.F_GETFL, 0)
want := syscall.O_RDONLY
if write {
want = syscall.O_WRONLY
}
if failure != 0 || int(flags)&syscall.O_ACCMODE != want {
return nil, ErrProtocol
}
fd, err := syscall.Dup(int(file.Fd()))
if err != nil {
return nil, ErrProtocol
}
syscall.CloseOnExec(fd)
if err := syscall.SetNonblock(fd, true); err != nil {
syscall.Close(fd)
return nil, ErrProtocol
}
owned := os.NewFile(uintptr(fd), "remote-input-pipe")
file.Close()
return owned, nil
}