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

1.1     ! root        1: /*
        !             2:  * Cpdir. Copy hierarchies in a file system, preserving structure.
        !             3:  *       Define SLOW for 'block at a time copying' - not recommended tho.
        !             4:  */
        !             5: #include <stdio.h>
        !             6: #include <errno.h>
        !             7: #include <signal.h>
        !             8: #include <sys/types.h>
        !             9: #include <sys/stat.h>
        !            10: #include <sys/dir.h>
        !            11: #include <ctype.h>
        !            12: #include <access.h>
        !            13: #include <canon.h>
        !            14: 
        !            15: #define        VERSION         "1.1"
        !            16: #define        CPBUFSIZ        (50*BUFSIZ)                     /* copy buffer */
        !            17: #define        SDSIZ           (sizeof(struct direct))
        !            18: #define        MAXINT          32767
        !            19: #define        SOURCE          0
        !            20: #define        TARGET          1
        !            21: #define        DEV0            ((dev_t)0)
        !            22: #define        INODE0          ((ino_t)0)
        !            23: #define        ROOTUID         0
        !            24: #define        HASHSIZE        37
        !            25: 
        !            26: #define        hash(ino)       ((ino)%HASHSIZE)
        !            27: 
        !            28: #define        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.