3 #=======================================================================
5 # File ID: 5818b856-0ba9-11de-b2c1-000475e441b9
7 # Move a whole subdirectory tree into a single .tar.gz file.
9 # Author: Øyvind A. Holm <sunny@sunbase.org>
10 # License: GNU General Public License version 2 or later.
11 #=======================================================================
62 " -n "$progname" -- "$@
")"
63 test "$?" = "0" ||
exit 1
82 opt_suffix
="$STD_SUFFIX"
91 -G|
--no-git-check) opt_no_git_check
=1; shift ;;
92 -d|
--dirs-only) opt_dirs_only
=1; shift ;;
93 -f|
--force) opt_force
=1; shift ;;
94 -h|
--help) opt_help
=1; shift ;;
95 -i|
--incremental) opt_incremental
=1; shift ;;
96 -L|
--dereference) opt_dereference
=1; shift ;;
97 -m|
--random-mac) opt_random_mac
=1; shift ;;
98 --no-uuid) opt_no_uuid
=1; shift ;;
99 --numeric-owner) opt_numeric_owner
=1; shift ;;
100 -o|
--output-dir) opt_output_dir
="$2"; shift 2 ;;
101 -P|
--prefix) opt_prefix
="$2"; shift 2 ;;
102 -q|
--quiet) opt_quiet
=$
(($opt_quiet + 1)); shift ;;
103 -r|
--remove-files) opt_remove_files
=1; shift ;;
104 -S|
--suffix) opt_suffix
="$2"; shift 2 ;;
105 -s|
--split) opt_split
="$2"; shift 2 ;;
106 -O|
--stdout) opt_stdout
=1; shift ;;
107 -v|
--verbose) opt_verbose
=$
(($opt_verbose + 1)); shift ;;
108 --version) echo $progname $VERSION; exit 0 ;;
109 -A|
--no-actime) opt_no_actime
=1; shift ;;
110 -X|
--no-xattrs) opt_no_xattrs
=1; shift ;;
111 -x|
--xz) opt_xz
=1; shift ;;
112 -z|
--gzip) opt_gzip
=1; shift ;;
114 *) echo $progname: Internal error
>&2; exit 1 ;;
117 opt_verbose
=$
(($opt_verbose - $opt_quiet))
119 if [ -n "$POSIXLY_CORRECT" ]; then
122 echo $progname: POSIXLY_CORRECT
= \"$POSIXLY_CORRECT\" >&2
126 if test "$opt_help" = "1"; then
127 test $opt_verbose -gt 0 && { echo; echo $progname $VERSION; }
130 Move a whole subdirectory tree into a single $STD_SUFFIX.tar.gz file.
132 Usage: $progname [options] DIRECTORY [DIRECTORIES [...]]
137 Alias for "--split 1G". No file systems should have problems with
138 this size, and it makes it easy to calculate the size of the .tar
141 Ignore non-directory arguments.
143 Don't abort if the .tar file exists, delete it before proceeding.
145 To protect against potential data loss, it first loops through all
146 arguments to check that none of them are stored in Git. If any files
147 are stored under any of the directories, it aborts. Useful with for
148 example git-annex, where only a symlink would be stored in the
149 archive file. This option disables the check.
153 Create a .snar file with information for creating incremental
154 backups. Uses the -g/--listed-incremental option in GNU tar.
156 Don't pack symlinks, include the actual files they point to.
158 Use random MAC address in UUID file label.
160 Don't create UUID label in the .tar file.
162 Use numbers for user/group names.
164 Send the .tar output to stdout instead of creating files on disk.
165 All nonsensical options are ignored, for example --split. Does not
166 work with compression.
167 -o DIR, --output-dir DIR
168 Store the tar files in DIR instead of the current directory.
169 -P PREFIX, --prefix PREFIX
170 Use PREFIX at the beginning of the tar filenames. Doesn't change the
171 name of the extracted files. Adds a terminating '.' if it doesn't
174 Be more quiet. Can be repeated to increase silence.
176 Remove files in DIRECTORY immediately after they've been added to
177 the archive. Can be used when there's not enough disk space for the
179 -S SUFFIX, --suffix SUFFIX
180 Add a custom suffix after the directory name and before the .tar
181 extension in the output filename. No changes are made to the
182 resulting tar file, only the file name is different. An intial '.'
183 is added if it's missing.
184 Default value: "$STD_SUFFIX".
185 -s SIZE, --split SIZE
186 Split the .tar file into files with SIZE bytes each. Allowed values
187 are those understood by the -b/--bytes option in split(1). These
188 files are not compressed by default, to make it easier to extract
189 data from the files without starting from the beginning.
191 Increase level of verbosity. Can be repeated.
193 Print version information.
195 Don't store atime or ctime in the tar file. Use with --no-uuid to
196 generate identical tar files.
198 Don't use --xattrs with tar(1), create standard tar archive without
199 extended attributes and nanoseconds.
201 Compress the archives with xz(1) after the files are added.
203 Compress the archives with gzip(1) after the files are added.
209 if test "$opt_xz" = "1" -a "$opt_gzip" = "1"; then
210 echo $progname: Cannot mix the
--gzip and
--xz options
>&2
214 if test "$opt_1" = "1" -a -n "$opt_split"; then
215 echo $progname: Cannot mix the
-1 and
--split options
>&2
219 if test "$opt_stdout" = "1" -a -n "$(echo $opt_gzip$opt_xz | grep 1)"; then
220 echo $progname: Cannot use compression with
-O/--stdout >&2
224 test "$opt_1" = "1" && opt_split
=1G
226 if test "$opt_dereference" = "1"; then
227 dereference_str
="--dereference"
232 if test "$opt_no_actime" = "1"; then
233 actime_str
="--pax-option=delete=atime,delete=ctime"
238 if test "$opt_random_mac" = "1"; then
239 random_mac_str
="--random-mac"
244 if test "$opt_remove_files" = "1"; then
245 rm_files_str
="--remove-files"
250 if test "$opt_no_xattrs" = "1"; then
253 xattrs_str
="--xattrs"
256 if test "$opt_numeric_owner" = "1"; then
257 numeric_str
="--numeric-owner"
263 if test -d "$f" -o "$opt_dirs_only" != "1"; then
264 if test "$opt_no_git_check" != "1"; then
265 git ls-files
"$f" |
grep -q .
>&2 && {
266 echo -n "$progname: $f: " >&2
267 if test -d "$f"; then
268 echo Files are stored
in Git below this directory
>&2
270 echo File is stored
in Git
>&2
272 echo $progname: Use
-G/--no-git-check to add it anyway
>&2
277 echo $progname: $f: Not a directory
>&2
282 if test -n "$prefix"; then
283 echo "$prefix" |
grep -q '\.$' || prefix
="$prefix."
287 if test -n "$suffix"; then
288 echo "$suffix" |
grep -q '^\.' || suffix
=".$suffix"
291 if test -n "$opt_output_dir"; then
292 if test ! -d "$opt_output_dir/."; then
293 echo "$progname: $opt_output_dir: Directory not found" >&2
296 output_dir
="$opt_output_dir/"
302 dir
="$(echo -n "$f" | sed 's/\/*$//')"
303 if [ -z "$dir" ]; then
304 echo "$progname: $f: Argument is empty after stripping slash" >&2
307 tarfile
="$output_dir$prefix$dir$suffix.tar"
309 if test $opt_verbose -ge 2; then
310 echo $progname: dir
= $dir >&2
313 if [ -d "$dir" -o "$opt_dirs_only" != "1" ]; then
315 echo $progname: Packing
$dir...
>&2
317 if test "$opt_stdout" != "1"; then
318 if ls "$tarfile"* 2>/dev
/null |
grep -q .
; then
319 if test "$opt_force" = "1"; then
322 echo "$progname: $tarfile* already exist" >&2
328 echo "$dir" |
grep -q / && {
329 echo "$progname: $dir: Slashes not allowed in the file name" >&2
333 if test "$opt_no_uuid" = "1"; then
337 suuid
-t mktar
--raw -w eo
$random_mac_str \
338 -c "<c_mktar> <filename>$tarfile</filename> <host>$(
340 )</host> <directory>$(/bin/pwd)</directory> </c_mktar>"
342 echo $progname: suuid error
>&2
345 label_str
="--label=$uuid"
347 if test "$opt_incremental" = "1"; then
348 incremental_str
="--listed-incremental $prefix$dir$suffix.snar"
352 tar_args
="$incremental_str $rm_files_str"
353 tar_args
="$tar_args --force-local $actime_str --sort=name --sparse"
354 tar_args
="$tar_args $dereference_str $numeric_str $xattrs_str"
355 tar_args
="$tar_args $label_str"
356 if test "$opt_stdout" = "1"; then
357 echo $progname: Sending to stdout
>&2
358 echo $progname: tar c
$tar_args $dir >&2
359 tar c
$tar_args "$dir" ||
exit 1
362 if test -n "$opt_split"; then
363 echo $progname: tar c
$tar_args $dir \
364 \|
split -b $opt_split --verbose - $tarfile.split_
>&2
365 tar c
$tar_args "$dir" \
366 |
split -b $opt_split --verbose - "$tarfile.split_" ||
exit 1
367 if test ! -e "$tarfile.split_ab"; then
368 mv -vi "$tarfile.split_aa" "$tarfile" ||
exit 1
370 test "$opt_xz" = "1" && xz
-v "$tarfile"*
371 test "$opt_gzip" = "1" && gzip -vn --rsyncable "$tarfile"*
373 echo $progname: tar cf
$tarfile $tar_args $dir >&2
374 tar cf
"$tarfile" $tar_args "$dir" ||
exit 1
375 if test "$opt_stdout" != "1"; then
377 | numfmt
--to=si
--format=%7.2f
--round=nearest
>&2
378 test "$opt_xz" = "1" && xz
-v "$tarfile"
379 test "$opt_gzip" = "1" && gzip -vn --rsyncable "$tarfile"