|
|
@@ -30,6 +30,8 @@ func preallocExtend(f *os.File, sizeInBytes int64) error {
|
|
|
}
|
|
|
|
|
|
func preallocFixed(f *os.File, sizeInBytes int64) error {
|
|
|
+ // allocate all requested space or no space at all
|
|
|
+ // TODO: allocate contiguous space on disk with F_ALLOCATECONTIG flag
|
|
|
fstore := &syscall.Fstore_t{
|
|
|
Flags: syscall.F_ALLOCATEALL,
|
|
|
Posmode: syscall.F_PEOFPOSMODE,
|
|
|
@@ -39,5 +41,25 @@ func preallocFixed(f *os.File, sizeInBytes int64) error {
|
|
|
if errno == 0 || errno == syscall.ENOTSUP {
|
|
|
return nil
|
|
|
}
|
|
|
+
|
|
|
+ // wrong argument to fallocate syscall
|
|
|
+ if errno == syscall.EINVAL {
|
|
|
+ // filesystem "st_blocks" are allocated in the units of
|
|
|
+ // "Allocation Block Size" (run "diskutil info /" command)
|
|
|
+ var stat syscall.Stat_t
|
|
|
+ syscall.Fstat(int(f.Fd()), &stat)
|
|
|
+
|
|
|
+ // syscall.Statfs_t.Bsize is "optimal transfer block size"
|
|
|
+ // and contains matching 4096 value when latest OS X kernel
|
|
|
+ // supports 4,096 KB filesystem block size
|
|
|
+ var statfs syscall.Statfs_t
|
|
|
+ syscall.Fstatfs(int(f.Fd()), &statfs)
|
|
|
+ blockSize := int64(statfs.Bsize)
|
|
|
+
|
|
|
+ if stat.Blocks*blockSize >= sizeInBytes {
|
|
|
+ // enough blocks are already allocated
|
|
|
+ return nil
|
|
|
+ }
|
|
|
+ }
|
|
|
return errno
|
|
|
}
|