#!/bin/sh
# $Id: archive,v 1.13 2023/02/18 18:09:22 tom Exp $
# archive, unarchive -- tar and compress source for archival storage
CDPATH=
command=`basename "$0"`
 
debug="eval"
extract="-xp"
listonly=""
remove="n"
touch="n"
unarchive="n"
verbose=""
suffix="tgz"
compress="gzip"
 
while getopts "bBdhlrtuvxzZ" opt
do
        case $opt in
        b)      compress="bzip2";suffix="tar.bz2";;
        B)      compress="bzip2";suffix="tbz";;
        d)      debug="echo";;
        l)      extract="-tv"listonly="#";;
        r)      remove="y";;
        t)      touch="y";;
        u)      unarchive="y";;
        v)      verbose="v";;
        x)      compress="xz";suffix="tar.xz";;
        z)      compress="gzip";suffix="tar.gz";;
        Z)      compress="compress";suffix="tar.Z";;
        *)      cat <<eof
Usage: 
$command [options] [archive_name]
 
Options:
  -b     use bzip2 and suffix .tar.bz2
  -B     use bzip2 and suffix .tbz
  -d     debug
  -l     list-only (don't extract files)
  -r     remove directory (leave tar in parent)
  -t     touch archive (latest file)
  -u     un archive
  -v     verbose (lists filenames)
  -x     use xz and .tar.xz
  -z     use gzip and .tar.gz
  -Z     use compress and suffix .tar.Z
 
Parameters:
    archive_name   name for archive (default is current directory name)
 
By default, archive uses gzip to produce a gzip'd tar archive with suffix .tgz
eof

                exit 1;;
        --)     break;;
        -*)     exec "$0" -h;;
        esac
done
shift `expr $OPTIND - 1`
 
#-- if script is invoked as 'unarchive' do same as -u option
if [ "$command" = unarchive ]
then    unarchive="y"
fi
 
#-- figure out where we are
paths=`/bin/pwd`
 
#-- Provide default archive-name
if [ $# = 1 ]
then    dir="$1"
        arg="$1"
else    dir=$paths
        arg=.
fi
 
myfile=
SUF=".tar.gz .tgz .tar.bz2 .tbz .tar.Z .tar.xz .tz"
 
# Try to decide what the parameter is, and deduce the archive-file and its
# directory:
if [ -f "$dir" ]
then
        myfile="$dir"
        dir=`echo "$dir" |sed -e 's@/[^/]*$@@'`
        if [ "$dir" = "$myfile" ]
        then
                dir=.
        fi
        cmp=`basename "$myfile"`
        for suf in $SUF none
        do
                tst=`basename "$myfile" "$suf"`
                if [ "$cmp" != "$tst" ]
                then
                        break
                fi
        done
elif [ -d "$dir" ]
then
        for suf in $SUF none
        do
                tst=$dir/`basename $dir`$suf
                if [ -f "$tst" ]
                then
                        myfile="$tst"
                        break
                fi
        done
else
        echo "Neither a directory nor a file: $dir"
        exit 1
fi
 
if [ $unarchive = "y" ]
then
        if [ -z "$myfile" ]
        then
                echo "Cannot determine archive-file for $dir"
                exit 1
        fi
 
        case $suf in #(vi
        .tar.gz|.tgz) #(vi
                decomp="gzip -d"
                ;;
        .tar.bz2|.tbz) #(vi
                decomp="bzip2 -d"
                ;;
        .tar.xz|.tz) #(vi
                decomp="xz -d"
                ;;
        .tar.Z) #(vi
                decomp="uncompress"
                ;;
        *) #(vi
                echo "No archive found in ${dir}."
                exit 1
        esac
 
        if [ ! -w . ] && [ ".$listonly" = "." ]
        then
                $debug "chmod u+w ."
                if [ $? != 0 ]
                then
                        echo "archive: chmod error"
                        exit 1
                fi
        fi
 
        if [ "$dir" != "$paths" ]
        then
                $debug cd "$dir"
                if [ "$debug" = echo ]
                then
                        cd "$dir" || exit 1
                fi
        fi
        myfile=`basename "$myfile"`
 
        #-- uncompress and untar
        if [ ".$listonly" = "." ]
        then
                if [ ! -w . ]
                then
                        $debug chmod u+w .
                fi
                if [ -w .. ]
                then
                        $debug  "mv $myfile .."
                        if [ $? != 0 ]
                        then
                                echo "archive: mv error"
                                exit 1
                        fi
                        myfile="../$myfile"
                fi
        fi
 
        $debug  "umask 0;$decomp -c $myfile | tar ${extract}${verbose}f - 2>&1"
        if [ $? != 0 ]
        then
                echo "archive: $decomp/tar error"
                exit 1
        fi
 
        #-- remove archive
        if [ ".$listonly" = "." ]
        then
                $debug  "rm -f $myfile"
        fi
 
elif [ ".$listonly" != "." ]
then
        echo "archive: -l option applies only to dearchiving"
        exit 1
else
        test -z "$myfile" && myfile="${dir}.$suffix"
        if [ -f "$myfile" ]
        then
                echo "Archive $myfile already present."
                exit 1
        fi
        myfile=`basename "$myfile"`
 
        if [ $arg = . ]
        then    all='`ls -A`'
        else    all='`ls -Ad '$arg'`'
        fi
        $debug  "tar -c${verbose}f - $all | $compress -c >../$myfile"
        if [ $? != 0 ]
        then
                echo "archive: tar error"
                exit 1
        fi
 
        #-- obtain date for "-t" option
        if [ $touch = "y" ]
        then
                last=`find $arg -type f -print |sed -e 's/^/"/' -e 's/$/"/'`
                if [ ".$last" != "." ]
                then
                        last=`eval ls -1t $last | head -1`
                        $debug cpd "$last" ../"$myfile"
                        if [ ".$verbose" = ".v" ]
                        then
                                echo "last=$last"
                        fi
                fi
        fi
 
        #-- remove current sources
        $debug  "chmod u+w ."
        $debug  "find $arg -type d -exec chmod u+w {} \\;"
        $debug  "rm -rf $all"
 
        if [ $remove = "y" ]
        then    #-- move archive to parent, removing leaf
                leaf=`basename "$paths"`
                $debug  "cd ..;rmdir $leaf"
        else    #-- move archive back in
                $debug  "mv ../$myfile ."
                if [ $arg = . ]
                then
                        $debug  "chmod -w ."
                fi
                if [ $touch = "y" ]
                then
                        $debug cpd "$myfile" .
                fi
        fi
fi