Initial QSfera import
This commit is contained in:
@@ -0,0 +1 @@
|
||||
dist
|
||||
+2
@@ -0,0 +1,2 @@
|
||||
builds:
|
||||
- skip: true
|
||||
+28
@@ -0,0 +1,28 @@
|
||||
BSD 3-Clause License
|
||||
|
||||
Copyright (c) 2025, Kovid Goyal
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
|
||||
1. Redistributions of source code must retain the above copyright notice, this
|
||||
list of conditions and the following disclaimer.
|
||||
|
||||
2. Redistributions in binary form must reproduce the above copyright notice,
|
||||
this list of conditions and the following disclaimer in the documentation
|
||||
and/or other materials provided with the distribution.
|
||||
|
||||
3. Neither the name of the copyright holder nor the names of its
|
||||
contributors may be used to endorse or promote products derived from
|
||||
this software without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
|
||||
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
||||
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
+3
@@ -0,0 +1,3 @@
|
||||
Tools to create and manage shared memory (POSIX Shared memory) across all Unix
|
||||
variants. Pure Go, no external dependencies. Implements Go versions of
|
||||
shm_open() and shm_unlink() that interoperate with the libc versions.
|
||||
+20
@@ -0,0 +1,20 @@
|
||||
// License: GPLv3 Copyright: 2023, Kovid Goyal, <kovid at kovidgoyal.net>
|
||||
|
||||
package shm
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
|
||||
"golang.org/x/sys/unix"
|
||||
)
|
||||
|
||||
var _ = fmt.Print
|
||||
|
||||
func Fallocate_simple(fd int, size int64) (err error) {
|
||||
for {
|
||||
if err = unix.Fallocate(fd, 0, 0, size); !errors.Is(err, unix.EINTR) {
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
+16
@@ -0,0 +1,16 @@
|
||||
// License: GPLv3 Copyright: 2023, Kovid Goyal, <kovid at kovidgoyal.net>
|
||||
|
||||
//go:build !linux
|
||||
|
||||
package shm
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
)
|
||||
|
||||
var _ = fmt.Print
|
||||
|
||||
func Fallocate_simple(fd int, size int64) (err error) {
|
||||
return errors.ErrUnsupported
|
||||
}
|
||||
+31
@@ -0,0 +1,31 @@
|
||||
#!/usr/bin/env python
|
||||
# License: GPLv3 Copyright: 2024, Kovid Goyal <kovid at kovidgoyal.net>
|
||||
|
||||
import os
|
||||
import subprocess
|
||||
|
||||
|
||||
VERSION = '1.0.0'
|
||||
|
||||
|
||||
def run(*args: str):
|
||||
cp = subprocess.run(args)
|
||||
if cp.returncode != 0:
|
||||
raise SystemExit(cp.returncode)
|
||||
|
||||
|
||||
def main():
|
||||
try:
|
||||
ans = input(f'Publish version \033[91m{VERSION}\033[m (y/n): ')
|
||||
except KeyboardInterrupt:
|
||||
ans = 'n'
|
||||
if ans.lower() != 'y':
|
||||
return
|
||||
os.environ['GITHUB_TOKEN'] = open(os.path.join(os.environ['PENV'], 'github-token')).read().strip().partition(':')[2]
|
||||
run('git', 'tag', '-a', 'v' + VERSION, '-m', f'version {VERSION}')
|
||||
run('git', 'push')
|
||||
run('goreleaser', 'release', '--clean')
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
||||
+208
@@ -0,0 +1,208 @@
|
||||
// License: GPLv3 Copyright: 2022, Kovid Goyal, <kovid at kovidgoyal.net>
|
||||
|
||||
package shm
|
||||
|
||||
import (
|
||||
"encoding/binary"
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
"io/fs"
|
||||
"os"
|
||||
"strings"
|
||||
|
||||
"golang.org/x/sys/unix"
|
||||
)
|
||||
|
||||
var _ = fmt.Print
|
||||
var ErrPatternHasSeparator = errors.New("The specified pattern has file path separators in it")
|
||||
var ErrPatternTooLong = errors.New("The specified pattern for the SHM name is too long")
|
||||
|
||||
type ErrNotSupported struct {
|
||||
err error
|
||||
}
|
||||
|
||||
func (self *ErrNotSupported) Error() string {
|
||||
return fmt.Sprintf("POSIX shared memory not supported on this platform: with underlying error: %v", self.err)
|
||||
}
|
||||
|
||||
// prefix_and_suffix splits pattern by the last wildcard "*", if applicable,
|
||||
// returning prefix as the part before "*" and suffix as the part after "*".
|
||||
func prefix_and_suffix(pattern string) (prefix, suffix string, err error) {
|
||||
for i := 0; i < len(pattern); i++ {
|
||||
if os.IsPathSeparator(pattern[i]) {
|
||||
return "", "", ErrPatternHasSeparator
|
||||
}
|
||||
}
|
||||
if pos := strings.LastIndexByte(pattern, '*'); pos != -1 {
|
||||
prefix, suffix = pattern[:pos], pattern[pos+1:]
|
||||
} else {
|
||||
prefix = pattern
|
||||
}
|
||||
return prefix, suffix, nil
|
||||
}
|
||||
|
||||
type MMap interface {
|
||||
Close() error
|
||||
Unlink() error
|
||||
Slice() []byte
|
||||
Name() string
|
||||
IsFileSystemBacked() bool
|
||||
FileSystemName() string
|
||||
Stat() (fs.FileInfo, error)
|
||||
Flush() error
|
||||
Seek(offset int64, whence int) (ret int64, err error)
|
||||
Read(b []byte) (n int, err error)
|
||||
Write(b []byte) (n int, err error)
|
||||
}
|
||||
|
||||
type AccessFlags int
|
||||
|
||||
const (
|
||||
READ AccessFlags = iota
|
||||
WRITE
|
||||
COPY
|
||||
)
|
||||
|
||||
func mmap(sz int, access AccessFlags, fd int, off int64) ([]byte, error) {
|
||||
flags := unix.MAP_SHARED
|
||||
prot := unix.PROT_READ
|
||||
switch access {
|
||||
case COPY:
|
||||
prot |= unix.PROT_WRITE
|
||||
flags = unix.MAP_PRIVATE
|
||||
case WRITE:
|
||||
prot |= unix.PROT_WRITE
|
||||
}
|
||||
|
||||
b, err := unix.Mmap(fd, off, sz, prot, flags)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return b, nil
|
||||
}
|
||||
|
||||
func munmap(s []byte) error {
|
||||
return unix.Munmap(s)
|
||||
}
|
||||
|
||||
func CreateTemp(pattern string, size uint64) (MMap, error) {
|
||||
return create_temp(pattern, size)
|
||||
}
|
||||
|
||||
func truncate_or_unlink(ans *os.File, size uint64, unlink func(string) error) (err error) {
|
||||
fd := int(ans.Fd())
|
||||
sz := int64(size)
|
||||
if err = Fallocate_simple(fd, sz); err != nil {
|
||||
if !errors.Is(err, errors.ErrUnsupported) {
|
||||
return fmt.Errorf("fallocate() failed on fd from shm_open(%s) with size: %d with error: %w", ans.Name(), size, err)
|
||||
}
|
||||
for {
|
||||
if err = unix.Ftruncate(fd, sz); !errors.Is(err, unix.EINTR) {
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
if err != nil {
|
||||
_ = ans.Close()
|
||||
_ = unlink(ans.Name())
|
||||
return fmt.Errorf("Failed to ftruncate() SHM file %s to size: %d with error: %w", ans.Name(), size, err)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
const NUM_BYTES_FOR_SIZE = 4
|
||||
|
||||
var ErrRegionTooSmall = errors.New("mmaped region too small")
|
||||
|
||||
func WriteWithSize(self MMap, b []byte, at int) error {
|
||||
if len(self.Slice()) < at+len(b)+NUM_BYTES_FOR_SIZE {
|
||||
return ErrRegionTooSmall
|
||||
}
|
||||
binary.BigEndian.PutUint32(self.Slice()[at:], uint32(len(b)))
|
||||
copy(self.Slice()[at+NUM_BYTES_FOR_SIZE:], b)
|
||||
return nil
|
||||
}
|
||||
|
||||
func ReadWithSize(self MMap, at int) ([]byte, error) {
|
||||
s := self.Slice()[at:]
|
||||
if len(s) < NUM_BYTES_FOR_SIZE {
|
||||
return nil, ErrRegionTooSmall
|
||||
}
|
||||
size := int(binary.BigEndian.Uint32(self.Slice()[at : at+NUM_BYTES_FOR_SIZE]))
|
||||
s = s[NUM_BYTES_FOR_SIZE:]
|
||||
if len(s) < size {
|
||||
return nil, ErrRegionTooSmall
|
||||
}
|
||||
return s[:size], nil
|
||||
}
|
||||
|
||||
func ReadWithSizeAndUnlink(name string, file_callback ...func(fs.FileInfo) error) ([]byte, error) {
|
||||
mmap, err := Open(name, 0)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if len(file_callback) > 0 {
|
||||
s, err := mmap.Stat()
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("Failed to stat SHM file with error: %w", err)
|
||||
}
|
||||
for _, f := range file_callback {
|
||||
err = f(s)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
}
|
||||
defer func() {
|
||||
mmap.Close()
|
||||
_ = mmap.Unlink()
|
||||
}()
|
||||
slice, err := ReadWithSize(mmap, 0)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
ans := make([]byte, len(slice))
|
||||
copy(ans, slice)
|
||||
return ans, nil
|
||||
}
|
||||
|
||||
func Read(self MMap, b []byte) (n int, err error) {
|
||||
pos, err := self.Seek(0, io.SeekCurrent)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
if pos < 0 {
|
||||
pos = 0
|
||||
}
|
||||
s := self.Slice()
|
||||
sz := int64(len(s))
|
||||
if pos >= sz {
|
||||
return 0, io.EOF
|
||||
}
|
||||
n = copy(b, s[pos:])
|
||||
_, err = self.Seek(int64(n), io.SeekCurrent)
|
||||
return
|
||||
}
|
||||
|
||||
func Write(self MMap, b []byte) (n int, err error) {
|
||||
if len(b) == 0 {
|
||||
return 0, nil
|
||||
}
|
||||
pos, _ := self.Seek(0, io.SeekCurrent)
|
||||
if pos < 0 {
|
||||
pos = 0
|
||||
}
|
||||
s := self.Slice()
|
||||
if pos >= int64(len(s)) {
|
||||
return 0, io.ErrShortWrite
|
||||
}
|
||||
n = copy(s[pos:], b)
|
||||
if _, err = self.Seek(int64(n), io.SeekCurrent); err != nil {
|
||||
return n, err
|
||||
}
|
||||
if n < len(b) {
|
||||
return n, io.ErrShortWrite
|
||||
}
|
||||
return n, nil
|
||||
}
|
||||
+187
@@ -0,0 +1,187 @@
|
||||
// License: GPLv3 Copyright: 2022, Kovid Goyal, <kovid at kovidgoyal.net>
|
||||
//go:build linux || netbsd || openbsd || dragonfly
|
||||
|
||||
package shm
|
||||
|
||||
import (
|
||||
"crypto/sha256"
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
"io/fs"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"runtime"
|
||||
"strings"
|
||||
|
||||
"golang.org/x/sys/unix"
|
||||
)
|
||||
|
||||
var _ = fmt.Print
|
||||
|
||||
type file_based_mmap struct {
|
||||
f *os.File
|
||||
pos int64
|
||||
region []byte
|
||||
unlinked bool
|
||||
special_name string
|
||||
}
|
||||
|
||||
func ShmUnlink(name string) error {
|
||||
if runtime.GOOS == "openbsd" {
|
||||
return os.Remove(openbsd_shm_path(name))
|
||||
}
|
||||
name = strings.TrimPrefix(name, "/")
|
||||
return os.Remove(filepath.Join(SHM_DIR, name))
|
||||
}
|
||||
|
||||
func file_mmap(f *os.File, size uint64, access AccessFlags, truncate bool, special_name string) (MMap, error) {
|
||||
if truncate {
|
||||
err := truncate_or_unlink(f, size, os.Remove)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
region, err := mmap(int(size), access, int(f.Fd()), 0)
|
||||
if err != nil {
|
||||
f.Close()
|
||||
os.Remove(f.Name())
|
||||
return nil, err
|
||||
}
|
||||
return &file_based_mmap{f: f, region: region, special_name: special_name}, nil
|
||||
}
|
||||
|
||||
func (self *file_based_mmap) Seek(offset int64, whence int) (ret int64, err error) {
|
||||
switch whence {
|
||||
case io.SeekStart:
|
||||
self.pos = offset
|
||||
case io.SeekEnd:
|
||||
self.pos = int64(len(self.region)) + offset
|
||||
case io.SeekCurrent:
|
||||
self.pos += offset
|
||||
}
|
||||
return self.pos, nil
|
||||
}
|
||||
|
||||
func (self *file_based_mmap) Read(b []byte) (n int, err error) {
|
||||
return Read(self, b)
|
||||
}
|
||||
|
||||
func (self *file_based_mmap) Write(b []byte) (n int, err error) {
|
||||
return Write(self, b)
|
||||
}
|
||||
|
||||
func (self *file_based_mmap) Stat() (fs.FileInfo, error) {
|
||||
return self.f.Stat()
|
||||
}
|
||||
|
||||
func (self *file_based_mmap) Name() string {
|
||||
if self.special_name != "" {
|
||||
return self.special_name
|
||||
}
|
||||
return filepath.Base(self.f.Name())
|
||||
}
|
||||
|
||||
func (self *file_based_mmap) Flush() error {
|
||||
return unix.Msync(self.region, unix.MS_SYNC)
|
||||
}
|
||||
|
||||
func (self *file_based_mmap) FileSystemName() string {
|
||||
return self.f.Name()
|
||||
}
|
||||
|
||||
func (self *file_based_mmap) Slice() []byte {
|
||||
return self.region
|
||||
}
|
||||
|
||||
func (self *file_based_mmap) Close() (err error) {
|
||||
if self.region != nil {
|
||||
self.f.Close()
|
||||
err = munmap(self.region)
|
||||
self.region = nil
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
func (self *file_based_mmap) Unlink() (err error) {
|
||||
if self.unlinked {
|
||||
return nil
|
||||
}
|
||||
self.unlinked = true
|
||||
return os.Remove(self.f.Name())
|
||||
}
|
||||
|
||||
func (self *file_based_mmap) IsFileSystemBacked() bool { return true }
|
||||
|
||||
func openbsd_shm_path(name string) string {
|
||||
hash := sha256.Sum256(UnsafeStringToBytes(name))
|
||||
return filepath.Join(SHM_DIR, UnsafeBytesToString(hash[:])+".shm")
|
||||
}
|
||||
|
||||
func file_path_from_name(name string) string {
|
||||
// See https://github.com/openbsd/src/blob/master/lib/libc/gen/shm_open.c
|
||||
if runtime.GOOS == "openbsd" {
|
||||
return openbsd_shm_path(name)
|
||||
}
|
||||
return filepath.Join(SHM_DIR, name)
|
||||
}
|
||||
|
||||
func create_temp(pattern string, size uint64) (ans MMap, err error) {
|
||||
special_name := ""
|
||||
var prefix, suffix string
|
||||
prefix, suffix, err = prefix_and_suffix(pattern)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
var f *os.File
|
||||
try := 0
|
||||
for {
|
||||
name := prefix + RandomFilename() + suffix
|
||||
path := file_path_from_name(name)
|
||||
f, err = os.OpenFile(path, os.O_EXCL|os.O_CREATE|os.O_RDWR, 0600)
|
||||
if err != nil {
|
||||
if errors.Is(err, fs.ErrExist) {
|
||||
try += 1
|
||||
if try > 10000 {
|
||||
return nil, &os.PathError{Op: "createtemp", Path: prefix + "*" + suffix, Err: fs.ErrExist}
|
||||
}
|
||||
continue
|
||||
}
|
||||
if errors.Is(err, fs.ErrNotExist) {
|
||||
return nil, &ErrNotSupported{err: err}
|
||||
}
|
||||
return
|
||||
}
|
||||
break
|
||||
}
|
||||
return file_mmap(f, size, WRITE, true, special_name)
|
||||
}
|
||||
|
||||
func open(name string) (*os.File, error) {
|
||||
ans, err := os.OpenFile(file_path_from_name(name), os.O_RDONLY, 0)
|
||||
if err != nil {
|
||||
if errors.Is(err, fs.ErrNotExist) {
|
||||
if _, serr := os.Stat(SHM_DIR); serr != nil && errors.Is(serr, fs.ErrNotExist) {
|
||||
return nil, &ErrNotSupported{err: serr}
|
||||
}
|
||||
}
|
||||
return nil, err
|
||||
}
|
||||
return ans, nil
|
||||
}
|
||||
|
||||
func Open(name string, size uint64) (MMap, error) {
|
||||
ans, err := open(name)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if size == 0 {
|
||||
s, err := ans.Stat()
|
||||
if err != nil {
|
||||
ans.Close()
|
||||
return nil, fmt.Errorf("Failed to stat SHM file with error: %w", err)
|
||||
}
|
||||
size = uint64(s.Size())
|
||||
}
|
||||
return file_mmap(ans, size, READ, false, name)
|
||||
}
|
||||
+198
@@ -0,0 +1,198 @@
|
||||
// License: GPLv3 Copyright: 2022, Kovid Goyal, <kovid at kovidgoyal.net>
|
||||
//go:build darwin || freebsd
|
||||
|
||||
package shm
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
"io/fs"
|
||||
"os"
|
||||
"strings"
|
||||
"unsafe"
|
||||
|
||||
"golang.org/x/sys/unix"
|
||||
)
|
||||
|
||||
var _ = fmt.Print
|
||||
|
||||
// ByteSliceFromString makes a zero terminated byte slice from the string
|
||||
func ByteSliceFromString(s string) []byte {
|
||||
a := make([]byte, len(s)+1)
|
||||
copy(a, s)
|
||||
return a
|
||||
}
|
||||
|
||||
func BytePtrFromString(s string) *byte {
|
||||
a := ByteSliceFromString(s)
|
||||
return &a[0]
|
||||
}
|
||||
|
||||
func shm_unlink(name string) (err error) {
|
||||
bname := BytePtrFromString(name)
|
||||
for {
|
||||
_, _, errno := unix.Syscall(unix.SYS_SHM_UNLINK, uintptr(unsafe.Pointer(bname)), 0, 0)
|
||||
if errno != unix.EINTR {
|
||||
if errno != 0 {
|
||||
if errno == unix.ENOENT {
|
||||
err = fs.ErrNotExist
|
||||
} else {
|
||||
err = fmt.Errorf("shm_unlink() failed with error: %w", errno)
|
||||
}
|
||||
}
|
||||
break
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func ShmUnlink(name string) error {
|
||||
return shm_unlink(name)
|
||||
}
|
||||
|
||||
func shm_open(name string, flags, perm int) (ans *os.File, err error) {
|
||||
bname := BytePtrFromString(name)
|
||||
var fd uintptr
|
||||
var errno unix.Errno
|
||||
for {
|
||||
fd, _, errno = unix.Syscall(unix.SYS_SHM_OPEN, uintptr(unsafe.Pointer(bname)), uintptr(flags), uintptr(perm))
|
||||
if errno != unix.EINTR {
|
||||
if errno != 0 {
|
||||
err = fmt.Errorf("shm_open() failed with error: %w", errno)
|
||||
}
|
||||
break
|
||||
}
|
||||
}
|
||||
if err == nil {
|
||||
ans = os.NewFile(fd, name)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
type syscall_based_mmap struct {
|
||||
f *os.File
|
||||
pos int64
|
||||
region []byte
|
||||
unlinked bool
|
||||
}
|
||||
|
||||
func syscall_mmap(f *os.File, size uint64, access AccessFlags, truncate bool) (MMap, error) {
|
||||
if truncate {
|
||||
err := truncate_or_unlink(f, size, shm_unlink)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("truncate failed with error: %w", err)
|
||||
}
|
||||
}
|
||||
region, err := mmap(int(size), access, int(f.Fd()), 0)
|
||||
if err != nil {
|
||||
_ = f.Close()
|
||||
_ = shm_unlink(f.Name())
|
||||
return nil, fmt.Errorf("mmap failed with error: %w", err)
|
||||
}
|
||||
return &syscall_based_mmap{f: f, region: region}, nil
|
||||
}
|
||||
|
||||
func (self *syscall_based_mmap) Name() string {
|
||||
return self.f.Name()
|
||||
}
|
||||
func (self *syscall_based_mmap) Stat() (fs.FileInfo, error) {
|
||||
return self.f.Stat()
|
||||
}
|
||||
|
||||
func (self *syscall_based_mmap) Flush() error {
|
||||
return unix.Msync(self.region, unix.MS_SYNC)
|
||||
}
|
||||
|
||||
func (self *syscall_based_mmap) Slice() []byte {
|
||||
return self.region
|
||||
}
|
||||
|
||||
func (self *syscall_based_mmap) Close() (err error) {
|
||||
if self.region != nil {
|
||||
self.f.Close()
|
||||
munmap(self.region)
|
||||
self.region = nil
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func (self *syscall_based_mmap) Unlink() (err error) {
|
||||
if self.unlinked {
|
||||
return nil
|
||||
}
|
||||
self.unlinked = true
|
||||
return shm_unlink(self.Name())
|
||||
}
|
||||
|
||||
func (self *syscall_based_mmap) Seek(offset int64, whence int) (ret int64, err error) {
|
||||
switch whence {
|
||||
case io.SeekStart:
|
||||
self.pos = offset
|
||||
case io.SeekEnd:
|
||||
self.pos = int64(len(self.region)) + offset
|
||||
case io.SeekCurrent:
|
||||
self.pos += offset
|
||||
}
|
||||
return self.pos, nil
|
||||
}
|
||||
|
||||
func (self *syscall_based_mmap) Read(b []byte) (n int, err error) {
|
||||
return Read(self, b)
|
||||
}
|
||||
|
||||
func (self *syscall_based_mmap) Write(b []byte) (n int, err error) {
|
||||
return Write(self, b)
|
||||
}
|
||||
|
||||
func (self *syscall_based_mmap) IsFileSystemBacked() bool { return false }
|
||||
func (self *syscall_based_mmap) FileSystemName() string { return "" }
|
||||
|
||||
func create_temp(pattern string, size uint64) (ans MMap, err error) {
|
||||
var prefix, suffix string
|
||||
prefix, suffix, err = prefix_and_suffix(pattern)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
if SHM_REQUIRED_PREFIX != "" && !strings.HasPrefix(pattern, SHM_REQUIRED_PREFIX) {
|
||||
// FreeBSD requires name to start with /
|
||||
prefix = SHM_REQUIRED_PREFIX + prefix
|
||||
}
|
||||
var f *os.File
|
||||
try := 0
|
||||
for {
|
||||
name := prefix + RandomFilename() + suffix
|
||||
if len(name) > SHM_NAME_MAX {
|
||||
return nil, ErrPatternTooLong
|
||||
}
|
||||
f, err = shm_open(name, os.O_EXCL|os.O_CREATE|os.O_RDWR, 0600)
|
||||
if err != nil && (errors.Is(err, fs.ErrExist) || errors.Unwrap(err) == unix.EEXIST) {
|
||||
try += 1
|
||||
if try > 10000 {
|
||||
return nil, &os.PathError{Op: "createtemp", Path: prefix + "*" + suffix, Err: fs.ErrExist}
|
||||
}
|
||||
continue
|
||||
}
|
||||
break
|
||||
}
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return syscall_mmap(f, size, WRITE, true)
|
||||
}
|
||||
|
||||
func Open(name string, size uint64) (MMap, error) {
|
||||
ans, err := shm_open(name, os.O_RDONLY, 0)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if size == 0 {
|
||||
s, err := ans.Stat()
|
||||
if err != nil {
|
||||
ans.Close()
|
||||
return nil, fmt.Errorf("Failed to stat SHM file with error: %w", err)
|
||||
}
|
||||
size = uint64(s.Size())
|
||||
}
|
||||
return syscall_mmap(ans, size, READ, false)
|
||||
}
|
||||
+7
@@ -0,0 +1,7 @@
|
||||
// License: GPLv3 Copyright: 2022, Kovid Goyal, <kovid at kovidgoyal.net>
|
||||
|
||||
package shm
|
||||
|
||||
const SHM_NAME_MAX = 30
|
||||
const SHM_REQUIRED_PREFIX = ""
|
||||
const SHM_DIR = ""
|
||||
+12
@@ -0,0 +1,12 @@
|
||||
// License: GPLv3 Copyright: 2022, Kovid Goyal, <kovid at kovidgoyal.net>
|
||||
|
||||
package shm
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
)
|
||||
|
||||
var _ = fmt.Print
|
||||
|
||||
// https://www.dragonflybsd.org/cgi/web-man?command=shm_open§ion=3
|
||||
const SHM_DIR = "/var/run/shm"
|
||||
+7
@@ -0,0 +1,7 @@
|
||||
// License: GPLv3 Copyright: 2022, Kovid Goyal, <kovid at kovidgoyal.net>
|
||||
|
||||
package shm
|
||||
|
||||
const SHM_NAME_MAX = 1023
|
||||
const SHM_REQUIRED_PREFIX = "/"
|
||||
const SHM_DIR = ""
|
||||
+11
@@ -0,0 +1,11 @@
|
||||
// License: GPLv3 Copyright: 2022, Kovid Goyal, <kovid at kovidgoyal.net>
|
||||
|
||||
package shm
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
)
|
||||
|
||||
var _ = fmt.Print
|
||||
|
||||
const SHM_DIR = "/dev/shm"
|
||||
+11
@@ -0,0 +1,11 @@
|
||||
// License: GPLv3 Copyright: 2022, Kovid Goyal, <kovid at kovidgoyal.net>
|
||||
|
||||
package shm
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
)
|
||||
|
||||
var _ = fmt.Print
|
||||
|
||||
const SHM_DIR = "/var/shm"
|
||||
+11
@@ -0,0 +1,11 @@
|
||||
// License: GPLv3 Copyright: 2022, Kovid Goyal, <kovid at kovidgoyal.net>
|
||||
|
||||
package shm
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
)
|
||||
|
||||
var _ = fmt.Print
|
||||
|
||||
const SHM_DIR = "/tmp"
|
||||
+35
@@ -0,0 +1,35 @@
|
||||
package shm
|
||||
|
||||
import (
|
||||
"crypto/rand"
|
||||
"encoding/base32"
|
||||
"fmt"
|
||||
not_rand "math/rand/v2"
|
||||
"strconv"
|
||||
"unsafe"
|
||||
)
|
||||
|
||||
var _ = fmt.Print
|
||||
|
||||
func RandomFilename() string {
|
||||
b := []byte{0, 0, 0, 0, 0, 0, 0, 0}
|
||||
_, err := rand.Read(b)
|
||||
if err != nil {
|
||||
return strconv.FormatUint(uint64(not_rand.Uint32()), 16)
|
||||
}
|
||||
return base32.StdEncoding.WithPadding(base32.NoPadding).EncodeToString(b)
|
||||
}
|
||||
|
||||
// Unsafely converts s into a byte slice.
|
||||
// If you modify b, then s will also be modified. This violates the
|
||||
// property that strings are immutable.
|
||||
func UnsafeStringToBytes(s string) (b []byte) {
|
||||
return unsafe.Slice(unsafe.StringData(s), len(s))
|
||||
}
|
||||
|
||||
// Unsafely converts b into a string.
|
||||
// If you modify b, then s will also be modified. This violates the
|
||||
// property that strings are immutable.
|
||||
func UnsafeBytesToString(b []byte) (s string) {
|
||||
return unsafe.String(unsafe.SliceData(b), len(b))
|
||||
}
|
||||
Reference in New Issue
Block a user