API Documentation

class borg.key.AESKeyBase(repository)[source]

Common base class shared by KeyfileKey and PassphraseKey

Chunks are encrypted using 256bit AES in Counter Mode (CTR)

Payload layout: TYPE(1) + HMAC(32) + NONCE(8) + CIPHERTEXT

To reduce payload size only 8 bytes of the 16 bytes nonce is saved in the payload, the first 8 bytes are always zeros. This does not affect security but limits the maximum repository capacity to only 295 exabytes!

PAYLOAD_OVERHEAD = 41
decrypt(id, data)[source]
encrypt(data)[source]
extract_nonce(payload)[source]
id_hash(data)[source]

Return HMAC hash using the “id” HMAC key

init_ciphers(enc_iv=b'')[source]
init_from_random_data(data)[source]
class borg.key.HMAC(key, msg=None, digestmod=None)[source]

Workaround a bug in Python < 3.4 Where HMAC does not accept memoryviews

update(msg)[source]
class borg.key.KeyBase(repository)[source]
TYPE = None
decrypt(id, data)[source]
encrypt(data)[source]
id_hash(data)[source]

Return HMAC hash using the “id” HMAC key

class borg.key.KeyfileKey(repository)[source]
FILE_ID = 'BORG_KEY'
TYPE = 0
find_key()[source]
get_new_target(args)[source]
load(target, passphrase)[source]
save(target, passphrase)[source]
class borg.key.KeyfileKeyBase(repository)[source]
change_passphrase()[source]
classmethod create(repository, args)[source]
decrypt_key_file(data, passphrase)[source]
classmethod detect(repository, manifest_data)[source]
encrypt_key_file(data, passphrase)[source]
find_key()[source]
get_new_target(args)[source]
load(target, passphrase)[source]
save(target, passphrase)[source]
exception borg.key.KeyfileNotFoundError[source]

No key file for repository {} found in {}.

class borg.key.Passphrase[source]
classmethod env_passphrase(default=None)[source]
classmethod getpass(prompt)[source]
kdf(salt, iterations, length)[source]
classmethod new(allow_empty=False)[source]
class borg.key.PassphraseKey(repository)[source]
TYPE = 1
change_passphrase()
classmethod create(repository, args)
classmethod detect(repository, manifest_data)
init(repository, passphrase)
iterations = 100000
class borg.key.PlaintextKey(repository)[source]
TYPE = 2
chunk_seed = 0
classmethod create(repository, args)[source]
decrypt(id, data)[source]
classmethod detect(repository, manifest_data)[source]
encrypt(data)[source]
id_hash(data)[source]
class borg.key.RepoKey(repository)[source]
TYPE = 3
find_key()[source]
get_new_target(args)[source]
load(target, passphrase)[source]
save(target, passphrase)[source]
exception borg.key.RepoKeyNotFoundError[source]

No key entry found in the config of repository {}.

exception borg.key.UnsupportedPayloadError[source]

Unsupported payload type {}. A newer version is required to access this repository.

borg.key.key_creator(repository, args)[source]
borg.key.key_factory(repository, manifest_data)[source]
class borg.cache.Cache(repository, key, manifest, path=None, sync=True, do_files=False, warn_if_unencrypted=True)[source]

Client Side cache

exception CacheInitAbortedError[source]

Cache initialization aborted

exception Cache.EncryptionMethodMismatch[source]

Repository encryption method changed since last access, refusing to continue

exception Cache.RepositoryAccessAborted[source]

Repository access aborted

exception Cache.RepositoryReplay[source]

Cache is newer than repository, refusing to continue

Cache.add_chunk(id, data, stats)[source]
Cache.begin_txn()[source]
Cache.chunk_decref(id, stats)[source]
Cache.chunk_incref(id, stats)[source]
Cache.close()[source]
Cache.commit()[source]

Commit transaction

Cache.create()[source]

Create a new empty cache at self.path

Cache.destroy()[source]

destroy the cache at self.path

Cache.file_known_and_unchanged(path_hash, st)[source]
Cache.format_tuple()[source]
Cache.memorize_file(path_hash, st, ids)[source]
Cache.open()[source]
Cache.rollback()[source]

