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
|
||||
- mount: provides utility function that wrappers mount syscall
|
||||
- rlimit: provides utility function that defines rlimit syscall
|
||||
- pipe: provides wrapper to collect all written content through pipe
|
||||
|
||||
## Packages
|
||||
|
||||
|
||||
@ -1,3 +1,6 @@
|
||||
// +build linux
|
||||
|
||||
// Package memfd provides a wrapper to linux memfd
|
||||
package memfd
|
||||
|
||||
import (
|
||||
@ -8,21 +11,31 @@ import (
|
||||
"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
|
||||
|
||||
// DupToMemfd convers a fd to sealed memfd for given name
|
||||
func DupToMemfd(name string, fin *os.File) (*os.File, error) {
|
||||
fd, err := unix.MemfdCreate(name, unix.MFD_CLOEXEC|unix.MFD_ALLOW_SEALING)
|
||||
// New creates a new memfd, caller need to close the file
|
||||
func New(name string) (*os.File, error) {
|
||||
fd, err := unix.MemfdCreate(name, createFlag)
|
||||
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)
|
||||
if file == nil {
|
||||
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
|
||||
if _, err = io.Copy(file, fin); err != nil {
|
||||
return file, 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()
|
||||
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