unix: add FcntlFstore on darwin

This allows to perform a fcntl syscall with the F_PREALLOCATE command.
See man fcntl(2) on macOS for details.

Change-Id: I21f95b91269513064859425ab7adc42a73d6adb5
Reviewed-on: https://go-review.googlesource.com/c/sys/+/255917
Trust: Tobias Klauser <tobias.klauser@gmail.com>
Run-TryBot: Tobias Klauser <tobias.klauser@gmail.com>
TryBot-Result: Go Bot <gobot@golang.org>
Reviewed-by: Ian Lance Taylor <iant@golang.org>
diff --git a/unix/fcntl_darwin.go b/unix/fcntl_darwin.go
index 5868a4a..a9911c7 100644
--- a/unix/fcntl_darwin.go
+++ b/unix/fcntl_darwin.go
@@ -16,3 +16,9 @@
 	_, err := fcntl(int(fd), cmd, int(uintptr(unsafe.Pointer(lk))))
 	return err
 }
+
+// FcntlFstore performs a fcntl syscall for the F_PREALLOCATE command.
+func FcntlFstore(fd uintptr, cmd int, fstore *Fstore_t) error {
+	_, err := fcntl(int(fd), cmd, int(uintptr(unsafe.Pointer(fstore))))
+	return err
+}
diff --git a/unix/syscall_darwin_test.go b/unix/syscall_darwin_test.go
index e7f6bdd..d9f1013 100644
--- a/unix/syscall_darwin_test.go
+++ b/unix/syscall_darwin_test.go
@@ -31,7 +31,7 @@
 }
 
 func createTestFile(t *testing.T, dir string) (f *os.File, cleanup func() error) {
-	file, err := ioutil.TempFile(dir, "TestClonefile")
+	file, err := ioutil.TempFile(dir, t.Name())
 	if err != nil {
 		t.Fatal(err)
 	}
@@ -185,3 +185,35 @@
 		t.Errorf("Fclonefileat: got %q, expected %q", clonedData, testData)
 	}
 }
+
+func TestFcntlFstore(t *testing.T) {
+	f, err := ioutil.TempFile("", t.Name())
+	if err != nil {
+		t.Fatal(err)
+	}
+	defer os.Remove(f.Name())
+	defer f.Close()
+
+	fstore := &unix.Fstore_t{
+		Flags:   unix.F_ALLOCATEALL,
+		Posmode: unix.F_PEOFPOSMODE,
+		Offset:  0,
+		Length:  1 << 10,
+	}
+	err = unix.FcntlFstore(f.Fd(), unix.F_PREALLOCATE, fstore)
+	if err == unix.EOPNOTSUPP {
+		t.Skipf("fcntl with F_PREALLOCATE not supported, skipping test")
+	} else if err != nil {
+		t.Fatalf("FcntlFstore: %v", err)
+	}
+
+	st, err := f.Stat()
+	if err != nil {
+		t.Fatal(err)
+	}
+
+	if st.Size() != 0 {
+		t.Errorf("FcntlFstore: got size = %d, want %d", st.Size(), 0)
+	}
+
+}