v17i025: delete - MIT Athena delete/undelete programs, Part03/04
Jonathan I. Kamens
jik at pit-manager.MIT.EDU
Tue Feb 26 05:07:45 AEST 1991
Submitted-by: Jonathan I. Kamens <jik at pit-manager.MIT.EDU>
Posting-number: Volume 17, Issue 25
Archive-name: delete/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 4)."
# Contents: delete.c directories.c
# Wrapped by jik at pit-manager on Fri Feb 22 08:14:26 1991
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'\" \(13684 characters\)
sed "s/^X//" >'delete.c' <<'END_OF_FILE'
X/*
X * $Source: /afs/athena.mit.edu/astaff/project/delete/src/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: /afs/athena.mit.edu/astaff/project/delete/src/RCS/delete.c,v 1.24 91/02/20 17:24:51 jik Exp $";
X#endif
X
X#include <sys/types.h>
X#include <stdio.h>
X#include <sys/dir.h>
X#ifdef SYSV
X#include <string.h>
X#define index strchr
X#define rindex strrchr
X#else
X#include <strings.h>
X#endif /* SYSV */
X#include <sys/param.h>
X#include <sys/file.h>
X#include <errno.h>
X#include "errors.h"
X#include "delete_errs.h"
X#include "util.h"
X#include "delete.h"
X#include "mit-copyright.h"
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;
Xint emulate_rm, linked_to_rm, linked_to_rmdir;
Xextern int errno;
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
X initialize_del_error_table();
X
X force = interactive = recursive = noop = verbose = filesonly =
X directoriesonly = emulate_rm = linked_to_rm = linked_to_rmdir = 0;
X
X if (!strcmp(whoami, "rm"))
X emulate_rm++, filesonly++, linked_to_rm++;
X if (!strcmp(whoami, "rmdir") || !strcmp(whoami, "rd"))
X emulate_rm++, directoriesonly++, linked_to_rmdir++;
X
X while ((arg = getopt(argc, argv, "efirnvFD")) != -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(1);
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 'e':
X emulate_rm++;
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(1);
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(1);
X }
X if (filesonly) {
X fprintf(stderr, "%s: -F and -D are mutually exclusive.\n",
X whoami);
X usage();
X exit(1);
X }
X break;
X default:
X usage();
X exit(1);
X }
X }
X report_errors = ! (force || emulate_rm);
X
X if (optind == argc) {
X if (! force) {
X fprintf(stderr, "%s: no files specified.\n", whoami);
X usage();
X }
X exit(force ? 0 : 1);
X }
X while (optind < argc) {
X if (delete(argv[optind], 0))
X error(argv[optind]);
X optind++;
X }
X exit(((! force) && error_occurred) ? 1 : 0);
X}
X
X
X
Xusage()
X{
X printf("Usage: %s [ options ] filename ...\n", whoami);
X printf("Options are:\n");
X if (! linked_to_rmdir)
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 if (! (linked_to_rmdir || linked_to_rm)) {
X printf(" -e emulate rm/rmdir\n");
X printf(" -F files only\n");
X printf(" -D directories only\n");
X }
X printf(" -- end options and start filenames\n");
X if (! (linked_to_rmdir || linked_to_rm)) {
X printf("-r and -D are mutually exclusive\n");
X printf("-F and -D are mutually exclusive\n");
X }
X}
X
X
X
X
Xdelete(filename, recursed)
Xchar *filename;
Xint recursed;
X{
X struct stat stat_buf;
X int retval;
X
X /* can the file be lstat'd? */
X if (lstat(filename, &stat_buf) == -1) {
X set_error(errno);
X if (emulate_rm && (! force))
X fprintf(stderr, "%s: %s nonexistent\n", whoami, filename);
X error(filename);
X return error_code;
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(lastpart(filename))) {
X set_error(DELETE_IS_DOTFILE);
X if (emulate_rm && (! force))
X fprintf(stderr, "%s: cannot remove `.' or `..'\n", whoami);
X error(filename);
X return error_code;
X }
X
X /* is the filesonly option set? */
X if (filesonly) {
X /* is the recursive option specified? */
X if (recursive) {
X if (retval = recursive_delete(filename, stat_buf,
X recursed)) {
X error(filename);
X return retval;
X }
X }
X else {
X if (emulate_rm && (! force))
X fprintf(stderr, "%s: %s directory\n", whoami,
X filename);
X set_error(DELETE_CANT_DEL_DIR);
X error(filename);
X return error_code;
X }
X }
X else {
X /* is the directory empty? */
X if ((retval = empty_directory(filename)) < 0) {
X error(filename);
X if (! emulate_rm)
X return error_code;
X }
X
X if (retval > 0) {
X /* remove it */
X if (retval = do_move(filename, stat_buf, 0)) {
X error(filename);
X return error_code;
X }
X }
X else {
X /* is the directoriesonly option set? */
X if (directoriesonly) {
X if (emulate_rm && (! force))
X fprintf(stderr, "%s: %s: Directory not empty\n",
X whoami, filename);
X set_error(DELETE_DIR_NOT_EMPTY);
X error(filename);
X return error_code;
X }
X else {
X /* is the recursive option specified? */
X if (recursive) {
X if (retval = recursive_delete(filename, stat_buf,
X recursed)) {
X error(filename);
X return error_code;
X }
X }
X else {
X if (emulate_rm && (! force))
X fprintf(stderr, "%s: %s not empty\n",
X whoami, filename);
X set_error(DELETE_DIR_NOT_EMPTY);
X error(filename);
X return error_code;
X }
X }
X }
X }
X }
X else {
X /* is the directoriesonly option set? */
X if (directoriesonly) {
X if (emulate_rm && (! force))
X fprintf(stderr, "%s: %s: Not a directory\n", whoami,
X filename);
X set_error(DELETE_CANT_DEL_FILE);
X error(filename);
X return error_code;
X }
X else {
X if (retval = do_move(filename, stat_buf, 0)) {
X error(filename);
X return error_code;
X }
X }
X }
X return 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 set_error(errno);
X error(filename);
X return -1;
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 int retval = 0;
X
X if (interactive && recursed) {
X printf("%s: remove directory %s? ", whoami, filename);
X if (! yes()) {
X set_status(DELETE_NOT_DELETED);
X return error_code;
X }
X }
X dirp = Opendir(filename);
X if (! dirp) {
X if (emulate_rm && (! force))
X fprintf(stderr, "%s: %s not changed\n", whoami, filename);
X set_error(errno);
X error(filename);
X return error_code;
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 (void) strcpy(newfile, append(filename, dp->d_name));
X if (! *newfile) {
X error(filename);
X status = error_code;
X }
X
X retval = delete(newfile, 1);
X if (retval) {
X error(newfile);
X status = retval;
X }
X }
X }
X closedir(dirp);
X
X if (status && (! emulate_rm)) {
X set_warning(DELETE_DIR_NOT_EMPTY);
X error(filename);
X }
X else
X retval = do_move(filename, stat_buf, status);
X
X if (retval)
X status = retval;
X
X return status;
X}
X
X
X
X
X
X
Xdo_move(filename, stat_buf, subs_not_deleted)
Xchar *filename;
Xstruct stat stat_buf;
Xint subs_not_deleted; /* If the file in question is a directory, and */
X /* there is something underneath it that hasn't */
X /* been removed, this will be set to true. */
X /* The program asks if the user wants to delete */
X /* the directory, and if the user says yes, */
X /* checks the value of subs_not_deleted. If */
X /* it's true, an error results. */
X /* This is used only when emulating rm. */
X{
X char *last;
X char buf[MAXPATHLEN];
X char name[MAXNAMLEN];
X struct stat deleted_buf;
X
X (void) strncpy(buf, filename, MAXPATHLEN);
X last = lastpart(buf);
X if (strlen(last) > MAXNAMLEN) {
X if (emulate_rm && (! force))
X fprintf(stderr, "%s: %s: filename too long\n", whoami,
X filename);
X set_error(ENAMETOOLONG);
X error(filename);
X return error_code;
X }
X (void) strcpy(name, last);
X if (strlen(buf) + 3 > MAXPATHLEN) {
X if (emulate_rm && (! force))
X fprintf(stderr, "%s: %s: pathname too long\n", whoami,
X filename);
X set_error(ENAMETOOLONG);
X error(filename);
X return error_code;
X }
X *last = '\0';
X (void) strcat(buf, ".#");
X (void) strcat(buf, name);
X if (interactive) {
X printf("%s: remove %s? ", whoami, filename);
X if (! yes()) {
X set_status(DELETE_NOT_DELETED);
X return error_code;
X }
X }
X else if ((! force)
X#ifdef S_IFLNK
X && ((stat_buf.st_mode & S_IFMT) != S_IFLNK)
X#endif
X && access(filename, W_OK)) {
X if (emulate_rm)
X printf("%s: override protection %o for %s? ", whoami,
X stat_buf.st_mode & 0777, filename);
X else
X printf("%s: File %s not writeable. Delete anyway? ", whoami,
X filename);
X if (! yes()) {
X set_status(DELETE_NOT_DELETED);
X return error_code;
X }
X }
X if (emulate_rm && subs_not_deleted) {
X if (! force)
X fprintf(stderr, "%s: %s not removed\n", whoami, filename);
X return 1;
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)) && unlink_completely(buf)) {
X if (emulate_rm && (! force))
X fprintf(stderr, "%s: %s not removed\n", whoami, filename);
X error(filename);
X return error_code;
X }
X if (rename(filename, buf)) {
X if (emulate_rm && (! force))
X fprintf(stderr, "%s: %s not removed\n", whoami, filename);
X set_error(errno);
X error(filename);
X return error_code;
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 int retval;
X
X if (lstat(filename, &stat_buf)) {
X set_error(errno);
X error(filename);
X return error_code;
X }
X
X if ((stat_buf.st_mode & S_IFMT) == S_IFDIR) {
X dirp = Opendir(filename);
X if (! dirp) {
X set_error(errno);
X error(filename);
X return error_code;
X }
X
X for (dp = readdir(dirp); dp != NULL; dp = readdir(dirp)) {
X if (is_dotfile(dp->d_name))
X continue;
X (void) strcpy(buf, append(filename, dp->d_name));
X if (! *buf) {
X status = error_code;
X error(filename);
X continue;
X }
X retval = unlink_completely(buf);
X if (retval) {
X status = retval;
X error(filename);
X }
X }
X closedir(dirp);
X
X if (status)
X return status;
X
X retval = rmdir(filename);
X if (retval) {
X set_error(errno);
X error(filename);
X return errno;
X }
X }
X else {
X retval = unlink(filename);
X if (retval) {
X set_error(errno);
X error(filename);
X return error_code;
X }
X else
X return 0;
X }
X return 0;
X}
END_OF_FILE
if test 13684 -ne `wc -c <'delete.c'`; then
echo shar: \"'delete.c'\" unpacked with wrong size!
fi
# end of 'delete.c'
fi
if test -f 'directories.c' -a "${1}" != "-c" ; then
echo shar: Will not clobber existing file \"'directories.c'\"
else
echo shar: Extracting \"'directories.c'\" \(15169 characters\)
sed "s/^X//" >'directories.c' <<'END_OF_FILE'
X/*
X * $Source: /afs/athena.mit.edu/user/j/jik/delete/src/RCS/directories.c,v $
X * $Author: jik $
X *
X * This program is part of a package including delete, undelete,
X * lsdel, expunge and purge. The software suite is meant as a
X * replacement for rm which allows for file recovery.
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_directories_c[] = "$Header: /afs/athena.mit.edu/user/j/jik/delete/src/RCS/directories.c,v 1.18 91/02/22 06:32:25 jik Exp $";
X#endif
X
X#include <stdio.h>
X#include <sys/types.h>
X#include <sys/param.h>
X#include <sys/dir.h>
X#ifdef SYSV
X#include <string.h>
X#define index strchr
X#define rindex strrchr
X#else
X#include <strings.h>
X#endif /* SYSV */
X#include <errno.h>
X#include <com_err.h>
X#include "delete_errs.h"
X#include "util.h"
X#include "directories.h"
X#include "mit-copyright.h"
X#include "errors.h"
X
Xextern char *realloc();
Xextern long time();
Xextern int errno;
X
Xstatic filerec root_tree;
Xstatic filerec cwd_tree;
X
Xvoid free_leaf();
X
X /* These are not static because external routines need to be able to */
X /* access them. */
Xtime_t current_time;
X
X
Xstatic filerec default_cwd = {
X "",
X (filerec *) NULL,
X (filerec *) NULL,
X (filerec *) NULL,
X (filerec *) NULL,
X (filerec *) NULL,
X False,
X False,
X {0}
X};
X
Xstatic filerec default_root = {
X "/",
X (filerec *) NULL,
X (filerec *) NULL,
X (filerec *) NULL,
X (filerec *) NULL,
X (filerec *) NULL,
X False,
X False,
X {0}
X};
X
Xstatic filerec default_directory = {
X "",
X (filerec *) NULL,
X (filerec *) NULL,
X (filerec *) NULL,
X (filerec *) NULL,
X (filerec *) NULL,
X False,
X False,
X {0}
X};
X
Xstatic filerec default_file = {
X "",
X (filerec *) NULL,
X (filerec *) NULL,
X (filerec *) NULL,
X (filerec *) NULL,
X (filerec *) NULL,
X False,
X False,
X {0}
X};
X
X
Xfilerec *get_root_tree()
X{
X return(&root_tree);
X}
X
X
X
Xfilerec *get_cwd_tree()
X{
X return(&cwd_tree);
X}
X
X
Xint initialize_tree()
X{
X int retval;
X
X root_tree = default_root;
X cwd_tree = default_cwd;
X
X current_time = time((time_t *)0);
X if (retval = get_specs(".", &cwd_tree.specs, FOLLOW_LINKS)) {
X error("get_specs on .");
X return retval;
X }
X if (retval = get_specs("/", &root_tree.specs, FOLLOW_LINKS)) {
X error("get_specs on /");
X return retval;
X }
X return 0;
X}
X
X
Xint add_path_to_tree(path, leaf)
Xchar *path;
Xfilerec **leaf;
X{
X filerec *parent;
X char next_name[MAXNAMLEN];
X char lpath[MAXPATHLEN], built_path[MAXPATHLEN], *ptr;
X struct mystat specs;
X int retval;
X
X if (retval = get_specs(path, &specs, DONT_FOLLOW_LINKS)) {
X char error_buf[MAXPATHLEN+14];
X
X (void) sprintf(error_buf, "get_specs on %s", path);
X error(error_buf);
X return retval;
X }
X
X (void) strcpy(lpath, path); /* we don't want to damage the user's */
X /* string */
X ptr = lpath;
X if (*ptr == '/') {
X parent = &root_tree;
X ptr++;
X (void) strcpy(built_path, "/");
X }
X else if (! strncmp(ptr, "./", 2)) {
X parent = &cwd_tree;
X ptr += 2;
X *built_path = '\0';
X }
X else {
X parent = &cwd_tree;
X *built_path = '\0';
X }
X
X (void) strcpy(next_name, firstpart(ptr, ptr));
X while (*ptr) {
X (void) strcat(built_path, next_name);
X if (retval = add_directory_to_parent(parent, next_name, False,
X &parent)) {
X error("add_directory_to_parent");
X return retval;
X }
X (void) strcpy(next_name, firstpart(ptr, ptr));
X if (retval = get_specs(built_path, &parent->specs, FOLLOW_LINKS)) {
X char error_buf[MAXPATHLEN+14];
X
X (void) sprintf(error_buf, "get_specs on %s", built_path);
X error(error_buf);
X return retval;
X }
X (void) strcat(built_path, "/");
X }
X if ((specs.st_mode & S_IFMT) == S_IFDIR) {
X retval = add_directory_to_parent(parent, next_name, True, leaf);
X if (retval) {
X error("add_directory_to_parent");
X return retval;
X }
X }
X else {
X retval = add_file_to_parent(parent, next_name, True, leaf);
X if (retval) {
X error("add_file_to_parent");
X return retval;
X }
X }
X
X (*leaf)->specs = specs;
X
X return 0;
X}
X
X
X
Xint get_specs(path, specs, follow)
Xchar *path;
Xstruct mystat *specs;
Xint follow; /* follow symlinks or not? */
X{
X int status;
X struct stat realspecs;
X
X if (strlen(path)) if ((path[strlen(path) - 1] == '/') &&
X (strlen(path) != 1))
X path[strlen(path) - 1] = '\0';
X if (follow == FOLLOW_LINKS)
X status = stat(path, &realspecs);
X else
X status = lstat(path, &realspecs);
X
X if (status) {
X set_error(errno);
X error(path);
X return error_code;
X }
X
X specs->st_dev = realspecs.st_dev;
X specs->st_ino = realspecs.st_ino;
X specs->st_mode = realspecs.st_mode;
X specs->st_size = realspecs.st_size;
X specs->st_ctime = realspecs.st_ctime;
X#ifdef notdef
X /*
X * See comment in directories.h to understand why this is
X * disabled.
X */
X specs->st_blocks = realspecs.st_blocks;
X#endif
X
X return 0;
X}
X
X
X
Xfilerec *next_leaf(leaf)
Xfilerec *leaf;
X{
X filerec *new;
X
X if ((leaf->specs.st_mode & S_IFMT) == S_IFDIR) {
X new = first_in_directory(leaf);
X if (new)
X return(new);
X new = next_directory(leaf);
X return(new);
X }
X else {
X new = next_in_directory(leaf);
X return(new);
X }
X}
X
X
Xfilerec *next_specified_leaf(leaf)
Xfilerec *leaf;
X{
X while (leaf = next_leaf(leaf))
X if (leaf->specified)
X return(leaf);
X return((filerec *) NULL);
X}
X
X
Xfilerec *next_directory(leaf)
Xfilerec *leaf;
X{
X filerec *ret;
X if ((leaf->specs.st_mode & S_IFMT) != S_IFDIR)
X leaf = leaf->parent;
X if (leaf)
X ret = leaf->next;
X else
X ret = (filerec *) NULL;
X if (ret) if (ret->freed)
X ret = next_directory(ret);
X return(ret);
X}
X
X
Xfilerec *next_specified_directory(leaf)
Xfilerec *leaf;
X{
X while (leaf = next_directory(leaf))
X if (leaf->specified)
X return(leaf);
X return ((filerec *) NULL);
X}
X
X
X
Xfilerec *next_in_directory(leaf)
Xfilerec *leaf;
X{
X filerec *ret;
X
X if (leaf->next)
X ret = leaf->next;
X else if (((leaf->specs.st_mode & S_IFMT) != S_IFDIR) && leaf->parent)
X ret = leaf->parent->dirs;
X else
X ret = (filerec *) NULL;
X if (ret) if (ret->freed)
X ret = next_in_directory(ret);
X return (ret);
X}
X
X
X
X
Xfilerec *next_specified_in_directory(leaf)
Xfilerec *leaf;
X{
X while (leaf = next_in_directory(leaf))
X if (leaf->specified)
X return(leaf);
X return ((filerec *) NULL);
X}
X
X
X
Xfilerec *first_in_directory(leaf)
Xfilerec *leaf;
X{
X filerec *ret;
X
X if ((leaf->specs.st_mode & S_IFMT) != S_IFDIR)
X ret = (filerec *) NULL;
X else if (leaf->files)
X ret = leaf->files;
X else if (leaf->dirs)
X ret = leaf->dirs;
X else
X ret = (filerec *) NULL;
X if (ret) if (ret->freed)
X ret = next_in_directory(ret);
X return(ret);
X}
X
X
Xfilerec *first_specified_in_directory(leaf)
Xfilerec *leaf;
X{
X leaf = first_in_directory(leaf);
X if (! leaf)
X return((filerec *) NULL);
X
X if (leaf->specified)
X return(leaf);
X else
X leaf = next_specified_in_directory(leaf);
X return (leaf);
X}
X
X
Xvoid print_paths_from(leaf)
Xfilerec *leaf;
X{
X char buf[MAXPATHLEN];
X
X printf("%s\n", get_leaf_path(leaf, buf));
X if (leaf->dirs)
X print_paths_from(leaf->dirs);
X if (leaf->files)
X print_paths_from(leaf->files);
X if (leaf->next)
X print_paths_from(leaf->next);
X}
X
X
Xvoid print_specified_paths_from(leaf)
Xfilerec *leaf;
X{
X char buf[MAXPATHLEN];
X
X if (leaf->specified)
X printf("%s\n", get_leaf_path(leaf, buf));
X if (leaf->dirs)
X print_specified_paths_from(leaf->dirs);
X if (leaf->files)
X print_specified_paths_from(leaf->files);
X if (leaf->next)
X print_specified_paths_from(leaf->next);
X}
X
X
Xint add_file_to_parent(parent, name, specified, last)
Xfilerec *parent, **last;
Xchar *name;
XBoolean specified;
X{
X filerec *files;
X
X *last = files = (filerec *) NULL;
X files = parent->files;
X while (files) {
X if (! strcmp(files->name, name))
X break;
X *last = files;
X files = files->next;
X }
X if (files) {
X files->specified = (files->specified || specified);
X *last = files;
X return 0;
X }
X if (*last) {
X (*last)->next = (filerec *) Malloc((unsigned) sizeof(filerec));
X if (! (*last)->next) {
X set_error(errno);
X error("Malloc");
X return error_code;
X }
X *(*last)->next = default_file;
X (*last)->next->previous = *last;
X (*last)->next->parent = parent;
X (*last) = (*last)->next;
X }
X else {
X parent->files = (filerec *) Malloc(sizeof(filerec));
X if (! parent->files) {
X set_error(errno);
X error("Malloc");
X return error_code;
X }
X *parent->files = default_file;
X parent->files->parent = parent;
X parent->files->previous = (filerec *) NULL;
X *last = parent->files;
X }
X (void) strcpy((*last)->name, name);
X (*last)->specified = specified;
X return 0;
X}
X
X
X
X
X
Xint add_directory_to_parent(parent, name, specified, last)
Xfilerec *parent, **last;
Xchar *name;
XBoolean specified;
X{
X filerec *directories;
X
X *last = (filerec *) NULL;
X directories = parent->dirs;
X while (directories) {
X if (! strcmp(directories->name, name))
X break;
X (*last) = directories;
X directories = directories->next;
X }
X if (directories) {
X directories->specified = (directories->specified || specified);
X *last = directories;
X return 0;
X }
X if (*last) {
X (*last)->next = (filerec *) Malloc(sizeof(filerec));
X if (! (*last)->next) {
X set_error(errno);
X error("Malloc");
X return error_code;
X }
X *(*last)->next = default_directory;
X (*last)->next->previous = *last;
X (*last)->next->parent = parent;
X (*last) = (*last)->next;
X }
X else {
X parent->dirs = (filerec *) Malloc(sizeof(filerec));
X if (! parent->dirs) {
X set_error(errno);
X error("Malloc");
X return error_code;
X }
X *parent->dirs = default_directory;
X parent->dirs->parent = parent;
X parent->dirs->previous = (filerec *) NULL;
X (*last) = parent->dirs;
X }
X (void) strcpy((*last)->name, name);
X (*last)->specified = specified;
X return 0;
X}
X
X
X
X
X
Xvoid free_leaf(leaf)
Xfilerec *leaf;
X{
X leaf->freed = True;
X if (! (leaf->dirs || leaf->files)) {
X if (leaf->previous)
X leaf->previous->next = leaf->next;
X if (leaf->next)
X leaf->next->previous = leaf->previous;
X if (leaf->parent) {
X if ((leaf->specs.st_mode & S_IFMT) == S_IFDIR) {
X if (leaf->parent->dirs == leaf) {
X leaf->parent->dirs = leaf->next;
X if (leaf->parent->freed)
X free_leaf(leaf->parent);
X }
X }
X else {
X if (leaf->parent->files == leaf) {
X leaf->parent->files = leaf->next;
X if (leaf->parent->freed)
X free_leaf(leaf->parent);
X }
X }
X free((char *) leaf);
X }
X }
X}
X
X
X
Xint find_child(directory, name, child)
Xfilerec *directory, **child;
Xchar *name;
X{
X filerec *ptr;
X
X *child = (filerec *) NULL;
X if ((directory->specs.st_mode & S_IFMT) != S_IFDIR)
X return DIR_NOT_DIRECTORY;
X ptr = directory->dirs;
X while (ptr)
X if (strcmp(ptr->name, name))
X ptr = ptr->next;
X else
X break;
X if (ptr) {
X *child = ptr;
X return DIR_MATCH;
X }
X ptr = directory->files;
X while (ptr)
X if (strcmp(ptr->name, name))
X ptr = ptr->next;
X else
X break;
X if (ptr) {
X *child = ptr;
X return DIR_MATCH;
X }
X set_status(DIR_NO_MATCH);
X return DIR_NO_MATCH;
X}
X
X
X
X
X
Xint change_path(old_path, new_path)
Xchar *old_path, *new_path;
X{
X char next_old[MAXNAMLEN], next_new[MAXNAMLEN];
X char rest_old[MAXPATHLEN], rest_new[MAXPATHLEN];
X int retval;
X filerec *current;
X
X if (*old_path == '/') {
X current = &root_tree;
X old_path++;
X new_path++;
X }
X else if (! strncmp(old_path, "./", 2)) {
X current = &cwd_tree;
X old_path += 2;
X new_path += 2;
X }
X else
X current = &cwd_tree;
X
X (void) strcpy(next_old, firstpart(old_path, rest_old));
X (void) strcpy(next_new, firstpart(new_path, rest_new));
X while (*next_old && *next_new) {
X retval = find_child(current, next_old, ¤t);
X if (retval == DIR_MATCH) {
X if (current) {
X (void) strcpy(current->name, next_new);
X current->specified = False;
X }
X else {
X set_error(INTERNAL_ERROR);
X error("change_path");
X return error_code;
X }
X }
X else {
X error("change_path");
X return retval;
X }
X
X (void) strcpy(next_old, firstpart(rest_old, rest_old));
X (void) strcpy(next_new, firstpart(rest_new, rest_new));
X }
X return 0;
X}
X
X
Xint get_leaf_path(leaf, leaf_buf)
Xfilerec *leaf;
Xchar leaf_buf[]; /* RETURN */
X{
X char *name_ptr;
X
X name_ptr = Malloc(1);
X if (! name_ptr) {
X set_error(errno);
X error("Malloc");
X *leaf_buf = '\0';
X return error_code;
X }
X *name_ptr = '\0';
X do {
X name_ptr = realloc((char *) name_ptr, (unsigned)
X (strlen(leaf->name) + strlen(name_ptr) + 2));
X if (! name_ptr) {
X set_error(errno);
X *leaf_buf = '\0';
X error("realloc");
X return error_code;
X }
X (void) strcpy(leaf_buf, name_ptr);
X *name_ptr = '\0';
X if (leaf->parent) if (leaf->parent->parent)
X (void) strcat(name_ptr, "/");
X (void) strcat(name_ptr, leaf->name);
X (void) strcat(name_ptr, leaf_buf);
X leaf = leaf->parent;
X } while (leaf);
X (void) strcpy(leaf_buf, name_ptr);
X return 0;
X}
X
X
X
X
X
Xint accumulate_names(leaf, in_strings, num)
Xfilerec *leaf;
Xchar ***in_strings;
Xint *num;
X{
X char newname[MAXPATHLEN];
X char **strings;
X int retval;
X
X strings = *in_strings;
X if (leaf->specified) {
X *num += 1;
X strings = (char **) realloc((char *) strings, (unsigned)
X (sizeof(char *) * (*num)));
X if (! strings) {
X set_error(errno);
X error("realloc");
X return error_code;
X }
X if (retval = get_leaf_path(leaf, newname)) {
X error("get_leaf_path");
X return retval;
X }
X (void) convert_to_user_name(newname, newname);
X strings[*num - 1] = Malloc((unsigned) (strlen(newname) + 1));
X if (! strings[*num - 1]) {
X set_error(errno);
X error("Malloc");
X return error_code;
X }
X (void) strcpy(strings[*num - 1], newname);
X }
X if (leaf->files) if (retval = accumulate_names(leaf->files, &strings,
X num)) {
X error("accumulate_names");
X return retval;
X }
X if (leaf->dirs) if (retval = accumulate_names(leaf->dirs, &strings,
X num)) {
X error("accumulate_names");
X return retval;
X }
X if (leaf->next) if (retval = accumulate_names(leaf->next, &strings,
X num)) {
X error("accumulate_names");
X return retval;
X }
X
X *in_strings = strings;
X return 0;
X}
END_OF_FILE
if test 15169 -ne `wc -c <'directories.c'`; then
echo shar: \"'directories.c'\" unpacked with wrong size!
fi
# end of 'directories.c'
fi
echo shar: End of archive 3 \(of 4\).
cp /dev/null ark3isdone
MISSING=""
for I in 1 2 3 4 ; do
if test ! -f ark${I}isdone ; then
MISSING="${MISSING} ${I}"
fi
done
if test "${MISSING}" = "" ; then
echo You have unpacked all 4 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
exit 0 # Just in case...
--
Kent Landfield INTERNET: kent at sparky.IMD.Sterling.COM
Sterling Software, IMD UUCP: uunet!sparky!kent
Phone: (402) 291-8300 FAX: (402) 291-4362
Please send comp.sources.misc-related mail to kent at uunet.uu.net.
More information about the Comp.sources.misc
mailing list