Annotation of coherent/f/tmp/cpdir.flakey/cpdir.c, revision 1.1.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.