##// END OF EJS Templates
verify: include "manifest" prefix in a few more places...
Martin von Zweigbergk -
r28113:d2e0d578 default
parent child Browse files
Show More
@@ -1,381 +1,381 b''
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 util,
21 util,
22 )
22 )
23
23
24 def verify(repo):
24 def verify(repo):
25 with repo.lock():
25 with repo.lock():
26 return verifier(repo).verify()
26 return verifier(repo).verify()
27
27
28 def _normpath(f):
28 def _normpath(f):
29 # under hg < 2.4, convert didn't sanitize paths properly, so a
29 # under hg < 2.4, convert didn't sanitize paths properly, so a
30 # converted repo may contain repeated slashes
30 # converted repo may contain repeated slashes
31 while '//' in f:
31 while '//' in f:
32 f = f.replace('//', '/')
32 f = f.replace('//', '/')
33 return f
33 return f
34
34
35 def _validpath(repo, path):
35 def _validpath(repo, path):
36 """Returns False if a path should NOT be treated as part of a repo.
36 """Returns False if a path should NOT be treated as part of a repo.
37
37
38 For all in-core cases, this returns True, as we have no way for a
38 For all in-core cases, this returns True, as we have no way for a
39 path to be mentioned in the history but not actually be
39 path to be mentioned in the history but not actually be
40 relevant. For narrow clones, this is important because many
40 relevant. For narrow clones, this is important because many
41 filelogs will be missing, and changelog entries may mention
41 filelogs will be missing, and changelog entries may mention
42 modified files that are outside the narrow scope.
42 modified files that are outside the narrow scope.
43 """
43 """
44 return True
44 return True
45
45
46 class verifier(object):
46 class verifier(object):
47 def __init__(self, repo):
47 def __init__(self, repo):
48 self.repo = repo.unfiltered()
48 self.repo = repo.unfiltered()
49 self.ui = repo.ui
49 self.ui = repo.ui
50 self.badrevs = set()
50 self.badrevs = set()
51 self.errors = 0
51 self.errors = 0
52 self.warnings = 0
52 self.warnings = 0
53 self.havecl = len(repo.changelog) > 0
53 self.havecl = len(repo.changelog) > 0
54 self.havemf = len(repo.manifest) > 0
54 self.havemf = len(repo.manifest) > 0
55 self.revlogv1 = repo.changelog.version != revlog.REVLOGV0
55 self.revlogv1 = repo.changelog.version != revlog.REVLOGV0
56 self.lrugetctx = util.lrucachefunc(repo.changectx)
56 self.lrugetctx = util.lrucachefunc(repo.changectx)
57 self.refersmf = False
57 self.refersmf = False
58 self.fncachewarned = False
58 self.fncachewarned = False
59
59
60 def warn(self, msg):
60 def warn(self, msg):
61 self.ui.warn(msg + "\n")
61 self.ui.warn(msg + "\n")
62 self.warnings += 1
62 self.warnings += 1
63
63
64 def err(self, linkrev, msg, filename=None):
64 def err(self, linkrev, msg, filename=None):
65 if linkrev is not None:
65 if linkrev is not None:
66 self.badrevs.add(linkrev)
66 self.badrevs.add(linkrev)
67 else:
67 else:
68 linkrev = '?'
68 linkrev = '?'
69 msg = "%s: %s" % (linkrev, msg)
69 msg = "%s: %s" % (linkrev, msg)
70 if filename:
70 if filename:
71 msg = "%s@%s" % (filename, msg)
71 msg = "%s@%s" % (filename, msg)
72 self.ui.warn(" " + msg + "\n")
72 self.ui.warn(" " + msg + "\n")
73 self.errors += 1
73 self.errors += 1
74
74
75 def exc(self, linkrev, msg, inst, filename=None):
75 def exc(self, linkrev, msg, inst, filename=None):
76 if not str(inst):
76 if not str(inst):
77 inst = repr(inst)
77 inst = repr(inst)
78 self.err(linkrev, "%s: %s" % (msg, inst), filename)
78 self.err(linkrev, "%s: %s" % (msg, inst), filename)
79
79
80 def checklog(self, obj, name, linkrev):
80 def checklog(self, obj, name, linkrev):
81 if not len(obj) and (self.havecl or self.havemf):
81 if not len(obj) and (self.havecl or self.havemf):
82 self.err(linkrev, _("empty or missing %s") % name)
82 self.err(linkrev, _("empty or missing %s") % name)
83 return
83 return
84
84
85 d = obj.checksize()
85 d = obj.checksize()
86 if d[0]:
86 if d[0]:
87 self.err(None, _("data length off by %d bytes") % d[0], name)
87 self.err(None, _("data length off by %d bytes") % d[0], name)
88 if d[1]:
88 if d[1]:
89 self.err(None, _("index contains %d extra bytes") % d[1], name)
89 self.err(None, _("index contains %d extra bytes") % d[1], name)
90
90
91 if obj.version != revlog.REVLOGV0:
91 if obj.version != revlog.REVLOGV0:
92 if not self.revlogv1:
92 if not self.revlogv1:
93 self.warn(_("warning: `%s' uses revlog format 1") % name)
93 self.warn(_("warning: `%s' uses revlog format 1") % name)
94 elif self.revlogv1:
94 elif self.revlogv1:
95 self.warn(_("warning: `%s' uses revlog format 0") % name)
95 self.warn(_("warning: `%s' uses revlog format 0") % name)
96
96
97 def checkentry(self, obj, i, node, seen, linkrevs, f):
97 def checkentry(self, obj, i, node, seen, linkrevs, f):
98 lr = obj.linkrev(obj.rev(node))
98 lr = obj.linkrev(obj.rev(node))
99 if lr < 0 or (self.havecl and lr not in linkrevs):
99 if lr < 0 or (self.havecl and lr not in linkrevs):
100 if lr < 0 or lr >= len(self.repo.changelog):
100 if lr < 0 or lr >= len(self.repo.changelog):
101 msg = _("rev %d points to nonexistent changeset %d")
101 msg = _("rev %d points to nonexistent changeset %d")
102 else:
102 else:
103 msg = _("rev %d points to unexpected changeset %d")
103 msg = _("rev %d points to unexpected changeset %d")
104 self.err(None, msg % (i, lr), f)
104 self.err(None, msg % (i, lr), f)
105 if linkrevs:
105 if linkrevs:
106 if f and len(linkrevs) > 1:
106 if f and len(linkrevs) > 1:
107 try:
107 try:
108 # attempt to filter down to real linkrevs
108 # attempt to filter down to real linkrevs
109 linkrevs = [l for l in linkrevs
109 linkrevs = [l for l in linkrevs
110 if self.lrugetctx(l)[f].filenode() == node]
110 if self.lrugetctx(l)[f].filenode() == node]
111 except Exception:
111 except Exception:
112 pass
112 pass
113 self.warn(_(" (expected %s)") % " ".join(map(str, linkrevs)))
113 self.warn(_(" (expected %s)") % " ".join(map(str, linkrevs)))
114 lr = None # can't be trusted
114 lr = None # can't be trusted
115
115
116 try:
116 try:
117 p1, p2 = obj.parents(node)
117 p1, p2 = obj.parents(node)
118 if p1 not in seen and p1 != nullid:
118 if p1 not in seen and p1 != nullid:
119 self.err(lr, _("unknown parent 1 %s of %s") %
119 self.err(lr, _("unknown parent 1 %s of %s") %
120 (short(p1), short(node)), f)
120 (short(p1), short(node)), f)
121 if p2 not in seen and p2 != nullid:
121 if p2 not in seen and p2 != nullid:
122 self.err(lr, _("unknown parent 2 %s of %s") %
122 self.err(lr, _("unknown parent 2 %s of %s") %
123 (short(p2), short(node)), f)
123 (short(p2), short(node)), f)
124 except Exception as inst:
124 except Exception as inst:
125 self.exc(lr, _("checking parents of %s") % short(node), inst, f)
125 self.exc(lr, _("checking parents of %s") % short(node), inst, f)
126
126
127 if node in seen:
127 if node in seen:
128 self.err(lr, _("duplicate revision %d (%d)") % (i, seen[node]), f)
128 self.err(lr, _("duplicate revision %d (%d)") % (i, seen[node]), f)
129 seen[node] = i
129 seen[node] = i
130 return lr
130 return lr
131
131
132 def verify(self):
132 def verify(self):
133 repo = self.repo
133 repo = self.repo
134
134
135 ui = repo.ui
135 ui = repo.ui
136
136
137 if not repo.url().startswith('file:'):
137 if not repo.url().startswith('file:'):
138 raise error.Abort(_("cannot verify bundle or remote repos"))
138 raise error.Abort(_("cannot verify bundle or remote repos"))
139
139
140 if os.path.exists(repo.sjoin("journal")):
140 if os.path.exists(repo.sjoin("journal")):
141 ui.warn(_("abandoned transaction found - run hg recover\n"))
141 ui.warn(_("abandoned transaction found - run hg recover\n"))
142
142
143 if ui.verbose or not self.revlogv1:
143 if ui.verbose or not self.revlogv1:
144 ui.status(_("repository uses revlog format %d\n") %
144 ui.status(_("repository uses revlog format %d\n") %
145 (self.revlogv1 and 1 or 0))
145 (self.revlogv1 and 1 or 0))
146
146
147 mflinkrevs, filelinkrevs = self._verifychangelog()
147 mflinkrevs, filelinkrevs = self._verifychangelog()
148
148
149 filenodes = self._verifymanifest(mflinkrevs)
149 filenodes = self._verifymanifest(mflinkrevs)
150 del mflinkrevs
150 del mflinkrevs
151
151
152 self._crosscheckfiles(filelinkrevs, filenodes)
152 self._crosscheckfiles(filelinkrevs, filenodes)
153
153
154 totalfiles, filerevisions = self._verifyfiles(filenodes, filelinkrevs)
154 totalfiles, filerevisions = self._verifyfiles(filenodes, filelinkrevs)
155
155
156 ui.status(_("%d files, %d changesets, %d total revisions\n") %
156 ui.status(_("%d files, %d changesets, %d total revisions\n") %
157 (totalfiles, len(repo.changelog), filerevisions))
157 (totalfiles, len(repo.changelog), filerevisions))
158 if self.warnings:
158 if self.warnings:
159 ui.warn(_("%d warnings encountered!\n") % self.warnings)
159 ui.warn(_("%d warnings encountered!\n") % self.warnings)
160 if self.fncachewarned:
160 if self.fncachewarned:
161 ui.warn(_('hint: run "hg debugrebuildfncache" to recover from '
161 ui.warn(_('hint: run "hg debugrebuildfncache" to recover from '
162 'corrupt fncache\n'))
162 'corrupt fncache\n'))
163 if self.errors:
163 if self.errors:
164 ui.warn(_("%d integrity errors encountered!\n") % self.errors)
164 ui.warn(_("%d integrity errors encountered!\n") % self.errors)
165 if self.badrevs:
165 if self.badrevs:
166 ui.warn(_("(first damaged changeset appears to be %d)\n")
166 ui.warn(_("(first damaged changeset appears to be %d)\n")
167 % min(self.badrevs))
167 % min(self.badrevs))
168 return 1
168 return 1
169
169
170 def _verifychangelog(self):
170 def _verifychangelog(self):
171 ui = self.ui
171 ui = self.ui
172 repo = self.repo
172 repo = self.repo
173 cl = repo.changelog
173 cl = repo.changelog
174
174
175 ui.status(_("checking changesets\n"))
175 ui.status(_("checking changesets\n"))
176 mflinkrevs = {}
176 mflinkrevs = {}
177 filelinkrevs = {}
177 filelinkrevs = {}
178 seen = {}
178 seen = {}
179 self.checklog(cl, "changelog", 0)
179 self.checklog(cl, "changelog", 0)
180 total = len(repo)
180 total = len(repo)
181 for i in repo:
181 for i in repo:
182 ui.progress(_('checking'), i, total=total, unit=_('changesets'))
182 ui.progress(_('checking'), i, total=total, unit=_('changesets'))
183 n = cl.node(i)
183 n = cl.node(i)
184 self.checkentry(cl, i, n, seen, [i], "changelog")
184 self.checkentry(cl, i, n, seen, [i], "changelog")
185
185
186 try:
186 try:
187 changes = cl.read(n)
187 changes = cl.read(n)
188 if changes[0] != nullid:
188 if changes[0] != nullid:
189 mflinkrevs.setdefault(changes[0], []).append(i)
189 mflinkrevs.setdefault(changes[0], []).append(i)
190 self.refersmf = True
190 self.refersmf = True
191 for f in changes[3]:
191 for f in changes[3]:
192 if _validpath(repo, f):
192 if _validpath(repo, f):
193 filelinkrevs.setdefault(_normpath(f), []).append(i)
193 filelinkrevs.setdefault(_normpath(f), []).append(i)
194 except Exception as inst:
194 except Exception as inst:
195 self.refersmf = True
195 self.refersmf = True
196 self.exc(i, _("unpacking changeset %s") % short(n), inst)
196 self.exc(i, _("unpacking changeset %s") % short(n), inst)
197 ui.progress(_('checking'), None)
197 ui.progress(_('checking'), None)
198 return mflinkrevs, filelinkrevs
198 return mflinkrevs, filelinkrevs
199
199
200 def _verifymanifest(self, mflinkrevs):
200 def _verifymanifest(self, mflinkrevs):
201 repo = self.repo
201 repo = self.repo
202 ui = self.ui
202 ui = self.ui
203 mf = self.repo.manifest
203 mf = self.repo.manifest
204
204
205 ui.status(_("checking manifests\n"))
205 ui.status(_("checking manifests\n"))
206 filenodes = {}
206 filenodes = {}
207 seen = {}
207 seen = {}
208 if self.refersmf:
208 if self.refersmf:
209 # Do not check manifest if there are only changelog entries with
209 # Do not check manifest if there are only changelog entries with
210 # null manifests.
210 # null manifests.
211 self.checklog(mf, "manifest", 0)
211 self.checklog(mf, "manifest", 0)
212 total = len(mf)
212 total = len(mf)
213 for i in mf:
213 for i in mf:
214 ui.progress(_('checking'), i, total=total, unit=_('manifests'))
214 ui.progress(_('checking'), i, total=total, unit=_('manifests'))
215 n = mf.node(i)
215 n = mf.node(i)
216 lr = self.checkentry(mf, i, n, seen, mflinkrevs.get(n, []),
216 lr = self.checkentry(mf, i, n, seen, mflinkrevs.get(n, []),
217 "manifest")
217 "manifest")
218 if n in mflinkrevs:
218 if n in mflinkrevs:
219 del mflinkrevs[n]
219 del mflinkrevs[n]
220 else:
220 else:
221 self.err(lr, _("%s not in changesets") % short(n), "manifest")
221 self.err(lr, _("%s not in changesets") % short(n), "manifest")
222
222
223 try:
223 try:
224 for f, fn in mf.readdelta(n).iteritems():
224 for f, fn in mf.readdelta(n).iteritems():
225 if not f:
225 if not f:
226 self.err(lr, _("file without name in manifest"))
226 self.err(lr, _("file without name in manifest"))
227 elif f != "/dev/null": # ignore this in very old repos
227 elif f != "/dev/null": # ignore this in very old repos
228 if _validpath(repo, f):
228 if _validpath(repo, f):
229 filenodes.setdefault(
229 filenodes.setdefault(
230 _normpath(f), {}).setdefault(fn, lr)
230 _normpath(f), {}).setdefault(fn, lr)
231 except Exception as inst:
231 except Exception as inst:
232 self.exc(lr, _("reading manifest delta %s") % short(n), inst)
232 self.exc(lr, _("reading delta %s") % short(n), inst)
233 ui.progress(_('checking'), None)
233 ui.progress(_('checking'), None)
234
234
235 if self.havemf:
235 if self.havemf:
236 for c, m in sorted([(c, m) for m in mflinkrevs
236 for c, m in sorted([(c, m) for m in mflinkrevs
237 for c in mflinkrevs[m]]):
237 for c in mflinkrevs[m]]):
238 self.err(c, _("changeset refers to unknown manifest %s") %
238 self.err(c, _("changeset refers to unknown revision %s") %
239 short(m))
239 short(m), "manifest")
240
240
241 return filenodes
241 return filenodes
242
242
243 def _crosscheckfiles(self, filelinkrevs, filenodes):
243 def _crosscheckfiles(self, filelinkrevs, filenodes):
244 repo = self.repo
244 repo = self.repo
245 ui = self.ui
245 ui = self.ui
246 ui.status(_("crosschecking files in changesets and manifests\n"))
246 ui.status(_("crosschecking files in changesets and manifests\n"))
247
247
248 total = len(filelinkrevs) + len(filenodes)
248 total = len(filelinkrevs) + len(filenodes)
249 count = 0
249 count = 0
250 if self.havemf:
250 if self.havemf:
251 for f in sorted(filelinkrevs):
251 for f in sorted(filelinkrevs):
252 count += 1
252 count += 1
253 ui.progress(_('crosschecking'), count, total=total)
253 ui.progress(_('crosschecking'), count, total=total)
254 if f not in filenodes:
254 if f not in filenodes:
255 lr = filelinkrevs[f][0]
255 lr = filelinkrevs[f][0]
256 self.err(lr, _("in changeset but not in manifest"), f)
256 self.err(lr, _("in changeset but not in manifest"), f)
257
257
258 if self.havecl:
258 if self.havecl:
259 for f in sorted(filenodes):
259 for f in sorted(filenodes):
260 count += 1
260 count += 1
261 ui.progress(_('crosschecking'), count, total=total)
261 ui.progress(_('crosschecking'), count, total=total)
262 if f not in filelinkrevs:
262 if f not in filelinkrevs:
263 try:
263 try:
264 fl = repo.file(f)
264 fl = repo.file(f)
265 lr = min([fl.linkrev(fl.rev(n)) for n in filenodes[f]])
265 lr = min([fl.linkrev(fl.rev(n)) for n in filenodes[f]])
266 except Exception:
266 except Exception:
267 lr = None
267 lr = None
268 self.err(lr, _("in manifest but not in changeset"), f)
268 self.err(lr, _("in manifest but not in changeset"), f)
269
269
270 ui.progress(_('crosschecking'), None)
270 ui.progress(_('crosschecking'), None)
271
271
272 def _verifyfiles(self, filenodes, filelinkrevs):
272 def _verifyfiles(self, filenodes, filelinkrevs):
273 repo = self.repo
273 repo = self.repo
274 ui = self.ui
274 ui = self.ui
275 lrugetctx = self.lrugetctx
275 lrugetctx = self.lrugetctx
276 revlogv1 = self.revlogv1
276 revlogv1 = self.revlogv1
277 havemf = self.havemf
277 havemf = self.havemf
278 ui.status(_("checking files\n"))
278 ui.status(_("checking files\n"))
279
279
280 storefiles = set()
280 storefiles = set()
281 for f, f2, size in repo.store.datafiles():
281 for f, f2, size in repo.store.datafiles():
282 if not f:
282 if not f:
283 self.err(None, _("cannot decode filename '%s'") % f2)
283 self.err(None, _("cannot decode filename '%s'") % f2)
284 elif (size > 0 or not revlogv1) and f.startswith('data/'):
284 elif (size > 0 or not revlogv1) and f.startswith('data/'):
285 storefiles.add(_normpath(f))
285 storefiles.add(_normpath(f))
286
286
287 files = sorted(set(filenodes) | set(filelinkrevs))
287 files = sorted(set(filenodes) | set(filelinkrevs))
288 total = len(files)
288 total = len(files)
289 revisions = 0
289 revisions = 0
290 for i, f in enumerate(files):
290 for i, f in enumerate(files):
291 ui.progress(_('checking'), i, item=f, total=total)
291 ui.progress(_('checking'), i, item=f, total=total)
292 try:
292 try:
293 linkrevs = filelinkrevs[f]
293 linkrevs = filelinkrevs[f]
294 except KeyError:
294 except KeyError:
295 # in manifest but not in changelog
295 # in manifest but not in changelog
296 linkrevs = []
296 linkrevs = []
297
297
298 if linkrevs:
298 if linkrevs:
299 lr = linkrevs[0]
299 lr = linkrevs[0]
300 else:
300 else:
301 lr = None
301 lr = None
302
302
303 try:
303 try:
304 fl = repo.file(f)
304 fl = repo.file(f)
305 except error.RevlogError as e:
305 except error.RevlogError as e:
306 self.err(lr, _("broken revlog! (%s)") % e, f)
306 self.err(lr, _("broken revlog! (%s)") % e, f)
307 continue
307 continue
308
308
309 for ff in fl.files():
309 for ff in fl.files():
310 try:
310 try:
311 storefiles.remove(ff)
311 storefiles.remove(ff)
312 except KeyError:
312 except KeyError:
313 self.warn(_(" warning: revlog '%s' not in fncache!") % ff)
313 self.warn(_(" warning: revlog '%s' not in fncache!") % ff)
314 self.fncachewarned = True
314 self.fncachewarned = True
315
315
316 self.checklog(fl, f, lr)
316 self.checklog(fl, f, lr)
317 seen = {}
317 seen = {}
318 rp = None
318 rp = None
319 for i in fl:
319 for i in fl:
320 revisions += 1
320 revisions += 1
321 n = fl.node(i)
321 n = fl.node(i)
322 lr = self.checkentry(fl, i, n, seen, linkrevs, f)
322 lr = self.checkentry(fl, i, n, seen, linkrevs, f)
323 if f in filenodes:
323 if f in filenodes:
324 if havemf and n not in filenodes[f]:
324 if havemf and n not in filenodes[f]:
325 self.err(lr, _("%s not in manifests") % (short(n)), f)
325 self.err(lr, _("%s not in manifests") % (short(n)), f)
326 else:
326 else:
327 del filenodes[f][n]
327 del filenodes[f][n]
328
328
329 # verify contents
329 # verify contents
330 try:
330 try:
331 l = len(fl.read(n))
331 l = len(fl.read(n))
332 rp = fl.renamed(n)
332 rp = fl.renamed(n)
333 if l != fl.size(i):
333 if l != fl.size(i):
334 if len(fl.revision(n)) != fl.size(i):
334 if len(fl.revision(n)) != fl.size(i):
335 self.err(lr, _("unpacked size is %s, %s expected") %
335 self.err(lr, _("unpacked size is %s, %s expected") %
336 (l, fl.size(i)), f)
336 (l, fl.size(i)), f)
337 except error.CensoredNodeError:
337 except error.CensoredNodeError:
338 # experimental config: censor.policy
338 # experimental config: censor.policy
339 if ui.config("censor", "policy", "abort") == "abort":
339 if ui.config("censor", "policy", "abort") == "abort":
340 self.err(lr, _("censored file data"), f)
340 self.err(lr, _("censored file data"), f)
341 except Exception as inst:
341 except Exception as inst:
342 self.exc(lr, _("unpacking %s") % short(n), inst, f)
342 self.exc(lr, _("unpacking %s") % short(n), inst, f)
343
343
344 # check renames
344 # check renames
345 try:
345 try:
346 if rp:
346 if rp:
347 if lr is not None and ui.verbose:
347 if lr is not None and ui.verbose:
348 ctx = lrugetctx(lr)
348 ctx = lrugetctx(lr)
349 found = False
349 found = False
350 for pctx in ctx.parents():
350 for pctx in ctx.parents():
351 if rp[0] in pctx:
351 if rp[0] in pctx:
352 found = True
352 found = True
353 break
353 break
354 if not found:
354 if not found:
355 self.warn(_("warning: copy source of '%s' not"
355 self.warn(_("warning: copy source of '%s' not"
356 " in parents of %s") % (f, ctx))
356 " in parents of %s") % (f, ctx))
357 fl2 = repo.file(rp[0])
357 fl2 = repo.file(rp[0])
358 if not len(fl2):
358 if not len(fl2):
359 self.err(lr, _("empty or missing copy source "
359 self.err(lr, _("empty or missing copy source "
360 "revlog %s:%s") % (rp[0], short(rp[1])), f)
360 "revlog %s:%s") % (rp[0], short(rp[1])), f)
361 elif rp[1] == nullid:
361 elif rp[1] == nullid:
362 ui.note(_("warning: %s@%s: copy source"
362 ui.note(_("warning: %s@%s: copy source"
363 " revision is nullid %s:%s\n")
363 " revision is nullid %s:%s\n")
364 % (f, lr, rp[0], short(rp[1])))
364 % (f, lr, rp[0], short(rp[1])))
365 else:
365 else:
366 fl2.rev(rp[1])
366 fl2.rev(rp[1])
367 except Exception as inst:
367 except Exception as inst:
368 self.exc(lr, _("checking rename of %s") % short(n), inst, f)
368 self.exc(lr, _("checking rename of %s") % short(n), inst, f)
369
369
370 # cross-check
370 # cross-check
371 if f in filenodes:
371 if f in filenodes:
372 fns = [(lr, n) for n, lr in filenodes[f].iteritems()]
372 fns = [(lr, n) for n, lr in filenodes[f].iteritems()]
373 for lr, node in sorted(fns):
373 for lr, node in sorted(fns):
374 self.err(lr, _("%s in manifests not found") % short(node),
374 self.err(lr, _("%s in manifests not found") % short(node),
375 f)
375 f)
376 ui.progress(_('checking'), None)
376 ui.progress(_('checking'), None)
377
377
378 for f in storefiles:
378 for f in storefiles:
379 self.warn(_("warning: orphan revlog '%s'") % f)
379 self.warn(_("warning: orphan revlog '%s'") % f)
380
380
381 return len(files), revisions
381 return len(files), revisions
@@ -1,319 +1,319 b''
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: f62022d3d590 in manifests not found
49 FOO.txt@0: f62022d3d590 in manifests not found
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: 88b857db8eba in manifests not found
52 QUICK.txt@0: 88b857db8eba in manifests not found
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: 256559129457 in manifests not found
55 bar.txt@0: 256559129457 in manifests not found
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: 362fef284ce2 in manifests not found
105 file@0: 362fef284ce2 in manifests not found
106 file@1: c10f2164107d in manifests not found
106 file@1: c10f2164107d in manifests not found
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: 362fef284ce2 in manifests not found
133 file@0: 362fef284ce2 in manifests not found
134 file@1: c10f2164107d in manifests not found
134 file@1: c10f2164107d in manifests not found
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 1: changeset refers to unknown manifest 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: c10f2164107d in manifests not found
185 file@1: c10f2164107d in manifests not found
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@?: c10f2164107d in manifests not found
211 file@?: c10f2164107d in manifests not found
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 1: changeset refers to unknown manifest 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 0: reading manifest 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 ..
General Comments 0
You need to be logged in to leave comments. Login now