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