[comp.sources.misc] v03i075: "can" a fast "C" version, a great alias for "rm"

athey@cod.nosc.mil (The Bit Butcher) (07/08/88)

Posting-number: Volume 3, Issue 75
Submitted-by: "The Bit Butcher" <athey@cod.nosc.mil>
Archive-name: can2

	This is a "C" version of an earlier posting of mine.  It is a
great alias for "rm".  It moves the file to your personal trashcan.
If you are consistently bothered by users or are a user yourself
who is bothered by you own ineptitude in removal of files you
realize you really don't want gone then this is just the thing for
you.  Enjoy.

	Yes, I know that this is amazingly similiar to the "rmunrm"
package that can be found at simtel20, but I just thought that since
mine is pretty fast and has some nice options, at least as far
as I am concerned.  One thing that the other package does that I
don't is preserve directories.  In other words, if you "can" two
files with the same name you will only have the last one you "can"ned.

			-the bit butcher

mail me:   athey@nosc.mil

#! /bin/sh
# This is a shell archive.  Remove anything before this line, then unpack
# it by saving it into a file and typing "sh file".  To overwrite existing
# files, type "sh file -c".  You can also feed this as standard input via
# unshar, or by typing "sh <file", e.g..  If this archive is complete, you
# will see the following message at the end:
#		"End of shell archive."
# Contents:  ReadMe Makefile.BSD Makefile.SUN Makefile.SYSV can.1 can.c
#   can.h emptytrash emptytrash.8 recurcan.c xdevcan.c
# Wrapped by athey@unicorn on Thu Jul  7 10:35:01 1988
PATH=/bin:/usr/bin:/usr/ucb ; export PATH
if test -f 'ReadMe' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'ReadMe'\"
else
echo shar: Extracting \"'ReadMe'\" \(2456 characters\)
sed "s/^X//" >'ReadMe' <<'END_OF_FILE'
XWell, I am back again and you may not be rejoicing.
X
XThis is CAN 2.0.
XYes it is all (almost all) new.
X
XFirst, what you need to do to make this nifty thing for yourself
Xor your system (if you are the system manager)
X
X1.  Copy the appropriate Makefile to Makefile and then compile.
X2.  Edit emptytrash to make it look in the trashcans of your system.
X3.  Install all of this wonderful stuff (Don't forget the man pages).
X    Make sure to make "emptytrash" executable by the crontab that will run it.
X
XSecond, So why have you wasted my time again or why version 2.0?
X
X1.  Well, I rewrote the entire can in C.  This made it move twice as fast.
X	Still a little slower than rm but certainly much nicer.
X2.  In the process of rewriting it, I added the verbose option and the 
X	interactive option.
X
XThird, There are some things about this that you should know.
X
X1.  This is my first attempt at a "C" utility but as far as I can tell,
X	it does the trick.
X2.  It only changes the access time, not the modification time and then
X	empties trash on the basis of access time.  So, if you are really
X	hard-core, you can see if the one you removed and then recovered is
X	really the version you want.
X3.  This has the same handicap as my original script.  You can only recover
X	one file at a time, and you must know it's specific name.  If I have
X	time I will try my best to fix this problem.
X4.  The listing option is very primitive but since it traverses the
X	directory tree by where it is placed, the last things canned are
X	usually at the end of the list.  I, once again, will do what I can
X	to repair these features (bugs?).
X5.  This is my first time passing around multiple system designs.
X	If I have a poor conception of what any system is like please let
X	me know at the address below. (rhyme?)
X6.  You may have the possibility of a pathname greater than 80.  I rarely do.
X	To remedy any problems caused by this, simply change the define
X	entitled MAXPATHLEN.
X7.  May be possible to add a force option, but I don't see the necessity
X	of it right now.
X
XIf you have any complaints or you have bug fixes or
Xanything of the sort please write me at
X
X            "athey@nosc.mil"
X
XPlease write me if you install this and find it useful.
XJust a quick note would be great, everybody.
XI mean let me know if I should keep posting this artwork (junk?).
X		-the bit butcher
X
XNOTE: CAN 2.01  now we can deal with cross device canning.
XNOTE: CAN 2.02  segmented and cleaned code.
END_OF_FILE
if test 2456 -ne `wc -c <'ReadMe'`; then
    echo shar: \"'ReadMe'\" unpacked with wrong size!
fi
# end of 'ReadMe'
fi
if test -f 'Makefile.BSD' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'Makefile.BSD'\"
else
echo shar: Extracting \"'Makefile.BSD'\" \(307 characters\)
sed "s/^X//" >'Makefile.BSD' <<'END_OF_FILE'
XCFLAGS        = -O -DBSD
X
XDEST	      = /cd441/athey/bin
X
XLIBS	      =
X
XLINKER	      = cc
X
XMAKEFILE      = Makefile
X
XOBJS	      = can.o recurcan.c xdevcan.c
X
XPROGRAM	      = can
X
XSRCS	      = can.c
X
Xall:		$(PROGRAM)
X
X$(PROGRAM):     $(OBJS) 
X		$(LINKER) $(OBJS) $(LIBS) -o $(PROGRAM)
X
Xclean:;		rm -f $(OBJS)
END_OF_FILE
if test 307 -ne `wc -c <'Makefile.BSD'`; then
    echo shar: \"'Makefile.BSD'\" unpacked with wrong size!
fi
# end of 'Makefile.BSD'
fi
if test -f 'Makefile.SUN' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'Makefile.SUN'\"
else
echo shar: Extracting \"'Makefile.SUN'\" \(307 characters\)
sed "s/^X//" >'Makefile.SUN' <<'END_OF_FILE'
XCFLAGS        = -O -DSUN
X
XDEST	      = /cd441/athey/bin
X
XLIBS	      =
X
XLINKER	      = cc
X
XMAKEFILE      = Makefile
X
XOBJS	      = can.o recurcan.c xdevcan.c
X
XPROGRAM	      = can
X
XSRCS	      = can.c
X
Xall:		$(PROGRAM)
X
X$(PROGRAM):     $(OBJS) 
X		$(LINKER) $(OBJS) $(LIBS) -o $(PROGRAM)
X
Xclean:;		rm -f $(OBJS)
END_OF_FILE
if test 307 -ne `wc -c <'Makefile.SUN'`; then
    echo shar: \"'Makefile.SUN'\" unpacked with wrong size!
fi
# end of 'Makefile.SUN'
fi
if test -f 'Makefile.SYSV' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'Makefile.SYSV'\"
else
echo shar: Extracting \"'Makefile.SYSV'\" \(327 characters\)
sed "s/^X//" >'Makefile.SYSV' <<'END_OF_FILE'
XCFLAGS        = -O -DSYSV
X
XDEST	      = /cd441/athey/bin
X
XLIBS	      = -lndir -ljobs
X
XLINKER	      = cc
X
XMAKEFILE      = Makefile
X
XOBJS	      = can.o recurcan.o xdevcan.o
X
XPROGRAM	      = can
X
XSRCS	      = can.c
X
Xall:		$(PROGRAM)
X
X$(PROGRAM):     $(OBJS) can.h
X		$(LINKER) $(OBJS) $(LIBS) -o $(PROGRAM)
X
Xclean:;		rm -f $(OBJS)
END_OF_FILE
if test 327 -ne `wc -c <'Makefile.SYSV'`; then
    echo shar: \"'Makefile.SYSV'\" unpacked with wrong size!
fi
# end of 'Makefile.SYSV'
fi
if test -f 'can.1' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'can.1'\"
else
echo shar: Extracting \"'can.1'\" \(1788 characters\)
sed "s/^X//" >'can.1' <<'END_OF_FILE'
X.\" @(#)run.1	10.2 (MASSCOMP) 8/14/86
X.RL "local"
X.TH CAN 1
X.SH NAME
Xcan \- a replacement for rm that is safe
X.SH SYNOPSIS
X\fB can [ ivlrR ] <file | directory> ...
X.br
X.ns
X.SH DESCRIPTION
X.I Can
Xis often an alias of
X.I rm(1).
X.I Can
Xworks similiarly, with the exception of putting things into a directory, in
Xyour home directory, called ".trashcan."
XThe
X.B -i
Xoption makes it interactive, querying for each "can"-ing.
XThe 
X.B -v
Xoption gives a verbose following of all activities of this command.
XThe
X.B -l
Xoption will give you a listing of the "$HOME/.trashcan"
Xdirectory.
XThe
X.B -r
Xoption works recursively just the same as 
X.I rm(1).
X.sp
XThe 
X.B -R
Xoption will retrieve a file from the "$HOME/.trashcan" without the hassle
Xof looking for it.  The
X.B -R
Xoption copies the file from the "$HOME/.trashcan" directory into the
Xpresent working directory.  This can only recover one file at a time and
Xis the only option that requires an argument.  You should
Xnote that
X.B -R
Xwill destroy the file in the working directory if it has the same name
Xas the file that is being recovered, so use with caution.
XYou cannot use 
X.B -r
Xand
X.B -R
Xin the same command and the file to be recoved must not have a directory
Xname in it.
X.sp
XThe trash gets dumped everyday but only gets rid of things that
Xare more than a week old.  In other words, you have a week to get something
Xback after you have
X.I can
Xned it.
X.SH FILES
X.TP 2.5i
X$HOME/.trashcan
XThe reservoir of canned files
X.SH SEE ALSO
X.I
Xemptytrash(8), rm(1)
X.SH BUGS
XThe 
X.B -R
Xoption does not work on wild cards.  You have to know the
Xexact name of a file in order to recover it with this command.
X.sp
XIf further bugs are found please report them.
X.SH AUTHOR
XThe Bit Butcher
X.br
XInspired by the original
X.B can
Xwhich was written by a Russ Sage.
END_OF_FILE
echo shar: 1 control character may be missing from \"'can.1'\"
if test 1788 -ne `wc -c <'can.1'`; then
    echo shar: \"'can.1'\" unpacked with wrong size!
fi
# end of 'can.1'
fi
if test -f 'can.c' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'can.c'\"
else
echo shar: Extracting \"'can.c'\" \(6932 characters\)
sed "s/^X//" >'can.c' <<'END_OF_FILE'
X/*************************************************************
X*	can.c	2.0
X*
X*	This is a utility to replace rm.  I hope you like it
X*
X*	written by "the bit butcher"
X*
X*	2.02 changed the error handling to cases and segmented the
X*		 program into three pieces and now have "can.h"
X*			28 June 1988
X*
X*	2.01 changed the way cross device problems are dealt with
X*        copy file from one system to the other
X*			before 28 June 1988
X*************************************************************/
X
X#include "can.h"
X
Xchar CAN[MAXPATHLEN];	/* String containing .trashcan directory*/	
Xchar ANSWER[14];		/* String used for finding interactive response */
Xint VERBOSE = 0;			/* Set if Verbose is wanted */
Xint INTERACTIVE = 0;			/* Set if Interactive is wanted */
Xlong TIME;		/* Used to get the current time */
XUTIMBUF TIMES;	/* Structure used to change the access time */
X
Xmain(argc, argv)
Xint argc;
Xchar** argv;
X{
X	int c;						/* which character in getopt */
X	DIR *DIRP;		/* Used to list the directory by pointing at .trashcan */
X	struct direct *DP;	/* Used to point at consecutive entries when listing */
X	char FILENAME[MAXPATHLEN];	/* String containing .trashcan/current file*/	
X	char *ACTNAME;		/* Points to filename without any leading directory */
X	struct stat BUF;	/* Used to point to mode info about files */
X	int RECURSIVE = 0;			/* Set if Recursive is wanted */
X#ifdef SYSV
X	int UID;	/* Variable holding user's ID */
X#endif
X#ifdef SUN
X	int UID;	/* Variable holding user's ID */
X#endif
X#ifdef BSD
X	uid_t UID;	/* Variable holding user's ID */
X#endif
X	char TEMP[MAXPATHLEN];	/* Used for quick access of file names */
X	struct passwd *USERINFO;	/* Structure used to find out $HOME dir */
X	extern int optind;	/* used to step through arguments */
X	extern char *optarg;	/* used to step through arguments */
X	int	errflag = 0;	/* Used to indicate errors in options */
X	void recurcan();	/* Say this is a void function */
X
X	/* Find out the users ID */
X	if((UID= getuid()) == NULL)
X	{
X		fprintf(stderr, "Invalid Login: Who Are You!?!\n");
X		exit(0);
X	}
X
X	/* Get his home directory from the passwd file */
X	USERINFO = getpwuid(UID);
X	if(USERINFO->pw_dir == NULL)
X	{
X		fprintf(stderr, "No Home Directory: check /etc/passwd !!!\n");
X		exit(0);
X	}
X	/*  say where the trashcan will be */
X	sprintf(CAN, "%s/.trashcan", USERINFO->pw_dir);
X
X	/* make sure there is a trashcan */
X	if (access(CAN, F_OK) != 0)
X		/* if not, make a trashcan */
X		if(mkdir(CAN, 004777) != 0)
X		{
X			perror("can");
X			exit(2);
X		}
X
X	/* could add force (-f) option later, perhaps */
X	/* Let's look at the options */
X	while((c=getopt(argc, argv, "ivlR:r")) != EOF)
X		switch(c)
X		{
X			case 'l':	/* list the contents by stepping through */
X				fprintf(stdout, "%s\n", CAN);
X				DIRP = opendir(CAN);
X		/* Could allow arguments for selective listing */
X				for(DP = readdir(DIRP); DP != NULL; DP= readdir(DIRP))
X					fprintf(stdout, "%s\n", DP->d_name);
X				closedir(DIRP);
X				exit(0);
X				break;
X			case 'v':	/* Set the verbose mode */
X				VERBOSE++;
X				break;
X			case 'i':	/* Set the interactive mode */
X				INTERACTIVE++;
X				break;
X			case 'R':	/* Recover a file */
X				if(RECURSIVE)	/* if recursive point out illegal option 
X								combination */
X				{
X					errflag++;
X					break;
X				}
X				/* get name of file to recover */
X				strcpy(TEMP, optarg);
X				/* does it have a directory in its name ? (it should not) */
X				if((ACTNAME = strrchr(TEMP, '/')) != NULL)
X				{
X					fprintf(stderr, "can: cannot access %s\n", TEMP);
X					fprintf(stderr, "    no directory names in Recovery\n");
X					continue;
X				}
X				else
X					/* name the actual file in the trashcan to get */
X					sprintf(FILENAME, "%s/%s", CAN, TEMP);
X				/* does it exist in the trashcan */
X				if(access(FILENAME, F_OK) != 0)
X				{
X					fprintf(stderr, "can: %s does not exist\n", TEMP);
X					continue;
X				}
X				/* interogate just in case */
X				if (INTERACTIVE)
X				{
X					fprintf(stdout, "can recover: %s\? ", TEMP);
X					fscanf(stdin, "%s", ANSWER);
X					if ((ANSWER[0] != 'y') && (ANSWER[0] != 'Y'))
X						continue;
X				}
X				/* get rid of file if it exists in current directory */
X				if (access(TEMP, F_OK) == 0)
X					if (unlink(TEMP) != 0)
X					{
X						perror("can");
X						continue;
X					}
X				/* get a new copy of the file into the working directory */
X				if (link(FILENAME, TEMP) != 0)
X				{
X					perror("can");
X					continue;
X				}
X				/* say it has been recycled */
X				fprintf(stdout, "%s: recovered\n", TEMP);
X				exit(0);
X				break;
X			case 'r':	/* Let's get recursive */
X				RECURSIVE++;
X				break;
X			default:	/* Errors in bad options */
X				errflag++;
X				break;
X		}
X
X		/* say if there are some bad options */
X		if(errflag)
X		{
X			fprintf(stderr, "%s\n", USAGE);
X			exit(2);
X		}
X
X		/* get the current time */
X		if((TIME =time(0)) == 0)
X		{
X			perror("can");
X			exit(2);
X		}
X		/* step through the arguments to see what to get rid of */
X		for( ; optind < argc; optind++)
X		{
X			strcpy(TEMP, argv[optind]);	/* get the next argument */
X			stat(TEMP, &BUF);	/* get file info about this file */
X			/* Check for the existence of a file that is not a directory */
X			if ((access(TEMP, F_OK) == 0) && (!(BUF.st_mode & 0040000)))
X			{
X				/* interogate */
X				if(INTERACTIVE != 0)
X				{
X					fprintf(stdout, "can %s\? ", TEMP);
X					fscanf(stdin, "%s", ANSWER);
X					if((ANSWER[0] != 'y') && (ANSWER[0] != 'Y'))
X						continue;
X				}
X				/* strip off directory names so we can trash it properly */
X				if((ACTNAME = strrchr(TEMP, '/')) != NULL)
X					sprintf(FILENAME, "%s%s", CAN, ACTNAME);
X				else
X					sprintf(FILENAME, "%s/%s", CAN, TEMP);
X				/* if it exists in the trashcan already get rid of it */
X				if (access(FILENAME, F_OK) == 0)
X					if(unlink(FILENAME) != 0)
X					{
X						perror("can3");
X						continue;
X					}
X				/* put it in the trashcan */
X				if(link(TEMP, FILENAME) != 0)
X				{
X					switch(errno)
X					{
X						case EXDEV:
X							crossdevcan(TEMP, FILENAME);
X							break;
X						default:
X							perror("can1");
X							continue;
X					}
X				}
X				/* get rid of the original */
X				if(unlink(TEMP) != 0)
X				{
X					perror("can4");
X					continue;
X				}
X				/* change the access time */
X				TIMES.actime= (time_t)TIME;
X				TIMES.modtime= BUF.st_mtime;
X				if(utime(FILENAME, &TIMES) != 0)
X				{
X					perror("can5");
X					continue;
X				}
X				/* tell them what we did if they want to know */
X				if(VERBOSE)
X					fprintf(stdout, "%s: canned\n", TEMP);
X			}
X			else
X			{
X				/* is this a directory? */
X				if(BUF.st_mode & 0040000)
X				{
X					if(RECURSIVE == 0) /* yes, then do recursion if OK */
X						fprintf(stderr, "cannot can: %s directory\n", TEMP);
X					else
X					{
X						if(INTERACTIVE != 0)
X						{
X							fprintf(stdout, "can check %s directory\? ", TEMP);
X							fscanf(stdin, "%s", ANSWER);
X							if((ANSWER[0] != 'y') && (ANSWER[0] != 'Y'))
X								continue;
X						}
X						recurcan(TEMP);
X					}
X				}
X				else	/* the file does not exist */
X					perror("can6");
X			}
X		}
X}
END_OF_FILE
if test 6932 -ne `wc -c <'can.c'`; then
    echo shar: \"'can.c'\" unpacked with wrong size!
fi
# end of 'can.c'
fi
if test -f 'can.h' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'can.h'\"
else
echo shar: Extracting \"'can.h'\" \(1096 characters\)
sed "s/^X//" >'can.h' <<'END_OF_FILE'
X/******************************************************************
X*
X*	CAN.H
X*
X*
X*
X******************************************************************/
X
X#include <stdio.h>
X#include <pwd.h>
X#include <string.h>
X#include <errno.h>
X#include <fcntl.h>
X#include <sys/types.h>
X#include <sys/timeb.h>
X#include <sys/file.h>
X#include <sys/stat.h>
X
X#ifdef SYSV
X#include <ndir.h>
X#endif
X
X#ifdef SUN
X#include <sys/dir.h>
X#endif
X
X#ifdef BSD
X#include <sys/dir.h>
X#endif
X
X#define USAGE "usage: can [ivlrR] file ..."
X#define MAXPATHLEN 80	/* Longest possible path name */
X
Xextern char CAN[];	/* String containing .trashcan directory*/	
Xextern char ANSWER[];		/* String used for finding interactive response */
Xextern int VERBOSE;			/* Set if Verbose is wanted */
Xextern int INTERACTIVE;			/* Set if Interactive is wanted */
Xextern long TIME;		/* Used to get the current time */
Xextern int errno;	/* Used to return the error value */
Xtypedef struct utimbuf
X{
X	time_t actime;	/* access time */
X	time_t modtime;	/* modification time */
X} UTIMBUF;	/* Structure used to change the access time */
Xextern UTIMBUF TIMES;
END_OF_FILE
if test 1096 -ne `wc -c <'can.h'`; then
    echo shar: \"'can.h'\" unpacked with wrong size!
fi
# end of 'can.h'
fi
if test -f 'emptytrash' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'emptytrash'\"
else
echo shar: Extracting \"'emptytrash'\" \(472 characters\)
sed "s/^X//" >'emptytrash' <<'END_OF_FILE'
X: /bin/sh
X
X# EMPTYTRASH 
X# Executed from root crontab file every night.
X# It finds all files in all users .traschan directories and gets
X# rid of any file that has not been accessed or modified for more
X# than 7 days.  Note:  this works in conjunction with can.  can
X# changes modifies the access time for a file when it moves the  
X# file to the user's .trashcan diretory.
X
Xfind /cd441/*/.trashcan -atime +7 -print | while read FILE
Xdo 
X#       echo $FILE
X	rm $FILE
Xdone
END_OF_FILE
if test 472 -ne `wc -c <'emptytrash'`; then
    echo shar: \"'emptytrash'\" unpacked with wrong size!
fi
# end of 'emptytrash'
fi
if test -f 'emptytrash.8' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'emptytrash.8'\"
else
echo shar: Extracting \"'emptytrash.8'\" \(871 characters\)
sed "s/^X//" >'emptytrash.8' <<'END_OF_FILE'
X.\" @(#)run.1	10.2 (MASSCOMP) 8/14/86
X.RL "local"
X.TH EMPTYTRASH 8
X.SH NAME
Xemptytrash \- the trash collector used with
X.I can
X.SH SYNOPSIS
X\fBemptytrash
X.br
X.ns
X.SH DESCRIPTION
X.I Emptytrash
Xsimply looks into each $HOME/.trashcan and checks the last access time
Xwhich is usually set by
X.I can(1).
XAnything that it finds that is more than seven days old it permanently
Xremoves via 
X.I rm(1).
XThis amount of time can be changed by changing the "7" in the script file.
XThe best thing to do is to put this in your root crontab file and have it
Xexecuted everyday.
X.SH FILES
X.TP 2.5i
X$HOME/.trashcan
XThe reservoir of canned files
X.SH SEE ALSO
X.I
Xcan(1), rm(1)
X.SH BUGS
XOnly that this was a quicky and could be made better by having it accept an
Xargument that would determine the amount of elapsed time to check for.
X.SH AUTHOR
XThe Bit Butcher
X.br
XWith the help of Steph Luse.
END_OF_FILE
if test 871 -ne `wc -c <'emptytrash.8'`; then
    echo shar: \"'emptytrash.8'\" unpacked with wrong size!
fi
# end of 'emptytrash.8'
fi
if test -f 'recurcan.c' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'recurcan.c'\"
else
echo shar: Extracting \"'recurcan.c'\" \(3460 characters\)
sed "s/^X//" >'recurcan.c' <<'END_OF_FILE'
X/************************************************************************
X*
X*	RECURCAN.C
X*		this is used to traverse a directory tree when doing a
X*		recursive can passed the directory to be examined
X*
X************************************************************************/
X
X#include "can.h"
X
Xvoid recurcan(temp)
Xchar *temp;
X{
X	DIR *DIRP;		/* Used to list the directory by pointing at .trashcan */
X	struct direct *DP;	/* Used to point at consecutive entries when listing */
X	char FILENAME[MAXPATHLEN];	/* String containing .trashcan/current file*/	
X	char *ACTNAME;		/* Points to filename without any leading directory */
X	struct stat BUF;	/* Used to point to mode info about files */
X	char TEMP[MAXPATHLEN];	/* this is used to look at the current file */
X	char WORKDIR[MAXPATHLEN];	/* the working directory we came from */
X
X	DIRP = opendir(temp);	/* open the directory being canned */
X	getwd(WORKDIR);	/* get the current working directory */
X	chdir(temp);	/* go to the directory to be canned */
X	/* get the next directory entry */
X	for(DP = readdir(DIRP); DP != NULL; DP= readdir(DIRP))
X	{
X		strcpy(TEMP, DP->d_name);	/* put the name in TEMP */
X		stat(TEMP, &BUF);	/* get some info about this file */
X		/* does it exist and is it not a directory */
X		if ((access(TEMP, F_OK) == 0) && (!(BUF.st_mode & 0040000)))
X		{
X			/* interogate */
X			if(INTERACTIVE != 0)
X			{
X				fprintf(stdout, "can %s\? ", TEMP);
X				fscanf(stdin, "%s", ANSWER);
X				if((ANSWER[0] != 'y') && (ANSWER[0] != 'Y'))
X					continue;
X			}
X			/* make the name of the trash file */
X			sprintf(FILENAME, "%s/%s", CAN, TEMP);
X			/* get rid of the trash version if there is one */
X			if (access(FILENAME, F_OK) == 0)
X				if(unlink(FILENAME) != 0)
X				{
X					perror("can7");
X					continue;
X				}
X			/* put file in the trash */
X			if(link(TEMP, FILENAME) != 0)
X			{
X				switch(errno)
X				{
X					case EXDEV:
X						crossdevcan(TEMP, FILENAME);
X						break;
X					default:
X						perror("can2");
X						continue;
X				}
X			}
X			/* get rid of the file here */
X			if(unlink(TEMP) != 0)
X			{
X				perror("can8");
X				continue;
X			}
X			/* change the access time */
X			TIMES.actime= (time_t)TIME;
X			TIMES.modtime= BUF.st_mtime;
X			if(utime(FILENAME, &TIMES) != 0)
X			{
X				perror("can9");
X				continue;
X			}
X			/* tell them what happened if they want to know */
X			if(VERBOSE)
X				fprintf(stdout, "%s: canned\n", TEMP);
X		}
X		else
X		{
X			/* is it a directory? */
X			if(BUF.st_mode & 0040000)
X			{
X				/* make sure it is not ".." or "." */
X				if((strcmp(TEMP,"..") != 0) && (strcmp(TEMP,".") != 0))
X				{
X					/* make sure they want to look at this directory */
X					if(INTERACTIVE != 0)
X					{
X						fprintf(stdout, "can check %s directory\? ", TEMP);
X						fscanf(stdin, "%s", ANSWER);
X						if((ANSWER[0] != 'y') && (ANSWER[0] != 'Y'))
X							continue;
X					}
X					/* get on with recursion using newest directory */
X					recurcan(TEMP);
X				}
X			}
X			else
X				perror("can10");
X		}
X	}
X	chdir(WORKDIR);	/* go back to directory from which started */
X	closedir(DIRP);	/* close the one we were canning */
X	/* make sure they want to get rid of the directory */
X	if(INTERACTIVE != 0)
X	{
X		fprintf(stdout, "can directory %s\? ", temp);
X		fscanf(stdin, "%s", ANSWER);
X		if((ANSWER[0] != 'y') && (ANSWER[0] != 'Y'))
X			return;
X	}
X	/* get rid of the directory */
X	if(rmdir(temp) != 0)
X		perror("can11");
X	else
X		/* tell them if they want to know */
X		if(VERBOSE)
X			fprintf(stdout, "%s: canned directory\n", temp);
X}
END_OF_FILE
if test 3460 -ne `wc -c <'recurcan.c'`; then
    echo shar: \"'recurcan.c'\" unpacked with wrong size!
fi
# end of 'recurcan.c'
fi
if test -f 'xdevcan.c' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'xdevcan.c'\"
else
echo shar: Extracting \"'xdevcan.c'\" \(1664 characters\)
sed "s/^X//" >'xdevcan.c' <<'END_OF_FILE'
X/***********************************************************************
X*
X*	XDEVCAN.C
X*		this is called and the file is copied via read and write to 
X*		the other device, sure it may be slow but it solves a problem 
X*		of cross device links crossdevcan(OLDFILE, NEWFILE)
X*
X***********************************************************************/
X
X#include "can.h"
X
Xcrossdevcan(OLDFILE, NEWFILE)
Xchar *OLDFILE, *NEWFILE;
X{
X	int oldFD, newFD;	/* File Descriptors for access */
X	char NEXTCHAR[512];	/* used to transfer the char to new place */
X	int RWSIZE = 512;	/* amount to read and write */
X	struct stat BUF;	/* used to transfer all stats of old file to new */
X	int n_read;	/* the number of bytes successfully read */
X
X	/* create the new file in the trashcan */
X	if((newFD = creat(NEWFILE, 00777)) < 0)
X	{
X		perror("Cross Device can");
X		return;
X	}
X	/* open the old one to be read */
X	if((oldFD = open(OLDFILE, O_RDONLY)) < 0)
X	{
X		perror("Cross Device can");
X		return;
X	}
X	/* repeatedly read and write until whole file is copied */
X	while((n_read = read(oldFD, NEXTCHAR, RWSIZE)) != 0)
X	{
X		if((write(newFD, NEXTCHAR, n_read)) != n_read)
X		{
X			perror("Cross Device can");
X			return;
X		}
X	}
X	/* close the files */
X	close(oldFD);
X	close(newFD);
X	/* get info concerning the old file */
X	stat(OLDFILE, &BUF);
X	/* make the new file's modes the same as the old one's */
X	if(chmod(NEWFILE, (int)(BUF.st_mode & 0777)) != 0)
X	{
X		perror("Cross Device can");
X		return;
X	}
X	/* make the new file's times the same as the old one's */
X	TIMES.actime= BUF.st_atime;
X	TIMES.modtime= BUF.st_mtime;
X	if(utime(NEWFILE, &TIMES) != 0)
X	{
X		perror("Cross Device can");
X		return;
X	}
X}
END_OF_FILE
if test 1664 -ne `wc -c <'xdevcan.c'`; then
    echo shar: \"'xdevcan.c'\" unpacked with wrong size!
fi
# end of 'xdevcan.c'
fi
echo shar: End of shell archive.
exit 0