|
1 # censor code related to censoring revision |
|
2 # |
|
3 # Copyright 2021 Pierre-Yves David <pierre-yves.david@octobus.net> |
|
4 # Copyright 2015 Google, Inc <martinvonz@google.com> |
|
5 # |
|
6 # This software may be used and distributed according to the terms of the |
|
7 # GNU General Public License version 2 or any later version. |
|
8 |
|
9 from ..node import ( |
|
10 nullrev, |
|
11 ) |
|
12 from ..i18n import _ |
|
13 from .. import ( |
|
14 error, |
|
15 ) |
|
16 from ..utils import ( |
|
17 storageutil, |
|
18 ) |
|
19 from . import constants |
|
20 |
|
21 |
|
22 def v1_censor(rl, tr, censornode, tombstone=b''): |
|
23 """censors a revision in a "version 1" revlog""" |
|
24 assert rl._format_version == constants.REVLOGV1, rl._format_version |
|
25 |
|
26 # avoid cycle |
|
27 from .. import revlog |
|
28 |
|
29 censorrev = rl.rev(censornode) |
|
30 tombstone = storageutil.packmeta({b'censored': tombstone}, b'') |
|
31 |
|
32 if len(tombstone) > rl.rawsize(censorrev): |
|
33 raise error.Abort( |
|
34 _(b'censor tombstone must be no longer than censored data') |
|
35 ) |
|
36 |
|
37 # Rewriting the revlog in place is hard. Our strategy for censoring is |
|
38 # to create a new revlog, copy all revisions to it, then replace the |
|
39 # revlogs on transaction close. |
|
40 # |
|
41 # This is a bit dangerous. We could easily have a mismatch of state. |
|
42 newrl = revlog.revlog( |
|
43 rl.opener, |
|
44 target=rl.target, |
|
45 radix=rl.radix, |
|
46 postfix=b'tmpcensored', |
|
47 censorable=True, |
|
48 ) |
|
49 newrl._format_version = rl._format_version |
|
50 newrl._format_flags = rl._format_flags |
|
51 newrl._generaldelta = rl._generaldelta |
|
52 newrl._parse_index = rl._parse_index |
|
53 |
|
54 for rev in rl.revs(): |
|
55 node = rl.node(rev) |
|
56 p1, p2 = rl.parents(node) |
|
57 |
|
58 if rev == censorrev: |
|
59 newrl.addrawrevision( |
|
60 tombstone, |
|
61 tr, |
|
62 rl.linkrev(censorrev), |
|
63 p1, |
|
64 p2, |
|
65 censornode, |
|
66 constants.REVIDX_ISCENSORED, |
|
67 ) |
|
68 |
|
69 if newrl.deltaparent(rev) != nullrev: |
|
70 m = _(b'censored revision stored as delta; cannot censor') |
|
71 h = _( |
|
72 b'censoring of revlogs is not fully implemented;' |
|
73 b' please report this bug' |
|
74 ) |
|
75 raise error.Abort(m, hint=h) |
|
76 continue |
|
77 |
|
78 if rl.iscensored(rev): |
|
79 if rl.deltaparent(rev) != nullrev: |
|
80 m = _( |
|
81 b'cannot censor due to censored ' |
|
82 b'revision having delta stored' |
|
83 ) |
|
84 raise error.Abort(m) |
|
85 rawtext = rl._chunk(rev) |
|
86 else: |
|
87 rawtext = rl.rawdata(rev) |
|
88 |
|
89 newrl.addrawrevision( |
|
90 rawtext, tr, rl.linkrev(rev), p1, p2, node, rl.flags(rev) |
|
91 ) |
|
92 |
|
93 tr.addbackup(rl._indexfile, location=b'store') |
|
94 if not rl._inline: |
|
95 tr.addbackup(rl._datafile, location=b'store') |
|
96 |
|
97 rl.opener.rename(newrl._indexfile, rl._indexfile) |
|
98 if not rl._inline: |
|
99 rl.opener.rename(newrl._datafile, rl._datafile) |
|
100 |
|
101 rl.clearcaches() |
|
102 rl._loadindex() |