static int
archive_read_format_cpio_read_header(struct archive_read *a,
    struct archive_entry *entry)
{
	struct cpio *cpio;
	size_t bytes;
	const void *h;
	size_t namelength;
	size_t name_pad;
	int r;

	cpio = (struct cpio *)(a->format->data);
	r = (cpio->read_header(a, cpio, entry, &namelength, &name_pad));

	if (r < ARCHIVE_WARN)
		return (r);

	/* Read name from buffer. */
	bytes = (a->decompressor->read_ahead)(a, &h, namelength + name_pad);
	if (bytes < namelength + name_pad)
	    return (ARCHIVE_FATAL);
	(a->decompressor->consume)(a, namelength + name_pad);
	archive_strncpy(&cpio->entry_name, (const char *)h, namelength);
	archive_entry_set_pathname(entry, cpio->entry_name.s);
	cpio->entry_offset = 0;

	/* If this is a symlink, read the link contents. */
	if (archive_entry_filetype(entry) == AE_IFLNK) {
		bytes = (a->decompressor->read_ahead)(a, &h,
		    cpio->entry_bytes_remaining);
		if ((off_t)bytes < cpio->entry_bytes_remaining)
			return (ARCHIVE_FATAL);
		(a->decompressor->consume)(a, cpio->entry_bytes_remaining);
		archive_strncpy(&cpio->entry_linkname, (const char *)h,
		    cpio->entry_bytes_remaining);
		archive_entry_set_symlink(entry, cpio->entry_linkname.s);
		cpio->entry_bytes_remaining = 0;
	}

	/* Compare name to "TRAILER!!!" to test for end-of-archive. */
	if (namelength == 11 && strcmp((const char *)h, "TRAILER!!!") == 0) {
	    /* TODO: Store file location of start of block. */
	    archive_set_error(&a->archive, 0, NULL);
	    return (ARCHIVE_EOF);
	}

	/* Detect and record hardlinks to previously-extracted entries. */
	record_hardlink(cpio, entry);

	return (r);
}
Ejemplo n.º 2
0
int createArchiveofFilesPC(char** files, unsigned long * size,
		unsigned int fileCount, const char* filename, const char* tarHostDir) {
	unsigned int ctr = 0;
	struct timespec ts;
	struct archive_entry* entry;
	struct archive* archive = archive_write_new();
	int dirlen = strlen(tarHostDir);
	if ((archive_write_set_compression_gzip(archive) != ARCHIVE_OK)
			|| (archive_write_set_format_ustar(archive) != ARCHIVE_OK)
			|| (archive_write_open_filename(archive, filename) != ARCHIVE_OK)) {
		printf("%s\n", archive_error_string(archive));
		return -1;
	}
	int tarHostDirLen = strlen(tarHostDir);
	for (ctr = 0; ctr < fileCount; ctr++) {
		entry = archive_entry_new();
		clock_gettime(CLOCK_REALTIME, &ts);

		//Set entry to be stored under the tarHostDir directory
		const char* path = files[ctr];
		int pathlength = dirlen + strlen(path) + 2; //One for / and the other for '\0'
		char newPath[pathlength];
		if(tarHostDirLen>0)
			snprintf(newPath, pathlength, "%s/%s", tarHostDir, boost::filesystem::path(path).filename().c_str());
		else
			snprintf(newPath, pathlength, "%s", boost::filesystem::path(path).filename().c_str());
		archive_entry_set_pathname(entry, newPath);
		archive_entry_set_size(entry, size[ctr]);
		archive_entry_set_filetype(entry, AE_IFREG);
		archive_entry_set_perm(entry, 0444);
		archive_entry_set_atime(entry, ts.tv_sec, ts.tv_nsec);
		archive_entry_set_birthtime(entry, ts.tv_sec, ts.tv_nsec);
		archive_entry_set_ctime(entry, ts.tv_sec, ts.tv_nsec);
		archive_entry_set_mtime(entry, ts.tv_sec, ts.tv_nsec);

		int rc = archive_write_header(archive, entry);
		char *contents = new char[size[ctr]+1];
		FILE* fp = fopen(files[ctr],"rb");
		fread((void *)contents, size[ctr], 1, fp);
		fclose(fp);
		archive_write_data(archive, contents, size[ctr]);
		archive_entry_free(entry);
		entry = NULL;
		delete[] contents;
		if (ARCHIVE_OK != rc) {
			printf("%s\n", archive_error_string(archive));
			return -1;
		}
	}
	archive_write_finish(archive);
}
Ejemplo n.º 3
0
static gboolean
asb_utils_write_archive (const gchar *filename,
			 const gchar *path_orig,
			 GPtrArray *files,
			 GError **error)
{
	const gchar *tmp;
	gboolean ret = TRUE;
	gsize len;
	guint i;
	struct archive *a;
	struct archive_entry *entry;
	struct stat st;

	a = archive_write_new ();
	if (g_str_has_suffix (filename, ".gz")) {
		archive_write_add_filter_gzip (a);
		archive_write_set_filter_option (a, "gzip", "timestamp", NULL);
	}
	if (g_str_has_suffix (filename, ".bz2"))
		archive_write_add_filter_bzip2 (a);
	if (g_str_has_suffix (filename, ".xz"))
		archive_write_add_filter_xz (a);
	archive_write_set_format_pax_restricted (a);
	archive_write_open_filename (a, filename);
	for (i = 0; i < files->len; i++) {
		g_autofree gchar *data = NULL;
		g_autofree gchar *filename_full = NULL;

		tmp = g_ptr_array_index (files, i);
		filename_full = g_build_filename (path_orig, tmp, NULL);
		if (stat (filename_full, &st) != 0)
			continue;
		entry = archive_entry_new ();
		archive_entry_set_pathname (entry, tmp);
		archive_entry_set_size (entry, st.st_size);
		archive_entry_set_filetype (entry, AE_IFREG);
		archive_entry_set_perm (entry, 0644);
		archive_write_header (a, entry);
		ret = g_file_get_contents (filename_full, &data, &len, error);
		if (!ret) {
			archive_entry_free (entry);
			break;
		}
		archive_write_data (a, data, len);
		archive_entry_free (entry);
	}
	archive_write_close (a);
	archive_write_free (a);
	return ret;
}
static int
archive_write_newc_finish(struct archive_write *a)
{
    struct cpio *cpio;
    int er;
    struct archive_entry *trailer;

    cpio = (struct cpio *)a->format_data;
    trailer = archive_entry_new();
    archive_entry_set_nlink(trailer, 1);
    archive_entry_set_pathname(trailer, "TRAILER!!!");
    er = archive_write_newc_header(a, trailer);
    archive_entry_free(trailer);
    return (er);
}
static int
archive_write_newc_close(struct archive_write *a)
{
	int er;
	struct archive_entry *trailer;

	trailer = archive_entry_new();
	archive_entry_set_nlink(trailer, 1);
	archive_entry_set_size(trailer, 0);
	archive_entry_set_pathname(trailer, "TRAILER!!!");
	/* Bypass the required data checks. */
	er = write_header(a, trailer);
	archive_entry_free(trailer);
	return (er);
}
Ejemplo n.º 6
0
int
packing_append_buffer(struct packing *pack, const char *buffer, const char *path, int size)
{
	archive_entry_clear(pack->entry);
	archive_entry_set_filetype(pack->entry, AE_IFREG);
	archive_entry_set_perm(pack->entry, 0644);
	archive_entry_set_gname(pack->entry, "wheel");
	archive_entry_set_uname(pack->entry, "root");
	archive_entry_set_pathname(pack->entry, path);
	archive_entry_set_size(pack->entry, size);
	archive_write_header(pack->awrite, pack->entry);
	archive_write_data(pack->awrite, buffer, size);
	archive_entry_clear(pack->entry);

	return (EPKG_OK);
}
Ejemplo n.º 7
0
/* Transform the destination path of the given entry.
 *
 * Returns 0 on success, 1 where the file does not need to be extracted and <0
 * on error.
 */
