Skip to content

Commit cbdd3a8

Browse files
authored
feat: Add clonefile implementation for linux (#1174)
Also cleanup the implementation a bit and expose the helper, it can be useful for other tools we build
1 parent 8eacf05 commit cbdd3a8

File tree

5 files changed

+61
-25
lines changed

5 files changed

+61
-25
lines changed

tools/common/BUILD.bazel

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,19 +4,26 @@ go_library(
44
name = "common",
55
srcs = [
66
"clonefile_darwin.go",
7+
"clonefile_linux.go",
78
"clonefile_stub.go",
89
"copy.go",
910
"file.go",
1011
],
1112
importpath = "github.com/bazel-contrib/bazel-lib/tools/common",
1213
visibility = ["//visibility:public"],
1314
deps = select({
15+
"@io_bazel_rules_go//go/platform:android": [
16+
"@org_golang_x_sys//unix",
17+
],
1418
"@io_bazel_rules_go//go/platform:darwin": [
1519
"@org_golang_x_sys//unix",
1620
],
1721
"@io_bazel_rules_go//go/platform:ios": [
1822
"@org_golang_x_sys//unix",
1923
],
24+
"@io_bazel_rules_go//go/platform:linux": [
25+
"@org_golang_x_sys//unix",
26+
],
2027
"//conditions:default": [],
2128
}),
2229
)

tools/common/clonefile_darwin.go

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -9,15 +9,14 @@ import (
99
)
1010

1111
// https://keith.github.io/xcode-man-pages/clonefile.2.html
12-
func cloneFile(src, dst string) (supported bool, err error) {
13-
supported = true
14-
if err = unix.Clonefile(src, dst, 0); err != nil {
15-
err = &os.LinkError{
12+
func CloneFile(src, dst string) error {
13+
if err := unix.Clonefile(src, dst, 0); err != nil {
14+
return &os.LinkError{
1615
Op: "clonefile",
1716
Old: src,
1817
New: dst,
1918
Err: err,
2019
}
2120
}
22-
return
21+
return nil
2322
}

tools/common/clonefile_linux.go

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
//go:build linux
2+
3+
package common
4+
5+
import (
6+
"os"
7+
8+
"golang.org/x/sys/unix"
9+
)
10+
11+
// FICLONE clones the contents of srcFd into the file referred to by dstFd.
12+
// #define FICLONE _IOW(0x94, 9, int) /* 0x40049409 */
13+
const _FICLONE = 0x40049409
14+
15+
func CloneFile(src, dst string) error {
16+
source, err := os.Open(src)
17+
if err != nil {
18+
return err
19+
}
20+
defer source.Close()
21+
22+
destination, err := os.Create(dst)
23+
if err != nil {
24+
return err
25+
}
26+
defer destination.Close()
27+
28+
// Perform ioctl on the destination FD, passing the source FD as the arg.
29+
// int ioctl(int dst_fd, FICLONE, int src_fd);
30+
if err := unix.IoctlSetInt(int(destination.Fd()), _FICLONE, int(source.Fd())); err != nil {
31+
return &os.LinkError{
32+
Op: "clonefile",
33+
Old: src,
34+
New: dst,
35+
Err: err,
36+
}
37+
}
38+
39+
return nil
40+
}

tools/common/clonefile_stub.go

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,7 @@
1-
//go:build !darwin
1+
//go:build !(darwin || linux)
22

33
package common
44

5-
func cloneFile(src, dst string) (supported bool, err error) {
6-
supported = false
7-
err = nil
8-
return
5+
func CloneFile(src, dst string) error {
6+
return CopyFile(src, dst)
97
}

tools/common/copy.go

Lines changed: 7 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -56,27 +56,19 @@ func Copy(opts CopyOpts) {
5656
if opts.verbose {
5757
fmt.Printf("clonefile%s %v => %v\n", opModifier, opts.src, opts.dst)
5858
}
59-
switch supported, err := cloneFile(opts.src, opts.dst); {
60-
case !supported:
61-
if opts.verbose {
62-
fmt.Print("clonefile skipped: not supported by platform\n")
63-
}
64-
// fallback to copy
65-
case supported && err == nil:
59+
err := CloneFile(opts.src, opts.dst)
60+
if err == nil {
6661
return
67-
case supported && err != nil:
68-
if opts.verbose {
69-
fmt.Printf("clonefile failed: %v\n", err)
70-
opModifier = fallback
71-
}
72-
// fallback to copy
7362
}
7463

75-
// copy this file
7664
if opts.verbose {
65+
fmt.Printf("clonefile failed: %v\n", err)
7766
fmt.Printf("copy%s %v => %v\n", opModifier, opts.src, opts.dst)
67+
opModifier = fallback
7868
}
79-
err := CopyFile(opts.src, opts.dst)
69+
70+
// copy this file
71+
err = CopyFile(opts.src, opts.dst)
8072
if err != nil {
8173
log.Fatal(err)
8274
}

0 commit comments

Comments
 (0)