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 #=======================================================================
60 " -n "$progname" -- "$@
")"
61 test "$?" = "0" ||
exit 1
80 opt_suffix
="$STD_SUFFIX"
88 -G|
--no-git-check) opt_no_git_check
=1; shift ;;
89 -d|
--dirs-only) opt_dirs_only
=1; shift ;;
90 -f|
--force) opt_force
=1; shift ;;
91 -h|
--help) opt_help
=1; shift ;;
92 -i|
--incremental) opt_incremental
=1; shift ;;
93 -L|
--dereference) opt_dereference
=1; shift ;;
94 -m|
--random-mac) opt_random_mac
=1; shift ;;
95 --no-uuid) opt_no_uuid
=1; shift ;;
96 --numeric-owner) opt_numeric_owner
=1; shift ;;
97 -o|
--output-dir) opt_output_dir
="$2"; shift 2 ;;
98 -P|
--prefix) opt_prefix
="$2"; shift 2 ;;
99 -q|
--quiet) opt_quiet
=$
(($opt_quiet + 1)); shift ;;
100 -r|
--remove-files) opt_remove_files
=1; shift ;;
101 -S|
--suffix) opt_suffix
="$2"; shift 2 ;;
102 -s|
--split) opt_split
="$2"; shift 2 ;;
103 -v|
--verbose) opt_verbose
=$
(($opt_verbose + 1)); shift ;;
104 --version) echo $progname $VERSION; exit 0 ;;
105 -A|
--no-actime) opt_no_actime
=1; shift ;;
106 -X|
--no-xattrs) opt_no_xattrs
=1; shift ;;
107 -x|
--xz) opt_xz
=1; shift ;;
108 -z|
--gzip) opt_gzip
=1; shift ;;
110 *) echo $progname: Internal error
>&2; exit 1 ;;
113 opt_verbose
=$
(($opt_verbose - $opt_quiet))
115 if test "$opt_help" = "1"; then
116 test $opt_verbose -gt 0 && { echo; echo $progname $VERSION; }
119 Move a whole subdirectory tree into a single $STD_SUFFIX.tar.gz file.
121 Usage: $progname [options] DIRECTORY [DIRECTORIES [...]]
126 Alias for "--split 1G". No file systems should have problems with
127 this size, and it makes it easy to calculate the size of the .tar
130 Ignore non-directory arguments.
132 Don't abort if the .tar file exists, delete it before proceeding.
134 To protect against potential data loss, it first loops through all
135 directories to check that no files under the directories are stored
136 in a parent Git repository. If any files are stored under any of the
137 directories, it aborts. It is useful for example with git-annex,
138 where only a symlink would be stored in the archive file. This
139 option disables the check.
143 Create a .snar file with information for creating incremental
144 backups. Uses the -g/--listed-incremental option in GNU tar.
146 Don't pack symlinks, include the actual files they point to.
148 Use random MAC address in UUID file label.
150 Don't create UUID label in the .tar file.
152 Use numbers for user/group names.
153 -o DIR, --output-dir DIR
154 Store the tar files in DIR instead of the current directory.
155 -P PREFIX, --prefix PREFIX
156 Use PREFIX at the beginning of the tar filenames. Doesn't change the
157 name of the extracted files. Adds a terminating '.' if it doesn't
160 Be more quiet. Can be repeated to increase silence.
162 Remove files in DIRECTORY immediately after they've been added to
163 the archive. Can be used when there's not enough disk space for the
165 -S SUFFIX, --suffix SUFFIX
166 Add a custom suffix after the directory name and before the .tar
167 extension in the output filename. No changes are made to the
168 resulting tar file, only the file name is different. An intial '.'
169 is added if it's missing.
170 Default value: "$STD_SUFFIX".
171 -s SIZE, --split SIZE
172 Split the .tar file into files with SIZE bytes each. Allowed values
173 are those understood by the -b/--bytes option in split(1). These
174 files are not compressed by default, to make it easier to extract
175 data from the files without starting from the beginning.
177 Increase level of verbosity. Can be repeated.
179 Print version information.
181 Don't store atime or ctime in the tar file. Use with --no-uuid to
182 generate identical tar files.
184 Don't use --xattrs with tar(1), create standard tar archive without
185 extended attributes and nanoseconds.
187 Compress the archives with xz(1) after the files are added.
189 Compress the archives with gzip(1) after the files are added.
195 if test "$opt_xz" = "1" -a "$opt_gzip" = "1"; then
196 echo $progname: Cannot mix the
--gzip and
--xz options
>&2
200 if test "$opt_1" = "1" -a -n "$opt_split"; then
201 echo $progname: Cannot mix the
-1 and
--split options
>&2
205 test "$opt_1" = "1" && opt_split
=1G
207 if test "$opt_dereference" = "1"; then
208 dereference_str
="--dereference"
213 if test "$opt_no_actime" = "1"; then
214 actime_str
="--pax-option=delete=atime,delete=ctime"
219 if test "$opt_random_mac" = "1"; then
220 random_mac_str
="--random-mac"
225 if test "$opt_remove_files" = "1"; then
226 rm_files_str
="--remove-files"
231 if test "$opt_no_xattrs" = "1"; then
234 xattrs_str
="--xattrs"
237 if test "$opt_numeric_owner" = "1"; then
238 numeric_str
="--numeric-owner"
244 if test -d "$f" -o "$opt_dirs_only" != "1"; then
245 if test "$opt_no_git_check" != "1"; then
246 git ls-files
"$f" |
grep -q .
>&2 && {
247 echo -n "$progname: $f: " >&2
248 if test -d "$f"; then
249 echo Files are stored
in Git below this directory
>&2
251 echo File is stored
in Git
>&2
253 echo $progname: Use
-G/--no-git-check to add it anyway
>&2
258 echo $progname: $f: Not a directory
>&2
263 if test -n "$prefix"; then
264 echo "$prefix" |
grep -q '\.$' || prefix
="$prefix."
268 if test -n "$suffix"; then
269 echo "$suffix" |
grep -q '^\.' || suffix
=".$suffix"
272 if test -n "$opt_output_dir"; then
273 if test ! -d "$opt_output_dir/."; then
274 echo "$progname: $opt_output_dir: Directory not found" >&2
277 output_dir
="$opt_output_dir/"
283 dir
="$(echo -n "$f" | sed 's/\/*$//')"
284 if [ -z "$dir" ]; then
285 echo "$progname: $f: Argument is empty after stripping slash" >&2
288 tarfile
="$output_dir$prefix$dir$suffix.tar"
290 if test $opt_verbose -ge 2; then
291 echo $progname: dir
= $dir >&2
294 if [ -d "$dir" -o "$opt_dirs_only" != "1" ]; then
296 echo $progname: Packing
$dir...
>&2
298 if ls "$tarfile"* 2>/dev
/null |
grep -q .
; then
299 if test "$opt_force" = "1"; then
302 echo "$progname: $tarfile* already exist" >&2
307 echo "$dir" |
grep -q / && {
308 echo "$progname: $dir: Slashes not allowed in the file name" >&2
312 if test "$opt_no_uuid" = "1"; then
316 suuid
-t mktar
--raw -w eo
$random_mac_str \
317 -c "<c_mktar> <filename>$tarfile</filename> <host>$(
319 )</host> <directory>$(/bin/pwd)</directory> </c_mktar>"
321 echo $progname: suuid error
>&2
324 label_str
="--label=$uuid"
326 if test "$opt_incremental" = "1"; then
327 incremental_str
="--listed-incremental $prefix$dir$suffix.snar"
331 if test -n "$opt_split"; then
332 echo $progname: tar c
$incremental_str $rm_files_str \
333 --force-local $actime_str --sort=name
--sparse \
334 $dereference_str $numeric_str $xattrs_str $dir \| \
335 split -b $opt_split --verbose - $tarfile.split_
>&2
336 tar c
$incremental_str $rm_files_str \
337 --force-local $actime_str --sort=name
--sparse \
338 $dereference_str $numeric_str $xattrs_str \
340 split -b $opt_split --verbose - "$tarfile.split_" ||
exit 1
341 if test ! -e "$tarfile.split_ab"; then
342 mv -vi "$tarfile.split_aa" "$tarfile" ||
exit 1
344 test "$opt_xz" = "1" && xz
-v "$tarfile"*
345 test "$opt_gzip" = "1" && gzip -vn --rsyncable "$tarfile"*
347 echo $progname: tar cf
$tarfile $incremental_str $rm_files_str \
348 --force-local $actime_str --sort=name
--sparse \
349 $dereference_str $numeric_str $xattrs_str $dir >&2
350 tar cf
"$tarfile" $incremental_str $rm_files_str \
351 --force-local $actime_str --sort=name
--sparse \
352 $dereference_str $numeric_str $xattrs_str \
353 $label_str "$dir" ||
exit 1
354 ls -la "$tarfile" >&2
355 test "$opt_xz" = "1" && xz
-v "$tarfile"
356 test "$opt_gzip" = "1" && gzip -vn --rsyncable "$tarfile"