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