github.com/hanwen/go-fuse@v1.0.0/fuse/nodefs/files_darwin.go (about)

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