mirror of
https://github.com/luxfi/kms.git
synced 2026-10-30 16:23:36 +00:00
Squashes all pre-rewrite history into a single root commit. Previous tree: - 14506 commits including upstream Infisical fork history - Multiple merge chains carrying pre-purge content Force-rewrite per disk-space reclamation discipline. GHCR images (1.9.9, 1.9.11) remain immutable; their git lineage is no longer materialized.
208 lines
5.2 KiB
Go
208 lines
5.2 KiB
Go
/*
|
|
* SPDX-FileCopyrightText: © 2017-2025 Istari Digital, Inc.
|
|
* SPDX-License-Identifier: Apache-2.0
|
|
*/
|
|
|
|
package z
|
|
|
|
import (
|
|
"encoding/binary"
|
|
"errors"
|
|
"fmt"
|
|
"io"
|
|
"os"
|
|
"path/filepath"
|
|
)
|
|
|
|
// MmapFile represents an mmapd file and includes both the buffer to the data
|
|
// and the file descriptor.
|
|
type MmapFile struct {
|
|
Data []byte
|
|
Fd *os.File
|
|
}
|
|
|
|
var NewFile = errors.New("Create a new file")
|
|
|
|
func OpenMmapFileUsing(fd *os.File, sz int, writable bool) (*MmapFile, error) {
|
|
filename := fd.Name()
|
|
fi, err := fd.Stat()
|
|
if err != nil {
|
|
return nil, errors.Join(err, fmt.Errorf("cannot stat file: %s", filename))
|
|
}
|
|
|
|
var rerr error
|
|
fileSize := fi.Size()
|
|
if sz > 0 && fileSize == 0 {
|
|
// If file is empty, truncate it to sz.
|
|
if err := fd.Truncate(int64(sz)); err != nil {
|
|
return nil, errors.Join(err, errors.New("error while truncation"))
|
|
}
|
|
fileSize = int64(sz)
|
|
rerr = NewFile
|
|
}
|
|
|
|
// fmt.Printf("Mmaping file: %s with writable: %v filesize: %d\n", fd.Name(), writable, fileSize)
|
|
buf, err := Mmap(fd, writable, fileSize) // Mmap up to file size.
|
|
if err != nil {
|
|
return nil, errors.Join(err, fmt.Errorf("while mmapping %s with size: %d", fd.Name(), fileSize))
|
|
}
|
|
|
|
if fileSize == 0 {
|
|
dir, _ := filepath.Split(filename)
|
|
if err := SyncDir(dir); err != nil {
|
|
return nil, err
|
|
}
|
|
}
|
|
return &MmapFile{
|
|
Data: buf,
|
|
Fd: fd,
|
|
}, rerr
|
|
}
|
|
|
|
// OpenMmapFile opens an existing file or creates a new file. If the file is
|
|
// created, it would truncate the file to maxSz. In both cases, it would mmap
|
|
// the file to maxSz and returned it. In case the file is created, z.NewFile is
|
|
// returned.
|
|
func OpenMmapFile(filename string, flag int, maxSz int) (*MmapFile, error) {
|
|
// fmt.Printf("opening file %s with flag: %v\n", filename, flag)
|
|
fd, err := os.OpenFile(filename, flag, 0666)
|
|
if err != nil {
|
|
return nil, errors.Join(err, fmt.Errorf("unable to open: %s", filename))
|
|
}
|
|
writable := true
|
|
if flag == os.O_RDONLY {
|
|
writable = false
|
|
}
|
|
return OpenMmapFileUsing(fd, maxSz, writable)
|
|
}
|
|
|
|
type mmapReader struct {
|
|
Data []byte
|
|
offset int
|
|
}
|
|
|
|
func (mr *mmapReader) Read(buf []byte) (int, error) {
|
|
if mr.offset > len(mr.Data) {
|
|
return 0, io.EOF
|
|
}
|
|
n := copy(buf, mr.Data[mr.offset:])
|
|
mr.offset += n
|
|
if n < len(buf) {
|
|
return n, io.EOF
|
|
}
|
|
return n, nil
|
|
}
|
|
|
|
func (m *MmapFile) NewReader(offset int) io.Reader {
|
|
return &mmapReader{
|
|
Data: m.Data,
|
|
offset: offset,
|
|
}
|
|
}
|
|
|
|
// Bytes returns data starting from offset off of size sz. If there's not enough data, it would
|
|
// return nil slice and io.EOF.
|
|
func (m *MmapFile) Bytes(off, sz int) ([]byte, error) {
|
|
if len(m.Data[off:]) < sz {
|
|
return nil, io.EOF
|
|
}
|
|
return m.Data[off : off+sz], nil
|
|
}
|
|
|
|
// Slice returns the slice at the given offset.
|
|
func (m *MmapFile) Slice(offset int) []byte {
|
|
sz := binary.BigEndian.Uint32(m.Data[offset:])
|
|
start := offset + 4
|
|
next := start + int(sz)
|
|
if next > len(m.Data) {
|
|
return []byte{}
|
|
}
|
|
res := m.Data[start:next]
|
|
return res
|
|
}
|
|
|
|
// AllocateSlice allocates a slice of the given size at the given offset.
|
|
func (m *MmapFile) AllocateSlice(sz, offset int) ([]byte, int, error) {
|
|
start := offset + 4
|
|
|
|
// If the file is too small, double its size or increase it by 1GB, whichever is smaller.
|
|
if start+sz > len(m.Data) {
|
|
const oneGB = 1 << 30
|
|
growBy := len(m.Data)
|
|
if growBy > oneGB {
|
|
growBy = oneGB
|
|
}
|
|
if growBy < sz+4 {
|
|
growBy = sz + 4
|
|
}
|
|
if err := m.Truncate(int64(len(m.Data) + growBy)); err != nil {
|
|
return nil, 0, err
|
|
}
|
|
}
|
|
|
|
binary.BigEndian.PutUint32(m.Data[offset:], uint32(sz))
|
|
return m.Data[start : start+sz], start + sz, nil
|
|
}
|
|
|
|
func (m *MmapFile) Sync() error {
|
|
if m == nil {
|
|
return nil
|
|
}
|
|
return Msync(m.Data)
|
|
}
|
|
|
|
func (m *MmapFile) Delete() error {
|
|
// Badger can set the m.Data directly, without setting any Fd. In that case, this should be a
|
|
// NOOP.
|
|
if m.Fd == nil {
|
|
return nil
|
|
}
|
|
|
|
if err := Munmap(m.Data); err != nil {
|
|
return fmt.Errorf("while munmap file: %s, error: %v\n", m.Fd.Name(), err)
|
|
}
|
|
m.Data = nil
|
|
if err := m.Fd.Truncate(0); err != nil {
|
|
return fmt.Errorf("while truncate file: %s, error: %v\n", m.Fd.Name(), err)
|
|
}
|
|
if err := m.Fd.Close(); err != nil {
|
|
return fmt.Errorf("while close file: %s, error: %v\n", m.Fd.Name(), err)
|
|
}
|
|
return os.Remove(m.Fd.Name())
|
|
}
|
|
|
|
// Close would close the file. It would also truncate the file if maxSz >= 0.
|
|
func (m *MmapFile) Close(maxSz int64) error {
|
|
// Badger can set the m.Data directly, without setting any Fd. In that case, this should be a
|
|
// NOOP.
|
|
if m.Fd == nil {
|
|
return nil
|
|
}
|
|
if err := m.Sync(); err != nil {
|
|
return fmt.Errorf("while sync file: %s, error: %v\n", m.Fd.Name(), err)
|
|
}
|
|
if err := Munmap(m.Data); err != nil {
|
|
return fmt.Errorf("while munmap file: %s, error: %v\n", m.Fd.Name(), err)
|
|
}
|
|
if maxSz >= 0 {
|
|
if err := m.Fd.Truncate(maxSz); err != nil {
|
|
return fmt.Errorf("while truncate file: %s, error: %v\n", m.Fd.Name(), err)
|
|
}
|
|
}
|
|
return m.Fd.Close()
|
|
}
|
|
|
|
func SyncDir(dir string) error {
|
|
df, err := os.Open(dir)
|
|
if err != nil {
|
|
return errors.Join(err, fmt.Errorf("while opening %s", dir))
|
|
}
|
|
if err := df.Sync(); err != nil {
|
|
return errors.Join(err, fmt.Errorf("while syncing %s", dir))
|
|
}
|
|
if err := df.Close(); err != nil {
|
|
return errors.Join(err, fmt.Errorf("while closing %s", dir))
|
|
}
|
|
return nil
|
|
}
|