diff --git a/src/borg/archive.py b/src/borg/archive.py index d89f628a44..65b9919e6e 100644 --- a/src/borg/archive.py +++ b/src/borg/archive.py @@ -1234,14 +1234,19 @@ def process_symlink(self, *, path, parent_fd, name, st): item.update(self.metadata_collector.stat_attrs(st, path)) # can't use FD here? return status - def process_pipe(self, *, path, cache, fd): - uid, gid = 0, 0 + def process_pipe(self, *, path, cache, fd, mode, user, group): + uid = user2uid(user) + if uid is None: + raise Error("no such user: %s" % user) + gid = group2gid(group) + if gid is None: + raise Error("no such group: %s" % group) t = int(time.time()) * 1000000000 item = Item( path=path, - mode=0o100660, # regular file, ug=rw - uid=uid, user=uid2user(uid), - gid=gid, group=gid2group(gid), + mode=mode & 0o107777 | 0o100000, # forcing regular file mode + uid=uid, user=user, + gid=gid, group=group, mtime=t, atime=t, ctime=t, ) self.process_file_chunks(item, cache, self.stats, self.show_progress, backup_io_iter(self.chunker.chunkify(fd))) diff --git a/src/borg/archiver.py b/src/borg/archiver.py index 5383260919..b9082f65c3 100644 --- a/src/borg/archiver.py +++ b/src/borg/archiver.py @@ -78,6 +78,7 @@ from .patterns import PatternMatcher from .item import Item from .platform import get_flags, get_process_id, SyncFile + from .platform import uid2user, gid2group from .remote import RepositoryServer, RemoteRepository, cache_if_remote from .repository import Repository, LIST_SCAN_LIMIT, TAG_PUT, TAG_DELETE, TAG_COMMIT from .selftest import selftest @@ -511,6 +512,9 @@ def create_inner(archive, cache, fso): logger.debug('Processing files ...') if args.content_from_command: path = args.stdin_name + mode = args.stdin_mode + user = args.stdin_user + group = args.stdin_group if not dry_run: try: try: @@ -518,7 +522,7 @@ def create_inner(archive, cache, fso): except (FileNotFoundError, PermissionError) as e: self.print_error('Failed to execute command: %s', e) return self.exit_code - status = fso.process_pipe(path=path, cache=cache, fd=proc.stdout) + status = fso.process_pipe(path=path, cache=cache, fd=proc.stdout, mode=mode, user=user, group=group) rc = proc.wait() if rc != 0: self.print_error('Command %r exited with status %d', args.paths[0], rc) @@ -533,9 +537,12 @@ def create_inner(archive, cache, fso): for path in args.paths: if path == '-': # stdin path = args.stdin_name + mode = args.stdin_mode + user = args.stdin_user + group = args.stdin_group if not dry_run: try: - status = fso.process_pipe(path=path, cache=cache, fd=sys.stdin.buffer) + status = fso.process_pipe(path=path, cache=cache, fd=sys.stdin.buffer, mode=mode, user=user, group=group) except BackupOSError as e: status = 'E' self.print_warning('%s: %s', path, e) @@ -3222,6 +3229,12 @@ def define_borg_mount(parser): help='experimental: do not synchronize the cache. Implies not using the files cache.') subparser.add_argument('--stdin-name', metavar='NAME', dest='stdin_name', default='stdin', help='use NAME in archive for stdin data (default: %(default)r)') + subparser.add_argument('--stdin-user', metavar='USER', dest='stdin_user', default=uid2user(0), + help='set user USER in archive for stdin data (default: %(default)r)') + subparser.add_argument('--stdin-group', metavar='GROUP', dest='stdin_group', default=gid2group(0), + help='set group GROUP in archive for stdin data (default: %(default)r)') + subparser.add_argument('--stdin-mode', metavar='M', dest='stdin_mode', type=lambda s: int(s, 8), default=STDIN_MODE_DEFAULT, + help='set mode to M in archive for stdin data (default: %(default)04o)') subparser.add_argument('--content-from-command', action='store_true', help='interpret PATH as command and store its stdout. See also section Reading from' ' stdin below.') diff --git a/src/borg/constants.py b/src/borg/constants.py index b265ec6bd1..a20719c65c 100644 --- a/src/borg/constants.py +++ b/src/borg/constants.py @@ -20,6 +20,10 @@ # default umask, overridden by --umask, defaults to read/write only for owner UMASK_DEFAULT = 0o077 +# default file mode to store stdin data, defaults to read/write for owner and group +# forcing to 0o100XXX later +STDIN_MODE_DEFAULT = 0o660 + CACHE_TAG_NAME = 'CACHEDIR.TAG' CACHE_TAG_CONTENTS = b'Signature: 8a477f597d28d172789f06886806bc55'