class TestTraverse(unittest.TestCase): def setUp(self): import io import transaction from AccessControl import SecurityManager from AccessControl.SecurityManagement import newSecurityManager from OFS.Application import Application from OFS.Folder import manage_addFolder from OFS.Image import manage_addFile from Testing.makerequest import makerequest from ZODB.DB import DB from ZODB.DemoStorage import DemoStorage s = DemoStorage() self.connection = DB(s).open() try: r = self.connection.root() a = Application() r['Application'] = a self.root = a responseOut = self.responseOut = io.BytesIO() self.app = makerequest(self.root, stdout=responseOut) manage_addFolder(self.app, 'folder1') folder1 = getattr(self.app, 'folder1') setattr(folder1, '+something', 'plus') folder1.all_meta_types = ( {'name': 'File', 'action': 'manage_addFile', 'permission': 'Add images and files' }, ) manage_addFile(folder1, 'file', file=b'', content_type='text/plain') # Hack, we need a _p_mtime for the file, so we make sure that it # has one. We use a subtransaction, which means we can rollback # later and pretend we didn't touch the ZODB. transaction.commit() except Exception: self.connection.close() raise transaction.begin() self.folder1 = getattr(self.app, 'folder1') self.policy = UnitTestSecurityPolicy() self.oldPolicy = SecurityManager.setSecurityPolicy(self.policy) newSecurityManager(None, self._makeUser().__of__(self.root)) def tearDown(self): import transaction self._setupSecurity() del self.oldPolicy del self.policy del self.folder1 transaction.abort() self.app._p_jar.sync() self.connection.close() del self.app del self.responseOut del self.root del self.connection def _makeUser(self): from Acquisition import Implicit class UnitTestUser(Implicit): """ Stubbed out manager for unit testing purposes. """ def getId(self): return 'unit_tester' getUserName = getId def allowed(self, object, object_roles=None): return 1 return UnitTestUser() def _makeBoboTraversable(self): from OFS.SimpleItem import SimpleItem class BoboTraversable(SimpleItem): __allow_access_to_unprotected_subobjects__ = 1 def __bobo_traverse__(self, request, name): if name == 'bb_subitem': return BoboTraversable().__of__(self) elif name == 'bb_method': return self.bb_method elif name == 'bb_status': return self.bb_status elif name == 'manufactured': return 42 else: raise KeyError def bb_method(self): """Test Method""" pass bb_status = 'screechy' return BoboTraversable() def _makeBoboTraversableWithAcquisition(self): from OFS.SimpleItem import SimpleItem class BoboTraversableWithAcquisition(SimpleItem): """ A BoboTraversable which may use acquisition to find objects. This is similar to how the __bobo_traverse__ behaves). """ def __bobo_traverse__(self, request, name): from Acquisition import aq_get return aq_get(self, name) return BoboTraversableWithAcquisition() def _makeRestricted(self, name='dummy'): from OFS.SimpleItem import SimpleItem class Restricted(SimpleItem): """Instance we'll check with ProtectedMethodSecurityPolicy.""" getId__roles__ = None # ACCESS_PUBLIC def getId(self): # NOQA: E306 # pseudo decorator return self.id private__roles__ = () # ACCESS_PRIVATE def private(self): # NOQA: E306 # pseudo decorator return 'private!' # not protected def ohno(self): return 'ohno!' return Restricted(name) def _setupSecurity(self, policy=None): from AccessControl import SecurityManager from AccessControl.SecurityManagement import noSecurityManager if policy is None: policy = self.oldPolicy noSecurityManager() SecurityManager.setSecurityPolicy(policy) def test_interfaces(self): from OFS.interfaces import ITraversable from OFS.Traversable import Traversable from zope.interface.verify import verifyClass verifyClass(ITraversable, Traversable) def testTraversePath(self): self.assertTrue('file' in self.folder1.objectIds()) self.assertTrue( self.folder1.unrestrictedTraverse(('', 'folder1', 'file'))) self.assertTrue(self.folder1.unrestrictedTraverse(('', 'folder1'))) def testTraverseURLNoSlash(self): self.assertTrue('file' in self.folder1.objectIds()) self.assertTrue(self.folder1.unrestrictedTraverse('/folder1/file')) self.assertTrue(self.folder1.unrestrictedTraverse('/folder1')) def testTraverseURLSlash(self): self.assertTrue('file' in self.folder1.objectIds()) self.assertTrue(self.folder1.unrestrictedTraverse('/folder1/file/')) self.assertTrue(self.folder1.unrestrictedTraverse('/folder1/')) def testTraverseToNone(self): self.assertRaises( KeyError, self.folder1.unrestrictedTraverse, ('', 'folder1', 'file2')) self.assertRaises( KeyError, self.folder1.unrestrictedTraverse, '/folder1/file2') self.assertRaises( KeyError, self.folder1.unrestrictedTraverse, '/folder1/file2/') def testTraverseMethodRestricted(self): from AccessControl import Unauthorized self.root.my = self._makeRestricted('my') my = self.root.my my.id = 'my' self._setupSecurity(ProtectedMethodSecurityPolicy()) r = my.restrictedTraverse('getId') self.assertEqual(r(), 'my') self.assertRaises(Unauthorized, my.restrictedTraverse, 'private') self.assertRaises(Unauthorized, my.restrictedTraverse, 'ohno') def testBoboTraverseToWrappedSubObj(self): # Verify it's possible to use __bobo_traverse__ with the # Zope security policy. self._setupSecurity() bb = self._makeBoboTraversable() self.assertRaises(KeyError, bb.restrictedTraverse, 'notfound') bb.restrictedTraverse('bb_subitem') def testBoboTraverseToMethod(self): # Verify it's possible to use __bobo_traverse__ to a method. self._setupSecurity() bb = self._makeBoboTraversable() self.assertTrue( bb.restrictedTraverse('bb_method') is not bb.bb_method) def testBoboTraverseToSimpleAttrValue(self): # Verify it's possible to use __bobo_traverse__ to a simple # python value self._setupSecurity() bb = self._makeBoboTraversable() self.assertEqual(bb.restrictedTraverse('bb_status'), 'screechy') def testBoboTraverseToNonAttrValue(self): # Verify it's possible to use __bobo_traverse__ to an # arbitrary manufactured object # Default security policy always seems to deny in this case, which # is fine, but to test the code branch we sub in the forgiving one self._setupSecurity(UnitTestSecurityPolicy()) bb = self._makeBoboTraversable() self.assertTrue( bb.restrictedTraverse('manufactured') == 42) def testBoboTraverseToAcquiredObject(self): # Verify it's possible to use a __bobo_traverse__ which retrieves # objects by acquisition from Acquisition import aq_inner self._setupSecurity() bb = self._makeBoboTraversableWithAcquisition() bb = bb.__of__(self.root) self.assertEqual( bb.restrictedTraverse('folder1'), bb.folder1) self.assertEqual( aq_inner(bb.restrictedTraverse('folder1')), self.root.folder1) def testBoboTraverseToAcquiredProtectedObject(self): # Verify it's possible to use a __bobo_traverse__ which retrieves # objects by acquisition from AccessControl import Unauthorized from AccessControl.Permissions import access_contents_information self._setupSecurity() folder = self.root.folder1 # restrict the ability to access the retrieved object itself folder.manage_permission(access_contents_information, [], 0) bb = self._makeBoboTraversableWithAcquisition() bb = bb.__of__(self.root) self.assertRaises(Unauthorized, bb.restrictedTraverse, 'folder1') def testBoboTraverseToAcquiredAttribute(self): # Verify it's possible to use __bobo_traverse__ to an acquired # attribute self._setupSecurity() folder = self.root.folder1 folder.stuff = 'stuff here' bb = self._makeBoboTraversableWithAcquisition() bb = bb.__of__(folder) self.assertEqual( bb.restrictedTraverse('stuff'), 'stuff here') def testBoboTraverseToAcquiredProtectedAttribute(self): # Verify that using __bobo_traverse__ to get an acquired but # protected attribute results in Unauthorized from AccessControl import Unauthorized from AccessControl.Permissions import access_contents_information self._setupSecurity() folder = self.root.folder1 # We protect the the attribute by restricting access to the parent folder.manage_permission(access_contents_information, [], 0) folder.stuff = 'stuff here' bb = self._makeBoboTraversableWithAcquisition() bb = bb.__of__(folder) self.assertRaises(Unauthorized, self.root.folder1.restrictedTraverse, 'stuff') def testBoboTraverseTraversalDefault(self): from OFS.SimpleItem import SimpleItem from ZPublisher.interfaces import UseTraversalDefault class BoboTraversableUseTraversalDefault(SimpleItem): """ A BoboTraversable class which may use "UseTraversalDefault" (dependent on "name") to indicate that standard traversal should be used. """ default = 'Default' def __bobo_traverse__(self, request, name): if name == 'normal': return 'Normal' raise UseTraversalDefault bb = BoboTraversableUseTraversalDefault() # normal access -- no traversal default used self.assertEqual(bb.unrestrictedTraverse('normal'), 'Normal') # use traversal default self.assertEqual(bb.unrestrictedTraverse('default'), 'Default') # test traversal default with acqires attribute si = SimpleItem() si.default_acquire = 'Default_Acquire' si.bb = bb self.assertEqual(si.unrestrictedTraverse('bb/default_acquire'), 'Default_Acquire') def testAcquiredAttributeDenial(self): # Verify that restrictedTraverse raises the right kind of exception # on denial of access to an acquired attribute. If it raises # AttributeError instead of Unauthorized, the user may never # be prompted for HTTP credentials. from AccessControl import Unauthorized from AccessControl.SecurityManagement import newSecurityManager self._setupSecurity(CruelSecurityPolicy()) newSecurityManager(None, self._makeUser().__of__(self.root)) self.root.stuff = 'stuff here' self.assertRaises(Unauthorized, self.app.folder1.restrictedTraverse, 'stuff') def testDefaultValueWhenUnathorized(self): # Test that traversing to an unauthorized object returns # the default when provided from AccessControl.SecurityManagement import newSecurityManager self._setupSecurity(CruelSecurityPolicy()) newSecurityManager(None, self._makeUser().__of__(self.root)) self.root.stuff = 'stuff here' self.assertEqual( self.root.folder1.restrictedTraverse('stuff', 42), 42) def testNotFoundIsRaised(self): from OFS.SimpleItem import SimpleItem from zExceptions import NotFound from operator import getitem self.folder1._setObject('foo', SimpleItem('foo')) self.assertRaises(AttributeError, getitem, self.folder1.foo, 'doesntexist') self.assertRaises(NotFound, self.folder1.unrestrictedTraverse, 'foo/doesntexist') self.assertRaises(TypeError, getitem, self.folder1.foo.isPrincipiaFolderish, 'doesntexist') self.assertRaises(NotFound, self.folder1.unrestrictedTraverse, 'foo/isPrincipiaFolderish/doesntexist') def testDefaultValueWhenNotFound(self): # Test that traversing to a non-existent object returns # the default when provided self._setupSecurity() self.assertEqual( self.root.restrictedTraverse('happy/happy', 'joy'), 'joy') def testTraverseUp(self): # Test that we can traverse upwards from Acquisition import aq_base self.assertTrue( aq_base(self.root.folder1.file.restrictedTraverse('../..')) is aq_base(self.root)) def testTraverseToNameStartingWithPlus(self): # Verify it's possible to traverse to a name such as +something self.assertTrue( self.folder1.unrestrictedTraverse('+something') == 'plus')
class TestTraverse(unittest.TestCase): def setUp(self): import io import transaction from AccessControl import SecurityManager from AccessControl.SecurityManagement import newSecurityManager from OFS.Application import Application from OFS.Folder import manage_addFolder from OFS.Image import manage_addFile from Testing.makerequest import makerequest from ZODB.DB import DB from ZODB.DemoStorage import DemoStorage s = DemoStorage() self.connection = DB(s).open() try: r = self.connection.root() a = Application() r['Application'] = a self.root = a responseOut = self.responseOut = io.BytesIO() self.app = makerequest(self.root, stdout=responseOut) manage_addFolder(self.app, 'folder1') folder1 = getattr(self.app, 'folder1') setattr(folder1, '+something', 'plus') folder1.all_meta_types = ({ 'name': 'File', 'action': 'manage_addFile', 'permission': 'Add images and files' }, ) manage_addFile(folder1, 'file', file=b'', content_type='text/plain') # Hack, we need a _p_mtime for the file, so we make sure that it # has one. We use a subtransaction, which means we can rollback # later and pretend we didn't touch the ZODB. transaction.commit() except Exception: self.connection.close() raise transaction.begin() self.folder1 = getattr(self.app, 'folder1') self.policy = UnitTestSecurityPolicy() self.oldPolicy = SecurityManager.setSecurityPolicy(self.policy) newSecurityManager(None, self._makeUser().__of__(self.root)) def tearDown(self): import transaction self._setupSecurity() del self.oldPolicy del self.policy del self.folder1 transaction.abort() self.app._p_jar.sync() self.connection.close() del self.app del self.responseOut del self.root del self.connection def _makeUser(self): from Acquisition import Implicit class UnitTestUser(Implicit): """ Stubbed out manager for unit testing purposes. """ def getId(self): return 'unit_tester' getUserName = getId def allowed(self, object, object_roles=None): return 1 return UnitTestUser() def _makeBoboTraversable(self): from OFS.SimpleItem import SimpleItem class BoboTraversable(SimpleItem): __allow_access_to_unprotected_subobjects__ = 1 def __bobo_traverse__(self, request, name): if name == 'bb_subitem': return BoboTraversable().__of__(self) elif name == 'bb_method': return self.bb_method elif name == 'bb_status': return self.bb_status elif name == 'manufactured': return 42 else: raise KeyError def bb_method(self): """Test Method""" pass bb_status = 'screechy' return BoboTraversable() def _makeBoboTraversableWithAcquisition(self): from OFS.SimpleItem import SimpleItem class BoboTraversableWithAcquisition(SimpleItem): """ A BoboTraversable which may use acquisition to find objects. This is similar to how the __bobo_traverse__ behaves). """ def __bobo_traverse__(self, request, name): from Acquisition import aq_get return aq_get(self, name) return BoboTraversableWithAcquisition() def _makeRestricted(self, name='dummy'): from OFS.SimpleItem import SimpleItem class Restricted(SimpleItem): """Instance we'll check with ProtectedMethodSecurityPolicy """ getId__roles__ = None # ACCESS_PUBLIC def getId(self): return self.id private__roles__ = () # ACCESS_PRIVATE def private(self): return 'private!' # not protected def ohno(self): return 'ohno!' return Restricted(name) def _setupSecurity(self, policy=None): from AccessControl import SecurityManager from AccessControl.SecurityManagement import noSecurityManager if policy is None: policy = self.oldPolicy noSecurityManager() SecurityManager.setSecurityPolicy(policy) def test_interfaces(self): from OFS.interfaces import ITraversable from OFS.Traversable import Traversable from zope.interface.verify import verifyClass verifyClass(ITraversable, Traversable) def testTraversePath(self): self.assertTrue('file' in self.folder1.objectIds()) self.assertTrue( self.folder1.unrestrictedTraverse(('', 'folder1', 'file'))) self.assertTrue(self.folder1.unrestrictedTraverse(('', 'folder1'))) def testTraverseURLNoSlash(self): self.assertTrue('file' in self.folder1.objectIds()) self.assertTrue(self.folder1.unrestrictedTraverse('/folder1/file')) self.assertTrue(self.folder1.unrestrictedTraverse('/folder1')) def testTraverseURLSlash(self): self.assertTrue('file' in self.folder1.objectIds()) self.assertTrue(self.folder1.unrestrictedTraverse('/folder1/file/')) self.assertTrue(self.folder1.unrestrictedTraverse('/folder1/')) def testTraverseToNone(self): self.assertRaises(KeyError, self.folder1.unrestrictedTraverse, ('', 'folder1', 'file2')) self.assertRaises(KeyError, self.folder1.unrestrictedTraverse, '/folder1/file2') self.assertRaises(KeyError, self.folder1.unrestrictedTraverse, '/folder1/file2/') def testTraverseMethodRestricted(self): from AccessControl import Unauthorized self.root.my = self._makeRestricted('my') my = self.root.my my.id = 'my' self._setupSecurity(ProtectedMethodSecurityPolicy()) r = my.restrictedTraverse('getId') self.assertEqual(r(), 'my') self.assertRaises(Unauthorized, my.restrictedTraverse, 'private') self.assertRaises(Unauthorized, my.restrictedTraverse, 'ohno') def testBoboTraverseToWrappedSubObj(self): # Verify it's possible to use __bobo_traverse__ with the # Zope security policy. self._setupSecurity() bb = self._makeBoboTraversable() self.assertRaises(KeyError, bb.restrictedTraverse, 'notfound') bb.restrictedTraverse('bb_subitem') def testBoboTraverseToMethod(self): # Verify it's possible to use __bobo_traverse__ to a method. self._setupSecurity() bb = self._makeBoboTraversable() self.assertTrue(bb.restrictedTraverse('bb_method') is not bb.bb_method) def testBoboTraverseToSimpleAttrValue(self): # Verify it's possible to use __bobo_traverse__ to a simple # python value self._setupSecurity() bb = self._makeBoboTraversable() self.assertEqual(bb.restrictedTraverse('bb_status'), 'screechy') def testBoboTraverseToNonAttrValue(self): # Verify it's possible to use __bobo_traverse__ to an # arbitrary manufactured object # Default security policy always seems to deny in this case, which # is fine, but to test the code branch we sub in the forgiving one self._setupSecurity(UnitTestSecurityPolicy()) bb = self._makeBoboTraversable() self.assertTrue(bb.restrictedTraverse('manufactured') is 42) def testBoboTraverseToAcquiredObject(self): # Verify it's possible to use a __bobo_traverse__ which retrieves # objects by acquisition from Acquisition import aq_inner self._setupSecurity() bb = self._makeBoboTraversableWithAcquisition() bb = bb.__of__(self.root) self.assertEqual(bb.restrictedTraverse('folder1'), bb.folder1) self.assertEqual(aq_inner(bb.restrictedTraverse('folder1')), self.root.folder1) def testBoboTraverseToAcquiredProtectedObject(self): # Verify it's possible to use a __bobo_traverse__ which retrieves # objects by acquisition from AccessControl import Unauthorized from AccessControl.Permissions import access_contents_information self._setupSecurity() folder = self.root.folder1 # restrict the ability to access the retrieved object itself folder.manage_permission(access_contents_information, [], 0) bb = self._makeBoboTraversableWithAcquisition() bb = bb.__of__(self.root) self.assertRaises(Unauthorized, bb.restrictedTraverse, 'folder1') def testBoboTraverseToAcquiredAttribute(self): # Verify it's possible to use __bobo_traverse__ to an acquired # attribute self._setupSecurity() folder = self.root.folder1 folder.stuff = 'stuff here' bb = self._makeBoboTraversableWithAcquisition() bb = bb.__of__(folder) self.assertEqual(bb.restrictedTraverse('stuff'), 'stuff here') def testBoboTraverseToAcquiredProtectedAttribute(self): # Verify that using __bobo_traverse__ to get an acquired but # protected attribute results in Unauthorized from AccessControl import Unauthorized from AccessControl.Permissions import access_contents_information self._setupSecurity() folder = self.root.folder1 # We protect the the attribute by restricting access to the parent folder.manage_permission(access_contents_information, [], 0) folder.stuff = 'stuff here' bb = self._makeBoboTraversableWithAcquisition() bb = bb.__of__(folder) self.assertRaises(Unauthorized, self.root.folder1.restrictedTraverse, 'stuff') def testBoboTraverseTraversalDefault(self): from OFS.SimpleItem import SimpleItem from ZPublisher.interfaces import UseTraversalDefault class BoboTraversableUseTraversalDefault(SimpleItem): """ A BoboTraversable class which may use "UseTraversalDefault" (dependent on "name") to indicate that standard traversal should be used. """ default = 'Default' def __bobo_traverse__(self, request, name): if name == 'normal': return 'Normal' raise UseTraversalDefault bb = BoboTraversableUseTraversalDefault() # normal access -- no traversal default used self.assertEqual(bb.unrestrictedTraverse('normal'), 'Normal') # use traversal default self.assertEqual(bb.unrestrictedTraverse('default'), 'Default') # test traversal default with acqires attribute si = SimpleItem() si.default_acquire = 'Default_Acquire' si.bb = bb self.assertEqual(si.unrestrictedTraverse('bb/default_acquire'), 'Default_Acquire') def testAcquiredAttributeDenial(self): # Verify that restrictedTraverse raises the right kind of exception # on denial of access to an acquired attribute. If it raises # AttributeError instead of Unauthorized, the user may never # be prompted for HTTP credentials. from AccessControl import Unauthorized from AccessControl.SecurityManagement import newSecurityManager self._setupSecurity(CruelSecurityPolicy()) newSecurityManager(None, self._makeUser().__of__(self.root)) self.root.stuff = 'stuff here' self.assertRaises(Unauthorized, self.app.folder1.restrictedTraverse, 'stuff') def testDefaultValueWhenUnathorized(self): # Test that traversing to an unauthorized object returns # the default when provided from AccessControl.SecurityManagement import newSecurityManager self._setupSecurity(CruelSecurityPolicy()) newSecurityManager(None, self._makeUser().__of__(self.root)) self.root.stuff = 'stuff here' self.assertEqual(self.root.folder1.restrictedTraverse('stuff', 42), 42) def testNotFoundIsRaised(self): from OFS.SimpleItem import SimpleItem from zExceptions import NotFound from operator import getitem self.folder1._setObject('foo', SimpleItem('foo')) self.assertRaises(AttributeError, getitem, self.folder1.foo, 'doesntexist') self.assertRaises(NotFound, self.folder1.unrestrictedTraverse, 'foo/doesntexist') self.assertRaises(TypeError, getitem, self.folder1.foo.isPrincipiaFolderish, 'doesntexist') self.assertRaises(NotFound, self.folder1.unrestrictedTraverse, 'foo/isPrincipiaFolderish/doesntexist') def testDefaultValueWhenNotFound(self): # Test that traversing to a non-existent object returns # the default when provided self._setupSecurity() self.assertEqual(self.root.restrictedTraverse('happy/happy', 'joy'), 'joy') def testTraverseUp(self): # Test that we can traverse upwards from Acquisition import aq_base self.assertTrue( aq_base(self.root.folder1.file.restrictedTraverse('../..')) is aq_base(self.root)) def testTraverseToNameStartingWithPlus(self): # Verify it's possible to traverse to a name such as +something self.assertTrue( self.folder1.unrestrictedTraverse('+something') is 'plus')
class PKEReporter(object): def __init__(self, db='zodb'): self._dbname = db self._config = get_config(db) self._storage = self._config.storages[0].open() self._conn = DB(self._storage).open() self._app = self._conn.root() self._size = self.get_total_count() def get_total_count(self): connmanager = self._storage._adapter.connmanager conn, cursor = connmanager.open() try: cursor.execute("SELECT count(zoid) from object_state") row = cursor.fetchone() return long(row[0]) finally: connmanager.close(conn, cursor) def update_progress(self, finished, total): fraction = finished / float(total) bar_width = 40 done = '=' * int(bar_width * fraction) undone = '-' * (bar_width - int(bar_width * fraction)) sys.stderr.write('[%s%s%s] %s%% complete\r' % (done, '|', undone, int(fraction*100))) sys.stderr.flush() def analyze(self, parent_oid, child_oid): parent_state = self._storage.load(parent_oid)[0] pickler = Analyzer(parent_state, child_oid) pickler.load() result = pickler.load() name = None # First try to get the name from the pickle state try: for k, v in result.iteritems(): if v is pickler._marker: name = k break except Exception: pass if not name: # Now load up the child and see if it has an id child = self._conn[child_oid] try: name = child.id except Exception: try: name = child.getId() except Exception: pass if not name: # Check the actual attributes on the parent parent = self._conn[parent_oid] try: for k, v in parent.__dict__.iteritems(): try: if v == child: name = k break except Exception: pass except AttributeError: # catch these errors - AttributeError: 'BTrees.OIBTree.OIBTree' object has no attribute '__dict__' pass return name, pickler.klass @staticmethod def oid_versions(oid): u64ed = u64(oid) oid_0xstyle = "0x%08x" % u64ed repred = repr(oid) return u64ed, oid_0xstyle, repred def report(self, oid, ancestors): parent_oid = ancestors[-2] parent_klass = None try: immediate_parent = self._conn[parent_oid] parent_klass = immediate_parent.__class__ path = immediate_parent.getPrimaryPath() except Exception: # Not a PrimaryPathObjectManager, do it manually path = [''] for (a, b) in zip(ancestors[:-2], ancestors[1:-1]): name, klass = self.analyze(a, b) path.append(name) parent_klass = klass path = filter(None, path) name, klass = self.analyze(*ancestors[-2:]) sys.stderr.write(' '*80) sys.stderr.flush() par_u64, par_0x, par_rep = self.oid_versions(parent_oid) oid_u64, oid_0x, oid_rep = self.oid_versions(oid) print """ FOUND DANGLING REFERENCE PATH {path} TYPE {type} OID {par_0x} {par_rep} {par_u64} Refers to a missing object: NAME {name} TYPE {klass} OID", {oid_0x} {oid_rep} {oid_u64} """.format(path='/'.join(path), type=parent_klass, name=name, klass=klass, par_u64=par_u64, par_0x=par_0x, par_rep=par_rep, oid_u64=oid_u64, oid_0x=oid_0x, oid_rep=oid_rep) def verify(self, root): seen = set() seen_add = seen.add path = () stack = deque([(root, path)]) reported = 0 while stack: oid, path = stack.popleft() seen_add(oid) if not len(seen) % 1000: self.update_progress(len(seen), self._size) try: state = self._storage.load(oid)[0] except POSKeyError: self.report(oid, path) reported += 1 else: refs = get_refs(state) stack.extend((o, path + (o,)) for o in set(refs) - seen) return reported, len(seen), self._size def run(self): print print "="*50 print print " DATABASE INTEGRITY SCAN: ", self._dbname print print "="*50 oid = '\x00\x00\x00\x00\x00\x00\x00\x01' reported, scanned, total = self.verify(oid) sys.stderr.write(' '*80) sys.stderr.flush() print print "SUMMARY:" print "Found", reported, "dangling references" print "Scanned", scanned, "out of", total, "reachable objects" if total > scanned: print "(Run zenossdbpack to garbage collect unreachable objects)" print