mirror of
https://github.com/criyle/go-sandbox.git
synced 2025-11-04 14:49:53 +08:00
add pipe util
This commit is contained in:
parent
2968ef7e27
commit
1df3228aec
@ -52,6 +52,7 @@ Default file access syscall check:
|
|||||||
- cgroup: creates cgroup directories and collects resource usage / limits
|
- cgroup: creates cgroup directories and collects resource usage / limits
|
||||||
- mount: provides utility function that wrappers mount syscall
|
- mount: provides utility function that wrappers mount syscall
|
||||||
- rlimit: provides utility function that defines rlimit syscall
|
- rlimit: provides utility function that defines rlimit syscall
|
||||||
|
- pipe: provides wrapper to collect all written content through pipe
|
||||||
|
|
||||||
## Packages
|
## Packages
|
||||||
|
|
||||||
|
|||||||
@ -1,3 +1,6 @@
|
|||||||
|
// +build linux
|
||||||
|
|
||||||
|
// Package memfd provides a wrapper to linux memfd
|
||||||
package memfd
|
package memfd
|
||||||
|
|
||||||
import (
|
import (
|
||||||
@ -8,21 +11,31 @@ import (
|
|||||||
"golang.org/x/sys/unix"
|
"golang.org/x/sys/unix"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
const createFlag = unix.MFD_CLOEXEC | unix.MFD_ALLOW_SEALING
|
||||||
const roSeal = unix.F_SEAL_SEAL | unix.F_SEAL_SHRINK | unix.F_SEAL_GROW | unix.F_SEAL_WRITE
|
const roSeal = unix.F_SEAL_SEAL | unix.F_SEAL_SHRINK | unix.F_SEAL_GROW | unix.F_SEAL_WRITE
|
||||||
|
|
||||||
// DupToMemfd convers a fd to sealed memfd for given name
|
// New creates a new memfd, caller need to close the file
|
||||||
func DupToMemfd(name string, fin *os.File) (*os.File, error) {
|
func New(name string) (*os.File, error) {
|
||||||
fd, err := unix.MemfdCreate(name, unix.MFD_CLOEXEC|unix.MFD_ALLOW_SEALING)
|
fd, err := unix.MemfdCreate(name, createFlag)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("DupToMemfd: memfd_create failed(%v)", err)
|
return nil, fmt.Errorf("memfd: memfd_create failed %v", err)
|
||||||
}
|
}
|
||||||
file := os.NewFile(uintptr(fd), name)
|
file := os.NewFile(uintptr(fd), name)
|
||||||
if file == nil {
|
if file == nil {
|
||||||
unix.Close(fd)
|
unix.Close(fd)
|
||||||
return nil, fmt.Errorf("DupToMemfd: memfd new file failed")
|
return nil, fmt.Errorf("memfd: MewFile failed")
|
||||||
}
|
}
|
||||||
// TODO: Send file might be more efficient here
|
return file, nil
|
||||||
if _, err = io.Copy(file, fin); err != nil {
|
}
|
||||||
|
|
||||||
|
// DupToMemfd reads content from reader to sealed (readonly) memfd for given name
|
||||||
|
func DupToMemfd(name string, reader io.Reader) (*os.File, error) {
|
||||||
|
file, err := New(name)
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("DupToMemfd: new memfd failed %v", err)
|
||||||
|
}
|
||||||
|
// linux syscall sendfile might be more efficient here if reader is a file
|
||||||
|
if _, err = io.Copy(file, reader); err != nil {
|
||||||
file.Close()
|
file.Close()
|
||||||
return nil, fmt.Errorf("DupToMemfd: memfd io copy failed(%v)", err)
|
return nil, fmt.Errorf("DupToMemfd: memfd io copy failed(%v)", err)
|
||||||
}
|
}
|
||||||
|
|||||||
52
pkg/pipe/buffer.go
Normal file
52
pkg/pipe/buffer.go
Normal file
@ -0,0 +1,52 @@
|
|||||||
|
// Package pipe provides a wrapper to create a pipe and
|
||||||
|
// read at most max content from the reader side
|
||||||
|
package pipe
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"io"
|
||||||
|
"os"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Buffer is used to create a writable pipe and read
|
||||||
|
// at most max bytes to a buffer
|
||||||
|
type Buffer struct {
|
||||||
|
W *os.File
|
||||||
|
Max int64
|
||||||
|
Buffer *bytes.Buffer
|
||||||
|
Done <-chan struct{}
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewPipe create a pipe with a goroutine to copy its read-end to writer
|
||||||
|
// returns the write end and signal for finish
|
||||||
|
// caller need to close w
|
||||||
|
func NewPipe(writer io.Writer, n int64) (<-chan struct{}, *os.File, error) {
|
||||||
|
r, w, err := os.Pipe()
|
||||||
|
if err != nil {
|
||||||
|
return nil, nil, err
|
||||||
|
}
|
||||||
|
done := make(chan struct{})
|
||||||
|
go func() {
|
||||||
|
defer close(done)
|
||||||
|
defer r.Close()
|
||||||
|
io.CopyN(writer, r, int64(n))
|
||||||
|
}()
|
||||||
|
return done, w, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewBuffer creates a os pipe, caller need to
|
||||||
|
// caller need to close w
|
||||||
|
// Notice: if rely on doen for finish, w need be closed in parent process
|
||||||
|
func NewBuffer(max int64) (*Buffer, error) {
|
||||||
|
buffer := new(bytes.Buffer)
|
||||||
|
done, w, err := NewPipe(buffer, max+1)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return &Buffer{
|
||||||
|
W: w,
|
||||||
|
Max: max,
|
||||||
|
Buffer: buffer,
|
||||||
|
Done: done,
|
||||||
|
}, nil
|
||||||
|
}
|
||||||
Loading…
Reference in New Issue
Block a user