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

unix.superglobalmegacorp.com

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