Files
beads/cmd/bd/doctor/fix/fs.go
Jordan Hubbard 7af3106610 doctor: add fs fault injection and lock contention coverage
Co-authored-by: factory-droid[bot] <138933559+factory-droid[bot]@users.noreply.github.com>
2025-12-26 09:22:45 -04:00

58 lines
1.1 KiB
Go

package fix
import (
"errors"
"fmt"
"io"
"os"
"syscall"
)
var (
renameFile = os.Rename
removeFile = os.Remove
openFileRO = os.Open
openFileRW = os.OpenFile
)
func moveFile(src, dst string) error {
if err := renameFile(src, dst); err == nil {
return nil
} else if isEXDEV(err) {
if err := copyFile(src, dst); err != nil {
return err
}
if err := removeFile(src); err != nil {
return fmt.Errorf("failed to remove source after copy: %w", err)
}
return nil
} else {
return err
}
}
func copyFile(src, dst string) error {
in, err := openFileRO(src) // #nosec G304 -- src is within the workspace
if err != nil {
return err
}
defer in.Close()
out, err := openFileRW(dst, os.O_CREATE|os.O_TRUNC|os.O_WRONLY, 0644)
if err != nil {
return err
}
defer func() { _ = out.Close() }()
if _, err := io.Copy(out, in); err != nil {
return err
}
return out.Close()
}
func isEXDEV(err error) bool {
var linkErr *os.LinkError
if errors.As(err, &linkErr) {
return errors.Is(linkErr.Err, syscall.EXDEV)
}
return errors.Is(err, syscall.EXDEV)
}