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