static int transform_dest_path(struct archive_entry *entry, const char *dest)
{
    char *path;
    const char *filename;

    filename = archive_entry_pathname(entry);

    path = join_paths(dest, filename);
    if (!path)
        return 1;

    archive_entry_set_pathname(entry, path);
    free(path);

    return 0;
}
Ejemplo n.º 8
0
int
do_extract_mtree(char *mtree, const char *prefix)
{
	struct archive *a = NULL;
	struct archive_entry *ae;
	char path[MAXPATHLEN];
	const char *fpath;
	int retcode = EPKG_OK;
	int ret;

	if (mtree == NULL || *mtree == '\0')
		return EPKG_OK;

	a = archive_read_new();
	archive_read_support_filter_none(a);
	archive_read_support_format_mtree(a);

	if (archive_read_open_memory(a, mtree, strlen(mtree)) != ARCHIVE_OK) {
		pkg_emit_error("Fail to extract the mtree: %s",
		    archive_error_string(a));
		retcode = EPKG_FATAL;
		goto cleanup;
	}

	while ((ret = archive_read_next_header(a, &ae)) != ARCHIVE_EOF) {
		if (ret != ARCHIVE_OK) {
			pkg_emit_error("Skipping unsupported mtree line: %s",
			    archive_error_string(a));
			continue;
		}
		fpath = archive_entry_pathname(ae);

		if (*fpath != '/') {
			snprintf(path, sizeof(path), "%s/%s", prefix, fpath);
			archive_entry_set_pathname(ae, path);
		}

		/* Ignored failed extraction on purpose */
		archive_read_extract(a, ae, EXTRACT_ARCHIVE_FLAGS);
	}

cleanup:
	if (a != NULL)
		archive_read_free(a);

	return (retcode);
}
/*
 * Mock up a fake header.
 */
static int
archive_read_format_raw_read_header(struct archive_read *a,
    struct archive_entry *entry)
{
	struct raw_info *info;

	info = (struct raw_info *)(a->format->data);
	if (info->end_of_file)
		return (ARCHIVE_EOF);

	a->archive.archive_format = ARCHIVE_FORMAT_RAW;
	a->archive.archive_format_name = "Raw data";
	archive_entry_set_pathname(entry, "data");
	/* XXX should we set mode to mimic a regular file? XXX */
	/* I'm deliberately leaving most fields unset here. */
	return (ARCHIVE_OK);
}
Ejemplo n.º 10
0
/*
 * Issue 185:  Test a regression that got in between 2.6 and 2.7 that
 * broke extraction of Zip entries with length-at-end.
 */
