Annotation of researchv9/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:  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.