Annotation of researchv8dc/cmd/rcp.c, revision 1.1.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.