static void
test_compat_zip_3(void)
{
	const char *refname = "test_compat_zip_3.zip";
	struct archive_entry *ae;
	struct archive *a;

	extract_reference_file(refname);
	assert((a = archive_read_new()) != NULL);
	assertEqualIntA(a, ARCHIVE_OK, archive_read_support_filter_all(a));
	assertEqualIntA(a, ARCHIVE_OK, archive_read_support_format_all(a));
	assertEqualIntA(a, ARCHIVE_OK, archive_read_open_filename(a, refname, 10240));

	/* First entry. */
	assertEqualIntA(a, ARCHIVE_OK, archive_read_next_header(a, &ae));
	assertEqualString("soapui-4.0.0/", archive_entry_pathname(ae));
	assertEqualInt(0, archive_entry_size(ae));
	assert(archive_entry_size_is_set(ae));
	assertEqualInt(AE_IFDIR, archive_entry_filetype(ae));

	/* Second entry. */
	assertEqualIntA(a, ARCHIVE_OK, archive_read_next_header(a, &ae));
	assertEqualString("soapui-4.0.0/soapui-settings.xml", archive_entry_pathname(ae));
	assertEqualInt(AE_IFREG, archive_entry_filetype(ae));
	assertEqualInt(1030, archive_entry_size(ae));
	assert(archive_entry_size_is_set(ae));

	/* Extract under a different name. */
	archive_entry_set_pathname(ae, "test_3.txt");
	if(libz_enabled) {
		char *p;
		size_t s;
		assertEqualIntA(a, ARCHIVE_OK, archive_read_extract(a, ae, 0));
		/* Verify the first 12 bytes actually got written to disk correctly. */
		p = slurpfile(&s, "test_3.txt");
		assertEqualInt(s, 1030);
		assertEqualMem(p, "<?xml versio", 12);
		free(p);
	} else {
		skipping("Skipping ZIP compression check, no libz support");
	}
	assertEqualIntA(a, ARCHIVE_EOF, archive_read_next_header(a, &ae));

	assertEqualIntA(a, ARCHIVE_OK, archive_read_close(a));
	assertEqualIntA(a, ARCHIVE_OK, archive_read_free(a));
}
Ejemplo n.º 11
0
int StudioFrame::WriteFileToZip(struct archive *zip, std::string file) {
	const char *filename = file.c_str();
	void *fd = studioCbs.open(filename);
	if (fd == NULL) {
		wxString str;
		str.Printf(wxT("Error creating file %s"), filename);
		wxMessageBox(str);

		return -1;
	}

	studioCbs.seek(fd, 0, SEEK_END);
	size_t size = studioCbs.tell(fd);
	studioCbs.seek(fd, 0, SEEK_SET);

	wxFileName fname(filename);

	struct archive_entry *entry = archive_entry_new();
	if (entry == NULL) {
		wxMessageBox(_("archive_entry_new error"));
		return -1;
	}

	archive_entry_set_pathname(entry, fname.GetFullName().ToStdString().c_str());
	archive_entry_set_size(entry, size);
	archive_entry_set_filetype(entry, AE_IFREG);
	archive_entry_set_perm(entry, 0644);
	archive_write_header(zip, entry);

	char buffer[4096];
	while (size > 0) {
		int bytes = studioCbs.read(buffer, 1, 4096, fd);
		if (bytes == 0) break;

		if (archive_write_data(zip, buffer, bytes) != bytes) {
			studioCbs.close(fd);
			wxMessageBox(_("archive_write_data error"));
			return -1;
		}
	}

	studioCbs.close(fd);
	archive_entry_free(entry);

	return 0;
}
Ejemplo n.º 12
0
Status Carver::compress(const std::set<boost::filesystem::path>& paths) {
  auto arch = archive_write_new();
  if (arch == nullptr) {
    return Status(1, "Failed to create tar archive");
  }
  // Zipping doesn't seem to be working currently
  // archive_write_set_format_zip(arch);
  archive_write_set_format_pax_restricted(arch);
  auto ret = archive_write_open_filename(arch, archivePath_.string().c_str());
  if (ret == ARCHIVE_FATAL) {
    archive_write_free(arch);
    return Status(1, "Failed to open tar archive for writing");
  }
  for (const auto& f : paths) {
    PlatformFile pFile(f.string(), PF_OPEN_EXISTING | PF_READ);

    auto entry = archive_entry_new();
    archive_entry_set_pathname(entry, f.leaf().string().c_str());
    archive_entry_set_size(entry, pFile.size());
    archive_entry_set_filetype(entry, AE_IFREG);
    archive_entry_set_perm(entry, 0644);
    // archive_entry_set_atime();
    // archive_entry_set_ctime();
    // archive_entry_set_mtime();
    archive_write_header(arch, entry);

    // TODO: Chunking or a max file size.
    std::ifstream in(f.string(), std::ios::binary);
    std::stringstream buffer;
    buffer << in.rdbuf();
    archive_write_data(arch, buffer.str().c_str(), buffer.str().size());
    in.close();
    archive_entry_free(entry);
  }
  archive_write_free(arch);

  PlatformFile archFile(archivePath_.string(), PF_OPEN_EXISTING | PF_READ);
  updateCarveValue(carveGuid_, "size", std::to_string(archFile.size()));
  updateCarveValue(
      carveGuid_,
      "sha256",
      hashFromFile(HashType::HASH_TYPE_SHA256, archivePath_.string()));

  return Status(0, "Ok");
};
Ejemplo n.º 13
0
/*
 * Verify that CP932/SJIS filenames are correctly translated to Unicode and UTF-8.
 */
static void
test_pax_filename_encoding_CP932(void)
{
  	struct archive *a;
  	struct archive_entry *entry;
	char buff[4096];
	size_t used;

	if (NULL == setlocale(LC_ALL, "Japanese_Japan") &&
	    NULL == setlocale(LC_ALL, "ja_JP.SJIS")) {
		skipping("eucJP locale not available on this system.");
		return;
	}

	/* Check if the paltform completely supports the string conversion. */
	a = archive_write_new();
	assertEqualInt(ARCHIVE_OK, archive_write_set_format_pax(a));
	if (archive_write_set_options(a, "hdrcharset=UTF-8") != ARCHIVE_OK) {
		skipping("This system cannot convert character-set"
		    " from CP932/SJIS to UTF-8.");
		archive_write_free(a);
		return;
	}
	archive_write_free(a);

	/* Re-create a write archive object since filenames should be written
	 * in UTF-8 by default. */
	a = archive_write_new();
	assertEqualInt(ARCHIVE_OK, archive_write_set_format_pax(a));
	assertEqualInt(ARCHIVE_OK,
	    archive_write_open_memory(a, buff, sizeof(buff), &used));

	entry = archive_entry_new2(a);
	archive_entry_set_pathname(entry, "\x95\x5C.txt");
	/* Check the Unicode version. */
	archive_entry_set_filetype(entry, AE_IFREG);
	archive_entry_set_size(entry, 0);
	assertEqualInt(ARCHIVE_OK, archive_write_header(a, entry));
	archive_entry_free(entry);
	assertEqualInt(ARCHIVE_OK, archive_write_free(a));

	/* Check UTF-8 version. */
	assertEqualMem(buff + 512, "16 path=\xE8\xA1\xA8.txt\x0A", 16);

}
/*
 * Mock up a fake header.
 */
static int
archive_read_format_raw_read_header(struct archive_read *a,
    struct archive_entry *entry)
{
	struct raw_info *info;

	info = (struct raw_info *)(a->format->data);
	if (info->end_of_file)
		return (ARCHIVE_EOF);

	a->archive.archive_format = ARCHIVE_FORMAT_RAW;
	a->archive.archive_format_name = "raw";
	archive_entry_set_pathname(entry, "data");
	archive_entry_set_filetype(entry, AE_IFREG);
	archive_entry_set_perm(entry, 0644);
	/* I'm deliberately leaving most fields unset here. */
	return (ARCHIVE_OK);
}
Ejemplo n.º 15
0
/*
 * Verify that CP1251 filenames are correctly translated to Unicode and UTF-8.
 */
