Annotation of 43BSD/bin/mv.c, revision 1.1.1.1

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

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.