| 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() |
| } |