source: trunk/src/allmydata/unknown.py

Last change on this file was 1cfe843d, checked in by Alexandre Detiste <alexandre.detiste@…>, at 2024-02-22T23:40:25Z

more python2 removal

  • Property mode set to 100644
File size: 8.4 KB
Line 
1"""Ported to Python 3.
2"""
3
4from zope.interface import implementer
5from twisted.internet import defer
6from allmydata.interfaces import IFilesystemNode, MustNotBeUnknownRWError, \
7    MustBeDeepImmutableError
8from allmydata import uri
9from allmydata.uri import ALLEGED_READONLY_PREFIX, ALLEGED_IMMUTABLE_PREFIX
10
11
12# See ticket #833 for design rationale of UnknownNodes.
13
14def strip_prefix_for_ro(ro_uri, deep_immutable):
15    """Strip prefixes when storing an URI in a ro_uri slot."""
16
17    # It is possible for an alleged-immutable URI to be put into a
18    # mutable directory. In that case the ALLEGED_IMMUTABLE_PREFIX
19    # should not be stripped. In other cases, the prefix can safely
20    # be stripped because it is implied by the context.
21
22    if ro_uri.startswith(ALLEGED_IMMUTABLE_PREFIX):
23        if not deep_immutable:
24            return ro_uri
25        return ro_uri[len(ALLEGED_IMMUTABLE_PREFIX):]
26    elif ro_uri.startswith(ALLEGED_READONLY_PREFIX):
27        return ro_uri[len(ALLEGED_READONLY_PREFIX):]
28    else:
29        return ro_uri
30
31@implementer(IFilesystemNode)
32class UnknownNode(object):
33
34    def __init__(self, given_rw_uri, given_ro_uri, deep_immutable=False,
35                 name=u"<unknown name>"):
36        assert given_rw_uri is None or isinstance(given_rw_uri, bytes)
37        assert given_ro_uri is None or isinstance(given_ro_uri, bytes)
38        given_rw_uri = given_rw_uri or None
39        given_ro_uri = given_ro_uri or None
40
41        # We don't raise errors when creating an UnknownNode; we instead create an
42        # opaque node (with rw_uri and ro_uri both None) that records the error.
43        # This avoids breaking operations that never store the opaque node.
44        # Note that this means that if a stored dirnode has only a rw_uri, it
45        # might be dropped. Any future "write-only" cap formats should have a dummy
46        # unusable readcap to stop that from happening.
47
48        self.error = None
49        self.rw_uri = self.ro_uri = None
50        if given_rw_uri:
51            if deep_immutable:
52                if given_rw_uri.startswith(ALLEGED_IMMUTABLE_PREFIX) and not given_ro_uri:
53                    # We needed an immutable cap, and were given one. It was given in the
54                    # rw_uri slot, but that's fine; we'll move it to ro_uri below.
55                    pass
56                elif not given_ro_uri:
57                    self.error = MustNotBeUnknownRWError("cannot attach unknown rw cap as immutable child",
58                                                         name, True)
59                    return  # node will be opaque
60                else:
61                    # We could report either error, but this probably makes more sense.
62                    self.error = MustBeDeepImmutableError("cannot attach unknown rw cap as immutable child",
63                                                         name)
64                    return  # node will be opaque
65
66            if not given_ro_uri:
67                # We were given a single cap argument, or a rw_uri with no ro_uri.
68
69                if not (given_rw_uri.startswith(ALLEGED_READONLY_PREFIX)
70                        or given_rw_uri.startswith(ALLEGED_IMMUTABLE_PREFIX)):
71                    # If the single cap is unprefixed, then we cannot tell whether it is a
72                    # writecap, and we don't know how to diminish it to a readcap if it is one.
73                    # If it didn't *already* have at least an ALLEGED_READONLY_PREFIX, then
74                    # prefixing it would be a bad idea because we have been given no reason
75                    # to believe that it is a readcap, so we might be letting a client
76                    # inadvertently grant excess write authority.
77                    self.error = MustNotBeUnknownRWError("cannot attach unknown rw cap as child",
78                                                         name, False)
79                    return  # node will be opaque
80
81                # OTOH, if the single cap already had a prefix (which is of the required
82                # strength otherwise an error would have been thrown above), then treat it
83                # as though it had been given in the ro_uri slot. This has a similar effect
84                # to the use for known caps of 'bigcap = writecap or readcap' in
85                # nodemaker.py: create_from_cap. It enables copying of unknown readcaps to
86                # work in as many cases as we can securely allow.
87                given_ro_uri = given_rw_uri
88                given_rw_uri = None
89            elif given_ro_uri.startswith(ALLEGED_IMMUTABLE_PREFIX):
90                # Strange corner case: we were given a cap in both slots, with the ro_uri
91                # alleged to be immutable. A real immutable object wouldn't have a writecap.
92                self.error = MustBeDeepImmutableError("cannot accept a child entry that specifies "
93                                                      "both rw_uri, and ro_uri with an imm. prefix",
94                                                      name)
95                return  # node will be opaque
96
97        # If the ro_uri definitely fails the constraint, it should be treated as opaque and
98        # the error recorded.
99        if given_ro_uri:
100            read_cap = uri.from_string(given_ro_uri, deep_immutable=deep_immutable, name=name)
101            if isinstance(read_cap, uri.UnknownURI):
102                self.error = read_cap.get_error()
103                if self.error:
104                    assert self.rw_uri is None and self.ro_uri is None
105                    return
106
107        if deep_immutable:
108            assert self.rw_uri is None
109            # strengthen the constraint on ro_uri to ALLEGED_IMMUTABLE_PREFIX
110            if given_ro_uri:
111                if given_ro_uri.startswith(ALLEGED_IMMUTABLE_PREFIX):
112                    self.ro_uri = given_ro_uri
113                elif given_ro_uri.startswith(ALLEGED_READONLY_PREFIX):
114                    self.ro_uri = ALLEGED_IMMUTABLE_PREFIX + given_ro_uri[len(ALLEGED_READONLY_PREFIX):]
115                else:
116                    self.ro_uri = ALLEGED_IMMUTABLE_PREFIX + given_ro_uri
117        else:
118            # not immutable, so a writecap is allowed
119            self.rw_uri = given_rw_uri
120            # strengthen the constraint on ro_uri to ALLEGED_READONLY_PREFIX
121            if given_ro_uri:
122                if (given_ro_uri.startswith(ALLEGED_READONLY_PREFIX) or
123                    given_ro_uri.startswith(ALLEGED_IMMUTABLE_PREFIX)):
124                    self.ro_uri = given_ro_uri
125                else:
126                    self.ro_uri = ALLEGED_READONLY_PREFIX + given_ro_uri
127
128    def get_cap(self):
129        return uri.UnknownURI(self.rw_uri or self.ro_uri)
130
131    def get_readcap(self):
132        return uri.UnknownURI(self.ro_uri)
133
134    def is_readonly(self):
135        raise AssertionError("an UnknownNode might be either read-only or "
136                             "read/write, so we shouldn't be calling is_readonly")
137
138    def is_mutable(self):
139        raise AssertionError("an UnknownNode might be either mutable or immutable, "
140                             "so we shouldn't be calling is_mutable")
141
142    def is_unknown(self):
143        return True
144
145    def is_allowed_in_immutable_directory(self):
146        # An UnknownNode consisting only of a ro_uri is allowed in an
147        # immutable directory, even though we do not know that it is
148        # immutable (or even read-only), provided that no error was detected.
149        return not self.error and not self.rw_uri
150
151    def is_alleged_immutable(self):
152        return not self.error and not self.rw_uri and (not self.ro_uri or self.ro_uri.startswith(ALLEGED_IMMUTABLE_PREFIX))
153
154    def raise_error(self):
155        if self.error is not None:
156            raise self.error
157
158    def get_uri(self):
159        return self.rw_uri or self.ro_uri
160
161    def get_write_uri(self):
162        return self.rw_uri
163
164    def get_readonly_uri(self):
165        return self.ro_uri
166
167    def get_storage_index(self):
168        return None
169
170    def get_verify_cap(self):
171        return None
172
173    def get_repair_cap(self):
174        return None
175
176    def get_size(self):
177        return None
178
179    def get_current_size(self):
180        return defer.succeed(None)
181
182    def check(self, monitor, verify, add_lease):
183        return defer.succeed(None)
184
185    def check_and_repair(self, monitor, verify, add_lease):
186        return defer.succeed(None)
187
188    def __eq__(self, other):
189        if not isinstance(other, UnknownNode):
190            return False
191        return other.ro_uri == self.ro_uri and other.rw_uri == self.rw_uri
192
193    def __ne__(self, other):
194        return not (self == other)
Note: See TracBrowser for help on using the repository browser.