Merge pull request #2722 from ThomasWaldmann/backports5

even more backports
This commit is contained in:
TW 2017-06-23 16:24:33 +02:00 committed by GitHub
commit 04aa426334
7 changed files with 45 additions and 11 deletions

View File

@ -39,7 +39,7 @@ static uint32_t table_base[] =
0xc5ae37bb, 0xa76ce12a, 0x8150d8f3, 0x2ec29218, 0xa35f0984, 0x48c0647e, 0x0b5ff98c, 0x71893f7b 0xc5ae37bb, 0xa76ce12a, 0x8150d8f3, 0x2ec29218, 0xa35f0984, 0x48c0647e, 0x0b5ff98c, 0x71893f7b
}; };
#define BARREL_SHIFT(v, shift) ( ((v) << shift) | ((v) >> (32 - shift)) ) #define BARREL_SHIFT(v, shift) ( ((v) << shift) | ((v) >> ((32 - shift) & 0x1f)) )
size_t pagemask; size_t pagemask;

View File

@ -381,7 +381,7 @@ Number of files: {0.stats.nfiles}'''.format(
path = os.path.join(dest, item[b'path']) path = os.path.join(dest, item[b'path'])
# Attempt to remove existing files, ignore errors on failure # Attempt to remove existing files, ignore errors on failure
try: try:
st = os.lstat(path) st = os.stat(path, follow_symlinks=False)
if stat.S_ISDIR(st.st_mode): if stat.S_ISDIR(st.st_mode):
os.rmdir(path) os.rmdir(path)
else: else:
@ -472,7 +472,7 @@ Number of files: {0.stats.nfiles}'''.format(
if fd: if fd:
os.fchown(fd, uid, gid) os.fchown(fd, uid, gid)
else: else:
os.lchown(path, uid, gid) os.chown(path, uid, gid, follow_symlinks=False)
except OSError: except OSError:
pass pass
if fd: if fd:

View File

@ -21,7 +21,7 @@ import collections
from . import __version__ from . import __version__
from .helpers import Error, location_validator, archivename_validator, format_line, format_time, format_file_size, \ from .helpers import Error, location_validator, archivename_validator, format_line, format_time, format_file_size, \
parse_pattern, PathPrefixPattern, to_localtime, timestamp, safe_timestamp, bin_to_hex, \ parse_pattern, PathPrefixPattern, to_localtime, timestamp, safe_timestamp, bin_to_hex, \
get_cache_dir, prune_within, prune_split, \ get_cache_dir, prune_within, prune_split, check_python, \
Manifest, NoManifestError, remove_surrogates, update_excludes, format_archive, check_extension_modules, Statistics, \ Manifest, NoManifestError, remove_surrogates, update_excludes, format_archive, check_extension_modules, Statistics, \
dir_is_tagged, bigint_to_int, ChunkerParams, CompressionSpec, PrefixSpec, is_slow_msgpack, yes, sysinfo, \ dir_is_tagged, bigint_to_int, ChunkerParams, CompressionSpec, PrefixSpec, is_slow_msgpack, yes, sysinfo, \
EXIT_SUCCESS, EXIT_WARNING, EXIT_ERROR, log_multi, PatternMatcher, ErrorIgnoringTextIOWrapper, set_ec, \ EXIT_SUCCESS, EXIT_WARNING, EXIT_ERROR, log_multi, PatternMatcher, ErrorIgnoringTextIOWrapper, set_ec, \
@ -293,7 +293,7 @@ class Archiver:
path = os.path.normpath(path) path = os.path.normpath(path)
if args.one_file_system: if args.one_file_system:
try: try:
restrict_dev = os.lstat(path).st_dev restrict_dev = os.stat(path, follow_symlinks=False).st_dev
except OSError as e: except OSError as e:
self.print_warning('%s: %s', path, e) self.print_warning('%s: %s', path, e)
continue continue
@ -346,7 +346,7 @@ class Archiver:
try: try:
with backup_io(): with backup_io():
st = os.lstat(path) st = os.stat(path, follow_symlinks=False)
if (st.st_ino, st.st_dev) in skip_inodes: if (st.st_ino, st.st_dev) in skip_inodes:
return return
# Entering a new filesystem? # Entering a new filesystem?
@ -2079,13 +2079,17 @@ class Archiver:
update_excludes(args) update_excludes(args)
return args return args
def prerun_checks(self, logger):
check_python()
check_extension_modules()
def run(self, args): def run(self, args):
os.umask(args.umask) # early, before opening files os.umask(args.umask) # early, before opening files
self.lock_wait = args.lock_wait self.lock_wait = args.lock_wait
# This works around http://bugs.python.org/issue9351 # This works around http://bugs.python.org/issue9351
func = getattr(args, 'func', None) or getattr(args, 'fallback_func') func = getattr(args, 'func', None) or getattr(args, 'fallback_func')
setup_logging(level=args.log_level, is_serve=func == self.do_serve) # do not use loggers before this! setup_logging(level=args.log_level, is_serve=func == self.do_serve) # do not use loggers before this!
check_extension_modules() self.prerun_checks(logger)
if is_slow_msgpack(): if is_slow_msgpack():
logger.warning("Using a pure-python msgpack! This will result in lower performance.") logger.warning("Using a pure-python msgpack! This will result in lower performance.")
return set_ec(func(args)) return set_ec(func(args))

View File

@ -48,11 +48,11 @@ cdef class Chunker:
return chunker_process(self.chunker) return chunker_process(self.chunker)
def buzhash(unsigned char *data, unsigned long seed): def buzhash(data, unsigned long seed):
cdef uint32_t *table cdef uint32_t *table
cdef uint32_t sum cdef uint32_t sum
table = buzhash_init_table(seed & 0xffffffff) table = buzhash_init_table(seed & 0xffffffff)
sum = c_buzhash(data, len(data), table) sum = c_buzhash(<const unsigned char *> data, len(data), table)
free(table) free(table)
return sum return sum

View File

@ -115,6 +115,16 @@ class MandatoryFeatureUnsupported(Error):
"""Unsupported repository feature(s) {}. A newer version of borg is required to access this repository.""" """Unsupported repository feature(s) {}. A newer version of borg is required to access this repository."""
class PythonLibcTooOld(Error):
"""FATAL: this Python was compiled for a too old (g)libc and misses required functionality."""
def check_python():
required_funcs = {os.stat, os.utime, os.chown}
if not os.supports_follow_symlinks.issuperset(required_funcs):
raise PythonLibcTooOld
def check_extension_modules(): def check_extension_modules():
from . import platform, compress from . import platform, compress
if hashindex.API_VERSION != '1.0_01': if hashindex.API_VERSION != '1.0_01':

View File

@ -73,8 +73,8 @@ class BaseTestCase(unittest.TestCase):
for filename in diff.common: for filename in diff.common:
path1 = os.path.join(diff.left, filename) path1 = os.path.join(diff.left, filename)
path2 = os.path.join(diff.right, filename) path2 = os.path.join(diff.right, filename)
s1 = os.lstat(path1) s1 = os.stat(path1, follow_symlinks=False)
s2 = os.lstat(path2) s2 = os.stat(path2, follow_symlinks=False)
# Assume path2 is on FUSE if st_dev is different # Assume path2 is on FUSE if st_dev is different
fuse = s1.st_dev != s2.st_dev fuse = s1.st_dev != s2.st_dev
attrs = ['st_mode', 'st_uid', 'st_gid', 'st_rdev'] attrs = ['st_mode', 'st_uid', 'st_gid', 'st_rdev']

View File

@ -20,6 +20,26 @@ There are different ways to install |project_name|:
have the latest code or use revision control (each release is have the latest code or use revision control (each release is
tagged). tagged).
.. _installation-requirements:
Pre-Installation Considerations
-------------------------------
(G)LIBC requirements
--------------------
Borg uses some filesytem functions from Python's `os` standard library module
with `follow_symlinks=False`. These are implemented since quite a while with
the non-symlink-following (g)libc functions like e.g. `lstat` or `lutimes`
(not: `stat` or `utimes`).
Some stoneage systems (like RHEL/CentOS 5) and also Python interpreter binaries
compiled to be able to run on such systems (like Python installed via Anaconda)
might miss these functions and Borg won't be able to work correctly.
This issue will be detected early and Borg will abort with a fatal error.
For the Borg binaries, there are additional (g)libc requirements, see below.
.. _distribution-package: .. _distribution-package:
Distribution Package Distribution Package