Roll back partial and aborted transactions

Cache.seen_chunk(id, size=None)[source]
Cache.sync()[source]

Re-synchronize chunks cache with repository.

Maintains a directory with known backup archive indexes, so it only needs to fetch infos from repo and build a chunk index once per backup archive. If out of sync, missing archive indexes get added, outdated indexes get removed and a new master chunks index is built by merging all archive indexes.

class borg.locking.ExclusiveLock(path, timeout=None, sleep=None, id=None)[source]

An exclusive Lock based on mkdir fs operation being atomic

exception LockError[source]

Failed to acquire the lock {}.

exception ExclusiveLock.LockFailed[source]

Failed to create/acquire the lock {} ({}).

exception ExclusiveLock.LockTimeout[source]

Failed to create/acquire the lock {} (timeout).

exception ExclusiveLock.NotLocked[source]

Failed to release the lock {} (was not locked).

exception ExclusiveLock.NotMyLock[source]

Failed to release the lock {} (was/is locked, but not by me).

exception ExclusiveLock.UnlockError[source]

Failed to release the lock {}.

ExclusiveLock.acquire(timeout=None, sleep=None)[source]
ExclusiveLock.break_lock()[source]
ExclusiveLock.by_me()[source]
ExclusiveLock.is_locked()[source]
ExclusiveLock.release()[source]
class borg.locking.LockRoster(path, id=None)[source]

A Lock Roster to track shared/exclusive lockers.

Note: you usually should call the methods with an exclusive lock held, to avoid conflicting access by multiple threads/processes/machines.

get(key)[source]
load()[source]
modify(key, op)[source]
remove()[source]
save(data)[source]
class borg.locking.TimeoutTimer(timeout=None, sleep=None)[source]

A timer for timeout checks (can also deal with no timeout, give timeout=None [default]). It can also compute and optionally execute a reasonable sleep time (e.g. to avoid polling too often or to support thread/process rescheduling).

sleep()[source]
start()[source]
timed_out()[source]
timed_out_or_sleep()[source]
class borg.locking.UpgradableLock(path, exclusive=False, sleep=None, id=None)[source]

A Lock for a resource that can be accessed in a shared or exclusive way. Typically, write access to a resource needs an exclusive lock (1 writer, noone is allowed reading) and read access to a resource needs a shared lock (multiple readers are allowed).

exception ExclusiveLockFailed[source]

Failed to acquire write lock [{}]

exception UpgradableLock.SharedLockFailed[source]

Failed to acquire shared lock [{}]

UpgradableLock.acquire(exclusive=None, remove=None, sleep=None)[source]
UpgradableLock.break_lock()[source]
UpgradableLock.downgrade()[source]
UpgradableLock.release()[source]
UpgradableLock.upgrade()[source]
borg.locking.get_id()[source]

Get identification tuple for ‘us’

A basic extended attributes (xattr) implementation for Linux and MacOS X

borg.xattr.get_all(path, follow_symlinks=True)[source]
borg.xattr.getxattr(path, name, *, follow_symlinks=True)[source]
borg.xattr.is_enabled(path=None)[source]

Determine if xattr is enabled on the filesystem

borg.xattr.listxattr(path, *, follow_symlinks=True)[source]
borg.xattr.setxattr(path, name, value, *, follow_symlinks=True)[source]

logging facilities

The way to use this is as follows:

  • each module declares its own logger, using:

    from .logger import create_logger logger = create_logger()

  • then each module uses logger.info/warning/debug/etc according to the level it believes is appropriate:

    logger.debug(‘debugging info for developers or power users’) logger.info(‘normal, informational output’) logger.warning(‘warn about a non-fatal error or sth else’) logger.error(‘a fatal error’)

    ... and so on. see the logging documentation for more information

  • console interaction happens on stderr, that includes interactive reporting functions like help, info and list

  • ...except input() is special, because we can’t control the stream it is using, unfortunately. we assume that it won’t clutter stdout, because interaction would be broken then anyways

  • what is output on INFO level is additionally controlled by commandline flags

borg.logger.create_logger(name=None)[source]

create a Logger object with the proper path, which is returned by find_parent_module() by default, or is provided via the commandline

this is really a shortcut for:

