github.com/fawick/restic@v0.1.1-0.20171126184616-c02923fbfc79/cmd/restic/cmd_cat.go (about) 1 package main 2 3 import ( 4 "context" 5 "encoding/json" 6 "fmt" 7 "os" 8 9 "github.com/spf13/cobra" 10 11 "github.com/restic/restic/internal/backend" 12 "github.com/restic/restic/internal/errors" 13 "github.com/restic/restic/internal/repository" 14 "github.com/restic/restic/internal/restic" 15 ) 16 17 var cmdCat = &cobra.Command{ 18 Use: "cat [flags] [pack|blob|snapshot|index|key|masterkey|config|lock] ID", 19 Short: "Print internal objects to stdout", 20 Long: ` 21 The "cat" command is used to print internal objects to stdout. 22 `, 23 DisableAutoGenTag: true, 24 RunE: func(cmd *cobra.Command, args []string) error { 25 return runCat(globalOptions, args) 26 }, 27 } 28 29 func init() { 30 cmdRoot.AddCommand(cmdCat) 31 } 32 33 func runCat(gopts GlobalOptions, args []string) error { 34 if len(args) < 1 || (args[0] != "masterkey" && args[0] != "config" && len(args) != 2) { 35 return errors.Fatal("type or ID not specified") 36 } 37 38 repo, err := OpenRepository(gopts) 39 if err != nil { 40 return err 41 } 42 43 lock, err := lockRepo(repo) 44 defer unlockRepo(lock) 45 if err != nil { 46 return err 47 } 48 49 tpe := args[0] 50 51 var id restic.ID 52 if tpe != "masterkey" && tpe != "config" { 53 id, err = restic.ParseID(args[1]) 54 if err != nil { 55 if tpe != "snapshot" { 56 return errors.Fatalf("unable to parse ID: %v\n", err) 57 } 58 59 // find snapshot id with prefix 60 id, err = restic.FindSnapshot(repo, args[1]) 61 if err != nil { 62 return err 63 } 64 } 65 } 66 67 // handle all types that don't need an index 68 switch tpe { 69 case "config": 70 buf, err := json.MarshalIndent(repo.Config(), "", " ") 71 if err != nil { 72 return err 73 } 74 75 fmt.Println(string(buf)) 76 return nil 77 case "index": 78 buf, err := repo.LoadAndDecrypt(context.TODO(), restic.IndexFile, id) 79 if err != nil { 80 return err 81 } 82 83 _, err = os.Stdout.Write(append(buf, '\n')) 84 return err 85 86 case "snapshot": 87 sn := &restic.Snapshot{} 88 err = repo.LoadJSONUnpacked(context.TODO(), restic.SnapshotFile, id, sn) 89 if err != nil { 90 return err 91 } 92 93 buf, err := json.MarshalIndent(&sn, "", " ") 94 if err != nil { 95 return err 96 } 97 98 fmt.Println(string(buf)) 99 100 return nil 101 case "key": 102 h := restic.Handle{Type: restic.KeyFile, Name: id.String()} 103 buf, err := backend.LoadAll(context.TODO(), repo.Backend(), h) 104 if err != nil { 105 return err 106 } 107 108 key := &repository.Key{} 109 err = json.Unmarshal(buf, key) 110 if err != nil { 111 return err 112 } 113 114 buf, err = json.MarshalIndent(&key, "", " ") 115 if err != nil { 116 return err 117 } 118 119 fmt.Println(string(buf)) 120 return nil 121 case "masterkey": 122 buf, err := json.MarshalIndent(repo.Key(), "", " ") 123 if err != nil { 124 return err 125 } 126 127 fmt.Println(string(buf)) 128 return nil 129 case "lock": 130 lock, err := restic.LoadLock(context.TODO(), repo, id) 131 if err != nil { 132 return err 133 } 134 135 buf, err := json.MarshalIndent(&lock, "", " ") 136 if err != nil { 137 return err 138 } 139 140 fmt.Println(string(buf)) 141 142 return nil 143 } 144 145 // load index, handle all the other types 146 err = repo.LoadIndex(context.TODO()) 147 if err != nil { 148 return err 149 } 150 151 switch tpe { 152 case "pack": 153 h := restic.Handle{Type: restic.DataFile, Name: id.String()} 154 buf, err := backend.LoadAll(context.TODO(), repo.Backend(), h) 155 if err != nil { 156 return err 157 } 158 159 hash := restic.Hash(buf) 160 if !hash.Equal(id) { 161 fmt.Fprintf(stderr, "Warning: hash of data does not match ID, want\n %v\ngot:\n %v\n", id.String(), hash.String()) 162 } 163 164 _, err = os.Stdout.Write(buf) 165 return err 166 167 case "blob": 168 for _, t := range []restic.BlobType{restic.DataBlob, restic.TreeBlob} { 169 list, err := repo.Index().Lookup(id, t) 170 if err != nil { 171 continue 172 } 173 blob := list[0] 174 175 buf := make([]byte, blob.Length) 176 n, err := repo.LoadBlob(context.TODO(), t, id, buf) 177 if err != nil { 178 return err 179 } 180 buf = buf[:n] 181 182 _, err = os.Stdout.Write(buf) 183 return err 184 } 185 186 return errors.Fatal("blob not found") 187 188 default: 189 return errors.Fatal("invalid type") 190 } 191 }