We introduce a new exception to handle the various failure categories,
rather than relying on RuntimeError.
Details
Details
Diff Detail
Diff Detail
- Repository
- rHG Mercurial
- Branch
- default
- Lint
No Linters Available - Unit
No Unit Test Coverage
( )
We introduce a new exception to handle the various failure categories,
rather than relying on RuntimeError.
No Linters Available |
No Unit Test Coverage |
Path | Packages | |||
---|---|---|---|---|
M | hgext/remotefilelog/basestore.py (2 lines) | |||
M | hgext/remotefilelog/shallowutil.py (14 lines) | |||
M | tests/test-remotefilelog-corrupt-cache.t (2 lines) |
Commit | Parents | Author | Summary | Date |
---|---|---|---|---|
4720e672d55c | 46a7e1030b97 | Augie Fackler | Jul 7 2021, 11:45 AM |
offset += size | offset += size | ||||
datanode = data[offset : offset + 20] | datanode = data[offset : offset + 20] | ||||
# and compare against the path | # and compare against the path | ||||
if os.path.basename(path) == hex(datanode): | if os.path.basename(path) == hex(datanode): | ||||
# Content matches the intended path | # Content matches the intended path | ||||
return True | return True | ||||
return False | return False | ||||
except (ValueError, RuntimeError): | except (ValueError, shallowutil.BadRemotefilelogHeader): | ||||
pass | pass | ||||
return False | return False | ||||
def gc(self, keepkeys): | def gc(self, keepkeys): | ||||
ui = self.ui | ui = self.ui | ||||
cachepath = self._path | cachepath = self._path | ||||
"""the reverse of int2bin, convert a binary buffer to an integer""" | """the reverse of int2bin, convert a binary buffer to an integer""" | ||||
x = 0 | x = 0 | ||||
for b in bytearray(buf): | for b in bytearray(buf): | ||||
x <<= 8 | x <<= 8 | ||||
x |= b | x |= b | ||||
return x | return x | ||||
class BadRemotefilelogHeader(error.StorageError): | |||||
"""Exception raised when parsing a remotefilelog blob header fails.""" | |||||
def parsesizeflags(raw): | def parsesizeflags(raw): | ||||
"""given a remotefilelog blob, return (headersize, rawtextsize, flags) | """given a remotefilelog blob, return (headersize, rawtextsize, flags) | ||||
see remotefilelogserver.createfileblob for the format. | see remotefilelogserver.createfileblob for the format. | ||||
raise RuntimeError if the content is illformed. | raise RuntimeError if the content is illformed. | ||||
""" | """ | ||||
flags = revlog.REVIDX_DEFAULT_FLAGS | flags = revlog.REVIDX_DEFAULT_FLAGS | ||||
size = None | size = None | ||||
try: | try: | ||||
index = raw.index(b'\0') | index = raw.index(b'\0') | ||||
header = raw[:index] | header = raw[:index] | ||||
if header.startswith(b'v'): | if header.startswith(b'v'): | ||||
# v1 and above, header starts with 'v' | # v1 and above, header starts with 'v' | ||||
if header.startswith(b'v1\n'): | if header.startswith(b'v1\n'): | ||||
for s in header.split(b'\n'): | for s in header.split(b'\n'): | ||||
if s.startswith(constants.METAKEYSIZE): | if s.startswith(constants.METAKEYSIZE): | ||||
size = int(s[len(constants.METAKEYSIZE) :]) | size = int(s[len(constants.METAKEYSIZE) :]) | ||||
elif s.startswith(constants.METAKEYFLAG): | elif s.startswith(constants.METAKEYFLAG): | ||||
flags = int(s[len(constants.METAKEYFLAG) :]) | flags = int(s[len(constants.METAKEYFLAG) :]) | ||||
else: | else: | ||||
raise RuntimeError( | raise BadRemotefilelogHeader( | ||||
b'unsupported remotefilelog header: %s' % header | b'unsupported remotefilelog header: %s' % header | ||||
) | ) | ||||
else: | else: | ||||
# v0, str(int(size)) is the header | # v0, str(int(size)) is the header | ||||
size = int(header) | size = int(header) | ||||
except ValueError: | except ValueError: | ||||
raise RuntimeError("unexpected remotefilelog header: illegal format") | raise BadRemotefilelogHeader( | ||||
"unexpected remotefilelog header: illegal format" | |||||
) | |||||
if size is None: | if size is None: | ||||
raise RuntimeError("unexpected remotefilelog header: no size found") | raise BadRemotefilelogHeader( | ||||
"unexpected remotefilelog header: no size found" | |||||
) | |||||
return index + 1, size, flags | return index + 1, size, flags | ||||
def buildfileblobheader(size, flags, version=None): | def buildfileblobheader(size, flags, version=None): | ||||
"""return the header of a remotefilelog blob. | """return the header of a remotefilelog blob. | ||||
see remotefilelogserver.createfileblob for the format. | see remotefilelogserver.createfileblob for the format. | ||||
approximately the reverse of parsesizeflags. | approximately the reverse of parsesizeflags. |
$ hg up -q null | $ hg up -q null | ||||
$ cat >> .hg/hgrc <<EOF | $ cat >> .hg/hgrc <<EOF | ||||
> [remotefilelog] | > [remotefilelog] | ||||
> validatecache=off | > validatecache=off | ||||
> EOF | > EOF | ||||
$ chmod u+w $CACHEDIR/master/11/f6ad8ec52a2984abaafd7c3b516503785c2072/1406e74118627694268417491f018a4a883152f0 | $ chmod u+w $CACHEDIR/master/11/f6ad8ec52a2984abaafd7c3b516503785c2072/1406e74118627694268417491f018a4a883152f0 | ||||
$ echo x > $CACHEDIR/master/11/f6ad8ec52a2984abaafd7c3b516503785c2072/1406e74118627694268417491f018a4a883152f0 | $ echo x > $CACHEDIR/master/11/f6ad8ec52a2984abaafd7c3b516503785c2072/1406e74118627694268417491f018a4a883152f0 | ||||
$ hg up tip 2>&1 | egrep "^[^ ].*unexpected remotefilelog" | $ hg up tip 2>&1 | egrep "^[^ ].*unexpected remotefilelog" | ||||
RuntimeError: unexpected remotefilelog header: illegal format | hgext.remotefilelog.shallowutil.BadRemotefilelogHeader: unexpected remotefilelog header: illegal format | ||||
Verify detection and remediation when remotefilelog.validatecachelog is set | Verify detection and remediation when remotefilelog.validatecachelog is set | ||||
$ cat >> .hg/hgrc <<EOF | $ cat >> .hg/hgrc <<EOF | ||||
> [remotefilelog] | > [remotefilelog] | ||||
> validatecachelog=$PWD/.hg/remotefilelog_cache.log | > validatecachelog=$PWD/.hg/remotefilelog_cache.log | ||||
> validatecache=strict | > validatecache=strict | ||||
> EOF | > EOF |