fuse: correctly handle snapshots

The fuse code kept adding snapshots to the top-level dir "snapshots". In
addition, snapshots with the same timestamp (same second) were not added
correctly, they will now be suffixed by an incrementing counter, e.g.:

    dr-xr-xr-x 1 fd0 users 0 Sep 18 15:01 2016-09-18T15:01:44+02:00
    dr-xr-xr-x 1 fd0 users 0 Sep 18 15:01 2016-09-18T15:01:48+02:00
    dr-xr-xr-x 1 fd0 users 0 Sep 18 15:01 2016-09-18T15:01:48+02:00-1

Closes #624
This commit is contained in:
Alexander Neumann 2016-09-18 15:03:14 +02:00
parent c5763e59d5
commit 5494c1858e

View file

@ -36,6 +36,7 @@ type SnapshotsDir struct {
// knownSnapshots maps snapshot timestamp to the snapshot // knownSnapshots maps snapshot timestamp to the snapshot
sync.RWMutex sync.RWMutex
knownSnapshots map[string]SnapshotWithId knownSnapshots map[string]SnapshotWithId
processed restic.IDSet
} }
// NewSnapshotsDir returns a new dir object for the snapshots. // NewSnapshotsDir returns a new dir object for the snapshots.
@ -45,6 +46,7 @@ func NewSnapshotsDir(repo restic.Repository, ownerIsRoot bool) *SnapshotsDir {
repo: repo, repo: repo,
knownSnapshots: make(map[string]SnapshotWithId), knownSnapshots: make(map[string]SnapshotWithId),
ownerIsRoot: ownerIsRoot, ownerIsRoot: ownerIsRoot,
processed: restic.NewIDSet(),
} }
} }
@ -66,6 +68,11 @@ func (sn *SnapshotsDir) updateCache(ctx context.Context) error {
defer sn.Unlock() defer sn.Unlock()
for id := range sn.repo.List(restic.SnapshotFile, ctx.Done()) { for id := range sn.repo.List(restic.SnapshotFile, ctx.Done()) {
if sn.processed.Has(id) {
debug.Log("SnapshotsDir.List", "skipping snapshot %v, already in list", id.Str())
continue
}
debug.Log("SnapshotsDir.List", "found snapshot id %v", id.Str()) debug.Log("SnapshotsDir.List", "found snapshot id %v", id.Str())
snapshot, err := restic.LoadSnapshot(sn.repo, id) snapshot, err := restic.LoadSnapshot(sn.repo, id)
if err != nil { if err != nil {
@ -73,7 +80,6 @@ func (sn *SnapshotsDir) updateCache(ctx context.Context) error {
} }
timestamp := snapshot.Time.Format(time.RFC3339) timestamp := snapshot.Time.Format(time.RFC3339)
for i := 1; ; i++ { for i := 1; ; i++ {
if _, ok := sn.knownSnapshots[timestamp]; !ok { if _, ok := sn.knownSnapshots[timestamp]; !ok {
break break
@ -84,6 +90,7 @@ func (sn *SnapshotsDir) updateCache(ctx context.Context) error {
debug.Log("SnapshotsDir.List", " add %v as dir %v", id.Str(), timestamp) debug.Log("SnapshotsDir.List", " add %v as dir %v", id.Str(), timestamp)
sn.knownSnapshots[timestamp] = SnapshotWithId{snapshot, id} sn.knownSnapshots[timestamp] = SnapshotWithId{snapshot, id}
sn.processed.Insert(id)
} }
return nil return nil
} }
@ -107,11 +114,11 @@ func (sn *SnapshotsDir) ReadDirAll(ctx context.Context) ([]fuse.Dirent, error) {
defer sn.RUnlock() defer sn.RUnlock()
ret := make([]fuse.Dirent, 0) ret := make([]fuse.Dirent, 0)
for _, snapshot := range sn.knownSnapshots { for timestamp, snapshot := range sn.knownSnapshots {
ret = append(ret, fuse.Dirent{ ret = append(ret, fuse.Dirent{
Inode: inodeFromBackendID(snapshot.ID), Inode: inodeFromBackendID(snapshot.ID),
Type: fuse.DT_Dir, Type: fuse.DT_Dir,
Name: snapshot.Time.Format(time.RFC3339), Name: timestamp,
}) })
} }
@ -120,20 +127,20 @@ func (sn *SnapshotsDir) ReadDirAll(ctx context.Context) ([]fuse.Dirent, error) {
} }
func (sn *SnapshotsDir) Lookup(ctx context.Context, name string) (fs.Node, error) { func (sn *SnapshotsDir) Lookup(ctx context.Context, name string) (fs.Node, error) {
debug.Log("SnapshotsDir.updateCache", "Lookup(%s)", name) debug.Log("SnapshotsDir.Lookup", "Lookup(%s)", name)
snapshot, ok := sn.get(name) snapshot, ok := sn.get(name)
if !ok { if !ok {
// We don't know about it, update the cache // We don't know about it, update the cache
err := sn.updateCache(ctx) err := sn.updateCache(ctx)
if err != nil { if err != nil {
debug.Log("SnapshotsDir.updateCache", " Lookup(%s) -> err %v", name, err) debug.Log("SnapshotsDir.Lookup", " Lookup(%s) -> err %v", name, err)
return nil, err return nil, err
} }
snapshot, ok = sn.get(name) snapshot, ok = sn.get(name)
if !ok { if !ok {
// We still don't know about it, this time it really doesn't exist // We still don't know about it, this time it really doesn't exist
debug.Log("SnapshotsDir.updateCache", " Lookup(%s) -> not found", name) debug.Log("SnapshotsDir.Lookup", " Lookup(%s) -> not found", name)
return nil, fuse.ENOENT return nil, fuse.ENOENT
} }
} }