github.com/pachyderm/pachyderm@v1.13.4/src/server/pfs/fuse/files_darwin.go (about)

     1  package fuse
     2  
     3  import (
     4  	"context"
     5  	"syscall"
     6  	"time"
     7  	"unsafe"
     8  
     9  	"github.com/hanwen/go-fuse/v2/fs"
    10  	"github.com/hanwen/go-fuse/v2/fuse"
    11  )
    12  
    13  func (f *loopbackFile) Allocate(ctx context.Context, off uint64, sz uint64, mode uint32) syscall.Errno {
    14  	// TODO: Handle `mode` parameter.
    15  
    16  	// From `man fcntl` on OSX:
    17  	//     The F_PREALLOCATE command operates on the following structure:
    18  	//
    19  	//             typedef struct fstore {
    20  	//                 u_int32_t fst_flags;      /* IN: flags word */
    21  	//                 int       fst_posmode;    /* IN: indicates offset field */
    22  	//                 off_t     fst_offset;     /* IN: start of the region */
    23  	//                 off_t     fst_length;     /* IN: size of the region */
    24  	//                 off_t     fst_bytesalloc; /* OUT: number of bytes allocated */
    25  	//             } fstore_t;
    26  	//
    27  	//     The flags (fst_flags) for the F_PREALLOCATE command are as follows:
    28  	//
    29  	//           F_ALLOCATECONTIG   Allocate contiguous space.
    30  	//
    31  	//           F_ALLOCATEALL      Allocate all requested space or no space at all.
    32  	//
    33  	//     The position modes (fst_posmode) for the F_PREALLOCATE command indicate how to use the offset field.  The modes are as fol-
    34  	//     lows:
    35  	//
    36  	//           F_PEOFPOSMODE   Allocate from the physical end of file.
    37  	//
    38  	//           F_VOLPOSMODE    Allocate from the volume offset.
    39  
    40  	k := struct {
    41  		Flags      uint32 // u_int32_t
    42  		Posmode    int64  // int
    43  		Offset     int64  // off_t
    44  		Length     int64  // off_t
    45  		Bytesalloc int64  // off_t
    46  	}{
    47  		0,
    48  		0,
    49  		int64(off),
    50  		int64(sz),
    51  		0,
    52  	}
    53  
    54  	// Linux version for reference:
    55  	// err := syscall.Fallocate(int(f.File.Fd()), mode, int64(off), int64(sz))
    56  	_, _, errno := syscall.Syscall(syscall.SYS_FCNTL, uintptr(f.fd), uintptr(syscall.F_PREALLOCATE), uintptr(unsafe.Pointer(&k)))
    57  
    58  	return errno
    59  }
    60  
    61  // MacOS before High Sierra lacks utimensat() and UTIME_OMIT.
    62  // We emulate using utimes() and extra Getattr() calls.
    63  func (f *loopbackFile) utimens(a *time.Time, m *time.Time) syscall.Errno {
    64  	var attr fuse.AttrOut
    65  	if a == nil || m == nil {
    66  		errno := f.Getattr(context.Background(), &attr)
    67  		if errno != 0 {
    68  			return errno
    69  		}
    70  	}
    71  	tv := Fill(a, m, &attr.Attr)
    72  	err := syscall.Futimes(int(f.fd), tv)
    73  	return fs.ToErrno(err)
    74  }
    75  
    76  // Fill converts a and m to a syscall.Timeval slice that can be passed
    77  // to syscall.Utimes. Missing values (if any) are taken from attr
    78  func Fill(a *time.Time, m *time.Time, attr *fuse.Attr) []syscall.Timeval {
    79  	if a == nil {
    80  		a2 := time.Unix(int64(attr.Atime), int64(attr.Atimensec))
    81  		a = &a2
    82  	}
    83  	if m == nil {
    84  		m2 := time.Unix(int64(attr.Mtime), int64(attr.Mtimensec))
    85  		m = &m2
    86  	}
    87  	tv := make([]syscall.Timeval, 2)
    88  	tv[0] = timeToTimeval(a)
    89  	tv[1] = timeToTimeval(m)
    90  	return tv
    91  }
    92  
    93  // timeToTimeval - Convert time.Time to syscall.Timeval
    94  //
    95  // Note: This does not use syscall.NsecToTimespec because
    96  // that does not work properly for times before 1970,
    97  // see https://github.com/golang/go/issues/12777
    98  func timeToTimeval(t *time.Time) syscall.Timeval {
    99  	var tv syscall.Timeval
   100  	tv.Usec = int32(t.Nanosecond() / 1000)
   101  	tv.Sec = t.Unix()
   102  	return tv
   103  }