#ifdef ournix #include "ournix.h" #endif char sccsID[] = "@(#) rm.c V1.2 Copyright Julian H. Stacey 1987.\n" ; /* rm - Unix like rm, with -r option, written for MSDOS by Julian Stacey, directory searching component adopted from ls.c (by pjac). BUGS - rm doesnt delete directories that were empty before rm was called. - mode of files & directories is not considered FEATURES - cd \ ; rm -r \ doesnt delete top directories however these top directories are mounted with join.exe, so they are special. (carefull if you try it, it does delete everything else ! FUTURES - -i & -f options */ #include #include #include #ifdef MSDOS #include #endif #ifdef MSDOS #include "ndir.h" #else #include #endif #define ENOUGH 128 #define MAXDIR 1024 #define strequ(a,b) (strcmp(a,b) == 0) struct m_list { char m_name[12+2] ; long m_size ; short m_mode ; long m_time ; } ; struct m_list *m_tab[MAXDIR] ; struct m_list **m_start ; struct m_list **m_end ; char *malloc() ; char r_flag ; char f_flag ; char i_flag ; char no_mem_flag ; char **ARGV ; char no_mem[] = "Out of memory.\n" ; /* ??????????????????? 0 = failed to stat */ struct m_list * our_stat(nam, nam_ptr, stat_ptr) char *nam ; char *nam_ptr ; struct stat *stat_ptr ; /* maybe where structure should be returned */ { struct stat stat_buf ; struct m_list *mem_ptr ; if (stat_ptr == (struct stat *)0) { stat_ptr = &stat_buf ; if (stat(nam, stat_ptr) < 0) { #ifdef DEBUG fprintf(stderr, "Can't stat '%s'.\n", nam) ; #endif return(0) ; } } mem_ptr = (struct m_list *)malloc(sizeof(struct m_list)) ; if (mem_ptr == 0) { if (!no_mem_flag) fprintf(stderr, no_mem ) ; no_mem_flag = 1 ; return(0) ; } if (nam_ptr != (char *)0) (void) strcpy(mem_ptr->m_name, nam_ptr) ; else mem_ptr->m_name[0] = '\0' ; mem_ptr->m_size = stat_ptr->st_size ; mem_ptr->m_mode = stat_ptr->st_mode ; mem_ptr->m_time = stat_ptr->st_mtime ; return(mem_ptr) ; } main(argc, argv) char **argv ; { char *opt ; int status = 0 ; ARGV = argv ; #ifdef VSL /* { */ #include "../../include/vsl.h" #endif /* } */ for(argv++, argc-- ; argc ; argc--, argv++) { if (*(opt = *argv) != '-') break ; while(*++opt) switch(*opt) { case 'P': /* print release number */ printf("%s",sccsID) ; break ; case 'r': /* recursive delete */ r_flag = 1 ; break ; case 'f': /* delete with force ie ignore protect mode */ f_flag = 1 ; break ; case 'i': /* interactive prompt */ i_flag = 1 ; break ; default: fprintf(stderr, "%s: Error, -%c not implemented, so ignored.\n", *ARGV,*opt) ; fprintf(stderr, "%s",sccsID) ; break ; } } if (argc <= 0) { fprintf(stderr, "%s: Error need at least one argument.\n",*ARGV) ; exit(1) ; } for ( ; argc ; argc--, argv++) status |= doit(*argv) ; exit(status) ; } doit(d) char *d ; /* name of element in current directory to analyse */ { struct m_list *mp ; struct stat stat_buf ; int status ; if ( strequ(d,"..") ) { fprintf(stderr, "%s: User Error: wont delete parent directory %s.\n", *ARGV,(r_flag)? "(with -r it would have been very unpleasant.)\n" : "" ) ; return(1) ; } if (stat(d, &stat_buf) < 0) /* */ { status = root_chk(d) ; if (status >= 0) return(status) ; mp = our_stat(d, 0, (struct stat *)0) ; } else { /* */ mp = our_stat(d, 0, &stat_buf) ; } if (mp == NULL) return(1) ; if ((mp->m_mode & S_IFMT) != S_IFDIR ) { free( (char *)mp) ; return(fzap("","",d)) ; } free( (char *)mp) ; if (!r_flag) { fprintf(stderr,"%s: Error %s is a directory.\n",*ARGV,d) ; return(1) ; } m_start = m_tab ; /* put start at start of table */ if (status = recurse(d)) return(status) ; return(0) ; } root_chk(d) /* check to see if directory is root */ /* return ............... */ char *d ; { DIR *dir_ptr ; static char NULLS[] = "" ; char **x_ptr ; static char *matches[] = { ".", "/", "\\", (char *)0, } ; for(x_ptr = matches ; *x_ptr ; x_ptr++) if (strcmp(d, *x_ptr) == 0) { dir_ptr = opendir(NULLS) ; /* "" for ROOT ?? */ if (dir_ptr == NULL) return(-1) ; closedir(dir_ptr) ; m_start = m_tab ; /* get start right */ return(recurse(NULLS)) ; } return(-1) ; } /* Recursively evaluates directories, * returns 1 on error, 0 on no entries or recursion flag not on, * returns 1 if a lower level returns 1, ?? on normal exit. */ recurse(d) char *d ; { int nentries ; struct m_list *mp, **xmp ; struct m_list **Mp ; char *tbuf ; nentries = dir_build(d) ; if (nentries < 0) return(1) ; else if (nentries == 0) return(0) ; for(Mp = m_start ; Mp < m_end ;) { mp = *Mp++ ; next(mp, mp->m_name, d) ; if (!r_flag) free( (char *)mp) ; } if (!r_flag) return(0) ; for(Mp = m_start ; Mp < m_end ;) { mp = *Mp++ ; if ((mp->m_mode & S_IFMT) == S_IFDIR && !skip_parent(mp->m_name)) { tbuf = malloc(strlen(d) + strlen(mp->m_name) + 2) ; if (tbuf != 0) { (void) sprintf(tbuf, "%s\\%s", d, mp->m_name) ; xmp = m_start ; m_start = m_end ; if (recurse(tbuf)) { m_end = m_start ; m_start = xmp ; free(tbuf) ; return(1) ; } m_end = m_start ; m_start = xmp ; free(tbuf) ; } } free( (char *)mp) ; } dir_rm(d) ; return(0) ; } dir_build(d) char *d ; { DIR *dir_ptr ; struct direct *dp ; struct m_list *mp ; static char tbuf[ENOUGH] ; int n = 0 ; m_end = m_start ; dir_ptr = opendir(d) ; if (dir_ptr == 0) { fprintf(stderr, "Cannot open '%s'.\n", d) ; return(-1) ; } (void) strcpy(tbuf, d) ; d = &tbuf[strlen(d)] ; *d++ = '\\' ; while((dp = readdir(dir_ptr)) != NULL) { if (skip_parent(dp->d_name)) continue ; (void) strcpy(d, dp->d_name) ; mp = our_stat(tbuf, dp->d_name, (struct stat *)0) ; if (mp == 0) { if (no_mem_flag) break ; continue ; } *m_end++ = mp ; if (m_end > &m_tab[MAXDIR-1]) { fprintf(stderr, no_mem ) ; no_mem_flag = 1 ; break ; } } closedir(dir_ptr) ; n = m_end - m_start ; sortit(m_start, n) ; return(n) ; } /* stops us recursing up .. & killing parent directories */ skip_parent(name) char *name ; { if (*name != '.') return(0) ; if (name[1] == '\0' || (name[1] == '.' && name[2] == '\0')) return(1) ; return(0) ; } asc_cmp(a1, a2) struct m_list **a1, **a2 ; { return(strcmp((*a1)->m_name, (*a2)->m_name)) ; } /* sorting prior to deletion is done so if rm -rf is run by accident, * you can tell what is missing more easily, as it will have * removed alphabetically, not by directory entry order * note this is something standard unix doesnt do, but would be nice if it did. */ sortit(m_tab, n) struct m_list **m_tab ; { int (*cmpfunc)() ; if (!n) return ; cmpfunc = asc_cmp ; qsort((char *)m_tab, n, sizeof(struct m_list *), cmpfunc) ; } next(mp, nam, d) struct m_list *mp ; char *nam, *d ; { if(nam == 0) nam = mp->m_name ; /* if(mp->m_mode & S_IWRITE) if(mp->m_mode & S_IEXEC) */ if((mp->m_mode & S_IFMT) != S_IFDIR) fzap(d,"/",nam) ; } /* Removes Directory * returns 0 on success, 1 on failure */ dir_rm(d) char *d ; { if (strequ(d,".") || strequ(d,"./.") || strequ(d,".\\.") || strequ(d,"\\") || strequ(d,"/") ) return(0) ; /* msdos wont allow rmdir . or rmdir \ */ if (rmdir(d)) return(1) ; else return(0) ; } /* Deletes File * returns 0 on success, 1 on failure */ fzap(d,slash,nam) char *d,*slash,*nam ; { char gone[ENOUGH] ; (void) sprintf(gone,"%s%s%s",d,slash,nam) ; if (unlink(gone) < 0) { fprintf(stderr,"%s: Failed to unlink %s.\n", *ARGV, gone) ; return(1) ; } return(0) ; }