Annotation of coherent/d/bin/mv.c, revision 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.