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