package local import ( "fmt" "io" "os" "path/filepath" "strings" "syscall" ) // copyDirectory copy the directory func copyDirectory(scrDir, dest string) error { if err := createIfNotexists(dest, 0755); err != nil { return err } entries, err := os.ReadDir(scrDir) if err != nil { return err } for _, entry := range entries { sourcePath := filepath.Join(scrDir, entry.Name()) destPath := filepath.Join(dest, entry.Name()) fileInfo, err := os.Stat(sourcePath) if err != nil { return err } stat, ok := fileInfo.Sys().(*syscall.Stat_t) if !ok { return fmt.Errorf("failed to get raw syscall.Stat_t data for '%s'", sourcePath) } switch fileInfo.Mode() & os.ModeType { case os.ModeDir: if err := createIfNotexists(destPath, 0755); err != nil { return err } if err := copyDirectory(sourcePath, destPath); err != nil { return err } case os.ModeSymlink: if err := copySymLink(sourcePath, destPath); err != nil { return err } default: if strings.HasPrefix(entry.Name(), ".") { continue } if err := copy(sourcePath, destPath); err != nil { return fmt.Errorf("failed to copy '%s' to '%s': %s", sourcePath, destPath, err.Error()) } } if err := os.Lchown(destPath, int(stat.Uid), int(stat.Gid)); err != nil { return err } fInfo, err := entry.Info() if err != nil { return err } isSymlink := fInfo.Mode()&os.ModeSymlink != 0 if !isSymlink { if err := os.Chmod(destPath, fInfo.Mode()); err != nil { return err } } } return nil } func copy(srcFile, dstFile string) error { out, err := os.Create(dstFile) if err != nil { return err } defer out.Close() in, err := os.Open(srcFile) if err != nil { return err } defer in.Close() _, err = io.Copy(out, in) if err != nil { return err } return nil } func exists(filePath string) bool { if _, err := os.Stat(filePath); os.IsNotExist(err) { return false } return true } func createIfNotexists(dir string, perm os.FileMode) error { if exists(dir) { return nil } if err := os.MkdirAll(dir, perm); err != nil { return fmt.Errorf("failed to create directory: '%s', error: '%s'", dir, err.Error()) } return nil } func copySymLink(source, dest string) error { link, err := os.Readlink(source) if err != nil { return err } return os.Symlink(link, dest) }