restic/src/cmds/restic/cmd_find.go

196 lines
4.1 KiB
Go
Raw Normal View History

2014-12-07 13:44:01 +00:00
package main
import (
"path/filepath"
2014-12-07 15:30:52 +00:00
"time"
2014-12-07 13:44:01 +00:00
"restic"
"restic/debug"
"restic/repository"
2014-12-07 13:44:01 +00:00
)
type findResult struct {
node *restic.Node
path string
}
2014-12-07 15:30:52 +00:00
type CmdFind struct {
2014-12-07 16:11:01 +00:00
Oldest string `short:"o" long:"oldest" description:"Oldest modification date/time"`
Newest string `short:"n" long:"newest" description:"Newest modification date/time"`
Snapshot string `short:"s" long:"snapshot" description:"Snapshot ID to search in"`
oldest, newest time.Time
pattern string
global *GlobalOptions
2014-12-07 16:11:01 +00:00
}
var timeFormats = []string{
"2006-01-02",
"2006-01-02 15:04",
"2006-01-02 15:04:05",
"2006-01-02 15:04:05 -0700",
"2006-01-02 15:04:05 MST",
"02.01.2006",
"02.01.2006 15:04",
"02.01.2006 15:04:05",
"02.01.2006 15:04:05 -0700",
"02.01.2006 15:04:05 MST",
"Mon Jan 2 15:04:05 -0700 MST 2006",
2014-12-07 15:30:52 +00:00
}
func init() {
_, err := parser.AddCommand("find",
"find a file/directory",
"The find command searches for files or directories in snapshots",
&CmdFind{global: &globalOpts})
2014-12-07 15:30:52 +00:00
if err != nil {
panic(err)
}
}
2014-12-07 16:11:01 +00:00
func parseTime(str string) (time.Time, error) {
for _, fmt := range timeFormats {
if t, err := time.ParseInLocation(fmt, str, time.Local); err == nil {
return t, nil
}
}
return time.Time{}, restic.Fatalf("unable to parse time: %q", str)
2014-12-07 16:11:01 +00:00
}
2016-09-01 14:04:29 +00:00
func (c CmdFind) findInTree(repo *repository.Repository, id restic.ID, path string) ([]findResult, error) {
debug.Log("restic.find", "checking tree %v\n", id)
2015-05-09 11:32:52 +00:00
tree, err := restic.LoadTree(repo, id)
2014-12-07 13:44:01 +00:00
if err != nil {
return nil, err
}
results := []findResult{}
for _, node := range tree.Nodes {
2015-01-14 21:08:48 +00:00
debug.Log("restic.find", " testing entry %q\n", node.Name)
2014-12-07 16:11:01 +00:00
m, err := filepath.Match(c.pattern, node.Name)
2014-12-07 13:44:01 +00:00
if err != nil {
return nil, err
}
if m {
2015-01-14 21:08:48 +00:00
debug.Log("restic.find", " pattern matches\n")
2014-12-07 16:11:01 +00:00
if !c.oldest.IsZero() && node.ModTime.Before(c.oldest) {
2015-01-14 21:08:48 +00:00
debug.Log("restic.find", " ModTime is older than %s\n", c.oldest)
2014-12-07 16:11:01 +00:00
continue
}
if !c.newest.IsZero() && node.ModTime.After(c.newest) {
2015-01-14 21:08:48 +00:00
debug.Log("restic.find", " ModTime is newer than %s\n", c.newest)
2014-12-07 16:11:01 +00:00
continue
}
2014-12-07 13:44:01 +00:00
results = append(results, findResult{node: node, path: path})
2014-12-07 16:11:01 +00:00
} else {
2015-01-14 21:08:48 +00:00
debug.Log("restic.find", " pattern does not match\n")
2014-12-07 13:44:01 +00:00
}
2016-09-01 14:04:29 +00:00
if node.FileType == "dir" {
2015-08-27 21:21:44 +00:00
subdirResults, err := c.findInTree(repo, *node.Subtree, filepath.Join(path, node.Name))
2014-12-07 13:44:01 +00:00
if err != nil {
return nil, err
}
results = append(results, subdirResults...)
}
}
return results, nil
}
2016-09-01 14:04:29 +00:00
func (c CmdFind) findInSnapshot(repo *repository.Repository, id restic.ID) error {
debug.Log("restic.find", "searching in snapshot %s\n for entries within [%s %s]", id.Str(), c.oldest, c.newest)
2014-12-07 13:44:01 +00:00
2015-05-09 11:32:52 +00:00
sn, err := restic.LoadSnapshot(repo, id)
2014-12-07 13:44:01 +00:00
if err != nil {
return err
}
results, err := c.findInTree(repo, *sn.Tree, "")
2014-12-07 13:44:01 +00:00
if err != nil {
return err
}
if len(results) == 0 {
return nil
}
2015-08-28 17:31:05 +00:00
c.global.Verbosef("found %d matching entries in snapshot %s\n", len(results), id)
2014-12-07 13:44:01 +00:00
for _, res := range results {
res.node.Name = filepath.Join(res.path, res.node.Name)
2015-08-28 17:31:05 +00:00
c.global.Printf(" %s\n", res.node)
2014-12-07 13:44:01 +00:00
}
return nil
}
2014-12-07 16:11:01 +00:00
func (CmdFind) Usage() string {
return "[find-OPTIONS] PATTERN"
2014-12-07 15:30:52 +00:00
}
2014-12-07 16:11:01 +00:00
func (c CmdFind) Execute(args []string) error {
if len(args) != 1 {
return restic.Fatalf("wrong number of arguments, Usage: %s", c.Usage())
2014-12-07 16:11:01 +00:00
}
var err error
if c.Oldest != "" {
c.oldest, err = parseTime(c.Oldest)
if err != nil {
return err
}
}
if c.Newest != "" {
c.newest, err = parseTime(c.Newest)
if err != nil {
return err
}
2014-12-07 15:30:52 +00:00
}
repo, err := c.global.OpenRepository()
2014-12-07 15:30:52 +00:00
if err != nil {
return err
2014-12-07 13:44:01 +00:00
}
lock, err := lockRepo(repo)
defer unlockRepo(lock)
2015-06-27 12:40:18 +00:00
if err != nil {
return err
}
2015-08-27 21:21:44 +00:00
err = repo.LoadIndex()
if err != nil {
return err
}
2014-12-07 16:11:01 +00:00
c.pattern = args[0]
if c.Snapshot != "" {
snapshotID, err := restic.FindSnapshot(repo, c.Snapshot)
2014-12-07 13:44:01 +00:00
if err != nil {
return restic.Fatalf("invalid id %q: %v", args[1], err)
2014-12-07 13:44:01 +00:00
}
return c.findInSnapshot(repo, snapshotID)
2014-12-07 13:44:01 +00:00
}
2015-03-28 10:50:23 +00:00
done := make(chan struct{})
defer close(done)
2016-09-01 14:04:29 +00:00
for snapshotID := range repo.List(restic.SnapshotFile, done) {
err := c.findInSnapshot(repo, snapshotID)
2014-12-07 13:44:01 +00:00
if err != nil {
return err
}
}
return nil
}