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 }