1
0
Fork 0
mirror of https://github.com/Kozea/Radicale.git synced 2025-06-26 16:45:52 +00:00
Radicale/radicale/storage/multifilesystem/verify.py

91 lines
4 KiB
Python
Raw Normal View History

2021-12-08 21:45:42 +01:00
# This file is part of Radicale - CalDAV and CardDAV server
2018-09-04 03:33:50 +02:00
# Copyright © 2014 Jean-Marc Martins
# Copyright © 2012-2017 Guillaume Ayoub
2024-06-09 11:13:38 +02:00
# Copyright © 2017-2021 Unrud <unrud@outlook.com>
# Copyright © 2024-2024 Peter Bieringer <pb@bieringer.de>
2018-09-04 03:33:50 +02:00
#
# This library is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This library is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with Radicale. If not, see <http://www.gnu.org/licenses/>.
2021-07-26 20:56:47 +02:00
from typing import Iterator, Optional, Set
2018-09-04 03:33:50 +02:00
2021-07-26 20:56:47 +02:00
from radicale import pathutils, storage, types
2018-09-04 03:33:50 +02:00
from radicale.log import logger
2021-07-26 20:56:47 +02:00
from radicale.storage.multifilesystem.base import StorageBase
from radicale.storage.multifilesystem.discover import StoragePartDiscover
2018-09-04 03:33:50 +02:00
2021-07-26 20:56:47 +02:00
class StoragePartVerify(StoragePartDiscover, StorageBase):
def verify(self) -> bool:
2018-09-04 03:33:50 +02:00
item_errors = collection_errors = 0
2021-07-26 20:56:47 +02:00
@types.contextmanager
def exception_cm(sane_path: str, href: Optional[str]
) -> Iterator[None]:
2018-09-04 03:33:50 +02:00
nonlocal item_errors, collection_errors
try:
yield
except Exception as e:
2021-07-26 20:56:47 +02:00
if href is not None:
2018-09-04 03:33:50 +02:00
item_errors += 1
name = "item %r in %r" % (href, sane_path)
else:
collection_errors += 1
name = "collection %r" % sane_path
logger.error("Invalid %s: %s", name, e, exc_info=True)
remaining_sane_paths = [""]
while remaining_sane_paths:
sane_path = remaining_sane_paths.pop(0)
path = pathutils.unstrip_path(sane_path, True)
logger.info("Verifying path %r", sane_path)
count = 0
is_collection = True
2021-07-26 20:56:47 +02:00
with exception_cm(sane_path, None):
2018-09-04 03:33:50 +02:00
saved_item_errors = item_errors
2021-07-26 20:56:47 +02:00
collection: Optional[storage.BaseCollection] = None
uids: Set[str] = set()
2018-09-04 03:33:50 +02:00
has_child_collections = False
for item in self.discover(path, "1", exception_cm):
2018-09-04 03:33:50 +02:00
if not collection:
2021-07-26 20:56:47 +02:00
assert isinstance(item, storage.BaseCollection)
2018-09-04 03:33:50 +02:00
collection = item
collection.get_meta()
if not collection.tag:
is_collection = False
logger.info("Skip !collection %r", sane_path)
2018-09-04 03:33:50 +02:00
continue
if isinstance(item, storage.BaseCollection):
has_child_collections = True
remaining_sane_paths.append(item.path)
elif item.uid in uids:
2018-09-09 14:58:43 +02:00
logger.error("Invalid item %r in %r: UID conflict %r",
item.href, sane_path, item.uid)
2018-09-04 03:33:50 +02:00
else:
uids.add(item.uid)
count += 1
logger.debug("Verified in %r item %r",
sane_path, item.href)
2021-07-26 20:56:47 +02:00
assert collection
2018-09-04 03:33:50 +02:00
if item_errors == saved_item_errors:
if is_collection:
collection.sync()
2021-07-26 20:56:46 +02:00
if has_child_collections and collection.tag:
2018-09-09 14:58:43 +02:00
logger.error("Invalid collection %r: %r must not have "
"child collections", sane_path,
2021-07-26 20:56:46 +02:00
collection.tag)
if is_collection:
logger.info("Verified collect %r (items: %d)", sane_path, count)
2018-09-04 03:33:50 +02:00
return item_errors == 0 and collection_errors == 0