static void
test_pax_filename_encoding_CP1251(void)
{
  	struct archive *a;
  	struct archive_entry *entry;
	char buff[4096];
	size_t used;

	if (NULL == setlocale(LC_ALL, "Russian_Russia") &&
	    NULL == setlocale(LC_ALL, "ru_RU.CP1251")) {
		skipping("KOI8-R locale not available on this system.");
		return;
	}

	/* Check if the paltform completely supports the string conversion. */
	a = archive_write_new();
	assertEqualInt(ARCHIVE_OK, archive_write_set_format_pax(a));
	if (archive_write_set_options(a, "hdrcharset=UTF-8") != ARCHIVE_OK) {
		skipping("This system cannot convert character-set"
		    " from KOI8-R to UTF-8.");
		archive_write_free(a);
		return;
	}
	archive_write_free(a);

	/* Re-create a write archive object since filenames should be written
	 * in UTF-8 by default. */
	a = archive_write_new();
	assertEqualInt(ARCHIVE_OK, archive_write_set_format_pax(a));
	assertEqualInt(ARCHIVE_OK,
	    archive_write_open_memory(a, buff, sizeof(buff), &used));

	entry = archive_entry_new2(a);
	archive_entry_set_pathname(entry, "\xef\xf0\xe8");
	archive_entry_set_filetype(entry, AE_IFREG);
	archive_entry_set_size(entry, 0);
	assertEqualInt(ARCHIVE_OK, archive_write_header(a, entry));
	archive_entry_free(entry);
	assertEqualInt(ARCHIVE_OK, archive_write_free(a));

	/* Above three characters in KOI8-R should translate to the following
	 * three characters (two bytes each) in UTF-8. */
	assertEqualMem(buff + 512, "15 path=\xD0\xBF\xD1\x80\xD0\xB8\x0A", 15);
}
Ejemplo n.º 16
0
static void create_archive(const char *filepath, const char *tarfile)
{
    struct archive *a;
    struct archive_entry *entry;
    struct stat st;
    char buff[8192];
    int len;
    int fd;
    char **filenames, **filename;

    filenames = list_filenames(filepath);
    filename = filenames;

    a = archive_write_new();
    archive_write_set_compression_bzip2(a);
    archive_write_set_format_ustar(a);
    archive_write_open_filename(a, tarfile);
    while (*filename) {
	stat(*filename, &st);
	entry = archive_entry_new();
	archive_entry_set_pathname(entry, *filename);
	archive_entry_set_size(entry, st.st_size);
	archive_entry_set_filetype(entry, AE_IFREG);
	archive_entry_set_perm(entry, 0644);
	archive_write_header(a, entry);
	fd = open(*filename, O_RDONLY);
	len = read(fd, buff, sizeof(buff));
	while ( len > 0 ) {
	    archive_write_data(a, buff, len);
	    len = read(fd, buff, sizeof(buff));
	}
	close(fd);
	archive_entry_free(entry);
	filename++;
    }

    free_str_array(filenames);
    archive_write_close(a);
#if ARCHIVE_VERSION_NUMBER < 4000000
    archive_write_finish(a);
#else
    archive_write_free(a);
#endif
}
Ejemplo n.º 17
0
void Package::pack()
{
    struct archive *a;
    char buf[8192];

    std::string package_base_filename(mManifest.packageName() + "-"
        + std::to_string(mManifest.packageVersion()) + "-"
        + mManifest.targetArch());

    std::string tbz2_path = mWorkDir.string() + "/"
        + package_base_filename + ".rps";

    a = archive_write_new();
    archive_write_add_filter_bzip2(a);
    archive_write_set_format_pax_restricted(a);
    archive_write_open_filename(a, tbz2_path.c_str());

    struct stat st;
    struct archive_entry *entry;

    for (auto &f: mManifest.files()) {
        std::string source = mUnpackedDir.string() + std::string("/data/") + f.name();
        std::string dest = std::string("data/") + f.name();
        stat(source.c_str(), &st);
        entry = archive_entry_new();
        archive_entry_set_pathname(entry, dest.c_str());
        archive_entry_set_size(entry, st.st_size);
        archive_entry_set_filetype(entry, AE_IFREG);
        archive_entry_set_perm(entry, 0644);
        archive_write_header(a, entry);
        int fd = open(source.c_str(), O_RDONLY);
        int len = read(fd, buf, sizeof(buf));
        while (len > 0) {
            archive_write_data(a, buf, len);
            len = read(fd, buf, sizeof(buf));
        }
        close(fd);
        archive_entry_free(entry);
    }

    archive_write_close(a);
    archive_write_free(a);
}
Ejemplo n.º 18
0
static void
write_meta_file(struct memory_file *file, struct archive *archive)
{
	struct archive_entry *entry;

	entry = archive_entry_new();
	archive_entry_set_pathname(entry, file->name);
	archive_entry_copy_stat(entry, &file->st);

	archive_entry_set_uname(entry, file->owner);
	archive_entry_set_gname(entry, file->group);

	if (archive_write_header(archive, entry))
		errx(2, "cannot write to archive: %s", archive_error_string(archive));

	archive_write_data(archive, file->data, file->len);

	archive_entry_free(entry);
}
Ejemplo n.º 19
0
static gboolean
http_archive_read_callback (gpointer user_data)
{
    FetchData *fetch_data = (FetchData *) user_data;

    gint r;
    struct archive_entry *entry;
    gchar *newPath = NULL;

    r = archive_read_next_header(fetch_data->a, &entry);
    if (r == ARCHIVE_EOF) {
        g_idle_add (archive_finish_callback, fetch_data);
        return FALSE;
    }

    if (r != ARCHIVE_OK) {
        g_set_error(&fetch_data->error, RESTRAINT_FETCH_LIBARCHIVE_ERROR, r,
                "archive_read_next_header failed: %s", archive_error_string(fetch_data->a));
        g_idle_add (archive_finish_callback, fetch_data);
        return FALSE;
    }

    if (fetch_data->archive_entry_callback) {
        fetch_data->archive_entry_callback (archive_entry_pathname (entry),
                                            fetch_data->user_data);
    }

    // Update pathname
    newPath = g_build_filename (fetch_data->base_path, archive_entry_pathname( entry ), NULL);
    archive_entry_set_pathname( entry, newPath );
    g_free(newPath);

    r = archive_read_extract2(fetch_data->a, entry, fetch_data->ext);
    if (r != ARCHIVE_OK) {
        g_set_error(&fetch_data->error, RESTRAINT_FETCH_LIBARCHIVE_ERROR, r,
                "archive_read_extract2 failed: %s", archive_error_string(fetch_data->ext));
        g_idle_add (archive_finish_callback, fetch_data);
        return FALSE;
    }
    return TRUE;
}
Ejemplo n.º 20
0
int createArchiveofFiles(char** files, unsigned long * size,
		unsigned int fileCount, const char* filename) {
	unsigned int ctr = 0;
	struct timespec ts;
	struct archive_entry* entry;
	struct archive* archive = archive_write_new();
	if ((archive_write_set_compression_gzip(archive) != ARCHIVE_OK)
			|| (archive_write_set_format_ustar(archive) != ARCHIVE_OK)
			|| (archive_write_open_filename(archive, filename) != ARCHIVE_OK)) {
		printf("%s\n", archive_error_string(archive));
		return -1;
	}
	for (ctr = 0; ctr < fileCount; ctr++) {
		entry = archive_entry_new();
		clock_gettime(CLOCK_REALTIME, &ts);

		archive_entry_set_pathname(entry, files[ctr]);
		archive_entry_set_size(entry, size[ctr]);
		archive_entry_set_filetype(entry, AE_IFREG);
		archive_entry_set_perm(entry, 0444);
		archive_entry_set_atime(entry, ts.tv_sec, ts.tv_nsec);
		archive_entry_set_birthtime(entry, ts.tv_sec, ts.tv_nsec);
		archive_entry_set_ctime(entry, ts.tv_sec, ts.tv_nsec);
		archive_entry_set_mtime(entry, ts.tv_sec, ts.tv_nsec);

		int rc = archive_write_header(archive, entry);
		char *contents = new char[size[ctr]+1];
		FILE* fp = fopen(files[ctr],"rb");
		fread((void *)contents, size[ctr], 1, fp);
		fclose(fp);
		archive_write_data(archive, contents, size[ctr]);
		archive_entry_free(entry);
		entry = NULL;
		delete[] contents;
		if (ARCHIVE_OK != rc) {
			printf("%s\n", archive_error_string(archive));
			return -1;
		}
	}
	archive_write_finish(archive);
}
Ejemplo n.º 21
0
static void record_entry(db_writer_t *writer, const char *root, const char *entry)
{
    time_t now = time(NULL);
    char entry_path[PATH_MAX];

    snprintf(entry_path, PATH_MAX, "%s/%s", root, entry);
    archive_entry_set_pathname(writer->entry, entry_path);
    archive_entry_set_filetype(writer->entry, AE_IFREG);
    archive_entry_set_size(writer->entry, writer->buf.len);

    archive_entry_set_perm(writer->entry, 0644);
    archive_entry_set_ctime(writer->entry, now, 0);
    archive_entry_set_mtime(writer->entry, now, 0);
    archive_entry_set_atime(writer->entry, now, 0);

    archive_write_header(writer->archive, writer->entry);
    archive_write_data(writer->archive, writer->buf.data, writer->buf.len);

    archive_entry_clear(writer->entry);
    buffer_clear(&writer->buf);
}
Ejemplo n.º 22
0
int
xbps_archive_append_buf(struct archive *ar, const void *buf, const size_t buflen,
	const char *fname, const mode_t mode, const char *uname, const char *gname)
{
	struct archive_entry *entry;
	time_t tm;

	assert(ar);
	assert(buf);
	assert(fname);
	assert(uname);
	assert(gname);

	tm = time(NULL);
	entry = archive_entry_new();
	assert(entry);

	archive_entry_set_filetype(entry, AE_IFREG);
	archive_entry_set_perm(entry, mode);
	archive_entry_set_uname(entry, uname);
	archive_entry_set_gname(entry, gname);
	archive_entry_set_pathname(entry, fname);
	archive_entry_set_size(entry, buflen);
	archive_entry_set_atime(entry, tm, 0);
	archive_entry_set_mtime(entry, tm, 0);
	archive_entry_set_ctime(entry, tm, 0);

	if (archive_write_header(ar, entry) != ARCHIVE_OK) {
		archive_entry_free(entry);
		return archive_errno(ar);
	}
	if (archive_write_data(ar, buf, buflen) != ARCHIVE_OK) {
		archive_entry_free(entry);
		return archive_errno(ar);
	}
	archive_write_finish_entry(ar);
	archive_entry_free(entry);

	return 0;
}
Ejemplo n.º 23
0
static int append_path_recursively(const char *pathname, struct archive *a) {
	int error = 0;
	
	struct archive_entry *entry = archive_entry_new();
	archive_entry_set_pathname(entry, pathname);
	struct stat st;
	stat(pathname, &st);
	archive_entry_copy_stat(entry, &st);
	// if we want to add uname/gname, we should do something like:
	// archive_entry_copy_uname(entry, uname);
	// archive_entry_copy_gname(entry, gname);
	archive_write_header(a, entry);
	int fd = open(pathname, O_RDONLY);
	ssize_t amt = 0;
	static char buffer[16*1024];
	while ((amt = read(fd, buffer, sizeof(buffer))) > 0) {
		archive_write_data(a, buffer, amt);
	}
	close(fd);
	archive_entry_free(entry);
	
	if (S_ISLNK(st.st_mode)) { } // don't recurse into symbolic link dirs
	else if (S_ISDIR(st.st_mode)) {
		DIR *dir = opendir(pathname);
		struct dirent *dirent = NULL;
		while ((dirent = readdir(dir))) {
			if (strcmp(dirent->d_name, ".") == 0 ||
				strcmp(dirent->d_name, "..") == 0) { continue; }
			
			char *subpath = NULL;
			asprintf(&subpath, "%s/%s", pathname, dirent->d_name);
			error = append_path_recursively(subpath, a);
			free(subpath);
			
			if (error != 0) { break; }
		}
	}
	
	return error;
}
Ejemplo n.º 24
0
int test2_with_write_callbacks()
{
	struct archive *a = archive_write_new();
	archive_write_set_format_zip(a);
	int ret = archive_write_open(a, NULL, myopen, mywrite, myclose);

	// add a file
	struct archive_entry  *entry = archive_entry_new();
	archive_entry_set_pathname(entry, "123.d/hello.txt");
	archive_entry_set_size(entry, 5);
	archive_entry_set_filetype(entry, AE_IFREG);
	archive_entry_set_perm(entry, 0644);
	ret = archive_write_header(a, entry);
	fprintf(stderr, "archive_write_header: ret=%d\n", ret);
	la_ssize_t n = archive_write_data(a, "world", 5);
	fprintf(stderr, "archive_write_data: n=%d, error=%s\n", n, archive_error_string(a));

	archive_entry_free(entry);

	ret = archive_write_free(a);
	fprintf(stderr, "archive_write_free: ret=%d, error=%s\n", ret, archive_error_string(a));
}
Ejemplo n.º 25
0
/*
 * Do not translate CP1251 into CP866 if non Windows platform.
 */
