|
|
1.1 ! root 1: /* ! 2: * cmd/mv.c ! 3: * Move (rename) files. ! 4: * Usage: mv file1 file2 ! 5: * mv file ... directory ! 6: * Define SLOW for block at a time copying (not recommended). ! 7: */ ! 8: ! 9: #include <stdio.h> ! 10: #include <stdlib.h> ! 11: #include <sys/stat.h> ! 12: #include <errno.h> ! 13: #include <access.h> ! 14: #include <signal.h> ! 15: #include <sys/dir.h> ! 16: #include <string.h> ! 17: ! 18: #define NOTREACHED return ! 19: ! 20: /* Global. */ ! 21: #ifndef SLOW ! 22: char buf[50*BUFSIZ]; ! 23: #else ! 24: char buf[BUFSIZ]; ! 25: #endif ! 26: ! 27: char *usage = "\ ! 28: Usage: mv [-f] file1 file2\n\ ! 29: mv [-f] file ... directory\n\ ! 30: "; ! 31: char *nowrite = "unwritable: %s"; ! 32: char *nolink = "link %s %s failed"; ! 33: char *nounlink = "unlink %s failed"; ! 34: char *cmd = "mv: "; /* for error routines */ ! 35: int myuid; ! 36: int newid; ! 37: char *child; ! 38: struct stat sb1, sb2, sb3; ! 39: int estat; ! 40: int fflag; ! 41: int interrupted; ! 42: ! 43: /* External. */ ! 44: long lseek(); ! 45: ! 46: /* Forward. */ ! 47: int mv(); ! 48: void cp(); ! 49: int iszero(); ! 50: int equals(); ! 51: char *concat(); ! 52: char *getparent(); ! 53: char *getchild(); ! 54: void warn(); ! 55: void nomemory(); ! 56: void onintr(); ! 57: void catch(); ! 58: void fatal(); ! 59: ! 60: main(argc, argv) int argc; char *argv[]; ! 61: { ! 62: register int i; ! 63: ! 64: if (argc>1 && *argv[1]=='-') ! 65: if (argv[1][1] == 'f' && argv[1][2] == '\0') { ! 66: fflag = 1; ! 67: argc--; ! 68: argv++; ! 69: } else { ! 70: fputs(usage, stderr); ! 71: exit(EINVAL); ! 72: NOTREACHED; ! 73: } ! 74: ! 75: catch(SIGINT); ! 76: catch(SIGHUP); ! 77: signal(SIGQUIT, SIG_IGN); ! 78: ! 79: myuid = getuid(); ! 80: ! 81: if (--argc >= 2 ! 82: && stat(argv[argc], &sb2) >= 0 ! 83: && (sb2.st_mode&S_IFMT) == S_IFDIR) ! 84: for (i = 1; i < argc && !interrupted; i += 1) { ! 85: child = getchild(argv[i]); ! 86: mv(argv[i], concat(0, argv[argc], child)); ! 87: } ! 88: else if (argc == 2) { ! 89: child = getchild(argv[1]); ! 90: mv(argv[1], argv[2]); ! 91: } else { ! 92: fputs(usage, stderr); ! 93: exit(EINVAL); ! 94: NOTREACHED; ! 95: } ! 96: exit(interrupted ? EINTR : estat); ! 97: } ! 98: ! 99: /* ! 100: * move f1 to f2 if at all possible. ! 101: */ ! 102: int ! 103: mv(f1, f2) char *f1, *f2; ! 104: { ! 105: int isdir, isxdev, nocopy; ! 106: char *p2, *lp2; ! 107: ! 108: /* Check existence, format, delete permission on source */ ! 109: if (stat(f1, &sb1) < 0) ! 110: return (warn(ENOENT, f1)); ! 111: nocopy = (sb1.st_mode&S_IFMT) != S_IFREG; ! 112: isdir = (sb1.st_mode&S_IFMT) == S_IFDIR; ! 113: newid = (sb1.st_uid != myuid); ! 114: if (access(getparent(f1), ADEL) < 0) ! 115: return (warn(EACCES, f1)); ! 116: ! 117: /* Check existence, format, create permission on parent of dest */ ! 118: if (stat(p2 = getparent(f2), &sb2) < 0) ! 119: return (warn(ENOENT, p2)); ! 120: if ((sb2.st_mode&S_IFMT) != S_IFDIR) ! 121: return (warn(ENOTDIR, p2)); ! 122: if (access(p2, ADEL) < 0) ! 123: return (warn(EACCES, p2)); ! 124: ! 125: /* Check for cross device mv's */ ! 126: isxdev = sb1.st_dev != sb2.st_dev; ! 127: if (isxdev && nocopy) ! 128: return (warn(EXDEV, "%s to %s", f1, f2)); ! 129: ! 130: /* Check for legal directory moves */ ! 131: if (isdir) { ! 132: /* Can't mv . or .. */ ! 133: if (equals(".", child) || equals("..", child)) ! 134: return (warn(-1, "rename %s forbidden", f1)); ! 135: /* Can't mv directory to child of itself */ ! 136: for (lp2 = p2; ; ) { ! 137: /* If dev and ino of source file appear in the path ! 138: * from dest parent to root, then the dest ! 139: * will be a child of the source. ! 140: */ ! 141: if (sb1.st_dev==sb2.st_dev && sb1.st_ino==sb2.st_ino) ! 142: return (warn(-1, "%s parent of %s", f1, f2)); ! 143: sb3 = sb2; ! 144: lp2 = concat(1, lp2, ".."); ! 145: if (stat(lp2, &sb2) < 0) ! 146: return (warn(errno, "%s", lp2)); ! 147: if (sb2.st_dev==sb3.st_dev && sb2.st_ino==sb3.st_ino) ! 148: break; ! 149: } ! 150: } ! 151: ! 152: /* Check for existence, format, and writability of dest */ ! 153: if (stat(f2, &sb2) >= 0) { ! 154: if ((sb2.st_mode&S_IFMT) == S_IFDIR) ! 155: return (warn(EISDIR, f2)); ! 156: if (!fflag && access(f2, AWRITE) < 0) ! 157: return (warn(-1, nowrite, f2)); ! 158: ! 159: /* Check for identity of source and dest */ ! 160: if (sb1.st_dev == sb2.st_dev && sb1.st_ino == sb2.st_ino) ! 161: return (warn(-1, "%s and %s are identical", f1, f2)); ! 162: ! 163: if (unlink(f2)) { ! 164: fatal(errno, nounlink, f2); ! 165: NOTREACHED; ! 166: } ! 167: } ! 168: ! 169: /* Do the mv, either cp or ln/rm */ ! 170: if (isxdev) ! 171: cp(f1, f2, sb1.st_mode, sb1.st_uid, sb1.st_gid); ! 172: else { ! 173: if (link(f1, f2)) ! 174: return (warn(errno, nolink, f1, f2)); ! 175: if (isdir) { ! 176: if (unlink(lp2 = concat(1, f2, ".."))) { ! 177: fatal(errno, nounlink, lp2); ! 178: NOTREACHED; ! 179: } ! 180: if (link(p2, lp2)) { ! 181: fatal(errno, nolink, p2, lp2); ! 182: NOTREACHED; ! 183: } ! 184: } ! 185: } ! 186: if (unlink(f1)) { ! 187: fatal(errno, nounlink, f1); ! 188: NOTREACHED; ! 189: } ! 190: } ! 191: ! 192: /* ! 193: * Copy f1 to f2. ! 194: * The mode and ownership must be maintained. ! 195: */ ! 196: void ! 197: cp(f1, f2, mode, uid, gid) char *f1, *f2; int mode, uid, gid; ! 198: { ! 199: register int fd1, fd2; ! 200: register int i, n; ! 201: register fsize_t size; ! 202: register char *bp; ! 203: ! 204: if ((fd1 = open(f1, 0)) < 0) { ! 205: fatal(errno, "open %s failed", f1); ! 206: NOTREACHED; ! 207: } ! 208: if ((fd2 = creat(f2, 0)) < 0) { ! 209: fatal(errno, "create %s failed", f2); ! 210: NOTREACHED; ! 211: } ! 212: if (newid) ! 213: mode &= 0777; ! 214: chmod(f2, mode&07777); ! 215: chown(f2, uid, gid); ! 216: size = sb1.st_size; ! 217: while ((n = read(fd1, buf, sizeof buf)) != 0) { ! 218: if (n < 0) { ! 219: fatal(errno, "read %s failed", f1); ! 220: NOTREACHED; ! 221: } ! 222: for (bp = buf; n > 0; n -= i, bp += i) { ! 223: i = (n > BUFSIZ) ? BUFSIZ : n; ! 224: size -= i; ! 225: if (i == BUFSIZ && iszero(bp) && size > 0 ) { ! 226: if (lseek(fd2, (long)BUFSIZ, 1) < 0L) { ! 227: fatal(errno, "seek %s failed", f2); ! 228: NOTREACHED; ! 229: } ! 230: } else if (write(fd2, bp, i) != i) { ! 231: fatal(errno, "write %s failed", f2); ! 232: NOTREACHED; ! 233: } ! 234: } ! 235: } ! 236: close(fd1); ! 237: close(fd2); ! 238: } ! 239: ! 240: /* ! 241: * Check for zeroes in a buffer of size BLKSIZ. ! 242: */ ! 243: int ! 244: iszero(bufp) char *bufp; ! 245: { ! 246: register int i; ! 247: register char *bp; ! 248: ! 249: i = BUFSIZ; ! 250: bp = bufp; ! 251: do if (*bp++) return (0); while (--i); ! 252: return (1); ! 253: } ! 254: ! 255: /* ! 256: * Check two path names for equality knowing that p2 could be '/' terminated. ! 257: */ ! 258: int ! 259: equals(p1, p2) register char *p1, *p2; ! 260: { ! 261: while (*p1++ == *p2) ! 262: if (*p2++ == '\0') ! 263: return (1); ! 264: if (*p2 == '/' && *--p1 == '\0') ! 265: return (1); ! 266: return (0); ! 267: } ! 268: ! 269: /* ! 270: * Concatenate s1 and s2 with a '/' between them. ! 271: */ ! 272: char * ! 273: concat(l, s1, s2) int l; register char *s1, *s2; ! 274: { ! 275: register char *s3; ! 276: static char *tmp[2]; ! 277: int n; ! 278: ! 279: n = strlen(s1) + strlen(s2) + 2; ! 280: if ((s3 = malloc(n)) == NULL) { ! 281: nomemory(); ! 282: NOTREACHED; ! 283: } ! 284: strcpy(s3, s1); ! 285: strcat(s3, "/"); ! 286: strcat(s3, s2); ! 287: if (tmp[l] != NULL) ! 288: free(tmp[l]); ! 289: tmp[l] = s3; ! 290: return (s3); ! 291: } ! 292: ! 293: void ! 294: warn(err, arg1) int err; char *arg1; ! 295: { ! 296: fprintf(stderr, "%s%r", cmd, &arg1); ! 297: if (err > 0 && err < sys_nerr) ! 298: fprintf(stderr, " %s", sys_errlist[err]); ! 299: fputs("\n", stderr); ! 300: estat = err; ! 301: } ! 302: ! 303: /* ! 304: * return name of parent ! 305: */ ! 306: char * ! 307: getparent(dir) char *dir; ! 308: { ! 309: register i; ! 310: register char *p; ! 311: static char *par; ! 312: ! 313: if (par) ! 314: free( par); ! 315: i = strlen( dir); ! 316: par = malloc( i+1); ! 317: if (par == NULL) { ! 318: nomemory( ); ! 319: NOTREACHED; ! 320: } ! 321: strcpy( par, dir); ! 322: ! 323: for (p=par+i; p>par; ) ! 324: if (*--p != '/') ! 325: break; ! 326: for (++p; *--p!='/'; ) ! 327: if (p == par) { ! 328: *p = '.'; ! 329: break; ! 330: } ! 331: *++p = '\0'; ! 332: return (par); ! 333: } ! 334: ! 335: /* ! 336: * return rightmost component of pathname ! 337: */ ! 338: char * ! 339: getchild(dir) register char *dir; ! 340: { ! 341: register i; ! 342: register char *p; ! 343: static char ch[DIRSIZ+1]; ! 344: ! 345: i = strlen( dir); ! 346: if (i == 0) { ! 347: fatal( -1, "NULL?"); ! 348: NOTREACHED; ! 349: } ! 350: for (p=dir+i; *--p=='/'; ) ! 351: if (p == dir) { ! 352: fatal( -1, "don't be silly"); ! 353: NOTREACHED; ! 354: } ! 355: while (p > dir) ! 356: if (*--p == '/') { ! 357: ++p; ! 358: break; ! 359: } ! 360: return (strncpy( ch, p, DIRSIZ)); ! 361: } ! 362: ! 363: void ! 364: nomemory( ) ! 365: { ! 366: fatal( ENOMEM, "out of mem"); ! 367: NOTREACHED; ! 368: } ! 369: ! 370: void ! 371: onintr( ) ! 372: { ! 373: signal( SIGINT, SIG_IGN); ! 374: signal( SIGHUP, SIG_IGN); ! 375: ++interrupted; ! 376: } ! 377: ! 378: void ! 379: catch( sig) int sig; ! 380: { ! 381: if( signal( sig, SIG_IGN) == SIG_DFL) ! 382: signal( sig, onintr); ! 383: } ! 384: ! 385: void ! 386: fatal(err, arg1) unsigned int err; char *arg1; ! 387: { ! 388: fputs(cmd, stderr); ! 389: if (err < sys_nerr) { ! 390: fputs(sys_errlist[err], stderr); ! 391: fputs(": ", stderr); ! 392: } ! 393: fprintf(stderr, "%r\n", &arg1); ! 394: exit(err); ! 395: NOTREACHED; ! 396: } ! 397: ! 398: /* end of mv.c */
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.