|
|
1.1 ! root 1: #ifndef lint ! 2: static char *sccsid = "@(#)mv.c 4.13 (Berkeley) 83/06/30"; ! 3: #endif ! 4: ! 5: /* ! 6: * mv file1 file2 ! 7: */ ! 8: #include <sys/param.h> ! 9: #include <sys/stat.h> ! 10: ! 11: #include <stdio.h> ! 12: #include <sys/dir.h> ! 13: #include <errno.h> ! 14: #include <signal.h> ! 15: ! 16: #define DELIM '/' ! 17: #define MODEBITS 07777 ! 18: ! 19: #define ISDIR(st) (((st).st_mode&S_IFMT) == S_IFDIR) ! 20: #define ISLNK(st) (((st).st_mode&S_IFMT) == S_IFLNK) ! 21: #define ISREG(st) (((st).st_mode&S_IFMT) == S_IFREG) ! 22: #define ISDEV(st) \ ! 23: (((st).st_mode&S_IFMT) == S_IFCHR || ((st).st_mode&S_IFMT) == S_IFBLK) ! 24: ! 25: char *sprintf(); ! 26: char *dname(); ! 27: struct stat s1, s2; ! 28: int iflag = 0; /* interactive mode */ ! 29: int fflag = 0; /* force overwriting */ ! 30: extern unsigned errno; ! 31: ! 32: main(argc, argv) ! 33: register char *argv[]; ! 34: { ! 35: register i, r; ! 36: register char *arg; ! 37: char *dest; ! 38: ! 39: if (argc < 2) ! 40: goto usage; ! 41: while (argc > 1 && *argv[1] == '-') { ! 42: argc--; ! 43: arg = *++argv; ! 44: ! 45: /* ! 46: * all files following a null option ! 47: * are considered file names ! 48: */ ! 49: if (*(arg+1) == '\0') ! 50: break; ! 51: while (*++arg != '\0') switch (*arg) { ! 52: ! 53: case 'i': ! 54: iflag++; ! 55: break; ! 56: ! 57: case 'f': ! 58: fflag++; ! 59: break; ! 60: ! 61: default: ! 62: goto usage; ! 63: } ! 64: } ! 65: if (argc < 3) ! 66: goto usage; ! 67: dest = argv[argc-1]; ! 68: if (stat(dest, &s2) >= 0 && ISDIR(s2)) { ! 69: r = 0; ! 70: for (i = 1; i < argc-1; i++) ! 71: r |= movewithshortname(argv[i], dest); ! 72: exit(r); ! 73: } ! 74: if (argc > 3) ! 75: goto usage; ! 76: r = move(argv[1], argv[2]); ! 77: exit(r); ! 78: /*NOTREACHED*/ ! 79: usage: ! 80: fprintf(stderr, ! 81: "usage: mv [-if] f1 f2 or mv [-if] f1 ... fn d1 (`fn' is a file or directory)\n"); ! 82: return (1); ! 83: } ! 84: ! 85: movewithshortname(src, dest) ! 86: char *src, *dest; ! 87: { ! 88: register char *shortname; ! 89: char target[MAXPATHLEN + 1]; ! 90: ! 91: shortname = dname(src); ! 92: if (strlen(dest) + strlen(shortname) > MAXPATHLEN - 1) { ! 93: error("%s/%s: pathname too long", dest, ! 94: shortname); ! 95: return (1); ! 96: } ! 97: sprintf(target, "%s/%s", dest, shortname); ! 98: return (move(src, target)); ! 99: } ! 100: ! 101: move(source, target) ! 102: char *source, *target; ! 103: { ! 104: int targetexists; ! 105: ! 106: if (lstat(source, &s1) < 0) { ! 107: error("cannot access %s", source); ! 108: return (1); ! 109: } ! 110: /* ! 111: * First, try to rename source to destination. ! 112: * The only reason we continue on failure is if ! 113: * the move is on a nondirectory and not across ! 114: * file systems. ! 115: */ ! 116: targetexists = lstat(target, &s2) >= 0; ! 117: if (targetexists) { ! 118: if (iflag && !fflag && query("remove %s? ", target) == 0) ! 119: return (1); ! 120: if (s1.st_dev == s2.st_dev && s1.st_ino == s2.st_ino) { ! 121: error("%s and %s are identical", source, target); ! 122: return (1); ! 123: } ! 124: if (access(target, 2) < 0 && !fflag && isatty(fileno(stdin))) { ! 125: if (query("override protection %o for %s? ", ! 126: s2.st_mode & MODEBITS, target) == 0) ! 127: return (1); ! 128: } ! 129: } ! 130: if (rename(source, target) >= 0) ! 131: return (0); ! 132: if (errno != EXDEV) { ! 133: Perror2(source, "rename"); ! 134: return (1); ! 135: } ! 136: if (ISDIR(s1)) { ! 137: error("can't mv directories across file systems"); ! 138: return (1); ! 139: } ! 140: if (targetexists && unlink(target) < 0) { ! 141: error("cannot unlink %s", target); ! 142: return (1); ! 143: } ! 144: /* ! 145: * File can't be renamed, try to recreate the symbolic ! 146: * link or special device, or copy the file wholesale ! 147: * between file systems. ! 148: */ ! 149: if (ISLNK(s1)) { ! 150: register m; ! 151: char symln[MAXPATHLEN]; ! 152: ! 153: if (readlink(source, symln, sizeof (symln)) < 0) { ! 154: Perror(source); ! 155: return (1); ! 156: } ! 157: m = umask(~(s1.st_mode & MODEBITS)); ! 158: if (symlink(symln, target) < 0) { ! 159: Perror(target); ! 160: return (1); ! 161: } ! 162: (void) umask(m); ! 163: goto cleanup; ! 164: } ! 165: if (ISDEV(s1)) { ! 166: time_t tv[2]; ! 167: ! 168: if (mknod(target, s1.st_mode, s1.st_rdev) < 0) { ! 169: Perror(target); ! 170: return (1); ! 171: } ! 172: /* kludge prior to utimes */ ! 173: tv[0] = s1.st_atime; ! 174: tv[1] = s1.st_mtime; ! 175: (void) utime(target, tv); ! 176: goto cleanup; ! 177: } ! 178: if (ISREG(s1)) { ! 179: int i, c, status; ! 180: time_t tv[2]; ! 181: ! 182: i = fork(); ! 183: if (i == -1) { ! 184: error("try again"); ! 185: return (1); ! 186: } ! 187: if (i == 0) { ! 188: execl("/bin/cp", "cp", source, target, 0); ! 189: error("cannot exec /bin/cp"); ! 190: exit(1); ! 191: } ! 192: while ((c = wait(&status)) != i && c != -1) ! 193: ; ! 194: if (status != 0) ! 195: return (1); ! 196: /* kludge prior to utimes */ ! 197: tv[0] = s1.st_atime; ! 198: tv[1] = s1.st_mtime; ! 199: (void) utime(target, tv); ! 200: goto cleanup; ! 201: } ! 202: error("%s: unknown file type %o", source, s1.st_mode); ! 203: return (1); ! 204: ! 205: cleanup: ! 206: if (unlink(source) < 0) { ! 207: error("cannot unlink %s", source); ! 208: return (1); ! 209: } ! 210: return (0); ! 211: } ! 212: ! 213: /*VARARGS*/ ! 214: query(prompt, a1, a2) ! 215: char *a1; ! 216: { ! 217: register char i, c; ! 218: ! 219: fprintf(stderr, prompt, a1, a2); ! 220: i = c = getchar(); ! 221: while (c != '\n' && c != EOF) ! 222: c = getchar(); ! 223: return (i == 'y'); ! 224: } ! 225: ! 226: char * ! 227: dname(name) ! 228: register char *name; ! 229: { ! 230: register char *p; ! 231: ! 232: p = name; ! 233: while (*p) ! 234: if (*p++ == DELIM && *p) ! 235: name = p; ! 236: return name; ! 237: } ! 238: ! 239: /*VARARGS*/ ! 240: error(fmt, a1, a2) ! 241: char *fmt; ! 242: { ! 243: ! 244: fprintf(stderr, "mv: "); ! 245: fprintf(stderr, fmt, a1, a2); ! 246: fprintf(stderr, "\n"); ! 247: } ! 248: ! 249: Perror(s) ! 250: char *s; ! 251: { ! 252: char buf[MAXPATHLEN + 10]; ! 253: ! 254: sprintf(buf, "mv: %s", s); ! 255: perror(buf); ! 256: } ! 257: ! 258: Perror2(s1, s2) ! 259: char *s1, *s2; ! 260: { ! 261: char buf[MAXPATHLEN + 20]; ! 262: ! 263: sprintf(buf, "mv: %s: %s", s1, s2); ! 264: perror(buf); ! 265: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.