diff --git a/api.go b/api.go index f42949b..8f2d1c1 100644 --- a/api.go +++ b/api.go @@ -440,23 +440,23 @@ func (a *Agate) GetRemoteSnapshot(ctx context.Context, address string, snapshotI if localParentID != "" { if err := a.manager.ExtractSnapshot(ctx, localParentID, newSnapshotDir, false); err != nil { - a.options.Logger.Printf("Warning: failed to extract local parent snapshot %s: %v", localParentID, err) - } else { - localParentSnap, err := a.GetSnapshotDetails(ctx, localParentID) - if err != nil { - a.options.Logger.Printf("Warning: failed to get local parent details %s: %v", localParentID, err) - } else { - remoteFilesMap := make(map[string]struct{}) - for _, f := range remoteSnapshot.Files { - remoteFilesMap[f.Path] = struct{}{} - } + return fmt.Errorf("failed to extract local parent snapshot %s for diff application: %w", localParentID, err) + } - for _, localFile := range localParentSnap.Files { - if _, exists := remoteFilesMap[localFile.Path]; !exists { - pathToDelete := filepath.Join(newSnapshotDir, localFile.Path) - if err := os.RemoveAll(pathToDelete); err != nil { - a.options.Logger.Printf("Warning: failed to delete file %s during diff apply: %v", pathToDelete, err) - } + localParentSnap, err := a.GetSnapshotDetails(ctx, localParentID) + if err != nil { + a.options.Logger.Printf("Warning: failed to get local parent details %s: %v", localParentID, err) + } else { + remoteFilesMap := make(map[string]struct{}) + for _, f := range remoteSnapshot.Files { + remoteFilesMap[f.Path] = struct{}{} + } + + for _, localFile := range localParentSnap.Files { + if _, exists := remoteFilesMap[localFile.Path]; !exists { + pathToDelete := filepath.Join(newSnapshotDir, localFile.Path) + if err := os.RemoveAll(pathToDelete); err != nil { + a.options.Logger.Printf("Warning: failed to delete file %s during diff apply: %v", pathToDelete, err) } } } diff --git a/manager.go b/manager.go index 59ae6dd..ae59d96 100644 --- a/manager.go +++ b/manager.go @@ -395,6 +395,12 @@ func (data *SnapshotManagerData) ExtractSnapshot(ctx context.Context, snapshotID // If cleanTarget is true, clean the target directory before extraction if cleanTarget { + rc, err := zip.OpenReader(blobPath) + if err != nil { + return fmt.Errorf("snapshot archive is corrupted or unreadable, restore aborted to protect data: %w", err) + } + rc.Close() + // Remove the directory and recreate it if err := os.RemoveAll(path); err != nil { return fmt.Errorf("failed to clean target directory: %w", err) diff --git a/store/filesystem/filesystem.go b/store/filesystem/filesystem.go index ec220a3..d6d1184 100644 --- a/store/filesystem/filesystem.go +++ b/store/filesystem/filesystem.go @@ -71,7 +71,6 @@ func (fs *fileSystemStore) getBlobPath(snapshotID string) string { // StoreBlob сохраняет данные из reader в файл в baseDir. func (fs *fileSystemStore) StoreBlob(ctx context.Context, snapshotID string, reader io.Reader) (string, error) { blobPath := fs.getBlobPath(snapshotID) - log.Printf("Starting to store blob for snapshot %s at %s", snapshotID, blobPath) // Используем временный файл, чтобы не повредить (возможно) существующий валидный файл // если загрузка упадет на середине. @@ -90,7 +89,7 @@ func (fs *fileSystemStore) StoreBlob(ctx context.Context, snapshotID string, rea } // Копируем данные - written, err := io.Copy(file, pr) + _, err = io.Copy(file, pr) if err != nil { file.Close() os.Remove(tempPath) // Удаляем мусор @@ -107,13 +106,10 @@ func (fs *fileSystemStore) StoreBlob(ctx context.Context, snapshotID string, rea file.Close() // Закрываем перед переименованием // Переименовываем временный файл в финальный (атомарная операция) - if err := os.Rename(tempPath, blobPath); err != nil { + if err = os.Rename(tempPath, blobPath); err != nil { return "", fmt.Errorf("failed to rename temp file to final blob: %w", err) } - log.Printf("Successfully stored blob for snapshot %s. Total size: %.2f MB", - snapshotID, float64(written)/1024/1024) - return blobPath, nil }