102 lines
2.8 KiB
Go
102 lines
2.8 KiB
Go
// Copyright 2016 the Go-FUSE Authors. All rights reserved.
|
|
// Use of this source code is governed by a BSD-style
|
|
// license that can be found in the LICENSE file.
|
|
|
|
package nodefs
|
|
|
|
import (
|
|
"syscall"
|
|
"time"
|
|
"unsafe"
|
|
|
|
"github.com/hanwen/go-fuse/fuse"
|
|
)
|
|
|
|
func (f *loopbackFile) Allocate(off uint64, sz uint64, mode uint32) fuse.Status {
|
|
// TODO: Handle `mode` parameter.
|
|
|
|
// From `man fcntl` on OSX:
|
|
// The F_PREALLOCATE command operates on the following structure:
|
|
//
|
|
// typedef struct fstore {
|
|
// u_int32_t fst_flags; /* IN: flags word */
|
|
// int fst_posmode; /* IN: indicates offset field */
|
|
// off_t fst_offset; /* IN: start of the region */
|
|
// off_t fst_length; /* IN: size of the region */
|
|
// off_t fst_bytesalloc; /* OUT: number of bytes allocated */
|
|
// } fstore_t;
|
|
//
|
|
// The flags (fst_flags) for the F_PREALLOCATE command are as follows:
|
|
//
|
|
// F_ALLOCATECONTIG Allocate contiguous space.
|
|
//
|
|
// F_ALLOCATEALL Allocate all requested space or no space at all.
|
|
//
|
|
// The position modes (fst_posmode) for the F_PREALLOCATE command indicate how to use the offset field. The modes are as fol-
|
|
// lows:
|
|
//
|
|
// F_PEOFPOSMODE Allocate from the physical end of file.
|
|
//
|
|
// F_VOLPOSMODE Allocate from the volume offset.
|
|
|
|
k := struct {
|
|
Flags uint32 // u_int32_t
|
|
Posmode int64 // int
|
|
Offset int64 // off_t
|
|
Length int64 // off_t
|
|
Bytesalloc int64 // off_t
|
|
}{
|
|
0,
|
|
0,
|
|
int64(off),
|
|
int64(sz),
|
|
0,
|
|
}
|
|
|
|
// Linux version for reference:
|
|
// err := syscall.Fallocate(int(f.File.Fd()), mode, int64(off), int64(sz))
|
|
|
|
f.lock.Lock()
|
|
_, _, errno := syscall.Syscall(syscall.SYS_FCNTL, f.File.Fd(), uintptr(syscall.F_PREALLOCATE), uintptr(unsafe.Pointer(&k)))
|
|
f.lock.Unlock()
|
|
if errno != 0 {
|
|
return fuse.ToStatus(errno)
|
|
}
|
|
return fuse.OK
|
|
}
|
|
|
|
const _UTIME_OMIT = ((1 << 30) - 2)
|
|
|
|
// timeToTimeval - Convert time.Time to syscall.Timeval
|
|
//
|
|
// Note: This does not use syscall.NsecToTimespec because
|
|
// that does not work properly for times before 1970,
|
|
// see https://github.com/golang/go/issues/12777
|
|
func timeToTimeval(t *time.Time) syscall.Timeval {
|
|
var tv syscall.Timeval
|
|
tv.Usec = int32(t.Nanosecond() / 1000)
|
|
tv.Sec = t.Unix()
|
|
return tv
|
|
}
|
|
|
|
// OSX does not have the utimensat syscall neded to implement this properly.
|
|
// We do our best to emulate it using futimes.
|
|
func (f *loopbackFile) Utimens(a *time.Time, m *time.Time) fuse.Status {
|
|
tv := make([]syscall.Timeval, 2)
|
|
if a == nil {
|
|
tv[0].Usec = _UTIME_OMIT
|
|
} else {
|
|
tv[0] = timeToTimeval(a)
|
|
}
|
|
|
|
if m == nil {
|
|
tv[1].Usec = _UTIME_OMIT
|
|
} else {
|
|
tv[1] = timeToTimeval(m)
|
|
}
|
|
|
|
f.lock.Lock()
|
|
err := syscall.Futimes(int(f.File.Fd()), tv)
|
|
f.lock.Unlock()
|
|
return fuse.ToStatus(err)
|
|
}
|