Add a new generic container registry client via a new `container` package. Use this to create a command line utility as well as a new upload target for container registries. The code uses the github.com/containers/* project and packages to interact with container registires that is also used by skopeo, podman et al. One if the dependencies is `proglottis/gpgme` that is using cgo to bind libgpgme, so we have to add the corresponding devel package to the BuildRequires as well as installing it on CI. Checks will follow later via an integration test.
141 lines
3.7 KiB
Go
141 lines
3.7 KiB
Go
package bbolt
|
|
|
|
import (
|
|
"fmt"
|
|
"os"
|
|
"syscall"
|
|
"time"
|
|
"unsafe"
|
|
)
|
|
|
|
// LockFileEx code derived from golang build filemutex_windows.go @ v1.5.1
|
|
var (
|
|
modkernel32 = syscall.NewLazyDLL("kernel32.dll")
|
|
procLockFileEx = modkernel32.NewProc("LockFileEx")
|
|
procUnlockFileEx = modkernel32.NewProc("UnlockFileEx")
|
|
)
|
|
|
|
const (
|
|
// see https://msdn.microsoft.com/en-us/library/windows/desktop/aa365203(v=vs.85).aspx
|
|
flagLockExclusive = 2
|
|
flagLockFailImmediately = 1
|
|
|
|
// see https://msdn.microsoft.com/en-us/library/windows/desktop/ms681382(v=vs.85).aspx
|
|
errLockViolation syscall.Errno = 0x21
|
|
)
|
|
|
|
func lockFileEx(h syscall.Handle, flags, reserved, locklow, lockhigh uint32, ol *syscall.Overlapped) (err error) {
|
|
r, _, err := procLockFileEx.Call(uintptr(h), uintptr(flags), uintptr(reserved), uintptr(locklow), uintptr(lockhigh), uintptr(unsafe.Pointer(ol)))
|
|
if r == 0 {
|
|
return err
|
|
}
|
|
return nil
|
|
}
|
|
|
|
func unlockFileEx(h syscall.Handle, reserved, locklow, lockhigh uint32, ol *syscall.Overlapped) (err error) {
|
|
r, _, err := procUnlockFileEx.Call(uintptr(h), uintptr(reserved), uintptr(locklow), uintptr(lockhigh), uintptr(unsafe.Pointer(ol)), 0)
|
|
if r == 0 {
|
|
return err
|
|
}
|
|
return nil
|
|
}
|
|
|
|
// fdatasync flushes written data to a file descriptor.
|
|
func fdatasync(db *DB) error {
|
|
return db.file.Sync()
|
|
}
|
|
|
|
// flock acquires an advisory lock on a file descriptor.
|
|
func flock(db *DB, exclusive bool, timeout time.Duration) error {
|
|
var t time.Time
|
|
if timeout != 0 {
|
|
t = time.Now()
|
|
}
|
|
var flag uint32 = flagLockFailImmediately
|
|
if exclusive {
|
|
flag |= flagLockExclusive
|
|
}
|
|
for {
|
|
// Fix for https://github.com/etcd-io/bbolt/issues/121. Use byte-range
|
|
// -1..0 as the lock on the database file.
|
|
var m1 uint32 = (1 << 32) - 1 // -1 in a uint32
|
|
err := lockFileEx(syscall.Handle(db.file.Fd()), flag, 0, 1, 0, &syscall.Overlapped{
|
|
Offset: m1,
|
|
OffsetHigh: m1,
|
|
})
|
|
|
|
if err == nil {
|
|
return nil
|
|
} else if err != errLockViolation {
|
|
return err
|
|
}
|
|
|
|
// If we timed oumercit then return an error.
|
|
if timeout != 0 && time.Since(t) > timeout-flockRetryTimeout {
|
|
return ErrTimeout
|
|
}
|
|
|
|
// Wait for a bit and try again.
|
|
time.Sleep(flockRetryTimeout)
|
|
}
|
|
}
|
|
|
|
// funlock releases an advisory lock on a file descriptor.
|
|
func funlock(db *DB) error {
|
|
var m1 uint32 = (1 << 32) - 1 // -1 in a uint32
|
|
err := unlockFileEx(syscall.Handle(db.file.Fd()), 0, 1, 0, &syscall.Overlapped{
|
|
Offset: m1,
|
|
OffsetHigh: m1,
|
|
})
|
|
return err
|
|
}
|
|
|
|
// mmap memory maps a DB's data file.
|
|
// Based on: https://github.com/edsrzf/mmap-go
|
|
func mmap(db *DB, sz int) error {
|
|
if !db.readOnly {
|
|
// Truncate the database to the size of the mmap.
|
|
if err := db.file.Truncate(int64(sz)); err != nil {
|
|
return fmt.Errorf("truncate: %s", err)
|
|
}
|
|
}
|
|
|
|
// Open a file mapping handle.
|
|
sizelo := uint32(sz >> 32)
|
|
sizehi := uint32(sz) & 0xffffffff
|
|
h, errno := syscall.CreateFileMapping(syscall.Handle(db.file.Fd()), nil, syscall.PAGE_READONLY, sizelo, sizehi, nil)
|
|
if h == 0 {
|
|
return os.NewSyscallError("CreateFileMapping", errno)
|
|
}
|
|
|
|
// Create the memory map.
|
|
addr, errno := syscall.MapViewOfFile(h, syscall.FILE_MAP_READ, 0, 0, uintptr(sz))
|
|
if addr == 0 {
|
|
return os.NewSyscallError("MapViewOfFile", errno)
|
|
}
|
|
|
|
// Close mapping handle.
|
|
if err := syscall.CloseHandle(syscall.Handle(h)); err != nil {
|
|
return os.NewSyscallError("CloseHandle", err)
|
|
}
|
|
|
|
// Convert to a byte array.
|
|
db.data = ((*[maxMapSize]byte)(unsafe.Pointer(addr)))
|
|
db.datasz = sz
|
|
|
|
return nil
|
|
}
|
|
|
|
// munmap unmaps a pointer from a file.
|
|
// Based on: https://github.com/edsrzf/mmap-go
|
|
func munmap(db *DB) error {
|
|
if db.data == nil {
|
|
return nil
|
|
}
|
|
|
|
addr := (uintptr)(unsafe.Pointer(&db.data[0]))
|
|
if err := syscall.UnmapViewOfFile(addr); err != nil {
|
|
return os.NewSyscallError("UnmapViewOfFile", err)
|
|
}
|
|
return nil
|
|
}
|