From 8a4cab13ae2afd79065b997f71d8109a763e32f6 Mon Sep 17 00:00:00 2001 From: Michael Kaplan Date: Mon, 29 Apr 2024 08:22:55 +0200 Subject: [PATCH 1/3] add: remotefs/Download function to support file download Signed-off-by: Michael Kaplan --- remotefs/download.go | 47 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 47 insertions(+) create mode 100644 remotefs/download.go diff --git a/remotefs/download.go b/remotefs/download.go new file mode 100644 index 00000000..35b1b75e --- /dev/null +++ b/remotefs/download.go @@ -0,0 +1,47 @@ +package remotefs + +import ( + "bytes" + "crypto/sha256" + "fmt" + "io" + "os" +) + +// Download a file from the remote host. +func Download(fs FS, src, dst string) error { + remote, err := fs.Open(src) + if err != nil { + return fmt.Errorf("open remote file for download: %w", err) + } + defer remote.Close() + + remoteStat, err := remote.Stat() + if err != nil { + return fmt.Errorf("stat remote file for download: %w", err) + } + + remoteSum := sha256.New() + localSum := sha256.New() + + local, err := os.OpenFile(dst, os.O_CREATE|os.O_WRONLY|os.O_TRUNC, remoteStat.Mode()) + if err != nil { + return fmt.Errorf("open local file for download: %w", err) + } + defer local.Close() + + remoteReader := io.TeeReader(remote, remoteSum) + if _, err := io.Copy(io.MultiWriter(local, localSum), remoteReader); err != nil { + _ = local.Close() + return fmt.Errorf("copy file from remote host: %w", err) + } + if err := local.Close(); err != nil { + return fmt.Errorf("close local file after download: %w", err) + } + + if !bytes.Equal(localSum.Sum(nil), remoteSum.Sum(nil)) { + return fmt.Errorf("downloading %s failed: %w", src, ErrChecksumMismatch) + } + + return nil +} From 3540252e8b81dce9bfbb943e4301c8d1096d5c96 Mon Sep 17 00:00:00 2001 From: Michael Kaplan Date: Sun, 5 May 2024 00:59:29 +0200 Subject: [PATCH 2/3] add: remotefs/UploadDirectory function to support recursive upload Signed-off-by: Michael Kaplan --- remotefs/uploaddirectory.go | 43 +++++++++++++++++++++++++++++++++++++ 1 file changed, 43 insertions(+) create mode 100644 remotefs/uploaddirectory.go diff --git a/remotefs/uploaddirectory.go b/remotefs/uploaddirectory.go new file mode 100644 index 00000000..bcd74697 --- /dev/null +++ b/remotefs/uploaddirectory.go @@ -0,0 +1,43 @@ +package remotefs + +import ( + "fmt" + "io/fs" + "os" + "path/filepath" +) + +// UploadDirectory uploads all files and directories recursively to the remote system. +func UploadDirectory(fsys FS, src, dst string) error { + walkErr := filepath.WalkDir(src, func(path string, dir fs.DirEntry, err error) error { + if err != nil { + return fmt.Errorf("walk local directory: %w", err) + } + + relPath, err := filepath.Rel(src, path) + if err != nil { + return fmt.Errorf("calculate relative path: %w", err) + } + targetPath := filepath.Join(dst, relPath) + + if dir.IsDir() { + dirInfo, err := dir.Info() + if err != nil { + return fmt.Errorf("get dir info: %w", err) + } + if err := fsys.MkdirAll(targetPath, dirInfo.Mode()&os.ModePerm); err != nil { + return fmt.Errorf("create remote directory: %w", err) + } + } else { + if err := Upload(fsys, path, targetPath); err != nil { + return fmt.Errorf("upload directory: %w", err) + } + } + return nil + }) + + if walkErr != nil { + return fmt.Errorf("walk remote directory tree: %w", walkErr) + } + return nil +} From ebe4d69390ffe0246b7ad781d8733a9bf42c71e7 Mon Sep 17 00:00:00 2001 From: Michael Kaplan Date: Sun, 5 May 2024 01:42:17 +0200 Subject: [PATCH 3/3] add: remotefs/DownloadDirectory function to support recursive download Signed-off-by: Michael Kaplan --- remotefs/downloaddirectory.go | 43 +++++++++++++++++++++++++++++++++++ 1 file changed, 43 insertions(+) create mode 100644 remotefs/downloaddirectory.go diff --git a/remotefs/downloaddirectory.go b/remotefs/downloaddirectory.go new file mode 100644 index 00000000..de4c77d1 --- /dev/null +++ b/remotefs/downloaddirectory.go @@ -0,0 +1,43 @@ +package remotefs + +import ( + "fmt" + "io/fs" + "os" + "path/filepath" +) + +// DownloadDirectory downloads all files and directories recursively from the remote system to local directory. +func DownloadDirectory(fsys FS, src, dst string) error { + walkErr := fs.WalkDir(fsys, src, func(path string, dir fs.DirEntry, err error) error { + if err != nil { + return fmt.Errorf("walk remote directory: %w", err) + } + + relPath, err := filepath.Rel(src, path) + if err != nil { + return fmt.Errorf("calculate relative path: %w", err) + } + targetPath := filepath.Join(dst, relPath) + + if dir.IsDir() { + dirInfo, err := dir.Info() + if err != nil { + return fmt.Errorf("get dir info: %w", err) + } + if err := os.MkdirAll(targetPath, dirInfo.Mode()&os.ModePerm); err != nil { + return fmt.Errorf("create local directory: %w", err) + } + } else { + if err := Download(fsys, path, targetPath); err != nil { + return fmt.Errorf("download directory: %w", err) + } + } + return nil + }) + + if walkErr != nil { + return fmt.Errorf("walk remote directory tree: %w", walkErr) + } + return nil +}