logger = logging.getLogger(__name__)

we use it to avoid errors and provide a more standard API.

borg.logger.find_parent_module()[source]

find the name of a the first module calling this module

if we cannot find it, we return the current module’s name (__name__) instead.

borg.logger.setup_logging(stream=None)[source]

setup logging module according to the arguments provided

this sets up a stream handler logger on stderr (by default, if no stream is provided).

class borg.repository.LoggedIO(path, limit, segments_per_dir, capacity=90)[source]
COMMIT = b'@\xf4<%\t\x00\x00\x00\x02'
cleanup(transaction_id)

Delete segment files left by aborted transactions

close()
close_segment()
crc_fmt = <Struct object>
delete_segment(segment)
get_fd(segment)
get_latest_segment()
get_segments_transaction_id()

Verify that the transaction id is consistent with the index transaction id

get_write_fd(no_new=False)
header_fmt = <Struct object>
header_no_crc_fmt = <Struct object>
is_committed_segment(filename)

Check if segment ends with a COMMIT_TAG tag

iter_objects(segment, include_data=False)
put_header_fmt = <Struct object>
read(segment, offset, id)
recover_segment(segment, filename)
segment_exists(segment)
segment_filename(segment)
segment_iterator(reverse=False)
write_commit()
write_delete(id)
write_put(id, data)
class borg.repository.Repository(path, create=False, exclusive=False)[source]

Filesystem based transactional key value store

On disk layout: dir/README dir/config dir/data/<X / SEGMENTS_PER_DIR>/<X> dir/index.X dir/hints.X

exception AlreadyExists[source]

Repository {} already exists.

exception Repository.CheckNeeded[source]

Inconsistency detected. Please run “borg check {}”.

Repository.DEFAULT_MAX_SEGMENT_SIZE = 5242880
Repository.DEFAULT_SEGMENTS_PER_DIR = 10000
exception Repository.DoesNotExist[source]

Repository {} does not exist.

exception Repository.InvalidRepository[source]

{} is not a valid repository. Check repo config.

exception Repository.ObjectNotFound[source]

Object with key {} not found in repository {}.

Repository.check(repair=False)[source]

Check repository consistency

This method verifies all segment checksums and makes sure the index is consistent with the data stored in the segments.

Repository.close()[source]
Repository.commit()[source]

Commit transaction

Repository.compact_segments()[source]

Compact sparse segments by copying data into new segments

Repository.create(path)[source]

Create a new empty repository at path

Repository.delete(id, wait=True)[source]
Repository.destroy()[source]

Destroy the repository at self.path

Repository.get(id_)[source]
Repository.get_index_transaction_id()[source]
Repository.get_many(ids, is_preloaded=False)[source]
Repository.get_transaction_id()[source]
Repository.list(limit=None, marker=None)[source]
Repository.load_key()[source]
Repository.open(path, exclusive)[source]
Repository.open_index(transaction_id)[source]
Repository.preload(ids)[source]

Preload objects (only applies to remote repositories)

Repository.prepare_txn(transaction_id, do_cleanup=True)[source]
Repository.put(id, data, wait=True)[source]
Repository.replay_segments(index_transaction_id, segments_transaction_id)[source]
Repository.rollback()[source]
Repository.save_config(path, config)[source]
Repository.save_key(keydata)[source]
Repository.write_index()[source]
class borg.archiver.Archiver(verbose=False)[source]
build_parser(args=None, prog=None)
do_change_passphrase(args)

Change repository key file passphrase

do_check(args)

Check repository consistency

do_create(args)

Create new archive

do_debug_delete_obj(args)

delete the objects with the given IDs from the repo

do_debug_dump_archive_items(args)

dump (decrypted, decompressed) archive items metadata (not: data)

do_debug_get_obj(args)

get object contents from the repository and write it into file

do_debug_put_obj(args)

put file(s) contents into the repository

do_delete(args)

Delete an existing repository or archive

do_extract(args)

Extract archive contents

do_help(parser, commands, args)
do_info(args)

Show archive details such as disk space used

do_init(args)

Initialize an empty repository

do_list(args)

List archive or repository contents

do_mount(args)

Mount archive or an entire repository as a FUSE fileystem

