Annotation of researchv10no/cmd/reccp.c, revision 1.1.1.1

1.1       root        1: /*
                      2:  *     reccp [-z] source dest
                      3:  *
                      4:  *          or
                      5:  *
                      6:  *     reccp [-z] source1 ... sourcen dest
                      7:  *
                      8:  *     In the first case, dest must not be a directory (else we have a
                      9:  *     degenerate version of the second case). In the second case,
                     10:  *     dest must be a directory; the resulting objects will be
                     11:  *     named dest/source1 ... dest/sourcen.
                     12:  *
                     13:  *     If any source is a directory, the tree structure under it
                     14:  *     will be (recursively) copied; this process will attempt to
                     15:  *     preserve any links that exist within the hierarchy.
                     16:  *
                     17:  *     This version of reccp copies symbolic links as symbolic links.
                     18:  *
                     19:  *     -z ==> copy blocks of zeros as holes.
                     20:  */
                     21: 
                     22: #include <stdio.h>
                     23: #include <sys/types.h>
                     24: #include <sys/stat.h>
                     25: #include <signal.h>
                     26: 
                     27: #define FTW_more_to_come 1
                     28: #include <ftw.h>
                     29:        /* rest of struct FTW: */
                     30:        int obase; /* added to give basename offset of output file */
                     31:        };
                     32: /* #include "ftw.body" */
                     33: /*
                     34:  * Struct FTW (whose definition starts at the end of ftw.h) must
                     35:  * must include at least the integers quit, base, and level.
                     36:  */
                     37: 
                     38: #define FTW_PATHLEN0 1000
                     39: #define FTW_PATHINC 1000
                     40: #ifndef S_IFLNK
                     41: #define lstat stat
                     42: #endif
                     43: #ifdef S_IFSOCK
                     44: #include <sys/dir.h>
                     45: #else
                     46: #include "ndir.h"
                     47: #endif
                     48: #ifndef ENOMEM
                     49: #include <errno.h>
                     50: #endif
                     51: 
                     52:        extern int errno;
                     53: 
                     54: /*
                     55:  *  Each generation of ftw1 (the real ftw) allocates one copy, R, of the
                     56:  *  following structure; it passes a pointer to this structure when it
                     57:  *  recursively invokes itself.  These structures are chained together,
                     58:  *  so that if it becomes necessary to recycle file descriptors, then
                     59:  *  the oldest descriptor (the one at the shallowest depth still open)
                     60:  *  can be recycled.
                     61:  */
                     62: 
                     63:        struct FTW_rec {
                     64:                struct FTW_rec *prev;
                     65:                long here;      /* seek to here when reopening at this level */
                     66:                DIR *fd;        /* file descriptor at this level */
                     67:                };
                     68: 
                     69: /*
                     70:  *  One instance, T, of the following structure is allocated by ftw; a
                     71:  *  pointer to it is passed to all generations of ftw1 (the real ftw).
                     72:  *  T could often be a global variable, but this way the parameter fn
                     73:  *  can invoke ftw for an independent tree walk.
                     74:  *  Component T->path points to storage for the object path-names;
                     75:  *  this storage may be relocated by realloc if T->path needs to be
                     76:  *  more than T->pathlast characters long.
                     77:  *  T->path[T->pathnext] is the next free character in the pathnames.
                     78:  *  T->depth = parameter depth to ftw.  T->lastout is the deepest level at
                     79:  *  which a file descriptor has been recycled.
                     80:  */
                     81: 
                     82:        struct FTW_top {
                     83:                int (*fn)();
                     84:                char *path;
                     85:                unsigned pathlast, pathnext;
                     86:                int lastout;
                     87:                int depth;
                     88:                };
                     89: 
                     90: int
                     91: ftw (path, fn, depth)
                     92:        char *path;
                     93:        int (*fn)();
                     94:        int depth;
                     95: {
                     96:        struct FTW_top T;
                     97:        struct FTW_rec R;
                     98:        struct FTW S;
                     99:        int rc;
                    100:        char *malloc(), *strcpy();
                    101: 
                    102:        T.depth = depth;
                    103:        T.lastout = -1;
                    104:        T.fn = fn;
                    105:        S.quit = 0;
                    106:        S.level = -1;
                    107: 
                    108:        /* initialize S.base, T.pathnext... */
                    109:                {
                    110:                register char c, *p, *q;
                    111:                for (p = q = path; c = *p; p++) if (c == '/') q = p + 1;
                    112:                S.base = q - path;
                    113:                T.pathnext = p - path;
                    114:                }
                    115: 
                    116:        T.pathlast = T.pathnext + FTW_PATHLEN0;
                    117:        T.path = malloc(T.pathlast);
                    118:        if (!T.path) { errno = ENOMEM; return -1; }
                    119:        strcpy(T.path, path);
                    120:        rc = ftw_1_(&R, &T, 0, &S);
                    121:        free(T.path);
                    122:        return rc;
                    123: }
                    124: 
                    125: int
                    126: ftw_1_ (R, T, level, S1)
                    127:        register struct FTW_rec *R;
                    128:        register struct FTW_top *T;
                    129:        int level;
                    130:        struct FTW *S1;
                    131: {
                    132:        int rc, n;
                    133:        DIR *fd;
                    134:        struct direct *dirp;
                    135:        char *component, *path;
                    136:        struct stat sb;
                    137:        struct FTW_rec mr;
                    138:        unsigned nextsave;
                    139:        struct FTW S;
                    140:        char *realloc();
                    141:        long lseek();
                    142: 
                    143:        mr.prev = R;
                    144:        path = T->path;
                    145:        S.level = level;
                    146:        S.quit = 0;
                    147:        S.base = S1->base;
                    148: 
                    149:        /* Try to get file status.  If unsuccessful, errno will say why. */
                    150:        if (lstat(path, &sb) < 0) {
                    151:                rc = (*T->fn) (path, &sb, FTW_NS, &S);
                    152:                S1->quit = S.quit;
                    153:                return rc;
                    154:                };
                    155: 
                    156:        /*
                    157:         *      The stat succeeded, so we know the object exists.
                    158:         *      If not a directory, call the user function and return.
                    159:         */
                    160: #ifdef S_IFLNK
                    161:        if ((sb.st_mode & S_IFMT) == S_IFLNK) {
                    162:                rc = (*T->fn) (path, &sb, FTW_SL, &S);
                    163:                S1->quit = S.quit;
                    164:                if (rc || S.quit == FTW_SKR) return rc;
                    165:                if (S.quit != FTW_FOLLOW) return 0;
                    166:                S1->quit = S.quit = 0;
                    167:                if (stat(path, &sb) < 0) {
                    168:                        rc = (*T->fn) (path, &sb, FTW_NSL, &S);
                    169:                        S1->quit = S.quit;
                    170:                        return rc;
                    171:                        };
                    172:                }
                    173: #endif
                    174:                
                    175:        if ((sb.st_mode & S_IFMT) != S_IFDIR) {
                    176:                rc = (*T->fn) (path, &sb, FTW_F, &S);
                    177:                S1->quit = S.quit;
                    178:                return rc;
                    179:                }
                    180: 
                    181:        /*
                    182:         *      The object was a directory.
                    183:         *
                    184:         *      Open a file to read the directory
                    185:         */
                    186:        mr.fd = fd = opendir(path);
                    187: 
                    188:        /*
                    189:         *      Call the user function, telling it whether
                    190:         *      the directory can be read.  If it can't be read
                    191:         *      call the user function or indicate an error,
                    192:         *      depending on the reason it couldn't be read.
                    193:         */
                    194:        if (!fd) {
                    195:                rc = (*T->fn) (path, &sb, FTW_DNR, &S);
                    196:                S1->quit = S.quit;
                    197:                return rc;
                    198:                }
                    199: 
                    200:        /* We could read the directory.  Call user function. */
                    201:        rc = (*T->fn) (path, &sb, FTW_D, &S);
                    202:        if (rc != 0)
                    203:                goto rtrn;
                    204:        if (S.quit == FTW_SKD) goto rtrn;
                    205:        if (S.quit == FTW_SKR) {S1->quit = FTW_SKR; goto rtrn;}
                    206: 
                    207:        /* Make sure path is big enough to hold generated pathnames. */
                    208: 
                    209:        n = nextsave = T->pathnext;
                    210:        if (n + MAXNAMLEN + 1 >= T->pathlast) {
                    211:                T->pathlast += FTW_PATHINC;
                    212:                path = T->path = realloc(T->path, T->pathlast);
                    213:                if (!path) {
                    214:                        errno = ENOMEM;
                    215:                        rc = -1;
                    216:                        goto rtrn;
                    217:                        }
                    218:                }
                    219:        
                    220:        /* Create a prefix to which we will append component names */
                    221: 
                    222:        if (n > 0 && path[n-1] != '/') path[n++] = '/';
                    223:        component = path + n;
                    224: 
                    225:        /*
                    226:         *      Read the directory one component at a time.
                    227:         *      We must ignore "." and "..", but other than that,
                    228:         *      just create a path name and call self to check it out.
                    229:         */
                    230:        while (dirp = readdir(fd)) {
                    231:                if (dirp->d_ino != 0
                    232:                    && strcmp (dirp->d_name, ".") != 0
                    233:                    && strcmp (dirp->d_name, "..") != 0) {
                    234:                        int i;
                    235:                        struct FTW_rec *pr;
                    236: 
                    237:                        /* Append the component name to the working path */
                    238:                        strcpy(component, dirp->d_name);
                    239:                        T->pathnext = n + strlen(dirp->d_name);
                    240: 
                    241:                        /*
                    242:                         *      If we are about to exceed our depth,
                    243:                         *      remember where we are and close the file.
                    244:                         */
                    245:                        if (level - T->lastout >= T->depth) {
                    246:                                pr = &mr;
                    247:                                i = T->lastout++;
                    248:                                while (++i < level) pr = pr->prev;
                    249:                                pr->here = telldir(pr->fd);
                    250:                                closedir(pr->fd);
                    251:                        }
                    252: 
                    253:                        /*
                    254:                         *      Do a recursive call to process the file.
                    255:                         */
                    256:                        S.quit = 0;
                    257:                        S.base = n;
                    258:                        rc = ftw_1_(&mr, T, level+1, &S);
                    259:                        if (rc != 0 || S.quit == FTW_SKR) {
                    260:                                if (level > T->lastout) closedir(fd);
                    261:                                T->pathnext = nextsave;
                    262:                                return rc;
                    263:                        }
                    264: 
                    265:                        /*
                    266:                         *      If we closed the file, try to reopen it.
                    267:                         */
                    268:                        if (level <= T->lastout) {
                    269:                                char c = path[nextsave];
                    270:                                path[nextsave] = 0;
                    271:                                T->lastout = level - 1;
                    272:                                mr.fd = fd = opendir(path);
                    273:                                if (!fd) {
                    274:                                        rc = (*T->fn) (path, &sb, FTW_DNR, &S);
                    275:                                        S1->quit = S.quit;
                    276:                                        T->pathnext = nextsave;
                    277:                                        return rc;
                    278:                                        }
                    279:                                path[nextsave] = c;
                    280:                                seekdir(fd, mr.here);
                    281:                                }
                    282:                        }
                    283:                }
                    284:        T->pathnext = nextsave;
                    285:        path[nextsave] = 0;
                    286: 
                    287:        /*
                    288:         *      We got out of the subdirectory loop.  Call the user
                    289:         *      function again at the end and clean up.
                    290:         */
                    291: 
                    292:        rc = (*T->fn) (path, &sb, FTW_DP, &S);
                    293:        S1->quit = S.quit;
                    294: rtrn:
                    295:        closedir(fd);
                    296:        return rc;
                    297: }
                    298: 
                    299: #define BLKSIZE BUFSIZ
                    300: #define        BSIZE(n)        BUFSIZ
                    301: char zero[BLKSIZE];    /* keep as zero */
                    302: int zflag;
                    303: 
                    304: /* destination path-name buffer initial value, increment */
                    305: #define PATHLEN0 1000
                    306: #define PATHINC 1000
                    307: #define IHTABLEN 287
                    308: #define SBUFLEN 1000
                    309: 
                    310: /* Non-zero if stat buffer b refers to a directory, zero otherwise */
                    311: #define isdir(b) (((b).st_mode & S_IFMT) == S_IFDIR)
                    312: 
                    313: char *malloc(), *realloc(), *strcpy(), *strcat();
                    314: int copy();
                    315: 
                    316: char symbuf[SBUFLEN];  /* Buffer for symbolic link names */
                    317: int firstyell = 1;
                    318: int destlen;           /* length of destination (last arg) */
                    319: int iamsu;
                    320: char *dest;
                    321: char *destdir;         /* Storage for output pathname -- handled like
                    322:                         * the source pathname in ftw, subject to being
                    323:                         * relocated by realloc.
                    324:                         */
                    325: unsigned dlast, dnext; /* Offsets of next available, last+1 chars of
                    326:                         * output pathname.
                    327:                         */
                    328: 
                    329: /* Final component of the path name by which we were invoked */
                    330: char *pgmname;
                    331: 
                    332: struct inodetab {      /* for keeping track of links */
                    333:        struct inodetab *nextint;
                    334:        ino_t i_ino;
                    335:        dev_t i_dev;
                    336:        char iname[1];
                    337:        };
                    338: 
                    339: struct inodetab *ihtab[IHTABLEN]; /* hash table for remembering links */
                    340: 
                    341: int retcode;
                    342: 
                    343: main(argc, argv)
                    344: int argc;
                    345: char **argv;
                    346: {
                    347:        char *p, *q;
                    348:        struct stat *argbufs, destbuf, statbuf, rootbuf;
                    349:        int i;
                    350: 
                    351:        umask(0);
                    352:        pgmname = argv[0];
                    353: 
                    354:        if (argc > 1 && !strcmp(argv[1],"-z")) {
                    355:                zflag = 1;
                    356:                --argc;
                    357:                ++argv;
                    358:                }
                    359: 
                    360:        /*
                    361:         *      Start validity checking
                    362:         */
                    363: 
                    364:        /* Check for too few arguments given */
                    365:        if (argc < 3) {
                    366:                fprintf(stderr,
                    367:                        "usage:  %s [-z] f1 f2  or  %s [-z] f1 ... fn d\n",
                    368:                                pgmname, pgmname);
                    369:                return 1;
                    370:        }
                    371: 
                    372:        /*
                    373:         *      If the last argument is a non-directory, we require
                    374:         *      argc == 3 (in the case of: cp f1 f2)
                    375:         */
                    376:        dest = argv[argc-1];
                    377:        destbuf.st_mode = 0;    /* Force isdir(destbuf) false */
                    378:        if ((stat (dest, &destbuf) < 0 || !isdir(destbuf)) && argc != 3) {
                    379:                scream ("%s not a directory", dest);
                    380:                return 1;
                    381:        }
                    382: 
                    383:        /*
                    384:         *      Allocate storage for a stat buffer for each argument
                    385:         *      but the last. This will be used to check for trying to
                    386:         *      copy something into a subdirectory of itself.
                    387:         */
                    388:        argbufs = (struct stat *)
                    389:                malloc ((unsigned) (sizeof (struct stat) * (argc-2)));
                    390:        if (argbufs == NULL) {
                    391:                scream ("insufficient storage", "");
                    392:                return 1;
                    393:        }
                    394:        iamsu = (getuid() == 0);
                    395: 
                    396:        for (i = 0; i < argc-2; i++) {
                    397:                if (lstat (argv[i+1], &argbufs[i]) < 0) {
                    398:                        scream ("cannot access %s", argv[i+1]);
                    399:                        return 1;
                    400:                }
                    401:        }
                    402:        
                    403:        /*
                    404:         *      Now run back from the destination to the root directory,
                    405:         *      checking along the way for any matches with anything in
                    406:         *      the argbufs array. If we find any, we tried a forbidden
                    407:         *      operation. If the destination is not already a directory,
                    408:         *      we must start from its parent. Note that even in this case,
                    409:         *      we can't elide the test, because otherwise we wouldn't get
                    410:         *
                    411:         *              cp . x
                    412:         *
                    413:         *      This code also handles pathological but legal destinations
                    414:         *      properly; in particular note that the null string is a
                    415:         *      valid name for the current directory. Sigh.
                    416:         *
                    417:         *      First figure out the name of the directory to check.
                    418:         */
                    419:        dnext = destlen = strlen(dest);
                    420:        dlast = destlen + 2;
                    421:        if (dlast < PATHLEN0) dlast = PATHLEN0;
                    422:        destdir = malloc(dlast);
                    423:        if (!destdir) { scream ("no storage", ""); return 1; }
                    424:        strcpy (destdir, dest);
                    425:        if (!isdir (destbuf)) {
                    426:                p = q = destdir;
                    427:                while (*q) {
                    428:                        if (*q++ == '/')
                    429:                                p = q - 1;
                    430:                }
                    431:                if (p == destdir) {
                    432:                        strcpy (destdir, ".");
                    433:                        dnext = 1;
                    434:                        }
                    435:                else {
                    436:                        *p = '\0';
                    437:                        dnext = p - destdir;
                    438:                        }
                    439:        }
                    440: 
                    441:        /* Now stat the root directory for later use */
                    442:        if (stat ("/", &rootbuf) < 0) {
                    443:                scream ("cannot access root directory", "");
                    444:                return 1;
                    445:        }
                    446: 
                    447:        /* Now run back from destdir to the root, checking against argbufs */
                    448:        do {
                    449:                if (stat (destdir, &statbuf) < 0) {
                    450:                        scream ("cannot stat %s", destdir);
                    451:                        return 1;
                    452:                }
                    453:                for (i = 0; i < argc-2; i++)
                    454:                        if (argbufs[i].st_dev == statbuf.st_dev
                    455:                         && argbufs[i].st_ino == statbuf.st_ino) {
                    456:                                fprintf (stderr, "%s: %s contains %s\n",
                    457:                                        pgmname, argv[i+1], dest);
                    458:                                return 1;
                    459:                        }
                    460:                dcheck(3, "initial arg checking");
                    461:                strcpy(destdir+dnext, "/..");
                    462:                dnext += 3;
                    463:        } while (statbuf.st_dev != rootbuf.st_dev
                    464:              || statbuf.st_ino != rootbuf.st_ino);
                    465: 
                    466:        /*
                    467:         *      End of validity checking
                    468:         */
                    469: 
                    470:        strcpy(destdir, dest);
                    471:        for (i = 0; i < IHTABLEN; i++) ihtab[i] = 0;
                    472:        if (isdir(destbuf)) {
                    473:                destdir[destlen] = '/';
                    474:                dnext = destlen + 1;
                    475:                for (i = 1; i < argc-1; i++) {
                    476: 
                    477:                        char *p, *q;
                    478: 
                    479:                        p = q = argv[i];
                    480:                        while (*p)
                    481:                                if (*p++ == '/')
                    482:                                        q = p;
                    483:                        dnext = destlen + (p - q) + 1;
                    484: 
                    485:                        p = destdir + destlen;
                    486:                        *p = '/';
                    487:                        strcpy(p+1, q);
                    488:                        retcode |= ftw(argv[i], copy, 12);
                    489:                        }
                    490:                }
                    491: 
                    492:        else {
                    493:                dnext = destlen;
                    494:                retcode = ftw(argv[1], copy, 12);
                    495:                }
                    496: 
                    497:        return retcode;
                    498: }
                    499: 
                    500: int
                    501: copy(source, srcbuf, code, S)
                    502:        char *source;
                    503:        struct stat *srcbuf;
                    504:        int code;
                    505:        struct FTW *S;
                    506: {
                    507:        char *s;
                    508:        int rc, slen;
                    509: 
                    510:        switch(code) {
                    511: 
                    512:                case FTW_F:             /* nondirectory */
                    513: 
                    514:                        dcheck(MAXNAMLEN+1,source);
                    515:                        if (S->level)
                    516:                                strcpy(destdir + dnext, source + S->base);
                    517:                        return copy1(source, srcbuf, destdir);
                    518: 
                    519:                case FTW_D:             /* new directory */
                    520:        
                    521:                        dcheck(MAXNAMLEN+1,source);
                    522:                        S->obase = dnext;
                    523:                        s = destdir+dnext;
                    524:                        if (S->level) {
                    525:                                for (source += S->base; *s = *source;)
                    526:                                        { s++, source++; }
                    527:                                }
                    528:                        dnext = s - destdir;
                    529:                        if (mkdir(destdir,0700)) {
                    530:                                scream("can't mkdir %s", destdir);
                    531:                                return 1;
                    532:                                }
                    533:                        *s++ = '/'; *s = 0;
                    534:                        ++dnext;
                    535:                        return 0;
                    536: 
                    537:                case FTW_DNR:           /* unreadable directory */
                    538: 
                    539:                        scream("can't read %s", source);
                    540:                        return 1;
                    541: 
                    542:                case FTW_NS:            /* unstatable file */
                    543: 
                    544:                        scream("can't stat %s", source);
                    545:                        return 1;
                    546: 
                    547:                case FTW_DP:            /* end of directory */
                    548: 
                    549:                        destdir[dnext-1] = 0;
                    550:                        dnext = S->obase;
                    551:                        if (chmod(destdir, (int)srcbuf->st_mode))
                    552:                                scream("can't chmod %s", destdir);
                    553:                        if(iamsu && chown(destdir, srcbuf->st_uid,
                    554:                                        srcbuf->st_gid))
                    555:                                scream("can't chown %s", destdir);
                    556:                        return settime(srcbuf, destdir);
                    557: 
                    558: #ifdef S_IFLNK
                    559:                case FTW_SL:            /* symbolic link */
                    560: 
                    561:                        slen = readlink(source, symbuf, SBUFLEN);
                    562:                        if (slen >= SBUFLEN) {
                    563:                                scream("Symbolic path to %s too long.",
                    564:                                        source);
                    565:                                return 1;
                    566:                                }
                    567:                        dcheck(MAXNAMLEN+1,source);
                    568:                        symbuf[slen] = 0;
                    569:                        if (S->level) strcpy(destdir + dnext,
                    570:                                                source + S->base);
                    571:                        rc = 0;
                    572:                        umask(~(int)srcbuf->st_mode);
                    573:                        if (symlink(symbuf,destdir)) {
                    574:                                fprintf(stderr,
                    575:                                    "%s: can't symbolically link %s to %s\n",
                    576:                                        pgmname, destdir, symbuf);
                    577:                                rc = 1;
                    578:                                }
                    579:                        umask(0);
                    580:                        return rc;
                    581: #endif
                    582: 
                    583:                default:                /* bug */
                    584:                        fprintf(stderr,"%s: unknown code = %d from ftw\n",
                    585:                                pgmname, code);
                    586:                        exit(1);
                    587:                }
                    588:        }
                    589: 
                    590: /*
                    591:  *     Copy a file. The source file name is in "source",
                    592:  *     and the destination file name is in "dest". "srcbuf" points to
                    593:  *     a stat buffer for the source.
                    594:  */
                    595: 
                    596: int
                    597: copy1(source, srcbuf, dest)
                    598:        char *source, *dest;
                    599:        struct stat *srcbuf;
                    600: {
                    601:        int bsize, inf, outf, n, type, zsize;
                    602:        char buffer[BLKSIZE];
                    603:        struct stat destbuf;
                    604:        long lseek();
                    605: 
                    606:        if (stat (dest, &destbuf) >= 0
                    607:         && srcbuf->st_dev == destbuf.st_dev
                    608:         && srcbuf->st_ino == destbuf.st_ino) {
                    609:                scream ("cannot copy %s to itself", source);
                    610:                return 1;
                    611:                }
                    612: 
                    613:        switch(type = srcbuf->st_mode & S_IFMT) {
                    614: 
                    615:                case S_IFCHR:   /* character special */
                    616:                case S_IFBLK:   /* block special */
                    617:                        if (!iamsu) {
                    618:                                scream("can't copy special file %s", source);
                    619:                                return 1;
                    620:                                }
                    621:                        if (n = linkchk(srcbuf,destdir)) return n-1;
                    622:                        if (mknod(destdir, (int) srcbuf->st_mode,
                    623:                                           (int) srcbuf->st_rdev)) {
                    624:                                scream("can't create %s", destdir);
                    625:                                return 1;
                    626:                                }
                    627:                        goto finish;
                    628: 
                    629:                case S_IFREG:   /* regular file */
                    630:                        if (n = linkchk(srcbuf,destdir)) return n-1;
                    631:                        break;
                    632: 
                    633:                default:
                    634:                        fprintf(stderr,
                    635:                                "%s: unknown file type 0x%x for %s\n",
                    636:                                pgmname, type, source);
                    637:                        return 1;
                    638:                }
                    639: 
                    640:        /* Now copy the file, whether or not there was a link */
                    641: 
                    642:        if ((outf = creat (dest, (int) (srcbuf->st_mode & 0777))) < 0) {
                    643:                scream ("cannot create %s", dest);
                    644:                return 1;
                    645:        }
                    646:        if ((inf = open (source, 0)) < 0) {
                    647:                scream ("cannot open %s", source);
                    648:                close(outf);
                    649:                return 1;
                    650:        }
                    651:        if (zflag) {
                    652:                fstat(outf, &destbuf);
                    653:                bsize = BSIZE(destbuf.st_dev);
                    654:                if (bsize > BLKSIZE) {
                    655:                        fprintf(stderr, "%s: BSIZE(%s) > %d\n", pgmname,
                    656:                                dest, BLKSIZE);
                    657:                        return 1;
                    658:                        }
                    659:                }
                    660:        else bsize = BLKSIZE;
                    661:        zsize = 0;
                    662:        while ((n = read (inf, buffer, bsize)) > 0) {
                    663:                if (zflag && (n == bsize) && !memcmp(buffer, zero, bsize)) {
                    664:                        if (lseek(outf, (long)bsize, 1) < 0) {
                    665:                                scream("lseek (for block of 0's) failed on %s",
                    666:                                        dest);
                    667:                                goto endit;
                    668:                                }
                    669:                        zsize = bsize;
                    670:                        }
                    671:                else if (write (outf, buffer, n) != n) {
                    672:                        scream ("output error on %s", dest);
                    673: endit:
                    674:                        close (inf);
                    675:                        close (outf);
                    676:                        return 1;
                    677:                }
                    678:                else zsize = 0;
                    679:        }
                    680:        if (n < 0) {
                    681:                scream ("input error on %s", source);
                    682:                goto endit;
                    683:        }
                    684:        if (zsize && (lseek(outf, (long)-zsize, 1) < 0
                    685:                || write(outf,zero,zsize) != zsize)) {
                    686:                        scream("error writing trailing 0's from %s", source);
                    687:                        goto endit;
                    688:                        }
                    689:        if (close (outf) < 0) {
                    690:                scream ("cannot close %s", dest);
                    691:                close (inf);
                    692:                return 1;
                    693:        }
                    694:        if (close (inf) < 0) {
                    695:                scream ("cannot close %s", source);
                    696:                return 1;
                    697:        }
                    698: 
                    699:  finish:
                    700:        if(iamsu && chown(dest, srcbuf->st_uid, srcbuf->st_gid)) {
                    701:                scream("can't chown %s", dest);
                    702:                return 1;
                    703:                }
                    704:        return settime(srcbuf, dest);
                    705: }
                    706: 
                    707: scream (s1, s2)
                    708:        char *s1, *s2;
                    709: {
                    710:        fprintf (stderr, "%s: ", pgmname);
                    711:        fprintf (stderr, s1, s2);
                    712:        putc ('\n', stderr);
                    713:        retcode |= 1;
                    714: }
                    715: 
                    716: dcheck(len, source)
                    717: int len;
                    718: char *source;
                    719: {
                    720:        int dnext1 = dnext + len;
                    721:        if (dnext1 >= dlast) {
                    722:                dlast += PATHINC;
                    723:                destdir = realloc(destdir, dlast);
                    724:                if (!destdir) {
                    725:                        scream("malloc failed on %s",source);
                    726:                        exit(1);
                    727:                        }
                    728:                }
                    729: }
                    730: 
                    731: int
                    732: linkchk(sb,d)
                    733: struct stat *sb;
                    734: char *d;
                    735: {
                    736:        register struct inodetab *p, *p0;
                    737:        struct stat buf;
                    738: 
                    739:        if (sb->st_nlink < 2) return 0;
                    740:   
                    741:        p0 = (struct inodetab *)
                    742:                (((sb->st_dev + sb->st_ino) % IHTABLEN) + ihtab);
                    743:        while ((p = p0->nextint) &&
                    744:                (p->i_ino != sb->st_ino || p->i_dev != sb->st_dev)) p0 = p;
                    745: 
                    746:        if (p) {/* If this is a link to a file already seen... */
                    747:                if (link(p->iname, d)) {
                    748: 
                    749:                        /* unlink d and try again, unless d is a directory */
                    750: 
                    751:                        if (lstat(d,&buf)
                    752:                                        || (buf.st_mode & S_IFMT) == S_IFDIR
                    753:                                        || unlink(d)
                    754:                                        || link(p->iname,d)) {
                    755:                                fprintf(stderr,"%s: can't link %s to %s\n",
                    756:                                        pgmname, p->iname, d);
                    757:                                return 2;
                    758:                                }
                    759:                        }
                    760:                return 1;
                    761:                }
                    762: 
                    763:        /* This file has more than one link to it -- add it to the list */
                    764:        /* of files that may be seen later. */
                    765: 
                    766:        p = (struct inodetab *)
                    767:                malloc((unsigned) (sizeof(struct inodetab) + strlen(d)));
                    768:        if (!p) {
                    769:                if (firstyell) {
                    770:                        firstyell = 0;
                    771:                        scream("storage for links exhausted with %s", d);
                    772:                        }
                    773:                return 0;
                    774:                }
                    775: 
                    776:        p0->nextint = p;
                    777:        p->nextint = 0;
                    778:        p->i_ino = sb->st_ino;
                    779:        p->i_dev = sb->st_dev;
                    780:        strcpy(p->iname, d);
                    781:        return 0;
                    782:        }
                    783: 
                    784: settime(srcbuf, dest)          /* set time and mode of dest */
                    785:        struct stat *srcbuf;
                    786:        char *dest;
                    787:        {
                    788:        time_t utimbuf[2];
                    789:        int m, rc = 0;
                    790: 
                    791:        utimbuf[0] = srcbuf->st_atime;
                    792:        utimbuf[1] = srcbuf->st_mtime;
                    793:        utime (dest, utimbuf);
                    794: 
                    795:        m = srcbuf->st_mode;
                    796: #ifdef S_ISVTX
                    797:        if (m & S_ISVTX && !iamsu) {
                    798:                scream("can't set save-text bit of %s", dest);
                    799:                m &= ~S_ISVTX;
                    800:                }
                    801:        if ((m & (S_ISUID | S_ISGID | S_ISVTX)) && (rc = chmod(dest,m)))
                    802: #else
                    803:        if ((m & (S_ISUID | S_ISGID)) && (rc = chmod(dest,m)))
                    804: #endif
                    805:                scream("can't set mode of %s", dest);
                    806:        return rc;
                    807:        }

unix.superglobalmegacorp.com

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