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
|
# Copyright 2010, 2011 Lars Wirzenius
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
import logging
import sys
import tracing
import ttystatus
import larch
class Error(larch.Error):
def __init__(self, msg):
self.msg = 'Assertion failed: %s' % msg
class WorkItem(object):
'''A work item for fsck.
Subclass can optionally set the ``name`` attribute; the class name
is used by default.
'''
def __str__(self):
if hasattr(self, 'name'):
return self.name
else:
return self.__class__.__name__
def do(self):
pass
def warning(self, msg):
self.fsck.warning('warning: %s: %s' % (self.name, msg))
def error(self, msg):
self.fsck.error('ERROR: %s: %s' % (self.name, msg))
def get_node(self, node_id):
try:
return self.fsck.forest.node_store.get_node(node_id)
except larch.NodeMissing:
self.error(
'forest %s: node %s is missing' %
(self.fsck.forest_name, node_id))
class CheckNode(WorkItem):
def __init__(self, fsck, node_id):
self.fsck = fsck
self.node_id = node_id
self.name = 'node %s in %s' % (self.node_id, self.fsck.forest_name)
def do(self):
node = self.get_node(self.node_id)
if type(node) == larch.IndexNode:
for child_id in node.values():
seen_already = child_id in self.fsck.refcounts
self.fsck.count(child_id)
if not seen_already:
yield CheckNode(self.fsck, child_id)
class CheckForest(WorkItem):
def __init__(self, fsck):
self.fsck = fsck
self.name = 'forest %s' % self.fsck.forest_name
def do(self):
for tree in self.fsck.forest.trees:
self.fsck.count(tree.root.id)
yield CheckNode(self.fsck, tree.root.id)
class CheckRefcounts(WorkItem):
def __init__(self, fsck):
self.fsck = fsck
self.name = 'refcounts in %s' % self.fsck.forest_name
def do(self):
for node_id in self.fsck.refcounts:
refcount = self.fsck.forest.node_store.get_refcount(node_id)
if refcount != self.fsck.refcounts[node_id]:
self.error(
'forest %s: node %s: refcount is %s but should be %s' %
(self.fsck.forest_name,
node_id,
refcount,
self.fsck.refcounts[node_id]))
class Fsck(object):
'''Verify internal consistency of a larch.Forest.'''
def __init__(self, forest, warning, error, fix):
self.forest = forest
self.forest_name = getattr(
forest.node_store, 'dirname', 'in-memory forest')
self.warning = warning
self.error = error
self.fix = fix
self.refcounts = {}
def find_work(self):
yield CheckForest(self)
yield CheckRefcounts(self)
def count(self, node_id):
self.refcounts[node_id] = self.refcounts.get(node_id, 0) + 1
|