mirror of
https://github.com/kopia/kopia.git
synced 2026-01-23 22:07:54 -05:00
This helps recycle buffers more efficiently during snapshots. Also, improved memory tracking, enabled profiling flags and added pprof by default.
100 lines
2.1 KiB
Go
100 lines
2.1 KiB
Go
package cli
|
|
|
|
import (
|
|
"bytes"
|
|
"context"
|
|
"encoding/json"
|
|
"io"
|
|
|
|
"github.com/pkg/errors"
|
|
|
|
"github.com/kopia/kopia/internal/gather"
|
|
"github.com/kopia/kopia/internal/iocopy"
|
|
"github.com/kopia/kopia/repo"
|
|
"github.com/kopia/kopia/repo/blob"
|
|
)
|
|
|
|
type commandBlobShow struct {
|
|
blobShowDecrypt bool
|
|
blobShowIDs []string
|
|
|
|
out textOutput
|
|
}
|
|
|
|
func (c *commandBlobShow) setup(svc appServices, parent commandParent) {
|
|
cmd := parent.Command("show", "Show contents of BLOBs").Alias("cat")
|
|
cmd.Flag("decrypt", "Decrypt blob if possible").BoolVar(&c.blobShowDecrypt)
|
|
cmd.Arg("blobID", "Blob IDs").Required().StringsVar(&c.blobShowIDs)
|
|
cmd.Action(svc.directRepositoryReadAction(c.run))
|
|
|
|
c.out.setup(svc)
|
|
}
|
|
|
|
func (c *commandBlobShow) run(ctx context.Context, rep repo.DirectRepository) error {
|
|
for _, blobID := range c.blobShowIDs {
|
|
if err := c.maybeDecryptBlob(ctx, c.out.stdout(), rep, blob.ID(blobID)); err != nil {
|
|
return errors.Wrap(err, "error presenting blob")
|
|
}
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
func (c *commandBlobShow) maybeDecryptBlob(ctx context.Context, w io.Writer, rep repo.DirectRepository, blobID blob.ID) error {
|
|
var (
|
|
d gather.WriteBuffer
|
|
b gather.Bytes
|
|
)
|
|
|
|
if err := rep.BlobReader().GetBlob(ctx, blobID, 0, -1, &d); err != nil {
|
|
return errors.Wrap(err, "error reading blob")
|
|
}
|
|
|
|
b = d.Bytes()
|
|
|
|
if c.blobShowDecrypt && canDecryptBlob(blobID) {
|
|
var tmp gather.WriteBuffer
|
|
defer tmp.Close()
|
|
|
|
if err := rep.Crypter().DecryptBLOB(b, blobID, &tmp); err != nil {
|
|
return errors.Wrap(err, "error decrypting blob")
|
|
}
|
|
|
|
b = tmp.Bytes()
|
|
}
|
|
|
|
if isJSONBlob(blobID) {
|
|
var buf bytes.Buffer
|
|
|
|
if err := json.Indent(&buf, b.ToByteSlice(), "", " "); err != nil {
|
|
return errors.Wrap(err, "invalid JSON")
|
|
}
|
|
|
|
b = gather.FromSlice(buf.Bytes())
|
|
}
|
|
|
|
if err := iocopy.JustCopy(w, b.Reader()); err != nil {
|
|
return errors.Wrap(err, "error copying data")
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
func canDecryptBlob(b blob.ID) bool {
|
|
switch b[0] {
|
|
case '_', 'n', 'm', 'l':
|
|
return true
|
|
default:
|
|
return false
|
|
}
|
|
}
|
|
|
|
func isJSONBlob(b blob.ID) bool {
|
|
switch b[0] {
|
|
case 'm', 'l':
|
|
return true
|
|
default:
|
|
return false
|
|
}
|
|
}
|