Пример #1
0
int copy(const char *src, const char *dst, struct stat *srcst,
			struct stat *dstst)
/* Copy one file to another and copy (some of) the attributes. */
{
    char buf[CHUNK];
    int srcfd, dstfd;
    ssize_t n;

    assert(srcst->st_ino != 0);

    if (dstst->st_ino == 0) {
	/* The file doesn't exist yet. */

	if (!S_ISREG(srcst->st_mode)) {
	    /* Making a new mode 666 regular file. */
	    srcst->st_mode= (S_IFREG | 0666) & fc_mask;
	} else
	if (!pflag && conforming) {
	    /* Making a new file copying mode with umask applied. */
	    srcst->st_mode &= fc_mask;
	}
    } else {
	/* File exists, ask if ok to overwrite if '-i'. */

	if (iflag || (action == MOVE && !fflag && !writable(dstst))) {
	    fprintf(stderr, "Overwrite %s? (mode = %03o) ",
			dst, dstst->st_mode & 07777);
	    if (!affirmative()) return 0;
	}

	if (action == MOVE) {
	    /* Don't overwrite, remove first. */
	    if (unlink(dst) < 0 && errno != ENOENT) {
		report(dst);
		return 0;
	    }
	} else {
	    /* Overwrite. */
	    if (!pflag) {
		/* Keep the existing mode and ownership. */
		srcst->st_mode= dstst->st_mode;
		srcst->st_uid= dstst->st_uid;
		srcst->st_gid= dstst->st_gid;
	    }
	}
    }

    /* Keep the link structure if possible. */
    if (trylink(src, dst, srcst, dstst)) return 1;

    if ((srcfd= open(src, O_RDONLY)) < 0) {
	report(src);
	return 0;
    }

    dstfd= open(dst, O_WRONLY|O_CREAT|O_TRUNC, srcst->st_mode & 0777);
    if (dstfd < 0 && fflag && errno == EACCES) {
	/* Retry adding a "w" bit. */
	(void) chmod(dst, dstst->st_mode | S_IWUSR);
	dstfd= open(dst, O_WRONLY|O_CREAT|O_TRUNC, 0);
    }
    if (dstfd < 0 && fflag && errno == EACCES) {
	/* Retry after trying to delete. */
	(void) unlink(dst);
	dstfd= open(dst, O_WRONLY|O_CREAT|O_TRUNC, 0);
    }
    if (dstfd < 0) {
	report(dst);
	close(srcfd);
	return 0;
    }

    /* Get current parameters. */
    if (fstat(dstfd, dstst) < 0) {
	report(dst);
	close(srcfd);
	close(dstfd);
	return 0;
    }

    /* Copy the little bytes themselves. */
    while ((n= read(srcfd, buf, sizeof(buf))) > 0) {
	char *bp = buf;
	ssize_t r;

	while (n > 0 && (r= write(dstfd, bp, n)) > 0) {
	    bp += r;
	    n -= r;
	}
	if (r <= 0) {
	    if (r == 0) {
		fprintf(stderr,
		    "%s: Warning: EOF writing to %s\n",
		    prog_name, dst);
		break;
	    }
	    fatal(dst);
	}
    }

    if (n < 0) {
	report(src);
	close(srcfd);
	close(dstfd);
	return 0;
    }

    close(srcfd);
    close(dstfd);

    /* Copy the ownership. */
    if ((pflag || !conforming)
	&& S_ISREG(dstst->st_mode)
	&& (dstst->st_uid != srcst->st_uid
		|| dstst->st_gid != srcst->st_gid)
    ) {
	if (chmod(dst, 0) == 0) dstst->st_mode&= ~07777;
	if (chown(dst, srcst->st_uid, srcst->st_gid) < 0) {
	    if (errno != EPERM) {
		report(dst);
		return 0;
	    }
	} else {
	    dstst->st_uid= srcst->st_uid;
	    dstst->st_gid= srcst->st_gid;
	}
    }

    if (conforming && S_ISREG(dstst->st_mode)
	&& (dstst->st_uid != srcst->st_uid
		|| dstst->st_gid != srcst->st_gid)
    ) {
	/* Suid bits must be cleared in the holy name of
	 * security (and the assumed user stupidity).
	 */
	srcst->st_mode&= ~06000;
    }

    /* Copy the mode. */
    if (S_ISREG(dstst->st_mode) && dstst->st_mode != srcst->st_mode) {
	if (chmod(dst, srcst->st_mode) < 0) {
	    if (errno != EPERM) {
		report(dst);
		return 0;
	    }
	    fprintf(stderr, "%s: Can't change the mode of %s\n",
		prog_name, dst);
	}
    }

    /* Copy the file modification time. */
    if ((pflag || !conforming) && S_ISREG(dstst->st_mode)) {
	struct utimbuf ut;

	ut.actime= action == MOVE ? srcst->st_atime : time(nil);
	ut.modtime= srcst->st_mtime;
	if (utime(dst, &ut) < 0) {
	    if (errno != EPERM) {
		report(dst);
		return 0;
	    }
	    if (pflag) {
		fprintf(stderr,
		    "%s: Can't set the time of %s\n",
		    prog_name, dst);
	    }
	}
    }
    if (vflag) {
	printf(action == COPY ? "cp %s ..\n" : "mv %s ..\n", src);
    }
    return 1;
}
Пример #2
0
void copy1(const char *src, const char *dst, struct stat *srcst,
			    struct stat *dstst)
