diff --git a/internal/backup/strategy/kopia/strategy.go b/internal/backup/strategy/kopia/strategy.go index 87e2013..39e3915 100644 --- a/internal/backup/strategy/kopia/strategy.go +++ b/internal/backup/strategy/kopia/strategy.go @@ -348,22 +348,17 @@ func (s *Strategy) DownloadBackup(ctx context.Context, backupID string, serviceN return nil, fmt.Errorf("failed to connect to repository: %w", err) } - // Create temporary directories for restore and ZIP creation + // Create a single temporary directory for restore and ZIP creation + // Note: We're not creating a nested "restore" subdirectory anymore tempDir, err := os.MkdirTemp("", "backea-download-*") if err != nil { return nil, fmt.Errorf("failed to create temporary directory: %w", err) } - restoreDir := filepath.Join(tempDir, "restore") zipFile := filepath.Join(tempDir, "backup.zip") - if err := os.MkdirAll(restoreDir, 0755); err != nil { - os.RemoveAll(tempDir) - return nil, fmt.Errorf("failed to create restore directory: %w", err) - } - - // Restore the snapshot to the temporary directory using the proper snapshot ID - log.Printf("Restoring snapshot %s to temporary directory %s", backupID, restoreDir) + // Restore the snapshot directly to the temporary directory + log.Printf("Restoring snapshot %s to temporary directory %s", backupID, tempDir) restoreCmd := exec.CommandContext( ctx, @@ -372,7 +367,7 @@ func (s *Strategy) DownloadBackup(ctx context.Context, backupID string, serviceN "snapshot", "restore", backupID, - restoreDir, + tempDir, // Restore directly to tempDir instead of a subdirectory ) restoreOutput, err := restoreCmd.CombinedOutput() @@ -397,10 +392,17 @@ func (s *Strategy) DownloadBackup(ctx context.Context, backupID string, serviceN archive := zip.NewWriter(zipWriter) defer archive.Close() - // Walk the restore directory and add files to ZIP - err = filepath.Walk(restoreDir, func(path string, info os.FileInfo, err error) error { + // Walk the restore directory and add files to ZIP with error handling + err = filepath.Walk(tempDir, func(path string, info os.FileInfo, err error) error { + // Handle errors accessing files/directories if err != nil { - return err + log.Printf("Warning: Error accessing path %s: %v", path, err) + return nil // Skip this file but continue walking + } + + // Skip the zip file itself to avoid recursion + if path == zipFile { + return nil } // Skip directories, we only want to add files @@ -411,13 +413,15 @@ func (s *Strategy) DownloadBackup(ctx context.Context, backupID string, serviceN // Create ZIP header header, err := zip.FileInfoHeader(info) if err != nil { - return err + log.Printf("Warning: Couldn't create header for %s: %v", path, err) + return nil // Skip this file but continue walking } - // Make the path relative to the restore directory - relPath, err := filepath.Rel(restoreDir, path) + // Make the path relative to the temp directory + relPath, err := filepath.Rel(tempDir, path) if err != nil { - return err + log.Printf("Warning: Couldn't get relative path for %s: %v", path, err) + return nil // Skip this file but continue walking } // Set the name in the archive to the relative path @@ -426,30 +430,36 @@ func (s *Strategy) DownloadBackup(ctx context.Context, backupID string, serviceN // Create the file in the ZIP writer, err := archive.CreateHeader(header) if err != nil { - return err + log.Printf("Warning: Couldn't create zip entry for %s: %v", path, err) + return nil // Skip this file but continue walking } // Open the file file, err := os.Open(path) if err != nil { - return err + log.Printf("Warning: Couldn't open file %s: %v", path, err) + return nil // Skip this file but continue walking } defer file.Close() // Copy the file content to the ZIP _, err = io.Copy(writer, file) - return err + if err != nil { + log.Printf("Warning: Error copying content from %s: %v", path, err) + } + return nil // Continue to next file regardless of error }) - // Close the ZIP writer + // Even if we had some file errors, don't fail the whole process + // as long as we created the zip file + if err != nil { + log.Printf("Some files may have been skipped during zip creation: %v", err) + } + + // Close the ZIP writer before opening it for reading archive.Close() zipWriter.Close() - if err != nil { - os.RemoveAll(tempDir) - return nil, fmt.Errorf("failed to create zip archive: %w", err) - } - // Open the ZIP file for reading zipReader, err := os.Open(zipFile) if err != nil {