do_prune(args)

Prune repository archives according to specified rules

do_rename(args)

Rename an existing archive

do_serve(args)

Start in server mode. This command is usually not used manually.

do_upgrade(args)

upgrade a repository from a previous version

helptext = {'patterns': "\n Exclude patterns use a variant of shell pattern syntax, with '*' matching any\n number of characters, '?' matching any single character, '[...]' matching any\n single character specified, including ranges, and '[!...]' matching any\n character not specified. For the purpose of these patterns, the path\n separator ('\\' for Windows and '/' on other systems) is not treated\n specially. For a path to match a pattern, it must completely match from\n start to end, or must match from the start to just before a path separator.\n Except for the root path, paths will never end in the path separator when\n matching is attempted. Thus, if a given pattern ends in a path separator, a\n '*' is appended before matching is attempted. Patterns with wildcards should\n be quoted to protect them from shell expansion.\n\n Examples:\n\n # Exclude '/home/user/file.o' but not '/home/user/file.odt':\n $ borg create -e '*.o' backup /\n\n # Exclude '/home/user/junk' and '/home/user/subdir/junk' but\n # not '/home/user/importantjunk' or '/etc/junk':\n $ borg create -e '/home/*/junk' backup /\n\n # Exclude the contents of '/home/user/cache' but not the directory itself:\n $ borg create -e /home/user/cache/ backup /\n\n # The file '/home/user/cache/important' is *not* backed up:\n $ borg create -e /home/user/cache/ backup / /home/user/cache/important\n "}
open_repository(location, create=False, exclusive=False)
parse_args(args=None)
preprocess_args(args)
print_error(msg, *args)
print_info(msg, *args)
print_status(status, path)
print_warning(msg, *args)
run(args)
borg.archiver.main()[source]
borg.archiver.setup_signal_handlers()[source]
borg.archiver.sig_info_handler(signum, stack)[source]

search the stack for infos about the currently processed file and print them

class borg.archive.Archive(repository, key, manifest, name, cache=None, create=False, checkpoint_interval=300, numeric_owner=False, progress=False, chunker_params=(10, 23, 16, 4095), start=datetime.datetime(2015, 12, 8, 11, 42, 24, 722941), end=datetime.datetime(2015, 12, 8, 11, 42, 24, 722958))[source]
exception AlreadyExists

Archive {} already exists

exception Archive.DoesNotExist

Archive {} does not exist

exception Archive.IncompatibleFilesystemEncodingError

Failed to encode filename “{}” into file system encoding “{}”. Consider configuring the LANG environment variable.

Archive.add_item(item)
Archive.calc_stats(cache)
Archive.delete(stats)
Archive.duration
Archive.extract_item(item, restore_attrs=True, dry_run=False, stdout=False, sparse=False)
Archive.fpr
Archive.iter_items(filter=None, preload=False)
static Archive.list_archives(repository, key, manifest, cache=None)
Archive.load(id)
Archive.process_dev(path, st)
Archive.process_dir(path, st)
Archive.process_fifo(path, st)
Archive.process_file(path, st, cache)
Archive.process_stdin(path, cache)
Archive.rename(name)
Archive.restore_attrs(path, item, symlink=False, fd=None)
Archive.save(name=None, timestamp=None)
Archive.stat_attrs(st, path)
Archive.ts

Timestamp of archive creation in UTC

Archive.write_checkpoint()
class borg.archive.ArchiveChecker[source]
check(repository, repair=False, archive=None, last=None)
finish()
identify_key(repository)
init_chunks()

Fetch a list of all object keys from repository

orphan_chunks_check()
rebuild_manifest()

Rebuild the manifest object if it is missing

Iterates through all objects in the repository looking for archive metadata blocks.

rebuild_refcounts(archive=None, last=None)

Rebuild object reference counts by walking the metadata

Missing and/or incorrect data is repaired when detected

