rsalz@uunet.uu.net (Rich Salz) (03/29/89)
Submitted-by: Jonathan I. Kamens <jik@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@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@uunet.uu.net.