wip
This commit is contained in:
2
mmap/README.md
Normal file
2
mmap/README.md
Normal file
@@ -0,0 +1,2 @@
|
||||
# mmap
|
||||
|
||||
100
mmap/file.go
Normal file
100
mmap/file.go
Normal file
@@ -0,0 +1,100 @@
|
||||
package mmap
|
||||
|
||||
import "os"
|
||||
|
||||
type File struct {
|
||||
f *os.File
|
||||
Map []byte
|
||||
}
|
||||
|
||||
func Create(path string, size int64) (*File, error) {
|
||||
f, err := os.Create(path)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if err := f.Truncate(size); err != nil {
|
||||
f.Close()
|
||||
return nil, err
|
||||
}
|
||||
m, err := Map(f, PROT_READ|PROT_WRITE)
|
||||
if err != nil {
|
||||
f.Close()
|
||||
return nil, err
|
||||
}
|
||||
return &File{f, m}, nil
|
||||
}
|
||||
|
||||
// Opens a mapped file in read-only mode.
|
||||
func Open(path string) (*File, error) {
|
||||
f, err := os.Open(path)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
m, err := Map(f, PROT_READ)
|
||||
if err != nil {
|
||||
f.Close()
|
||||
return nil, err
|
||||
}
|
||||
return &File{f, m}, nil
|
||||
}
|
||||
|
||||
func OpenFile(
|
||||
path string,
|
||||
fileFlags int,
|
||||
perm os.FileMode,
|
||||
size int64, // -1 for file size.
|
||||
) (*File, error) {
|
||||
f, err := os.OpenFile(path, fileFlags, perm)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
writable := fileFlags|os.O_RDWR != 0 || fileFlags|os.O_WRONLY != 0
|
||||
|
||||
fi, err := f.Stat()
|
||||
if err != nil {
|
||||
f.Close()
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if writable && size > 0 && size != fi.Size() {
|
||||
if err := f.Truncate(size); err != nil {
|
||||
f.Close()
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
mapFlags := PROT_READ
|
||||
if writable {
|
||||
mapFlags |= PROT_WRITE
|
||||
}
|
||||
|
||||
m, err := Map(f, mapFlags)
|
||||
if err != nil {
|
||||
f.Close()
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &File{f, m}, nil
|
||||
}
|
||||
|
||||
func (f *File) Sync() error {
|
||||
return Sync(f.Map)
|
||||
}
|
||||
|
||||
func (f *File) Close() error {
|
||||
if f.Map != nil {
|
||||
if err := Unmap(f.Map); err != nil {
|
||||
return err
|
||||
}
|
||||
f.Map = nil
|
||||
}
|
||||
|
||||
if f.f != nil {
|
||||
if err := f.f.Close(); err != nil {
|
||||
return err
|
||||
}
|
||||
f.f = nil
|
||||
}
|
||||
return nil
|
||||
}
|
||||
3
mmap/go.mod
Normal file
3
mmap/go.mod
Normal file
@@ -0,0 +1,3 @@
|
||||
module git.crumpington.com/lib/mmap
|
||||
|
||||
go 1.23.2
|
||||
0
mmap/go.sum
Normal file
0
mmap/go.sum
Normal file
59
mmap/mmap.go
Normal file
59
mmap/mmap.go
Normal file
@@ -0,0 +1,59 @@
|
||||
package mmap
|
||||
|
||||
import (
|
||||
"os"
|
||||
"syscall"
|
||||
"unsafe"
|
||||
)
|
||||
|
||||
const (
|
||||
PROT_READ = syscall.PROT_READ
|
||||
PROT_WRITE = syscall.PROT_WRITE
|
||||
)
|
||||
|
||||
// Mmap creates a memory map of the given file. The flags argument should be a
|
||||
// combination of PROT_READ and PROT_WRITE. The size of the map will be the
|
||||
// file's size.
|
||||
func Map(f *os.File, flags int) ([]byte, error) {
|
||||
fi, err := f.Stat()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
size := fi.Size()
|
||||
|
||||
addr, _, errno := syscall.Syscall6(
|
||||
syscall.SYS_MMAP,
|
||||
0, // addr: 0 => allow kernel to choose
|
||||
uintptr(size),
|
||||
uintptr(flags),
|
||||
uintptr(syscall.MAP_SHARED),
|
||||
f.Fd(),
|
||||
0) // offset: 0 => start of file
|
||||
if errno != 0 {
|
||||
return nil, syscall.Errno(errno)
|
||||
}
|
||||
|
||||
return unsafe.Slice((*byte)(unsafe.Pointer(addr)), size), nil
|
||||
}
|
||||
|
||||
// Munmap unmaps the data obtained by Map.
|
||||
func Unmap(data []byte) error {
|
||||
_, _, errno := syscall.Syscall(
|
||||
syscall.SYS_MUNMAP,
|
||||
uintptr(unsafe.Pointer(&data[:1][0])),
|
||||
uintptr(cap(data)),
|
||||
0)
|
||||
if errno != 0 {
|
||||
return syscall.Errno(errno)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func Sync(b []byte) (err error) {
|
||||
_p0 := unsafe.Pointer(&b[0])
|
||||
_, _, errno := syscall.Syscall(syscall.SYS_MSYNC, uintptr(_p0), uintptr(len(b)), uintptr(syscall.MS_SYNC))
|
||||
if errno != 0 {
|
||||
err = syscall.Errno(errno)
|
||||
}
|
||||
return
|
||||
}
|
||||
Reference in New Issue
Block a user