Przeglądaj źródła

Merge pull request #5462 from schors/master

create: implement --stdin-mode, --stdin-user and --stdin-group, fixes #5333
TW 4 lat temu
rodzic
commit
5f23ff656a
3 zmienionych plików z 29 dodań i 7 usunięć
  1. 10 5
      src/borg/archive.py
  2. 15 2
      src/borg/archiver.py
  3. 4 0
      src/borg/constants.py

+ 10 - 5
src/borg/archive.py

@@ -1234,14 +1234,19 @@ class FilesystemObjectProcessors:
             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)))

+ 15 - 2
src/borg/archiver.py

@@ -78,6 +78,7 @@ try:
     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 @@ class Archiver:
             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 @@ class Archiver:
                         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 @@ class Archiver:
                 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 @@ class Archiver:
                                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.')

+ 4 - 0
src/borg/constants.py

@@ -20,6 +20,10 @@ REQUIRED_ARCHIVE_KEYS = frozenset(['version', 'name', 'items', 'cmdline', 'time'
 # 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'