mirror of
https://github.com/rwinkhart/sys.git
synced 2026-09-05 08:37:31 -04:00
unix: add Darwin support for clonefile syscalls
This commit adds support for three Darwin-specific calls that accelerate the copying of files: * clonefile() * clonefileat() * fclonefileat() Fixes golang/go#41366 Change-Id: I7e6c525fc23d8474ea85feff24314d3d672d87ed Reviewed-on: https://go-review.googlesource.com/c/sys/+/254757 Run-TryBot: Tobias Klauser <tobias.klauser@gmail.com> TryBot-Result: Go Bot <gobot@golang.org> Reviewed-by: Tobias Klauser <tobias.klauser@gmail.com> Reviewed-by: Ian Lance Taylor <iant@golang.org> Trust: Tobias Klauser <tobias.klauser@gmail.com>
This commit is contained in:
committed by
Ian Lance Taylor
parent
288bc346aa
commit
2334cc1a13
@@ -4,6 +4,18 @@
|
||||
|
||||
package unix_test
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"path"
|
||||
"testing"
|
||||
|
||||
"golang.org/x/sys/unix"
|
||||
)
|
||||
|
||||
var testData = []byte("This is a test\n")
|
||||
|
||||
// stringsFromByteSlice converts a sequence of attributes to a []string.
|
||||
// On Darwin, each entry is a NULL-terminated string.
|
||||
func stringsFromByteSlice(buf []byte) []string {
|
||||
@@ -17,3 +29,152 @@ func stringsFromByteSlice(buf []byte) []string {
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
func createTestFile(t *testing.T, dir string) (f *os.File, cleanup func() error) {
|
||||
file, err := ioutil.TempFile(dir, "TestClonefile")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
_, err = file.Write(testData)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
err = file.Close()
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
return file, func() error {
|
||||
return os.Remove(file.Name())
|
||||
}
|
||||
}
|
||||
|
||||
func TestClonefile(t *testing.T) {
|
||||
file, cleanup := createTestFile(t, "")
|
||||
defer cleanup()
|
||||
|
||||
clonedName := file.Name() + "-cloned"
|
||||
err := unix.Clonefile(file.Name(), clonedName, 0)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
defer os.Remove(clonedName)
|
||||
|
||||
clonedData, err := ioutil.ReadFile(clonedName)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
if !bytes.Equal(testData, clonedData) {
|
||||
t.Errorf("Clonefile: got %q, expected %q", clonedData, testData)
|
||||
}
|
||||
}
|
||||
|
||||
func TestClonefileatWithCwd(t *testing.T) {
|
||||
file, cleanup := createTestFile(t, "")
|
||||
defer cleanup()
|
||||
|
||||
clonedName := file.Name() + "-cloned"
|
||||
err := unix.Clonefileat(unix.AT_FDCWD, file.Name(), unix.AT_FDCWD, clonedName, 0)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
defer os.Remove(clonedName)
|
||||
|
||||
clonedData, err := ioutil.ReadFile(clonedName)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
if !bytes.Equal(testData, clonedData) {
|
||||
t.Errorf("Clonefileat: got %q, expected %q", clonedData, testData)
|
||||
}
|
||||
}
|
||||
|
||||
func TestClonefileatWithRelativePaths(t *testing.T) {
|
||||
srcDir, err := ioutil.TempDir("", "src")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
defer os.RemoveAll(srcDir)
|
||||
|
||||
dstDir, err := ioutil.TempDir("", "dest")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
defer os.RemoveAll(dstDir)
|
||||
|
||||
srcFd, err := unix.Open(srcDir, unix.O_RDONLY|unix.O_DIRECTORY, 0)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
defer unix.Close(srcFd)
|
||||
|
||||
dstFd, err := unix.Open(dstDir, unix.O_RDONLY|unix.O_DIRECTORY, 0)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
defer unix.Close(dstFd)
|
||||
|
||||
srcFile, cleanup := createTestFile(t, srcDir)
|
||||
defer cleanup()
|
||||
|
||||
dstFile, err := ioutil.TempFile(dstDir, "TestClonefileat")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
err = os.Remove(dstFile.Name())
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
src := path.Base(srcFile.Name())
|
||||
dst := path.Base(dstFile.Name())
|
||||
err = unix.Clonefileat(srcFd, src, dstFd, dst, 0)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
clonedData, err := ioutil.ReadFile(dstFile.Name())
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
if !bytes.Equal(testData, clonedData) {
|
||||
t.Errorf("Clonefileat: got %q, expected %q", clonedData, testData)
|
||||
}
|
||||
}
|
||||
|
||||
func TestFclonefileat(t *testing.T) {
|
||||
file, cleanup := createTestFile(t, "")
|
||||
defer cleanup()
|
||||
|
||||
fd, err := unix.Open(file.Name(), unix.O_RDONLY, 0)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
defer unix.Close(fd)
|
||||
|
||||
dstFile, err := ioutil.TempFile("", "TestFclonefileat")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
os.Remove(dstFile.Name())
|
||||
|
||||
err = unix.Fclonefileat(fd, unix.AT_FDCWD, dstFile.Name(), 0)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
clonedData, err := ioutil.ReadFile(dstFile.Name())
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
if !bytes.Equal(testData, clonedData) {
|
||||
t.Errorf("Fclonefileat: got %q, expected %q", clonedData, testData)
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user