| 
									
										
										
										
											2016-08-01 18:55:07 +02:00
										 |  |  | package repository | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | import ( | 
					
						
							| 
									
										
										
										
											2017-06-04 11:16:55 +02:00
										 |  |  | 	"context" | 
					
						
							| 
									
										
										
										
											2017-01-23 17:05:30 +01:00
										 |  |  | 	"crypto/sha256" | 
					
						
							| 
									
										
										
										
											2016-08-01 18:55:07 +02:00
										 |  |  | 	"io" | 
					
						
							| 
									
										
										
										
											2016-08-29 19:18:57 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-07-23 14:21:03 +02:00
										 |  |  | 	"github.com/restic/restic/internal/debug" | 
					
						
							|  |  |  | 	"github.com/restic/restic/internal/fs" | 
					
						
							|  |  |  | 	"github.com/restic/restic/internal/hashing" | 
					
						
							|  |  |  | 	"github.com/restic/restic/internal/pack" | 
					
						
							| 
									
										
										
										
											2017-07-24 17:42:25 +02:00
										 |  |  | 	"github.com/restic/restic/internal/restic" | 
					
						
							| 
									
										
										
										
											2017-07-23 14:21:03 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	"github.com/restic/restic/internal/errors" | 
					
						
							| 
									
										
										
										
											2016-08-01 18:55:07 +02:00
										 |  |  | ) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // Repack takes a list of packs together with a list of blobs contained in | 
					
						
							|  |  |  | // these packs. Each pack is loaded and the blobs listed in keepBlobs is saved | 
					
						
							| 
									
										
										
										
											2017-06-15 14:40:34 +02:00
										 |  |  | // into a new pack. Returned is the list of obsolete packs which can then | 
					
						
							|  |  |  | // be removed. | 
					
						
							|  |  |  | func Repack(ctx context.Context, repo restic.Repository, packs restic.IDSet, keepBlobs restic.BlobSet, p *restic.Progress) (obsoletePacks restic.IDSet, err error) { | 
					
						
							| 
									
										
										
										
											2016-09-27 22:35:08 +02:00
										 |  |  | 	debug.Log("repacking %d packs while keeping %d blobs", len(packs), len(keepBlobs)) | 
					
						
							| 
									
										
										
										
											2016-08-01 18:55:07 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	for packID := range packs { | 
					
						
							| 
									
										
										
										
											2017-01-23 17:05:30 +01:00
										 |  |  | 		// load the complete pack into a temp file | 
					
						
							| 
									
										
										
										
											2016-09-01 21:19:30 +02:00
										 |  |  | 		h := restic.Handle{Type: restic.DataFile, Name: packID.String()} | 
					
						
							| 
									
										
										
										
											2016-08-01 18:55:07 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-05-10 19:48:22 +02:00
										 |  |  | 		tempfile, err := fs.TempFile("", "restic-temp-repack-") | 
					
						
							| 
									
										
										
										
											2017-01-23 17:05:30 +01:00
										 |  |  | 		if err != nil { | 
					
						
							| 
									
										
										
										
											2017-06-15 14:40:34 +02:00
										 |  |  | 			return nil, errors.Wrap(err, "TempFile") | 
					
						
							| 
									
										
										
										
											2016-08-01 18:55:07 +02:00
										 |  |  | 		} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-06-04 11:16:55 +02:00
										 |  |  | 		beRd, err := repo.Backend().Load(ctx, h, 0, 0) | 
					
						
							| 
									
										
										
										
											2016-08-01 18:55:07 +02:00
										 |  |  | 		if err != nil { | 
					
						
							| 
									
										
										
										
											2017-06-15 14:40:34 +02:00
										 |  |  | 			return nil, err | 
					
						
							| 
									
										
										
										
											2016-08-01 18:55:07 +02:00
										 |  |  | 		} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-01-23 17:05:30 +01:00
										 |  |  | 		hrd := hashing.NewReader(beRd, sha256.New()) | 
					
						
							|  |  |  | 		packLength, err := io.Copy(tempfile, hrd) | 
					
						
							|  |  |  | 		if err != nil { | 
					
						
							| 
									
										
										
										
											2017-06-15 14:40:34 +02:00
										 |  |  | 			return nil, errors.Wrap(err, "Copy") | 
					
						
							| 
									
										
										
										
											2017-01-23 17:05:30 +01:00
										 |  |  | 		} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-02-05 15:40:30 +01:00
										 |  |  | 		if err = beRd.Close(); err != nil { | 
					
						
							| 
									
										
										
										
											2017-06-15 14:40:34 +02:00
										 |  |  | 			return nil, errors.Wrap(err, "Close") | 
					
						
							| 
									
										
										
										
											2017-02-05 15:40:30 +01:00
										 |  |  | 		} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-01-23 17:05:30 +01:00
										 |  |  | 		hash := restic.IDFromHash(hrd.Sum(nil)) | 
					
						
							|  |  |  | 		debug.Log("pack %v loaded (%d bytes), hash %v", packID.Str(), packLength, hash.Str()) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		if !packID.Equal(hash) { | 
					
						
							| 
									
										
										
										
											2017-06-15 14:40:34 +02:00
										 |  |  | 			return nil, errors.Errorf("hash does not match id: want %v, got %v", packID, hash) | 
					
						
							| 
									
										
										
										
											2017-01-23 17:05:30 +01:00
										 |  |  | 		} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		_, err = tempfile.Seek(0, 0) | 
					
						
							|  |  |  | 		if err != nil { | 
					
						
							| 
									
										
										
										
											2017-06-15 14:40:34 +02:00
										 |  |  | 			return nil, errors.Wrap(err, "Seek") | 
					
						
							| 
									
										
										
										
											2017-01-23 17:05:30 +01:00
										 |  |  | 		} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		blobs, err := pack.List(repo.Key(), tempfile, packLength) | 
					
						
							| 
									
										
										
										
											2016-08-01 18:55:07 +02:00
										 |  |  | 		if err != nil { | 
					
						
							| 
									
										
										
										
											2017-06-15 14:40:34 +02:00
										 |  |  | 			return nil, err | 
					
						
							| 
									
										
										
										
											2016-08-01 18:55:07 +02:00
										 |  |  | 		} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-09-27 22:35:08 +02:00
										 |  |  | 		debug.Log("processing pack %v, blobs: %v", packID.Str(), len(blobs)) | 
					
						
							| 
									
										
										
										
											2017-01-23 17:05:30 +01:00
										 |  |  | 		var buf []byte | 
					
						
							| 
									
										
										
										
											2016-08-25 21:08:16 +02:00
										 |  |  | 		for _, entry := range blobs { | 
					
						
							| 
									
										
										
										
											2016-08-31 22:39:36 +02:00
										 |  |  | 			h := restic.BlobHandle{ID: entry.ID, Type: entry.Type} | 
					
						
							| 
									
										
										
										
											2016-08-03 22:38:05 +02:00
										 |  |  | 			if !keepBlobs.Has(h) { | 
					
						
							| 
									
										
										
										
											2016-08-01 18:55:07 +02:00
										 |  |  | 				continue | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-09-27 22:35:08 +02:00
										 |  |  | 			debug.Log("  process blob %v", h) | 
					
						
							| 
									
										
										
										
											2016-08-01 18:55:07 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-05-17 01:28:39 +02:00
										 |  |  | 			buf = buf[:] | 
					
						
							| 
									
										
										
										
											2017-01-23 17:05:30 +01:00
										 |  |  | 			if uint(len(buf)) < entry.Length { | 
					
						
							|  |  |  | 				buf = make([]byte, entry.Length) | 
					
						
							| 
									
										
										
										
											2016-08-01 18:55:07 +02:00
										 |  |  | 			} | 
					
						
							| 
									
										
										
										
											2017-01-23 17:05:30 +01:00
										 |  |  | 			buf = buf[:entry.Length] | 
					
						
							| 
									
										
										
										
											2016-08-01 18:55:07 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-01-23 17:05:30 +01:00
										 |  |  | 			n, err := tempfile.ReadAt(buf, int64(entry.Offset)) | 
					
						
							|  |  |  | 			if err != nil { | 
					
						
							| 
									
										
										
										
											2017-06-15 14:40:34 +02:00
										 |  |  | 				return nil, errors.Wrap(err, "ReadAt") | 
					
						
							| 
									
										
										
										
											2017-01-23 17:05:30 +01:00
										 |  |  | 			} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			if n != len(buf) { | 
					
						
							| 
									
										
										
										
											2017-06-15 14:40:34 +02:00
										 |  |  | 				return nil, errors.Errorf("read blob %v from %v: not enough bytes read, want %v, got %v", | 
					
						
							| 
									
										
										
										
											2017-01-23 17:05:30 +01:00
										 |  |  | 					h, tempfile.Name(), len(buf), n) | 
					
						
							|  |  |  | 			} | 
					
						
							| 
									
										
										
										
											2016-09-03 13:34:04 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-06-19 21:12:53 +02:00
										 |  |  | 			n, err = repo.Key().Decrypt(buf, buf) | 
					
						
							| 
									
										
										
										
											2016-08-01 18:55:07 +02:00
										 |  |  | 			if err != nil { | 
					
						
							| 
									
										
										
										
											2017-06-15 14:40:34 +02:00
										 |  |  | 				return nil, err | 
					
						
							| 
									
										
										
										
											2016-08-01 18:55:07 +02:00
										 |  |  | 			} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-01-23 17:05:30 +01:00
										 |  |  | 			buf = buf[:n] | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			id := restic.Hash(buf) | 
					
						
							|  |  |  | 			if !id.Equal(entry.ID) { | 
					
						
							| 
									
										
										
										
											2017-06-15 14:40:34 +02:00
										 |  |  | 				return nil, errors.Errorf("read blob %v from %v: wrong data returned, hash is %v", | 
					
						
							| 
									
										
										
										
											2017-01-23 17:05:30 +01:00
										 |  |  | 					h, tempfile.Name(), id) | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-06-04 11:16:55 +02:00
										 |  |  | 			_, err = repo.SaveBlob(ctx, entry.Type, buf, entry.ID) | 
					
						
							| 
									
										
										
										
											2016-08-01 18:55:07 +02:00
										 |  |  | 			if err != nil { | 
					
						
							| 
									
										
										
										
											2017-06-15 14:40:34 +02:00
										 |  |  | 				return nil, err | 
					
						
							| 
									
										
										
										
											2016-08-01 18:55:07 +02:00
										 |  |  | 			} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-09-27 22:35:08 +02:00
										 |  |  | 			debug.Log("  saved blob %v", entry.ID.Str()) | 
					
						
							| 
									
										
										
										
											2016-08-01 18:55:07 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-08-03 22:38:05 +02:00
										 |  |  | 			keepBlobs.Delete(h) | 
					
						
							| 
									
										
										
										
											2016-08-01 18:55:07 +02:00
										 |  |  | 		} | 
					
						
							| 
									
										
										
										
											2017-01-23 17:05:30 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  | 		if err = tempfile.Close(); err != nil { | 
					
						
							| 
									
										
										
										
											2017-06-15 14:40:34 +02:00
										 |  |  | 			return nil, errors.Wrap(err, "Close") | 
					
						
							| 
									
										
										
										
											2017-01-23 17:05:30 +01:00
										 |  |  | 		} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-05-10 19:48:22 +02:00
										 |  |  | 		if err = fs.RemoveIfExists(tempfile.Name()); err != nil { | 
					
						
							| 
									
										
										
										
											2017-06-15 14:40:34 +02:00
										 |  |  | 			return nil, errors.Wrap(err, "Remove") | 
					
						
							| 
									
										
										
										
											2017-01-23 17:05:30 +01:00
										 |  |  | 		} | 
					
						
							| 
									
										
										
										
											2017-03-04 17:38:34 +01:00
										 |  |  | 		if p != nil { | 
					
						
							|  |  |  | 			p.Report(restic.Stat{Blobs: 1}) | 
					
						
							|  |  |  | 		} | 
					
						
							| 
									
										
										
										
											2016-08-01 18:55:07 +02:00
										 |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if err := repo.Flush(); err != nil { | 
					
						
							| 
									
										
										
										
											2017-06-15 14:40:34 +02:00
										 |  |  | 		return nil, err | 
					
						
							| 
									
										
										
										
											2016-08-01 18:55:07 +02:00
										 |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-06-15 14:40:34 +02:00
										 |  |  | 	return packs, nil | 
					
						
							| 
									
										
										
										
											2016-08-01 18:55:07 +02:00
										 |  |  | } |