forked from someonegg/pathfs
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathdump.go
More file actions
167 lines (139 loc) · 3.17 KB
/
dump.go
File metadata and controls
167 lines (139 loc) · 3.17 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
package pathfs
import (
"errors"
"fmt"
"github.com/hanwen/go-fuse/v2/fuse"
"io"
)
type DumpFileEntry struct {
Opener fuse.Owner
Path string
// file
UFh uint32
// dir
Stream []fuse.DirEntry
}
type DumpRawBridge struct {
NodeCount int
Files []*DumpFileEntry
FreeFiles []uint32
}
type DumpInode struct {
Ino uint64
Revision uint32
LookupCount uint32
Parents []DumpParentEntry
IsDir bool
}
type DumpParentEntry struct {
Name string
Node uint64
}
type InodeIterator interface {
// returning io.EOF error means that all inodes has been dumped
Next() (data *DumpInode, err error)
}
type Copier interface {
Dump() (data *DumpRawBridge, iterator InodeIterator, err error)
Restore(data *DumpRawBridge) (filler InodeFiller, err error)
}
type InodeDumper struct {
inodes []*inode // flatted inodesMap
off int
}
func NewInodeDumper(inodesMap map[uint64]*inode) *InodeDumper {
inodes := make([]*inode, len(inodesMap))
i := 0
for _, v := range inodesMap {
inodes[i] = v
i++
}
return &InodeDumper{
inodes: inodes,
off: 0,
}
}
func (s *InodeDumper) Next() (data *DumpInode, err error) {
if s.off >= len(s.inodes) {
return nil, io.EOF
}
node := s.inodes[s.off]
data = &DumpInode{
node.ino,
node.revision,
node.lookupCount,
node.parents.Dump(),
node.isDir(),
}
s.off++
return data, nil
}
type InodeFiller interface {
AddInode(*DumpInode) error
// update bridge's root, may be removed
Finished() error
}
type InodeRestorer struct {
nodeCount int
addNodeCount int
bridge *rawBridge
}
// if not found in bridge's inodes, insert a new one and return it
// otherwise just return the existed one
func (s *InodeRestorer) getDirInode(ino uint64) *inode {
inodes := s.bridge.nodes
var ret *inode
var found bool
if ret, found = inodes[ino]; !found {
ret = &inode{
ino: ino,
children: make(map[string]*inode),
}
inodes[ino] = ret
}
return ret
}
func (s *InodeRestorer) AddInode(dumpInode *DumpInode) error {
inodes := s.bridge.nodes
var curInode *inode
var found bool
if curInode, found = inodes[dumpInode.Ino]; !found {
curInode = &inode{
ino: dumpInode.Ino,
}
inodes[dumpInode.Ino] = curInode
}
// restore other fields
curInode.revision = dumpInode.Revision
curInode.lookupCount = dumpInode.LookupCount
if dumpInode.IsDir && curInode.children == nil {
curInode.children = make(map[string]*inode)
}
var parInode *inode
for _, p := range dumpInode.Parents {
parInode = s.getDirInode(p.Node)
parInode.children[p.Name] = curInode
curInode.parents.add(parentEntry{name: p.Name, node: parInode})
}
s.addNodeCount++
return nil
}
// Finished restore root inode and verify inode's count
func (s *InodeRestorer) Finished() error {
bridge := s.bridge
if root, found := s.bridge.nodes[1]; !found {
return errors.New("root inode not found")
} else {
bridge.root = root
}
if s.addNodeCount < s.nodeCount {
for _, n := range s.bridge.nodes {
if n.revision == 0 {
bridge.logf("warning: inode %d is lost.\n", n.ino)
}
}
return fmt.Errorf("expected %d inodes, but only got %d inodes", s.nodeCount, s.addNodeCount)
}
s.bridge.nodeCountHigh = len(s.bridge.nodes)
return nil
}