Skip to content

Commit 21eb927

Browse files
authored
Merge pull request #223 from dmcgowan/support-darwin-clonefile
Support darwin clonefile
2 parents cec82ed + 30cf84d commit 21eb927

File tree

4 files changed

+96
-0
lines changed

4 files changed

+96
-0
lines changed

fs/copy.go

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -184,6 +184,10 @@ func copyDirectory(dst, src string, inodes map[uint64]string, o *copyDirOpts) er
184184
// CopyFile copies the source file to the target.
185185
// The most efficient means of copying is used for the platform.
186186
func CopyFile(target, source string) error {
187+
return copyFile(target, source)
188+
}
189+
190+
func openAndCopyFile(target, source string) error {
187191
src, err := os.Open(source)
188192
if err != nil {
189193
return fmt.Errorf("failed to open source %s: %w", source, err)

fs/copy_darwin.go

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
/*
2+
Copyright The containerd Authors.
3+
4+
Licensed under the Apache License, Version 2.0 (the "License");
5+
you may not use this file except in compliance with the License.
6+
You may obtain a copy of the License at
7+
8+
http://www.apache.org/licenses/LICENSE-2.0
9+
10+
Unless required by applicable law or agreed to in writing, software
11+
distributed under the License is distributed on an "AS IS" BASIS,
12+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
See the License for the specific language governing permissions and
14+
limitations under the License.
15+
*/
16+
17+
package fs
18+
19+
import (
20+
"errors"
21+
"fmt"
22+
23+
"golang.org/x/sys/unix"
24+
)
25+
26+
func copyFile(target, source string) error {
27+
if err := unix.Clonefile(source, target, unix.CLONE_NOFOLLOW); err != nil {
28+
if !errors.Is(err, unix.ENOTSUP) {
29+
return fmt.Errorf("clonefile failed: %w", err)
30+
}
31+
32+
return openAndCopyFile(target, source)
33+
}
34+
return nil
35+
}

fs/copy_nondarwin.go

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
//go:build !darwin
2+
// +build !darwin
3+
4+
/*
5+
Copyright The containerd Authors.
6+
7+
Licensed under the Apache License, Version 2.0 (the "License");
8+
you may not use this file except in compliance with the License.
9+
You may obtain a copy of the License at
10+
11+
http://www.apache.org/licenses/LICENSE-2.0
12+
13+
Unless required by applicable law or agreed to in writing, software
14+
distributed under the License is distributed on an "AS IS" BASIS,
15+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16+
See the License for the specific language governing permissions and
17+
limitations under the License.
18+
*/
19+
20+
package fs
21+
22+
var copyFile = openAndCopyFile

fs/copy_test.go

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ package fs
1919
import (
2020
_ "crypto/sha256"
2121
"fmt"
22+
"os"
2223
"testing"
2324
"time"
2425

@@ -89,3 +90,37 @@ func testCopy(t testing.TB, apply fstest.Applier) error {
8990

9091
return fstest.CheckDirectoryEqual(t1, t2)
9192
}
93+
94+
func BenchmarkLargeCopy100MB(b *testing.B) {
95+
benchmarkLargeCopyFile(b, 100*1024*1024)
96+
}
97+
98+
func BenchmarkLargeCopy1GB(b *testing.B) {
99+
benchmarkLargeCopyFile(b, 1024*1024*1024)
100+
}
101+
102+
func benchmarkLargeCopyFile(b *testing.B, size int64) {
103+
b.StopTimer()
104+
base := b.TempDir()
105+
apply := fstest.Apply(
106+
fstest.CreateRandomFile("/large", time.Now().UnixNano(), size, 0o644),
107+
)
108+
if err := apply.Apply(base); err != nil {
109+
b.Fatal("failed to apply changes:", err)
110+
}
111+
112+
for i := 0; i < b.N; i++ {
113+
copied := b.TempDir()
114+
b.StartTimer()
115+
if err := CopyDir(copied, base); err != nil {
116+
b.Fatal("failed to copy:", err)
117+
}
118+
b.StopTimer()
119+
if i == 0 {
120+
if err := fstest.CheckDirectoryEqual(base, copied); err != nil {
121+
b.Fatal("check failed:", err)
122+
}
123+
}
124+
os.RemoveAll(copied)
125+
}
126+
}

0 commit comments

Comments
 (0)