blob: 0eba77253e29b62426f83b7a1c084f8b392bb4fc [file] [log] [blame]
package fs
import (
"fmt"
"io"
"io/fs"
"os"
"path"
)
// CopyFile copies a source file to a destination file.
func CopyFile(src string, dst string, mode fs.FileMode) error {
srcFile, err := os.Open(src)
if err != nil {
return fmt.Errorf("could not open source file for copying: %v", err)
}
defer srcFile.Close()
dstFile, err := os.OpenFile(dst, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, mode)
if err != nil {
return fmt.Errorf("could not open destination file for copying: %v", err)
}
defer dstFile.Close()
_, err = io.Copy(dstFile, srcFile)
if err != nil {
return fmt.Errorf("error while copying file %s to %s: %v", src, dst, err)
}
return nil
}
// CopyDir copies a source directory to a target directory, preserving file
// permissions.
// This should be faster than calling `cp -r <src> <dst>` for small directories.
func CopyDir(src string, dst string, mode fs.FileMode) error {
entries, err := os.ReadDir(src)
if err != nil {
return fmt.Errorf("failed to read directory for copying: %v", err)
}
err = os.MkdirAll(dst, mode)
if err != nil {
return err
}
for _, entry := range entries {
entrySrc := path.Join(src, entry.Name())
entryDst := path.Join(dst, entry.Name())
entryInfo, err := entry.Info()
if err != nil {
return err
}
entryMode := entryInfo.Mode()
if entryInfo.IsDir() {
err = CopyDir(entrySrc, entryDst, entryMode)
} else {
err = CopyFile(entrySrc, entryDst, entryMode)
}
if err != nil {
return err
}
}
return nil
}
// IsDir returns whether or not a path exists and is a directory or is a
// symlink to a directory.
func IsDir(path string) bool {
info, err := os.Stat(path)
if err != nil {
return false
}
return info.Mode().IsDir()
}
// IsFile returns whether or not a path exists and is a file or is a
// symlink to a file.
func IsFile(path string) bool {
info, err := os.Stat(path)
if err != nil {
return false
}
return info.Mode().IsRegular()
}