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

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

unix.superglobalmegacorp.com

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