Files
kopia/cli/command_snapshot_fix_remove_files.go
Jarek Kowalski f49bcdd883 feat(cli): implementation for 'kopia snapshot fix' (#1930)
* feat(cli): implementation for 'kopia snapshot fix'

This allows modifications and fixes to the snapshots after they have
been taken.

Supported are:

* `kopia snapshot fix remove-invalid-files [--verify-files-percent=X]`

Removes all directory entries where the underlying files cannot be
read based on index analysis (this does not read the files, only index
structures so is reasonably quick).

`--verify-files-percent=100` can be used to trigger full read for
all files.

* `kopia snapshot fix remove-files --object-id=<object-id>`

Removes the object with a given ID from the entire snapshot tree.
Useful when you accidentally snapshot a sensitive file.

* `kopia snapshot fix remove-files --filename=<wildcard>`

Removes the files with a given name from the entire snapshot tree.
Useful when you accidentally snapshot a sensitive file.

By default all snapshots are analyzed and rewritten. To limit the scope
use:

--source=user@host:/path
--manifest-id=manifestID

By default the rewrite operation writes new directory entries but
does not replace the manifests. To do that pass `--commit`.

Related #1906
Fixes #799

reorganized CLI per PR suggestion

* additional logging for diff command

* added Clone() method to snapshot manifst and directory entry

* added a comprehensive test, moved DirRewriter  to separate file

* pr feedback

* more pr feedback

* improved logging output

* disable test in -race configuration since it's way to slow

* pr feedback
2022-05-25 01:17:55 +00:00

62 lines
1.6 KiB
Go

package cli
import (
"context"
"path"
"github.com/pkg/errors"
"github.com/kopia/kopia/repo"
"github.com/kopia/kopia/snapshot"
)
type commandSnapshotFixRemoveFiles struct {
common commonRewriteSnapshots
removeObjectIDs []string
removeFilesByName []string
}
func (c *commandSnapshotFixRemoveFiles) setup(svc appServices, parent commandParent) {
cmd := parent.Command("remove-files", "Remove references to the specified files from snapshots.")
c.common.setup(svc, cmd)
cmd.Flag("object-id", "Remove files by their object ID").StringsVar(&c.removeObjectIDs)
cmd.Flag("filename", "Remove files by filename (wildcards are supported)").StringsVar(&c.removeFilesByName)
cmd.Action(svc.repositoryWriterAction(c.run))
}
func (c *commandSnapshotFixRemoveFiles) rewriteEntry(ctx context.Context, dirRelativePath string, ent *snapshot.DirEntry) (*snapshot.DirEntry, error) {
for _, id := range c.removeObjectIDs {
if string(ent.ObjectID) == id {
log(ctx).Infof("will remove file %v", path.Join(dirRelativePath, ent.Name))
return nil, nil
}
}
for _, n := range c.removeFilesByName {
matched, err := path.Match(n, ent.Name)
if err != nil {
return nil, errors.Wrap(err, "invalid wildcard")
}
if matched {
log(ctx).Infof("will remove file %v", path.Join(dirRelativePath, ent.Name))
return nil, nil
}
}
return ent, nil
}
func (c *commandSnapshotFixRemoveFiles) run(ctx context.Context, rep repo.RepositoryWriter) error {
if len(c.removeObjectIDs)+len(c.removeFilesByName) == 0 {
return errors.Errorf("must specify files to remove")
}
return c.common.rewriteMatchingSnapshots(ctx, rep, c.rewriteEntry)
}