Annotation of coherent/b/bin/cpdir.c, revision 1.1

1.1     ! root        1: /*
        !             2:  * Cpdir. Copy hierarchies in a file system, preserving structure.
        !             3:  *       Define SLOW for 'block at a time copying' - not recommended tho.
        !             4:  */
        !             5: #include <stdio.h>
        !             6: #include <errno.h>
        !             7: #include <signal.h>
        !             8: #include <sys/types.h>
        !             9: #include <sys/stat.h>
        !            10: #include <sys/dir.h>
        !            11: #include <ctype.h>
        !            12: #include <access.h>
        !            13: #include <canon.h>
        !            14: 
        !            15: #define        VERSION         "1.1"
        !            16: #define        CPBUFSIZ        (50*BUFSIZ)                     /* copy buffer */
        !            17: #define        SDSIZ           (sizeof(struct direct))
        !            18: #define        MAXINT          32767
        !            19: #define        SOURCE          0
        !            20: #define        TARGET          1
        !            21: #define        DEV0            ((dev_t)0)
        !            22: #define        INODE0          ((ino_t)0)
        !            23: #define        ROOTUID         0
        !            24: #define        HASHSIZE        37
        !            25: 
        !            26: #define        hash(ino)       ((ino)%HASHSIZE)
        !            27: 
        !            28: #define        TRUE            (0==0)
        !            29: #define        FALSE           (0==1)
        !            30: 
        !            31: typedef        char            bool;
        !            32: typedef        unsigned char   uchar;
        !            33: typedef        unsigned int    uint;
        !            34: typedef        unsigned short  ushort;
        !            35: typedef        unsigned long   ulong;
        !            36: 
        !            37: typedef union {
        !            38:        struct  direct  dbuf;
        !            39:        char            cbuf[SDSIZ + 1];
        !            40: } DIRBUF;
        !            41: #define        db_ino          dbuf.d_ino
        !            42: #define        db_name         dbuf.d_name
        !            43: 
        !            44: typedef struct link {
        !            45:        ino_t           l_ino;
        !            46:        dev_t           l_dev;
        !            47:        dev_t           l_tdev;
        !            48:        struct link     *l_next;
        !            49:        uint            l_nlink;
        !            50:        char            l_name[];
        !            51: } LINK;
        !            52: 
        !            53: typedef struct str {
        !            54:        struct str      *s_next;
        !            55:        char            s_str[];
        !            56: } STR;
        !            57: 
        !            58: 
        !            59: 
        !            60: /*
        !            61:  * Global variables.
        !            62:  */
        !            63: extern int     errno;
        !            64: dev_t          dir2_dev;
        !            65: ino_t          dir2_ino;
        !            66: dev_t          src_dev;
        !            67: dev_t          tgt_dev;
        !            68: struct stat    srcstat;
        !            69: struct stat    tgtstat;
        !            70: LINK           *srctab[HASHSIZE];
        !            71: LINK           *tgttab[HASHSIZE];
        !            72: STR            *strtab[HASHSIZE];
        !            73: 
        !            74: bool   aflag;
        !            75: bool   dflag;
        !            76: bool   eflag;
        !            77: bool   sflag;
        !            78: bool   tflag;
        !            79: bool   uflag;
        !            80: bool   vflag;
        !            81: bool   wflag;
        !            82: bool   root;
        !            83: bool   splitmsg;
        !            84: bool   errprefix;
        !            85: bool   dir1slash;
        !            86: bool   dir2slash;
        !            87: 
        !            88: int    rlimit = MAXINT;
        !            89: int    rlevel = 1;
        !            90: int    exitval;
        !            91: int    numsuppress;
        !            92: int    broken;
        !            93: int    srclinks;
        !            94: int    tgtlinks;
        !            95: int    srcsize;
        !            96: int    tgtsize;
        !            97: int    dir1len;
        !            98: int    dir2len;
        !            99: int    interrupted;            /* For handling SIGINT and SIGQUIT */
        !           100: 
        !           101: short  uid;
        !           102: short  gid;
        !           103: 
        !           104: char   *dir1;
        !           105: char   *dir2;
        !           106: char   *target;
        !           107: char   *source;
        !           108: 
        !           109: /*
        !           110:  * Error message and other strings.
        !           111:  */
        !           112: char   *dot =          ".";
        !           113: char   *dotdot =       "..";
        !           114: char   *fmt1 =         "%s\n";
        !           115: char   *fmt1a =        "%-72s\r";
        !           116: char   *fmt2 =         "%s: %s\n";
        !           117: char   *fmt3 =         "%s: %s%s\n";
        !           118: char   *fmt4 =         "%s: %s%s%s\n";
        !           119: char   *usage =        "usage: cpdir [options] dir1 dir2";
        !           120: char   *devbound =     "crossing device boundary";
        !           121: char   *writeerr =     "write error";
        !           122: char   *readerr =      "read error";
        !           123: char   *supressd =     "suppressed";
        !           124: char   *linked =       "linked";
        !           125: char   *notdir =       "not a directory";
        !           126: char   *nomemory =     "out of memory";
        !           127: char   *nopermit =     "permission denied";
        !           128: char   *nomkdir =      "cannot make directory";
        !           129: char   *nounlink =     "cannot unlink ";
        !           130: char   *nolink =       "cannot link ";
        !           131: char   *nocreate =     "cannot create";
        !           132: char   *nofind =       "cannot find";
        !           133: char   *noopen =       "cannot open";
        !           134: 
        !           135: /*
        !           136:  * Functions returning non_int.
        !           137:  */
        !           138: long   lseek();
        !           139: char   *tmalloc();
        !           140: char   *realloc();
        !           141: char   *rindex();
        !           142: char   *concat();
        !           143: char   *parent();
        !           144: bool   suppress();
        !           145: bool   isslash();
        !           146: bool   dirchecks();
        !           147: bool   linkattempt();
        !           148: bool   tgtunlink();
        !           149: LINK   *linklocate();
        !           150: LINK   *linkinstall();
        !           151: 
        !           152: main(ac, av) int ac; char *av[];
        !           153: {
        !           154:        ac = 0;
        !           155:        aarghh(av);
        !           156:        init();
        !           157:        cpdir();
        !           158:        report();
        !           159:        if (aflag)
        !           160:                printf("%72s\r", "");
        !           161:        return (exitval);
        !           162: }
        !           163: 
        !           164: aarghh(av)
        !           165: register char *av[];
        !           166: {
        !           167:        register char *cp;
        !           168: 
        !           169:        for (;;) {
        !           170:                if ((cp = *++av) == NULL) {
        !           171:                        errprint(fmt1, usage);
        !           172:                        exit(1);
        !           173:                }
        !           174:                if (*cp++ != '-')
        !           175:                        break;
        !           176:                while (*cp)
        !           177:                        switch (*cp++) {
        !           178:                        case 'a':
        !           179:                                aflag = TRUE;
        !           180:                                break;
        !           181:                        case 'd':
        !           182:                                dflag = TRUE;
        !           183:                                break;
        !           184:                        case 'e':
        !           185:                                eflag = TRUE;
        !           186:                                break;
        !           187:                        case 'r':
        !           188:                                if (!isdigit(*cp)) {
        !           189:                                        rlimit = 1;
        !           190:                                        break;
        !           191:                                }
        !           192:                                *av = cp;
        !           193:                                rlimit = new_atoi(av);
        !           194:                                cp = *av;
        !           195:                                break;
        !           196:                        case 's':
        !           197:                                sflag = TRUE;
        !           198:                                strinstall(cp);
        !           199:                                ++numsuppress;
        !           200:                                goto NEXTARG;
        !           201:                                break;
        !           202:                        case 't':
        !           203:                                tflag = wflag = eflag = TRUE;
        !           204:                                break;
        !           205:                        case 'u':
        !           206:                                uflag = TRUE;
        !           207:                                break;
        !           208:                        case 'v':
        !           209:                                vflag = wflag = TRUE;
        !           210:                                break;
        !           211:                        case 'V':
        !           212:                                fprintf(stderr, "cpdir: V%s\n", VERSION);
        !           213:                                break;
        !           214:                        default:
        !           215:                                errprint(fmt1, usage);
        !           216:                                exit(1);
        !           217:                        }
        !           218:                NEXTARG:;
        !           219:        }
        !           220: 
        !           221:        if ((dir1=*av++) == NULL  ||  (dir2=*av++) == NULL  ||  *av != NULL) {
        !           222:                errprint(fmt1, usage);
        !           223:                exit(1);
        !           224:        }
        !           225:        return;
        !           226: }
        !           227: 
        !           228: /*
        !           229:  * Actions: Initialize certain flags and the name buffers source and target.
        !           230:  * Verify dir1 and dir2 permissions. Dir2 is made if necessary.
        !           231:  * Side Effects: On return srcstat contains the status of dir1. If dir2
        !           232:  * exists tgtstat contains its status. In the case that tflag is set and dir2
        !           233:  * does not exist, tgt_dev and tgtstat.st_dev are the device of target's
        !           234:  * parent, the device that target would be created on except for tflag.
        !           235:  */
        !           236: init()
        !           237: {
        !           238:        struct stat outstat;
        !           239:        struct stat errstat;
        !           240: 
        !           241:        uid = getuid();
        !           242:        gid = getgid();
        !           243:        root = (uid == ROOTUID);
        !           244:        if (root)
        !           245:                umask(0);
        !           246: 
        !           247:        errprefix = !isatty(fileno(stdin));
        !           248:        fstat(fileno(stdout), &outstat);
        !           249:        fstat(fileno(stderr), &errstat);
        !           250:        splitmsg = (outstat.st_ino != errstat.st_ino) ||
        !           251:                   (outstat.st_dev != errstat.st_dev);
        !           252: 
        !           253:        dir1len = strlen(dir1);
        !           254:        srcsize = (dir1len + 1);
        !           255:        source = tmalloc(srcsize);
        !           256:        strcpy(source, dir1);
        !           257:        dir1slash = isslash(dir1);
        !           258: 
        !           259:        dir2len = strlen(dir2);
        !           260:        tgtsize = dir2len + 1;
        !           261:        target = tmalloc(tgtsize);
        !           262:        strcpy(target, dir2);
        !           263:        dir2slash = isslash(dir2);
        !           264: 
        !           265:        /*
        !           266:         * We must check boundary conditions before we call dirchecks().
        !           267:         * These are: source exists and is a directory, and if target does not
        !           268:         * exist that we have write and search permission on its parent and
        !           269:         * tgt_dev contains the device number of the parent.
        !           270:         */
        !           271:        if (stat(dir1, &srcstat) < 0) {
        !           272:                errprint(fmt2, dir1, nofind);
        !           273:                exit(1);
        !           274:        }
        !           275:        if ((srcstat.st_mode & S_IFMT) != S_IFDIR) {
        !           276:                errprint(fmt2, dir1, notdir);
        !           277:                exit(1);
        !           278:        }
        !           279:        if (access(dir2, 0) < 0) {
        !           280:                register char *cp;
        !           281:                cp = parent(dir2);
        !           282:                if (stat(cp, &tgtstat) < 0) {
        !           283:                        errprint(fmt2, dir2, "cannot find parent");
        !           284:                        exit(1);
        !           285:                }
        !           286:                if (access(cp, AWRITE|ASRCH) < 0) {
        !           287:                        errprint(fmt2, dir2, nomkdir);
        !           288:                        exit(1);
        !           289:                }
        !           290:                tgt_dev = tgtstat.st_dev;
        !           291:        }
        !           292:        if (!dirchecks())
        !           293:                exit(1);
        !           294: 
        !           295:        src_dev = srcstat.st_dev;
        !           296:        dir2_dev = tgt_dev = tgtstat.st_dev;
        !           297:        if (access(target, 0) == 0)
        !           298:                dir2_ino = tgtstat.st_ino;
        !           299:        return;
        !           300: }
        !           301: 
        !           302: 
        !           303: /*
        !           304:  * Assume: Source is a directory we can read and search. Srcstat contains its
        !           305:  * status. Target is a directory we can write and search. Tgtstat contains its
        !           306:  * status. Src_dev and tgt_dev are the devices of the parents of source and
        !           307:  * target. If tflag is on target may not exist. In this case tgtstat.st_dev
        !           308:  * contains the device where target would have been created if tflag were off.
        !           309:  */
        !           310: cpdir()
        !           311: {
        !           312:        register int    n;
        !           313:        register int    fd;
        !           314:        register DIRBUF *dbp;
        !           315:        DIRBUF  dirbuf;
        !           316:        long    address;
        !           317:        dev_t   sdev;
        !           318:        dev_t   tdev;
        !           319:        struct  stat    locsrcstat;
        !           320:        struct  stat    loctgtstat;
        !           321: 
        !           322:        /*
        !           323:         * Check for circular copy.
        !           324:         */
        !           325:        if (srcstat.st_ino == dir2_ino &&
        !           326:            srcstat.st_dev == dir2_dev) {
        !           327:                if (wflag)
        !           328:                        printf(fmt2, source,
        !           329:                        "not copied to avoid circular copy");
        !           330:                return;
        !           331:        }
        !           332: 
        !           333:        /*
        !           334:         * Open source, and prepare dirbuf.
        !           335:         */
        !           336:        if ((fd = open(source, 0)) < 0) {
        !           337:                errprint(fmt2, source, noopen);
        !           338:                return;
        !           339:        }
        !           340:        dbp = &dirbuf;
        !           341:        dbp->cbuf[SDSIZ] = '\0';
        !           342: 
        !           343:        /*
        !           344:         * Save srcstat, src_dev, tgtstat, tgt_dev to restore before exit.
        !           345:         */
        !           346:        locsrcstat = srcstat;
        !           347:        loctgtstat = tgtstat;
        !           348:        tdev = tgt_dev;
        !           349:        sdev = src_dev;
        !           350: 
        !           351:        /*
        !           352:         * Detect the crossing of device boundaries.
        !           353:         */
        !           354:        if (tgt_dev != tgtstat.st_dev) {
        !           355:                if (wflag)
        !           356:                        printf(fmt2, target, devbound);
        !           357:                tgt_dev = tgtstat.st_dev;
        !           358:        }
        !           359:        if (src_dev != srcstat.st_dev) {
        !           360:                if (wflag)
        !           361:                        printf(fmt2, source, devbound);
        !           362:                src_dev = srcstat.st_dev;
        !           363:        }
        !           364: 
        !           365:        /*
        !           366:         * Loop through the directory source.
        !           367:         */
        !           368:        while ((n = read(fd, dbp->cbuf, SDSIZ)) > 0) {
        !           369:                if (n != SDSIZ) {
        !           370:                        errprint(fmt2, source, readerr);
        !           371:                        close(fd);
        !           372:                        goto OUT;
        !           373:                }
        !           374: 
        !           375:                canino(dbp->db_ino);
        !           376:                if (dbp->db_ino == INODE0       ||
        !           377:                    !strcmp(dbp->db_name, dot)  ||
        !           378:                    !strcmp(dbp->db_name, dotdot))
        !           379:                        continue;
        !           380: 
        !           381:                grow(dbp->db_name);
        !           382:                if (sflag  &&  suppress()) {
        !           383:                        if (vflag)
        !           384:                                printf(fmt2, source, supressd);
        !           385:                        shrink();
        !           386:                        continue;
        !           387:                }
        !           388:                if (stat(source, &srcstat) < 0) {
        !           389:                        errprint(fmt2, source, nofind);
        !           390:                        shrink();
        !           391:                        continue;
        !           392:                }
        !           393: 
        !           394:                switch (srcstat.st_mode & S_IFMT) {
        !           395:                default:
        !           396:                        errprint(fmt2, source, "unknown file type");
        !           397:                        shrink();
        !           398:                        continue;
        !           399:                case S_IFCHR:
        !           400:                case S_IFBLK:
        !           401:                        cpnode();
        !           402:                        shrink();
        !           403:                        continue;
        !           404:                case S_IFPIP:
        !           405:                        srcstat.st_rdev = DEV0;
        !           406:                        cpnode();
        !           407:                        shrink();
        !           408:                        continue;
        !           409:                case S_IFREG:
        !           410:                        cpfile();
        !           411:                        shrink();
        !           412:                        continue;
        !           413:                case S_IFDIR:
        !           414:                        if (rlevel == rlimit) {
        !           415:                                if (vflag)
        !           416:                                        printf(fmt2, source, supressd);
        !           417:                                shrink();
        !           418:                                continue;
        !           419:                        }
        !           420:                        if (!dirchecks()) {
        !           421:                                shrink();
        !           422:                                continue;
        !           423:                        }
        !           424: 
        !           425:                        address = lseek(fd, 0L, 1);
        !           426:                        close(fd);
        !           427:                        ++rlevel;
        !           428:                        cpdir();
        !           429:                        --rlevel;
        !           430:                        shrink();
        !           431:                        if ((fd = open(source, 0)) < 0) {
        !           432:                                errprint(fmt2, source,
        !           433:                                "cannot reopen, copy incomplete");
        !           434:                                goto OUT;
        !           435:                        }
        !           436:                        lseek(fd, address, 0);
        !           437:                        continue;
        !           438:                }
        !           439:        }
        !           440:        close(fd);
        !           441: 
        !           442:        OUT:
        !           443:        vprintf();
        !           444:        srcstat = locsrcstat;
        !           445:        tgtstat = loctgtstat;
        !           446:        tgt_dev = tdev;
        !           447:        src_dev = sdev;
        !           448:        adjust();
        !           449:        return;
        !           450: }
        !           451: 
        !           452: /*
        !           453:  * Assume source names the file to be copied, srcstat contains its status,
        !           454:  * and target is the file to copy to. Target may or may not exist.
        !           455:  */
        !           456: cpfile()
        !           457: {
        !           458: #ifndef        SLOW
        !           459:        register char *ip;
        !           460: #endif
        !           461:        register int n;
        !           462:        register int i;
        !           463:        register int fd1;
        !           464:        register int fd2;
        !           465:        register fsize_t size;
        !           466: #ifndef        SLOW
        !           467:        register char *wp;                              /* write pointer */
        !           468:        register int wflag;                             /* write flag */
        !           469:        static char buf[CPBUFSIZ];                      /* copy buffer */
        !           470: #else
        !           471:        static char buf[BUFSIZ];
        !           472: #endif
        !           473:        int intflag, hupflag;
        !           474: 
        !           475:        if (access(source, AREAD) < 0) {
        !           476:                errprint(fmt2, source, noopen);
        !           477:                return;
        !           478:        }
        !           479: 
        !           480:        if (uflag  &&  stat(target, &tgtstat) == 0)
        !           481:                if (srcstat.st_mtime <= tgtstat.st_mtime) {
        !           482:                        if (vflag)
        !           483:                                printf(fmt2, target, "no update");
        !           484:                        return;
        !           485:                }
        !           486: 
        !           487:        if (!tgtunlink())
        !           488:                return;
        !           489:        if (srcstat.st_nlink > 1)
        !           490:                if (linkattempt())
        !           491:                        return;
        !           492: 
        !           493:        if (tflag) {
        !           494:                vprintf();
        !           495:                return;
        !           496:        }
        !           497: 
        !           498:        intflag = catch(SIGINT);
        !           499:        hupflag = catch(SIGHUP);
        !           500:        if ((fd1 = open(source, 0)) < 0) {
        !           501:                errprint(fmt2, source, noopen);
        !           502:                return;
        !           503:        }
        !           504:        if ((fd2 = creat(target, 0)) < 0) {
        !           505:                close(fd1);
        !           506:                errprint(fmt2, target, nocreate);
        !           507:                return;
        !           508:        }
        !           509: 
        !           510:        size = srcstat.st_size;
        !           511: #ifndef        SLOW
        !           512:        while ((n = read(fd1, buf, sizeof(buf))) > 0) {
        !           513: #else
        !           514:        while ((n = read(fd1, buf, BUFSIZ)) > 0) {
        !           515: #endif
        !           516:                /*
        !           517:                 * Check for blocks of zeroes (holes in a sparse file).
        !           518:                 * However, a block of zeroes at the end of a file must be
        !           519:                 * written so the file has correct length.
        !           520:                 */
        !           521: #ifndef        SLOW
        !           522:                wp = ip = buf;
        !           523:                size -= n;
        !           524:                while ((n-BUFSIZ) > 0 || ((n-BUFSIZ) == 0 && size != 0)) {
        !           525:                        n -= BUFSIZ;
        !           526:                        wflag = FALSE;
        !           527:                        ip = wp;
        !           528:                        for (i = 0; i < BUFSIZ; ++i)
        !           529:                                if (*ip++ != '\0') {
        !           530:                                        wflag = TRUE;
        !           531:                                        break;
        !           532:                                }
        !           533:                        if (wflag) {
        !           534:                                if (write(fd2, wp, BUFSIZ) < BUFSIZ) {
        !           535:                                        errprint(fmt2, target, writeerr);
        !           536:                                        close(fd1);
        !           537:                                        close(fd2);
        !           538:                                        return (FALSE);
        !           539:                                }
        !           540:                        } else {
        !           541:                                lseek(fd2, (long)BUFSIZ, 1);
        !           542:                        }
        !           543:                        wp += BUFSIZ;
        !           544:                }
        !           545:                if (write(fd2, wp, n) < n) {
        !           546:                        errprint(fmt2, target, writeerr);
        !           547:                        close(fd1);
        !           548:                        close(fd2);
        !           549:                        return (FALSE);
        !           550:                }
        !           551: #else
        !           552:                if ((size -= n) == (fsize_t)0)
        !           553:                        goto WRITE;
        !           554:                for (i = 0; i < n; ++i)
        !           555:                        if (buf[i] != '\0')
        !           556:                                goto WRITE;
        !           557:                lseek(fd2, (long)BUFSIZ, 1);
        !           558:                continue;
        !           559: 
        !           560:                WRITE:
        !           561:                if (write(fd2, buf, n) < n) {
        !           562:                        errprint(fmt2, target, writeerr);
        !           563:                        close(fd1);
        !           564:                        close(fd2);
        !           565:                        return (FALSE);
        !           566:                }
        !           567: #endif
        !           568:        }
        !           569:        close(fd1);
        !           570:        close(fd2);
        !           571:        adjust();
        !           572:        if (intflag)
        !           573:                signal(SIGINT, SIG_DFL);
        !           574:        if (hupflag)
        !           575:                signal(SIGHUP, SIG_DFL);
        !           576:        if (interrupted)
        !           577:                exit(1);
        !           578: 
        !           579:        if (n < 0)
        !           580:                errprint(fmt2, source, readerr);
        !           581:        else vprintf();
        !           582:        return;
        !           583: }
        !           584: 
        !           585: /*
        !           586:  * Copy special nodes and named pipes.
        !           587:  */
        !           588: cpnode()
        !           589: {
        !           590:        if (!root) {
        !           591:                if (vflag)
        !           592:                        printf(fmt2, source, "not the super-user");
        !           593:                return;
        !           594:        }
        !           595:        if (!tgtunlink())
        !           596:                return;
        !           597:        if (srcstat.st_nlink > 1)
        !           598:                if (linkattempt())
        !           599:                        return;
        !           600:        if (!tflag) {
        !           601:                if (mknod(target, srcstat.st_mode, srcstat.st_rdev) < 0) {
        !           602:                        errprint(fmt2, target, "cannot make node");
        !           603:                        return;
        !           604:                }
        !           605:                adjust();
        !           606:        }
        !           607:        if (vflag)
        !           608:                printf(fmt2, target, "copied node");
        !           609:        else if (aflag)
        !           610:                printf(fmt1a, target);
        !           611:        return;
        !           612: }
        !           613: 
        !           614: 
        !           615: /*
        !           616:  * Grow each of target and source by appending '/' and cp.
        !           617:  */
        !           618: grow(cp)
        !           619: register char *cp;
        !           620: {
        !           621:        register int a;
        !           622:        register int b;
        !           623: 
        !           624:        a = strlen(cp) + 2;
        !           625: 
        !           626:        b = strlen(source);
        !           627:        if (a+b > srcsize) {
        !           628:                if ((source = realloc(source, a+b)) == NULL) {
        !           629:                        errprint(fmt1, nomemory);
        !           630:                        exit(1);
        !           631:                }
        !           632:                srcsize = a+b;
        !           633:        }
        !           634:        if (rlevel > 1  ||  !dir1slash)
        !           635:                source[b++] = '/';
        !           636:        strcpy(source+b, cp);
        !           637: 
        !           638:        b = strlen(target);
        !           639:        if (a+b > tgtsize) {
        !           640:                if ((target = realloc(target, a+b)) == NULL) {
        !           641:                        errprint(fmt1, nomemory);
        !           642:                        exit(1);
        !           643:                }
        !           644:                tgtsize = a+b;
        !           645:        }
        !           646:        if (rlevel > 1  ||  !dir2slash)
        !           647:                target[b++] = '/';
        !           648:        strcpy(target+b, cp);
        !           649: }
        !           650: 
        !           651: /*
        !           652:  * Shrink source and target down by the last pathname component.
        !           653:  */
        !           654: shrink()
        !           655: {
        !           656:        if (rlevel == 1  &&  dir1slash)
        !           657:                source[dir1len] = '\0';
        !           658:        else
        !           659:                *rindex(source, '/') = '\0';
        !           660:        if (rlevel == 1  &&  dir2slash)
        !           661:                target[dir2len] = '\0';
        !           662:        else
        !           663:                *rindex(target, '/') = '\0';
        !           664:        return;
        !           665: }
        !           666: 
        !           667: 
        !           668: /*
        !           669:  * Returns a value equal to atoi(*cpp). Positive decimal integers only.
        !           670:  * Leaves *cpp pointing to the character that terminated the digit string.
        !           671:  */
        !           672: new_atoi(cpp)
        !           673: char **cpp;
        !           674: {
        !           675:        register int sum = 0;
        !           676:        register int c;
        !           677:        register char *cp;
        !           678: 
        !           679:        sum = 0;
        !           680:        cp = *cpp;
        !           681:        while (isdigit(c = *cp++)) {
        !           682:                sum *= 10;
        !           683:                sum -= '0';
        !           684:                sum += c;
        !           685:        }
        !           686:        *cpp = cp-1;
        !           687:        return (sum);
        !           688: }
        !           689: 
        !           690: errprint(arg)
        !           691: char *arg[];
        !           692: {
        !           693:        register char *format;
        !           694: 
        !           695:        format = (errprefix) ? "cpdir: %r" : "%r";
        !           696:        fprintf(stderr, format, &arg);
        !           697:        if (wflag  &&  splitmsg)
        !           698:                printf(format, &arg);
        !           699:        if (!eflag)
        !           700:                exit(1);
        !           701:        exitval = 1;
        !           702:        return;
        !           703: }
        !           704: 
        !           705: /*
        !           706:  * Interface to malloc to check for bad returns.
        !           707:  */
        !           708: char *
        !           709: tmalloc(n)
        !           710: int n;
        !           711: {
        !           712:        register char *cp;
        !           713:        if ((cp = malloc(n)) == NULL) {
        !           714:                errprint(fmt1, nomemory);
        !           715:                exit(1);
        !           716:        }
        !           717:        return (cp);
        !           718: }
        !           719: 
        !           720: /*
        !           721:  * Assume: source is a dir, srcstat has its status, we have write and search
        !           722:  * permission on target's parent directory, tgt_dev is the device of target's
        !           723:  * parent.
        !           724:  * Actions: Check permissions on source. Check permissions on target if it
        !           725:  * exists. If non-extant and tflag is off, make it.
        !           726:  * Side Effects: On return, if target exists, tgtstat contains its status. If
        !           727:  * it does not exist, tgtstat.st_dev is the device it would have been created
        !           728:  * on if tflag were off.
        !           729:  * Return TRUE if everything Aok, FALSE otherwise.
        !           730:  */
        !           731: bool
        !           732: dirchecks()
        !           733: {
        !           734:        register int n;
        !           735:        static int status;
        !           736: 
        !           737:        if (access(source, AREAD | ASRCH) < 0) {
        !           738:                errprint(fmt2, source, nopermit);
        !           739:                return (FALSE);
        !           740:        }
        !           741: 
        !           742:        if (stat(target, &tgtstat) == 0) {
        !           743:                if ((tgtstat.st_mode & S_IFMT) != S_IFDIR) {
        !           744:                        errprint(fmt3, source, "target is ", notdir);
        !           745:                        return (FALSE);
        !           746:                }
        !           747:                if (access(target, AWRITE | ASRCH) < 0) {
        !           748:                        errprint(fmt2, target, nopermit);
        !           749:                        return (FALSE);
        !           750:                }
        !           751:                return (TRUE);
        !           752:        }
        !           753: 
        !           754:        if (tflag) {
        !           755:                tgtstat.st_dev = tgt_dev;
        !           756:                return (TRUE);
        !           757:        }
        !           758: 
        !           759:        if (mkdir(target, 0700)) {
        !           760:                errprint(fmt2, target, nomkdir);
        !           761:                return (FALSE);
        !           762:        }
        !           763: 
        !           764:        if (stat(target, &tgtstat) < 0) {
        !           765:                errprint(fmt2, target, "made but cannot stat");
        !           766:                return (FALSE);
        !           767:        }
        !           768:        return (TRUE);
        !           769: }
        !           770: 
        !           771: strinstall(cp)
        !           772: register char *cp;
        !           773: {
        !           774:        register STR *sp;
        !           775:        register int n;
        !           776: 
        !           777:        n = strhash(cp);
        !           778:        for (sp = strtab[n]; sp != NULL; sp = sp->s_next)
        !           779:                if (strcmp(cp, sp->s_str) == 0)
        !           780:                        return;
        !           781:        sp = (STR *) tmalloc(sizeof(STR) + strlen(cp) + 1);
        !           782:        sp->s_next = strtab[n];
        !           783:        strtab[n] = sp;
        !           784:        strcpy(sp->s_str, cp);
        !           785:        return;
        !           786: }
        !           787: 
        !           788: bool
        !           789: suppress()
        !           790: {
        !           791:        register char *cp;
        !           792:        register STR *sp;
        !           793:        register STR **spp;
        !           794: 
        !           795:        cp = source + dir1len;
        !           796:        if (!dir1slash)
        !           797:                ++cp;
        !           798:        spp = strtab + strhash(cp);
        !           799:        if ((sp = *spp) == NULL)
        !           800:                return (FALSE);
        !           801:        while (sp != NULL) {
        !           802:                if (strcmp(cp, sp->s_str) == 0) {
        !           803:                        *spp = sp->s_next;
        !           804:                        free(sp);
        !           805:                        if (--numsuppress == 0)
        !           806:                                sflag = FALSE;
        !           807:                        return (TRUE);
        !           808:                }
        !           809:                spp = &(sp->s_next);
        !           810:                sp = *spp;
        !           811:        }
        !           812:        return (FALSE);
        !           813: }
        !           814: 
        !           815: strhash(cp)
        !           816: register uchar *cp;
        !           817: {
        !           818:        register uint sum = 0;
        !           819:        for (sum = 0; *cp != '\0'; sum += *cp++)
        !           820:                ;
        !           821:        return (sum % HASHSIZE);
        !           822: }
        !           823: 
        !           824: LINK *
        !           825: linklocate(flag)
        !           826: int flag;
        !           827: {
        !           828:        register LINK *lp;
        !           829:        register struct stat *stp;
        !           830: 
        !           831:        if (flag == SOURCE) {
        !           832:                stp = &srcstat;
        !           833:                lp = srctab[hash(stp->st_ino)];
        !           834:        }
        !           835:        else {
        !           836:                stp = &tgtstat;
        !           837:                lp = tgttab[hash(stp->st_ino)];
        !           838:        }
        !           839: 
        !           840:        for ( ; lp != NULL; lp = lp->l_next) {
        !           841:                if (lp->l_ino != stp->st_ino)
        !           842:                        continue;
        !           843:                if (lp->l_dev != stp->st_dev)
        !           844:                        continue;
        !           845:                --(lp->l_nlink);
        !           846:                return (lp);
        !           847:        }
        !           848:        return (NULL);
        !           849: }
        !           850: 
        !           851: LINK *
        !           852: linkinstall(flag)
        !           853: int flag;
        !           854: {
        !           855:        register LINK **lpp;
        !           856:        register LINK *lp;
        !           857:        register struct stat *stp;
        !           858: 
        !           859:        if (flag == SOURCE) {
        !           860:                ++srclinks;
        !           861:                stp = &srcstat;
        !           862:                lpp = hash(stp->st_ino) + srctab;
        !           863:        }
        !           864:        else {
        !           865:                ++tgtlinks;
        !           866:                stp = &tgtstat;
        !           867:                lpp = hash(stp->st_ino) + tgttab;
        !           868:        }
        !           869: 
        !           870:        lp = (LINK *) tmalloc(sizeof(LINK) + strlen(target) - dir2len + 1);
        !           871:        if (!dir2slash)
        !           872:                strcpy(lp->l_name, target + dir2len + 1);
        !           873:        else
        !           874:                strcpy(lp->l_name, target + dir2len);
        !           875:        lp->l_dev = stp->st_dev;
        !           876:        lp->l_ino = stp->st_ino;
        !           877:        lp->l_tdev = tgt_dev;
        !           878:        lp->l_nlink = stp->st_nlink - 1;
        !           879:        lp->l_next = *lpp;
        !           880:        *lpp = lp;
        !           881:        return (lp);
        !           882: }
        !           883: 
        !           884: linkpurge(flag, lp)
        !           885: int flag;
        !           886: register LINK *lp;
        !           887: {
        !           888:        register LINK *lp1;
        !           889:        register LINK **lpp;
        !           890: 
        !           891:        if (flag == SOURCE) {
        !           892:                --srclinks;
        !           893:                lpp = hash(srcstat.st_ino) + srctab;
        !           894:        }
        !           895:        else {
        !           896:                --tgtlinks;
        !           897:                lpp = hash(tgtstat.st_ino) + tgttab;
        !           898:        }
        !           899: 
        !           900:        for (lp1 = *lpp; lp1 != NULL; *lpp = lp1, lp1 = lp1->l_next) {
        !           901:                if (lp1 != lp)
        !           902:                        continue;
        !           903:                *lpp = lp1->l_next;
        !           904:                free((char *)lp1);
        !           905:                return;
        !           906:        }
        !           907:        return;
        !           908: }
        !           909: 
        !           910: bool
        !           911: linkattempt()
        !           912: {
        !           913:        register LINK *lp;
        !           914:        register bool ret;
        !           915:        register char *cp;
        !           916: 
        !           917:        if ((lp = linklocate(SOURCE)) == NULL) {
        !           918:                linkinstall(SOURCE);
        !           919:                return (FALSE);
        !           920:        }
        !           921:        cp = concat(dir2, lp->l_name);
        !           922: 
        !           923:        if (tflag) {
        !           924:                if (tgt_dev != lp->l_tdev) {
        !           925:                        errprint(fmt4, target, nolink, " to ", cp);
        !           926:                        ++broken;
        !           927:                        ret = FALSE;
        !           928:                }
        !           929:                else {
        !           930:                        vprintf();
        !           931:                        ret = TRUE;
        !           932:                }
        !           933:        }
        !           934:        else if (link(cp, target) == 0) {
        !           935:                vprintf();
        !           936:                ret = TRUE;
        !           937:        }
        !           938:        else {
        !           939:                errprint(fmt4, target, nolink, " to ", cp);
        !           940:                ++broken;
        !           941:                ret = FALSE;
        !           942:        }
        !           943: 
        !           944:        if (lp->l_nlink == 0)
        !           945:                linkpurge(SOURCE, lp);
        !           946:        return (ret);
        !           947: }
        !           948: 
        !           949: bool
        !           950: tgtunlink()
        !           951: {
        !           952:        register LINK *lp;
        !           953: 
        !           954:        if (stat(target, &tgtstat) < 0)
        !           955:                return (TRUE);
        !           956:        if ((tgtstat.st_mode & S_IFMT) == S_IFDIR) {
        !           957:                errprint(fmt3, target, nounlink, "directory");
        !           958:                return (FALSE);
        !           959:        }
        !           960:        else if ((tgtstat.st_mode & S_IFMT) != (srcstat.st_mode & S_IFMT)) {
        !           961:                errprint(fmt3, source, "file type mismatch with ", target);
        !           962:                return (FALSE);
        !           963:        }
        !           964: 
        !           965:        if (!tflag)
        !           966:                if (unlink(target) < 0) {
        !           967:                        errprint(fmt2, target, nounlink);
        !           968:                        return (FALSE);
        !           969:                }
        !           970:        if (tflag)
        !           971:                printf(fmt2, target, "unlinked");
        !           972: 
        !           973:        if ((lp = linklocate(TARGET)) != NULL) {
        !           974:                if (lp->l_nlink == 0)
        !           975:                        linkpurge(TARGET, lp);
        !           976:        }
        !           977:        else if (tgtstat.st_nlink > 1)
        !           978:                linkinstall(TARGET);
        !           979:        return (TRUE);
        !           980: }
        !           981: 
        !           982: report()
        !           983: {
        !           984:        register LINK *lp;
        !           985:        register LINK **lpp;
        !           986:        static char *fmtlinks = "%s external links into hierarchy %s:\n";
        !           987: 
        !           988:        if (!wflag)
        !           989:                return;
        !           990:        if (broken)
        !           991:                printf("%d internal link%s broken\n", broken,
        !           992:                        (broken == 1) ? "" : "s");
        !           993:        if (srclinks) {
        !           994:                printf(fmtlinks, "missed", dir1);
        !           995:                for (lpp = srctab; lpp < srctab + HASHSIZE; ++lpp)
        !           996:                        for (lp = *lpp; lp != NULL; lp = lp->l_next)
        !           997:                                printf("\t%d\t%s (inode %d)\n", lp->l_nlink,
        !           998:                                        concat(dir1, lp->l_name), lp->l_ino);
        !           999:        }
        !          1000:        if (tgtlinks) {
        !          1001:                printf(fmtlinks, "broken", target);
        !          1002:                for (lpp = tgttab; lpp < tgttab + HASHSIZE; ++lpp)
        !          1003:                        for (lp = *lpp; lp != NULL; lp = lp->l_next)
        !          1004:                                printf("\t%d\t%s (inode %d)\n", lp->l_nlink,
        !          1005:                                        concat(dir2, lp->l_name), lp->l_ino);
        !          1006:        }
        !          1007:        return;
        !          1008: }
        !          1009: 
        !          1010: /*
        !          1011:  * Chown, chmod, and chdate target. Assume srcstat has status of source,
        !          1012:  * and tgtstat has status of target if it exists.
        !          1013:  */
        !          1014: adjust()
        !          1015: {
        !          1016:        time_t date[2];
        !          1017: 
        !          1018:        if (tflag)
        !          1019:                return;
        !          1020:        if (root)
        !          1021:                chown(target, srcstat.st_uid, srcstat.st_gid);
        !          1022:        else
        !          1023:                chown(target, uid, gid);
        !          1024:        chmod(target, srcstat.st_mode & (root ? 07777 : 06777));
        !          1025:        if (dflag) {
        !          1026:                time(&date[0]);
        !          1027:                date[1] = srcstat.st_mtime;
        !          1028:                utime(target, date);
        !          1029:        }
        !          1030:        return;
        !          1031: }
        !          1032: 
        !          1033: /*
        !          1034:  * Concatenate pieces of pathnames, a and b. If a is not "/" a '/' char
        !          1035:  * is placed between the names. Previous return is freed.
        !          1036:  */
        !          1037: char *
        !          1038: concat(a, b)
        !          1039: register char *a;
        !          1040: char *b;
        !          1041: {
        !          1042:        static char *ret;
        !          1043:        register int a1;
        !          1044:        register char *rp;
        !          1045: 
        !          1046:        if (ret != NULL)
        !          1047:                free(ret);
        !          1048:        a1 = strlen(a);
        !          1049:        rp = ret = tmalloc(a1 + strlen(b) + 2);
        !          1050:        strcpy(rp, a);
        !          1051:        rp += a1;
        !          1052:        if (!isslash(ret))
        !          1053:                *rp++ = '/';
        !          1054:        strcpy(rp, b);
        !          1055:        return (ret);
        !          1056: }
        !          1057: 
        !          1058: char *
        !          1059: parent(cp)
        !          1060: register char *cp;
        !          1061: {
        !          1062:        static char *ret;
        !          1063:        register char *cp0;
        !          1064: 
        !          1065:        if (ret != NULL)
        !          1066:                free(ret);
        !          1067:        if ((cp0 = rindex(cp, '/')) == NULL)
        !          1068:                return (dot);
        !          1069:        ret = tmalloc(cp0 - cp + 1);
        !          1070:        strncpy(ret, cp, cp0 - cp);
        !          1071:        return (ret);
        !          1072: }
        !          1073: 
        !          1074: bool
        !          1075: isslash(cp)
        !          1076: register char *cp;
        !          1077: {
        !          1078:        register int c;
        !          1079:        while ((c = *cp++) != '\0')
        !          1080:                if (c != '/')
        !          1081:                        return (FALSE);
        !          1082:        return (TRUE);
        !          1083: }
        !          1084: 
        !          1085: /*
        !          1086:  * Routine exectuted when SIGINT or SIGHUP caught.
        !          1087:  * Set the interrupted flag.
        !          1088:  */
        !          1089: onintr()
        !          1090: {
        !          1091:        signal(SIGINT, SIG_IGN);
        !          1092:        signal(SIGHUP, SIG_IGN);
        !          1093:        ++interrupted;
        !          1094: }
        !          1095: 
        !          1096: /*
        !          1097:  * If sig's handler is currently SIG_DFL,
        !          1098:  * catch it with onintr and return 1.
        !          1099:  * If not, leave its handler unchanged and return 0.
        !          1100:  */
        !          1101: int
        !          1102: catch(sig) int sig;
        !          1103: {
        !          1104:        int (*old)();
        !          1105: 
        !          1106:        if ((old = signal(sig, SIG_IGN)) == SIG_DFL) {
        !          1107:                signal(sig, onintr);
        !          1108:                return 1;
        !          1109:        }
        !          1110:        signal(sig, old);
        !          1111:        return 0;
        !          1112: }
        !          1113: 
        !          1114: vprintf()
        !          1115: {
        !          1116:        if (vflag)
        !          1117:                printf(fmt1, target);
        !          1118:        else if (aflag) {
        !          1119:                printf(fmt1a, target);
        !          1120:                fflush(stdout);
        !          1121:        }
        !          1122: }

unix.superglobalmegacorp.com

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