#! /bin/bash
#
# RMX
# Version 1.04.14
# WangBo
# 2008.04.03
#
# Version 1.04.17
# WangBo
# 2008.04.17
# add handle for mutil files
#
#
# This shell script for "rmx" that is a delete and retrieve file script.
#
#echo "########################### DEBUG RMX ############################"
EXIT_SUCCESS=0
EXIT_ARGUMENT_INVALID=91
declare -ri FALSE=0
declare -ri TRUE=1
# Define the option struct
declare -i OPT_CLEAN=$FALSE # -c option
declare -i OPT_DESTROY=$FALSE # -d option and filename
OPT_DESTROY_FILENAME=""
declare -i OPT_LIST=$FALSE # -l option and filename
OPT_LIST_FILENAME=""
declare -i OPT_RETRIEVE=$FALSE # -r option and filename
OPT_RETRIEVE_FILENAME=""
declare -i OPT_INFORMATION=$FALSE # -i option and filename
OPT_INFORATION_FILENAME=""
declare -i OPT_VERSION=$FALSE # -V option
declare -i OPT_HELP=$FALSE
DELETED_FILENAME="" # filename for deleted.
declare -i DELETED_FILE_COUNT=0 # delete file index
declare -a DELETED_FILE_VECTOR # for mutil deleted file.
# Define the work dir.
RMX_DIR=""
#
# Show version information and help information and copyright
#
show_version()
{
local VERSION="RMX Version 1.04.17"
echo $VERSION
}
show_help()
{
local HELP="RMX help : /n
/trmx [filename1] [filename2] .../n
/trmx [-i [filename]] [-c] [-d [filename]] [-l [filename]] /
[-r [filename]] [-V] [-h] /n/n
/trmx /n
/t/tShow version and help information. /n
/trmx -i [filename] /n
/t/tShow deleted file informations, no filename is show all deleted files. /n
/trmx -c /n
/t/tClean the deleted files. /n
/trmx -d [filename] /n
/t/tDestroy the deleted file, no filename is the same of -c. /n
/trmx -l [filename] /n
/t/tShow the deleted file, no filename is show all deleted files. /n
/trmx -r [filename] /n
/t/tRetrieve the deleted file, no filename is retrieved all deleted files. /n
/trmx -V /n
/t/tShow rmx version informations. /n
/trmx -h /n
/t/tShow rmx help informations."
echo -e $HELP
}
show_copyright()
{
echo "Copyrighe (C) 2002 - 2008 ActiveSys.Wangbo"
}
#
# check the arguments
#
check_option()
{
#
# Check the if the rmx is no arguments.
#
if [ $# -eq 0 ]
then
show_version
show_copyright
echo
show_help
exit $EXIT_SUCCESS
fi
#
# Check the options.
#
while [ ! -z "$1" ]
do
case "$1" in
"-c")
OPT_CLEAN=$TRUE
;;
"-d")
OPT_DESTROY=$TRUE
if [ -z "$2" ]
then
OPT_DESTROY=$FALSE
OPT_CLEAN=$TRUE
elif [ "${2:0:1}" == "-" ]
then
OPT_DESTROY=$FALSE
OPT_CLEAN=$TRUE
else
OPT_DESTROY_FILENAME="$2"
shift
fi
;;
"-h")
OPT_HELP=$TRUE
;;
"-i")
OPT_INFORMATION=$TRUE
if [ ! -z "$2" ]
then
if [ ! "${2:0:1}" == "-" ]
then
OPT_INFORATION_FILENAME="$2"
shift
fi
fi
;;
"-l")
OPT_LIST=$TRUE
if [ ! -z "$2" ]
then
if [ ! "${2:0:1}" == "-" ]
then
OPT_LIST_FILENAME="$2"
shift
fi
fi
;;
"-r")
OPT_RETRIEVE=$TRUE
if [ ! -z "$2" ]
then
if [ ! "${2:0:1}" == "-" ]
then
OPT_RETRIEVE_FILENAME="$2"
shift
fi
fi
;;
"-V")
OPT_VERSION=$TRUE
;;
*)
if [ "${1:0:1}" == "-" ]
then
echo "Invalid argument: $1"
show_help
exit $EXIT_ARGUMENT_INVALID
else
#DELETED_FILENAME="$1"
DELETED_FILE_VECTOR[$DELETED_FILE_COUNT]="$1"
((DELETED_FILE_COUNT++))
fi
;;
esac
shift
done
# If the -c option set other option invalid except -r -V -h and delete file
if [ $OPT_CLEAN -eq $TRUE ]
then
OPT_DESTROY=$FALSE
OPT_DESTROY_FILENAME=""
OPT_INFORMATION=$FALSE
OPT_INFORATION_FILENAME=""
OPT_LIST=$FALSE
OPT_LIST_FILENAME=""
fi
# If show information set and list set use the same name that close the list option
if [ $OPT_INFORMATION -eq $TRUE ]
then
# show all deleted files.
if [ -z "$OPT_INFORATION_FILENAME" ]
then
OPT_LIST=$FALSE
OPT_LIST_FILENAME=""
# list option set.
elif [ $OPT_LIST -eq $TRUE ]
then
# list filename equal show information filename.
if [ "$OPT_LIST_FILENAME" == "$OPT_INFORATION_FILENAME" ]
then
OPT_LIST=$FALSE
OPT_LIST_FILENAME=""
fi
fi
fi
}
#
# Trash operation
#
# show stat of file
show_stat()
{
local FILE_MSG=`cat $RMX_DIR/.$1`
local FILE_DIR="${FILE_MSG#*:}"
FILE_DIR="${FILE_DIR%:*}"
local FILE_NAME="${FILE_MSG%%:*}"
local FILE_PATH="$FILE_DIR/$FILE_NAME"
local FILE_ATTR=${FILE_MSG##*:}
echo " File: $FILE_NAME"
echo " Path: $FILE_PATH"
echo " Access: 0$FILE_ATTR"
stat --format=" Size: %s
Type: %F
Device: %D (%T : %t)
Blocks: %b
IO Block: %o
Inode: %i
Links: %h
Group: %G (%g)
User: %U (%u)
Time: Access: %x (%X)
Modify: %y (%Y)
Change: %z (%Z)" $RMX_DIR/$1
echo
}
# Show information
show_information()
{
local RESULT=""
local FILE_MSG=""
local INFO_COUNT=0
if [ $OPT_INFORMATION -eq $TRUE ]
then
if [ ! -z "$OPT_INFORATION_FILENAME" ]
then
RESULT=`ls $RMX_DIR`
if [ ! -z "$RESULT" ]
then
for RESULT in $RMX_DIR/*
do
FILE_MSG=`cat $RMX_DIR/.${RESULT##*/}`
if [ "${FILE_MSG%%:*}" == "$OPT_INFORATION_FILENAME" ]
then
((INFO_COUNT++))
show_stat ${RESULT##*/}
fi
done
if [ $INFO_COUNT -eq 0 ]
then
echo "rmx : /"$OPT_INFORATION_FILENAME/" : No such file or directory"
fi
else
echo "rmx : /"$OPT_INFORATION_FILENAME/" : No such file or directory"
fi
else
RESULT=`ls $RMX_DIR`
if [ ! -z "$RESULT" ]
then
for RESULT in $RMX_DIR/*
do
show_stat ${RESULT##*/}
done
fi
fi
fi
}
# List deleted file
list_file()
{
local RESULT=""
local FILE_MSG=""
local FILE_NAME=""
local LIST_COUNT=0
if [ $OPT_LIST -eq $TRUE ]
then
if [ ! -z "$OPT_LIST_FILENAME" ]
then
RESULT=`ls $RMX_DIR`
if [ ! -z "$RESULT" ]
then
for RESULT in $RMX_DIR/*
do
FILE_MSG=`cat $RMX_DIR/.${RESULT##*/}`
if [ "${FILE_MSG%%:*}" == "$OPT_LIST_FILENAME" ]
then
((LIST_COUNT++))
echo "$OPT_LIST_FILENAME"
fi
done
if [ $LIST_COUNT -eq 0 ]
then
echo "rmx : /"$OPT_LIST_FILENAME/" : No such file or directory"
fi
else
echo "rmx : /"$OPT_LIST_FILENAME/" : No such file or directory"
fi
else
RESULT=`ls $RMX_DIR`
if [ ! -z "$RESULT" ]
then
for RESULT in $RMX_DIR/*
do
FILE_MSG=`cat $RMX_DIR/.${RESULT##*/}`
echo "${FILE_MSG%%:*}"
done
fi
fi
fi
}
# Retrieve deleted file
move_file()
{
# the format of msg file is
#path:rights
local QUESTION=""
local FILE_MSG=`cat $RMX_DIR/.$1`
local FILE_DIR="${FILE_MSG%:*}"
FILE_DIR="${FILE_DIR#*:}"
local FILE_NAME="${FILE_MSG%%:*}"
local FILE_ATTR="${FILE_MSG##*:}"
local FILE_PATH="$FILE_DIR/$FILE_NAME"
#echo "--$1--$RMX_DIR--$FILE_MSG--$FILE_DIR--$FILE_NAME--$FILE_ATTR--$FILE_PATH--"
# the path is the same of an exist directory
if [ -d "$FILE_PATH" ]
then
# the same name in the director as the deleted file
if [ -e "$FILE_PATH/${FILE_PATH##*/}" ]
then
echo -n "rmx : overwrite /"$FILE_PATH/${FILE_PATH##*/}/"? "
read QUESTION
if [ "${QUESTION:0:1}" == "y" -o "${QUESTION:0:1}" == "Y" ]
then
chmod $FILE_ATTR "$RMX_DIR/$1"
mv -f "$RMX_DIR/$1" "$FILE_PATH/${FILE_PATH##*/}"
rm -f "$RMX_DIR/.$1"
fi
else
chmod $FILE_ATTR "$RMX_DIR/$1"
mv -f "$RMX_DIR/$1" "$FILE_PATH/${FILE_PATH##*/}"
rm -f "$RMX_DIR/.$1"
fi
else
if [ -e "$FILE_PATH" ]
then
echo -n "rmx : overwrite /"$FILE_PATH/"? "
read QUESTION
if [ "${QUESTION:0:1}" == "y" -o "${QUESTION:0:1}" == "Y" ]
then
chmod $FILE_ATTR "$RMX_DIR/$1"
mv -f "$RMX_DIR/$1" "$FILE_PATH"
rm -f "$RMX_DIR/.$1"
fi
else
chmod $FILE_ATTR "$RMX_DIR/$1"
mv -f "$RMX_DIR/$1" "$FILE_PATH"
rm -f "$RMX_DIR/.$1"
fi
fi
}
retrieve_file()
{
local RESULT=""
local FILE_MSG=""
local FILE_PATH=""
local FILE_NAME=""
local FILE_DIR=""
local RET_COUNT=0
local QUESTION=""
local RET_FLAG=0
if [ $OPT_RETRIEVE -eq $TRUE ]
then
if [ ! -z "$OPT_RETRIEVE_FILENAME" ]
then
RESULT=`ls $RMX_DIR`
if [ ! -z "$RESULT" ]
then
for RESULT in $RMX_DIR/*
do
FILE_MSG=`cat $RMX_DIR/.${RESULT##*/}`
if [ "${FILE_MSG%%:*}" == "$OPT_RETRIEVE_FILENAME" ]
then
# get the file ni the array
FILE_VECTOR[$RET_COUNT]="${RESULT##*/}"
((RET_COUNT++))
fi
done
if [ $RET_COUNT -eq 0 ]
then
echo "rmx : /"$OPT_RETRIEVE_FILENAME/" : No such file or directory"
elif [ $RET_COUNT -eq 1 ]
then
move_file ${FILE_VECTOR[0]}
else
for ((i = 0; i < RET_COUNT; i++))
do
FILE_MSG=`cat $RMX_DIR/.${FILE_VECTOR[$i]}`
FILE_NAME="${FILE_MSG%%:*}"
FILE_DIR="${FILE_MSG%:*}"
FILE_DIR="${FILE_DIR#*:}"
FILE_PATH="$FILE_DIR/$FILE_NAME"
echo "$i : /"$FILE_NAME/" (Original Path : $FILE_PATH)"
done
while [ $RET_FLAG -eq 0 ]
do
echo -n "retrieve [0 - $((RET_COUNT-1)) / a / q] : "
read QUESTION
case "$QUESTION" in
[0-9]*)
if [ $QUESTION -lt $RET_COUNT -a $QUESTION -ge 0 ]
then
move_file ${FILE_VECTOR[$QUESTION]}
RET_FLAG=1
else
echo "invalid command"
continue
fi
;;
"a"|"A")
for ((i = 0; i < RET_COUNT; i++))
do
move_file ${FILE_VECTOR[$i]}
done
RET_FLAG=1
;;
"q"|"Q")
RET_FLAG=1
;;
*)
echo "invalid command"
;;
esac
done
fi
else
echo "rmx : /"$OPT_RETRIEVE_FILENAME/" : No such file or directory"
fi
else
RESULT=`ls $RMX_DIR`
if [ ! -z "$RESULT" ]
then
for RESULT in $RMX_DIR/*
do
move_file ${RESULT##*/}
done
fi
fi
fi
}
# Destroy file include clean
destroy_file()
{
local QUESTION=""
local RESULT=""
local FILE_NAME=""
local FILE_PATH=""
local FILE_MSG=""
local DEL_COUNT=0
if [ $OPT_CLEAN -eq $TRUE ]
then
RESULT=`ls $RMX_DIR`
if [ ! -z "$RESULT" ]
then
echo -n "rmx : destroy all deleted file? "
read QUESTION
if [ "${QUESTION:0:1}" == "y" -o "${QUESTION:0:1}" == "Y" ]
then
for RESULT in $RMX_DIR/*
do
chmod 777 "$RESULT"
rm -r -f "$RESULT"
rm -r -f "$RMX_DIR/.${RESULT##*/}"
done
fi
fi
elif [ $OPT_DESTROY -eq $TRUE ]
then
RESULT=`ls $RMX_DIR`
if [ ! -z "$RESULT" ]
then
for RESULT in $RMX_DIR/*
do
FILE_MSG=`cat $RMX_DIR/.${RESULT##*/}`
FILE_NAME=${FILE_MSG%%:*}
FILE_PATH=${FILE_MSG#*:}
FILE_PATH=${FILE_PATH%:*}
if [ "$FILE_NAME" == "$OPT_DESTROY_FILENAME" ]
then
((DEL_COUNT++))
echo "rmx : /"$FILE_NAME (Original Path : $FILE_PATH/$FILE_NAME)/""
echo -n "destroy it? "
read QUESTION
if [ "${QUESTION:0:1}" == "y" -o "${QUESTION:0:1}" == "Y" ]
then
chmod 777 "$RESULT"
rm -r -f "$RESULT"
rm -r -f "$RMX_DIR/.${RESULT##*/}"
fi
fi
done
if [ $DEL_COUNT -eq 0 ]
then
echo "rmx : /"$OPT_DESTROY_FILENAME/" : No such file or directory"
fi
else
echo "rmx : /"$OPT_DESTROY_FILENAME/" : No such file or directory"
fi
fi
}
# Delete file
delete_file()
{
local FILE_DIR=""
local FILE_PATH=""
local FILE_ATTR=""
local FILE_NAME=""
local TRA_NAME=""
local CUR_SECONDS=""
local MOD_SECONDS=""
local DEL_FILE_LEN=""
for((i = 0; i < DELETED_FILE_COUNT; i++))
do
DELETED_FILENAME="${DELETED_FILE_VECTOR[$i]}"
DEL_FILE_LEN=${#DELETED_FILENAME}
if [ ! -z "$DELETED_FILENAME" ]
then
# can't delete /
while [ "${DELETED_FILENAME:((DEL_FILE_LEN-1))}" == "/" ]
do
DELETED_FILENAME="${DELETED_FILENAME%/}"
DEL_FILE_LEN=${#DELETED_FILENAME}
done
if [ -z "$DELETED_FILENAME" ]
then
echo "rmx : $DELETED_FILENAME/ : Permission denied"
return
fi
DEL_FILE_LEN=${#DELETED_FILENAME}
if [ "${DELETED_FILENAME:((DEL_FILE_LEN-1))}" == "." -o /
"${DELETED_FILENAME:((DEL_FILE_LEN-2))}" == ".." ]
then
echo "rmx : $DELETED_FILENAME : Invalid argument"
return
fi
if [ $DELETED_FILENAME == "/" -o $DELETED_FILENAME == "$HOME" ]
then
echo "rmx : $DELETED_FILENAME : Permission denied"
return
fi
if [ "${DELETED_FILENAME:0:1}" != "/" ]
then
DELETED_FILENAME="./$DELETED_FILENAME"
fi
# get file dir
FILE_NAME="${DELETED_FILENAME##*/}"
FILE_DIR="${DELETED_FILENAME%/*}"
if [ -z "$FILE_DIR" ]
then
FILE_DIR="$PWD" # current project e.g. file
else
cd "$FILE_DIR" 2&>/dev/null # goto the directory and ignore the error
if [ $? -eq 0 ]
then
FILE_DIR="$PWD"
cd - > /dev/null
else
echo "rmx : $DELETED_FILENAME : Permission denied"
return
fi
fi
FILE_PATH="$FILE_DIR/$FILE_NAME"
if [ -e "$FILE_PATH" ]
then
FILE_ATTR=`stat --format=%a $FILE_PATH`
if [ -e "$RMX_DIR/$FILE_NAME" ]
then
CUR_SECOND=`date +%s`
MOD_SECONDS=`stat --format=%Y $FILE_PATH`
TRA_NAME="$FILE_NAME.$CUR_SECOND.$MOD_SECONDS.$$"
mv -f "$FILE_PATH" "$RMX_DIR/$TRA_NAME"
chmod 000 "$RMX_DIR/$TRA_NAME"
echo "$FILE_NAME:$FILE_DIR:$FILE_ATTR" > "$RMX_DIR/.$TRA_NAME"
chmod 400 "$RMX_DIR/.$TRA_NAME"
else
mv -f "$FILE_PATH" "$RMX_DIR/$FILE_NAME"
chmod 000 "$RMX_DIR/$FILE_NAME"
echo "$FILE_NAME:$FILE_DIR:$FILE_ATTR" > "$RMX_DIR/.$FILE_NAME"
chmod 400 "$RMX_DIR/.$FILE_NAME"
fi
else
echo "rmx : /"$FILE_PATH/" : No suce file or directory"
fi
fi
done
}
#
# rmx shell script start here
#
check_option "$@"
# Check the ~/.rmx is exist or not
if [ ! -d "$HOME/.rmx" ]
then
mkdir "$HOME/.rmx"
chmod 700 "$HOME/.rmx"
fi
RMX_DIR="$HOME/.rmx"
# Execute show information
list_file
show_information
retrieve_file
destroy_file
delete_file
if [ $OPT_VERSION -eq $TRUE ]
then
show_version
fi
if [ $OPT_HELP -eq $TRUE ]
then
show_help
fi
exit $EXIT_SUCCESS