diff --git a/radicale/storage/multifilesystem/__init__.py b/radicale/storage/multifilesystem/__init__.py index 1b908239..2f273a7f 100644 --- a/radicale/storage/multifilesystem/__init__.py +++ b/radicale/storage/multifilesystem/__init__.py @@ -25,6 +25,7 @@ Uses one folder per collection and one file per collection entry. """ import os +import sys import time from typing import ClassVar, Iterator, Optional, Type @@ -90,6 +91,27 @@ class Storage( def __init__(self, configuration: config.Configuration) -> None: super().__init__(configuration) - self._makedirs_synced(self._filesystem_folder) logger.info("storage location: %r", self._filesystem_folder) - logger.info("storage cache subfolder usage for item: %s", self._use_cache_subfolder_for_item) + self._makedirs_synced(self._filesystem_folder) + logger.info("storage location subfolder: %r", self._get_collection_root_folder()) + logger.info("storage cache subfolder usage for 'item': %s", self._use_cache_subfolder_for_item) + logger.info("storage cache subfolder usage for 'history': %s", self._use_cache_subfolder_for_history) + logger.info("storage cache subfolder usage for 'sync-token': %s", self._use_cache_subfolder_for_synctoken) + if self._use_cache_subfolder_for_item is True or self._use_cache_subfolder_for_history is True or self._use_cache_subfolder_for_synctoken is True: + logger.info("storage cache subfolder: %r", self._get_collection_cache_folder()) + self._makedirs_synced(self._get_collection_cache_folder()) + if sys.platform != "win32": + if not self._folder_umask: + # retrieve current umask by setting a dummy umask + current_umask = os.umask(0o0022) + logger.info("storage folder umask (from system): '%04o'", current_umask) + # reset to original + os.umask(current_umask) + else: + try: + config_umask = int(self._folder_umask, 8) + except: + logger.critical("storage folder umask defined but invalid: '%s'", self._folder_umask) + raise + logger.info("storage folder umask defined: '%04o'", config_umask) + self._config_umask = config_umask diff --git a/radicale/storage/multifilesystem/base.py b/radicale/storage/multifilesystem/base.py index 8d9f1940..67071d8e 100644 --- a/radicale/storage/multifilesystem/base.py +++ b/radicale/storage/multifilesystem/base.py @@ -69,8 +69,13 @@ class StorageBase(storage.BaseStorage): _collection_class: ClassVar[Type["multifilesystem.Collection"]] _filesystem_folder: str + _filesystem_cache_folder: str _filesystem_fsync: bool _use_cache_subfolder_for_item: bool + _use_cache_subfolder_for_history: bool + _use_cache_subfolder_for_synctoken: bool + _folder_umask: str + _config_umask: int def __init__(self, configuration: config.Configuration) -> None: super().__init__(configuration) @@ -78,15 +83,30 @@ class StorageBase(storage.BaseStorage): "storage", "filesystem_folder") self._filesystem_fsync = configuration.get( "storage", "_filesystem_fsync") + self._filesystem_cache_folder = configuration.get( + "storage", "filesystem_cache_folder") self._use_cache_subfolder_for_item = configuration.get( "storage", "use_cache_subfolder_for_item") + self._use_cache_subfolder_for_history = configuration.get( + "storage", "use_cache_subfolder_for_history") + self._use_cache_subfolder_for_synctoken = configuration.get( + "storage", "use_cache_subfolder_for_synctoken") + self._folder_umask = configuration.get( + "storage", "folder_umask") def _get_collection_root_folder(self) -> str: return os.path.join(self._filesystem_folder, "collection-root") - def _get_collection_cache_folder(self, path, folder, subfolder) -> str: + def _get_collection_cache_folder(self) -> str: + return os.path.join(self._filesystem_cache_folder, "collection-cache") + + def _get_collection_cache_subfolder(self, path, folder, subfolder) -> str: if (self._use_cache_subfolder_for_item is True) and (subfolder == "item"): - path = path.replace(os.path.join(self._filesystem_folder, "collection-root"), os.path.join(self._filesystem_folder, "collection-cache")) + path = path.replace(self._get_collection_root_folder(), self._get_collection_cache_folder()) + elif (self._use_cache_subfolder_for_history is True) and (subfolder == "history"): + path = path.replace(self._get_collection_root_folder(), self._get_collection_cache_folder()) + elif (self._use_cache_subfolder_for_synctoken is True) and (subfolder == "sync-token"): + path = path.replace(self._get_collection_root_folder(), self._get_collection_cache_folder()) return os.path.join(path, folder, subfolder) def _fsync(self, f: IO[AnyStr]) -> None: