115 def packmeta(meta, text): |
115 def packmeta(meta, text): |
116 keys = sorted(meta) |
116 keys = sorted(meta) |
117 metatext = "".join("%s: %s\n" % (k, meta[k]) for k in keys) |
117 metatext = "".join("%s: %s\n" % (k, meta[k]) for k in keys) |
118 return "\1\n%s\1\n%s" % (metatext, text) |
118 return "\1\n%s\1\n%s" % (metatext, text) |
119 |
119 |
|
120 def _censoredtext(text): |
|
121 m, offs = parsemeta(text) |
|
122 return m and "censored" in m |
|
123 |
120 def addflagprocessor(flag, processor): |
124 def addflagprocessor(flag, processor): |
121 """Register a flag processor on a revision data flag. |
125 """Register a flag processor on a revision data flag. |
122 |
126 |
123 Invariant: |
127 Invariant: |
124 - Flags need to be defined in REVIDX_KNOWN_FLAGS and REVIDX_FLAGS_ORDER, |
128 - Flags need to be defined in REVIDX_KNOWN_FLAGS and REVIDX_FLAGS_ORDER, |
572 writing, to avoid file stat ambiguity. |
576 writing, to avoid file stat ambiguity. |
573 |
577 |
574 If mmaplargeindex is True, and an mmapindexthreshold is set, the |
578 If mmaplargeindex is True, and an mmapindexthreshold is set, the |
575 index will be mmapped rather than read if it is larger than the |
579 index will be mmapped rather than read if it is larger than the |
576 configured threshold. |
580 configured threshold. |
|
581 |
|
582 If censorable is True, the revlog can have censored revisions. |
577 """ |
583 """ |
578 def __init__(self, opener, indexfile, datafile=None, checkambig=False, |
584 def __init__(self, opener, indexfile, datafile=None, checkambig=False, |
579 mmaplargeindex=False): |
585 mmaplargeindex=False, censorable=False): |
580 """ |
586 """ |
581 create a revlog object |
587 create a revlog object |
582 |
588 |
583 opener is a function that abstracts the file opening operation |
589 opener is a function that abstracts the file opening operation |
584 and can be used to implement COW semantics or the like. |
590 and can be used to implement COW semantics or the like. |
587 self.datafile = datafile or (indexfile[:-2] + ".d") |
593 self.datafile = datafile or (indexfile[:-2] + ".d") |
588 self.opener = opener |
594 self.opener = opener |
589 # When True, indexfile is opened with checkambig=True at writing, to |
595 # When True, indexfile is opened with checkambig=True at writing, to |
590 # avoid file stat ambiguity. |
596 # avoid file stat ambiguity. |
591 self._checkambig = checkambig |
597 self._checkambig = checkambig |
|
598 self._censorable = censorable |
592 # 3-tuple of (node, rev, text) for a raw revision. |
599 # 3-tuple of (node, rev, text) for a raw revision. |
593 self._cache = None |
600 self._cache = None |
594 # Maps rev to chain base rev. |
601 # Maps rev to chain base rev. |
595 self._chainbasecache = util.lrucachedict(100) |
602 self._chainbasecache = util.lrucachedict(100) |
596 # 2-tuple of (offset, data) of raw data from the revlog at an offset. |
603 # 2-tuple of (offset, data) of raw data from the revlog at an offset. |
1865 """Check node hash integrity. |
1872 """Check node hash integrity. |
1866 |
1873 |
1867 Available as a function so that subclasses can extend hash mismatch |
1874 Available as a function so that subclasses can extend hash mismatch |
1868 behaviors as needed. |
1875 behaviors as needed. |
1869 """ |
1876 """ |
1870 if p1 is None and p2 is None: |
1877 try: |
1871 p1, p2 = self.parents(node) |
1878 if p1 is None and p2 is None: |
1872 if node != self.hash(text, p1, p2): |
1879 p1, p2 = self.parents(node) |
1873 revornode = rev |
1880 if node != self.hash(text, p1, p2): |
1874 if revornode is None: |
1881 revornode = rev |
1875 revornode = templatefilters.short(hex(node)) |
1882 if revornode is None: |
1876 raise RevlogError(_("integrity check failed on %s:%s") |
1883 revornode = templatefilters.short(hex(node)) |
1877 % (self.indexfile, pycompat.bytestr(revornode))) |
1884 raise RevlogError(_("integrity check failed on %s:%s") |
|
1885 % (self.indexfile, pycompat.bytestr(revornode))) |
|
1886 except RevlogError: |
|
1887 if self._censorable and _censoredtext(text): |
|
1888 raise error.CensoredNodeError(self.indexfile, node, text) |
|
1889 raise |
1878 |
1890 |
1879 def _enforceinlinesize(self, tr, fp=None): |
1891 def _enforceinlinesize(self, tr, fp=None): |
1880 """Check if the revlog is too big for inline and convert if so. |
1892 """Check if the revlog is too big for inline and convert if so. |
1881 |
1893 |
1882 This should be called after revisions are added to the revlog. If the |
1894 This should be called after revisions are added to the revlog. If the |
2298 |
2310 |
2299 return nodes |
2311 return nodes |
2300 |
2312 |
2301 def iscensored(self, rev): |
2313 def iscensored(self, rev): |
2302 """Check if a file revision is censored.""" |
2314 """Check if a file revision is censored.""" |
2303 return False |
2315 if not self._censorable: |
|
2316 return False |
|
2317 |
|
2318 return self.flags(rev) & REVIDX_ISCENSORED |
2304 |
2319 |
2305 def _peek_iscensored(self, baserev, delta, flush): |
2320 def _peek_iscensored(self, baserev, delta, flush): |
2306 """Quickly check if a delta produces a censored revision.""" |
2321 """Quickly check if a delta produces a censored revision.""" |
2307 return False |
2322 if not self._censorable: |
|
2323 return False |
|
2324 |
|
2325 # Fragile heuristic: unless new file meta keys are added alphabetically |
|
2326 # preceding "censored", all censored revisions are prefixed by |
|
2327 # "\1\ncensored:". A delta producing such a censored revision must be a |
|
2328 # full-replacement delta, so we inspect the first and only patch in the |
|
2329 # delta for this prefix. |
|
2330 hlen = struct.calcsize(">lll") |
|
2331 if len(delta) <= hlen: |
|
2332 return False |
|
2333 |
|
2334 oldlen = self.rawsize(baserev) |
|
2335 newlen = len(delta) - hlen |
|
2336 if delta[:hlen] != mdiff.replacediffheader(oldlen, newlen): |
|
2337 return False |
|
2338 |
|
2339 add = "\1\ncensored:" |
|
2340 addlen = len(add) |
|
2341 return newlen >= addlen and delta[hlen:hlen + addlen] == add |
2308 |
2342 |
2309 def getstrippoint(self, minlink): |
2343 def getstrippoint(self, minlink): |
2310 """find the minimum rev that must be stripped to strip the linkrev |
2344 """find the minimum rev that must be stripped to strip the linkrev |
2311 |
2345 |
2312 Returns a tuple containing the minimum rev and a set of all revs that |
2346 Returns a tuple containing the minimum rev and a set of all revs that |