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

1.1       root        1: #ifndef lint
                      2: static char *sccsid = "@(#)mv.c        4.13 (Berkeley) 83/06/30";
                      3: #endif
                      4: 
                      5: /*
                      6:  * mv file1 file2
                      7:  */
                      8: #include <sys/param.h>
                      9: #include <sys/stat.h>
                     10: 
                     11: #include <stdio.h>
                     12: #include <sys/dir.h>
                     13: #include <errno.h>
                     14: #include <signal.h>
                     15: 
                     16: #define        DELIM   '/'
                     17: #define MODEBITS 07777
                     18: 
                     19: #define        ISDIR(st)       (((st).st_mode&S_IFMT) == S_IFDIR)
                     20: #define        ISLNK(st)       (((st).st_mode&S_IFMT) == S_IFLNK)
                     21: #define        ISREG(st)       (((st).st_mode&S_IFMT) == S_IFREG)
                     22: #define        ISDEV(st) \
                     23:        (((st).st_mode&S_IFMT) == S_IFCHR || ((st).st_mode&S_IFMT) == S_IFBLK)
                     24: 
                     25: char   *sprintf();
                     26: char   *dname();
                     27: struct stat s1, s2;
                     28: int    iflag = 0;      /* interactive mode */
                     29: int    fflag = 0;      /* force overwriting */
                     30: extern unsigned errno;
                     31: 
                     32: main(argc, argv)
                     33:        register char *argv[];
                     34: {
                     35:        register i, r;
                     36:        register char *arg;
                     37:        char *dest;
                     38: 
                     39:        if (argc < 2)
                     40:                goto usage;
                     41:        while (argc > 1 && *argv[1] == '-') {
                     42:                argc--;
                     43:                arg = *++argv;
                     44: 
                     45:                /*
                     46:                 * all files following a null option
                     47:                 * are considered file names
                     48:                 */
                     49:                if (*(arg+1) == '\0')
                     50:                        break;
                     51:                while (*++arg != '\0') switch (*arg) {
                     52: 
                     53:                case 'i':
                     54:                        iflag++;
                     55:                        break;
                     56: 
                     57:                case 'f':
                     58:                        fflag++;
                     59:                        break;
                     60: 
                     61:                default:
                     62:                        goto usage;
                     63:                }
                     64:        }
                     65:        if (argc < 3)
                     66:                goto usage;
                     67:        dest = argv[argc-1];
                     68:        if (stat(dest, &s2) >= 0 && ISDIR(s2)) {
                     69:                r = 0;
                     70:                for (i = 1; i < argc-1; i++)
                     71:                        r |= movewithshortname(argv[i], dest);
                     72:                exit(r);
                     73:        }
                     74:        if (argc > 3)
                     75:                goto usage;
                     76:        r = move(argv[1], argv[2]);
                     77:        exit(r);
                     78:        /*NOTREACHED*/
                     79: usage:
                     80:        fprintf(stderr,
                     81: "usage: mv [-if] f1 f2 or mv [-if] f1 ... fn d1 (`fn' is a file or directory)\n");
                     82:        return (1);
                     83: }
                     84: 
                     85: movewithshortname(src, dest)
                     86:        char *src, *dest;
                     87: {
                     88:        register char *shortname;
                     89:        char target[MAXPATHLEN + 1];
                     90: 
                     91:        shortname = dname(src);
                     92:        if (strlen(dest) + strlen(shortname) > MAXPATHLEN - 1) {
                     93:                error("%s/%s: pathname too long", dest,
                     94:                        shortname);
                     95:                return (1);
                     96:        }
                     97:        sprintf(target, "%s/%s", dest, shortname);
                     98:        return (move(src, target));
                     99: }
                    100: 
                    101: move(source, target)
                    102:        char *source, *target;
                    103: {
                    104:        int targetexists;
                    105: 
                    106:        if (lstat(source, &s1) < 0) {
                    107:                error("cannot access %s", source);
                    108:                return (1);
                    109:        }
                    110:        /*
                    111:         * First, try to rename source to destination.
                    112:         * The only reason we continue on failure is if
                    113:         * the move is on a nondirectory and not across
                    114:         * file systems.
                    115:         */
                    116:        targetexists = lstat(target, &s2) >= 0;
                    117:        if (targetexists) {
                    118:                if (iflag && !fflag && query("remove %s? ", target) == 0)
                    119:                        return (1);
                    120:                if (s1.st_dev == s2.st_dev && s1.st_ino == s2.st_ino) {
                    121:                        error("%s and %s are identical", source, target);
                    122:                        return (1);
                    123:                }
                    124:                if (access(target, 2) < 0 && !fflag && isatty(fileno(stdin))) {
                    125:                        if (query("override protection %o for %s? ",
                    126:                          s2.st_mode & MODEBITS, target) == 0)
                    127:                                return (1);
                    128:                }
                    129:        }
                    130:        if (rename(source, target) >= 0)
                    131:                return (0);
                    132:        if (errno != EXDEV) {
                    133:                Perror2(source, "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:                error("cannot unlink %s", target);
                    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];
                    152: 
                    153:                if (readlink(source, symln, sizeof (symln)) < 0) {
                    154:                        Perror(source);
                    155:                        return (1);
                    156:                }
                    157:                m = umask(~(s1.st_mode & MODEBITS));
                    158:                if (symlink(symln, target) < 0) {
                    159:                        Perror(target);
                    160:                        return (1);
                    161:                }
                    162:                (void) umask(m);
                    163:                goto cleanup;
                    164:        }
                    165:        if (ISDEV(s1)) {
                    166:                time_t tv[2];
                    167: 
                    168:                if (mknod(target, s1.st_mode, s1.st_rdev) < 0) {
                    169:                        Perror(target);
                    170:                        return (1);
                    171:                }
                    172:                /* kludge prior to utimes */
                    173:                tv[0] = s1.st_atime;
                    174:                tv[1] = s1.st_mtime;
                    175:                (void) utime(target, tv);
                    176:                goto cleanup;
                    177:        }
                    178:        if (ISREG(s1)) {
                    179:                int i, c, status;
                    180:                time_t tv[2];
                    181: 
                    182:                i = fork();
                    183:                if (i == -1) {
                    184:                        error("try again");
                    185:                        return (1);
                    186:                }
                    187:                if (i == 0) {
                    188:                        execl("/bin/cp", "cp", source, target, 0);
                    189:                        error("cannot exec /bin/cp");
                    190:                        exit(1);
                    191:                }
                    192:                while ((c = wait(&status)) != i && c != -1)
                    193:                        ;
                    194:                if (status != 0)
                    195:                        return (1);
                    196:                /* kludge prior to utimes */
                    197:                tv[0] = s1.st_atime;
                    198:                tv[1] = s1.st_mtime;
                    199:                (void) utime(target, tv);
                    200:                goto cleanup;
                    201:        }
                    202:        error("%s: unknown file type %o", source, s1.st_mode);
                    203:        return (1);
                    204: 
                    205: cleanup:
                    206:        if (unlink(source) < 0) {
                    207:                error("cannot unlink %s", source);
                    208:                return (1);
                    209:        }
                    210:        return (0);
                    211: }
                    212: 
                    213: /*VARARGS*/
                    214: query(prompt, a1, a2)
                    215:        char *a1;
                    216: {
                    217:        register char i, c;
                    218: 
                    219:        fprintf(stderr, prompt, a1, a2);
                    220:        i = c = getchar();
                    221:        while (c != '\n' && c != EOF)
                    222:                c = getchar();
                    223:        return (i == 'y');
                    224: }
                    225: 
                    226: char *
                    227: dname(name)
                    228:        register char *name;
                    229: {
                    230:        register char *p;
                    231: 
                    232:        p = name;
                    233:        while (*p)
                    234:                if (*p++ == DELIM && *p)
                    235:                        name = p;
                    236:        return name;
                    237: }
                    238: 
                    239: /*VARARGS*/
                    240: error(fmt, a1, a2)
                    241:        char *fmt;
                    242: {
                    243: 
                    244:        fprintf(stderr, "mv: ");
                    245:        fprintf(stderr, fmt, a1, a2);
                    246:        fprintf(stderr, "\n");
                    247: }
                    248: 
                    249: Perror(s)
                    250:        char *s;
                    251: {
                    252:        char buf[MAXPATHLEN + 10];
                    253:        
                    254:        sprintf(buf, "mv: %s", s);
                    255:        perror(buf);
                    256: }
                    257: 
                    258: Perror2(s1, s2)
                    259:        char *s1, *s2;
                    260: {
                    261:        char buf[MAXPATHLEN + 20];
                    262: 
                    263:        sprintf(buf, "mv: %s: %s", s1, s2);
                    264:        perror(buf);
                    265: }

unix.superglobalmegacorp.com

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