diff --git a/README.rst b/README.rst index 07e8b0d39..6655e77a6 100644 --- a/README.rst +++ b/README.rst @@ -75,6 +75,7 @@ Main features * FreeBSD * OpenBSD and NetBSD (no xattrs/ACLs support or binaries yet) * Cygwin (not supported, no binaries yet) + * Linux Subsystem of Windows 10 (not supported) **Free and Open Source Software** * security and functionality can be audited independently diff --git a/conftest.py b/conftest.py index d28672e47..a1822767d 100644 --- a/conftest.py +++ b/conftest.py @@ -3,7 +3,7 @@ import os import pytest # needed to get pretty assertion failures in unit tests: -pytest.register_assert_rewrite('borg') +pytest.register_assert_rewrite('borg.testsuite') from borg.logger import setup_logging diff --git a/docs/changes.rst b/docs/changes.rst index 1678d0599..e6ebcb45c 100644 --- a/docs/changes.rst +++ b/docs/changes.rst @@ -82,6 +82,9 @@ Bug fixes: - skip corrupted chunks during manifest rebuild - fix TypeError in integrity error handler, #1903, #1894 - fix location parser for archives with @ char (regression introduced in 1.0.8), #1930 +- fix wrong duration/timestamps if system clock jumped during a create +- fix progress display not updating if system clock jumps backwards +- fix checkpoint interval being incorrect if system clock jumps Other changes: diff --git a/docs/installation.rst b/docs/installation.rst index ad5ffb75a..5a904eaf9 100644 --- a/docs/installation.rst +++ b/docs/installation.rst @@ -290,12 +290,21 @@ and commands to make fuse work for using the mount command. sysctl vfs.usermount=1 +Windows 10's Linux Subsystem +++++++++++++++++++++++++++++ + +.. note:: + Running under Windows 10's Linux Subsystem is experimental and has not been tested much yet. + +Just follow the Ubuntu Linux installation steps. You can omit the FUSE stuff, it won't work anyway. + + Cygwin ++++++ .. note:: Running under Cygwin is experimental and has only been tested with Cygwin - (x86-64) v2.5.2. + (x86-64) v2.5.2. Remote repositories are known broken, local repositories should work. Use the Cygwin installer to install the dependencies:: diff --git a/src/borg/archive.py b/src/borg/archive.py index c39a11664..c5d1ef85d 100644 --- a/src/borg/archive.py +++ b/src/borg/archive.py @@ -5,7 +5,7 @@ import stat import sys import time from contextlib import contextmanager -from datetime import datetime, timezone +from datetime import datetime, timezone, timedelta from functools import partial from getpass import getuser from io import BytesIO @@ -81,7 +81,7 @@ class Statistics: return format_file_size(self.csize) def show_progress(self, item=None, final=False, stream=None, dt=None): - now = time.time() + now = time.monotonic() if dt is None or now - self.last_progress > dt: self.last_progress = now columns, lines = get_terminal_size() @@ -255,7 +255,7 @@ class Archive: def __init__(self, repository, key, manifest, name, cache=None, create=False, checkpoint_interval=300, numeric_owner=False, noatime=False, noctime=False, progress=False, - chunker_params=CHUNKER_PARAMS, start=None, end=None, compression=None, compression_files=None, + chunker_params=CHUNKER_PARAMS, start=None, start_monotonic=None, end=None, compression=None, compression_files=None, consider_part_files=False): self.cwd = os.getcwd() self.key = key @@ -270,10 +270,13 @@ class Archive: self.numeric_owner = numeric_owner self.noatime = noatime self.noctime = noctime + assert (start is None) == (start_monotonic is None), 'Logic error: if start is given, start_monotonic must be given as well and vice versa.' if start is None: start = datetime.utcnow() + start_monotonic = time.monotonic() self.chunker_params = chunker_params self.start = start + self.start_monotonic = start_monotonic if end is None: end = datetime.utcnow() self.end = end @@ -288,7 +291,7 @@ class Archive: key.compression_decider2 = CompressionDecider2(compression or CompressionSpec('none')) if name in manifest.archives: raise self.AlreadyExists(name) - self.last_checkpoint = time.time() + self.last_checkpoint = time.monotonic() i = 0 while True: self.checkpoint_name = '%s.checkpoint%s' % (name, i and ('.%d' % i) or '') @@ -381,14 +384,17 @@ Number of files: {0.stats.nfiles}'''.format( if name in self.manifest.archives: raise self.AlreadyExists(name) self.items_buffer.flush(flush=True) + duration = timedelta(seconds=time.monotonic() - self.start_monotonic) if timestamp is None: self.end = datetime.utcnow() + self.start = self.end - duration start = self.start end = self.end else: self.end = timestamp - start = timestamp - end = timestamp # we only have 1 value + self.start = timestamp - duration + end = timestamp + start = self.start metadata = { 'version': 1, 'name': name, diff --git a/src/borg/archiver.py b/src/borg/archiver.py index cb2206d78..f6017e130 100644 --- a/src/borg/archiver.py +++ b/src/borg/archiver.py @@ -12,11 +12,11 @@ import stat import subprocess import sys import textwrap +import time import traceback from binascii import unhexlify from datetime import datetime from itertools import zip_longest -from operator import attrgetter from .logger import create_logger, setup_logging logger = create_logger() @@ -327,7 +327,6 @@ class Archiver: if args.progress: archive.stats.show_progress(final=True) if args.stats: - archive.end = datetime.utcnow() log_multi(DASHES, str(archive), DASHES, @@ -341,6 +340,7 @@ class Archiver: self.ignore_inode = args.ignore_inode dry_run = args.dry_run t0 = datetime.utcnow() + t0_monotonic = time.monotonic() if not dry_run: with Cache(repository, key, manifest, do_files=args.cache_files, progress=args.progress, lock_wait=self.lock_wait) as cache: @@ -348,7 +348,7 @@ class Archiver: create=True, checkpoint_interval=args.checkpoint_interval, numeric_owner=args.numeric_owner, noatime=args.noatime, noctime=args.noctime, progress=args.progress, - chunker_params=args.chunker_params, start=t0, + chunker_params=args.chunker_params, start=t0, start_monotonic=t0_monotonic, compression=args.compression, compression_files=args.compression_files) create_inner(archive, cache) else: diff --git a/src/borg/testsuite/archiver.py b/src/borg/testsuite/archiver.py index 711aca68e..68c8f9e24 100644 --- a/src/borg/testsuite/archiver.py +++ b/src/borg/testsuite/archiver.py @@ -328,7 +328,8 @@ class ArchiverTestCaseBase(BaseTestCase): except PermissionError: have_root = False except OSError as e: - if e.errno != errno.EINVAL: + # Note: ENOSYS "Function not implemented" happens as non-root on Win 10 Linux Subsystem. + if e.errno not in (errno.EINVAL, errno.ENOSYS): raise have_root = False return have_root