#!/bin/sh
#
# Script used to generate/compare lists of files.
#
# Usage:
#   filelist -g -d directory [-o outputfile]
#      or
#   filelist -c -d directory -l filelist [-o outputfile] [-r removedfilelist]
#
# Where:
#   -g   Is used to request the generation of a list of all files (not directories)
#        found at or below the specified "directory".  The output has the form:
#
#        ssss bbbb name
#
#        where:
#
#            ssss = since seconds since Jan. 1, 1970, 00:00 GMT when the file was last modified
#            bbbb = size of the file in bytes
#            name = the name of the file
#
#        This option is mutually exclusive with the "-c" option.
#
#   -c   Is used to request that the contents of the specified "directory" be compared
#        against the specified "filelist" (hopefully generated using the -g option).
#        This option is mutually exclusive with the "-g" option.
#
#   -d   Is used to specify the directory to be used.  When used in conjunction with the
#        "-g" option, the list of the contents of this directory is what will be generated.
#        When used in conjunction with the -c option, the contents of this directory is
#        what will be used during the comparison.
#
#   -l   Is used to specify the "filelist" to be used to compare against the current contents
#        of the specified "directory".
#
#   -o   Is optionally used to specify a file that is to be used to write the generated
#        file list when using the "-g" option or the list of changed files when using the
#        "-c" option.  If not specified, the file list will be written to standard output.
#
#   -r   Is optionally used to specify a file that is to be used to write the list of files
#        that has been removed from the specified "directory" when performing a comparison.
#        If not specified, this list is not generated.
#
#   -?   Prints this usage text.
#
#ENDUSAGE
#
# Description: Provides common methods for generating/compare lists of file.
#
# Arguments:
#   See above
#
# Change log:
#
# 09/14/2004 Kurt Schroeder      Initial creation
# 06/02/2006 Kurt Schroeder -01  Add gid, uid, and permissions to list.
#
#****************************************************************************

giveUsage=1;
genlist=0;
cmplist=0;
outputfile="";
cmpfile="";
removedfile="";
listdir="";
format="%p %T@ %s %G %U %m\n";
tmplistfile='/tmp/$$temporary.list.file$$';

# Parse the options
while getopts 'gcd:o:l:r:?' optname; do
   case "$optname" in
      g) genlist=1;;
      c) cmplist=1;;
      d) listdir="$OPTARG";;
      o) outputfile="$OPTARG";;
      l) cmpfile="$OPTARG";;
      r) removedfile="$OPTARG";;
      \?) giveUsage=1;;
   esac
done

if [ "$genlist" -ne 0 ] && [ "$cmplist" -ne 0 ]; then
   genlist=0;
   cmplist=0;
   giveUsage=1;
   echo -e "\aError: options -g and -c are mutually exclusive.\n";
fi

if [ "$genlist" -ne 0 ]; then
   # We need to generate a list
   # Make sure the caller specified a directory to list
   if [ -n "$listdir" ]; then
      giveUsage=0;
      if [ -n "$outputfile" ]; then
         find "$listdir" -type f -printf "$format" | sort -u > "$outputfile";
      else
         find "$listdir" -type f -printf "$format" | sort -u;
      fi
   else
      echo -e "\aError: no directory specified (i.e. the -d option is missing).\n";
   fi
fi

if [ "$cmplist" -ne 0 ]; then
   # We need to compare a list
   # Make sure the caller specified a directory to compare against
   if [ -n "$listdir" ]; then
      # Make sure the caller specified a file list to compare with
      if [ -n "$cmpfile" ]; then
         # Make sure the file exists
         if [ -e "$cmpfile" ]; then
            giveUsage=0;
            # erase/recreate the output file if specified
            if [ -n "$outputfile" ]; then
               rm -f "$outputfile";
               touch "$outputfile";
            fi
            # erase/recreate the removed file if specified
            if [ -n "$removedfile" ]; then
               rm -f "$removedfile"
               touch "$removedfile"
            fi
            # generate a temporary new list of files
            find "$listdir" -type f -printf "$format" | sort -u > "$tmplistfile";
            # now figure out what has changed
            diff -d "$cmpfile" "$tmplistfile" | grep -E '^<|>' | sed -e 's/^..//' -e 's/ .*//' | sort -u | while read fn rest;
            do
               if [ -e "$fn" ]; then
                  # The file still exists, so it must be an add or change
                  if [ -n "$outputfile" ]; then
                     echo "$fn" >> "$outputfile"
                  else
                     echo "$fn"
                  fi
               else
                  # The file no longer exists, so it must be a delete
                  if [ -n "$removedfile" ]; then
                     echo "$fn" >> "$removedfile"
                  fi
               fi
            done
            rm -f "$tmpfilelist"
         else
            echo -e "\aError: the file '$cmpfile' does not exist.\n";
         fi
      else
         echo -e "\aError: no filelist specified (i.e. the -l option is missing).\n";
      fi
   else
      echo -e "\aError: no directory specified (i.e. the -d option is missing).\n";
   fi
fi

if [ "$giveUsage" -eq 1 ]; then
   # Print out the prologue comments as usage info
   sed -e '1 d' -e '2,/ENDUSAGE/ s/^#//' -e '/ENDUSAGE/,$ d' "$0"
   exit 0
fi
