github.com/ncruces/go-sqlite3@v0.15.1-0.20240520133447-53eef1510ff0/vfs/os_darwin.go (about)

     1  //go:build !(sqlite3_flock || sqlite3_nosys)
     2  
     3  package vfs
     4  
     5  import (
     6  	"io"
     7  	"os"
     8  	"time"
     9  
    10  	"golang.org/x/sys/unix"
    11  )
    12  
    13  const (
    14  	// https://github.com/apple/darwin-xnu/blob/main/bsd/sys/fcntl.h
    15  	_F_OFD_SETLK         = 90
    16  	_F_OFD_SETLKW        = 91
    17  	_F_OFD_SETLKWTIMEOUT = 93
    18  )
    19  
    20  type flocktimeout_t struct {
    21  	fl      unix.Flock_t
    22  	timeout unix.Timespec
    23  }
    24  
    25  func osSync(file *os.File, fullsync, _ /*dataonly*/ bool) error {
    26  	if fullsync {
    27  		return file.Sync()
    28  	}
    29  	return unix.Fsync(int(file.Fd()))
    30  }
    31  
    32  func osAllocate(file *os.File, size int64) error {
    33  	off, err := file.Seek(0, io.SeekEnd)
    34  	if err != nil {
    35  		return err
    36  	}
    37  	if size <= off {
    38  		return nil
    39  	}
    40  
    41  	store := unix.Fstore_t{
    42  		Flags:   unix.F_ALLOCATEALL | unix.F_ALLOCATECONTIG,
    43  		Posmode: unix.F_PEOFPOSMODE,
    44  		Offset:  0,
    45  		Length:  size - off,
    46  	}
    47  
    48  	// Try to get a continuous chunk of disk space.
    49  	err = unix.FcntlFstore(file.Fd(), unix.F_PREALLOCATE, &store)
    50  	if err != nil {
    51  		// OK, perhaps we are too fragmented, allocate non-continuous.
    52  		store.Flags = unix.F_ALLOCATEALL
    53  		unix.FcntlFstore(file.Fd(), unix.F_PREALLOCATE, &store)
    54  	}
    55  	return file.Truncate(size)
    56  }
    57  
    58  func osUnlock(file *os.File, start, len int64) _ErrorCode {
    59  	err := unix.FcntlFlock(file.Fd(), _F_OFD_SETLK, &unix.Flock_t{
    60  		Type:  unix.F_UNLCK,
    61  		Start: start,
    62  		Len:   len,
    63  	})
    64  	if err != nil {
    65  		return _IOERR_UNLOCK
    66  	}
    67  	return _OK
    68  }
    69  
    70  func osLock(file *os.File, typ int16, start, len int64, timeout time.Duration, def _ErrorCode) _ErrorCode {
    71  	lock := flocktimeout_t{fl: unix.Flock_t{
    72  		Type:  typ,
    73  		Start: start,
    74  		Len:   len,
    75  	}}
    76  	var err error
    77  	switch {
    78  	case timeout == 0:
    79  		err = unix.FcntlFlock(file.Fd(), _F_OFD_SETLK, &lock.fl)
    80  	case timeout < 0:
    81  		err = unix.FcntlFlock(file.Fd(), _F_OFD_SETLKW, &lock.fl)
    82  	default:
    83  		lock.timeout = unix.NsecToTimespec(int64(timeout / time.Nanosecond))
    84  		err = unix.FcntlFlock(file.Fd(), _F_OFD_SETLKWTIMEOUT, &lock.fl)
    85  	}
    86  	return osLockErrorCode(err, def)
    87  }
    88  
    89  func osReadLock(file *os.File, start, len int64, timeout time.Duration) _ErrorCode {
    90  	return osLock(file, unix.F_RDLCK, start, len, timeout, _IOERR_RDLOCK)
    91  }
    92  
    93  func osWriteLock(file *os.File, start, len int64, timeout time.Duration) _ErrorCode {
    94  	return osLock(file, unix.F_WRLCK, start, len, timeout, _IOERR_LOCK)
    95  }