/* * rmdir -- unlink directory * * Usage: rmdir name ... * * Note: name must not end in '.' or '..', otherwise URK! */ #define R 04 #define W 02 #define X 01 #define WX (W|X) #define IFMT 060000 #define IFDIR 040000 char *arg; main(ac, av) char *av[]; { if(ac-- < 2) { prints(2, "Usage: rmdir name ...\n"); exit(1); } while( ac-- ) { register char *p,*q; p = *++av; arg = *av; q = p+1; /* * Problems can arise when the pathname contains * segments of '.' or '..'. To avoid this we will * chdir to the penultimate path and then do a simple * remove there. It's tough if the directory you remove * happens to be your current one, but the system (now) * protects against you making files there. You must not * remove pathnames that terminate in '.' or '..'. * Access permissions must be checked down the path * as this program is setuid to ROOT. */ while( *q ) { register char *r; r = q; if( *q++ == '/') { while( *q == '/' ) q++; if (*q) p = q; else *r = 0; } } /* * Now: Either p points to the front of the name * (it may have a slash), * Or it points to the last pathname segment. */ if( p == *av) { /* * No chdir necessary * * Must have write permission in * dir containing name */ if (*p == '/') q = "/"; else q = ""; if(access(q, WX) < 0) { perror(p); continue; } rem( p ); } else { register i; /* * A fork is required, for chdir. */ p[-1] = 0; if( (access(*av, WX) < 0) || (i = fork()) < 0) { p[-1] = '/'; perror(*av); continue; } if( i == 0) { chdir(*av); p[-1] = '/'; rem(p); return 0; /* * child dies */ } else { int status; waitx(&status); } } } return 0; } rem(name) register char *name; { register f; register char *q; struct { int i_dev; int i_number; int i_node[16]; } stbuf; if( dot(name) ) { prints(2, arg); prints(2, ": Ill formed\n"); return; } if(access(name, W) < 0 || (f = open(name,0)) < 0) { perror(arg); return; } fstat(f, &stbuf); if(stbuf.i_number == 1) { prints(2, arg); prints(2, ": Root directory\n"); goto retu; } if( (stbuf.i_node[0]&IFMT) != IFDIR ) { prints(2, arg); prints(2, ": Not a directory\n"); goto retu; } stbuf.i_node[8] = 0; while( read(f, stbuf.i_node, 16) == 16) { if(stbuf.i_node[0] == 0) continue; if( dot( &stbuf.i_node[1]) ) continue; prints(2, arg); prints(2, ": Directory not empty\n"); retu: close(f); return; } close(f); /* * can finally unlink */ q = stbuf.i_node; while( *q = *name++) q++; *q++ = '/'; *q++ = '.'; *q++ = '.'; *q = 0; unlink(stbuf.i_node); *--q = 0; unlink(stbuf.i_node); --q; *--q = 0; unlink(stbuf.i_node); } dot(name) register char *name; { if( *name++ == '.' && ( *name == 0 || ( *name++ == '.' && *name == 0 )) ) return 1; else return 0; }