From 417b472fa79f665cbe27c51b2d5372989ac386b8 Mon Sep 17 00:00:00 2001
From: Daira Hopwood <daira@jacaranda.org>
Date: Tue, 8 Apr 2014 22:43:24 +0100
Subject: [PATCH] Add backend support for listing container contents. refs
 #1759

Signed-off-by: Daira Hopwood <daira@jacaranda.org>
---
 src/allmydata/interfaces.py                           |  7 +++++++
 src/allmydata/storage/backends/cloud/cloud_backend.py |  5 +++++
 src/allmydata/storage/backends/disk/disk_backend.py   |  6 ++++++
 src/allmydata/storage/backends/null/null_backend.py   | 10 ++++++++++
 4 files changed, 28 insertions(+)

diff --git a/src/allmydata/interfaces.py b/src/allmydata/interfaces.py
index 2d103bf2..fb04775c 100644
--- a/src/allmydata/interfaces.py
+++ b/src/allmydata/interfaces.py
@@ -366,6 +366,13 @@ class IStorageBackend(Interface):
         created. It is an error to attempt to create a container that already exists.
         """
 
+    def list_container(prefix=str):
+        """
+        Return a Deferred that fires with a list of ContainerItems for all
+        objects in the backend container. If prefix is given, restrict the
+        list to objects having keys with the given prefix.
+        """
+
 
 class IShareSet(Interface):
     def get_storage_index():
diff --git a/src/allmydata/storage/backends/cloud/cloud_backend.py b/src/allmydata/storage/backends/cloud/cloud_backend.py
index dbf91461..217864f7 100644
--- a/src/allmydata/storage/backends/cloud/cloud_backend.py
+++ b/src/allmydata/storage/backends/cloud/cloud_backend.py
@@ -100,6 +100,11 @@ class CloudBackend(Backend):
     def create_container(self):
         return self._container.create()
 
+    def list_container(self, prefix=''):
+        d = self._container.list_objects(prefix)
+        d.addCallback(lambda listing: listing.contents)
+        return d
+
 
 class CloudShareSet(ShareSet):
     implements(IShareSet)
diff --git a/src/allmydata/storage/backends/disk/disk_backend.py b/src/allmydata/storage/backends/disk/disk_backend.py
index 5255cdfe..a82d51b0 100644
--- a/src/allmydata/storage/backends/disk/disk_backend.py
+++ b/src/allmydata/storage/backends/disk/disk_backend.py
@@ -118,6 +118,12 @@ class DiskBackend(Backend):
         # so must use its TubID as a permutation-seed.
         return bool(set(fileutil.listdir(self._sharedir)) - set(["incoming"]))
 
+    def list_container(self, prefix=''):
+        def _not_implemented():
+            raise NotImplementedError("the disk backend does not support listing container contents.\n" +
+                                      "Use 'tahoe debug catalog-shares' instead.")
+        return defer.execute(_not_implemented)
+
 
 class DiskShareSet(ShareSet):
     implements(IShareSet)
diff --git a/src/allmydata/storage/backends/null/null_backend.py b/src/allmydata/storage/backends/null/null_backend.py
index b8e80c3d..baee824a 100644
--- a/src/allmydata/storage/backends/null/null_backend.py
+++ b/src/allmydata/storage/backends/null/null_backend.py
@@ -6,9 +6,11 @@ from allmydata.interfaces import IStorageBackend, IShareSet, IShareBase, \
     IShareForReading, IShareForWriting, IMutableShare
 
 from allmydata.util.assertutil import precondition
+from allmydata.util.listutil import concat
 from allmydata.storage.backends.base import Backend, ShareSet, empty_check_testv
 from allmydata.storage.bucket import BucketWriter
 from allmydata.storage.common import si_b2a
+from allmydata.storage.backends.base import ContainerItem
 
 
 def configure_null_backend(storedir, config):
@@ -51,6 +53,9 @@ class NullBackend(Backend):
     def fill_in_space_stats(self, stats):
         pass
 
+    def list_container(self, prefix=''):
+        return defer.succeed(concat([s._list_items() for s in self.get_sharesets_for_prefix(prefix)]))
+
 
 class NullShareSet(ShareSet):
     implements(IShareSet)
@@ -69,6 +74,11 @@ class NullShareSet(ShareSet):
     def get_overhead(self):
         return 0
 
+    def _list_items(self):
+        sistr = si_b2a(self.storage_index)
+        return [ContainerItem("shares/%s/%s/%d" % (sistr[:2], sistr, shnum), None, "", 0, "STANDARD", None)
+                for shnum in set.union(self._immutable_shnums, self._mutable_shnums)]
+
     def _locked_get_shares(self):
         shares = {}
         for shnum in self._immutable_shnums:
-- 
2.45.2