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