##// END OF EJS Templates
verify: add a config option to skip certain flag processors...
Jun Wu -
r32288:a2ab9ebc default
parent child Browse files
Show More
@@ -1,482 +1,488
1 # verify.py - repository integrity checking for Mercurial
1 # verify.py - repository integrity checking for Mercurial
2 #
2 #
3 # Copyright 2006, 2007 Matt Mackall <mpm@selenic.com>
3 # Copyright 2006, 2007 Matt Mackall <mpm@selenic.com>
4 #
4 #
5 # This software may be used and distributed according to the terms of the
5 # This software may be used and distributed according to the terms of the
6 # GNU General Public License version 2 or any later version.
6 # GNU General Public License version 2 or any later version.
7
7
8 from __future__ import absolute_import
8 from __future__ import absolute_import
9
9
10 import os
10 import os
11
11
12 from .i18n import _
12 from .i18n import _
13 from .node import (
13 from .node import (
14 nullid,
14 nullid,
15 short,
15 short,
16 )
16 )
17
17
18 from . import (
18 from . import (
19 error,
19 error,
20 revlog,
20 revlog,
21 scmutil,
21 scmutil,
22 util,
22 util,
23 )
23 )
24
24
25 def verify(repo):
25 def verify(repo):
26 with repo.lock():
26 with repo.lock():
27 return verifier(repo).verify()
27 return verifier(repo).verify()
28
28
29 def _normpath(f):
29 def _normpath(f):
30 # under hg < 2.4, convert didn't sanitize paths properly, so a
30 # under hg < 2.4, convert didn't sanitize paths properly, so a
31 # converted repo may contain repeated slashes
31 # converted repo may contain repeated slashes
32 while '//' in f:
32 while '//' in f:
33 f = f.replace('//', '/')
33 f = f.replace('//', '/')
34 return f
34 return f
35
35
36 class verifier(object):
36 class verifier(object):
37 # The match argument is always None in hg core, but e.g. the narrowhg
37 # The match argument is always None in hg core, but e.g. the narrowhg
38 # extension will pass in a matcher here.
38 # extension will pass in a matcher here.
39 def __init__(self, repo, match=None):
39 def __init__(self, repo, match=None):
40 self.repo = repo.unfiltered()
40 self.repo = repo.unfiltered()
41 self.ui = repo.ui
41 self.ui = repo.ui
42 self.match = match or scmutil.matchall(repo)
42 self.match = match or scmutil.matchall(repo)
43 self.badrevs = set()
43 self.badrevs = set()
44 self.errors = 0
44 self.errors = 0
45 self.warnings = 0
45 self.warnings = 0
46 self.havecl = len(repo.changelog) > 0
46 self.havecl = len(repo.changelog) > 0
47 self.havemf = len(repo.manifestlog._revlog) > 0
47 self.havemf = len(repo.manifestlog._revlog) > 0
48 self.revlogv1 = repo.changelog.version != revlog.REVLOGV0
48 self.revlogv1 = repo.changelog.version != revlog.REVLOGV0
49 self.lrugetctx = util.lrucachefunc(repo.changectx)
49 self.lrugetctx = util.lrucachefunc(repo.changectx)
50 self.refersmf = False
50 self.refersmf = False
51 self.fncachewarned = False
51 self.fncachewarned = False
52 # developer config: verify.skipflags
53 self.skipflags = repo.ui.configint('verify', 'skipflags')
52
54
53 def warn(self, msg):
55 def warn(self, msg):
54 self.ui.warn(msg + "\n")
56 self.ui.warn(msg + "\n")
55 self.warnings += 1
57 self.warnings += 1
56
58
57 def err(self, linkrev, msg, filename=None):
59 def err(self, linkrev, msg, filename=None):
58 if linkrev is not None:
60 if linkrev is not None:
59 self.badrevs.add(linkrev)
61 self.badrevs.add(linkrev)
60 else:
62 else:
61 linkrev = '?'
63 linkrev = '?'
62 msg = "%s: %s" % (linkrev, msg)
64 msg = "%s: %s" % (linkrev, msg)
63 if filename:
65 if filename:
64 msg = "%s@%s" % (filename, msg)
66 msg = "%s@%s" % (filename, msg)
65 self.ui.warn(" " + msg + "\n")
67 self.ui.warn(" " + msg + "\n")
66 self.errors += 1
68 self.errors += 1
67
69
68 def exc(self, linkrev, msg, inst, filename=None):
70 def exc(self, linkrev, msg, inst, filename=None):
69 if not str(inst):
71 if not str(inst):
70 inst = repr(inst)
72 inst = repr(inst)
71 self.err(linkrev, "%s: %s" % (msg, inst), filename)
73 self.err(linkrev, "%s: %s" % (msg, inst), filename)
72
74
73 def checklog(self, obj, name, linkrev):
75 def checklog(self, obj, name, linkrev):
74 if not len(obj) and (self.havecl or self.havemf):
76 if not len(obj) and (self.havecl or self.havemf):
75 self.err(linkrev, _("empty or missing %s") % name)
77 self.err(linkrev, _("empty or missing %s") % name)
76 return
78 return
77
79
78 d = obj.checksize()
80 d = obj.checksize()
79 if d[0]:
81 if d[0]:
80 self.err(None, _("data length off by %d bytes") % d[0], name)
82 self.err(None, _("data length off by %d bytes") % d[0], name)
81 if d[1]:
83 if d[1]:
82 self.err(None, _("index contains %d extra bytes") % d[1], name)
84 self.err(None, _("index contains %d extra bytes") % d[1], name)
83
85
84 if obj.version != revlog.REVLOGV0:
86 if obj.version != revlog.REVLOGV0:
85 if not self.revlogv1:
87 if not self.revlogv1:
86 self.warn(_("warning: `%s' uses revlog format 1") % name)
88 self.warn(_("warning: `%s' uses revlog format 1") % name)
87 elif self.revlogv1:
89 elif self.revlogv1:
88 self.warn(_("warning: `%s' uses revlog format 0") % name)
90 self.warn(_("warning: `%s' uses revlog format 0") % name)
89
91
90 def checkentry(self, obj, i, node, seen, linkrevs, f):
92 def checkentry(self, obj, i, node, seen, linkrevs, f):
91 lr = obj.linkrev(obj.rev(node))
93 lr = obj.linkrev(obj.rev(node))
92 if lr < 0 or (self.havecl and lr not in linkrevs):
94 if lr < 0 or (self.havecl and lr not in linkrevs):
93 if lr < 0 or lr >= len(self.repo.changelog):
95 if lr < 0 or lr >= len(self.repo.changelog):
94 msg = _("rev %d points to nonexistent changeset %d")
96 msg = _("rev %d points to nonexistent changeset %d")
95 else:
97 else:
96 msg = _("rev %d points to unexpected changeset %d")
98 msg = _("rev %d points to unexpected changeset %d")
97 self.err(None, msg % (i, lr), f)
99 self.err(None, msg % (i, lr), f)
98 if linkrevs:
100 if linkrevs:
99 if f and len(linkrevs) > 1:
101 if f and len(linkrevs) > 1:
100 try:
102 try:
101 # attempt to filter down to real linkrevs
103 # attempt to filter down to real linkrevs
102 linkrevs = [l for l in linkrevs
104 linkrevs = [l for l in linkrevs
103 if self.lrugetctx(l)[f].filenode() == node]
105 if self.lrugetctx(l)[f].filenode() == node]
104 except Exception:
106 except Exception:
105 pass
107 pass
106 self.warn(_(" (expected %s)") % " ".join(map(str, linkrevs)))
108 self.warn(_(" (expected %s)") % " ".join(map(str, linkrevs)))
107 lr = None # can't be trusted
109 lr = None # can't be trusted
108
110
109 try:
111 try:
110 p1, p2 = obj.parents(node)
112 p1, p2 = obj.parents(node)
111 if p1 not in seen and p1 != nullid:
113 if p1 not in seen and p1 != nullid:
112 self.err(lr, _("unknown parent 1 %s of %s") %
114 self.err(lr, _("unknown parent 1 %s of %s") %
113 (short(p1), short(node)), f)
115 (short(p1), short(node)), f)
114 if p2 not in seen and p2 != nullid:
116 if p2 not in seen and p2 != nullid:
115 self.err(lr, _("unknown parent 2 %s of %s") %
117 self.err(lr, _("unknown parent 2 %s of %s") %
116 (short(p2), short(node)), f)
118 (short(p2), short(node)), f)
117 except Exception as inst:
119 except Exception as inst:
118 self.exc(lr, _("checking parents of %s") % short(node), inst, f)
120 self.exc(lr, _("checking parents of %s") % short(node), inst, f)
119
121
120 if node in seen:
122 if node in seen:
121 self.err(lr, _("duplicate revision %d (%d)") % (i, seen[node]), f)
123 self.err(lr, _("duplicate revision %d (%d)") % (i, seen[node]), f)
122 seen[node] = i
124 seen[node] = i
123 return lr
125 return lr
124
126
125 def verify(self):
127 def verify(self):
126 repo = self.repo
128 repo = self.repo
127
129
128 ui = repo.ui
130 ui = repo.ui
129
131
130 if not repo.url().startswith('file:'):
132 if not repo.url().startswith('file:'):
131 raise error.Abort(_("cannot verify bundle or remote repos"))
133 raise error.Abort(_("cannot verify bundle or remote repos"))
132
134
133 if os.path.exists(repo.sjoin("journal")):
135 if os.path.exists(repo.sjoin("journal")):
134 ui.warn(_("abandoned transaction found - run hg recover\n"))
136 ui.warn(_("abandoned transaction found - run hg recover\n"))
135
137
136 if ui.verbose or not self.revlogv1:
138 if ui.verbose or not self.revlogv1:
137 ui.status(_("repository uses revlog format %d\n") %
139 ui.status(_("repository uses revlog format %d\n") %
138 (self.revlogv1 and 1 or 0))
140 (self.revlogv1 and 1 or 0))
139
141
140 mflinkrevs, filelinkrevs = self._verifychangelog()
142 mflinkrevs, filelinkrevs = self._verifychangelog()
141
143
142 filenodes = self._verifymanifest(mflinkrevs)
144 filenodes = self._verifymanifest(mflinkrevs)
143 del mflinkrevs
145 del mflinkrevs
144
146
145 self._crosscheckfiles(filelinkrevs, filenodes)
147 self._crosscheckfiles(filelinkrevs, filenodes)
146
148
147 totalfiles, filerevisions = self._verifyfiles(filenodes, filelinkrevs)
149 totalfiles, filerevisions = self._verifyfiles(filenodes, filelinkrevs)
148
150
149 ui.status(_("%d files, %d changesets, %d total revisions\n") %
151 ui.status(_("%d files, %d changesets, %d total revisions\n") %
150 (totalfiles, len(repo.changelog), filerevisions))
152 (totalfiles, len(repo.changelog), filerevisions))
151 if self.warnings:
153 if self.warnings:
152 ui.warn(_("%d warnings encountered!\n") % self.warnings)
154 ui.warn(_("%d warnings encountered!\n") % self.warnings)
153 if self.fncachewarned:
155 if self.fncachewarned:
154 ui.warn(_('hint: run "hg debugrebuildfncache" to recover from '
156 ui.warn(_('hint: run "hg debugrebuildfncache" to recover from '
155 'corrupt fncache\n'))
157 'corrupt fncache\n'))
156 if self.errors:
158 if self.errors:
157 ui.warn(_("%d integrity errors encountered!\n") % self.errors)
159 ui.warn(_("%d integrity errors encountered!\n") % self.errors)
158 if self.badrevs:
160 if self.badrevs:
159 ui.warn(_("(first damaged changeset appears to be %d)\n")
161 ui.warn(_("(first damaged changeset appears to be %d)\n")
160 % min(self.badrevs))
162 % min(self.badrevs))
161 return 1
163 return 1
162
164
163 def _verifychangelog(self):
165 def _verifychangelog(self):
164 ui = self.ui
166 ui = self.ui
165 repo = self.repo
167 repo = self.repo
166 match = self.match
168 match = self.match
167 cl = repo.changelog
169 cl = repo.changelog
168
170
169 ui.status(_("checking changesets\n"))
171 ui.status(_("checking changesets\n"))
170 mflinkrevs = {}
172 mflinkrevs = {}
171 filelinkrevs = {}
173 filelinkrevs = {}
172 seen = {}
174 seen = {}
173 self.checklog(cl, "changelog", 0)
175 self.checklog(cl, "changelog", 0)
174 total = len(repo)
176 total = len(repo)
175 for i in repo:
177 for i in repo:
176 ui.progress(_('checking'), i, total=total, unit=_('changesets'))
178 ui.progress(_('checking'), i, total=total, unit=_('changesets'))
177 n = cl.node(i)
179 n = cl.node(i)
178 self.checkentry(cl, i, n, seen, [i], "changelog")
180 self.checkentry(cl, i, n, seen, [i], "changelog")
179
181
180 try:
182 try:
181 changes = cl.read(n)
183 changes = cl.read(n)
182 if changes[0] != nullid:
184 if changes[0] != nullid:
183 mflinkrevs.setdefault(changes[0], []).append(i)
185 mflinkrevs.setdefault(changes[0], []).append(i)
184 self.refersmf = True
186 self.refersmf = True
185 for f in changes[3]:
187 for f in changes[3]:
186 if match(f):
188 if match(f):
187 filelinkrevs.setdefault(_normpath(f), []).append(i)
189 filelinkrevs.setdefault(_normpath(f), []).append(i)
188 except Exception as inst:
190 except Exception as inst:
189 self.refersmf = True
191 self.refersmf = True
190 self.exc(i, _("unpacking changeset %s") % short(n), inst)
192 self.exc(i, _("unpacking changeset %s") % short(n), inst)
191 ui.progress(_('checking'), None)
193 ui.progress(_('checking'), None)
192 return mflinkrevs, filelinkrevs
194 return mflinkrevs, filelinkrevs
193
195
194 def _verifymanifest(self, mflinkrevs, dir="", storefiles=None,
196 def _verifymanifest(self, mflinkrevs, dir="", storefiles=None,
195 progress=None):
197 progress=None):
196 repo = self.repo
198 repo = self.repo
197 ui = self.ui
199 ui = self.ui
198 match = self.match
200 match = self.match
199 mfl = self.repo.manifestlog
201 mfl = self.repo.manifestlog
200 mf = mfl._revlog.dirlog(dir)
202 mf = mfl._revlog.dirlog(dir)
201
203
202 if not dir:
204 if not dir:
203 self.ui.status(_("checking manifests\n"))
205 self.ui.status(_("checking manifests\n"))
204
206
205 filenodes = {}
207 filenodes = {}
206 subdirnodes = {}
208 subdirnodes = {}
207 seen = {}
209 seen = {}
208 label = "manifest"
210 label = "manifest"
209 if dir:
211 if dir:
210 label = dir
212 label = dir
211 revlogfiles = mf.files()
213 revlogfiles = mf.files()
212 storefiles.difference_update(revlogfiles)
214 storefiles.difference_update(revlogfiles)
213 if progress: # should be true since we're in a subdirectory
215 if progress: # should be true since we're in a subdirectory
214 progress()
216 progress()
215 if self.refersmf:
217 if self.refersmf:
216 # Do not check manifest if there are only changelog entries with
218 # Do not check manifest if there are only changelog entries with
217 # null manifests.
219 # null manifests.
218 self.checklog(mf, label, 0)
220 self.checklog(mf, label, 0)
219 total = len(mf)
221 total = len(mf)
220 for i in mf:
222 for i in mf:
221 if not dir:
223 if not dir:
222 ui.progress(_('checking'), i, total=total, unit=_('manifests'))
224 ui.progress(_('checking'), i, total=total, unit=_('manifests'))
223 n = mf.node(i)
225 n = mf.node(i)
224 lr = self.checkentry(mf, i, n, seen, mflinkrevs.get(n, []), label)
226 lr = self.checkentry(mf, i, n, seen, mflinkrevs.get(n, []), label)
225 if n in mflinkrevs:
227 if n in mflinkrevs:
226 del mflinkrevs[n]
228 del mflinkrevs[n]
227 elif dir:
229 elif dir:
228 self.err(lr, _("%s not in parent-directory manifest") %
230 self.err(lr, _("%s not in parent-directory manifest") %
229 short(n), label)
231 short(n), label)
230 else:
232 else:
231 self.err(lr, _("%s not in changesets") % short(n), label)
233 self.err(lr, _("%s not in changesets") % short(n), label)
232
234
233 try:
235 try:
234 mfdelta = mfl.get(dir, n).readdelta(shallow=True)
236 mfdelta = mfl.get(dir, n).readdelta(shallow=True)
235 for f, fn, fl in mfdelta.iterentries():
237 for f, fn, fl in mfdelta.iterentries():
236 if not f:
238 if not f:
237 self.err(lr, _("entry without name in manifest"))
239 self.err(lr, _("entry without name in manifest"))
238 elif f == "/dev/null": # ignore this in very old repos
240 elif f == "/dev/null": # ignore this in very old repos
239 continue
241 continue
240 fullpath = dir + _normpath(f)
242 fullpath = dir + _normpath(f)
241 if fl == 't':
243 if fl == 't':
242 if not match.visitdir(fullpath):
244 if not match.visitdir(fullpath):
243 continue
245 continue
244 subdirnodes.setdefault(fullpath + '/', {}).setdefault(
246 subdirnodes.setdefault(fullpath + '/', {}).setdefault(
245 fn, []).append(lr)
247 fn, []).append(lr)
246 else:
248 else:
247 if not match(fullpath):
249 if not match(fullpath):
248 continue
250 continue
249 filenodes.setdefault(fullpath, {}).setdefault(fn, lr)
251 filenodes.setdefault(fullpath, {}).setdefault(fn, lr)
250 except Exception as inst:
252 except Exception as inst:
251 self.exc(lr, _("reading delta %s") % short(n), inst, label)
253 self.exc(lr, _("reading delta %s") % short(n), inst, label)
252 if not dir:
254 if not dir:
253 ui.progress(_('checking'), None)
255 ui.progress(_('checking'), None)
254
256
255 if self.havemf:
257 if self.havemf:
256 for c, m in sorted([(c, m) for m in mflinkrevs
258 for c, m in sorted([(c, m) for m in mflinkrevs
257 for c in mflinkrevs[m]]):
259 for c in mflinkrevs[m]]):
258 if dir:
260 if dir:
259 self.err(c, _("parent-directory manifest refers to unknown "
261 self.err(c, _("parent-directory manifest refers to unknown "
260 "revision %s") % short(m), label)
262 "revision %s") % short(m), label)
261 else:
263 else:
262 self.err(c, _("changeset refers to unknown revision %s") %
264 self.err(c, _("changeset refers to unknown revision %s") %
263 short(m), label)
265 short(m), label)
264
266
265 if not dir and subdirnodes:
267 if not dir and subdirnodes:
266 self.ui.status(_("checking directory manifests\n"))
268 self.ui.status(_("checking directory manifests\n"))
267 storefiles = set()
269 storefiles = set()
268 subdirs = set()
270 subdirs = set()
269 revlogv1 = self.revlogv1
271 revlogv1 = self.revlogv1
270 for f, f2, size in repo.store.datafiles():
272 for f, f2, size in repo.store.datafiles():
271 if not f:
273 if not f:
272 self.err(None, _("cannot decode filename '%s'") % f2)
274 self.err(None, _("cannot decode filename '%s'") % f2)
273 elif (size > 0 or not revlogv1) and f.startswith('meta/'):
275 elif (size > 0 or not revlogv1) and f.startswith('meta/'):
274 storefiles.add(_normpath(f))
276 storefiles.add(_normpath(f))
275 subdirs.add(os.path.dirname(f))
277 subdirs.add(os.path.dirname(f))
276 subdircount = len(subdirs)
278 subdircount = len(subdirs)
277 currentsubdir = [0]
279 currentsubdir = [0]
278 def progress():
280 def progress():
279 currentsubdir[0] += 1
281 currentsubdir[0] += 1
280 ui.progress(_('checking'), currentsubdir[0], total=subdircount,
282 ui.progress(_('checking'), currentsubdir[0], total=subdircount,
281 unit=_('manifests'))
283 unit=_('manifests'))
282
284
283 for subdir, linkrevs in subdirnodes.iteritems():
285 for subdir, linkrevs in subdirnodes.iteritems():
284 subdirfilenodes = self._verifymanifest(linkrevs, subdir, storefiles,
286 subdirfilenodes = self._verifymanifest(linkrevs, subdir, storefiles,
285 progress)
287 progress)
286 for f, onefilenodes in subdirfilenodes.iteritems():
288 for f, onefilenodes in subdirfilenodes.iteritems():
287 filenodes.setdefault(f, {}).update(onefilenodes)
289 filenodes.setdefault(f, {}).update(onefilenodes)
288
290
289 if not dir and subdirnodes:
291 if not dir and subdirnodes:
290 ui.progress(_('checking'), None)
292 ui.progress(_('checking'), None)
291 for f in sorted(storefiles):
293 for f in sorted(storefiles):
292 self.warn(_("warning: orphan revlog '%s'") % f)
294 self.warn(_("warning: orphan revlog '%s'") % f)
293
295
294 return filenodes
296 return filenodes
295
297
296 def _crosscheckfiles(self, filelinkrevs, filenodes):
298 def _crosscheckfiles(self, filelinkrevs, filenodes):
297 repo = self.repo
299 repo = self.repo
298 ui = self.ui
300 ui = self.ui
299 ui.status(_("crosschecking files in changesets and manifests\n"))
301 ui.status(_("crosschecking files in changesets and manifests\n"))
300
302
301 total = len(filelinkrevs) + len(filenodes)
303 total = len(filelinkrevs) + len(filenodes)
302 count = 0
304 count = 0
303 if self.havemf:
305 if self.havemf:
304 for f in sorted(filelinkrevs):
306 for f in sorted(filelinkrevs):
305 count += 1
307 count += 1
306 ui.progress(_('crosschecking'), count, total=total)
308 ui.progress(_('crosschecking'), count, total=total)
307 if f not in filenodes:
309 if f not in filenodes:
308 lr = filelinkrevs[f][0]
310 lr = filelinkrevs[f][0]
309 self.err(lr, _("in changeset but not in manifest"), f)
311 self.err(lr, _("in changeset but not in manifest"), f)
310
312
311 if self.havecl:
313 if self.havecl:
312 for f in sorted(filenodes):
314 for f in sorted(filenodes):
313 count += 1
315 count += 1
314 ui.progress(_('crosschecking'), count, total=total)
316 ui.progress(_('crosschecking'), count, total=total)
315 if f not in filelinkrevs:
317 if f not in filelinkrevs:
316 try:
318 try:
317 fl = repo.file(f)
319 fl = repo.file(f)
318 lr = min([fl.linkrev(fl.rev(n)) for n in filenodes[f]])
320 lr = min([fl.linkrev(fl.rev(n)) for n in filenodes[f]])
319 except Exception:
321 except Exception:
320 lr = None
322 lr = None
321 self.err(lr, _("in manifest but not in changeset"), f)
323 self.err(lr, _("in manifest but not in changeset"), f)
322
324
323 ui.progress(_('crosschecking'), None)
325 ui.progress(_('crosschecking'), None)
324
326
325 def _verifyfiles(self, filenodes, filelinkrevs):
327 def _verifyfiles(self, filenodes, filelinkrevs):
326 repo = self.repo
328 repo = self.repo
327 ui = self.ui
329 ui = self.ui
328 lrugetctx = self.lrugetctx
330 lrugetctx = self.lrugetctx
329 revlogv1 = self.revlogv1
331 revlogv1 = self.revlogv1
330 havemf = self.havemf
332 havemf = self.havemf
331 ui.status(_("checking files\n"))
333 ui.status(_("checking files\n"))
332
334
333 storefiles = set()
335 storefiles = set()
334 for f, f2, size in repo.store.datafiles():
336 for f, f2, size in repo.store.datafiles():
335 if not f:
337 if not f:
336 self.err(None, _("cannot decode filename '%s'") % f2)
338 self.err(None, _("cannot decode filename '%s'") % f2)
337 elif (size > 0 or not revlogv1) and f.startswith('data/'):
339 elif (size > 0 or not revlogv1) and f.startswith('data/'):
338 storefiles.add(_normpath(f))
340 storefiles.add(_normpath(f))
339
341
340 files = sorted(set(filenodes) | set(filelinkrevs))
342 files = sorted(set(filenodes) | set(filelinkrevs))
341 total = len(files)
343 total = len(files)
342 revisions = 0
344 revisions = 0
343 for i, f in enumerate(files):
345 for i, f in enumerate(files):
344 ui.progress(_('checking'), i, item=f, total=total, unit=_('files'))
346 ui.progress(_('checking'), i, item=f, total=total, unit=_('files'))
345 try:
347 try:
346 linkrevs = filelinkrevs[f]
348 linkrevs = filelinkrevs[f]
347 except KeyError:
349 except KeyError:
348 # in manifest but not in changelog
350 # in manifest but not in changelog
349 linkrevs = []
351 linkrevs = []
350
352
351 if linkrevs:
353 if linkrevs:
352 lr = linkrevs[0]
354 lr = linkrevs[0]
353 else:
355 else:
354 lr = None
356 lr = None
355
357
356 try:
358 try:
357 fl = repo.file(f)
359 fl = repo.file(f)
358 except error.RevlogError as e:
360 except error.RevlogError as e:
359 self.err(lr, _("broken revlog! (%s)") % e, f)
361 self.err(lr, _("broken revlog! (%s)") % e, f)
360 continue
362 continue
361
363
362 for ff in fl.files():
364 for ff in fl.files():
363 try:
365 try:
364 storefiles.remove(ff)
366 storefiles.remove(ff)
365 except KeyError:
367 except KeyError:
366 self.warn(_(" warning: revlog '%s' not in fncache!") % ff)
368 self.warn(_(" warning: revlog '%s' not in fncache!") % ff)
367 self.fncachewarned = True
369 self.fncachewarned = True
368
370
369 self.checklog(fl, f, lr)
371 self.checklog(fl, f, lr)
370 seen = {}
372 seen = {}
371 rp = None
373 rp = None
372 for i in fl:
374 for i in fl:
373 revisions += 1
375 revisions += 1
374 n = fl.node(i)
376 n = fl.node(i)
375 lr = self.checkentry(fl, i, n, seen, linkrevs, f)
377 lr = self.checkentry(fl, i, n, seen, linkrevs, f)
376 if f in filenodes:
378 if f in filenodes:
377 if havemf and n not in filenodes[f]:
379 if havemf and n not in filenodes[f]:
378 self.err(lr, _("%s not in manifests") % (short(n)), f)
380 self.err(lr, _("%s not in manifests") % (short(n)), f)
379 else:
381 else:
380 del filenodes[f][n]
382 del filenodes[f][n]
381
383
382 # Verify contents. 4 cases to care about:
384 # Verify contents. 4 cases to care about:
383 #
385 #
384 # common: the most common case
386 # common: the most common case
385 # rename: with a rename
387 # rename: with a rename
386 # meta: file content starts with b'\1\n', the metadata
388 # meta: file content starts with b'\1\n', the metadata
387 # header defined in filelog.py, but without a rename
389 # header defined in filelog.py, but without a rename
388 # ext: content stored externally
390 # ext: content stored externally
389 #
391 #
390 # More formally, their differences are shown below:
392 # More formally, their differences are shown below:
391 #
393 #
392 # | common | rename | meta | ext
394 # | common | rename | meta | ext
393 # -------------------------------------------------------
395 # -------------------------------------------------------
394 # flags() | 0 | 0 | 0 | not 0
396 # flags() | 0 | 0 | 0 | not 0
395 # renamed() | False | True | False | ?
397 # renamed() | False | True | False | ?
396 # rawtext[0:2]=='\1\n'| False | True | True | ?
398 # rawtext[0:2]=='\1\n'| False | True | True | ?
397 #
399 #
398 # "rawtext" means the raw text stored in revlog data, which
400 # "rawtext" means the raw text stored in revlog data, which
399 # could be retrieved by "revision(rev, raw=True)". "text"
401 # could be retrieved by "revision(rev, raw=True)". "text"
400 # mentioned below is "revision(rev, raw=False)".
402 # mentioned below is "revision(rev, raw=False)".
401 #
403 #
402 # There are 3 different lengths stored physically:
404 # There are 3 different lengths stored physically:
403 # 1. L1: rawsize, stored in revlog index
405 # 1. L1: rawsize, stored in revlog index
404 # 2. L2: len(rawtext), stored in revlog data
406 # 2. L2: len(rawtext), stored in revlog data
405 # 3. L3: len(text), stored in revlog data if flags==0, or
407 # 3. L3: len(text), stored in revlog data if flags==0, or
406 # possibly somewhere else if flags!=0
408 # possibly somewhere else if flags!=0
407 #
409 #
408 # L1 should be equal to L2. L3 could be different from them.
410 # L1 should be equal to L2. L3 could be different from them.
409 # "text" may or may not affect commit hash depending on flag
411 # "text" may or may not affect commit hash depending on flag
410 # processors (see revlog.addflagprocessor).
412 # processors (see revlog.addflagprocessor).
411 #
413 #
412 # | common | rename | meta | ext
414 # | common | rename | meta | ext
413 # -------------------------------------------------
415 # -------------------------------------------------
414 # rawsize() | L1 | L1 | L1 | L1
416 # rawsize() | L1 | L1 | L1 | L1
415 # size() | L1 | L2-LM | L1(*) | L1 (?)
417 # size() | L1 | L2-LM | L1(*) | L1 (?)
416 # len(rawtext) | L2 | L2 | L2 | L2
418 # len(rawtext) | L2 | L2 | L2 | L2
417 # len(text) | L2 | L2 | L2 | L3
419 # len(text) | L2 | L2 | L2 | L3
418 # len(read()) | L2 | L2-LM | L2-LM | L3 (?)
420 # len(read()) | L2 | L2-LM | L2-LM | L3 (?)
419 #
421 #
420 # LM: length of metadata, depending on rawtext
422 # LM: length of metadata, depending on rawtext
421 # (*): not ideal, see comment in filelog.size
423 # (*): not ideal, see comment in filelog.size
422 # (?): could be "- len(meta)" if the resolved content has
424 # (?): could be "- len(meta)" if the resolved content has
423 # rename metadata
425 # rename metadata
424 #
426 #
425 # Checks needed to be done:
427 # Checks needed to be done:
426 # 1. length check: L1 == L2, in all cases.
428 # 1. length check: L1 == L2, in all cases.
427 # 2. hash check: depending on flag processor, we may need to
429 # 2. hash check: depending on flag processor, we may need to
428 # use either "text" (external), or "rawtext" (in revlog).
430 # use either "text" (external), or "rawtext" (in revlog).
429 try:
431 try:
432 skipflags = self.skipflags
433 if skipflags:
434 skipflags &= fl.flags(i)
435 if not skipflags:
430 fl.read(n) # side effect: read content and do checkhash
436 fl.read(n) # side effect: read content and do checkhash
431 rp = fl.renamed(n)
437 rp = fl.renamed(n)
432 # the "L1 == L2" check
438 # the "L1 == L2" check
433 l1 = fl.rawsize(i)
439 l1 = fl.rawsize(i)
434 l2 = len(fl.revision(n, raw=True))
440 l2 = len(fl.revision(n, raw=True))
435 if l1 != l2:
441 if l1 != l2:
436 self.err(lr, _("unpacked size is %s, %s expected") %
442 self.err(lr, _("unpacked size is %s, %s expected") %
437 (l2, l1), f)
443 (l2, l1), f)
438 except error.CensoredNodeError:
444 except error.CensoredNodeError:
439 # experimental config: censor.policy
445 # experimental config: censor.policy
440 if ui.config("censor", "policy", "abort") == "abort":
446 if ui.config("censor", "policy", "abort") == "abort":
441 self.err(lr, _("censored file data"), f)
447 self.err(lr, _("censored file data"), f)
442 except Exception as inst:
448 except Exception as inst:
443 self.exc(lr, _("unpacking %s") % short(n), inst, f)
449 self.exc(lr, _("unpacking %s") % short(n), inst, f)
444
450
445 # check renames
451 # check renames
446 try:
452 try:
447 if rp:
453 if rp:
448 if lr is not None and ui.verbose:
454 if lr is not None and ui.verbose:
449 ctx = lrugetctx(lr)
455 ctx = lrugetctx(lr)
450 found = False
456 found = False
451 for pctx in ctx.parents():
457 for pctx in ctx.parents():
452 if rp[0] in pctx:
458 if rp[0] in pctx:
453 found = True
459 found = True
454 break
460 break
455 if not found:
461 if not found:
456 self.warn(_("warning: copy source of '%s' not"
462 self.warn(_("warning: copy source of '%s' not"
457 " in parents of %s") % (f, ctx))
463 " in parents of %s") % (f, ctx))
458 fl2 = repo.file(rp[0])
464 fl2 = repo.file(rp[0])
459 if not len(fl2):
465 if not len(fl2):
460 self.err(lr, _("empty or missing copy source "
466 self.err(lr, _("empty or missing copy source "
461 "revlog %s:%s") % (rp[0], short(rp[1])), f)
467 "revlog %s:%s") % (rp[0], short(rp[1])), f)
462 elif rp[1] == nullid:
468 elif rp[1] == nullid:
463 ui.note(_("warning: %s@%s: copy source"
469 ui.note(_("warning: %s@%s: copy source"
464 " revision is nullid %s:%s\n")
470 " revision is nullid %s:%s\n")
465 % (f, lr, rp[0], short(rp[1])))
471 % (f, lr, rp[0], short(rp[1])))
466 else:
472 else:
467 fl2.rev(rp[1])
473 fl2.rev(rp[1])
468 except Exception as inst:
474 except Exception as inst:
469 self.exc(lr, _("checking rename of %s") % short(n), inst, f)
475 self.exc(lr, _("checking rename of %s") % short(n), inst, f)
470
476
471 # cross-check
477 # cross-check
472 if f in filenodes:
478 if f in filenodes:
473 fns = [(v, k) for k, v in filenodes[f].iteritems()]
479 fns = [(v, k) for k, v in filenodes[f].iteritems()]
474 for lr, node in sorted(fns):
480 for lr, node in sorted(fns):
475 self.err(lr, _("manifest refers to unknown revision %s") %
481 self.err(lr, _("manifest refers to unknown revision %s") %
476 short(node), f)
482 short(node), f)
477 ui.progress(_('checking'), None)
483 ui.progress(_('checking'), None)
478
484
479 for f in sorted(storefiles):
485 for f in sorted(storefiles):
480 self.warn(_("warning: orphan revlog '%s'") % f)
486 self.warn(_("warning: orphan revlog '%s'") % f)
481
487
482 return len(files), revisions
488 return len(files), revisions
@@ -1,319 +1,363
1 prepare repo
1 prepare repo
2
2
3 $ hg init a
3 $ hg init a
4 $ cd a
4 $ cd a
5 $ echo "some text" > FOO.txt
5 $ echo "some text" > FOO.txt
6 $ echo "another text" > bar.txt
6 $ echo "another text" > bar.txt
7 $ echo "more text" > QUICK.txt
7 $ echo "more text" > QUICK.txt
8 $ hg add
8 $ hg add
9 adding FOO.txt
9 adding FOO.txt
10 adding QUICK.txt
10 adding QUICK.txt
11 adding bar.txt
11 adding bar.txt
12 $ hg ci -mtest1
12 $ hg ci -mtest1
13
13
14 verify
14 verify
15
15
16 $ hg verify
16 $ hg verify
17 checking changesets
17 checking changesets
18 checking manifests
18 checking manifests
19 crosschecking files in changesets and manifests
19 crosschecking files in changesets and manifests
20 checking files
20 checking files
21 3 files, 1 changesets, 3 total revisions
21 3 files, 1 changesets, 3 total revisions
22
22
23 verify with journal
23 verify with journal
24
24
25 $ touch .hg/store/journal
25 $ touch .hg/store/journal
26 $ hg verify
26 $ hg verify
27 abandoned transaction found - run hg recover
27 abandoned transaction found - run hg recover
28 checking changesets
28 checking changesets
29 checking manifests
29 checking manifests
30 crosschecking files in changesets and manifests
30 crosschecking files in changesets and manifests
31 checking files
31 checking files
32 3 files, 1 changesets, 3 total revisions
32 3 files, 1 changesets, 3 total revisions
33 $ rm .hg/store/journal
33 $ rm .hg/store/journal
34
34
35 introduce some bugs in repo
35 introduce some bugs in repo
36
36
37 $ cd .hg/store/data
37 $ cd .hg/store/data
38 $ mv _f_o_o.txt.i X_f_o_o.txt.i
38 $ mv _f_o_o.txt.i X_f_o_o.txt.i
39 $ mv bar.txt.i xbar.txt.i
39 $ mv bar.txt.i xbar.txt.i
40 $ rm _q_u_i_c_k.txt.i
40 $ rm _q_u_i_c_k.txt.i
41
41
42 $ hg verify
42 $ hg verify
43 checking changesets
43 checking changesets
44 checking manifests
44 checking manifests
45 crosschecking files in changesets and manifests
45 crosschecking files in changesets and manifests
46 checking files
46 checking files
47 warning: revlog 'data/FOO.txt.i' not in fncache!
47 warning: revlog 'data/FOO.txt.i' not in fncache!
48 0: empty or missing FOO.txt
48 0: empty or missing FOO.txt
49 FOO.txt@0: manifest refers to unknown revision f62022d3d590
49 FOO.txt@0: manifest refers to unknown revision f62022d3d590
50 warning: revlog 'data/QUICK.txt.i' not in fncache!
50 warning: revlog 'data/QUICK.txt.i' not in fncache!
51 0: empty or missing QUICK.txt
51 0: empty or missing QUICK.txt
52 QUICK.txt@0: manifest refers to unknown revision 88b857db8eba
52 QUICK.txt@0: manifest refers to unknown revision 88b857db8eba
53 warning: revlog 'data/bar.txt.i' not in fncache!
53 warning: revlog 'data/bar.txt.i' not in fncache!
54 0: empty or missing bar.txt
54 0: empty or missing bar.txt
55 bar.txt@0: manifest refers to unknown revision 256559129457
55 bar.txt@0: manifest refers to unknown revision 256559129457
56 3 files, 1 changesets, 0 total revisions
56 3 files, 1 changesets, 0 total revisions
57 3 warnings encountered!
57 3 warnings encountered!
58 hint: run "hg debugrebuildfncache" to recover from corrupt fncache
58 hint: run "hg debugrebuildfncache" to recover from corrupt fncache
59 6 integrity errors encountered!
59 6 integrity errors encountered!
60 (first damaged changeset appears to be 0)
60 (first damaged changeset appears to be 0)
61 [1]
61 [1]
62
62
63 $ cd ../../..
63 $ cd ../../..
64 $ cd ..
64 $ cd ..
65
65
66 Set up a repo for testing missing revlog entries
66 Set up a repo for testing missing revlog entries
67
67
68 $ hg init missing-entries
68 $ hg init missing-entries
69 $ cd missing-entries
69 $ cd missing-entries
70 $ echo 0 > file
70 $ echo 0 > file
71 $ hg ci -Aqm0
71 $ hg ci -Aqm0
72 $ cp -R .hg/store .hg/store-partial
72 $ cp -R .hg/store .hg/store-partial
73 $ echo 1 > file
73 $ echo 1 > file
74 $ hg ci -Aqm1
74 $ hg ci -Aqm1
75 $ cp -R .hg/store .hg/store-full
75 $ cp -R .hg/store .hg/store-full
76
76
77 Entire changelog missing
77 Entire changelog missing
78
78
79 $ rm .hg/store/00changelog.*
79 $ rm .hg/store/00changelog.*
80 $ hg verify -q
80 $ hg verify -q
81 0: empty or missing changelog
81 0: empty or missing changelog
82 manifest@0: d0b6632564d4 not in changesets
82 manifest@0: d0b6632564d4 not in changesets
83 manifest@1: 941fc4534185 not in changesets
83 manifest@1: 941fc4534185 not in changesets
84 3 integrity errors encountered!
84 3 integrity errors encountered!
85 (first damaged changeset appears to be 0)
85 (first damaged changeset appears to be 0)
86 [1]
86 [1]
87 $ cp -R .hg/store-full/. .hg/store
87 $ cp -R .hg/store-full/. .hg/store
88
88
89 Entire manifest log missing
89 Entire manifest log missing
90
90
91 $ rm .hg/store/00manifest.*
91 $ rm .hg/store/00manifest.*
92 $ hg verify -q
92 $ hg verify -q
93 0: empty or missing manifest
93 0: empty or missing manifest
94 1 integrity errors encountered!
94 1 integrity errors encountered!
95 (first damaged changeset appears to be 0)
95 (first damaged changeset appears to be 0)
96 [1]
96 [1]
97 $ cp -R .hg/store-full/. .hg/store
97 $ cp -R .hg/store-full/. .hg/store
98
98
99 Entire filelog missing
99 Entire filelog missing
100
100
101 $ rm .hg/store/data/file.*
101 $ rm .hg/store/data/file.*
102 $ hg verify -q
102 $ hg verify -q
103 warning: revlog 'data/file.i' not in fncache!
103 warning: revlog 'data/file.i' not in fncache!
104 0: empty or missing file
104 0: empty or missing file
105 file@0: manifest refers to unknown revision 362fef284ce2
105 file@0: manifest refers to unknown revision 362fef284ce2
106 file@1: manifest refers to unknown revision c10f2164107d
106 file@1: manifest refers to unknown revision c10f2164107d
107 1 warnings encountered!
107 1 warnings encountered!
108 hint: run "hg debugrebuildfncache" to recover from corrupt fncache
108 hint: run "hg debugrebuildfncache" to recover from corrupt fncache
109 3 integrity errors encountered!
109 3 integrity errors encountered!
110 (first damaged changeset appears to be 0)
110 (first damaged changeset appears to be 0)
111 [1]
111 [1]
112 $ cp -R .hg/store-full/. .hg/store
112 $ cp -R .hg/store-full/. .hg/store
113
113
114 Entire changelog and manifest log missing
114 Entire changelog and manifest log missing
115
115
116 $ rm .hg/store/00changelog.*
116 $ rm .hg/store/00changelog.*
117 $ rm .hg/store/00manifest.*
117 $ rm .hg/store/00manifest.*
118 $ hg verify -q
118 $ hg verify -q
119 warning: orphan revlog 'data/file.i'
119 warning: orphan revlog 'data/file.i'
120 1 warnings encountered!
120 1 warnings encountered!
121 $ cp -R .hg/store-full/. .hg/store
121 $ cp -R .hg/store-full/. .hg/store
122
122
123 Entire changelog and filelog missing
123 Entire changelog and filelog missing
124
124
125 $ rm .hg/store/00changelog.*
125 $ rm .hg/store/00changelog.*
126 $ rm .hg/store/data/file.*
126 $ rm .hg/store/data/file.*
127 $ hg verify -q
127 $ hg verify -q
128 0: empty or missing changelog
128 0: empty or missing changelog
129 manifest@0: d0b6632564d4 not in changesets
129 manifest@0: d0b6632564d4 not in changesets
130 manifest@1: 941fc4534185 not in changesets
130 manifest@1: 941fc4534185 not in changesets
131 warning: revlog 'data/file.i' not in fncache!
131 warning: revlog 'data/file.i' not in fncache!
132 ?: empty or missing file
132 ?: empty or missing file
133 file@0: manifest refers to unknown revision 362fef284ce2
133 file@0: manifest refers to unknown revision 362fef284ce2
134 file@1: manifest refers to unknown revision c10f2164107d
134 file@1: manifest refers to unknown revision c10f2164107d
135 1 warnings encountered!
135 1 warnings encountered!
136 hint: run "hg debugrebuildfncache" to recover from corrupt fncache
136 hint: run "hg debugrebuildfncache" to recover from corrupt fncache
137 6 integrity errors encountered!
137 6 integrity errors encountered!
138 (first damaged changeset appears to be 0)
138 (first damaged changeset appears to be 0)
139 [1]
139 [1]
140 $ cp -R .hg/store-full/. .hg/store
140 $ cp -R .hg/store-full/. .hg/store
141
141
142 Entire manifest log and filelog missing
142 Entire manifest log and filelog missing
143
143
144 $ rm .hg/store/00manifest.*
144 $ rm .hg/store/00manifest.*
145 $ rm .hg/store/data/file.*
145 $ rm .hg/store/data/file.*
146 $ hg verify -q
146 $ hg verify -q
147 0: empty or missing manifest
147 0: empty or missing manifest
148 warning: revlog 'data/file.i' not in fncache!
148 warning: revlog 'data/file.i' not in fncache!
149 0: empty or missing file
149 0: empty or missing file
150 1 warnings encountered!
150 1 warnings encountered!
151 hint: run "hg debugrebuildfncache" to recover from corrupt fncache
151 hint: run "hg debugrebuildfncache" to recover from corrupt fncache
152 2 integrity errors encountered!
152 2 integrity errors encountered!
153 (first damaged changeset appears to be 0)
153 (first damaged changeset appears to be 0)
154 [1]
154 [1]
155 $ cp -R .hg/store-full/. .hg/store
155 $ cp -R .hg/store-full/. .hg/store
156
156
157 Changelog missing entry
157 Changelog missing entry
158
158
159 $ cp -f .hg/store-partial/00changelog.* .hg/store
159 $ cp -f .hg/store-partial/00changelog.* .hg/store
160 $ hg verify -q
160 $ hg verify -q
161 manifest@?: rev 1 points to nonexistent changeset 1
161 manifest@?: rev 1 points to nonexistent changeset 1
162 manifest@?: 941fc4534185 not in changesets
162 manifest@?: 941fc4534185 not in changesets
163 file@?: rev 1 points to nonexistent changeset 1
163 file@?: rev 1 points to nonexistent changeset 1
164 (expected 0)
164 (expected 0)
165 1 warnings encountered!
165 1 warnings encountered!
166 3 integrity errors encountered!
166 3 integrity errors encountered!
167 [1]
167 [1]
168 $ cp -R .hg/store-full/. .hg/store
168 $ cp -R .hg/store-full/. .hg/store
169
169
170 Manifest log missing entry
170 Manifest log missing entry
171
171
172 $ cp -f .hg/store-partial/00manifest.* .hg/store
172 $ cp -f .hg/store-partial/00manifest.* .hg/store
173 $ hg verify -q
173 $ hg verify -q
174 manifest@1: changeset refers to unknown revision 941fc4534185
174 manifest@1: changeset refers to unknown revision 941fc4534185
175 file@1: c10f2164107d not in manifests
175 file@1: c10f2164107d not in manifests
176 2 integrity errors encountered!
176 2 integrity errors encountered!
177 (first damaged changeset appears to be 1)
177 (first damaged changeset appears to be 1)
178 [1]
178 [1]
179 $ cp -R .hg/store-full/. .hg/store
179 $ cp -R .hg/store-full/. .hg/store
180
180
181 Filelog missing entry
181 Filelog missing entry
182
182
183 $ cp -f .hg/store-partial/data/file.* .hg/store/data
183 $ cp -f .hg/store-partial/data/file.* .hg/store/data
184 $ hg verify -q
184 $ hg verify -q
185 file@1: manifest refers to unknown revision c10f2164107d
185 file@1: manifest refers to unknown revision c10f2164107d
186 1 integrity errors encountered!
186 1 integrity errors encountered!
187 (first damaged changeset appears to be 1)
187 (first damaged changeset appears to be 1)
188 [1]
188 [1]
189 $ cp -R .hg/store-full/. .hg/store
189 $ cp -R .hg/store-full/. .hg/store
190
190
191 Changelog and manifest log missing entry
191 Changelog and manifest log missing entry
192
192
193 $ cp -f .hg/store-partial/00changelog.* .hg/store
193 $ cp -f .hg/store-partial/00changelog.* .hg/store
194 $ cp -f .hg/store-partial/00manifest.* .hg/store
194 $ cp -f .hg/store-partial/00manifest.* .hg/store
195 $ hg verify -q
195 $ hg verify -q
196 file@?: rev 1 points to nonexistent changeset 1
196 file@?: rev 1 points to nonexistent changeset 1
197 (expected 0)
197 (expected 0)
198 file@?: c10f2164107d not in manifests
198 file@?: c10f2164107d not in manifests
199 1 warnings encountered!
199 1 warnings encountered!
200 2 integrity errors encountered!
200 2 integrity errors encountered!
201 [1]
201 [1]
202 $ cp -R .hg/store-full/. .hg/store
202 $ cp -R .hg/store-full/. .hg/store
203
203
204 Changelog and filelog missing entry
204 Changelog and filelog missing entry
205
205
206 $ cp -f .hg/store-partial/00changelog.* .hg/store
206 $ cp -f .hg/store-partial/00changelog.* .hg/store
207 $ cp -f .hg/store-partial/data/file.* .hg/store/data
207 $ cp -f .hg/store-partial/data/file.* .hg/store/data
208 $ hg verify -q
208 $ hg verify -q
209 manifest@?: rev 1 points to nonexistent changeset 1
209 manifest@?: rev 1 points to nonexistent changeset 1
210 manifest@?: 941fc4534185 not in changesets
210 manifest@?: 941fc4534185 not in changesets
211 file@?: manifest refers to unknown revision c10f2164107d
211 file@?: manifest refers to unknown revision c10f2164107d
212 3 integrity errors encountered!
212 3 integrity errors encountered!
213 [1]
213 [1]
214 $ cp -R .hg/store-full/. .hg/store
214 $ cp -R .hg/store-full/. .hg/store
215
215
216 Manifest and filelog missing entry
216 Manifest and filelog missing entry
217
217
218 $ cp -f .hg/store-partial/00manifest.* .hg/store
218 $ cp -f .hg/store-partial/00manifest.* .hg/store
219 $ cp -f .hg/store-partial/data/file.* .hg/store/data
219 $ cp -f .hg/store-partial/data/file.* .hg/store/data
220 $ hg verify -q
220 $ hg verify -q
221 manifest@1: changeset refers to unknown revision 941fc4534185
221 manifest@1: changeset refers to unknown revision 941fc4534185
222 1 integrity errors encountered!
222 1 integrity errors encountered!
223 (first damaged changeset appears to be 1)
223 (first damaged changeset appears to be 1)
224 [1]
224 [1]
225 $ cp -R .hg/store-full/. .hg/store
225 $ cp -R .hg/store-full/. .hg/store
226
226
227 Corrupt changelog base node to cause failure to read revision
227 Corrupt changelog base node to cause failure to read revision
228
228
229 $ printf abcd | dd conv=notrunc of=.hg/store/00changelog.i bs=1 seek=16 \
229 $ printf abcd | dd conv=notrunc of=.hg/store/00changelog.i bs=1 seek=16 \
230 > 2> /dev/null
230 > 2> /dev/null
231 $ hg verify -q
231 $ hg verify -q
232 0: unpacking changeset 08b1860757c2: * (glob)
232 0: unpacking changeset 08b1860757c2: * (glob)
233 manifest@?: rev 0 points to unexpected changeset 0
233 manifest@?: rev 0 points to unexpected changeset 0
234 manifest@?: d0b6632564d4 not in changesets
234 manifest@?: d0b6632564d4 not in changesets
235 file@?: rev 0 points to unexpected changeset 0
235 file@?: rev 0 points to unexpected changeset 0
236 (expected 1)
236 (expected 1)
237 1 warnings encountered!
237 1 warnings encountered!
238 4 integrity errors encountered!
238 4 integrity errors encountered!
239 (first damaged changeset appears to be 0)
239 (first damaged changeset appears to be 0)
240 [1]
240 [1]
241 $ cp -R .hg/store-full/. .hg/store
241 $ cp -R .hg/store-full/. .hg/store
242
242
243 Corrupt manifest log base node to cause failure to read revision
243 Corrupt manifest log base node to cause failure to read revision
244
244
245 $ printf abcd | dd conv=notrunc of=.hg/store/00manifest.i bs=1 seek=16 \
245 $ printf abcd | dd conv=notrunc of=.hg/store/00manifest.i bs=1 seek=16 \
246 > 2> /dev/null
246 > 2> /dev/null
247 $ hg verify -q
247 $ hg verify -q
248 manifest@0: reading delta d0b6632564d4: * (glob)
248 manifest@0: reading delta d0b6632564d4: * (glob)
249 file@0: 362fef284ce2 not in manifests
249 file@0: 362fef284ce2 not in manifests
250 2 integrity errors encountered!
250 2 integrity errors encountered!
251 (first damaged changeset appears to be 0)
251 (first damaged changeset appears to be 0)
252 [1]
252 [1]
253 $ cp -R .hg/store-full/. .hg/store
253 $ cp -R .hg/store-full/. .hg/store
254
254
255 Corrupt filelog base node to cause failure to read revision
255 Corrupt filelog base node to cause failure to read revision
256
256
257 $ printf abcd | dd conv=notrunc of=.hg/store/data/file.i bs=1 seek=16 \
257 $ printf abcd | dd conv=notrunc of=.hg/store/data/file.i bs=1 seek=16 \
258 > 2> /dev/null
258 > 2> /dev/null
259 $ hg verify -q
259 $ hg verify -q
260 file@0: unpacking 362fef284ce2: * (glob)
260 file@0: unpacking 362fef284ce2: * (glob)
261 1 integrity errors encountered!
261 1 integrity errors encountered!
262 (first damaged changeset appears to be 0)
262 (first damaged changeset appears to be 0)
263 [1]
263 [1]
264 $ cp -R .hg/store-full/. .hg/store
264 $ cp -R .hg/store-full/. .hg/store
265
265
266 $ cd ..
266 $ cd ..
267
267
268 test changelog without a manifest
268 test changelog without a manifest
269
269
270 $ hg init b
270 $ hg init b
271 $ cd b
271 $ cd b
272 $ hg branch foo
272 $ hg branch foo
273 marked working directory as branch foo
273 marked working directory as branch foo
274 (branches are permanent and global, did you want a bookmark?)
274 (branches are permanent and global, did you want a bookmark?)
275 $ hg ci -m branchfoo
275 $ hg ci -m branchfoo
276 $ hg verify
276 $ hg verify
277 checking changesets
277 checking changesets
278 checking manifests
278 checking manifests
279 crosschecking files in changesets and manifests
279 crosschecking files in changesets and manifests
280 checking files
280 checking files
281 0 files, 1 changesets, 0 total revisions
281 0 files, 1 changesets, 0 total revisions
282
282
283 test revlog corruption
283 test revlog corruption
284
284
285 $ touch a
285 $ touch a
286 $ hg add a
286 $ hg add a
287 $ hg ci -m a
287 $ hg ci -m a
288
288
289 $ echo 'corrupted' > b
289 $ echo 'corrupted' > b
290 $ dd if=.hg/store/data/a.i of=start bs=1 count=20 2>/dev/null
290 $ dd if=.hg/store/data/a.i of=start bs=1 count=20 2>/dev/null
291 $ cat start b > .hg/store/data/a.i
291 $ cat start b > .hg/store/data/a.i
292
292
293 $ hg verify
293 $ hg verify
294 checking changesets
294 checking changesets
295 checking manifests
295 checking manifests
296 crosschecking files in changesets and manifests
296 crosschecking files in changesets and manifests
297 checking files
297 checking files
298 a@1: broken revlog! (index data/a.i is corrupted)
298 a@1: broken revlog! (index data/a.i is corrupted)
299 warning: orphan revlog 'data/a.i'
299 warning: orphan revlog 'data/a.i'
300 1 files, 2 changesets, 0 total revisions
300 1 files, 2 changesets, 0 total revisions
301 1 warnings encountered!
301 1 warnings encountered!
302 1 integrity errors encountered!
302 1 integrity errors encountered!
303 (first damaged changeset appears to be 1)
303 (first damaged changeset appears to be 1)
304 [1]
304 [1]
305
305
306 $ cd ..
306 $ cd ..
307
307
308 test revlog format 0
308 test revlog format 0
309
309
310 $ revlog-formatv0.py
310 $ revlog-formatv0.py
311 $ cd formatv0
311 $ cd formatv0
312 $ hg verify
312 $ hg verify
313 repository uses revlog format 0
313 repository uses revlog format 0
314 checking changesets
314 checking changesets
315 checking manifests
315 checking manifests
316 crosschecking files in changesets and manifests
316 crosschecking files in changesets and manifests
317 checking files
317 checking files
318 1 files, 1 changesets, 1 total revisions
318 1 files, 1 changesets, 1 total revisions
319 $ cd ..
319 $ cd ..
320
321 test flag processor and skipflags
322
323 $ hg init skipflags
324 $ cd skipflags
325 $ cat >> .hg/hgrc <<EOF
326 > [extensions]
327 > flagprocesor=$RUNTESTDIR/flagprocessorext.py
328 > EOF
329 $ echo '[BASE64]content' > base64
330 $ hg commit -Aqm 'flag processor content' base64
331 $ hg verify
332 checking changesets
333 checking manifests
334 crosschecking files in changesets and manifests
335 checking files
336 1 files, 1 changesets, 1 total revisions
337
338 $ cat >> $TESTTMP/break-base64.py <<EOF
339 > from __future__ import absolute_import
340 > import base64
341 > base64.b64decode=lambda x: x
342 > EOF
343 $ cat >> .hg/hgrc <<EOF
344 > breakbase64=$TESTTMP/break-base64.py
345 > EOF
346
347 $ hg verify
348 checking changesets
349 checking manifests
350 crosschecking files in changesets and manifests
351 checking files
352 base64@0: unpacking 794cee7777cb: integrity check failed on data/base64.i:0
353 1 files, 1 changesets, 1 total revisions
354 1 integrity errors encountered!
355 (first damaged changeset appears to be 0)
356 [1]
357 $ hg verify --config verify.skipflags=2147483647
358 checking changesets
359 checking manifests
360 crosschecking files in changesets and manifests
361 checking files
362 1 files, 1 changesets, 1 total revisions
363
General Comments 0
You need to be logged in to leave comments. Login now