report_progress(msg, error=False)
class borg.archive.CacheChunkBuffer(cache, key, stats, chunker_params=(10, 23, 16, 4095))[source]
write_chunk(chunk)
class borg.archive.ChunkBuffer(key, chunker_params=(10, 23, 16, 4095))[source]
BUFFER_SIZE = 1048576
add(item)[source]
flush(flush=False)[source]
is_full()[source]
write_chunk(chunk)[source]
class borg.archive.DownloadPipeline(repository, key)[source]
fetch_many(ids, is_preloaded=False)
unpack_many(ids, filter=None, preload=False)
class borg.archive.RobustUnpacker(validator)[source]

A restartable/robust version of the streaming msgpack unpacker

feed(data)[source]
resync()[source]
class borg.lrucache.LRUCache(capacity, dispose)[source]
clear()[source]
items()[source]
exception borg.remote.ConnectionClosed[source]

Connection closed by remote host

exception borg.remote.ConnectionClosedWithHint[source]

Connection closed by remote host. {}

exception borg.remote.InvalidRPCMethod[source]

RPC method {} is not valid

exception borg.remote.PathNotAllowed[source]

Repository path not allowed

class borg.remote.RemoteRepository(location, create=False)[source]
exception RPCError(name)[source]
RemoteRepository.call(cmd, *args, **kw)[source]
RemoteRepository.call_many(cmd, calls, wait=True, is_preloaded=False)[source]
RemoteRepository.check(repair=False)[source]
RemoteRepository.close()[source]
RemoteRepository.commit(*args)[source]
RemoteRepository.delete(id_, wait=True)[source]
RemoteRepository.destroy()[source]
RemoteRepository.extra_test_args = []
RemoteRepository.get(id_)[source]
RemoteRepository.get_many(ids, is_preloaded=False)[source]
RemoteRepository.list(limit=None, marker=None)[source]
RemoteRepository.load_key()[source]
RemoteRepository.preload(ids)[source]
RemoteRepository.put(id_, data, wait=True)[source]
RemoteRepository.remote_path = 'borg'
RemoteRepository.rollback(*args)[source]
RemoteRepository.save_key(keydata)[source]
RemoteRepository.ssh_cmd(location)[source]
RemoteRepository.umask = 63
RemoteRepository.umask_flag()[source]
class borg.remote.RepositoryCache(repository)[source]

A caching Repository wrapper

Caches Repository GET operations using a local temporary Repository.

get(key)[source]
get_many(keys)[source]
class borg.remote.RepositoryServer(restrict_to_paths)[source]
negotiate(versions)[source]
open(path, create=False)[source]
rpc_methods = ('__len__', 'check', 'commit', 'delete', 'destroy', 'get', 'list', 'negotiate', 'open', 'put', 'repair', 'rollback', 'save_key', 'load_key')
serve()[source]
borg.remote.cache_if_remote(repository)[source]
class borg.upgrader.AtticKeyfileKey(repository)[source]

backwards compatible Attic key file parser

FILE_ID = 'ATTIC KEY'
classmethod find_key_file(repository)[source]

copy of attic’s `find_key_file`_

this has two small modifications:

  1. it uses the above `get_keys_dir`_ instead of the global one, assumed to be borg’s
  2. it uses `repository.path`_ instead of `repository._location.canonical_path`_ because we can’t assume the repository has been opened by the archiver yet
static get_keys_dir()[source]

Determine where to repository keys and cache

class borg.upgrader.AtticRepositoryUpgrader(path, create=False, exclusive=False)[source]
convert_cache(dryrun)[source]

convert caches from attic to borg

those are all hash indexes, so we need to s/ATTICIDX/BORG_IDX/ in a few locations:

  • the repository index (in $ATTIC_REPO/index.%d, where %d is the Repository.get_index_transaction_id()), which we should probably update, with a lock, see Repository.open(), which i’m not sure we should use because it may write data on Repository.close()...
  • the files and chunks cache (in $ATTIC_CACHE_DIR or $HOME/.cache/attic/<repoid>/), which we could just drop, but if we’d want to convert, we could open it with the Cache.open(), edit in place and then Cache.close() to make sure we have locking right
static convert_keyfiles(keyfile, dryrun)[source]

convert key files from attic to borg

replacement pattern is s/ATTIC KEY/BORG_KEY/ in get_keys_dir(), that is $ATTIC_KEYS_DIR or $HOME/.attic/keys, and moved to $BORG_KEYS_DIR or $HOME/.borg/keys.

