comparison mercurial/revlog.py @ 36768:7bf80d9d9543

merge with stable There were a handful of merge conflicts in the wire protocol code due to significant refactoring in default. When resolving the conflicts, I tried to produce the minimal number of changes to make the incoming security patches work with the new code. I will send some follow-up commits to get the security patches better integrated into default.
author Gregory Szorc <gregory.szorc@gmail.com>
date Tue, 06 Mar 2018 14:32:14 -0800
parents 6bacb2f663cb 369aadf7a326
children f0b6fbea00cf
comparison
equal deleted inserted replaced
36767:4c71a26a4009 36768:7bf80d9d9543
75 REVIDX_ISCENSORED, 75 REVIDX_ISCENSORED,
76 REVIDX_ELLIPSIS, 76 REVIDX_ELLIPSIS,
77 REVIDX_EXTSTORED, 77 REVIDX_EXTSTORED,
78 ] 78 ]
79 REVIDX_KNOWN_FLAGS = util.bitsfrom(REVIDX_FLAGS_ORDER) 79 REVIDX_KNOWN_FLAGS = util.bitsfrom(REVIDX_FLAGS_ORDER)
80 # bitmark for flags that could cause rawdata content change
81 REVIDX_RAWTEXT_CHANGING_FLAGS = REVIDX_ISCENSORED | REVIDX_EXTSTORED
80 82
81 # max size of revlog with inline data 83 # max size of revlog with inline data
82 _maxinline = 131072 84 _maxinline = 131072
83 _chunksize = 1048576 85 _chunksize = 1048576
84 86
94 96
95 def addflagprocessor(flag, processor): 97 def addflagprocessor(flag, processor):
96 """Register a flag processor on a revision data flag. 98 """Register a flag processor on a revision data flag.
97 99
98 Invariant: 100 Invariant:
99 - Flags need to be defined in REVIDX_KNOWN_FLAGS and REVIDX_FLAGS_ORDER. 101 - Flags need to be defined in REVIDX_KNOWN_FLAGS and REVIDX_FLAGS_ORDER,
102 and REVIDX_RAWTEXT_CHANGING_FLAGS if they can alter rawtext.
100 - Only one flag processor can be registered on a specific flag. 103 - Only one flag processor can be registered on a specific flag.
101 - flagprocessors must be 3-tuples of functions (read, write, raw) with the 104 - flagprocessors must be 3-tuples of functions (read, write, raw) with the
102 following signatures: 105 following signatures:
103 - (read) f(self, rawtext) -> text, bool 106 - (read) f(self, rawtext) -> text, bool
104 - (write) f(self, text) -> rawtext, bool 107 - (write) f(self, text) -> rawtext, bool
331 hlen = struct.calcsize(">lll") 334 hlen = struct.calcsize(">lll")
332 if delta[:hlen] == mdiff.replacediffheader(revlog.rawsize(baserev), 335 if delta[:hlen] == mdiff.replacediffheader(revlog.rawsize(baserev),
333 len(delta) - hlen): 336 len(delta) - hlen):
334 btext[0] = delta[hlen:] 337 btext[0] = delta[hlen:]
335 else: 338 else:
336 basetext = revlog.revision(baserev, _df=fh, raw=True) 339 # deltabase is rawtext before changed by flag processors, which is
340 # equivalent to non-raw text
341 basetext = revlog.revision(baserev, _df=fh, raw=False)
337 btext[0] = mdiff.patch(basetext, delta) 342 btext[0] = mdiff.patch(basetext, delta)
338 343
339 try: 344 try:
340 res = revlog._processflags(btext[0], flags, 'read', raw=True) 345 res = revlog._processflags(btext[0], flags, 'read', raw=True)
341 btext[0], validatehash = res 346 btext[0], validatehash = res
402 407
403 deltainfo = None 408 deltainfo = None
404 for candidaterevs in self._getcandidaterevs(p1, p2, cachedelta): 409 for candidaterevs in self._getcandidaterevs(p1, p2, cachedelta):
405 nominateddeltas = [] 410 nominateddeltas = []
406 for candidaterev in candidaterevs: 411 for candidaterev in candidaterevs:
412 # no delta for rawtext-changing revs (see "candelta" for why)
413 if revlog.flags(candidaterev) & REVIDX_RAWTEXT_CHANGING_FLAGS:
414 continue
407 candidatedelta = self._builddeltainfo(revinfo, candidaterev, fh) 415 candidatedelta = self._builddeltainfo(revinfo, candidaterev, fh)
408 if revlog._isgooddeltainfo(candidatedelta, revinfo.textlen): 416 if revlog._isgooddeltainfo(candidatedelta, revinfo.textlen):
409 nominateddeltas.append(candidatedelta) 417 nominateddeltas.append(candidatedelta)
410 if nominateddeltas: 418 if nominateddeltas:
411 deltainfo = min(nominateddeltas, key=lambda x: x.deltalen) 419 deltainfo = min(nominateddeltas, key=lambda x: x.deltalen)
735 try: 743 try:
736 self.rev(node) 744 self.rev(node)
737 return True 745 return True
738 except KeyError: 746 except KeyError:
739 return False 747 return False
748
749 def candelta(self, baserev, rev):
750 """whether two revisions (baserev, rev) can be delta-ed or not"""
751 # Disable delta if either rev requires a content-changing flag
752 # processor (ex. LFS). This is because such flag processor can alter
753 # the rawtext content that the delta will be based on, and two clients
754 # could have a same revlog node with different flags (i.e. different
755 # rawtext contents) and the delta could be incompatible.
756 if ((self.flags(baserev) & REVIDX_RAWTEXT_CHANGING_FLAGS)
757 or (self.flags(rev) & REVIDX_RAWTEXT_CHANGING_FLAGS)):
758 return False
759 return True
740 760
741 def clearcaches(self): 761 def clearcaches(self):
742 self._cache = None 762 self._cache = None
743 self._chainbasecache.clear() 763 self._chainbasecache.clear()
744 self._chunkcache = (0, '') 764 self._chunkcache = (0, '')
2076 p1r, p2r = self.rev(p1), self.rev(p2) 2096 p1r, p2r = self.rev(p1), self.rev(p2)
2077 2097
2078 # full versions are inserted when the needed deltas 2098 # full versions are inserted when the needed deltas
2079 # become comparable to the uncompressed text 2099 # become comparable to the uncompressed text
2080 if rawtext is None: 2100 if rawtext is None:
2081 textlen = mdiff.patchedsize(self.rawsize(cachedelta[0]), 2101 # need rawtext size, before changed by flag processors, which is
2102 # the non-raw size. use revlog explicitly to avoid filelog's extra
2103 # logic that might remove metadata size.
2104 textlen = mdiff.patchedsize(revlog.size(self, cachedelta[0]),
2082 cachedelta[1]) 2105 cachedelta[1])
2083 else: 2106 else:
2084 textlen = len(rawtext) 2107 textlen = len(rawtext)
2085 2108
2086 if deltacomputer is None: 2109 if deltacomputer is None:
2087 deltacomputer = _deltacomputer(self) 2110 deltacomputer = _deltacomputer(self)
2088 2111
2089 revinfo = _revisioninfo(node, p1, p2, btext, textlen, cachedelta, flags) 2112 revinfo = _revisioninfo(node, p1, p2, btext, textlen, cachedelta, flags)
2090 deltainfo = deltacomputer.finddeltainfo(revinfo, fh) 2113
2114 # no delta for flag processor revision (see "candelta" for why)
2115 # not calling candelta since only one revision needs test, also to
2116 # avoid overhead fetching flags again.
2117 if flags & REVIDX_RAWTEXT_CHANGING_FLAGS:
2118 deltainfo = None
2119 else:
2120 deltainfo = deltacomputer.finddeltainfo(revinfo, fh)
2091 2121
2092 if deltainfo is not None: 2122 if deltainfo is not None:
2093 base = deltainfo.base 2123 base = deltainfo.base
2094 chainbase = deltainfo.chainbase 2124 chainbase = deltainfo.chainbase
2095 data = deltainfo.data 2125 data = deltainfo.data