static void
test_zip_filename_encoding_ru_RU_CP1251(void)
{
  	struct archive *a;
  	struct archive_entry *entry;
	char buff[4096];
	size_t used;

	if (NULL == setlocale(LC_ALL, "ru_RU.CP1251")) {
		skipping("Russian_Russia locale not available on this system.");
		return;
	}

	/*
	 * Verify that CP1251 filenames are not translated into any
	 * other character-set, in particular, CP866.
	 */
	a = archive_write_new();
	assertEqualInt(ARCHIVE_OK, archive_write_set_format_zip(a));
	assertEqualInt(ARCHIVE_OK,
	    archive_write_open_memory(a, buff, sizeof(buff), &used));

	entry = archive_entry_new2(a);
	/* Set a CP1251 filename. */
	archive_entry_set_pathname(entry, "\xEF\xF0\xE8");
	archive_entry_set_filetype(entry, AE_IFREG);
	archive_entry_set_size(entry, 0);
	assertEqualInt(ARCHIVE_OK, archive_write_header(a, entry));
	archive_entry_free(entry);
	assertEqualInt(ARCHIVE_OK, archive_write_free(a));

	/* A bit 11 of general purpose flag should be 0,
	 * which indicates the filename charset is unknown. */
	assertEqualInt(0, buff[7]);
	/* Above three characters in CP1251 should not translate into
	 * any other character-set. */
	assertEqualMem(buff + 30, "\xEF\xF0\xE8", 3);
}
Ejemplo n.º 26
0
void archive_add(char* from, char* to){
	struct archive_entry *entry;
	char buff[8192];
	int len;
	int fd;
	struct stat s;

	if(stat(from, &s)==-1)
		show_errno();

	entry = archive_entry_new(); // Note 2
	archive_entry_set_pathname(entry, to);
	archive_entry_copy_stat(entry,&s);
	archive_write_header(g_archive, entry);
	fd = open(from, O_RDONLY);
	len = read(fd, buff, sizeof(buff));
	while ( len > 0 ) {
	    archive_write_data(g_archive, buff, len);
	    len = read(fd, buff, sizeof(buff));
	}
	close(fd);
	archive_entry_free(entry);
}
Ejemplo n.º 27
0
// This function will create a gzipped tar file (outname)
// which contains the files matched by the function pattern_match.
// Pattern_match should return 0 on no match and 1 on match.
int create_archive(char *outname, char *path, 
                   const std::vector<std::string> &filenames)
{
    struct archive *a;
    struct archive_entry *entry;
    struct stat st;
    char buff[BUFFER_SIZE];
    int len;
    int fd;

    a = archive_write_new();
    archive_write_set_compression_gzip(a);
    archive_write_set_format_pax_restricted(a);
    archive_write_open_filename(a, outname);

    for (unsigned int i=0;i<filenames.size();i++) {
        stat(filenames[i].c_str(), &st);
        entry = archive_entry_new();
        archive_entry_set_pathname(entry, filenames[i].c_str());
        archive_entry_set_size(entry, st.st_size);
        archive_entry_set_filetype(entry, AE_IFREG);
        archive_entry_set_perm(entry, 0644);
        archive_write_header(a, entry);
        fd = open(filenames[i].c_str(), O_RDONLY);
        len = read(fd, buff, sizeof(buff));
        while (len > 0) {
            archive_write_data(a, buff, len);
            len = read(fd, buff, sizeof(buff));
        }
        close(fd);
    }

    archive_write_close(a);
    archive_write_finish(a);

    return 0;
}
Ejemplo n.º 28
0
/*
 * Sparse test without directory traversals.
 */
