Annotation of researchv8dc/cmd/rcp.c, revision 1.1

1.1     ! root        1: 
        !             2: /*
        !             3:  *     cp source dest
        !             4:  *
        !             5:  *          or
        !             6:  *
        !             7:  *     cp source1 ... sourcen dest
        !             8:  *
        !             9:  *     In the first case, dest must not be a directory (else we have a
        !            10:  *     degenerate version of the second case). In the second case,
        !            11:  *     dest must be a directory; the resulting objects will be
        !            12:  *     named dest/source1 ... dest/sourcen.
        !            13:  *
        !            14:  *     If any source is a directory, the tree structure under it
        !            15:  *     will be (recursively) copied; this process will attempt to
        !            16:  *     preserve any links that exist within the hierarchy.
        !            17:  */
        !            18: 
        !            19: #include <stdio.h>
        !            20: #include <sys/types.h>
        !            21: #include <sys/stat.h>
        !            22: #include <sys/dir.h>
        !            23: 
        !            24: #define BLKSIZE BUFSIZ
        !            25: 
        !            26: /* Maximum file tree nesting before we start closing and re-opening */
        !            27: #define MAXLEVEL 8
        !            28: 
        !            29: /* Non-zero if stat buffer b refers to a directory, zero otherwise */
        !            30: #define isdir(b) (((b).st_mode & S_IFMT) == S_IFDIR)
        !            31: 
        !            32: char *malloc(), *realloc(), *strcpy(), *strcat();
        !            33: int iamsu;
        !            34: 
        !            35: /* Final component of the path name by which we were invoked */
        !            36: char *pgmname;
        !            37: 
        !            38: main (argc, argv)
        !            39:        int argc;
        !            40:        char **argv;
        !            41: {
        !            42:        int retcode;
        !            43:        char *dest, *destdir, *p, *q;
        !            44:        struct stat *argbufs, destbuf, statbuf, rootbuf;
        !            45:        int i;
        !            46: 
        !            47:        umask(0);
        !            48:        pgmname = argv[0];
        !            49: 
        !            50:        /*
        !            51:         *      Start validity checking
        !            52:         */
        !            53: 
        !            54:        /* Check for too few arguments given */
        !            55:        if (argc < 3) {
        !            56:                fprintf (stderr, "usage:  %s f1 f2  or  %s f1 ... fn d\n",
        !            57:                                pgmname, pgmname);
        !            58:                return 1;
        !            59:        }
        !            60: 
        !            61:        /*
        !            62:         *      If the last argument is a non-directory, we require
        !            63:         *      argc == 3 (in the case of: cp f1 f2)
        !            64:         */
        !            65:        dest = argv[argc-1];
        !            66:        destbuf.st_mode = 0;    /* Force isdir(destbuf) false */
        !            67:        if ((stat (dest, &destbuf) < 0 || !isdir(destbuf)) && argc != 3) {
        !            68:                scream ("%s not a directory", dest);
        !            69:                return 1;
        !            70:        }
        !            71: 
        !            72:        /*
        !            73:         *      Allocate storage for a stat buffer for each argument
        !            74:         *      but the last. This will be used to check for trying to
        !            75:         *      copy something into a subdirectory of itself.
        !            76:         */
        !            77:        argbufs = (struct stat *)
        !            78:                malloc ((unsigned) (sizeof (struct stat) * (argc-2)));
        !            79:        if (argbufs == NULL) {
        !            80:                scream ("insufficient storage", "");
        !            81:                return 1;
        !            82:        }
        !            83:        iamsu = (getuid() == 0);
        !            84: 
        !            85:        for (i = 0; i < argc-2; i++) {
        !            86:                if (stat (argv[i+1], &argbufs[i]) < 0) {
        !            87:                        scream ("cannot access %s", argv[i+1]);
        !            88:                        return 1;
        !            89:                }
        !            90:        }
        !            91:        
        !            92:        /*
        !            93:         *      Now run back from the destination to the root directory,
        !            94:         *      checking along the way for any matches with anything in
        !            95:         *      the argbufs array. If we find any, we tried a forbidden
        !            96:         *      operation. If the destination is not already a directory,
        !            97:         *      we must start from its parent. Note that even in this case,
        !            98:         *      we can't elide the test, because otherwise we wouldn't get
        !            99:         *
        !           100:         *              cp . x
        !           101:         *
        !           102:         *      This code also handles pathological but legal destinations
        !           103:         *      properly; in particular note that the null string is a
        !           104:         *      valid name for the current directory. Sigh.
        !           105:         *
        !           106:         *      First figure out the name of the directory to check.
        !           107:         */
        !           108:        destdir = malloc ((unsigned) (strlen (dest) + 2));
        !           109:        if (destdir == NULL) {
        !           110:                scream ("insufficient storage", "");
        !           111:                return 1;
        !           112:        }
        !           113:        strcpy (destdir, dest);
        !           114:        if (!isdir (destbuf)) {
        !           115:                p = q = destdir;
        !           116:                while (*q) {
        !           117:                        if (*q++ == '/')
        !           118:                                p = q - 1;
        !           119:                }
        !           120:                if (p == destdir)
        !           121:                        strcpy (destdir, ".");
        !           122:                else
        !           123:                        *p = '\0';
        !           124:        }
        !           125: 
        !           126:        /* Now stat the root directory for later use */
        !           127:        if (stat ("/", &rootbuf) < 0) {
        !           128:                scream ("cannot access root directory", "");
        !           129:                return 1;
        !           130:        }
        !           131: 
        !           132:        /* Now run back from destdir to the root, checking against argbufs */
        !           133:        do {
        !           134:                if (stat (destdir, &statbuf) < 0) {
        !           135:                        scream ("cannot stat %s", destdir);
        !           136:                        return 1;
        !           137:                }
        !           138:                for (i = 0; i < argc-2; i++)
        !           139:                        if (argbufs[i].st_dev == statbuf.st_dev
        !           140:                         && argbufs[i].st_ino == statbuf.st_ino) {
        !           141:                                fprintf (stderr, "%s: %s contains %s\n",
        !           142:                                        pgmname, argv[i+1], dest);
        !           143:                                return 1;
        !           144:                        }
        !           145:                destdir = realloc (destdir, (unsigned) (strlen(destdir) + 4));
        !           146:                if (destdir == NULL) {
        !           147:                        scream ("insufficient storage", "");
        !           148:                        return 1;
        !           149:                }
        !           150:                strcat (destdir, "/..");
        !           151:        } while (statbuf.st_dev != rootbuf.st_dev
        !           152:              || statbuf.st_ino != rootbuf.st_ino);
        !           153:        free (destdir);
        !           154: 
        !           155:        /*
        !           156:         *      End of validity checking
        !           157:         */
        !           158: 
        !           159:        if (isdir (destbuf)) {
        !           160:                retcode = 0;
        !           161:                for (i=1; i<argc-1; i++) {
        !           162: 
        !           163:                        char *p, *q;
        !           164:                        char *xdest;
        !           165: 
        !           166:                        p = q = argv[i];
        !           167:                        while (*p)
        !           168:                                if (*p++ == '/')
        !           169:                                        q = p;
        !           170:                        xdest = malloc ((unsigned)
        !           171:                                (strlen(dest) + strlen (q) + 2));
        !           172:                        if (xdest != NULL) {
        !           173:                                strcpy (xdest, dest);
        !           174:                                strcat (xdest, "/");
        !           175:                                strcat (xdest, q);
        !           176:                                retcode |= copy (argv[i], &argbufs[i-1], xdest);
        !           177:                                free (xdest);
        !           178:                        } else {
        !           179:                                scream ("no storage", "");
        !           180:                                retcode = 1;
        !           181:                        }
        !           182:                }
        !           183:        } else
        !           184:                retcode = copy (argv[1], &argbufs[0], dest);
        !           185: 
        !           186:        return retcode;
        !           187: }
        !           188: 
        !           189: /*
        !           190:  *     Copy a file or directory. The source file name is in "source",
        !           191:  *     and the destination file name is in "dest". "srcbuf" points to
        !           192:  *     a stat buffer for the source.
        !           193:  */
        !           194: int
        !           195: copy (source, srcbuf, dest)
        !           196:        char *source, *dest;
        !           197:        struct stat *srcbuf;
        !           198: {
        !           199:        int inf, outf, n;
        !           200:        char buffer[BLKSIZE];
        !           201:        struct stat newbuf, destbuf;
        !           202:        static int level = 0;
        !           203:        static short firstyell = 1;
        !           204:        struct {
        !           205:                long actime, modtime;
        !           206:        } utimbuf;
        !           207:        long time();
        !           208:        static struct linknode {
        !           209:                dev_t ln_dev;
        !           210:                ino_t ln_ino;
        !           211:                struct linknode *ln_next;
        !           212:                char *ln_name;          /* variable */
        !           213:        } *ln_head = NULL, *lnp;
        !           214: 
        !           215:        if (isdir (*srcbuf)) {
        !           216:                
        !           217:                char *srcname, *destname;
        !           218:                FILE *dirfile;
        !           219:                struct direct dir;
        !           220:                long dirloc;
        !           221:                int retcode = 0;
        !           222: 
        !           223:                /*
        !           224:                 *      Copy from a directory. This will have to copy the
        !           225:                 *      tree structure recursively. Thus, we will create
        !           226:                 *      a new directory of an appropriate name, then
        !           227:                 *      copy everything in source to elements of dest.
        !           228:                 */
        !           229:                if (stat (dest, &destbuf) < 0) {
        !           230:                        if (mkdir (dest)) {
        !           231:                                scream ("cannot create directory %s", dest);
        !           232:                                return 1;
        !           233:                        }
        !           234:                } else {
        !           235:                        scream ("%s already exists", dest);
        !           236:                        return 1;
        !           237:                }
        !           238: 
        !           239:                if ((dirfile = fopen (source, "r")) == NULL) {
        !           240:                        scream ("cannot open %s", source);
        !           241:                        return 1;
        !           242:                }
        !           243: 
        !           244:                srcname = malloc ((unsigned) (strlen(source) + DIRSIZ + 2));
        !           245:                destname = malloc ((unsigned) (strlen(dest) + DIRSIZ + 2));
        !           246:                if (srcname == NULL || destname == NULL) {
        !           247:                        scream ("insufficient storage", "");
        !           248:                        fclose(dirfile);
        !           249:                        return 1;
        !           250:                }
        !           251: 
        !           252:                while (fread ((char *) & dir, sizeof (struct direct),
        !           253:                        1, dirfile) == 1)
        !           254:                        if (dir.d_ino != 0 &&
        !           255:                            strncmp (dir.d_name, ".", DIRSIZ) &&
        !           256:                            strncmp (dir.d_name, "..", DIRSIZ)) {
        !           257:                                strcpy (srcname, source);
        !           258:                                strcat (srcname, "/");
        !           259:                                strncat (srcname, dir.d_name, DIRSIZ);
        !           260:                                strcpy (destname, dest);
        !           261:                                strcat (destname, "/");
        !           262:                                strncat (destname, dir.d_name, DIRSIZ);
        !           263: 
        !           264:                                if (level > MAXLEVEL) {
        !           265:                                        dirloc = ftell (dirfile);
        !           266:                                        fclose (dirfile);
        !           267:                                        dirfile = NULL;
        !           268:                                }
        !           269: 
        !           270:                                if (lstat (srcname, &newbuf) < 0) {
        !           271:                                        scream ("cannot stat %s", srcname);
        !           272:                                        if(dirfile != NULL)
        !           273:                                                fclose(dirfile);
        !           274:                                        return 1;
        !           275:                                }
        !           276: 
        !           277:                                level++;
        !           278:                                retcode |= copy (srcname, &newbuf, destname);
        !           279:                                level--;
        !           280: 
        !           281:                                if (level > MAXLEVEL) {
        !           282:                                        if ((dirfile = fopen (source, "r"))
        !           283:                                            == NULL) {
        !           284:                                                scream ("cannot reopen %s",
        !           285:                                                    source);
        !           286:                                                return 1;
        !           287:                                        }
        !           288:                                        if(fseek(dirfile, dirloc, 0) == EOF) {
        !           289:                                                scream("can't seek on %s",
        !           290:                                                        source);
        !           291:                                                fclose(dirfile);
        !           292:                                                return(1);
        !           293:                                        }
        !           294:                                }
        !           295:                }
        !           296: 
        !           297:                free (srcname);
        !           298:                free (destname);
        !           299:                if(iamsu)
        !           300:                        chown(dest, srcbuf->st_uid, srcbuf->st_gid);
        !           301: 
        !           302:                utimbuf.actime = time ((long *) NULL);
        !           303:                utimbuf.modtime = srcbuf->st_mtime;
        !           304:                utime (dest, &utimbuf);
        !           305: 
        !           306:                if (chmod (dest, srcbuf->st_mode & 07777) < 0) {
        !           307:                        scream ("cannot chmod for %s", dest);
        !           308:                        retcode = 1;
        !           309:                }
        !           310:                fclose(dirfile);
        !           311:                return retcode;
        !           312:        }
        !           313: 
        !           314:        /*
        !           315:         *      Here when src is not a directory
        !           316:         */
        !           317:        if (stat (dest, &destbuf) >= 0
        !           318:         && srcbuf->st_dev == destbuf.st_dev
        !           319:         && srcbuf->st_ino == destbuf.st_ino) {
        !           320:                scream ("cannot copy %s to itself", source);
        !           321:                return 1;
        !           322:        }
        !           323: 
        !           324:        /*
        !           325:         *      Check if the source (which is known to be a file) has
        !           326:         *      more than one link. If not, all is easy. If so, we may
        !           327:         *      be able to create a link rather than copying the source.
        !           328:         */
        !           329:        if (srcbuf->st_nlink > 1) {
        !           330: 
        !           331:                /* Hunt through the table of linked items for a match */
        !           332:                lnp = ln_head;
        !           333:                while (lnp != NULL &&
        !           334:                   (lnp->ln_dev != srcbuf->st_dev
        !           335:                   ||  lnp->ln_ino != srcbuf->st_ino)) {
        !           336:                        lnp = lnp->ln_next;
        !           337:                }
        !           338: 
        !           339:                /* If match found, try a link */
        !           340:                if (lnp != NULL)
        !           341:                        if (link (lnp->ln_name, dest)) {
        !           342:                                scream ("cannot create %s link", dest);
        !           343:                                return 1;
        !           344:                        } else
        !           345:                                return 0;
        !           346: 
        !           347:                /* No match found -- build a table entry */
        !           348:                lnp = (struct linknode *) malloc (sizeof (struct linknode));
        !           349: 
        !           350:                if (lnp == NULL) {
        !           351:                        if (firstyell) {
        !           352:                                scream ("link table too large", "");
        !           353:                                firstyell = 0;
        !           354:                        }
        !           355:                } else if ((lnp->ln_name = malloc ((unsigned) (strlen(dest)+1)))
        !           356:                            == NULL) {
        !           357:                        if (firstyell) {
        !           358:                                scream ("link names too large", "");
        !           359:                                firstyell = 0;
        !           360:                        }
        !           361:                        free ((char *) lnp);
        !           362:                } else {
        !           363:                        lnp->ln_dev = srcbuf->st_dev;
        !           364:                        lnp->ln_ino = srcbuf->st_ino;
        !           365:                        strcpy (lnp->ln_name, dest);
        !           366:                        lnp->ln_next = ln_head;
        !           367:                        ln_head = lnp;
        !           368:                }
        !           369:        }
        !           370: 
        !           371:        /* Now copy the file, whether or not there was a link */
        !           372:        switch(srcbuf->st_mode & S_IFMT){
        !           373:        case S_IFLNK:{
        !           374:                int len;
        !           375:                char buf[1024];
        !           376:                len = readlink(source, buf, sizeof buf);
        !           377:                if(len<=0){
        !           378:                        scream("can't read link for %s", source);
        !           379:                        return 1;
        !           380:                }
        !           381:                if(symlink(buf, dest)!=0){
        !           382:                        scream("can't write link for %s", dest);
        !           383:                        return 1;
        !           384:                }
        !           385:                break;
        !           386:        }
        !           387:        case S_IFCHR:
        !           388:        case S_IFBLK:
        !           389:                if(mknod(dest, srcbuf->st_mode, srcbuf->st_rdev)!=0){
        !           390:                        scream("can't mknod %s", dest);
        !           391:                        return 1;
        !           392:                }
        !           393:                break;
        !           394:        default:
        !           395:                if ((outf = creat (dest, srcbuf->st_mode & 07777)) < 0) {
        !           396:                        scream ("cannot create %s", dest);
        !           397:                        return 1;
        !           398:                }
        !           399:                if ((inf = open (source, 0)) < 0) {
        !           400:                        scream ("cannot open %s", source);
        !           401:                        close(outf);
        !           402:                        return 1;
        !           403:                }
        !           404:                while ((n = read (inf, buffer, BLKSIZE)) > 0) {
        !           405:                        if (write (outf, buffer, n) != n) {
        !           406:                                scream ("output error on %s", dest);
        !           407:                                close (inf);
        !           408:                                close (outf);
        !           409:                                return 1;
        !           410:                        }
        !           411:                }
        !           412:                if (n < 0) {
        !           413:                        scream ("input error on %s", source);
        !           414:                        close (inf);
        !           415:                        close (outf);
        !           416:                        return 1;
        !           417:                }
        !           418:                if (close (outf) < 0) {
        !           419:                        scream ("cannot close %s", dest);
        !           420:                        close (inf);
        !           421:                        return 1;
        !           422:                }
        !           423:                if (close (inf) < 0) {
        !           424:                        scream ("cannot close %s", source);
        !           425:                        return 1;
        !           426:                }
        !           427:                break;
        !           428:        }
        !           429:        utimbuf.actime = srcbuf->st_atime;
        !           430:        utimbuf.modtime = srcbuf->st_mtime;
        !           431:        utime (dest, &utimbuf);
        !           432:        if(iamsu)
        !           433:                chown(dest, srcbuf->st_uid, srcbuf->st_gid);
        !           434:        return 0;
        !           435: }
        !           436: 
        !           437: int
        !           438: mkdir(d)
        !           439:        char *d;
        !           440: {
        !           441:        int status, pid, w;
        !           442:        /*w = open(".", 0);
        !           443:        printf("%d\t%s\n", w, d);
        !           444:        close(w);*/
        !           445:        switch (pid=fork()) {
        !           446:        case 0:
        !           447:                execl ("/bin/mkdir", "mkdir", d, 0);
        !           448:                /* No break */
        !           449:        case -1:
        !           450:                return 1;
        !           451: 
        !           452:        default:
        !           453:                do w = wait (&status);
        !           454:                while (w != pid && w > 0);
        !           455:                if (w == pid)
        !           456:                        return status;
        !           457:                return w;
        !           458:        }
        !           459: }
        !           460: 
        !           461: scream (s1, s2)
        !           462:        char *s1, *s2;
        !           463: {
        !           464:        fprintf (stderr, "%s: ", pgmname);
        !           465:        fprintf (stderr, s1, s2);
        !           466:        putc ('\n', stderr);
        !           467: }

unix.superglobalmegacorp.com

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