From 7d804c0b62975b4059dea757dbc2fbd0320c1497 Mon Sep 17 00:00:00 2001 From: Lucas Di Pentima Date: Mon, 17 Dec 2018 18:18:52 -0300 Subject: [PATCH] 14539: Persists empty directories by adding a '\056' empty file. Also: * Fixes test * Errors out when trying to open a file/dir with '\056' on its path. Arvados-DCO-1.1-Signed-off-by: Lucas Di Pentima --- sdk/python/arvados/collection.py | 16 +++++++++++++++- sdk/python/tests/test_collections.py | 2 +- 2 files changed, 16 insertions(+), 2 deletions(-) diff --git a/sdk/python/arvados/collection.py b/sdk/python/arvados/collection.py index 627f0346db..c2517c6189 100644 --- a/sdk/python/arvados/collection.py +++ b/sdk/python/arvados/collection.py @@ -600,6 +600,9 @@ class RichCollectionBase(CollectionBase): pathcomponents = path.split("/", 1) if pathcomponents[0]: + # Don't allow naming files/dirs \\056 + if pathcomponents[0] == "\\056": + raise IOError(errno.EINVAL, "Invalid name", pathcomponents[0]) item = self._items.get(pathcomponents[0]) if len(pathcomponents) == 1: if item is None: @@ -1058,7 +1061,9 @@ class RichCollectionBase(CollectionBase): if stream: buf.append(" ".join(normalize_stream(stream_name, stream)) + "\n") for dirname in [s for s in sorted_keys if isinstance(self[s], RichCollectionBase)]: - buf.append(self[dirname].manifest_text(stream_name=os.path.join(stream_name, dirname), strip=strip, normalize=True, only_committed=only_committed)) + buf.append(self[dirname].manifest_text( + stream_name=os.path.join(stream_name, dirname), + strip=strip, normalize=True, only_committed=only_committed)) return "".join(buf) else: if strip: @@ -1833,6 +1838,15 @@ class Subcollection(RichCollectionBase): self.name = newname self.lock = self.parent.root_collection().lock + @synchronized + def _get_manifest_text(self, stream_name, strip, normalize, only_committed=False): + """Encode empty directories by using an \056-named (".") empty file""" + if len(self._items) == 0: + return "%s %s 0:0:\\056\n" % (stream_name, config.EMPTY_BLOCK_LOCATOR) + return super(Subcollection, self)._get_manifest_text(stream_name, + strip, normalize, + only_committed) + class CollectionReader(Collection): """A read-only collection object. diff --git a/sdk/python/tests/test_collections.py b/sdk/python/tests/test_collections.py index de01006741..b5c0c1c524 100644 --- a/sdk/python/tests/test_collections.py +++ b/sdk/python/tests/test_collections.py @@ -955,7 +955,7 @@ class NewCollectionTestCase(unittest.TestCase, CollectionTestMixin): def test_remove_in_subdir(self): c = Collection('. 781e5e245d69b566979b86e28d23f2c7+10 0:10:count1.txt\n./foo 781e5e245d69b566979b86e28d23f2c7+10 0:10:count2.txt\n') c.remove("foo/count2.txt") - self.assertEqual(". 781e5e245d69b566979b86e28d23f2c7+10 0:10:count1.txt\n", c.portable_manifest_text()) + self.assertEqual(". 781e5e245d69b566979b86e28d23f2c7+10 0:10:count1.txt\n./foo d41d8cd98f00b204e9800998ecf8427e+0 0:0:\\056\n", c.portable_manifest_text()) def test_remove_empty_subdir(self): c = Collection('. 781e5e245d69b566979b86e28d23f2c7+10 0:10:count1.txt\n./foo 781e5e245d69b566979b86e28d23f2c7+10 0:10:count2.txt\n') -- 2.30.2