static void
verify_sparse_file2(struct archive *a, const char *path,
    const struct sparse *sparse, int blocks, int preopen)
{
	struct archive_entry *ae;
	int fd;

	(void)sparse; /* UNUSED */
	assert((ae = archive_entry_new()) != NULL);
	archive_entry_set_pathname(ae, path);
	if (preopen)
		fd = open(path, O_RDONLY | O_BINARY);
	else
		fd = -1;
	assertEqualIntA(a, ARCHIVE_OK,
	    archive_read_disk_entry_from_file(a, ae, fd, NULL));
	if (fd >= 0)
		close(fd);
	/* Verify the number of holes only, not its offset nor its
	 * length because those alignments are deeply dependence on
	 * its filesystem. */ 
	assertEqualInt(blocks, archive_entry_sparse_count(ae));
	archive_entry_free(ae);
}
Ejemplo n.º 29
0
static int
archive_write_zip_header(struct archive_write *a, struct archive_entry *entry)
{
	struct zip *zip;
	uint8_t h[SIZE_LOCAL_FILE_HEADER];
	uint8_t e[SIZE_EXTRA_DATA_LOCAL];
	uint8_t *d;
	struct zip_file_header_link *l;
	struct archive_string_conv *sconv;
	int ret, ret2 = ARCHIVE_OK;
	int64_t size;
	mode_t type;

	/* Entries other than a regular file or a folder are skipped. */
	type = archive_entry_filetype(entry);
	if (type != AE_IFREG && type != AE_IFDIR && type != AE_IFLNK) {
		archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
		    "Filetype not supported");
		return ARCHIVE_FAILED;
	};

	/* Directory entries should have a size of 0. */
	if (type == AE_IFDIR)
		archive_entry_set_size(entry, 0);

	zip = a->format_data;
	/* Setup default conversion. */
	if (zip->opt_sconv == NULL && !zip->init_default_conversion) {
		zip->sconv_default =
		    archive_string_default_conversion_for_write(&(a->archive));
		zip->init_default_conversion = 1;
	}

	if (zip->flags == 0) {
		/* Initialize the general purpose flags. */
		zip->flags = ZIP_FLAGS;
		if (zip->opt_sconv != NULL) {
			if (strcmp(archive_string_conversion_charset_name(
			    zip->opt_sconv), "UTF-8") == 0)
				zip->flags |= ZIP_FLAGS_UTF8_NAME;
#if HAVE_NL_LANGINFO
		} else if (strcmp(nl_langinfo(CODESET), "UTF-8") == 0) {
			zip->flags |= ZIP_FLAGS_UTF8_NAME;
#endif
		}
	}
	d = zip->data_descriptor;
	size = archive_entry_size(entry);
	zip->remaining_data_bytes = size;

	/* Append archive entry to the central directory data. */
	l = (struct zip_file_header_link *) malloc(sizeof(*l));
	if (l == NULL) {
		archive_set_error(&a->archive, ENOMEM,
		    "Can't allocate zip header data");
		return (ARCHIVE_FATAL);
	}
#if defined(_WIN32) && !defined(__CYGWIN__)
	/* Make sure the path separators in pahtname, hardlink and symlink
	 * are all slash '/', not the Windows path separator '\'. */
	l->entry = __la_win_entry_in_posix_pathseparator(entry);
	if (l->entry == entry)
		l->entry = archive_entry_clone(entry);
#else
	l->entry = archive_entry_clone(entry);