/* Inspect the source file and then copy it.  Treatment of symlinks and
 * special files is a bit complicated.  The filetype and link-structure are
 * ignored if (expand && !rflag), symlinks and link-structure are ignored
 * if (expand && rflag), everything is copied precisely if !expand.
 */
{
    int r, linked;

    assert(srcst->st_ino != 0);

    if (srcst->st_ino == dstst->st_ino && srcst->st_dev == dstst->st_dev) {
	fprintf(stderr, "%s: can't copy %s onto itself\n",
	    prog_name, src);
	ex_code= 1;
	return;
    }

    /* You can forget it if the destination is a directory. */
    if (dstst->st_ino != 0 && S_ISDIR(dstst->st_mode)) {
	errno= EISDIR;
	report(dst);
	return;
    }

    if (S_ISREG(srcst->st_mode) || (expand && !rflag)) {
	if (!copy(src, dst, srcst, dstst)) return;

	if (action == MOVE && unlink(src) < 0) {
	    report(src);
	    return;
	}
	return;
    }

    if (dstst->st_ino != 0) {
	if (iflag || (action == MOVE && !fflag && !writable(dstst))) {
	    fprintf(stderr, "Replace %s? (mode = %03o) ",
		dst, dstst->st_mode & 07777);
	    if (!affirmative()) return;
	}
	if (unlink(dst) < 0) {
	    report(dst);
	    return;
	}
	dstst->st_ino= 0;
    }

    /* Apply the file creation mask if so required. */
    if (!pflag && conforming) srcst->st_mode &= fc_mask;

    linked= 0;

    if (S_ISLNK(srcst->st_mode)) {
	char buf[1024+1];

	if ((r= readlink(src, buf, sizeof(buf)-1)) < 0) {
	    report(src);
	    return;
	}
	buf[r]= 0;
	r= symlink(buf, dst);
	if (vflag && r == 0)
	    printf("ln -s %s %s\n", buf, dst);
    } else
    if (trylink(src, dst, srcst, dstst)) {
	linked= 1;
	r= 0;
    } else
    if (S_ISFIFO(srcst->st_mode)) {
	r= mkfifo(dst, srcst->st_mode);
	if (vflag && r == 0)
	    printf("mkfifo %s\n", dst);
    } else
    if (S_ISBLK(srcst->st_mode) || S_ISCHR(srcst->st_mode)) {
	r= mknod(dst, srcst->st_mode, srcst->st_rdev);
	if (vflag && r == 0) {
	    printf("mknod %s %c %d %d\n",
		dst,
		S_ISBLK(srcst->st_mode) ? 'b' : 'c',
		(srcst->st_rdev >> 8) & 0xFF,
		(srcst->st_rdev >> 0) & 0xFF);
	}
Пример #3
0
/*
 * Copy unmarked files in packing list to playpen - marked files
 * have already been copied in an earlier pass through the list.
 */
void
copy_plist(const char *home, Package *plist)
{
    PackingList p = plist->head;
    const char *where = home;
    const char *there = NULL, *mythere;
    char *where_args, *prefix = NULL;
    const char *last_chdir, *root = "/";
    long maxargs;
    int where_count = 0, add_count;
    struct stat stb;
    dev_t curdir;

    maxargs = sysconf(_SC_ARG_MAX);
    maxargs -= 64;			/*
					 * Some slop for the tar cmd text,
					 * and sh -c
					 */
    where_args = malloc(maxargs);
    if (!where_args) {
	cleanup(0);
	errx(2, "%s: can't get argument list space", __func__);
    }

    memset(where_args, 0, maxargs);
    strcpy(where_args, STARTSTRING);
    where_count = sizeof(STARTSTRING)-1;
    last_chdir = 0;

    if (stat(".", &stb) == 0)
	curdir = stb.st_dev;
    else
	curdir = (dev_t) -1;		/*
					 * It's ok if this is a valid dev_t;
					 * this is just a hint for an
					 * optimization.
					 */

    while (p) {
	if (p->type == PLIST_CWD)
	{
	    if (!prefix)
		prefix = p->name;
	    where = p->name == NULL ? prefix : p->name;
	}
	else if (p->type == PLIST_SRC)
	    there = p->name;
	else if (p->type == PLIST_IGNORE)
	    p = p->next;
	else if (p->type == PLIST_FILE && !p->marked) {
	    char fn[FILENAME_MAX];


	    /* First, look for it in the "home" dir */
	    sprintf(fn, "%s/%s", home, p->name);
	    if (fexists(fn)) {
		if (lstat(fn, &stb) == 0 && stb.st_dev == curdir &&
		    S_ISREG(stb.st_mode)) {
		    /*
		     * If we can link it to the playpen, that avoids a copy
		     * and saves time.
		     */
		    if (p->name[0] != '/') {
			/*
			 * Don't link abspn stuff--it doesn't come from
			 * local dir!
			 */
			if (trylink(fn, p->name) == 0) {
			    p = p->next;
			    continue;
			}
		    }
		}
		if (TOOBIG(fn)) {
		    PUSHOUT();
		}
		if (p->name[0] == '/') {
		    add_count = snprintf(&where_args[where_count],
					 maxargs - where_count,
					 " %s %s",
					 last_chdir == root ? "" : "-C /",
					 p->name);
		    last_chdir = root;
		} else {
		    add_count = snprintf(&where_args[where_count],
					 maxargs - where_count,
					 " %s%s %s",
					 last_chdir == home ? "" : "-C ",
					 last_chdir == home ? "" : home,
					 p->name);
		    last_chdir = home;
		}
		if (add_count < 0 || add_count >= maxargs - where_count) {
		    cleanup(0);
		    errx(2, "%s: oops, miscounted strings!", __func__);
		}
		where_count += add_count;
	    }
	    /*
	     * Otherwise, try along the actual extraction path..
	     */
	    else {
		if (p->name[0] == '/')
		    mythere = root;
		else mythere = there;
		if (mythere)
		    snprintf(fn, sizeof(fn), "%s/%s", mythere, p->name);
		else
		    snprintf(fn, sizeof(fn), "%s%s/%s",
			BaseDir && where && where[0] == '/' ? BaseDir : "", where, p->name);
		if (lstat(fn, &stb) == 0 && stb.st_dev == curdir &&
		    S_ISREG(stb.st_mode)) {
		    /*
		     * If we can link it to the playpen, that avoids a copy
		     * and saves time.
		     */
		    if (trylink(fn, p->name) == 0) {
			p = p->next;
			continue;
		    }
		}
		if (TOOBIG(p->name)) {
		    PUSHOUT();
		}
		if (last_chdir == (mythere ? mythere : where))
		    add_count = snprintf(&where_args[where_count],
					 maxargs - where_count,
					 " %s", p->name);
		else
		    add_count = snprintf(&where_args[where_count],
					 maxargs - where_count,
					 " -C %s %s",
					 mythere ? mythere : where,
					 p->name);
		if (add_count < 0 || add_count >= maxargs - where_count) {
		    cleanup(0);
		    errx(2, "%s: oops, miscounted strings!", __func__);
		}
		where_count += add_count;
		last_chdir = (mythere ? mythere : where);
	    }
	}
	p = p->next;
    }
    PUSHOUT();
    free(where_args);
}