In golang having an instance of io.ReadWriteCloser
how to obtain its representation (kind of proxy) as an instance of *os.File
(E.g. to be provided for exec.Cmd.ExtraFiles
)
The first is coming to a mind is to use os.Pipe
approach. Still such a stub would be unidirectional (read or write only).
So how to completely represent io.ReadWriteCloser
as an *os.File
E.g.
func something(stream io.ReadWriteCloser) {
cmd := exec.Command("comm")
var wrapped *os.File = wrappAsFile(stream) // How this could be achieved?
cmd.ExtraFiles := []*File{wrapped}
}
Simplified solution I can see would be something like the following. Still (as I mentioned it before) it covers only a Reader flow.
func something(stream io.ReadWriteCloser) {
cmd := exec.Command("comm")
r, w, _ := os.Pipe()
go func() {
io.Copy(w, stream)
w.Close()
}()
cmd.ExtraFiles := []*File{r}
}
Thx
If you can be constrained to POSIX systems, you can use a socketpair
to create a full duplex pipe with syscall.Socketpair
func socketpair() (*os.File, *os.File, error) {
fds, err := syscall.Socketpair(syscall.AF_UNIX, syscall.SOCK_STREAM, 0)
if err != nil {
return nil, nil, err
}
// Setnonblock may not be necessary if only using these to pass to
// another process, but the runtime will handled it either way.
if err := syscall.SetNonblock(int(fds[0]), true); err != nil {
return nil, nil, err
}
if err := syscall.SetNonblock(int(fds[1]), true); err != nil {
return nil, nil, err
}
f0 := os.NewFile(uintptr(fds[0]), "socket-0")
f1 := os.NewFile(uintptr(fds[1]), "socket-1")
return f0, f1, nil
}
Which you could then connect to an io.ReadWriteCloser
with a couple io.Copy
calls:
// We'll use f0 as the local side of the pipe, and pass along f1 to the child process
f0, f1, err := socketpair()
if err != nil {
log.Fatal(err)
}
go func() {
io.Copy(f0, rw)
f0.Close()
}()
go func() {
io.Copy(rw, f0)
}()
Windows now also supports unix domain sockets too, so while not quite as convenient as a socketpair, you can also create unix socket listener, and then dial another socket to create the connection and get the underlying files from the File()
method