|
@@ -53,7 +53,6 @@ try:
|
|
from ..helpers import ErrorIgnoringTextIOWrapper
|
|
from ..helpers import ErrorIgnoringTextIOWrapper
|
|
from ..helpers import ProgressIndicatorPercent
|
|
from ..helpers import ProgressIndicatorPercent
|
|
from ..helpers import basic_json_data, json_print
|
|
from ..helpers import basic_json_data, json_print
|
|
- from ..helpers import umount
|
|
|
|
from ..helpers import flags_root, flags_dir, flags_special_follow, flags_special
|
|
from ..helpers import flags_root, flags_dir, flags_special_follow, flags_special
|
|
from ..helpers import msgpack
|
|
from ..helpers import msgpack
|
|
from ..helpers import sig_int
|
|
from ..helpers import sig_int
|
|
@@ -61,7 +60,7 @@ try:
|
|
from ..patterns import PatternMatcher
|
|
from ..patterns import PatternMatcher
|
|
from ..platform import get_flags
|
|
from ..platform import get_flags
|
|
from ..platform import uid2user, gid2group
|
|
from ..platform import uid2user, gid2group
|
|
- from ..remote import RepositoryServer, RemoteRepository, cache_if_remote
|
|
|
|
|
|
+ from ..remote import RepositoryServer, RemoteRepository
|
|
from ..selftest import selftest
|
|
from ..selftest import selftest
|
|
except BaseException:
|
|
except BaseException:
|
|
# an unhandled exception in the try-block would cause the borg cli command to exit with rc 1 due to python's
|
|
# an unhandled exception in the try-block would cause the borg cli command to exit with rc 1 due to python's
|
|
@@ -106,6 +105,7 @@ from .diff import DiffMixIn
|
|
from .help import HelpMixIn
|
|
from .help import HelpMixIn
|
|
from .keys import KeysMixIn
|
|
from .keys import KeysMixIn
|
|
from .locks import LocksMixIn
|
|
from .locks import LocksMixIn
|
|
|
|
+from .mount import MountMixIn
|
|
from .prune import PruneMixIn
|
|
from .prune import PruneMixIn
|
|
from .tar import TarMixIn
|
|
from .tar import TarMixIn
|
|
from .transfer import TransferMixIn
|
|
from .transfer import TransferMixIn
|
|
@@ -121,6 +121,7 @@ class Archiver(
|
|
BenchmarkMixIn,
|
|
BenchmarkMixIn,
|
|
KeysMixIn,
|
|
KeysMixIn,
|
|
LocksMixIn,
|
|
LocksMixIn,
|
|
|
|
+ MountMixIn,
|
|
PruneMixIn,
|
|
PruneMixIn,
|
|
HelpMixIn,
|
|
HelpMixIn,
|
|
TransferMixIn,
|
|
TransferMixIn,
|
|
@@ -898,40 +899,6 @@ class Archiver(
|
|
|
|
|
|
return self.exit_code
|
|
return self.exit_code
|
|
|
|
|
|
- def do_mount(self, args):
|
|
|
|
- """Mount archive or an entire repository as a FUSE filesystem"""
|
|
|
|
- # Perform these checks before opening the repository and asking for a passphrase.
|
|
|
|
-
|
|
|
|
- from ..fuse_impl import llfuse, BORG_FUSE_IMPL
|
|
|
|
-
|
|
|
|
- if llfuse is None:
|
|
|
|
- self.print_error("borg mount not available: no FUSE support, BORG_FUSE_IMPL=%s." % BORG_FUSE_IMPL)
|
|
|
|
- return self.exit_code
|
|
|
|
-
|
|
|
|
- if not os.path.isdir(args.mountpoint) or not os.access(args.mountpoint, os.R_OK | os.W_OK | os.X_OK):
|
|
|
|
- self.print_error("%s: Mountpoint must be a writable directory" % args.mountpoint)
|
|
|
|
- return self.exit_code
|
|
|
|
-
|
|
|
|
- return self._do_mount(args)
|
|
|
|
-
|
|
|
|
- @with_repository(compatibility=(Manifest.Operation.READ,))
|
|
|
|
- def _do_mount(self, args, repository, manifest, key):
|
|
|
|
- from ..fuse import FuseOperations
|
|
|
|
-
|
|
|
|
- with cache_if_remote(repository, decrypted_cache=key) as cached_repo:
|
|
|
|
- operations = FuseOperations(key, repository, manifest, args, cached_repo)
|
|
|
|
- logger.info("Mounting filesystem")
|
|
|
|
- try:
|
|
|
|
- operations.mount(args.mountpoint, args.options, args.foreground)
|
|
|
|
- except RuntimeError:
|
|
|
|
- # Relevant error message already printed to stderr by FUSE
|
|
|
|
- self.exit_code = EXIT_ERROR
|
|
|
|
- return self.exit_code
|
|
|
|
-
|
|
|
|
- def do_umount(self, args):
|
|
|
|
- """un-mount the FUSE filesystem"""
|
|
|
|
- return umount(args.mountpoint)
|
|
|
|
-
|
|
|
|
@with_repository(compatibility=(Manifest.Operation.READ,))
|
|
@with_repository(compatibility=(Manifest.Operation.READ,))
|
|
def do_list(self, args, repository, manifest, key):
|
|
def do_list(self, args, repository, manifest, key):
|
|
"""List archive contents"""
|
|
"""List archive contents"""
|
|
@@ -1415,35 +1382,6 @@ class Archiver(
|
|
help="repository to use",
|
|
help="repository to use",
|
|
)
|
|
)
|
|
|
|
|
|
- def define_borg_mount(parser):
|
|
|
|
- parser.set_defaults(func=self.do_mount)
|
|
|
|
- parser.add_argument(
|
|
|
|
- "--consider-checkpoints",
|
|
|
|
- action="store_true",
|
|
|
|
- dest="consider_checkpoints",
|
|
|
|
- help="Show checkpoint archives in the repository contents list (default: hidden).",
|
|
|
|
- )
|
|
|
|
- parser.add_argument("mountpoint", metavar="MOUNTPOINT", type=str, help="where to mount filesystem")
|
|
|
|
- parser.add_argument(
|
|
|
|
- "-f",
|
|
|
|
- "--foreground",
|
|
|
|
- dest="foreground",
|
|
|
|
- action="store_true",
|
|
|
|
- help="stay in foreground, do not daemonize",
|
|
|
|
- )
|
|
|
|
- parser.add_argument("-o", dest="options", type=str, action=Highlander, help="Extra mount options")
|
|
|
|
- parser.add_argument(
|
|
|
|
- "--numeric-ids",
|
|
|
|
- dest="numeric_ids",
|
|
|
|
- action="store_true",
|
|
|
|
- help="use numeric user and group identifiers from archive(s)",
|
|
|
|
- )
|
|
|
|
- define_archive_filters_group(parser)
|
|
|
|
- parser.add_argument(
|
|
|
|
- "paths", metavar="PATH", nargs="*", type=str, help="paths to extract; patterns are supported"
|
|
|
|
- )
|
|
|
|
- define_exclusion_group(parser, strip_components=True)
|
|
|
|
-
|
|
|
|
parser = argparse.ArgumentParser(prog=self.prog, description="Borg - Deduplicated Backups", add_help=False)
|
|
parser = argparse.ArgumentParser(prog=self.prog, description="Borg - Deduplicated Backups", add_help=False)
|
|
# paths and patterns must have an empty list as default everywhere
|
|
# paths and patterns must have an empty list as default everywhere
|
|
parser.set_defaults(fallback2_func=functools.partial(self.do_maincommand_help, parser), paths=[], patterns=[])
|
|
parser.set_defaults(fallback2_func=functools.partial(self.do_maincommand_help, parser), paths=[], patterns=[])
|
|
@@ -1463,75 +1401,8 @@ class Archiver(
|
|
mid_common_parser.set_defaults(paths=[], patterns=[])
|
|
mid_common_parser.set_defaults(paths=[], patterns=[])
|
|
parser.common_options.add_common_group(mid_common_parser, "_midcommand")
|
|
parser.common_options.add_common_group(mid_common_parser, "_midcommand")
|
|
|
|
|
|
- # borg mount
|
|
|
|
- mount_epilog = process_epilog(
|
|
|
|
- """
|
|
|
|
- This command mounts an archive as a FUSE filesystem. This can be useful
|
|
|
|
- for browsing an archive or restoring individual files. When restoring,
|
|
|
|
- take into account that the current FUSE implementation does not support
|
|
|
|
- special fs flags and ACLs.
|
|
|
|
-
|
|
|
|
- Unless the ``--foreground`` option is given the command will run in the
|
|
|
|
- background until the filesystem is ``umounted``.
|
|
|
|
-
|
|
|
|
- The command ``borgfs`` provides a wrapper for ``borg mount``. This can also be
|
|
|
|
- used in fstab entries:
|
|
|
|
- ``/path/to/repo /mnt/point fuse.borgfs defaults,noauto 0 0``
|
|
|
|
-
|
|
|
|
- To allow a regular user to use fstab entries, add the ``user`` option:
|
|
|
|
- ``/path/to/repo /mnt/point fuse.borgfs defaults,noauto,user 0 0``
|
|
|
|
-
|
|
|
|
- For FUSE configuration and mount options, see the mount.fuse(8) manual page.
|
|
|
|
-
|
|
|
|
- Borg's default behavior is to use the archived user and group names of each
|
|
|
|
- file and map them to the system's respective user and group ids.
|
|
|
|
- Alternatively, using ``numeric-ids`` will instead use the archived user and
|
|
|
|
- group ids without any mapping.
|
|
|
|
-
|
|
|
|
- The ``uid`` and ``gid`` mount options (implemented by Borg) can be used to
|
|
|
|
- override the user and group ids of all files (i.e., ``borg mount -o
|
|
|
|
- uid=1000,gid=1000``).
|
|
|
|
-
|
|
|
|
- The man page references ``user_id`` and ``group_id`` mount options
|
|
|
|
- (implemented by fuse) which specify the user and group id of the mount owner
|
|
|
|
- (aka, the user who does the mounting). It is set automatically by libfuse (or
|
|
|
|
- the filesystem if libfuse is not used). However, you should not specify these
|
|
|
|
- manually. Unlike the ``uid`` and ``gid`` mount options which affect all files,
|
|
|
|
- ``user_id`` and ``group_id`` affect the user and group id of the mounted
|
|
|
|
- (base) directory.
|
|
|
|
-
|
|
|
|
- Additional mount options supported by borg:
|
|
|
|
-
|
|
|
|
- - versions: when used with a repository mount, this gives a merged, versioned
|
|
|
|
- view of the files in the archives. EXPERIMENTAL, layout may change in future.
|
|
|
|
- - allow_damaged_files: by default damaged files (where missing chunks were
|
|
|
|
- replaced with runs of zeros by borg check ``--repair``) are not readable and
|
|
|
|
- return EIO (I/O error). Set this option to read such files.
|
|
|
|
- - ignore_permissions: for security reasons the "default_permissions" mount
|
|
|
|
- option is internally enforced by borg. "ignore_permissions" can be given to
|
|
|
|
- not enforce "default_permissions".
|
|
|
|
-
|
|
|
|
- The BORG_MOUNT_DATA_CACHE_ENTRIES environment variable is meant for advanced users
|
|
|
|
- to tweak the performance. It sets the number of cached data chunks; additional
|
|
|
|
- memory usage can be up to ~8 MiB times this number. The default is the number
|
|
|
|
- of CPU cores.
|
|
|
|
-
|
|
|
|
- When the daemonized process receives a signal or crashes, it does not unmount.
|
|
|
|
- Unmounting in these cases could cause an active rsync or similar process
|
|
|
|
- to unintentionally delete data.
|
|
|
|
-
|
|
|
|
- When running in the foreground ^C/SIGINT unmounts cleanly, but other
|
|
|
|
- signals or crashes do not.
|
|
|
|
- """
|
|
|
|
- )
|
|
|
|
-
|
|
|
|
if parser.prog == "borgfs":
|
|
if parser.prog == "borgfs":
|
|
- parser.description = self.do_mount.__doc__
|
|
|
|
- parser.epilog = mount_epilog
|
|
|
|
- parser.formatter_class = argparse.RawDescriptionHelpFormatter
|
|
|
|
- parser.help = "mount repository"
|
|
|
|
- define_borg_mount(parser)
|
|
|
|
- return parser
|
|
|
|
|
|
+ return self.build_parser_borgfs(parser)
|
|
|
|
|
|
subparsers = parser.add_subparsers(title="required arguments", metavar="<command>")
|
|
subparsers = parser.add_subparsers(title="required arguments", metavar="<command>")
|
|
|
|
|
|
@@ -1540,6 +1411,7 @@ class Archiver(
|
|
self.build_parser_compact(subparsers, common_parser, mid_common_parser)
|
|
self.build_parser_compact(subparsers, common_parser, mid_common_parser)
|
|
self.build_parser_diff(subparsers, common_parser, mid_common_parser)
|
|
self.build_parser_diff(subparsers, common_parser, mid_common_parser)
|
|
self.build_parser_locks(subparsers, common_parser, mid_common_parser)
|
|
self.build_parser_locks(subparsers, common_parser, mid_common_parser)
|
|
|
|
+ self.build_parser_mount_umount(subparsers, common_parser, mid_common_parser)
|
|
self.build_parser_prune(subparsers, common_parser, mid_common_parser)
|
|
self.build_parser_prune(subparsers, common_parser, mid_common_parser)
|
|
|
|
|
|
# borg create
|
|
# borg create
|
|
@@ -2492,17 +2364,6 @@ class Archiver(
|
|
)
|
|
)
|
|
define_archive_filters_group(subparser)
|
|
define_archive_filters_group(subparser)
|
|
|
|
|
|
- subparser = subparsers.add_parser(
|
|
|
|
- "mount",
|
|
|
|
- parents=[common_parser],
|
|
|
|
- add_help=False,
|
|
|
|
- description=self.do_mount.__doc__,
|
|
|
|
- epilog=mount_epilog,
|
|
|
|
- formatter_class=argparse.RawDescriptionHelpFormatter,
|
|
|
|
- help="mount repository",
|
|
|
|
- )
|
|
|
|
- define_borg_mount(subparser)
|
|
|
|
-
|
|
|
|
# borg recreate
|
|
# borg recreate
|
|
recreate_epilog = process_epilog(
|
|
recreate_epilog = process_epilog(
|
|
"""
|
|
"""
|
|
@@ -2743,29 +2604,6 @@ class Archiver(
|
|
"repository as well. Default: no quota.",
|
|
"repository as well. Default: no quota.",
|
|
)
|
|
)
|
|
|
|
|
|
- # borg umount
|
|
|
|
- umount_epilog = process_epilog(
|
|
|
|
- """
|
|
|
|
- This command un-mounts a FUSE filesystem that was mounted with ``borg mount``.
|
|
|
|
-
|
|
|
|
- This is a convenience wrapper that just calls the platform-specific shell
|
|
|
|
- command - usually this is either umount or fusermount -u.
|
|
|
|
- """
|
|
|
|
- )
|
|
|
|
- subparser = subparsers.add_parser(
|
|
|
|
- "umount",
|
|
|
|
- parents=[common_parser],
|
|
|
|
- add_help=False,
|
|
|
|
- description=self.do_umount.__doc__,
|
|
|
|
- epilog=umount_epilog,
|
|
|
|
- formatter_class=argparse.RawDescriptionHelpFormatter,
|
|
|
|
- help="umount repository",
|
|
|
|
- )
|
|
|
|
- subparser.set_defaults(func=self.do_umount)
|
|
|
|
- subparser.add_argument(
|
|
|
|
- "mountpoint", metavar="MOUNTPOINT", type=str, help="mountpoint of the filesystem to umount"
|
|
|
|
- )
|
|
|
|
-
|
|
|
|
self.build_parser_tar(subparsers, common_parser, mid_common_parser)
|
|
self.build_parser_tar(subparsers, common_parser, mid_common_parser)
|
|
|
|
|
|
self.build_parser_transfer(subparsers, common_parser, mid_common_parser)
|
|
self.build_parser_transfer(subparsers, common_parser, mid_common_parser)
|