create: handle BackupOSError on a per-path level in one spot

This commit is contained in:
Marian Beermann 2017-02-14 18:58:34 +01:00
parent 22464295cf
commit 73990b878f
1 changed files with 81 additions and 84 deletions

View File

@ -29,7 +29,7 @@ import borg
from . import __version__ from . import __version__
from . import helpers from . import helpers
from .archive import Archive, ArchiveChecker, ArchiveRecreater, Statistics, is_special from .archive import Archive, ArchiveChecker, ArchiveRecreater, Statistics, is_special
from .archive import BackupOSError from .archive import BackupOSError, backup_io
from .cache import Cache from .cache import Cache
from .constants import * # NOQA from .constants import * # NOQA
from .crc32 import crc32 from .crc32 import crc32
@ -396,15 +396,20 @@ class Archiver:
def _process(self, archive, cache, matcher, exclude_caches, exclude_if_present, def _process(self, archive, cache, matcher, exclude_caches, exclude_if_present,
keep_exclude_tags, skip_inodes, path, restrict_dev, keep_exclude_tags, skip_inodes, path, restrict_dev,
read_special=False, dry_run=False, st=None): read_special=False, dry_run=False, st=None):
"""
Process *path* recursively according to the various parameters.
*st* (if given) is a *os.stat_result* object for *path*.
This should only raise on critical errors. Per-item errors must be handled within this method.
"""
if not matcher.match(path): if not matcher.match(path):
self.print_file_status('x', path) self.print_file_status('x', path)
return return
if st is None:
try: try:
if st is None:
with backup_io('stat'):
st = os.lstat(path) st = os.lstat(path)
except OSError as e:
self.print_warning('%s: stat: %s', path, e)
return
if (st.st_ino, st.st_dev) in skip_inodes: if (st.st_ino, st.st_dev) in skip_inodes:
return return
# if restrict_dev is given, we do not want to recurse into a new filesystem, # if restrict_dev is given, we do not want to recurse into a new filesystem,
@ -413,20 +418,13 @@ class Archiver:
recurse = restrict_dev is None or st.st_dev == restrict_dev recurse = restrict_dev is None or st.st_dev == restrict_dev
status = None status = None
# Ignore if nodump flag is set # Ignore if nodump flag is set
try: with backup_io('flags'):
if get_flags(path, st) & stat.UF_NODUMP: if get_flags(path, st) & stat.UF_NODUMP:
self.print_file_status('x', path) self.print_file_status('x', path)
return return
except OSError as e:
self.print_warning('%s: flags: %s', path, e)
return
if stat.S_ISREG(st.st_mode): if stat.S_ISREG(st.st_mode):
if not dry_run: if not dry_run:
try:
status = archive.process_file(path, st, cache, self.ignore_inode) status = archive.process_file(path, st, cache, self.ignore_inode)
except BackupOSError as e:
status = 'E'
self.print_warning('%s: %s', path, e)
elif stat.S_ISDIR(st.st_mode): elif stat.S_ISDIR(st.st_mode):
if recurse: if recurse:
tag_paths = dir_is_tagged(path, exclude_caches, exclude_if_present) tag_paths = dir_is_tagged(path, exclude_caches, exclude_if_present)
@ -441,12 +439,8 @@ class Archiver:
if not dry_run: if not dry_run:
status = archive.process_dir(path, st) status = archive.process_dir(path, st)
if recurse: if recurse:
try: with backup_io('scandir'):
entries = helpers.scandir_inorder(path) entries = helpers.scandir_inorder(path)
except OSError as e:
status = 'E'
self.print_warning('%s: scandir: %s', path, e)
else:
for dirent in entries: for dirent in entries:
normpath = os.path.normpath(dirent.path) normpath = os.path.normpath(dirent.path)
self._process(archive, cache, matcher, exclude_caches, exclude_if_present, self._process(archive, cache, matcher, exclude_caches, exclude_if_present,
@ -491,6 +485,9 @@ class Archiver:
else: else:
self.print_warning('Unknown file type: %s', path) self.print_warning('Unknown file type: %s', path)
return return
except BackupOSError as e:
self.print_warning('%s: %s', path, e)
status = 'E'
# Status output # Status output
if status is None: if status is None:
if not dry_run: if not dry_run: