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