| 
									
										
										
										
											2024-01-20 18:40:22 +01:00
										 |  |  | package repository | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | import ( | 
					
						
							|  |  |  | 	"context" | 
					
						
							|  |  |  | 	"errors" | 
					
						
							|  |  |  | 	"io" | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	"github.com/restic/restic/internal/restic" | 
					
						
							|  |  |  | 	"github.com/restic/restic/internal/ui/progress" | 
					
						
							|  |  |  | 	"golang.org/x/sync/errgroup" | 
					
						
							|  |  |  | ) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-01-20 21:52:27 +01:00
										 |  |  | func RepairPacks(ctx context.Context, repo restic.Repository, ids restic.IDSet, printer progress.Printer) error { | 
					
						
							| 
									
										
										
										
											2024-01-20 18:40:22 +01:00
										 |  |  | 	wg, wgCtx := errgroup.WithContext(ctx) | 
					
						
							|  |  |  | 	repo.StartPackUploader(wgCtx, wg) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	printer.P("salvaging intact data from specified pack files") | 
					
						
							|  |  |  | 	bar := printer.NewCounter("pack files") | 
					
						
							|  |  |  | 	bar.SetMax(uint64(len(ids))) | 
					
						
							|  |  |  | 	defer bar.Done() | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	wg.Go(func() error { | 
					
						
							|  |  |  | 		// examine all data the indexes have for the pack file | 
					
						
							| 
									
										
										
										
											2024-05-19 12:41:56 +02:00
										 |  |  | 		for b := range repo.ListPacksFromIndex(wgCtx, ids) { | 
					
						
							| 
									
										
										
										
											2024-01-20 18:40:22 +01:00
										 |  |  | 			blobs := b.Blobs | 
					
						
							|  |  |  | 			if len(blobs) == 0 { | 
					
						
							|  |  |  | 				printer.E("no blobs found for pack %v", b.PackID) | 
					
						
							|  |  |  | 				bar.Add(1) | 
					
						
							|  |  |  | 				continue | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			err := repo.LoadBlobsFromPack(wgCtx, b.PackID, blobs, func(blob restic.BlobHandle, buf []byte, err error) error { | 
					
						
							|  |  |  | 				if err != nil { | 
					
						
							| 
									
										
										
										
											2024-05-09 17:46:36 +02:00
										 |  |  | 					printer.E("failed to load blob %v: %v", blob.ID, err) | 
					
						
							|  |  |  | 					return nil | 
					
						
							| 
									
										
										
										
											2024-01-20 18:40:22 +01:00
										 |  |  | 				} | 
					
						
							|  |  |  | 				id, _, _, err := repo.SaveBlob(wgCtx, blob.Type, buf, restic.ID{}, true) | 
					
						
							|  |  |  | 				if !id.Equal(blob.ID) { | 
					
						
							|  |  |  | 					panic("pack id mismatch during upload") | 
					
						
							|  |  |  | 				} | 
					
						
							|  |  |  | 				return err | 
					
						
							|  |  |  | 			}) | 
					
						
							| 
									
										
										
										
											2024-01-20 21:54:27 +01:00
										 |  |  | 			// ignore truncated file parts | 
					
						
							|  |  |  | 			if err != nil && !errors.Is(err, io.ErrUnexpectedEOF) { | 
					
						
							| 
									
										
										
										
											2024-01-20 18:40:22 +01:00
										 |  |  | 				return err | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 			bar.Add(1) | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		return repo.Flush(wgCtx) | 
					
						
							|  |  |  | 	}) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	err := wg.Wait() | 
					
						
							|  |  |  | 	bar.Done() | 
					
						
							|  |  |  | 	if err != nil { | 
					
						
							|  |  |  | 		return err | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	// remove salvaged packs from index | 
					
						
							| 
									
										
										
										
											2024-04-10 21:31:53 +02:00
										 |  |  | 	err = rebuildIndexFiles(ctx, repo, ids, nil, false, printer) | 
					
						
							| 
									
										
										
										
											2024-01-20 18:40:22 +01:00
										 |  |  | 	if err != nil { | 
					
						
							|  |  |  | 		return err | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	// cleanup | 
					
						
							|  |  |  | 	printer.P("removing salvaged pack files") | 
					
						
							|  |  |  | 	// if we fail to delete the damaged pack files, then prune will remove them later on | 
					
						
							|  |  |  | 	bar = printer.NewCounter("files deleted") | 
					
						
							|  |  |  | 	_ = restic.ParallelRemove(ctx, repo, ids, restic.PackFile, nil, bar) | 
					
						
							|  |  |  | 	bar.Done() | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	return nil | 
					
						
							|  |  |  | } |