|
|
1.1 ! root 1: static char *sccsid = "@(#)mv.c 4.1 (Berkeley) 10/6/80"; ! 2: /* ! 3: * mv file1 file2 ! 4: */ ! 5: ! 6: #include <stdio.h> ! 7: #include <sys/types.h> ! 8: #include <sys/stat.h> ! 9: #include <sys/dir.h> ! 10: #include <signal.h> ! 11: ! 12: #define DOT "." ! 13: #define DOTDOT ".." ! 14: #define DELIM '/' ! 15: #define SDELIM "/" ! 16: #define MAXN 100 ! 17: #define MODEBITS 07777 ! 18: #define ROOTINO 2 ! 19: ! 20: char *pname(); ! 21: char *sprintf(); ! 22: char *dname(); ! 23: struct stat s1, s2; ! 24: int iflag = 0; /* interactive flag. If this flag is set, ! 25: * the user is queried before files are ! 26: * destroyed by cp. ! 27: */ ! 28: int fflag = 0; /* force flag. supercedes all restrictions */ ! 29: ! 30: main(argc, argv) ! 31: register char *argv[]; ! 32: { ! 33: register i, r; ! 34: ! 35: /* get the flag(s) */ ! 36: ! 37: if (argc < 2) ! 38: goto usage; ! 39: if (*argv[1] == '-') { ! 40: argc--; ! 41: while (*++argv[1] != '\0') ! 42: switch (*argv[1]) { ! 43: ! 44: /* interactive mode */ ! 45: case 'i': ! 46: iflag++; ! 47: break; ! 48: ! 49: /* force moves */ ! 50: case 'f': ! 51: fflag++; ! 52: break; ! 53: ! 54: /* don't live with bad options */ ! 55: default: ! 56: goto usage; ! 57: } ! 58: argv++; ! 59: } ! 60: if (argc < 3) ! 61: goto usage; ! 62: if (stat(argv[1], &s1) < 0) { ! 63: fprintf(stderr, "mv: cannot access %s\n", argv[1]); ! 64: return(1); ! 65: } ! 66: if ((s1.st_mode & S_IFMT) == S_IFDIR) { ! 67: if (argc != 3) ! 68: goto usage; ! 69: return mvdir(argv[1], argv[2]); ! 70: } ! 71: setuid(getuid()); ! 72: if (argc > 3) ! 73: if (stat(argv[argc-1], &s2) < 0 || (s2.st_mode & S_IFMT) != S_IFDIR) ! 74: goto usage; ! 75: r = 0; ! 76: for (i=1; i<argc-1; i++) ! 77: r |= move(argv[i], argv[argc-1]); ! 78: return(r); ! 79: usage: ! 80: fprintf(stderr, "usage: mv f1 f2; or mv d1 d2; or mv f1 ... fn d1\n"); ! 81: return(1); ! 82: } ! 83: ! 84: move(source, target) ! 85: char *source, *target; ! 86: { ! 87: register c, i; ! 88: int status; ! 89: char buf[MAXN]; ! 90: ! 91: if (stat(source, &s1) < 0) { ! 92: fprintf(stderr, "mv: cannot access %s\n", source); ! 93: return(1); ! 94: } ! 95: if ((s1.st_mode & S_IFMT) == S_IFDIR) { ! 96: fprintf(stderr, "mv: directory rename only\n"); ! 97: return(1); ! 98: } ! 99: if (stat(target, &s2) >= 0) { ! 100: if ((s2.st_mode & S_IFMT) == S_IFDIR) { ! 101: sprintf(buf, "%s/%s", target, dname(source)); ! 102: target = buf; ! 103: } ! 104: if (stat(target, &s2) >= 0) { ! 105: if ((s2.st_mode & S_IFMT) == S_IFDIR) { ! 106: fprintf(stderr, "mv: %s is a directory\n", target); ! 107: return(1); ! 108: } else if (iflag && !fflag) { ! 109: fprintf(stderr, "remove %s? ", target); ! 110: i = c = getchar(); ! 111: while (c != '\n' && c != EOF) ! 112: c = getchar(); ! 113: if (i != 'y') ! 114: return(1); ! 115: } ! 116: if (s1.st_dev==s2.st_dev && s1.st_ino==s2.st_ino) { ! 117: fprintf(stderr, "mv: %s and %s are identical\n", ! 118: source, target); ! 119: return(1); ! 120: } ! 121: if (access(target, 2) < 0 && !fflag && isatty(fileno(stdin))) { ! 122: fprintf(stderr, "override protection %o for %s? ", ! 123: s2.st_mode & MODEBITS, target); ! 124: i = c = getchar(); ! 125: while (c != '\n' && c != EOF) ! 126: c = getchar(); ! 127: if (i != 'y') ! 128: return(1); ! 129: } ! 130: if (unlink(target) < 0) { ! 131: fprintf(stderr, "mv: cannot unlink %s\n", target); ! 132: return(1); ! 133: } ! 134: } ! 135: } ! 136: if (link(source, target) < 0) { ! 137: i = fork(); ! 138: if (i == -1) { ! 139: fprintf(stderr, "mv: try again\n"); ! 140: return(1); ! 141: } ! 142: if (i == 0) { ! 143: execl("/bin/cp", "cp", source, target, 0); ! 144: fprintf(stderr, "mv: cannot exec cp\n"); ! 145: exit(1); ! 146: } ! 147: while ((c = wait(&status)) != i && c != -1) ! 148: ; ! 149: if (status != 0) ! 150: return(1); ! 151: utime(target, &s1.st_atime); ! 152: } ! 153: if (unlink(source) < 0) { ! 154: fprintf(stderr, "mv: cannot unlink %s\n", source); ! 155: return(1); ! 156: } ! 157: return(0); ! 158: } ! 159: ! 160: mvdir(source, target) ! 161: char *source, *target; ! 162: { ! 163: register char *p; ! 164: register i; ! 165: char buf[MAXN]; ! 166: char c,cc; ! 167: ! 168: if (stat(target, &s2) >= 0) { ! 169: if ((s2.st_mode&S_IFMT) != S_IFDIR) { ! 170: fprintf(stderr, "mv: %s exists\n", target); ! 171: return(1); ! 172: } else if (iflag && !fflag) { ! 173: fprintf(stderr, "remove %s? ", target); ! 174: cc = c = getchar(); ! 175: while (c != '\n' && c != EOF) ! 176: c = getchar(); ! 177: if (cc != 'y') ! 178: return(1); ! 179: } ! 180: if (strlen(target) > MAXN-DIRSIZ-2) { ! 181: fprintf(stderr, "mv :target name too long\n"); ! 182: return(1); ! 183: } ! 184: strcpy(buf, target); ! 185: target = buf; ! 186: strcat(buf, SDELIM); ! 187: strcat(buf, dname(source)); ! 188: if (stat(target, &s2) >= 0) { ! 189: fprintf(stderr, "mv: %s exists\n", buf); ! 190: return(1); ! 191: } ! 192: } ! 193: if (strcmp(source, target) == 0) { ! 194: fprintf(stderr, "mv: ?? source == target, source exists and target doesnt\n"); ! 195: return(1); ! 196: } ! 197: p = dname(source); ! 198: if (!strcmp(p, DOT) || !strcmp(p, DOTDOT) || !strcmp(p, "") || p[strlen(p)-1]=='/') { ! 199: fprintf(stderr, "mv: cannot rename %s\n", p); ! 200: return(1); ! 201: } ! 202: if (stat(pname(source), &s1) < 0 || stat(pname(target), &s2) < 0) { ! 203: fprintf(stderr, "mv: cannot locate parent\n"); ! 204: return(1); ! 205: } ! 206: if (access(pname(target), 2) < 0) { ! 207: fprintf(stderr, "mv: no write access to %s\n", pname(target)); ! 208: return(1); ! 209: } ! 210: if (access(pname(source), 2) < 0) { ! 211: fprintf(stderr, "mv: no write access to %s\n", pname(source)); ! 212: return(1); ! 213: } ! 214: if (access(source, 2) < 0) { ! 215: fprintf(stderr, "mv: no write access to %s\n", source); ! 216: return(1); ! 217: } ! 218: if (s1.st_dev != s2.st_dev) { ! 219: fprintf(stderr, "mv: cannot move directories across devices\n"); ! 220: return(1); ! 221: } ! 222: if (s1.st_ino != s2.st_ino) { ! 223: char dst[MAXN+5]; ! 224: ! 225: if (chkdot(source) || chkdot(target)) { ! 226: fprintf(stderr, "mv: Sorry, path names including %s aren't allowed\n", DOTDOT); ! 227: return(1); ! 228: } ! 229: stat(source, &s1); ! 230: if (check(pname(target), s1.st_ino)) ! 231: return(1); ! 232: for (i = 1; i <= NSIG; i++) ! 233: signal(i, SIG_IGN); ! 234: if (link(source, target) < 0) { ! 235: fprintf(stderr, "mv: cannot link %s to %s\n", target, source); ! 236: return(1); ! 237: } ! 238: if (unlink(source) < 0) { ! 239: fprintf(stderr, "mv: %s: cannot unlink\n", source); ! 240: unlink(target); ! 241: return(1); ! 242: } ! 243: strcat(dst, target); ! 244: strcat(dst, "/"); ! 245: strcat(dst, DOTDOT); ! 246: if (unlink(dst) < 0) { ! 247: fprintf(stderr, "mv: %s: cannot unlink\n", dst); ! 248: if (link(target, source) >= 0) ! 249: unlink(target); ! 250: return(1); ! 251: } ! 252: if (link(pname(target), dst) < 0) { ! 253: fprintf(stderr, "mv: cannot link %s to %s\n", ! 254: dst, pname(target)); ! 255: if (link(pname(source), dst) >= 0) ! 256: if (link(target, source) >= 0) ! 257: unlink(target); ! 258: return(1); ! 259: } ! 260: return(0); ! 261: } ! 262: if (link(source, target) < 0) { ! 263: fprintf(stderr, "mv: cannot link %s and %s\n", ! 264: source, target); ! 265: return(1); ! 266: } ! 267: if (unlink(source) < 0) { ! 268: fprintf(stderr, "mv: ?? cannot unlink %s\n", source); ! 269: return(1); ! 270: } ! 271: return(0); ! 272: } ! 273: ! 274: char * ! 275: pname(name) ! 276: register char *name; ! 277: { ! 278: register c; ! 279: register char *p, *q; ! 280: static char buf[MAXN]; ! 281: ! 282: p = q = buf; ! 283: while (c = *p++ = *name++) ! 284: if (c == DELIM) ! 285: q = p-1; ! 286: if (q == buf && *q == DELIM) ! 287: q++; ! 288: *q = 0; ! 289: return buf[0]? buf : DOT; ! 290: } ! 291: ! 292: char * ! 293: dname(name) ! 294: register char *name; ! 295: { ! 296: register char *p; ! 297: ! 298: p = name; ! 299: while (*p) ! 300: if (*p++ == DELIM && *p) ! 301: name = p; ! 302: return name; ! 303: } ! 304: ! 305: check(spth, dinode) ! 306: char *spth; ! 307: ino_t dinode; ! 308: { ! 309: char nspth[MAXN]; ! 310: struct stat sbuf; ! 311: ! 312: sbuf.st_ino = 0; ! 313: ! 314: strcpy(nspth, spth); ! 315: while (sbuf.st_ino != ROOTINO) { ! 316: if (stat(nspth, &sbuf) < 0) { ! 317: fprintf(stderr, "mv: cannot access %s\n", nspth); ! 318: return(1); ! 319: } ! 320: if (sbuf.st_ino == dinode) { ! 321: fprintf(stderr, "mv: cannot move a directory into itself\n"); ! 322: return(1); ! 323: } ! 324: if (strlen(nspth) > MAXN-2-sizeof(DOTDOT)) { ! 325: fprintf(stderr, "mv: name too long\n"); ! 326: return(1); ! 327: } ! 328: strcat(nspth, SDELIM); ! 329: strcat(nspth, DOTDOT); ! 330: } ! 331: return(0); ! 332: } ! 333: ! 334: chkdot(s) ! 335: register char *s; ! 336: { ! 337: do { ! 338: if (strcmp(dname(s), DOTDOT) == 0) ! 339: return(1); ! 340: s = pname(s); ! 341: } while (strcmp(s, DOT) != 0 && strcmp(s, SDELIM) != 0); ! 342: return(0); ! 343: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.