royalcat
e9df8925d1
Some checks failed
docker / build-docker (linux/amd64) (push) Failing after 18s
docker / build-docker (linux/386) (push) Successful in 1m57s
docker / build-docker (linux/arm64) (push) Successful in 7m22s
docker / build-docker (linux/arm/v7) (push) Successful in 7m53s
docker / build-docker (linux/arm64/v8) (push) Failing after 3h2m18s
54 lines
1.8 KiB
Go
54 lines
1.8 KiB
Go
package cowutils
|
|
|
|
import (
|
|
"context"
|
|
"fmt"
|
|
"io"
|
|
"io/fs"
|
|
"os"
|
|
)
|
|
|
|
// Reflink performs the reflink operation on the passed files, replacing
|
|
// dst's contents with src. If fallback is true and reflink fails,
|
|
// copy_file_range will be used first, and if that fails too io.Copy will
|
|
// be used to copy the data.
|
|
func Reflink(ctx context.Context, dst, src *os.File, fallback bool) error {
|
|
err := reflink(dst, src)
|
|
if (err != nil) && fallback {
|
|
// reflink failed, but we can fallback, but first we need to know the file's size
|
|
var st fs.FileInfo
|
|
st, err = src.Stat()
|
|
if err != nil {
|
|
// couldn't stat source, this can't be helped
|
|
return fmt.Errorf("failed to stat source: %w", err)
|
|
}
|
|
_, err = copyFileRange(dst, src, 0, 0, st.Size())
|
|
if err != nil {
|
|
// copyFileRange failed too, switch to simple io copy
|
|
reader := io.NewSectionReader(src, 0, st.Size())
|
|
writer := §ionWriter{w: dst}
|
|
_ = dst.Truncate(0) // assuming any error in trucate will result in copy error
|
|
_, err = io.Copy(writer, reader)
|
|
}
|
|
}
|
|
return err
|
|
}
|
|
|
|
// ReflinkRange performs a range reflink operation on the passed files, replacing
|
|
// part of dst's contents with data from src. If fallback is true and reflink
|
|
// fails, copy_file_range will be used first, and if that fails too io.CopyN
|
|
// will be used to copy the data.
|
|
func ReflinkRange(ctx context.Context, dst, src *os.File, dstOffset, srcOffset, n int64, fallback bool) error {
|
|
err := reflinkRange(dst, src, dstOffset, srcOffset, n)
|
|
if (err != nil) && fallback {
|
|
_, err = copyFileRange(dst, src, dstOffset, srcOffset, n)
|
|
}
|
|
|
|
if (err != nil) && fallback {
|
|
// seek both src & dst
|
|
reader := io.NewSectionReader(src, srcOffset, n)
|
|
writer := §ionWriter{w: dst, base: dstOffset}
|
|
_, err = io.CopyN(writer, reader, n)
|
|
}
|
|
return err
|
|
}
|