From 05a4285f54feb076b22e71a13a777837546a78f5 Mon Sep 17 00:00:00 2001 From: Unrud Date: Fri, 5 Aug 2016 17:17:37 +0200 Subject: [PATCH 1/3] Durable creation of intermediate directories --- radicale/storage.py | 20 ++++++++++++++++---- 1 file changed, 16 insertions(+), 4 deletions(-) diff --git a/radicale/storage.py b/radicale/storage.py index d14797f..e70028c 100644 --- a/radicale/storage.py +++ b/radicale/storage.py @@ -406,6 +406,19 @@ class Collection(BaseCollection): return file_name raise FileExistsError(errno.EEXIST, "No usable file name found") + @classmethod + def _makedirs_synced(cls, filesystem_path, exist_ok=False): + if os.path.isdir(filesystem_path) and exist_ok: + return + parent_filesystem_path = os.path.dirname(filesystem_path) + # Prevent infinite loop + if filesystem_path != parent_filesystem_path: + # Create parent dirs recursively + cls._makedirs_synced(parent_filesystem_path, exist_ok=True) + # Possible race! + os.makedirs(filesystem_path, exist_ok=exist_ok) + sync_directory(parent_filesystem_path) + @classmethod def discover(cls, path, depth="0"): if path is None: @@ -476,11 +489,11 @@ class Collection(BaseCollection): if not props.get("tag") and collection: props["tag"] = collection[0].name if not props: - os.makedirs(filesystem_path, exist_ok=True) + cls._makedirs_synced(filesystem_path, exist_ok=True) return cls(sane_path, principal=principal) parent_dir = os.path.dirname(filesystem_path) - os.makedirs(parent_dir, exist_ok=True) + cls._makedirs_synced(parent_dir, exist_ok=True) # Create a temporary directory with an unsafe name with TemporaryDirectory( @@ -679,8 +692,7 @@ class Collection(BaseCollection): if not cls._lock_file: folder = os.path.expanduser( cls.configuration.get("storage", "filesystem_folder")) - if not os.path.exists(folder): - os.makedirs(folder, exist_ok=True) + cls._makedirs_synced(folder, exist_ok=True) lock_path = os.path.join(folder, ".Radicale.lock") cls._lock_file = open(lock_path, "w+") # Set access rights to a necessary minimum to prevent locking From 6c3e59fd11400734a8b9ec9942858724a36e3f1d Mon Sep 17 00:00:00 2001 From: Unrud Date: Fri, 5 Aug 2016 17:19:57 +0200 Subject: [PATCH 2/3] Make sure that the root collection exists. Since the collections are not directly in **filesystem_path** anymore, the folder is not created by ``Collection.acquire_lock``. --- radicale/storage.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/radicale/storage.py b/radicale/storage.py index e70028c..cab6641 100644 --- a/radicale/storage.py +++ b/radicale/storage.py @@ -262,6 +262,8 @@ class BaseCollection: The ``path`` is relative. + The root collection "/" must always exist. + """ raise NotImplementedError @@ -433,6 +435,8 @@ class Collection(BaseCollection): # Try to guess if the path leads to a collection or an item folder = cls._get_collection_root_folder() + # Create the root collection + cls._makedirs_synced(folder, exist_ok=True) try: filesystem_path = path_to_filesystem(folder, sane_path) except ValueError: From 07dc71fd73228ea327bb36c275516782663dfcf4 Mon Sep 17 00:00:00 2001 From: Unrud Date: Fri, 5 Aug 2016 17:22:21 +0200 Subject: [PATCH 3/3] Update comment --- radicale/storage.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/radicale/storage.py b/radicale/storage.py index cab6641..34e7a90 100644 --- a/radicale/storage.py +++ b/radicale/storage.py @@ -433,7 +433,6 @@ class Collection(BaseCollection): if not attributes[0]: attributes.pop() - # Try to guess if the path leads to a collection or an item folder = cls._get_collection_root_folder() # Create the root collection cls._makedirs_synced(folder, exist_ok=True) @@ -443,6 +442,7 @@ class Collection(BaseCollection): # Path is unsafe return + # Check if the path exists and if it leads to a collection or an item if not os.path.isdir(filesystem_path): if attributes and os.path.isfile(filesystem_path): href = attributes.pop()