# HG changeset patch # User Goffi # Date 1718705205 -7200 # Node ID 64a85ce8be700917720a69cfaf481c38506bad75 # Parent 51d004e5078608999ed307533d25a11d657be938 memory (file): avoid race condition when creating parent path directories. diff -r 51d004e50786 -r 64a85ce8be70 libervia/backend/memory/memory.py --- a/libervia/backend/memory/memory.py Thu Jun 13 13:22:41 2024 +0200 +++ b/libervia/backend/memory/memory.py Tue Jun 18 12:06:45 2024 +0200 @@ -251,6 +251,7 @@ self._cache_path = Path(self.config_get("", "local_dir"), C.CACHE_DIR) self.admins = self.config_get("", "admins_list", []) self.admin_jids = set() + self._file_path_lock = defer.DeferredLock() async def initialise(self): @@ -1706,28 +1707,36 @@ owner = self.get_files_owner(client, owner, peer_jid, file_id, parent) if path is not None: - path = str(path) - # _get_parent_dir will check permissions if peer_jid is set, so we use owner - parent, remaining_path_elts = await self._get_parent_dir( - client, path, parent, namespace, owner, owner, perms_to_check - ) - # if remaining directories don't exist, we have to create them - for new_dir in remaining_path_elts: - new_dir_id = shortuuid.uuid() - await self.storage.set_file( - client, - name=new_dir, - file_id=new_dir_id, - version="", - parent=parent, - type_=C.FILE_TYPE_DIRECTORY, - namespace=namespace, - created=time.time(), - owner=owner, - access=access, - extra={}, + # We use a lock to avoid race condition leading to duplicate directories with + # same name and parent. + await self._file_path_lock.acquire() + try: + + path = str(path) + # _get_parent_dir will check permissions if peer_jid is set, so we use owner + parent, remaining_path_elts = await self._get_parent_dir( + client, path, parent, namespace, owner, owner, perms_to_check ) - parent = new_dir_id + # if remaining directories don't exist, we have to create them + for new_dir in remaining_path_elts: + new_dir_id = shortuuid.uuid() + await self.storage.set_file( + client, + name=new_dir, + file_id=new_dir_id, + version="", + parent=parent, + type_=C.FILE_TYPE_DIRECTORY, + namespace=namespace, + created=time.time(), + owner=owner, + access=access, + extra={}, + ) + parent = new_dir_id + finally: + self._file_path_lock.release() + elif parent is None: parent = ""