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

unix.superglobalmegacorp.com

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