no need to decrypt to convert. we need to rewrite the whole key file because magic string length changed, but that’s not a problem because the keyfiles are small (compared to, say, all the segments).

static convert_segments(segments, dryrun=True, inplace=False)[source]

convert repository segments from attic to borg

replacement pattern is s/ATTICSEG/BORG_SEG/ in files in $ATTIC_REPO/data/**.

luckily the magic string length didn’t change so we can just replace the 8 first bytes of all regular files in there.

find_attic_keyfile()[source]

find the attic keyfiles

the keyfiles are loaded by KeyfileKey.find_key_file(). that finds the keys with the right identifier for the repo.

this is expected to look into $HOME/.attic/keys or $ATTIC_KEYS_DIR for key files matching the given Borg repository.

it is expected to raise an exception (KeyfileNotFoundError) if no key is found. whether that exception is from Borg or Attic is unclear.

this is split in a separate function in case we want to use the attic code here directly, instead of our local implementation.

static header_replace(filename, old_magic, new_magic, inplace=True)[source]
upgrade(dryrun=True, inplace=False)[source]

convert an attic repository to a borg repository

those are the files that need to be upgraded here, from most important to least important: segments, key files, and various caches, the latter being optional, as they will be rebuilt if missing.

we nevertheless do the order in reverse, as we prefer to do the fast stuff first, to improve interactivity.

borg.helpers.ChunkerParams(s)[source]
borg.helpers.CompressionSpec(s)[source]
exception borg.helpers.Error[source]

Error base class

exit_code = 2
get_message()[source]
traceback = False
exception borg.helpers.ErrorWithTraceback[source]

like Error, but show a traceback also

traceback = True
class borg.helpers.ExcludePattern(pattern)[source]

Shell glob patterns to exclude. A trailing slash means to exclude the contents of a directory, but not the directory itself.

match(path)[source]
exception borg.helpers.ExtensionModuleError[source]

The Borg binary extension modules do not seem to be properly installed

class borg.helpers.IncludePattern(pattern)[source]

Literal files or directories listed on the command line for some operations (e.g. extract, but not create). If a directory is specified, all paths that start with that path match as well. A trailing slash makes no difference.

match(path)[source]
exception borg.helpers.IntegrityError[source]

Data integrity error

class borg.helpers.Location(text='')[source]

Object representing a repository / archive location

archive = None
canonical_path()[source]
env_re = re.compile('(?:::(?P<archive>[^/]+)?)?$')
file_re = re.compile('(?P<proto>file)://(?P<path>[^:]+)(?:::(?P<archive>[^/]+))?$')
host = None
parse(text)[source]
path = None
port = None
proto = None
scp_re = re.compile('((?:(?P<user>[^@]+)@)?(?P<host>[^:/]+):)?(?P<path>[^:]+)(?:::(?P<archive>[^/]+))?$')
ssh_re = re.compile('(?P<proto>ssh)://(?:(?P<user>[^@]+)@)?(?P<host>[^:/#]+)(?::(?P<port>\\d+))?(?P<path>[^:]+)(?:::(?P<archive>[^/]+))?$')
to_key_filename()[source]
user = None
class borg.helpers.Manifest(key, repository)[source]
MANIFEST_ID = b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'
list_archive_infos(sort_by=None, reverse=False)
classmethod load(repository, key=None)
write()
class borg.helpers.StableDict[source]

A dict subclass with stable items() ordering

items()[source]
class borg.helpers.Statistics[source]
csize_fmt
osize_fmt
show_progress(item=None, final=False, stream=None)
summary = ' Original size Compressed size Deduplicated size\n{label:15} {stats.osize_fmt:>20s} {stats.csize_fmt:>20s} {stats.usize_fmt:>20s}'
update(size, csize, unique)
usize_fmt
borg.helpers.adjust_patterns(paths, excludes)[source]
borg.helpers.bigint_to_int(mtime)[source]

Convert bytearray to int

borg.helpers.check_extension_modules()[source]
borg.helpers.daemonize()[source]

Detach process from controlling terminal and run in background

borg.helpers.decode_dict(d, keys, encoding='utf-8', errors='surrogateescape')[source]
borg.helpers.dir_is_cachedir(path)[source]

Determines whether the specified path is a cache directory (and therefore should potentially be excluded from the backup) according to the CACHEDIR.TAG protocol (http://www.brynosaurus.com/cachedir/spec.html).

borg.helpers.dir_is_tagged(path, exclude_caches, exclude_if_present)[source]

Determines whether the specified path is excluded by being a cache directory or containing the user-specified tag file. Returns the path of the tag file (either CACHEDIR.TAG or the matching user-specified file)

borg.helpers.exclude_path(path, patterns)[source]

Used by create and extract sub-commands to determine whether or not an item should be processed.

borg.helpers.format_archive(archive)[source]
borg.helpers.format_file_mode(mod)[source]

Format file mode bits for list output

borg.helpers.format_file_size(v, precision=2)[source]

Format file size into a human friendly format

borg.helpers.format_time(t)[source]

Format datetime suitable for fixed length list output

borg.helpers.format_timedelta(td)[source]

Format timedelta in a human friendly format

borg.helpers.get_cache_dir()[source]

Determine where to repository keys and cache

borg.helpers.get_keys_dir()[source]

Determine where to repository keys and cache

borg.helpers.gid2group(*args)[source]
borg.helpers.group2gid(*args)[source]
borg.helpers.int_to_bigint(value)[source]

Convert integers larger than 64 bits to bytearray

Smaller integers are left alone

borg.helpers.is_slow_msgpack()[source]
borg.helpers.location_validator(archive=None)[source]
borg.helpers.make_path_safe(path)[source]

Make path safe by making it relative and local

borg.helpers.memoize(function)[source]
borg.helpers.normalized(func)[source]

Decorator for the Pattern match methods, returning a wrapper that normalizes OSX paths to match the normalized pattern on OSX, and returning the original method on other platforms

borg.helpers.parse_timestamp(timestamp)[source]

Parse a ISO 8601 timestamp string

borg.helpers.posix_acl_use_stored_uid_gid(acl)[source]

Replace the user/group field with the stored uid/gid

borg.helpers.prune_split(archives, pattern, n, skip=[])[source]
borg.helpers.prune_within(archives, within)[source]
borg.helpers.read_msgpack(filename)[source]
borg.helpers.remove_surrogates(s, errors='replace')[source]

Replace surrogates generated by fsdecode with ‘?’

borg.helpers.safe_decode(s, coding='utf-8', errors='surrogateescape')[source]

decode bytes to str, with round-tripping “invalid” bytes

borg.helpers.safe_encode(s, coding='utf-8', errors='surrogateescape')[source]

encode str to bytes, with round-tripping “invalid” bytes

borg.helpers.sizeof_fmt(num, suffix='B', units=None, power=None, sep='', precision=2)[source]
borg.helpers.sizeof_fmt_decimal(num, suffix='B', sep='', precision=2)[source]
borg.helpers.sizeof_fmt_iec(num, suffix='B', sep='', precision=2)[source]
borg.helpers.st_atime_ns(st)[source]
borg.helpers.st_ctime_ns(st)[source]
borg.helpers.st_mtime_ns(st)[source]
borg.helpers.timestamp(s)[source]

Convert a –timestamp=s argument to a datetime object

borg.helpers.to_localtime(ts)[source]

Convert datetime object from UTC to local time zone

borg.helpers.uid2user(*args)[source]
borg.helpers.update_excludes(args)[source]

Merge exclude patterns from files with those on command line. Empty lines and lines starting with ‘#’ are ignored, but whitespace is not stripped.

borg.helpers.user2uid(*args)[source]
borg.helpers.write_msgpack(filename, d)[source]
borg.helpers.yes(msg=None, retry_msg=None, false_msg=None, true_msg=None, default=False, default_notty=None, default_eof=None, falsish=('No', 'no', 'N', 'n'), truish=('Yes', 'yes', 'Y', 'y'), env_var_override=None, ifile=None, ofile=None, input=<built-in function input>)[source]

Output <msg> (usually a question) and let user input an answer. Qualifies the answer according to falsish and truish as True or False. If it didn’t qualify and retry_msg is None (no retries wanted), return the default [which defaults to False]. Otherwise let user retry answering until answer is qualified.

If env_var_override is given and it is non-empty, counts as truish answer and won’t ask user for an answer. If we don’t have a tty as input and default_notty is not None, return its value. Otherwise read input from non-tty and proceed as normal. If EOF is received instead an input, return default_eof [or default, if not given].

param msg:introducing message to output on ofile, no
is added [None]
param retry_msg:
 retry message to output on ofile, no
is added [None]
(also enforces retries instead of returning default)
param false_msg:
 message to output before returning False [None]
param true_msg:message to output before returning True [None]
param default:default return value (empty answer is given) [False]
param default_notty:
 if not None, return its value if no tty is connected [None]
param default_eof:
 return value if EOF was read as answer [same as default]
param falsish:sequence of answers qualifying as False
param truish:sequence of answers qualifying as True
param env_var_override:
 environment variable name [None]
param ifile:input stream [sys.stdin] (only for testing!)
param ofile:output stream [sys.stderr]
param input:input function [input from builtins]
return:boolean answer value, True or False
class borg.hashindex.ChunkIndex
iteritems()
merge()
summarize()
value_size = 12
class borg.hashindex.ChunkKeyIterator
class borg.hashindex.NSIndex
iteritems()
value_size = 8
class borg.hashindex.NSKeyIterator
class borg.chunker.Chunker
chunkify()

Cut a file into chunks.

Parameters:
  • fd – Python file object
  • fh – OS-level file handle (if available), defaults to -1 which means not to use OS-level fd.
borg.chunker.buzhash()
borg.chunker.buzhash_update()
borg.platform_linux.acl_get()

Saves ACL Entries

If numeric_owner is True the user/group field is not preserved only uid/gid

borg.platform_linux.acl_set()

Restore ACL Entries

If numeric_owner is True the stored uid/gid is used instead of the user/group names

borg.platform_linux.acl_use_local_uid_gid()

Replace the user/group field with the local uid/gid if possible

class borg.compress.CNONE

none - no compression, just pass through data

ID = b'\x00\x00'
compress()
decompress()
name = 'none'
class borg.compress.Compressor

compresses using a compressor with given name and parameters decompresses everything we can handle (autodetect)

compress()
decompress()
class borg.compress.CompressorBase

base class for all (de)compression classes, also handles compression format auto detection and adding/stripping the ID header (which enable auto detection).

ID = b'\xff\xff'
compress()
decompress()
detect()
name = 'baseclass'
class borg.compress.LZ4

raw LZ4 compression / decompression (liblz4).

Features:
  • lz4 is super fast
  • wrapper releases CPython’s GIL to support multithreaded code
  • buffer given by caller, avoiding frequent reallocation and buffer duplication
  • uses safe lz4 methods that never go beyond the end of the output buffer
But beware:
  • this is not very generic, the given buffer MUST be large enough to handle all compression or decompression output (or it will fail).
  • you must not do method calls to the same LZ4 instance from different threads at the same time - create one LZ4 instance per thread!
ID = b'\x01\x00'
compress()
decompress()
name = 'lz4'
class borg.compress.LZMA

lzma compression / decompression (python 3.3+ stdlib)

ID = b'\x02\x00'
compress()
decompress()
name = 'lzma'
class borg.compress.ZLIB

zlib compression / decompression (python stdlib)

ID = b'\x08\x00'
compress()
decompress()
classmethod detect()
name = 'zlib'
borg.compress.get_compressor()

A thin OpenSSL wrapper

This could be replaced by PyCrypto or something similar when the performance of their PBKDF2 implementation is comparable to the OpenSSL version.

class borg.crypto.AES

A thin wrapper around the OpenSSL EVP cipher API

decrypt()
encrypt()
iv
reset()
borg.crypto.bytes_to_int
borg.crypto.bytes_to_long
borg.crypto.get_random_bytes()

Return n cryptographically strong pseudo-random bytes

borg.crypto.long_to_bytes
borg.crypto.num_aes_blocks()

Return the number of AES blocks required to encrypt/decrypt length bytes of data. Note: this is only correct for modes without padding, like AES-CTR.

borg.crypto.pbkdf2_sha256()

Password based key derivation function 2 (RFC2898)