Annotation of researchv10no/cmd/reccp.c, revision 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.