v18i075: MIT Athena delete/undelete programs, Part03/06
Rich Salz
rsalz at uunet.uu.net
Wed Mar 29 14:32:02 AEST 1989
Submitted-by: Jonathan I. Kamens <jik at PIT-MANAGER.MIT.EDU>
Posting-number: Volume 18, Issue 75
Archive-name: undel/part03
#! /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 archive 3 (of 6)."
# Contents: delete.c lsdel.c
# Wrapped by jik at pit-manager on Mon Mar 27 12:16:50 1989
PATH=/bin:/usr/bin:/usr/ucb ; export PATH
if test -f 'delete.c' -a "${1}" != "-c" ; then
echo shar: Will not clobber existing file \"'delete.c'\"
else
echo shar: Extracting \"'delete.c'\" \(9801 characters\)
sed "s/^X//" >'delete.c' <<'END_OF_FILE'
X/*
X * $Source: /mit/jik/src/delete/RCS/delete.c,v $
X * $Author: jik $
X *
X * This program is a replacement for rm. Instead of actually deleting
X * files, it marks them for deletion by prefixing them with a ".#"
X * prefix.
X *
X * Copyright (c) 1989 by the Massachusetts Institute of Technology.
X * For copying and distribution information, see the file "mit-copyright.h."
X */
X
X#if (!defined(lint) && !defined(SABER))
X static char rcsid_delete_c[] = "$Header: delete.c,v 1.17 89/03/27 12:05:58 jik Exp $";
X#endif
X
X#include <sys/types.h>
X#include <stdio.h>
X#include <sys/stat.h>
X#include <sys/dir.h>
X#include <strings.h>
X#include <sys/param.h>
X#include <sys/file.h>
X#include "util.h"
X#include "delete.h"
X#include "mit-copyright.h"
X
X
X
X
X/*
X * ALGORITHM:
X *
X * 1. Parse command-line arguments and set flags.
X * 2. Call the function delete() for each filename command-line argument.
X *
X * delete():
X *
X * 1. Can the file be lstat'd?
X * no -- abort
X * yes -- continue
X * 2. Is the file a directory?
X * yes -- is it a dotfile?
X * yes -- abort
X * no -- continue
X * -- is the filesonly option set?
X * yes -- is the recursive option specified?
X * yes -- continue
X * no -- abort
X * no -- is the directory empty?
X * yes -- remove it
X * no -- is the directoriesonly option set?
X * yes -- abort
X * no -- continue
X * -- is the recursive option specified?
X * yes -- continue
X * no -- abort
X * no -- is the directoriesonly option set?
X * yes -- abort
X * no -- continue
X * 3. If the file is a file, remove it.
X * 4. If the file is a directory, open it and pass each of its members
X * (excluding . files) to delete().
X */
X
X
Xint force, interactive, recursive, noop, verbose, filesonly, directoriesonly;
Xchar *whoami;
Xchar *malloc();
X
Xmain(argc, argv)
Xint argc;
Xchar *argv[];
X{
X extern char *optarg;
X extern int optind;
X int arg;
X int status = 0;
X
X whoami = lastpart(argv[0]);
X
X force = interactive = recursive = noop = verbose = filesonly =
X directoriesonly = 0;
X while ((arg = getopt(argc, argv, "firnvFD")) != -1) {
X switch (arg) {
X case 'r':
X recursive++;
X if (directoriesonly) {
X fprintf(stderr, "%s: -r and -D are mutually exclusive.\n",
X whoami);
X usage();
X exit(! force);
X }
X break;
X case 'f':
X force++;
X break;
X case 'i':
X interactive++;
X break;
X case 'n':
X noop++;
X break;
X case 'v':
X verbose++;
X break;
X case 'F':
X filesonly++;
X if (directoriesonly) {
X fprintf(stderr, "%s: -F and -D are mutually exclusive.\n",
X whoami);
X usage();
X exit(! force);
X }
X break;
X case 'D':
X directoriesonly++;
X if (recursive) {
X fprintf(stderr, "%s: -r and -D are mutually exclusive.\n",
X whoami);
X usage();
X exit(! force);
X }
X if (filesonly) {
X fprintf(stderr, "%s: -F and -D are mutually exclusive.\n",
X whoami);
X usage();
X exit(! force);
X }
X break;
X default:
X usage();
X exit(! force);
X }
X }
X if (optind == argc) {
X fprintf(stderr, "%s: no files specified.\n", whoami);
X usage();
X exit(! force);
X }
X while (optind < argc) {
X status = status | delete(argv[optind], 0);
X optind++;
X }
X exit((! force) && (status & ERROR_MASK));
X}
X
X
X
X
Xusage()
X{
X printf("Usage: %s [ options ] filename ...\n", whoami);
X printf("Options are:\n");
X printf(" -r recursive\n");
X printf(" -i interactive\n");
X printf(" -f force\n");
X printf(" -n noop\n");
X printf(" -v verbose\n");
X printf(" -F files only\n");
X printf(" -D directories only\n");
X printf(" -- end options and start filenames\n");
X printf("-r and -D are mutually exclusive\n");
X printf("-F and -D are mutually exclusive\n");
X}
X
X
X
X
X
X
Xdelete(filename, recursed)
Xchar *filename;
Xint recursed;
X{
X struct stat stat_buf;
X
X /* can the file be lstat'd? */
X if (lstat(filename, &stat_buf) == -1) {
X if (! force)
X fprintf(stderr, "%s: %s nonexistent\n", whoami, filename);
X return(ERROR_MASK);
X }
X
X /* is the file a directory? */
X if ((stat_buf.st_mode & S_IFMT) == S_IFDIR) {
X /* is the file a dot file? */
X if (is_dotfile(filename)) {
X if (! force)
X fprintf(stderr, "%s: cannot remove `.' or `..'\n",
X whoami);
X return(ERROR_MASK);
X }
X /* is the filesonly option set? */
X if (filesonly) {
X /* is the recursive option specified? */
X if (recursive) {
X return(recursive_delete(filename, stat_buf, recursed));
X }
X else {
X if (! force)
X fprintf(stderr, "%s: %s directory\n", whoami,
X filename);
X return(ERROR_MASK);
X }
X }
X else {
X /* is the directory empty? */
X if (empty_directory(filename)) {
X /* remove it */
X return(do_move(filename, stat_buf, 0));
X }
X else {
X /* is the directoriesonly option set? */
X if (directoriesonly) {
X if (! force)
X fprintf(stderr, "%s: %s: Directory not empty\n",
X whoami, filename);
X return(ERROR_MASK);
X }
X else {
X /* is the recursive option specified? */
X if (recursive) {
X return(recursive_delete(filename, stat_buf,
X recursed));
X }
X else {
X if (! force)
X fprintf(stderr, "%s: %s not empty\n",
X whoami, filename);
X return(ERROR_MASK);
X }
X }
X }
X }
X }
X else {
X /* is the directoriesonly option set? */
X if (directoriesonly) {
X if (! force)
X fprintf(stderr, "%s: %s: Not a directory\n", whoami,
X filename);
X return(ERROR_MASK);
X }
X else
X return(do_move(filename, stat_buf, 0));
X }
X}
X
X
X
X
Xempty_directory(filename)
Xchar *filename;
X{
X DIR *dirp;
X struct direct *dp;
X
X dirp = opendir(filename);
X if (! dirp) {
X return(0);
X }
X for (dp = readdir(dirp); dp != NULL; dp = readdir(dirp)) {
X if (is_dotfile(dp->d_name))
X continue;
X if (is_deleted(dp->d_name))
X continue;
X else {
X closedir(dirp);
X return(0);
X }
X }
X closedir(dirp);
X return(1);
X}
X
X
X
X
Xrecursive_delete(filename, stat_buf, recursed)
Xchar *filename;
Xstruct stat stat_buf;
Xint recursed;
X{
X DIR *dirp;
X struct direct *dp;
X int status = 0;
X char newfile[MAXPATHLEN];
X
X if (interactive && recursed) {
X printf("%s: remove directory %s? ", whoami, filename);
X if (! yes())
X return(NO_DELETE_MASK);
X }
X dirp = opendir(filename);
X if (! dirp) {
X if (! force)
X fprintf(stderr, "%s: %s not changed\n", whoami, filename);
X return(ERROR_MASK);
X }
X for (dp = readdir(dirp); dp != NULL; dp = readdir(dirp)) {
X if (is_dotfile(dp->d_name))
X continue;
X if (is_deleted(dp->d_name))
X continue;
X else {
X strcpy(newfile, append(filename, dp->d_name, !force));
X if (*newfile)
X status = status | delete(newfile, 1);
X else
X status = ERROR_MASK;
X }
X }
X closedir(dirp);
X status = status | do_move(filename, stat_buf, status);
X return(status);
X}
X
X
X
X
X
X
Xdo_move(filename, stat_buf, err_mask)
Xchar *filename;
Xstruct stat stat_buf;
Xint err_mask;
X{
X char *last;
X char buf[MAXPATHLEN];
X char name[MAXNAMLEN];
X struct stat deleted_buf;
X
X strncpy(buf, filename, MAXPATHLEN);
X last = lastpart(buf);
X if (strlen(last) > MAXNAMLEN) {
X if (! force)
X fprintf(stderr, "%s: %s: filename too long\n", whoami,
X filename);
X return(ERROR_MASK);
X }
X strcpy(name, last);
X if (strlen(buf) + 3 > MAXPATHLEN) {
X if (! force)
X fprintf(stderr, "%s: %s: pathname too long\n", whoami,
X filename);
X return(ERROR_MASK);
X }
X *last = '\0';
X strcat(buf, ".#");
X strcat(buf, name);
X if (err_mask) {
X if (! force)
X fprintf(stderr, "%s: %s not removed\n", whoami, filename);
X return(err_mask);
X }
X if (interactive) {
X printf("%s: remove %s? ", whoami, filename);
X if (! yes())
X return(NO_DELETE_MASK);
X }
X else if ((! force) && ((stat_buf.st_mode & S_IFMT) != S_IFLNK)
X && access(filename, W_OK)) {
X printf("%s: override protection %o for %s? ", whoami,
X stat_buf.st_mode & 0777, filename);
X if (! yes())
X return(NO_DELETE_MASK);
X }
X if (noop) {
X fprintf(stderr, "%s: %s would be removed\n", whoami, filename);
X return(0);
X }
X if (! lstat(buf, &deleted_buf))
X unlink_completely(buf);
X if (rename(filename, buf)) {
X if (! force)
X fprintf(stderr, "%s: %s not removed\n", whoami, filename);
X return(ERROR_MASK);
X }
X else {
X if (verbose)
X fprintf(stderr, "%s: %s removed\n", whoami, filename);
X return(0);
X }
X}
X
X
X
Xunlink_completely(filename)
Xchar *filename;
X{
X char buf[MAXPATHLEN];
X struct stat stat_buf;
X DIR *dirp;
X struct direct *dp;
X int status = 0;
X
X if (lstat(filename, &stat_buf))
X return(1);
X
X if ((stat_buf.st_mode & S_IFMT) == S_IFDIR) {
X dirp = opendir(filename);
X if (! dirp)
X return(1);
X readdir(dirp); readdir(dirp); /* get rid of . and .. */
X for (dp = readdir(dirp); dp != NULL; dp = readdir(dirp)) {
X strcpy(buf, append(filename, dp->d_name, 0));
X if (! buf) {
X status = 1;
X continue;
X }
X status = status | unlink_completely(buf);
X }
X closedir(dirp);
X status = status | rmdir(filename);
X return(status);
X }
X else
X return(unlink(filename) == -1);
X}
X
END_OF_FILE
if test 9801 -ne `wc -c <'delete.c'`; then
echo shar: \"'delete.c'\" unpacked with wrong size!
fi
# end of 'delete.c'
fi
if test -f 'lsdel.c' -a "${1}" != "-c" ; then
echo shar: Will not clobber existing file \"'lsdel.c'\"
else
echo shar: Extracting \"'lsdel.c'\" \(6087 characters\)
sed "s/^X//" >'lsdel.c' <<'END_OF_FILE'
X/*
X * $Source: /mit/jik/src/delete/RCS/lsdel.c,v $
X * $Author: jik $
X *
X * This program is a replacement for rm. Instead of actually deleting
X * files, it marks them for deletion by prefixing them with a ".#"
X * prefix.
X *
X * Copyright (c) 1989 by the Massachusetts Institute of Technology.
X * For copying and distribution information, see the file "mit-copyright.h."
X */
X
X#if (!defined(lint) && !defined(SABER))
X static char rcsid_lsdel_c[] = "$Header: lsdel.c,v 1.4 89/03/27 12:07:13 jik Exp $";
X#endif
X
X#include <stdio.h>
X#include <sys/types.h>
X#include <sys/dir.h>
X#include <sys/param.h>
X#include <sys/stat.h>
X#include <strings.h>
X#include "col.h"
X#include "util.h"
X#include "directories.h"
X#include "pattern.h"
X#include "lsdel.h"
X#include "mit-copyright.h"
X
Xchar *malloc(), *realloc();
Xextern int current_time;
X
Xint block_total = 0;
Xint dirsonly, recursive, timev, yield;
Xchar *whoami, *error_buf;
X
Xmain(argc, argv)
Xint argc;
Xchar *argv[];
X{
X extern char *optarg;
X extern int optind;
X int arg;
X
X whoami = lastpart(argv[0]);
X error_buf = malloc(strlen(whoami) + MAXPATHLEN + 3);
X if (! error_buf) {
X perror(whoami);
X exit(1);
X }
X dirsonly = recursive = timev = yield = 0;
X while ((arg = getopt(argc, argv, "drt:y")) != -1) {
X switch (arg) {
X case 'd':
X dirsonly++;
X break;
X case 'r':
X recursive++;
X break;
X case 't':
X timev = atoi(optarg);
X break;
X case 'y':
X yield++;
X break;
X default:
X usage();
X exit(1);
X }
X }
X if (optind == argc) {
X char *cwd;
X
X cwd = ".";
X exit(ls(&cwd, 1));
X }
X exit(ls(&argv[optind], argc - optind));
X}
X
X
X
X
X
X
Xusage()
X{
X printf("Usage: %s [ options ] [ filename [ ...]]\n", whoami);
X printf("Options are:\n");
X printf(" -d list directory names, not contents\n");
X printf(" -r recursive\n");
X printf(" -t n list n-day-or-older files only\n");
X printf(" -y report total space taken up by files\n");
X}
X
X
X
X
Xls(args, num)
Xchar **args;
Xint num;
X{
X char *start_dir;
X char **found_files;
X int num_found, total = 0;
X char *file_re;
X int status = 0;
X
X if (initialize_tree())
X exit(1);
X
X for ( ; num; num--) {
X if (*args[num - 1] == '/') {
X start_dir = "/";
X file_re = parse_pattern(args[num - 1] + 1);
X }
X else {
X start_dir = "";
X file_re = parse_pattern(args[num - 1]);
X }
X if (! file_re)
X return(ERROR_MASK);
X
X found_files = get_the_files(start_dir, file_re, &num_found);
X free(file_re);
X total += num_found;
X if (num_found)
X num_found = process_files(found_files, num_found);
X else {
X /* What we do at this point depends on exactly what the
X * file_re is. There are three possible conditions:
X * 1. It's an existing directory. Print nothing.
X * 2. It doesn't exist in deleted form, and there are
X * no wildcards in it. Then we print "not found."
X * 3. It does't exist, but there are wildcards in it.
X * Then we print "no match."
X * None of these are considered error conditions, so we
X * don't set the error flag.
X */
X if (no_wildcards(file_re)) {
X if (! directory_exists(args[num - 1])) {
X fprintf(stderr, "%s: %s: not found\n",
X whoami, args[num - 1]);
X }
X }
X else {
X fprintf(stderr, "%s: %s: no match\n",
X whoami, args[num-1]);
X }
X }
X }
X if (total) {
X list_files();
X }
X if (yield)
X printf("\nTotal space taken up by file%s: %dk\n",
X (total == 1 ? "" : "s"), blk_to_k(block_total));
X return(status);
X}
X
X
X
X
Xchar **get_the_files(start_dir, file_re, number_found)
Xchar *start_dir, *file_re;
Xint *number_found;
X{
X char **matches;
X int num_matches;
X char **found;
X int num;
X int i;
X
X found = (char **) malloc(0);
X num = 0;
X
X matches = find_matches(start_dir, file_re, &num_matches);
X if (recursive) {
X char **recurs_found;
X int recurs_num;
X
X for (i = 0; i < num_matches; free(matches[i]), i++) {
X if (is_deleted(lastpart(matches[i]))) {
X found = add_str(found, num, matches[i]);
X num++;
X }
X recurs_found = find_deleted_recurses(matches[i], &recurs_num);
X add_arrays(&found, &num, &recurs_found, &recurs_num);
X }
X }
X else {
X struct stat stat_buf;
X char **contents_found;
X int num_contents;
X
X for (i = 0; i < num_matches; free(matches[i]), i++) {
X if (is_deleted(lastpart(matches[i]))) {
X found = add_str(found, num, matches[i]);
X num++;
X }
X if (dirsonly)
X continue;
X if (lstat(matches[i], &stat_buf))
X continue;
X if ((stat_buf.st_mode & S_IFMT) == S_IFDIR) {
X contents_found = find_deleted_contents_recurs(matches[i],
X &num_contents);
X add_arrays(&found, &num, &contents_found, &num_contents);
X
X }
X }
X }
X free(matches);
X *number_found = num;
X return(found);
X}
X
X
X
X
X
X
Xprocess_files(files, num)
Xchar **files;
Xint num;
X{
X int i;
X filerec *leaf;
X
X for (i = 0; i < num; i++) {
X if (! (leaf = add_path_to_tree(files[i]))) {
X fprintf(stderr, "%s: error adding path to filename tree\n",
X whoami);
X exit(1);
X }
X
X free(files[i]);
X if (! timed_out(leaf, current_time, timev)) {
X free_leaf(leaf);
X num--;
X continue;
X }
X block_total += leaf->specs.st_blocks;
X }
X free(files);
X return(num);
X}
X
X
X
X
X
Xlist_files()
X{
X filerec *current;
X char **strings;
X int num;
X
X strings = (char **) malloc(sizeof(char *));
X num = 0;
X if (! strings) {
X perror(sprintf(error_buf, "%s: list_files", whoami));
X exit(1);
X }
X current = get_root_tree();
X strings = accumulate_names(current, strings, &num);
X current = get_cwd_tree();
X strings = accumulate_names(current, strings, &num);
X column_array(strings, num, DEF_SCR_WIDTH, 0, 0, 2, 1, 0, 1, stdout);
X for ( ; num; num--)
X free(strings[num - 1]);
X free(strings);
X return(0);
X}
END_OF_FILE
if test 6087 -ne `wc -c <'lsdel.c'`; then
echo shar: \"'lsdel.c'\" unpacked with wrong size!
fi
# end of 'lsdel.c'
fi
echo shar: End of archive 3 \(of 6\).
cp /dev/null ark3isdone
MISSING=""
for I in 1 2 3 4 5 6 ; do
if test ! -f ark${I}isdone ; then
MISSING="${MISSING} ${I}"
fi
done
if test "${MISSING}" = "" ; then
echo You have unpacked all 6 archives.
rm -f ark[1-9]isdone
else
echo You still need to unpack the following archives:
echo " " ${MISSING}
fi
## End of shell archive.
exit 0
--
Please send comp.sources.unix-related mail to rsalz at uunet.uu.net.
More information about the Comp.sources.unix
mailing list