github.com/mckael/restic@v0.8.3/internal/archiver/archive_reader.go (about) 1 package archiver 2 3 import ( 4 "context" 5 "io" 6 "time" 7 8 "github.com/restic/restic/internal/debug" 9 "github.com/restic/restic/internal/restic" 10 11 "github.com/restic/restic/internal/errors" 12 13 "github.com/restic/chunker" 14 ) 15 16 // Reader allows saving a stream of data to the repository. 17 type Reader struct { 18 restic.Repository 19 20 Tags []string 21 Hostname string 22 } 23 24 // Archive reads data from the reader and saves it to the repo. 25 func (r *Reader) Archive(ctx context.Context, name string, rd io.Reader, p *restic.Progress) (*restic.Snapshot, restic.ID, error) { 26 if name == "" { 27 return nil, restic.ID{}, errors.New("no filename given") 28 } 29 30 debug.Log("start archiving %s", name) 31 sn, err := restic.NewSnapshot([]string{name}, r.Tags, r.Hostname, time.Now()) 32 if err != nil { 33 return nil, restic.ID{}, err 34 } 35 36 p.Start() 37 defer p.Done() 38 39 repo := r.Repository 40 chnker := chunker.New(rd, repo.Config().ChunkerPolynomial) 41 42 ids := restic.IDs{} 43 var fileSize uint64 44 45 for { 46 chunk, err := chnker.Next(getBuf()) 47 if errors.Cause(err) == io.EOF { 48 break 49 } 50 51 if err != nil { 52 return nil, restic.ID{}, errors.Wrap(err, "chunker.Next()") 53 } 54 55 id := restic.Hash(chunk.Data) 56 57 if !repo.Index().Has(id, restic.DataBlob) { 58 _, err := repo.SaveBlob(ctx, restic.DataBlob, chunk.Data, id) 59 if err != nil { 60 return nil, restic.ID{}, err 61 } 62 debug.Log("saved blob %v (%d bytes)\n", id, chunk.Length) 63 } else { 64 debug.Log("blob %v already saved in the repo\n", id) 65 } 66 67 freeBuf(chunk.Data) 68 69 ids = append(ids, id) 70 71 p.Report(restic.Stat{Bytes: uint64(chunk.Length)}) 72 fileSize += uint64(chunk.Length) 73 } 74 75 tree := &restic.Tree{ 76 Nodes: []*restic.Node{ 77 { 78 Name: name, 79 AccessTime: time.Now(), 80 ModTime: time.Now(), 81 Type: "file", 82 Mode: 0644, 83 Size: fileSize, 84 UID: sn.UID, 85 GID: sn.GID, 86 User: sn.Username, 87 Content: ids, 88 }, 89 }, 90 } 91 92 treeID, err := repo.SaveTree(ctx, tree) 93 if err != nil { 94 return nil, restic.ID{}, err 95 } 96 sn.Tree = &treeID 97 debug.Log("tree saved as %v", treeID) 98 99 id, err := repo.SaveJSONUnpacked(ctx, restic.SnapshotFile, sn) 100 if err != nil { 101 return nil, restic.ID{}, err 102 } 103 104 debug.Log("snapshot saved as %v", id) 105 106 err = repo.Flush(ctx) 107 if err != nil { 108 return nil, restic.ID{}, err 109 } 110 111 err = repo.SaveIndex(ctx) 112 if err != nil { 113 return nil, restic.ID{}, err 114 } 115 116 return sn, id, nil 117 }