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: }