Ejemplo n.º 1
0
int
packing_append_file_attr(struct packing *pack, const char *filepath,
    const char *newpath, const char *uname, const char *gname, mode_t perm,
    u_long fflags)
{
	int fd;
	int retcode = EPKG_OK;
	int ret;
	time_t source_time;
	struct stat st;
	struct archive_entry *entry, *sparse_entry;
	bool unset_timestamp;
	const char *source_date_epoch;
	char buf[32768];
	int len;

	entry = archive_entry_new();
	archive_entry_copy_sourcepath(entry, filepath);

	pkg_debug(2, "Packing file '%s'", filepath);

	if (lstat(filepath, &st) != 0) {
		pkg_emit_errno("lstat", filepath);
		retcode = EPKG_FATAL;
		goto cleanup;
	}

	ret = archive_read_disk_entry_from_file(pack->aread, entry, -1,
			&st);
	if (ret != ARCHIVE_OK) {
		pkg_emit_error("%s: %s", filepath,
				archive_error_string(pack->aread));
		retcode = EPKG_FATAL;
		goto cleanup;
	}

	if (newpath != NULL)
		archive_entry_set_pathname(entry, newpath);

	if (archive_entry_filetype(entry) != AE_IFREG) {
		archive_entry_set_size(entry, 0);
	}

	if (uname != NULL && uname[0] != '\0') {
		archive_entry_set_uname(entry, uname);
	}

	if (gname != NULL && gname[0] != '\0') {
		archive_entry_set_gname(entry, gname);
	}

	if (fflags > 0)
		archive_entry_set_fflags(entry, fflags, 0);

	if (perm != 0)
		archive_entry_set_perm(entry, perm);

	unset_timestamp = pkg_object_bool(pkg_config_get("UNSET_TIMESTAMP"));

	if (unset_timestamp) {
		archive_entry_unset_atime(entry);
		archive_entry_unset_ctime(entry);
		archive_entry_unset_mtime(entry);
		archive_entry_unset_birthtime(entry);
	}

	if ((source_date_epoch = getenv("SOURCE_DATE_EPOCH")) != NULL) {
		if (source_date_epoch[strspn(source_date_epoch, "0123456789")] != '\0') {
			pkg_emit_error("Bad environment variable "
			    "SOURCE_DATE_EPOCH: %s", source_date_epoch);
			retcode = EPKG_FATAL;
			goto cleanup;
		}
		source_time = strtoll(source_date_epoch, NULL, 10);
		archive_entry_set_atime(entry, source_time, 0);
		archive_entry_set_ctime(entry, source_time, 0);
		archive_entry_set_mtime(entry, source_time, 0);
		archive_entry_set_birthtime(entry, source_time, 0);
	}

	archive_entry_linkify(pack->resolver, &entry, &sparse_entry);

	if (sparse_entry != NULL && entry == NULL)
		entry = sparse_entry;

	archive_write_header(pack->awrite, entry);

	if (archive_entry_size(entry) <= 0)
		goto cleanup;

	if ((fd = open(filepath, O_RDONLY)) < 0) {
		pkg_emit_errno("open", filepath);
		retcode = EPKG_FATAL;
		goto cleanup;
	}

	while ((len = read(fd, buf, sizeof(buf))) > 0) {
		if (archive_write_data(pack->awrite, buf, len) == -1) {
			pkg_emit_errno("archive_write_data", "archive write error");
			retcode = EPKG_FATAL;
			break;
		}
	}

	if (len == -1) {
		pkg_emit_errno("read", "file read error");
		retcode = EPKG_FATAL;
	}
	close(fd);

cleanup:
	archive_entry_free(entry);
	return (retcode);
}
int
archive_read_disk_entry_from_file(struct archive *_a,
    struct archive_entry *entry,
    int fd,
    const struct stat *st)
{
	struct archive_read_disk *a = (struct archive_read_disk *)_a;
	const char *path, *name;
	struct stat s;
	int initial_fd = fd;
	int r, r1;

	archive_clear_error(_a);
	path = archive_entry_sourcepath(entry);
	if (path == NULL)
		path = archive_entry_pathname(entry);

	if (a->tree == NULL) {
		if (st == NULL) {
#if HAVE_FSTAT
			if (fd >= 0) {
				if (fstat(fd, &s) != 0) {
					archive_set_error(&a->archive, errno,
					    "Can't fstat");
					return (ARCHIVE_FAILED);
				}
			} else
#endif
#if HAVE_LSTAT
			if (!a->follow_symlinks) {
				if (lstat(path, &s) != 0) {
					archive_set_error(&a->archive, errno,
					    "Can't lstat %s", path);
					return (ARCHIVE_FAILED);
				}
			} else
#endif
			if (stat(path, &s) != 0) {
				archive_set_error(&a->archive, errno,
				    "Can't stat %s", path);
				return (ARCHIVE_FAILED);
			}
			st = &s;
		}
		archive_entry_copy_stat(entry, st);
	}

	/* Lookup uname/gname */
	name = archive_read_disk_uname(_a, archive_entry_uid(entry));
	if (name != NULL)
		archive_entry_copy_uname(entry, name);
	name = archive_read_disk_gname(_a, archive_entry_gid(entry));
	if (name != NULL)
		archive_entry_copy_gname(entry, name);

#ifdef HAVE_STRUCT_STAT_ST_FLAGS
	/* On FreeBSD, we get flags for free with the stat. */
	/* TODO: Does this belong in copy_stat()? */
	if (st->st_flags != 0)
		archive_entry_set_fflags(entry, st->st_flags, 0);
#endif

#if defined(EXT2_IOC_GETFLAGS) && defined(HAVE_WORKING_EXT2_IOC_GETFLAGS)
	/* Linux requires an extra ioctl to pull the flags.  Although
	 * this is an extra step, it has a nice side-effect: We get an
	 * open file descriptor which we can use in the subsequent lookups. */
	if ((S_ISREG(st->st_mode) || S_ISDIR(st->st_mode))) {
		if (fd < 0) {
			if (a->tree != NULL)
				fd = a->open_on_current_dir(a->tree, path,
					O_RDONLY | O_NONBLOCK | O_CLOEXEC);
			else
				fd = open(path, O_RDONLY | O_NONBLOCK |
						O_CLOEXEC);
			__archive_ensure_cloexec_flag(fd);
		}
		if (fd >= 0) {
			int stflags;
			r = ioctl(fd, EXT2_IOC_GETFLAGS, &stflags);
			if (r == 0 && stflags != 0)
				archive_entry_set_fflags(entry, stflags, 0);
		}
	}
#endif

#if defined(HAVE_READLINK) || defined(HAVE_READLINKAT)
	if (S_ISLNK(st->st_mode)) {
		size_t linkbuffer_len = st->st_size + 1;
		char *linkbuffer;
		int lnklen;

		linkbuffer = malloc(linkbuffer_len);
		if (linkbuffer == NULL) {
			archive_set_error(&a->archive, ENOMEM,
			    "Couldn't read link data");
			return (ARCHIVE_FAILED);
		}
		if (a->tree != NULL) {
#ifdef HAVE_READLINKAT
			lnklen = readlinkat(a->tree_current_dir_fd(a->tree),
			    path, linkbuffer, linkbuffer_len);
#else
			if (a->tree_enter_working_dir(a->tree) != 0) {
				archive_set_error(&a->archive, errno,
				    "Couldn't read link data");
				free(linkbuffer);
				return (ARCHIVE_FAILED);
			}
			lnklen = readlink(path, linkbuffer, linkbuffer_len);
#endif /* HAVE_READLINKAT */
		} else
			lnklen = readlink(path, linkbuffer, linkbuffer_len);
		if (lnklen < 0) {
			archive_set_error(&a->archive, errno,
			    "Couldn't read link data");
			free(linkbuffer);
			return (ARCHIVE_FAILED);
		}
		linkbuffer[lnklen] = 0;
		archive_entry_set_symlink(entry, linkbuffer);
		free(linkbuffer);
	}
#endif /* HAVE_READLINK || HAVE_READLINKAT */

	r = setup_acls(a, entry, &fd);
	r1 = setup_xattrs(a, entry, &fd);
	if (r1 < r)
		r = r1;
	if (a->enable_copyfile) {
		r1 = setup_mac_metadata(a, entry, &fd);
		if (r1 < r)
			r = r1;
	}
	r1 = setup_sparse(a, entry, &fd);
	if (r1 < r)
		r = r1;

	/* If we opened the file earlier in this function, close it. */
	if (initial_fd != fd)
		close(fd);
	return (r);
}
Ejemplo n.º 3
0
static void
test_write_format_mtree_sub(int use_set)
{
	struct archive_entry *ae;
	struct archive* a;
	size_t used;
	int i;

	/* Create a mtree format archive. */
	assert((a = archive_write_new()) != NULL);
	assertEqualIntA(a, ARCHIVE_OK, archive_write_set_format_mtree(a));
	if (use_set)
		assertEqualIntA(a, ARCHIVE_OK,
		    archive_write_set_options(a, "use-set,!all,flags,type"));
	else
		assertEqualIntA(a, ARCHIVE_OK,
		    archive_write_set_options(a, "!all,flags,type"));
	assertEqualIntA(a, ARCHIVE_OK,
	    archive_write_open_memory(a, buff, sizeof(buff)-1, &used));

	/* Write entries */
	for (i = 0; entries[i].path != NULL; i++) {
		assert((ae = archive_entry_new()) != NULL);
		archive_entry_set_fflags(ae, entries[i].fflags, 0);
		archive_entry_copy_pathname(ae, entries[i].path);
		archive_entry_set_size(ae, 0);
		assertEqualIntA(a, ARCHIVE_OK, archive_write_header(a, ae));
		archive_entry_free(ae);
	}
	assertEqualIntA(a, ARCHIVE_OK, archive_write_close(a));
        assertEqualInt(ARCHIVE_OK, archive_write_free(a));

	if (use_set) {
		const char *p;

		buff[used] = '\0';
		assert(NULL != (p = strstr(buff, "\n/set ")));
		if (p != NULL) {
			char *r;
			const char *o;
			p++;
			r = strchr(p, '\n');
			if (r != NULL)
				*r = '\0';
			o = "/set type=file flags=uchg,nodump";
			assertEqualString(o, p);
			if (r != NULL)
				*r = '\n';
		}
	}

	/*
	 * Read the data and check it.
	 */
	assert((a = archive_read_new()) != NULL);
	assertEqualIntA(a, ARCHIVE_OK, archive_read_support_format_all(a));
	assertEqualIntA(a, ARCHIVE_OK, archive_read_support_filter_all(a));
	assertEqualIntA(a, ARCHIVE_OK, archive_read_open_memory(a, buff, used));

	/* Read entries */
	for (i = 0; entries[i].path != NULL; i++) {
		unsigned long fset, fclr;

		assertEqualIntA(a, ARCHIVE_OK, archive_read_next_header(a, &ae));
		archive_entry_fflags(ae, &fset, &fclr);
		assertEqualInt((int)entries[i].fflags, (int)fset);
		assertEqualInt(0, (int)fclr);
		assertEqualString(entries[i].path, archive_entry_pathname(ae));
	}
	assertEqualIntA(a, ARCHIVE_OK, archive_read_close(a));
	assertEqualInt(ARCHIVE_OK, archive_read_free(a));
}
int
archive_read_disk_entry_from_file(struct archive *_a,
    struct archive_entry *entry,
    int fd, const struct stat *st)
{
	struct archive_read_disk *a = (struct archive_read_disk *)_a;
	const char *path, *name;
	struct stat s;
	int initial_fd = fd;
	int r, r1;

	archive_clear_error(_a);
	path = archive_entry_sourcepath(entry);
	if (path == NULL)
		path = archive_entry_pathname(entry);

#ifdef EXT2_IOC_GETFLAGS
	/* Linux requires an extra ioctl to pull the flags.  Although
	 * this is an extra step, it has a nice side-effect: We get an
	 * open file descriptor which we can use in the subsequent lookups. */
	if ((S_ISREG(st->st_mode) || S_ISDIR(st->st_mode))) {
		if (fd < 0)
			fd = open(pathname, O_RDONLY | O_NONBLOCK | O_BINARY);
		if (fd >= 0) {
			unsigned long stflags;
			int r = ioctl(fd, EXT2_IOC_GETFLAGS, &stflags);
			if (r == 0 && stflags != 0)
				archive_entry_set_fflags(entry, stflags, 0);
		}
	}
#endif

	if (st == NULL) {
		/* TODO: On Windows, use GetFileInfoByHandle() here.
		 * Using Windows stat() call is badly broken, but
		 * even the stat() wrapper has problems because
		 * 'struct stat' is broken on Windows.
		 */
#if HAVE_FSTAT
		if (fd >= 0) {
			if (fstat(fd, &s) != 0) {
				archive_set_error(&a->archive, errno,
				    "Can't fstat");
				return (ARCHIVE_FAILED);
			}
		} else
#endif
#if HAVE_LSTAT
		if (!a->follow_symlinks) {
			if (lstat(path, &s) != 0) {
				archive_set_error(&a->archive, errno,
				    "Can't lstat %s", path);
				return (ARCHIVE_FAILED);
			}
		} else
#endif
		if (stat(path, &s) != 0) {
			archive_set_error(&a->archive, errno,
			    "Can't stat %s", path);
			return (ARCHIVE_FAILED);
		}
		st = &s;
	}
	archive_entry_copy_stat(entry, st);

	/* Lookup uname/gname */
	name = archive_read_disk_uname(_a, archive_entry_uid(entry));
	if (name != NULL)
		archive_entry_copy_uname(entry, name);
	name = archive_read_disk_gname(_a, archive_entry_gid(entry));
	if (name != NULL)
		archive_entry_copy_gname(entry, name);

#ifdef HAVE_STRUCT_STAT_ST_FLAGS
	/* On FreeBSD, we get flags for free with the stat. */
	/* TODO: Does this belong in copy_stat()? */
	if (st->st_flags != 0)
		archive_entry_set_fflags(entry, st->st_flags, 0);
#endif

#ifdef HAVE_READLINK
	if (S_ISLNK(st->st_mode)) {
		char linkbuffer[PATH_MAX + 1];
		int lnklen = readlink(path, linkbuffer, PATH_MAX);
		if (lnklen < 0) {
			archive_set_error(&a->archive, errno,
			    "Couldn't read link data");
			return (ARCHIVE_FAILED);
		}
		linkbuffer[lnklen] = 0;
		archive_entry_set_symlink(entry, linkbuffer);
	}
#endif

	r = setup_acls_posix1e(a, entry, fd);
	r1 = setup_xattrs(a, entry, fd);
	if (r1 < r)
		r = r1;
	/* If we opened the file earlier in this function, close it. */
	if (initial_fd != fd)
		close(fd);
	return (r);
}
Ejemplo n.º 5
0
int
packing_append_file_attr(struct packing *pack, const char *filepath,
    const char *newpath, const char *uname, const char *gname, mode_t perm,
    u_long fflags)
{
	int fd;
	char *map;
	int retcode = EPKG_OK;
	int ret;
	struct stat st;
	struct archive_entry *entry, *sparse_entry;
	bool unset_timestamp;

	entry = archive_entry_new();
	archive_entry_copy_sourcepath(entry, filepath);

	pkg_debug(2, "Packing file '%s'", filepath);

	if (lstat(filepath, &st) != 0) {
		pkg_emit_errno("lstat", filepath);
		retcode = EPKG_FATAL;
		goto cleanup;
	}

	ret = archive_read_disk_entry_from_file(pack->aread, entry, -1,
			&st);
	if (ret != ARCHIVE_OK) {
		pkg_emit_error("%s: %s", filepath,
				archive_error_string(pack->aread));
		retcode = EPKG_FATAL;
		goto cleanup;
	}

	if (newpath != NULL)
		archive_entry_set_pathname(entry, newpath);

	if (archive_entry_filetype(entry) != AE_IFREG) {
		archive_entry_set_size(entry, 0);
	}

	if (uname != NULL && uname[0] != '\0') {
		if (pack->pass) {
			struct passwd* pw = getpwnam(uname);
			if (pw == NULL) {
				pkg_emit_error("Unknown user: '******'", uname);
				retcode = EPKG_FATAL;
				goto cleanup;
			}
			archive_entry_set_uid(entry, pw->pw_uid);
		}
		archive_entry_set_uname(entry, uname);
	}

	if (gname != NULL && gname[0] != '\0') {
		if (pack->pass) {
			struct group *gr = (getgrnam(gname));
			if (gr == NULL) {
				pkg_emit_error("Unknown group: '%s'", gname);
				retcode = EPKG_FATAL;
				goto cleanup;
			}
			archive_entry_set_gid(entry, gr->gr_gid);
		}
		archive_entry_set_gname(entry, gname);
	}

	if (fflags > 0)
		archive_entry_set_fflags(entry, fflags, 0);

	if (perm != 0)
		archive_entry_set_perm(entry, perm);

	unset_timestamp = pkg_object_bool(pkg_config_get("UNSET_TIMESTAMP"));

	if (unset_timestamp) {
		archive_entry_unset_atime(entry);
		archive_entry_unset_ctime(entry);
		archive_entry_unset_mtime(entry);
		archive_entry_unset_birthtime(entry);
	}

	archive_entry_linkify(pack->resolver, &entry, &sparse_entry);

	if (sparse_entry != NULL && entry == NULL)
		entry = sparse_entry;

	archive_write_header(pack->awrite, entry);

	if (archive_entry_size(entry) > 0) {
		if ((fd = open(filepath, O_RDONLY)) < 0) {
			pkg_emit_errno("open", filepath);
			retcode = EPKG_FATAL;
			goto cleanup;
		}
		if (st.st_size > SSIZE_MAX) {
			char buf[BUFSIZ];
			int len;

			while ((len = read(fd, buf, sizeof(buf))) > 0)
				if (archive_write_data(pack->awrite, buf, len) == -1) {
					pkg_emit_errno("archive_write_data", "archive write error");
					retcode = EPKG_FATAL;
					break;
				}

			if (len == -1) {
				pkg_emit_errno("read", "file read error");
				retcode = EPKG_FATAL;
			}
			close(fd);
		}
		else {
			if ((map = mmap(NULL, st.st_size, PROT_READ,
					MAP_SHARED, fd, 0)) != MAP_FAILED) {
				close(fd);
				if (archive_write_data(pack->awrite, map, st.st_size) == -1) {
					pkg_emit_errno("archive_write_data", "archive write error");
					retcode = EPKG_FATAL;
				}
				munmap(map, st.st_size);
			}
			else {
				close(fd);
				pkg_emit_errno("open", filepath);
				retcode = EPKG_FATAL;
				goto cleanup;
			}
		}
	}

	cleanup:
	archive_entry_free(entry);
	return (retcode);
}