mutable/layout.py: raise BadShareError instead of assert()
authorBrian Warner <warner@lothar.com>
Sun, 8 Jan 2012 02:05:08 +0000 (18:05 -0800)
committerBrian Warner <warner@lothar.com>
Sun, 8 Jan 2012 22:12:47 +0000 (14:12 -0800)
src/allmydata/mutable/common.py
src/allmydata/mutable/layout.py

index 4a04339f1ae97c28a96ca261f389bfc934b1aadf..9ce11c536e8e95db7f2213c1a3a9a4598928a1b2 100644 (file)
@@ -10,7 +10,13 @@ MODE_READ = "MODE_READ"
 class NotWriteableError(Exception):
     pass
 
-class NeedMoreDataError(Exception):
+class BadShareError(Exception):
+    """This represents an error discovered in a particular share, during
+    retrieve, from which we can recover by using some other share. This does
+    *not* include local coding errors.
+    """
+
+class NeedMoreDataError(BadShareError):
     def __init__(self, needed_bytes, encprivkey_offset, encprivkey_length):
         Exception.__init__(self)
         self.needed_bytes = needed_bytes # up through EOF
@@ -40,7 +46,7 @@ class NotEnoughServersError(Exception):
         Exception.__init__(self, why, first_error)
         self.first_error = first_error
 
-class CorruptShareError(Exception):
+class CorruptShareError(BadShareError):
     def __init__(self, server, shnum, reason):
         self.args = (server, shnum, reason)
         self.server = server
@@ -50,7 +56,7 @@ class CorruptShareError(Exception):
         return "<CorruptShareError server=%s shnum[%d]: %s" % \
                (self.server.get_name(), self.shnum, self.reason)
 
-class UnknownVersionError(Exception):
+class UnknownVersionError(BadShareError):
     """The share we received was of a version we don't recognize."""
 
 class ResponseCache:
index 848940141bde6980dbbf38f7f679ed5ac47ea8c7..cb113c39340cc735ea4a450002a3d0e4321455ef 100644 (file)
@@ -1,6 +1,7 @@
 
 import struct
-from allmydata.mutable.common import NeedMoreDataError, UnknownVersionError
+from allmydata.mutable.common import NeedMoreDataError, UnknownVersionError, \
+     BadShareError
 from allmydata.interfaces import HASH_SIZE, SALT_SIZE, SDMF_VERSION, \
                                  MDMF_VERSION, IMutableSlotWriter
 from allmydata.util import mathutil
@@ -116,7 +117,9 @@ def unpack_share(data):
     share_hash_chain_s = data[o['share_hash_chain']:o['block_hash_tree']]
     share_hash_format = ">H32s"
     hsize = struct.calcsize(share_hash_format)
-    assert len(share_hash_chain_s) % hsize == 0, len(share_hash_chain_s)
+    if len(share_hash_chain_s) % hsize != 0:
+        raise BadShareError("hash chain is %d bytes, not multiple of %d"
+                            % (len(share_hash_chain_s), hsize))
     share_hash_chain = []
     for i in range(0, len(share_hash_chain_s), hsize):
         chunk = share_hash_chain_s[i:i+hsize]
@@ -124,7 +127,9 @@ def unpack_share(data):
         share_hash_chain.append( (hid, h) )
     share_hash_chain = dict(share_hash_chain)
     block_hash_tree_s = data[o['block_hash_tree']:o['share_data']]
-    assert len(block_hash_tree_s) % 32 == 0, len(block_hash_tree_s)
+    if len(block_hash_tree_s) % 32 != 0:
+        raise BadShareError("block_hash_tree is %d bytes, not multiple of %d"
+                            % (len(block_hash_tree_s), 32))
     block_hash_tree = []
     for i in range(0, len(block_hash_tree_s), 32):
         block_hash_tree.append(block_hash_tree_s[i:i+32])
@@ -1168,6 +1173,11 @@ class MDMFSlotWriteProxy:
         d.addCallback(_result)
         return d
 
