Annotation of coherent/d/bin/mv.c, revision 1.1.1.1

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 */

unix.superglobalmegacorp.com

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