#endif
	if (l->entry == NULL) {
		archive_set_error(&a->archive, ENOMEM,
		    "Can't allocate zip header data");
		free(l);
		return (ARCHIVE_FATAL);
	}
	l->flags = zip->flags;
	if (zip->opt_sconv != NULL)
		sconv = zip->opt_sconv;
	else
		sconv = zip->sconv_default;
	if (sconv != NULL) {
		const char *p;
		size_t len;

		if (archive_entry_pathname_l(entry, &p, &len, sconv) != 0) {
			if (errno == ENOMEM) {
				archive_entry_free(l->entry);
				free(l);
				archive_set_error(&a->archive, ENOMEM,
				    "Can't allocate memory for Pathname");
				return (ARCHIVE_FATAL);
			}
			archive_set_error(&a->archive,
			    ARCHIVE_ERRNO_FILE_FORMAT,
			    "Can't translate Pathname '%s' to %s",
			    archive_entry_pathname(entry),
			    archive_string_conversion_charset_name(sconv));
			ret2 = ARCHIVE_WARN;
		}
		if (len > 0)
			archive_entry_set_pathname(l->entry, p);

		/*
		 * Although there is no character-set regulation for Symlink,
		 * it is suitable to convert a character-set of Symlinke to
		 * what those of the Pathname has been converted to.
		 */
		if (type == AE_IFLNK) {
			if (archive_entry_symlink_l(entry, &p, &len, sconv)) {
				if (errno == ENOMEM) {
					archive_entry_free(l->entry);
					free(l);
					archive_set_error(&a->archive, ENOMEM,
					    "Can't allocate memory "
					    " for Symlink");
					return (ARCHIVE_FATAL);
				}
				/*
				 * Even if the strng conversion failed,
				 * we should not report the error since
				 * thre is no regulation for.
				 */
			} else if (len > 0)
				archive_entry_set_symlink(l->entry, p);
		}
	}
	/* If all characters in a filename are ASCII, Reset UTF-8 Name flag. */
	if ((l->flags & ZIP_FLAGS_UTF8_NAME) != 0 &&
	    is_all_ascii(archive_entry_pathname(l->entry)))
		l->flags &= ~ZIP_FLAGS_UTF8_NAME;

	/* Initialize the CRC variable and potentially the local crc32(). */
	l->crc32 = crc32(0, NULL, 0);
	if (type == AE_IFLNK) {
		const char *p = archive_entry_symlink(l->entry);
		if (p != NULL)
			size = strlen(p);
		else
			size = 0;
		zip->remaining_data_bytes = 0;
		archive_entry_set_size(l->entry, size);
		l->compression = COMPRESSION_STORE;
		l->compressed_size = size;
	} else {
		l->compression = zip->compression;
		l->compressed_size = 0;
	}
	l->next = NULL;
	if (zip->central_directory == NULL) {
		zip->central_directory = l;
	} else {
		zip->central_directory_end->next = l;
	}
	zip->central_directory_end = l;

	/* Store the offset of this header for later use in central
	 * directory. */
	l->offset = zip->written_bytes;

	memset(h, 0, sizeof(h));
	archive_le32enc(&h[LOCAL_FILE_HEADER_SIGNATURE],
		ZIP_SIGNATURE_LOCAL_FILE_HEADER);
	archive_le16enc(&h[LOCAL_FILE_HEADER_VERSION], ZIP_VERSION_EXTRACT);
	archive_le16enc(&h[LOCAL_FILE_HEADER_FLAGS], l->flags);
	archive_le16enc(&h[LOCAL_FILE_HEADER_COMPRESSION], l->compression);
	archive_le32enc(&h[LOCAL_FILE_HEADER_TIMEDATE],
		dos_time(archive_entry_mtime(entry)));
	archive_le16enc(&h[LOCAL_FILE_HEADER_FILENAME_LENGTH],
		(uint16_t)path_length(l->entry));

	switch (l->compression) {
	case COMPRESSION_STORE:
		/* Setting compressed and uncompressed sizes even when
		 * specification says to set to zero when using data
		 * descriptors. Otherwise the end of the data for an
		 * entry is rather difficult to find. */
		archive_le32enc(&h[LOCAL_FILE_HEADER_COMPRESSED_SIZE],
		    (uint32_t)size);
		archive_le32enc(&h[LOCAL_FILE_HEADER_UNCOMPRESSED_SIZE],
		    (uint32_t)size);
		break;
#ifdef HAVE_ZLIB_H
	case COMPRESSION_DEFLATE:
		archive_le32enc(&h[LOCAL_FILE_HEADER_UNCOMPRESSED_SIZE],
		    (uint32_t)size);

		zip->stream.zalloc = Z_NULL;
		zip->stream.zfree = Z_NULL;
		zip->stream.opaque = Z_NULL;
		zip->stream.next_out = zip->buf;
		zip->stream.avail_out = (uInt)zip->len_buf;
		if (deflateInit2(&zip->stream, Z_DEFAULT_COMPRESSION,
		    Z_DEFLATED, -15, 8, Z_DEFAULT_STRATEGY) != Z_OK) {
			archive_set_error(&a->archive, ENOMEM,
			    "Can't init deflate compressor");
			return (ARCHIVE_FATAL);
		}
		break;
#endif
	}

	/* Formatting extra data. */
	archive_le16enc(&h[LOCAL_FILE_HEADER_EXTRA_LENGTH], sizeof(e));
	archive_le16enc(&e[EXTRA_DATA_LOCAL_TIME_ID],
		ZIP_SIGNATURE_EXTRA_TIMESTAMP);
	archive_le16enc(&e[EXTRA_DATA_LOCAL_TIME_SIZE], 1 + 4 * 3);
	e[EXTRA_DATA_LOCAL_TIME_FLAG] = 0x07;
	archive_le32enc(&e[EXTRA_DATA_LOCAL_MTIME],
	    (uint32_t)archive_entry_mtime(entry));
	archive_le32enc(&e[EXTRA_DATA_LOCAL_ATIME],
	    (uint32_t)archive_entry_atime(entry));
	archive_le32enc(&e[EXTRA_DATA_LOCAL_CTIME],
	    (uint32_t)archive_entry_ctime(entry));

	archive_le16enc(&e[EXTRA_DATA_LOCAL_UNIX_ID],
		ZIP_SIGNATURE_EXTRA_NEW_UNIX);
	archive_le16enc(&e[EXTRA_DATA_LOCAL_UNIX_SIZE], 1 + (1 + 4) * 2);
	e[EXTRA_DATA_LOCAL_UNIX_VERSION] = 1;
	e[EXTRA_DATA_LOCAL_UNIX_UID_SIZE] = 4;
	archive_le32enc(&e[EXTRA_DATA_LOCAL_UNIX_UID],
		(uint32_t)archive_entry_uid(entry));
	e[EXTRA_DATA_LOCAL_UNIX_GID_SIZE] = 4;
	archive_le32enc(&e[EXTRA_DATA_LOCAL_UNIX_GID],
		(uint32_t)archive_entry_gid(entry));

	archive_le32enc(&d[DATA_DESCRIPTOR_UNCOMPRESSED_SIZE],
	    (uint32_t)size);

	ret = __archive_write_output(a, h, sizeof(h));
	if (ret != ARCHIVE_OK)
		return (ARCHIVE_FATAL);
	zip->written_bytes += sizeof(h);

	ret = write_path(l->entry, a);
	if (ret <= ARCHIVE_OK)
		return (ARCHIVE_FATAL);
	zip->written_bytes += ret;

	ret = __archive_write_output(a, e, sizeof(e));
	if (ret != ARCHIVE_OK)
		return (ARCHIVE_FATAL);
	zip->written_bytes += sizeof(e);

	if (type == AE_IFLNK) {
		const unsigned char *p;

		p = (const unsigned char *)archive_entry_symlink(l->entry);
		ret = __archive_write_output(a, p, (size_t)size);
		if (ret != ARCHIVE_OK)
			return (ARCHIVE_FATAL);
		zip->written_bytes += size;
		l->crc32 = crc32(l->crc32, p, (unsigned)size);
	}

	if (ret2 != ARCHIVE_OK)
		return (ret2);
	return (ARCHIVE_OK);
}
Ejemplo n.º 30
0
Installer::ProceedState RomInstaller::on_checked_device()
{
    // /sbin is not going to be populated with anything useful in a normal boot
    // image. We can almost guarantee that a recovery image is going to be
    // installed though, so we'll open the recovery partition with libmbp and
    // extract its /sbin with libarchive into the chroot's /sbin.

    std::string block_dev(_recovery_block_dev);
    mbp::BootImage bi;
    mbp::CpioFile innerCpio;
    const unsigned char *ramdisk_data;
    std::size_t ramdisk_size;
    bool using_boot = false;

    // Check if the device has a combined boot/recovery partition. If the
    // FOTAKernel partition is listed, it will be used instead of the combined
    // ramdisk from the boot image
    bool combined = mb_device_flags(_device)
            & FLAG_HAS_COMBINED_BOOT_AND_RECOVERY;
    if (combined && block_dev.empty()) {
        block_dev = _boot_block_dev;
        using_boot = true;
    }

    if (block_dev.empty()) {
        display_msg("Could not determine the recovery block device");
        return ProceedState::Fail;
    }

    if (!bi.loadFile(block_dev)) {
        display_msg("Failed to load recovery partition image");
        return ProceedState::Fail;
    }

    // Load ramdisk
    bi.ramdiskImageC(&ramdisk_data, &ramdisk_size);

    if (using_boot) {
        if (!innerCpio.load(ramdisk_data, ramdisk_size)) {
            display_msg("Failed to load ramdisk from combined boot image");
            return ProceedState::Fail;
        }

        if (!innerCpio.contentsC("sbin/ramdisk-recovery.cpio",
                                 &ramdisk_data, &ramdisk_size)) {
            display_msg("Could not find recovery ramdisk in combined boot image");
            return ProceedState::Fail;
        }
    }

    autoclose::archive in(archive_read_new(), archive_read_free);
    autoclose::archive out(archive_write_disk_new(), archive_write_free);

    if (!in || !out) {
        LOGE("Out of memory");
        return ProceedState::Fail;
    }

    archive_entry *entry;

    // Set up input
    archive_read_support_filter_gzip(in.get());
    archive_read_support_filter_lzop(in.get());
    archive_read_support_filter_lz4(in.get());
    archive_read_support_filter_lzma(in.get());
    archive_read_support_filter_xz(in.get());
    archive_read_support_format_cpio(in.get());

    int ret = archive_read_open_memory(in.get(),
            const_cast<unsigned char *>(ramdisk_data), ramdisk_size);
    if (ret != ARCHIVE_OK) {
        LOGW("Failed to open recovery ramdisk: %s",
             archive_error_string(in.get()));
        return ProceedState::Fail;
    }

    // Set up output
    archive_write_disk_set_options(out.get(),
                                   ARCHIVE_EXTRACT_ACL |
                                   ARCHIVE_EXTRACT_FFLAGS |
                                   ARCHIVE_EXTRACT_PERM |
                                   ARCHIVE_EXTRACT_SECURE_NODOTDOT |
                                   ARCHIVE_EXTRACT_SECURE_SYMLINKS |
                                   ARCHIVE_EXTRACT_TIME |
                                   ARCHIVE_EXTRACT_UNLINK |
                                   ARCHIVE_EXTRACT_XATTR);

    while ((ret = archive_read_next_header(in.get(), &entry)) == ARCHIVE_OK) {
        std::string path = archive_entry_pathname(entry);

        if (path == "default.prop") {
            path = "default.recovery.prop";
        } else if (!util::starts_with(path, "sbin/")) {
            continue;
        }

        LOGE("Copying from recovery: %s", path.c_str());

        archive_entry_set_pathname(entry, in_chroot(path).c_str());

        if (util::libarchive_copy_header_and_data(
                in.get(), out.get(), entry) != ARCHIVE_OK) {
            return ProceedState::Fail;
        }

        archive_entry_set_pathname(entry, path.c_str());
    }

    if (ret != ARCHIVE_EOF) {
        LOGE("Archive extraction ended without reaching EOF: %s",
             archive_error_string(in.get()));
        return ProceedState::Fail;
    }

    // Create fake /etc/fstab file to please installers that read the file
    std::string etc_fstab(in_chroot("/etc/fstab"));
    if (access(etc_fstab.c_str(), R_OK) < 0 && errno == ENOENT) {
        autoclose::file fp(autoclose::fopen(etc_fstab.c_str(), "w"));
        if (fp) {
            auto system_devs = mb_device_system_block_devs(_device);
            auto cache_devs = mb_device_cache_block_devs(_device);
            auto data_devs = mb_device_data_block_devs(_device);

            // Set block device if it's provided and non-empty
            const char *system_dev =
                    system_devs && system_devs[0] && system_devs[0][0]
                    ? system_devs[0] : "dummy";
            const char *cache_dev =
                    cache_devs && cache_devs[0] && cache_devs[0][0]
                    ? cache_devs[0] : "dummy";
            const char *data_dev =
                    data_devs && data_devs[0] && data_devs[0][0]
                    ? data_devs[0] : "dummy";

            fprintf(fp.get(), "%s /system ext4 rw 0 0\n", system_dev);
            fprintf(fp.get(), "%s /cache ext4 rw 0 0\n", cache_dev);
            fprintf(fp.get(), "%s /data ext4 rw 0 0\n", data_dev);
        }
    }

    // Load recovery properties
    util::file_get_all_properties(
            in_chroot("/default.recovery.prop"), &_recovery_props);

    return ProceedState::Continue;
}