+def _handle_bad_struct(f):
+    # struct.unpack errors mean the server didn't give us enough data, so
+    # this share is bad
+    f.trap(struct.error)
+    raise BadShareError(f.value.args[0])
 
 class MDMFSlotReadProxy:
     """
@@ -1238,11 +1248,13 @@ class MDMFSlotReadProxy:
         d = self._read(readvs, force_remote)
         d.addCallback(self._process_encoding_parameters)
         d.addCallback(self._process_offsets)
+        d.addErrback(_handle_bad_struct)
         return d
 
 
     def _process_encoding_parameters(self, encoding_parameters):
-        assert self.shnum in encoding_parameters
+        if self.shnum not in encoding_parameters:
+            raise BadShareError("no data for shnum %d" % self.shnum)
         encoding_parameters = encoding_parameters[self.shnum][0]
         # The first byte is the version number. It will tell us what
         # to do next.
@@ -1387,7 +1399,8 @@ class MDMFSlotReadProxy:
         d.addCallback(_then)
         d.addCallback(lambda readvs: self._read(readvs))
         def _process_results(results):
-            assert self.shnum in results
+            if self.shnum not in results:
+                raise BadShareError("no data for shnum %d" % self.shnum)
             if self._version_number == 0:
                 # We only read the share data, but we know the salt from
                 # when we fetched the header
@@ -1395,7 +1408,8 @@ class MDMFSlotReadProxy:
                 if not data:
                     data = ""
                 else:
-                    assert len(data) == 1
+                    if len(data) != 1:
+                        raise BadShareError("got %d vectors, not 1" % len(data))
                     data = data[0]
                 salt = self._salt
             else:
@@ -1445,7 +1459,8 @@ class MDMFSlotReadProxy:
         d.addCallback(lambda readvs:
             self._read(readvs, force_remote=force_remote))
         def _build_block_hash_tree(results):
-            assert self.shnum in results
+            if self.shnum not in results:
+                raise BadShareError("no data for shnum %d" % self.shnum)
 
             rawhashes = results[self.shnum][0]
             results = [rawhashes[i:i+HASH_SIZE]
@@ -1484,7 +1499,8 @@ class MDMFSlotReadProxy:
         d.addCallback(lambda readvs:
             self._read(readvs, force_remote=force_remote))
         def _build_share_hash_chain(results):
-            assert self.shnum in results
+            if self.shnum not in results:
+                raise BadShareError("no data for shnum %d" % self.shnum)
 
             sharehashes = results[self.shnum][0]
             results = [sharehashes[i:i+(HASH_SIZE + 2)]
@@ -1493,6 +1509,7 @@ class MDMFSlotReadProxy:
                             for data in results])
             return results
         d.addCallback(_build_share_hash_chain)
+        d.addErrback(_handle_bad_struct)
         return d
 
 
@@ -1513,7 +1530,8 @@ class MDMFSlotReadProxy:
         d.addCallback(_make_readvs)
         d.addCallback(lambda readvs: self._read(readvs))
         def _process_results(results):
-            assert self.shnum in results
+            if self.shnum not in results:
+                raise BadShareError("no data for shnum %d" % self.shnum)
             privkey = results[self.shnum][0]
             return privkey
         d.addCallback(_process_results)
@@ -1537,7 +1555,8 @@ class MDMFSlotReadProxy:
         d.addCallback(_make_readvs)
         d.addCallback(lambda readvs: self._read(readvs))
         def _process_results(results):
-            assert self.shnum in results
+            if self.shnum not in results:
+                raise BadShareError("no data for shnum %d" % self.shnum)
             signature = results[self.shnum][0]
             return signature
         d.addCallback(_process_results)
@@ -1562,7 +1581,8 @@ class MDMFSlotReadProxy:
         d.addCallback(_make_readvs)
         d.addCallback(lambda readvs: self._read(readvs))
         def _process_results(results):
-            assert self.shnum in results
+            if self.shnum not in results:
+                raise BadShareError("no data for shnum %d" % self.shnum)
             verification_key = results[self.shnum][0]
             return verification_key
         d.addCallback(_process_results)
@@ -1738,7 +1758,7 @@ class MDMFSlotReadProxy:
         return d
 
 
-class LayoutInvalid(Exception):
+class LayoutInvalid(BadShareError):
     """
     This isn't a valid MDMF mutable file
     """