fs: Clone(): make clone methods report whether they did a clone or copy

This commit is contained in:
Ivan Shapovalov 2024-12-05 17:48:48 +04:00
parent 8b1e7a0256
commit cc8b75a20a

View file

@ -12,7 +12,7 @@ import (
"golang.org/x/sys/unix"
)
type cloneMethod func(src, dst *os.File) error
type cloneMethod func(src, dst *os.File) (cloned bool, err error)
var (
mCloneMethods = &sync.Mutex{}
@ -114,22 +114,22 @@ func Readdirnames(filesystem FS, dir string, flags int) ([]string, error) {
return entries, nil
}
func doCloneCopy(src, dest *os.File) error {
func doCloneCopy(src, dest *os.File) (cloned bool, err error) {
srcInfo, err := src.Stat()
if err != nil {
return err
return false, err
}
n, err := io.Copy(dest, src)
if n > 0 && n != srcInfo.Size() {
return errors.Wrapf(err, "io.Copy() wrote %d of %d bytes", n, srcInfo.Size())
return false, errors.Wrapf(err, "io.Copy() wrote %d of %d bytes", n, srcInfo.Size())
}
return err
return false, err
}
func doClone(srcName, destName string, method cloneMethod) error {
func doClone(srcName, destName string, method cloneMethod) (cloned bool, err error) {
src, err := OpenFile(srcName, O_RDONLY|O_NOFOLLOW, 0)
if err != nil {
return err
return false, err
}
defer func() {
_ = src.Close()
@ -137,7 +137,7 @@ func doClone(srcName, destName string, method cloneMethod) error {
dest, err := OpenFile(destName, O_CREATE|O_TRUNC|O_WRONLY|O_NOFOLLOW, 0600)
if err != nil {
return err
return false, err
}
defer func() {
_ = dest.Close()
@ -151,14 +151,14 @@ func doClone(srcName, destName string, method cloneMethod) error {
// The cloned flag reports whether an accelerated copy (reflink) was performed.
func Clone(srcName, destName string) (cloned bool, err error) {
for _, fn := range cloneMethods {
err = doClone(srcName, destName, fn)
cloned, err = doClone(srcName, destName, fn)
// if a particular method is not supported, or we hit the cross-device limitation,
// "eat" the error and go to the next method or the fallback
if errors.Is(err, unix.EXDEV) || errors.Is(err, unix.ENOTSUP) {
continue
}
return true, err
return cloned, err
}
return false, doClone(srcName, destName, doCloneCopy)
return doClone(srcName, destName, doCloneCopy)
}