3 # https://sourceware.org/bugzilla/show_bug.cgi?id=26034
4 export "BUP_ARGV_0"="$0"
7 export "BUP_ARGV_${arg_i}"="$arg"
11 # Here to end of preamble replaced during install
12 bup_python="$(dirname "$0")/bup-python" || exit $?
13 exec "$bup_python" "$0"
17 # Copyright (C) 2010 Rob Browning
19 # This code is covered under the terms of the GNU Library General
20 # Public License as described in the bup LICENSE file.
22 # TODO: Add tar-like -C option.
24 from __future__ import absolute_import
26 from bup import compat, metadata
27 from bup import options
28 from bup.compat import argv_bytes
29 from bup.io import byte_stream
30 from bup.helpers import handle_ctrl_c, log, saved_errors
34 if not name or name == b'-':
35 return byte_stream(sys.stdin)
36 return open(name, 'rb')
39 def open_output(name):
40 if not name or name == b'-':
42 return byte_stream(sys.stdout)
43 return open(name, 'wb')
47 bup meta --create [OPTION ...] <PATH ...>
48 bup meta --list [OPTION ...]
49 bup meta --extract [OPTION ...]
50 bup meta --start-extract [OPTION ...]
51 bup meta --finish-extract [OPTION ...]
52 bup meta --edit [OPTION ...] <PATH ...>
54 c,create write metadata for PATHs to stdout (or --file)
55 t,list display metadata
56 x,extract perform --start-extract followed by --finish-extract
57 start-extract build tree matching metadata provided on standard input (or --file)
58 finish-extract finish applying standard input (or --file) metadata to filesystem
59 edit alter metadata; write to stdout (or --file)
60 f,file= specify source or destination file
61 R,recurse recurse into subdirectories
62 xdev,one-file-system don't cross filesystem boundaries
63 numeric-ids apply numeric IDs (user, group, etc.) rather than names
64 symlinks handle symbolic links (default is true)
65 paths include paths in metadata (default is true)
66 set-uid= set metadata uid (via --edit)
67 set-gid= set metadata gid (via --edit)
68 set-user= set metadata user (via --edit)
69 unset-user remove metadata user (via --edit)
70 set-group= set metadata group (via --edit)
71 unset-group remove metadata group (via --edit)
72 v,verbose increase log output (can be used more than once)
73 q,quiet don't show progress meter
78 o = options.Options(optspec)
79 (opt, flags, remainder) = o.parse(['--paths', '--symlinks', '--recurse']
82 opt.verbose = opt.verbose or 0
83 opt.quiet = opt.quiet or 0
84 metadata.verbose = opt.verbose - opt.quiet
85 opt.file = argv_bytes(opt.file) if opt.file else None
87 action_count = sum([bool(x) for x in [opt.create, opt.list, opt.extract,
88 opt.start_extract, opt.finish_extract,
91 o.fatal("bup: only one action permitted: --create --list --extract --edit")
93 o.fatal("bup: no action specified")
96 if len(remainder) < 1:
97 o.fatal("no paths specified for create")
98 output_file = open_output(opt.file)
99 metadata.save_tree(output_file,
100 [argv_bytes(r) for r in remainder],
102 write_paths=opt.paths,
103 save_symlinks=opt.symlinks,
106 if len(remainder) > 0:
107 o.fatal("cannot specify paths for --list")
108 src = open_input(opt.file)
109 metadata.display_archive(src, open_output(b'-'))
110 elif opt.start_extract:
111 if len(remainder) > 0:
112 o.fatal("cannot specify paths for --start-extract")
113 src = open_input(opt.file)
114 metadata.start_extract(src, create_symlinks=opt.symlinks)
115 elif opt.finish_extract:
116 if len(remainder) > 0:
117 o.fatal("cannot specify paths for --finish-extract")
118 src = open_input(opt.file)
119 metadata.finish_extract(src, restore_numeric_ids=opt.numeric_ids)
121 if len(remainder) > 0:
122 o.fatal("cannot specify paths for --extract")
123 src = open_input(opt.file)
124 metadata.extract(src,
125 restore_numeric_ids=opt.numeric_ids,
126 create_symlinks=opt.symlinks)
128 if len(remainder) < 1:
129 o.fatal("no paths specified for edit")
130 output_file = open_output(opt.file)
132 unset_user = False # True if --unset-user was the last relevant option.
133 unset_group = False # True if --unset-group was the last relevant option.
135 if flag[0] == '--set-user':
137 elif flag[0] == '--unset-user':
139 elif flag[0] == '--set-group':
141 elif flag[0] == '--unset-group':
144 for path in remainder:
145 f = open(argv_bytes(path), 'rb')
147 for m in metadata._ArchiveIterator(f):
148 if opt.set_uid is not None:
150 m.uid = int(opt.set_uid)
152 o.fatal("uid must be an integer")
154 if opt.set_gid is not None:
156 m.gid = int(opt.set_gid)
158 o.fatal("gid must be an integer")
162 elif opt.set_user is not None:
163 m.user = argv_bytes(opt.set_user)
167 elif opt.set_group is not None:
168 m.group = argv_bytes(opt.set_group)
176 log('WARNING: %d errors encountered.\n' % len(saved_errors))