Annotation of coherent/f/tmp/cpdir.flakey/cpdir.c, revision 1.1

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

unix.superglobalmegacorp.com

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