Beispiel #1
0
static void
extract(const char *filename, int do_extract, int flags)
{
	struct archive *a;
	struct archive *ext;
	struct archive_entry *entry;
	int r;

	a = archive_read_new();
	ext = archive_write_disk_new();
	archive_write_disk_set_options(ext, flags);
	/*
	 * Note: archive_write_disk_set_standard_lookup() is useful
	 * here, but it requires library routines that can add 500k or
	 * more to a static executable.
	 */
	archive_read_support_format_tar(a);
	/*
	 * On my system, enabling other archive formats adds 20k-30k
	 * each.  Enabling gzip decompression adds about 20k.
	 * Enabling bzip2 is more expensive because the libbz2 library
	 * isn't very well factored.
	 */
	if (filename != NULL && strcmp(filename, "-") == 0)
		filename = NULL;
	if ((r = archive_read_open_filename(a, filename, 10240)))
		fail("archive_read_open_filename()",
		    archive_error_string(a), r);
	for (;;) {
		r = archive_read_next_header(a, &entry);
		if (r == ARCHIVE_EOF)
			break;
		if (r != ARCHIVE_OK)
			fail("archive_read_next_header()",
			    archive_error_string(a), 1);
		if (verbose && do_extract)
			msg("x ");
		if (verbose || !do_extract)
			msg(archive_entry_pathname(entry));
		if (do_extract) {
			r = archive_write_header(ext, entry);
			if (r != ARCHIVE_OK)
				warn("archive_write_header()",
				    archive_error_string(ext));
			else {
				copy_data(a, ext);
				r = archive_write_finish_entry(ext);
				if (r != ARCHIVE_OK)
					fail("archive_write_finish_entry()",
					    archive_error_string(ext), 1);
			}

		}
		if (verbose || !do_extract)
			msg("\n");
	}
	archive_read_close(a);
	archive_read_free(a);
	exit(0);
}
Beispiel #2
0
int Tarball::install () {
  archive_entry *entry;
  int r;

  archive* a = archive_read_new();
  archive_read_support_format_all(a);
  archive_read_support_filter_all(a);

  archive* ext = archive_write_disk_new();
  const int flags = ARCHIVE_EXTRACT_TIME | ARCHIVE_EXTRACT_PERM |
    ARCHIVE_EXTRACT_ACL | ARCHIVE_EXTRACT_FFLAGS;
  archive_write_disk_set_options(ext, flags);
  archive_write_disk_set_standard_lookup(ext);

  const std::string subdir = "deps";
  const std::string filename = subdir + "/" + basename(this->location);
  printf("Unpacking archive %s\n", filename.c_str());
  if ((r = archive_read_open_filename(a,filename.c_str(), 10240))) {
    fprintf(stderr, "Error opening archive:\n%s\n", archive_error_string(a));
    return -1;
  }
  for (;;) {
    r = archive_read_next_header(a, &entry);
    if (r == ARCHIVE_EOF) {
      break;
    }
    if (r < ARCHIVE_OK) {
      fprintf(stderr, "%s\n", archive_error_string(a));
    }
    if (r < ARCHIVE_WARN) {
      return -1;
    }
    rewrite_subdir(entry, subdir);
    r = archive_write_header(ext, entry);
    if (r < ARCHIVE_OK) {
      fprintf(stderr, "%s\n", archive_error_string(ext));
    } else if (archive_entry_size(entry) > 0) {
      r = copy_data(a, ext);
      if (r < ARCHIVE_OK) {
        fprintf(stderr, "%s\n", archive_error_string(ext));
      }
      if (r < ARCHIVE_WARN) {
        return -1;
      }
    }
    r = archive_write_finish_entry(ext);
    if (r < ARCHIVE_OK) {
      fprintf(stderr, "%s\n", archive_error_string(ext));
    }
    if (r < ARCHIVE_WARN) {
      return -1;
    }
  }
  archive_read_close(a);
  archive_read_free(a);
  archive_write_close(ext);
  archive_write_free(ext);

  return 0;
};
Beispiel #3
0
int
packing_init(struct packing **pack, const char *path, pkg_formats format)
{
	char archive_path[MAXPATHLEN];
	const char *ext;

	assert(pack != NULL);

	if ((*pack = calloc(1, sizeof(struct packing))) == NULL) {
		pkg_emit_errno("calloc", "packing");
		return (EPKG_FATAL);
	}

	(*pack)->aread = archive_read_disk_new();
	archive_read_disk_set_standard_lookup((*pack)->aread);
	archive_read_disk_set_symlink_physical((*pack)->aread);

	if (!is_dir(path)) {
		(*pack)->pass = false;
		(*pack)->awrite = archive_write_new();
		archive_write_set_format_pax_restricted((*pack)->awrite);
		ext = packing_set_format((*pack)->awrite, format);
		if (ext == NULL) {
			archive_read_close((*pack)->aread);
			archive_read_free((*pack)->aread);
			archive_write_close((*pack)->awrite);
			archive_write_free((*pack)->awrite);
			*pack = NULL;
			return EPKG_FATAL; /* error set by _set_format() */
		}
		snprintf(archive_path, sizeof(archive_path), "%s.%s", path,
		    ext);

		pkg_debug(1, "Packing to file '%s'", archive_path);
		if (archive_write_open_filename(
		    (*pack)->awrite, archive_path) != ARCHIVE_OK) {
			pkg_emit_errno("archive_write_open_filename",
			    archive_path);
			archive_read_close((*pack)->aread);
			archive_read_free((*pack)->aread);
			archive_write_close((*pack)->awrite);
			archive_write_free((*pack)->awrite);
			*pack = NULL;
			return EPKG_FATAL;
		}
	} else { /* pass mode directly write to the disk */
		pkg_debug(1, "Packing to directory '%s' (pass mode)", path);
		(*pack)->pass = true;
		(*pack)->awrite = archive_write_disk_new();
		archive_write_disk_set_options((*pack)->awrite,
		    EXTRACT_ARCHIVE_FLAGS);
	}

	(*pack)->resolver = archive_entry_linkresolver_new();
	archive_entry_linkresolver_set_strategy((*pack)->resolver,
	    ARCHIVE_FORMAT_TAR_PAX_RESTRICTED);

	return (EPKG_OK);
}
Beispiel #4
0
/*
 * memory to file
 */
int archive_extract_file3( void *arch_buff, size_t arch_size, const char *src, char *dest )
{
    int                     flags;     
    const char              *filename;
    struct archive          *arch_r = NULL, *arch_w = NULL;
    struct archive_entry    *entry;

    if( !src || !dest )
        return -1;

    arch_r = archive_read_new();
    archive_read_support_format_all( arch_r );
    archive_read_support_compression_all( arch_r );

    if( archive_read_open_memory( arch_r, arch_buff, arch_size ) != ARCHIVE_OK )
        goto errout;

    while( archive_read_next_header( arch_r, &entry ) == ARCHIVE_OK ) 
    {
        filename = archive_entry_pathname( entry );
		if( fnmatch( src, filename, FNM_PATHNAME | FNM_PERIOD ) )
		{
			if( archive_read_data_skip( arch_r ) != ARCHIVE_OK )
            {
                goto errout;
            }
		}
        else
        {
#ifdef DEBUG
            printf("extract:%s\n", filename );
#endif

            flags = ARCHIVE_EXTRACT_TIME | ARCHIVE_EXTRACT_PERM | ARCHIVE_EXTRACT_ACL | ARCHIVE_EXTRACT_FFLAGS;
            arch_w = archive_write_disk_new();
            archive_write_disk_set_options( arch_w, flags );
            archive_write_disk_set_standard_lookup( arch_w );
            archive_entry_set_pathname( entry, dest );

            if( archive_read_extract2( arch_r, entry, arch_w ) != ARCHIVE_OK ) 
                goto errout;

            archive_write_finish( arch_w );
        }
    }

    archive_read_finish( arch_r );
    return 0;

errout:
#ifdef DEBUG
    fprintf( stderr, "%s\n", archive_error_string( arch_r ) );
#endif
    if( arch_r )
        archive_read_finish( arch_r );
    if( arch_w )
        archive_write_finish( arch_w );
    return -1;
}
Beispiel #5
0
int extract_archive(const char* filename, const char* to_path) {
  struct archive* a;
  struct archive* ext;
  struct archive_entry* entry;
  int r;
  int flags = ARCHIVE_EXTRACT_TIME | ARCHIVE_EXTRACT_PERM | ARCHIVE_EXTRACT_ACL | ARCHIVE_EXTRACT_FFLAGS;

  a = archive_read_new();
  ext = archive_write_disk_new();
  archive_write_disk_set_options(ext, flags);
  archive_write_disk_set_standard_lookup(ext);

  archive_read_support_format_all(a);
  archive_read_support_compression_all(a);

  if(filename != NULL && strcmp(filename, "-") == 0) {
    filename = NULL;
  }
  if((r = archive_read_open_file(a, filename, 10240))) {
    printf("archive_read_open_file(): %s\n", archive_error_string(a));
    return r;
  }
  for(;;) {
    r = archive_read_next_header(a, &entry);
    if(r == ARCHIVE_EOF) {
      break;
    }
    if(r != ARCHIVE_OK) {
      printf("archive_read_next_header(): %s\n", archive_error_string(a));
      return 0;
    }

    // rewrite pathname
    const char* path = archive_entry_pathname(entry);
    char new_path[PATH_MAX + 1];
    sprintf(new_path, "%s/%s", to_path, path + (strncmp(path, "rootfs/", 7) == 0 ? 7 : 0));
    archive_entry_set_pathname(entry, new_path);

    r = archive_write_header(ext, entry);
    if(r != ARCHIVE_OK) {
      printf("archive_write_header(): %s\n", archive_error_string(ext));
    } else {
      copy_data(a, ext);
      if(r != ARCHIVE_OK) {
        printf("archive_write_finish_entry(): %s\n", archive_error_string(ext));
        return 0;
      }

    }
    r = archive_write_finish_entry(ext);

  }
  archive_read_close(a);
  archive_read_finish(a);
  archive_write_close(ext);
  archive_write_finish(ext);
  return 1;
}
Beispiel #6
0
static void extract_recovery(char *ramdisk_path)
{
    // Delete everything in the current root
    DIR *root = opendir("/");
    struct dirent *dp;
    while ((dp = readdir(root)) != NULL)
    {
        unlink(dp->d_name);
    }
    closedir(root);

    // Open the ramdisk
    struct archive *a = archive_read_new();
    archive_read_support_filter_lzma(a);
    archive_read_support_format_cpio(a);
    if (archive_read_open_filename(a, ramdisk_path, 4096) == ARCHIVE_OK)
    {
        // Set up the writer
        struct archive *ext = archive_write_disk_new();
        archive_write_disk_set_options(ext, ARCHIVE_EXTRACT_UNLINK | ARCHIVE_EXTRACT_PERM);
        chdir("/");

        while (1)
        {
            struct archive_entry *entry;

            // Read the next file
            if (archive_read_next_header(a, &entry) == ARCHIVE_EOF)
                break;

            // Create the file
            archive_write_header(ext, entry);

            // If the file has data to write...
            if (!archive_entry_size_is_set(entry) || archive_entry_size(entry) > 0)
            {
                const void *block;
                size_t size;
                int64_t offset;

                // Write the blocks until EOF
                while (1)
                {
                    if (archive_read_data_block(a, &block, &size, &offset) == ARCHIVE_EOF)
                        break;
                    archive_write_data_block(ext, block, size, offset);
                }
            }
        }

        archive_write_free(ext);
    }

    archive_read_free(a);
}
Beispiel #7
0
int
archive_read_extract(struct archive *_a, struct archive_entry *entry, int flags)
{
	struct extract *extract;

	extract = get_extract((struct archive_read *)_a);
	if (extract == NULL)
		return (ARCHIVE_FATAL);
	archive_write_disk_set_options(extract->ad, flags);
	return (archive_read_extract2(_a, entry, extract->ad));
}
Beispiel #8
0
static void
mode_pass(struct cpio *cpio, const char *destdir)
{
	struct lafe_line_reader *lr;
	const char *p;
	int r;

	/* Ensure target dir has a trailing '/' to simplify path surgery. */
	cpio->destdir = malloc(strlen(destdir) + 8);
	strcpy(cpio->destdir, destdir);
	if (destdir[strlen(destdir) - 1] != '/')
		strcat(cpio->destdir, "/");

	cpio->archive = archive_write_disk_new();
	if (cpio->archive == NULL)
		lafe_errc(1, 0, "Failed to allocate archive object");
	r = archive_write_disk_set_options(cpio->archive, cpio->extract_flags);
	if (r != ARCHIVE_OK)
		lafe_errc(1, 0, "%s", archive_error_string(cpio->archive));
	cpio->linkresolver = archive_entry_linkresolver_new();
	archive_write_disk_set_standard_lookup(cpio->archive);

	cpio->archive_read_disk = archive_read_disk_new();
	if (cpio->archive_read_disk == NULL)
		lafe_errc(1, 0, "Failed to allocate archive object");
	if (cpio->option_follow_links)
		archive_read_disk_set_symlink_logical(cpio->archive_read_disk);
	else
		archive_read_disk_set_symlink_physical(cpio->archive_read_disk);
	archive_read_disk_set_standard_lookup(cpio->archive_read_disk);

	lr = lafe_line_reader("-", cpio->option_null);
	while ((p = lafe_line_reader_next(lr)) != NULL)
		file_to_archive(cpio, p);
	lafe_line_reader_free(lr);

	archive_entry_linkresolver_free(cpio->linkresolver);
	r = archive_write_close(cpio->archive);
	if (cpio->dot)
		fprintf(stderr, "\n");
	if (r != ARCHIVE_OK)
		lafe_errc(1, 0, "%s", archive_error_string(cpio->archive));

	if (!cpio->quiet) {
		int64_t blocks =
			(archive_filter_bytes(cpio->archive, 0) + 511)
			/ 512;
		fprintf(stderr, "%lu %s\n", (unsigned long)blocks,
		    blocks == 1 ? "block" : "blocks");
	}

	archive_write_free(cpio->archive);
}
Beispiel #9
0
static void set_up_output(archive *out)
{
    archive_write_disk_set_options(out,
                                   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);
}
Beispiel #10
0
// Based on libarchive's public example code.
// https://github.com/libarchive/libarchive/wiki/Examples#wiki-Constructing_Objects_On_Disk
void GuiZipper::unpackFile(const char *zipFile, const char *outputDir)
    throw (ZipperException*) {
  // TODO: use archive_write_disk_open instead (if/when it exists)
  char cwd[4096];
  getcwd(cwd, 4096);
  char *absZipFile = fileManager_->getAbsFilePath(zipFile);
  platformstl::filesystem_traits<char> traits;
  traits.set_current_directory(outputDir);
  
  struct archive *a;
  struct archive *ext;
  struct archive_entry *entry;
  int flags;
  int r;
  
  flags = ARCHIVE_EXTRACT_TIME;
  flags |= ARCHIVE_EXTRACT_PERM;
  flags |= ARCHIVE_EXTRACT_ACL;
  flags |= ARCHIVE_EXTRACT_FFLAGS;
  
  a = archive_read_new();
  archive_read_support_format_tar(a);
  archive_read_support_filter_gzip(a);
  ext = archive_write_disk_new();
  archive_write_disk_set_options(ext, flags);
  archive_write_disk_set_standard_lookup(ext);
  r = archive_read_open_filename(a, absZipFile, 10240);
  checkForErrors("Error opening archive for reading", a, r);
  for (;;) {
    r = archive_read_next_header(a, &entry);
    if (r == ARCHIVE_EOF) {
      break;
    }
    checkForErrors("Error reading next archive header", a, r);
    r = archive_write_header(ext, entry);
    checkForErrors("Error writing next archive header", a, r);
    copyData(a, ext, outputDir);
    r = archive_write_finish_entry(ext);
    checkForErrors("Error writing archive finish entry", a, r);
  }
  r = archive_read_close(a);
  checkForErrors("Error closing read archive", a, r);
  r = archive_read_free(a);
  checkForErrors("Error freeing read archive", a, r);
  r = archive_write_close(ext);
  checkForErrors("Error closing write archive", a, r);
  r = archive_write_free(ext);
  checkForErrors("Error freeing write archive", a, r);

  traits.set_current_directory(cwd);
  delete absZipFile;
}
Beispiel #11
0
static void
extract(const char *filename)
{
	struct archive *a;
	struct archive *ext;
	struct archive_entry *entry;
	int flags;
	int r;

	flags = ARCHIVE_EXTRACT_OWNER | ARCHIVE_EXTRACT_PERM;

	a = archive_read_new();
	archive_read_support_format_all(a);
#if ARCHIVE_VERSION_NUMBER < 3000000
	archive_read_support_compression_all(a);
#else
	archive_read_support_filter_all(a);
#endif
	ext = archive_write_disk_new();
	archive_write_disk_set_options(ext, flags);
	archive_write_disk_set_standard_lookup(ext);
#if ARCHIVE_VERSION_NUMBER < 3000000
	if ((r = archive_read_open_file(a, filename, 10240)))
		die("archive_read_open_file");
#else
	if ((r = archive_read_open_filename(a, filename, 10240)))
		die("archive_read_open_filename");
#endif
	for (;;) {
		r = archive_read_next_header(a, &entry);
		if (r == ARCHIVE_EOF)
			break;
		if (r < ARCHIVE_WARN)
			die(archive_error_string(a));
		r = archive_write_header(ext, entry);
		if (r == ARCHIVE_OK && archive_entry_size(entry) > 0) {
			r = copy_data(a, ext);
			if (r < ARCHIVE_WARN)
				die(archive_error_string(a));
		}
		r = archive_write_finish_entry(ext);
		if (r < ARCHIVE_WARN)
			die(archive_error_string(ext));
	}
	archive_read_close(a);
	archive_read_free(a);
	archive_write_close(ext);
	archive_write_free(ext);
}
Beispiel #12
0
void
tar_mode_x(struct bsdtar *bsdtar)
{
	struct archive *writer;

	writer = archive_write_disk_new();
	if (writer == NULL)
		lafe_errc(1, ENOMEM, "Cannot allocate disk writer object");
	if (!bsdtar->option_numeric_owner)
		archive_write_disk_set_standard_lookup(writer);
	archive_write_disk_set_options(writer, bsdtar->extract_flags);

	read_archive(bsdtar, 'x', writer);

	if (lafe_unmatched_inclusions_warn(bsdtar->matching, "Not found in archive") != 0)
		bsdtar->return_value = 1;
	archive_write_free(writer);
}
Beispiel #13
0
static void create_reg_file(struct archive_entry *ae, const char *msg)
{
	static const char data[]="abcdefghijklmnopqrstuvwxyz";
	struct archive *ad;

	/* Write the entry to disk. */
	assert((ad = archive_write_disk_new()) != NULL);
        archive_write_disk_set_options(ad, ARCHIVE_EXTRACT_TIME);
	failure("%s", msg);
	/*
	 * A touchy API design issue: archive_write_data() does (as of
	 * 2.4.12) enforce the entry size as a limit on the data
	 * written to the file.  This was not enforced prior to
	 * 2.4.12.  The change was prompted by the refined
	 * hardlink-restore semantics introduced at that time.  In
	 * short, libarchive needs to know whether a "hardlink entry"
	 * is going to overwrite the contents so that it can know
	 * whether or not to open the file for writing.  This implies
	 * that there is a fundamental semantic difference between an
	 * entry with a zero size and one with a non-zero size in the
	 * case of hardlinks and treating the hardlink case
	 * differently from the regular file case is just asking for
	 * trouble.  So, a zero size must always mean that no data
	 * will be accepted, which is consistent with the file size in
	 * the entry being a maximum size.
	 */
	archive_entry_set_size(ae, sizeof(data));
	archive_entry_set_mtime(ae, 123456789, 0);
	assertEqualIntA(ad, 0, archive_write_header(ad, ae));
	assertEqualInt(sizeof(data), archive_write_data(ad, data, sizeof(data)));
	assertEqualIntA(ad, 0, archive_write_finish_entry(ad));
#if ARCHIVE_VERSION_NUMBER < 2000000
	archive_write_finish(ad);
#else
	assertEqualInt(0, archive_write_finish(ad));
#endif
	/* Test the entries on disk. */
	assertIsReg(archive_entry_pathname(ae), archive_entry_mode(ae) & 0777);
	assertFileSize(archive_entry_pathname(ae), sizeof(data));
	/* test_write_disk_times has more detailed tests of this area. */
	assertFileMtime(archive_entry_pathname(ae), 123456789, 0);
        failure("No atime given, so atime should get set to current time");
	assertFileAtimeRecent(archive_entry_pathname(ae));
}
Beispiel #14
0
static void
mode_pass(struct cpio *cpio, const char *destdir)
{
	unsigned long blocks;
	struct line_reader *lr;
	const char *p;
	int r;

	/* Ensure target dir has a trailing '/' to simplify path surgery. */
	cpio->destdir = malloc(strlen(destdir) + 8);
	strcpy(cpio->destdir, destdir);
	if (destdir[strlen(destdir) - 1] != '/')
		strcat(cpio->destdir, "/");

	cpio->archive = archive_write_disk_new();
	if (cpio->archive == NULL)
		cpio_errc(1, 0, "Failed to allocate archive object");
	r = archive_write_disk_set_options(cpio->archive, cpio->extract_flags);
	if (r != ARCHIVE_OK)
		cpio_errc(1, 0, archive_error_string(cpio->archive));
	cpio->linkresolver = archive_entry_linkresolver_new();
	archive_write_disk_set_standard_lookup(cpio->archive);
	lr = process_lines_init("-", cpio->line_separator);
	while ((p = process_lines_next(lr)) != NULL)
		file_to_archive(cpio, p);
	process_lines_free(lr);

	archive_entry_linkresolver_free(cpio->linkresolver);
	r = archive_write_close(cpio->archive);
	if (r != ARCHIVE_OK)
		cpio_errc(1, 0, archive_error_string(cpio->archive));

	if (!cpio->quiet) {
		blocks = (archive_position_uncompressed(cpio->archive) + 511)
			      / 512;
		fprintf(stderr, "%lu %s\n", blocks,
		    blocks == 1 ? "block" : "blocks");
	}

	archive_write_finish(cpio->archive);
}
Beispiel #15
0
static struct archive *open_disk(int flags)
{
    struct archive *disk;
    int r;

    disk = archive_write_disk_new();
    if (!disk) {
        opkg_msg(ERROR, "Failed to create disk archive object.\n");
        return NULL;
    }

    r = archive_write_disk_set_options(disk, flags);
    if (r == ARCHIVE_WARN)
        opkg_msg(NOTICE, "Warning when setting disk options: %s\n",
                 archive_error_string(disk));
    else if (r != ARCHIVE_OK) {
        opkg_msg(ERROR, "Failed to set disk options: %s\n",
                 archive_error_string(disk));
        goto err_cleanup;
    }

    r = archive_write_disk_set_standard_lookup(disk);
    if (r == ARCHIVE_WARN)
        opkg_msg(NOTICE,
                 "Warning when setting user/group lookup functions: %s\n",
                 archive_error_string(disk));
    else if (r != ARCHIVE_OK) {
        opkg_msg(ERROR, "Failed to set user/group lookup functions: %s\n",
                 archive_error_string(disk));
        goto err_cleanup;
    }

    return disk;

 err_cleanup:
    archive_write_free(disk);
    return NULL;
}
Beispiel #16
0
static void create_reg_file_win(struct archive_entry *ae, const char *msg)
{
	static const char data[]="abcdefghijklmnopqrstuvwxyz";
	struct archive *ad;
	struct stat st;
	char *p, *fname;
	size_t l;

	/* Write the entry to disk. */
	assert((ad = archive_write_disk_new()) != NULL);
        archive_write_disk_set_options(ad, ARCHIVE_EXTRACT_TIME);
	failure("%s", msg);
	archive_entry_set_size(ae, sizeof(data));
	archive_entry_set_mtime(ae, 123456789, 0);
	assertEqualIntA(ad, 0, archive_write_header(ad, ae));
	assertEqualInt(sizeof(data), archive_write_data(ad, data, sizeof(data)));
	assertEqualIntA(ad, 0, archive_write_finish_entry(ad));
#if ARCHIVE_VERSION_NUMBER < 2000000
	archive_write_finish(ad);
#else
	assertEqualInt(0, archive_write_finish(ad));
#endif
	/* Test the entries on disk. */
	l = strlen(archive_entry_pathname(ae));
	fname = malloc(l + 1);
	assert(NULL != fname);
	strcpy(fname, archive_entry_pathname(ae));
	/* Replace unusable characters in Windows to '_' */
	for (p = fname; *p != '\0'; p++)
		if (*p == ':' || *p == '*' || *p == '?' ||
		    *p == '"' || *p == '<' || *p == '>' || *p == '|')
			*p = '_';
	assert(0 == stat(fname, &st));
	failure("st.st_mode=%o archive_entry_mode(ae)=%o",
	    st.st_mode, archive_entry_mode(ae));
	assertEqualInt(st.st_size, sizeof(data));
}
Beispiel #17
0
int
packing_init(struct packing **pack, const char *path, pkg_formats format)
{
	char archive_path[MAXPATHLEN];
	const char *ext;

	if ((*pack = calloc(1, sizeof(struct packing))) == NULL) {
		pkg_emit_event(PKG_EVENT_MALLOC_ERROR, /*argc*/1,
		    strerror(errno));
	}

	(*pack)->aread = archive_read_disk_new();
	archive_read_disk_set_standard_lookup((*pack)->aread);
	archive_read_disk_set_symlink_physical((*pack)->aread);

	(*pack)->entry = archive_entry_new();

	if (!is_dir(path)) {
		(*pack)->awrite = archive_write_new();
		archive_write_set_format_pax_restricted((*pack)->awrite);
		if ((ext = packing_set_format((*pack)->awrite, format)) == NULL) {
			archive_read_finish((*pack)->aread);
			archive_write_finish((*pack)->awrite);
			archive_entry_free((*pack)->entry);
			return EPKG_FATAL; /* error set by _set_format() */
		}
		snprintf(archive_path, sizeof(archive_path), "%s.%s", path, ext);

		archive_write_open_filename((*pack)->awrite, archive_path);
	} else { /* pass mode directly write to the disk */
		(*pack)->awrite = archive_write_disk_new();
		archive_write_disk_set_options((*pack)->awrite, EXTRACT_ARCHIVE_FLAGS);
	}

	return (EPKG_OK);
}
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.

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

    const unsigned char *ramdisk_data;
    std::size_t ramdisk_size;
    bi.ramdiskImageC(&ramdisk_data, &ramdisk_size);

    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_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 (!util::starts_with(path, "sbin/")) {
            continue;
        }

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

        archive_entry_set_pathname(entry, (_chroot + "/" + path).c_str());

        if (util::archive_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;
    }

    return ProceedState::Continue;
}
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;
}
compare_acls(acl_t acl, struct archive_test_acl_t *myacls, int n)
#endif
{
	int *marker;
	int matched;
	int i;
#if HAVE_SUN_ACL
	int e;
	aclent_t *acl_entry;
#else
	int entry_id = ACL_FIRST_ENTRY;
	acl_entry_t acl_entry;
#endif

	/* Count ACL entries in myacls array and allocate an indirect array. */
	marker = malloc(sizeof(marker[0]) * n);
	if (marker == NULL)
		return;
	for (i = 0; i < n; i++)
		marker[i] = i;

	/*
	 * Iterate over acls in system acl object, try to match each
	 * one with an item in the myacls array.
	 */
#if HAVE_SUN_ACL
	for(e = 0; e < acl->acl_cnt; e++) {
		acl_entry = &((aclent_t *)acl->acl_aclp)[e];
#else
	while (1 == acl_get_entry(acl, entry_id, &acl_entry)) {
		/* After the first time... */
		entry_id = ACL_NEXT_ENTRY;
#endif

		/* Search for a matching entry (tag and qualifier) */
		for (i = 0, matched = 0; i < n && !matched; i++) {
			if (acl_match(acl_entry, &myacls[marker[i]])) {
				/* We found a match; remove it. */
				marker[i] = marker[n - 1];
				n--;
				matched = 1;
			}
		}

		/* TODO: Print out more details in this case. */
		failure("ACL entry on file that shouldn't be there");
		assert(matched == 1);
	}

	/* Dump entries in the myacls array that weren't in the system acl. */
	for (i = 0; i < n; ++i) {
		failure(" ACL entry missing from file: "
		    "type=%#010x,permset=%#010x,tag=%d,qual=%d,name=``%s''\n",
		    myacls[marker[i]].type, myacls[marker[i]].permset,
		    myacls[marker[i]].tag, myacls[marker[i]].qual,
		    myacls[marker[i]].name);
		assert(0); /* Record this as a failure. */
	}
	free(marker);
}

#endif


/*
 * Verify ACL restore-to-disk.  This test is Platform-specific.
 */

DEFINE_TEST(test_acl_platform_posix1e_restore)
{
#if !HAVE_SUN_ACL && !HAVE_POSIX_ACL
	skipping("POSIX.1e ACLs are not supported on this platform");
#else	/* HAVE_SUN_ACL || HAVE_POSIX_ACL */
	struct stat st;
	struct archive *a;
	struct archive_entry *ae;
	int n, fd;
	char *func;
#if HAVE_SUN_ACL
	acl_t *acl, *acl2;
#else
	acl_t acl;
#endif

	/*
	 * First, do a quick manual set/read of ACL data to
	 * verify that the local filesystem does support ACLs.
	 * If it doesn't, we'll simply skip the remaining tests.
	 */
#if HAVE_SUN_ACL
	n = acl_fromtext("user::rwx,user:1:rw-,group::rwx,group:15:r-x,other:rwx,mask:rwx", &acl);
	failure("acl_fromtext(): errno = %d (%s)", errno, strerror(errno));
	assertEqualInt(0, n);
#else
	acl = acl_from_text("u::rwx,u:1:rw,g::rwx,g:15:rx,o::rwx,m::rwx");
	failure("acl_from_text(): errno = %d (%s)", errno, strerror(errno));
	assert((void *)acl != NULL);
#endif

	/* Create a test file and try ACL on it. */
	fd = open("pretest", O_WRONLY | O_CREAT | O_EXCL, 0777);
	failure("Could not create test file?!");
	if (!assert(fd >= 0)) {
		acl_free(acl);
		return;
	}

#if HAVE_SUN_ACL
	n = facl_get(fd, 0, &acl2);
	if (n != 0) {
		close(fd);
		acl_free(acl);
	}
	if (errno == ENOSYS) {
		skipping("POSIX.1e ACLs are not supported on this filesystem");
		return;
	}
	failure("facl_get(): errno = %d (%s)", errno, strerror(errno));
	assertEqualInt(0, n);

	if (acl2->acl_type != ACLENT_T) {
		acl_free(acl2);
		skipping("POSIX.1e ACLs are not supported on this filesystem");
		return;
	}
	acl_free(acl2);

	func = "facl_set()";
	n = facl_set(fd, acl);
#else
	func = "acl_set_fd()";
	n = acl_set_fd(fd, acl);
#endif
	acl_free(acl);
	if (n != 0) {
#if HAVE_SUN_ACL
		if (errno == ENOSYS)
#else
		if (errno == EOPNOTSUPP || errno == EINVAL)
#endif
		{
			close(fd);
			skipping("POSIX.1e ACLs are not supported on this filesystem");
			return;
		}
	}
	failure("%s: errno = %d (%s)", func, errno, strerror(errno));
	assertEqualInt(0, n);

#if HAVE_SUN_ACL

#endif
	close(fd);

	/* Create a write-to-disk object. */
	assert(NULL != (a = archive_write_disk_new()));
	archive_write_disk_set_options(a,
	    ARCHIVE_EXTRACT_TIME | ARCHIVE_EXTRACT_PERM | ARCHIVE_EXTRACT_ACL);

	/* Populate an archive entry with some metadata, including ACL info */
	ae = archive_entry_new();
	assert(ae != NULL);
	archive_entry_set_pathname(ae, "test0");
	archive_entry_set_mtime(ae, 123456, 7890);
	archive_entry_set_size(ae, 0);
	assertEntrySetAcls(ae, acls2, sizeof(acls2)/sizeof(acls2[0]));
	assertEqualIntA(a, ARCHIVE_OK, archive_write_header(a, ae));
	archive_entry_free(ae);

	/* Close the archive. */
	assertEqualIntA(a, ARCHIVE_OK, archive_write_close(a));
	assertEqualInt(ARCHIVE_OK, archive_write_free(a));

	/* Verify the data on disk. */
	assertEqualInt(0, stat("test0", &st));
	assertEqualInt(st.st_mtime, 123456);
#if HAVE_SUN_ACL
	n = acl_get("test0", 0, &acl);
	failure("acl_get(): errno = %d (%s)", errno, strerror(errno));
	assertEqualInt(0, n);
#else
	acl = acl_get_file("test0", ACL_TYPE_ACCESS);
	failure("acl_get_file(): errno = %d (%s)", errno, strerror(errno));
	assert(acl != (acl_t)NULL);
#endif
	compare_acls(acl, acls2, sizeof(acls2)/sizeof(acls2[0]));
	acl_free(acl);
#endif	/* HAVE_SUN_ACL || HAVE_POSIX_ACL */
}

/*
 * Verify ACL read-from-disk.  This test is Platform-specific.
 */
DEFINE_TEST(test_acl_platform_posix1e_read)
{
#if !HAVE_SUN_ACL && !HAVE_POSIX_ACL
	skipping("POSIX.1e ACLs are not supported on this platform");
#else
	struct archive *a;
	struct archive_entry *ae;
	int n, fd, flags, dflags;
	char *func, *acl_text;
	const char *acl1_text, *acl2_text, *acl3_text;
#if HAVE_SUN_ACL
	acl_t *acl, *acl1, *acl2, *acl3;
#else
	acl_t acl1, acl2, acl3;
#endif

	/*
	 * Manually construct a directory and two files with
	 * different ACLs.  This also serves to verify that ACLs
	 * are supported on the local filesystem.
	 */

	/* Create a test file f1 with acl1 */
#if HAVE_SUN_ACL
	acl1_text = "user::rwx,"
	    "group::rwx,"
	    "other:rwx,"
	    "user:1:rw-,"
	    "group:15:r-x,"
	    "mask:rwx";
	n = acl_fromtext(acl1_text, &acl1);
	failure("acl_fromtext(): errno = %d (%s)", errno, strerror(errno));
	assertEqualInt(0, n);
#else
	acl1_text = "user::rwx\n"
	    "group::rwx\n"
	    "other::rwx\n"
	    "user:1:rw-\n"
	    "group:15:r-x\n"
	    "mask::rwx";
	acl1 = acl_from_text(acl1_text);
	failure("acl_from_text(): errno = %d (%s)", errno, strerror(errno));
	assert((void *)acl1 != NULL);
#endif
	fd = open("f1", O_WRONLY | O_CREAT | O_EXCL, 0777);
	failure("Could not create test file?!");
	if (!assert(fd >= 0)) {
		acl_free(acl1);
		return;
	}
#if HAVE_SUN_ACL
	/* Check if Solaris filesystem supports POSIX.1e ACLs */
	n = facl_get(fd, 0, &acl);
	if (n != 0)
		close(fd);
	if (n != 0 && errno == ENOSYS) {
		acl_free(acl1);
		skipping("POSIX.1e ACLs are not supported on this filesystem");
		return;
	}
	failure("facl_get(): errno = %d (%s)", errno, strerror(errno));
	assertEqualInt(0, n);

	if (acl->acl_type != ACLENT_T) {
		acl_free(acl);
		acl_free(acl1);
		close(fd);
		skipping("POSIX.1e ACLs are not supported on this filesystem");
		return;
	}

	func = "facl_set()";
	n = facl_set(fd, acl1);
#else
	func = "acl_set_fd()";
	n = acl_set_fd(fd, acl1);
#endif
	acl_free(acl1);

	if (n != 0) {
#if HAVE_SUN_ACL
		if (errno == ENOSYS)
#else
		if (errno == EOPNOTSUPP || errno == EINVAL)
#endif
		{
			close(fd);
			skipping("POSIX.1e ACLs are not supported on this filesystem");
			return;
		}
	}
	failure("%s: errno = %d (%s)", func, errno, strerror(errno));
	assertEqualInt(0, n);

	close(fd);

	assertMakeDir("d", 0700);

	/*
	 * Create file d/f1 with acl2
	 *
	 * This differs from acl1 in the u:1: and g:15: permissions.
	 *
	 * This file deliberately has the same name but a different ACL.
	 * Github Issue #777 explains how libarchive's directory traversal
	 * did not always correctly enter directories before attempting
	 * to read ACLs, resulting in reading the ACL from a like-named
	 * file in the wrong directory.
	 */
#if HAVE_SUN_ACL
	acl2_text = "user::rwx,"
	    "group::rwx,"
	    "other:---,"
	    "user:1:r--,"
	    "group:15:r--,"
	    "mask:rwx";
	n = acl_fromtext(acl2_text, &acl2);
	failure("acl_fromtext(): errno = %d (%s)", errno, strerror(errno));
	assertEqualInt(0, n);
#else
	acl2_text = "user::rwx\n"
	    "group::rwx\n"
	    "other::---\n"
	    "user:1:r--\n"
	    "group:15:r--\n"
	    "mask::rwx";
	acl2 = acl_from_text(acl2_text);
	failure("acl_from_text(): errno = %d (%s)", errno, strerror(errno));
	assert((void *)acl2 != NULL);
#endif
	fd = open("d/f1", O_WRONLY | O_CREAT | O_EXCL, 0777);
	failure("Could not create test file?!");
	if (!assert(fd >= 0)) {
		acl_free(acl2);
		return;
	}
#if HAVE_SUN_ACL
	func = "facl_set()";
	n = facl_set(fd, acl2);
#else
	func = "acl_set_fd()";
	n = acl_set_fd(fd, acl2);
#endif
	acl_free(acl2);
	if (n != 0)
		close(fd);
	failure("%s: errno = %d (%s)", func, errno, strerror(errno));
	assertEqualInt(0, n);
	close(fd);

	/* Create nested directory d2 with default ACLs */
	assertMakeDir("d/d2", 0755);

#if HAVE_SUN_ACL
	acl3_text = "user::rwx,"
	    "group::r-x,"
	    "other:r-x,"
	    "user:2:r--,"
	    "group:16:-w-,"
	    "mask:rwx,"
	    "default:user::rwx,"
	    "default:user:1:r--,"
	    "default:group::r-x,"
	    "default:group:15:r--,"
	    "default:mask:rwx,"
	    "default:other:r-x";
	n = acl_fromtext(acl3_text, &acl3);
	failure("acl_fromtext(): errno = %d (%s)", errno, strerror(errno));
	assertEqualInt(0, n);
#else
	acl3_text = "user::rwx\n"
	    "user:1:r--\n"
	    "group::r-x\n"
	    "group:15:r--\n"
	    "mask::rwx\n"
	    "other::r-x";
	acl3 = acl_from_text(acl3_text);
	failure("acl_from_text(): errno = %d (%s)", errno, strerror(errno));
	assert((void *)acl3 != NULL);
#endif

#if HAVE_SUN_ACL
	func = "acl_set()";
	n = acl_set("d/d2", acl3);
#else
	func = "acl_set_file()";
	n = acl_set_file("d/d2", ACL_TYPE_DEFAULT, acl3);
#endif
	acl_free(acl3);

	failure("%s: errno = %d (%s)", func, errno, strerror(errno));
	assertEqualInt(0, n);

	/* Create a read-from-disk object. */
	assert(NULL != (a = archive_read_disk_new()));
	assertEqualIntA(a, ARCHIVE_OK, archive_read_disk_open(a, "."));
	assert(NULL != (ae = archive_entry_new()));

#if HAVE_SUN_ACL
	flags = ARCHIVE_ENTRY_ACL_TYPE_POSIX1E
	    | ARCHIVE_ENTRY_ACL_STYLE_SEPARATOR_COMMA
	    | ARCHIVE_ENTRY_ACL_STYLE_SOLARIS;
	dflags = flags;
#else
	flags = ARCHIVE_ENTRY_ACL_TYPE_ACCESS;
	dflags = ARCHIVE_ENTRY_ACL_TYPE_DEFAULT;
#endif

	/* Walk the dir until we see both of the files */
	while (ARCHIVE_OK == archive_read_next_header2(a, ae)) {
		archive_read_disk_descend(a);
		if (strcmp(archive_entry_pathname(ae), "./f1") == 0) {
			acl_text = archive_entry_acl_to_text(ae, NULL, flags);
			assertEqualString(acl_text, acl1_text);
			free(acl_text);
		} else if (strcmp(archive_entry_pathname(ae), "./d/f1") == 0) {
			acl_text = archive_entry_acl_to_text(ae, NULL, flags);
			assertEqualString(acl_text, acl2_text);
			free(acl_text);
		} else if (strcmp(archive_entry_pathname(ae), "./d/d2") == 0) {
			acl_text = archive_entry_acl_to_text(ae, NULL, dflags);
			assertEqualString(acl_text, acl3_text);
			free(acl_text);
		}
	}

	archive_entry_free(ae);
	assertEqualInt(ARCHIVE_OK, archive_free(a));
#endif
}
Beispiel #21
0
static void
extract(const char *filename, int do_extract, int flags)
{
	struct archive *a;
	struct archive *ext;
	struct archive_entry *entry;
	int r;

	a = archive_read_new();
	ext = archive_write_disk_new();
	archive_write_disk_set_options(ext, flags);
#ifndef NO_BZIP2_EXTRACT
	archive_read_support_filter_bzip2(a);
#endif
#ifndef NO_GZIP_EXTRACT
	archive_read_support_filter_gzip(a);
#endif
#ifndef NO_COMPRESS_EXTRACT
	archive_read_support_filter_compress(a);
#endif
#ifndef NO_TAR_EXTRACT
	archive_read_support_format_tar(a);
#endif
#ifndef NO_CPIO_EXTRACT
	archive_read_support_format_cpio(a);
#endif
#ifndef NO_LOOKUP
	archive_write_disk_set_standard_lookup(ext);
#endif
	if (filename != NULL && strcmp(filename, "-") == 0)
		filename = NULL;
	if ((r = archive_read_open_filename(a, filename, 10240))) {
		errmsg(archive_error_string(a));
		errmsg("\n");
		exit(r);
	}
	for (;;) {
		r = archive_read_next_header(a, &entry);
		if (r == ARCHIVE_EOF)
			break;
		if (r != ARCHIVE_OK) {
			errmsg(archive_error_string(a));
			errmsg("\n");
			exit(1);
		}
		if (verbose && do_extract)
			msg("x ");
		if (verbose || !do_extract)
			msg(archive_entry_pathname(entry));
		if (do_extract) {
			r = archive_write_header(ext, entry);
			if (r != ARCHIVE_OK)
				errmsg(archive_error_string(a));
			else
				copy_data(a, ext);
		}
		if (verbose || !do_extract)
			msg("\n");
	}
	archive_read_close(a);
	archive_read_free(a);
	exit(0);
}
/*! \brief Extracts the selected .tar.gz archive to the selected folder, will try to create the target folder if it does not exist.
* @param filePath Full path to selected archive.
* @param targetFolderPath Full path to target folder.
* @return Returns full path to the extracted archive, or empty QString if failed.
*/
QString ArchiveExtractor::extractFileToTargetFolder(QString filePath, QString targetFolderPath){
  //check if the selected archive file exist
  QFile *selectedFile = new QFile(filePath);
  if(!selectedFile->exists()){
    qDebug()<<"ERROR: File marked for decompression does not exist!";
    delete selectedFile;
    return QString("");
  }
  delete selectedFile;
  struct archive *a;
  struct archive *ext;
  struct archive_entry *entry;
  int r;
  //  /* The "flags" argument selects optional behavior, 'OR' the flags you want. */
  //  /* Default: Do not try to set owner/group. */
  //#define	ARCHIVE_EXTRACT_OWNER			(0x0001)
  //  /* Default: Do obey umask, do not restore SUID/SGID/SVTX bits. */
  //#define	ARCHIVE_EXTRACT_PERM			(0x0002)
  //  /* Default: Do not restore mtime/atime. */
  //#define	ARCHIVE_EXTRACT_TIME			(0x0004)
  //  /* Default: Replace existing files. */
  //#define	ARCHIVE_EXTRACT_NO_OVERWRITE 		(0x0008)
  //  /* Default: Try create first, unlink only if create fails with EEXIST. */
  //#define	ARCHIVE_EXTRACT_UNLINK			(0x0010)
  //  /* Default: Do not restore ACLs. */
  //#define	ARCHIVE_EXTRACT_ACL			(0x0020)
  //  /* Default: Do not restore fflags. */
  //#define	ARCHIVE_EXTRACT_FFLAGS			(0x0040)
  //  /* Default: Do not restore xattrs. */
  //#define	ARCHIVE_EXTRACT_XATTR 			(0x0080)
  //  /* Default: Do not try to guard against extracts redirected by symlinks. */
  //  /* Note: With ARCHIVE_EXTRACT_UNLINK, will remove any intermediate symlink. */
  //#define	ARCHIVE_EXTRACT_SECURE_SYMLINKS		(0x0100)
  //  /* Default: Do not reject entries with '..' as path elements. */
  //#define	ARCHIVE_EXTRACT_SECURE_NODOTDOT		(0x0200)
  //  /* Default: Create parent directories as needed. */
  //#define	ARCHIVE_EXTRACT_NO_AUTODIR		(0x0400)
  //  /* Default: Overwrite files, even if one on disk is newer. */
  //#define	ARCHIVE_EXTRACT_NO_OVERWRITE_NEWER	(0x0800)
  //  /* Detect blocks of 0 and write holes instead. */
  //#define	ARCHIVE_EXTRACT_SPARSE			(0x1000)
  //  /* Default: Do not restore Mac extended metadata. */
  //  /* This has no effect except on Mac OS. */
  //#define	ARCHIVE_EXTRACT_MAC_METADATA		(0x2000)
  int flags = 0;
  //      flags |= ARCHIVE_EXTRACT_TIME;
  //      flags |= ARCHIVE_EXTRACT_NO_AUTODIR;
  //      flags |= ARCHIVE_EXTRACT_NO_OVERWRITE_NEWER;

  QFileInfo *fileInfo = new QFileInfo(filePath);
//  qDebug()<<"resolved filename: "<<fileInfo->fileName();
  delete fileInfo;

  //MEMORY LEAK!!! (Pointers be dangerous, man. :)
  //  const char *filename = fileInfo->fileName().toUtf8().constData();
  //AVOID IT BY CONVERTING TO A QBYTEARRAY FIRST!
  QByteArray byteArray = filePath.toUtf8();
  const char *filename = byteArray.constData();
  //That's better :D

  //toggle extraction
  bool do_extract = true;

  a = archive_read_new();
  ext = archive_write_disk_new();
  archive_write_disk_set_options(ext, flags);

  //tuned for .tar.gz
  archive_read_support_filter_gzip(a);
  archive_read_support_format_gnutar(a);

  if((r = archive_read_open_filename(a, filename, 10240)) ){
    errmsg(archive_error_string(a));
  }
  for(;;){
    r = archive_read_next_header(a, &entry);
    if(r == ARCHIVE_EOF) break;
    if(r != ARCHIVE_OK){
      errmsg(archive_error_string(a));
    }
    if (verbose || !do_extract){
      qDebug()<<"Detected files in archive: ";
      msg(archive_entry_pathname(entry));
    }
    QString currentPath(archive_entry_pathname( entry ));
    qDebug()<<currentPath;

    QDir targetFolder(targetFolderPath);
    if(!targetFolder.exists()){//target folder does not exist
      //attempt to create it
      if(!targetFolder.mkpath(targetFolderPath)){//failed to create target folder
        //break procedure
        qDebug()<<"ERROR: Target folder does not exist and cannot be created";
        return QString("");
      }
    }

    QString newPath = targetFolderPath + currentPath;
    qDebug()<<"newPath: " << newPath;

    archive_entry_set_pathname( entry, newPath.toUtf8().constData() );
    if (verbose && do_extract){
//      msg("About to start extracting\n");
    }
    if (do_extract){
      qDebug()<<"Extracting...";
      r = archive_write_header(ext, entry);
      if (r != ARCHIVE_OK) errmsg(archive_error_string(a));
      else copy_data(a, ext);
      std::string returnPath;
      returnPath = archive_entry_pathname(entry);
      qDebug()<<"File extracted: " << QString::fromStdString(returnPath);
      archive_read_close(a);
      archive_read_free(a);
      archive_write_close(ext);
      archive_write_free(ext);
      return QString::fromStdString( returnPath );
    }
  }
  archive_read_close(a);
  archive_read_free(a);
  archive_write_close(ext);
  archive_write_free(ext);
  return QString("");
}
Beispiel #23
0
static void extract_archive(const char *filename, const char *output)
{
    struct archive *a;
    struct archive *ext;
    struct archive_entry *entry;
    int flags;
    int r;

    flags = ARCHIVE_EXTRACT_PERM | ARCHIVE_EXTRACT_SECURE_NODOTDOT;

    a = archive_read_new();
#if ARCHIVE_VERSION_NUMBER < 4000000
    archive_read_support_compression_bzip2(a);
#else
    archive_read_support_filter_bzip2(a);
#endif
    archive_read_support_format_tar(a);

    ext = archive_write_disk_new();
    archive_write_disk_set_options(ext, flags);
    archive_write_disk_set_standard_lookup(ext);

    r = archive_read_open_file(a, filename, 10240);

    if (r) {
        std::string msg = extract_archive_error(filename, output, a);

	archive_read_close(a);
#if ARCHIVE_VERSION_NUMBER < 4000000
        archive_read_finish(a);
#else
	archive_read_free(a);
#endif

        throw utils::InternalError(msg);
    }

    for (;;) {
        r = archive_read_next_header(a, &entry);
        if (r == ARCHIVE_EOF) {
            break;
        }

        if (r != ARCHIVE_OK) {
            std::string msg = extract_archive_error(filename, output, a);

            archive_read_close(a);
#if ARCHIVE_VERSION_NUMBER < 4000000
            archive_read_finish(a);
#else
            archive_read_free(a);
#endif

            archive_write_close(ext);
#if ARCHIVE_VERSION_NUMBER < 4000000
            archive_write_finish(ext);
#else
            archive_write_free(ext);
#endif

            throw utils::InternalError(msg);
        }

        if (r < ARCHIVE_WARN) {
            break;
        }

        r = archive_write_header(ext, entry);

        if (r != ARCHIVE_OK) {
            std::string msg = extract_archive_error(filename, output, a);

            archive_read_close(a);
#if ARCHIVE_VERSION_NUMBER < 4000000
            archive_read_finish(a);
#else
            archive_read_free(a);
#endif
            archive_write_close(ext);
#if ARCHIVE_VERSION_NUMBER < 4000000
            archive_write_finish(ext);
#else
            archive_write_free(ext);
#endif

            throw utils::InternalError(msg);
        } else {
            r = copy_data(a, ext);

            if (r != ARCHIVE_OK) {
                std::string msg = extract_archive_error(filename, output, a);

                archive_read_close(a);
#if ARCHIVE_VERSION_NUMBER < 4000000
                archive_read_finish(a);
#else
                archive_read_free(a);
#endif
                archive_write_close(ext);
#if ARCHIVE_VERSION_NUMBER < 4000000
                archive_write_finish(ext);
#else
                archive_write_free(ext);
#endif


                throw utils::InternalError(msg);
            }
        }
    }

    archive_read_close(a);
#if ARCHIVE_VERSION_NUMBER < 4000000
    archive_read_finish(a);
#else
    archive_read_free(a);
#endif
    archive_write_close(ext);
#if ARCHIVE_VERSION_NUMBER < 4000000
    archive_write_finish(ext);
#else
    archive_write_free(ext);
#endif

}
//********************************************************************************************************
void read_archive(const char* const infile, const char* const extractFolder){
  // Strongly inspired by
  // https://github.com/libarchive/libarchive/wiki/Examples#A_Complete_Extractor

  //printf("Opening archive '%s' for extracting to folder '%s'...\n",infile,extractFolder);

  //Check that the archive exists

  //Check that the folder exists, if not then create it

  struct archive* a = archive_read_new();
  archive_read_support_format_zip(a);
  struct archive* ext = archive_write_disk_new();
  archive_write_disk_set_options(ext,ARCHIVE_EXTRACT_TIME|ARCHIVE_EXTRACT_PERM|ARCHIVE_EXTRACT_ACL|ARCHIVE_EXTRACT_FFLAGS);
  archive_write_disk_set_standard_lookup(ext);

  int err;
  err = archive_read_open_filename(a, infile, 10240);
  if (err != ARCHIVE_OK) {
    fprintf(stderr, "CRITICAL ERROR in read_archive(): When opening archive '%s', err=%i\n",infile,err);
    fprintf(stderr, "CRITICAL ERROR in read_archive(): %s\n",archive_error_string(a));
    exit(EXIT_FAILURE);
  }

  struct archive_entry *entry;

  const int fcount_max = 1000;
  char fcompleted=0; //C-Boolean
  for(int fcount=0; fcount<fcount_max;fcount++){
    err = archive_read_next_header(a,&entry);
    if (err == ARCHIVE_EOF){
      fcompleted=1;
      break;
    }
    else if (err != ARCHIVE_OK){
      fprintf(stderr, "CRITICAL ERROR in read_archive(): When reading archive, err=%i\n",err);
      fprintf(stderr, "CRITICAL ERROR in read_archive(): %s\n",archive_error_string(a));
      exit(EXIT_FAILURE);
    }
    //printf("Found file: '%s'\n",archive_entry_pathname(entry));

    //Avoid clobbering files in current directory - solution from
    // http://stackoverflow.com/questions/4496001/libarchive-to-extract-to-a-specified-folder
    char newPath[PATH_MAX];
    int buff_used = snprintf(newPath, PATH_MAX, "%s/%s",extractFolder,archive_entry_pathname(entry));
    if (buff_used >= PATH_MAX || buff_used < 0){
      fprintf(stderr, "CRITICAL ERROR in read_archive(): Buffer overflow or other error when creating the path.\n");
      fprintf(stderr, "CRITICAL ERROR in read_archive(): buff_used=%i\n",buff_used);
      exit(EXIT_FAILURE);
    }
    archive_entry_set_pathname(entry,newPath);

    err = archive_write_header(ext, entry);
    if (err != ARCHIVE_OK){
      fprintf(stderr, "CRITICAL ERROR in read_archive(): when extracting archive (creating new file), err=%i\n",err);
      fprintf(stderr, "CRITICAL ERROR in read_archive(): %s\n",archive_error_string(ext));
      exit(EXIT_FAILURE);
    }

    //Write the data!
    const void* buff;
    size_t size;
    la_int64_t offset;

    const int bcount_max = 100000000;
    char bcompleted = 0; //C boolean
    for (int bcount=0; bcount<bcount_max;bcount++){
      err = archive_read_data_block(a,&buff,&size, &offset);
      if ( err == ARCHIVE_EOF ) {
	bcompleted=1;
	break;
      }
      else if (err != ARCHIVE_OK){
	fprintf(stderr, "CRITICAL ERROR in read_archive(): When extracting archive (reading data), err=%i\n",err);
	fprintf(stderr, "CRITICAL ERROR in read_archive(): %s\n",archive_error_string(a));
	exit(EXIT_FAILURE);
      }

      err = archive_write_data_block(ext,buff,size,offset);
      if (err != ARCHIVE_OK){
	fprintf(stderr, "CRITICAL ERROR in read_archive(): When extracting archive (writing data), err=%i\n",err);
	fprintf(stderr, "CRITICAL ERROR in read_archive(): %s\n",archive_error_string(a));
	exit(EXIT_FAILURE);
      }
    }
    if (!bcompleted){
      fprintf(stderr, "CRITICAL ERROR in read_archive(): The file writing block loop was aborted by the infinite loop guard\n");
      exit(EXIT_FAILURE);
    }

    err=archive_write_finish_entry(ext);
    if (err != ARCHIVE_OK) {
      fprintf(stderr, "CRITICAL ERROR in read_archive(): When extracting archive (closing new file), err=%i\n",err);
      fprintf(stderr, "CRITICAL ERROR in read_archive(): %s\n",archive_error_string(ext));
      exit(EXIT_FAILURE);
    }
  }

  archive_read_close(a);
  err=archive_read_free(a);
  if (err != ARCHIVE_OK){
    fprintf(stderr, "CRITICAL ERROR in read_archive(): When calling archive_read_free(a), err=%i\n",err);
    fprintf(stderr, "CRITICAL ERROR in read_archive(): %s\n",archive_error_string(a));
    exit(EXIT_FAILURE);
  }
  archive_write_close(ext);
  err = archive_write_free(ext);
  if (err != ARCHIVE_OK){
    fprintf(stderr, "CRITICAL ERROR in read_archive(): When calling archive_read_free(ext), err=%i\n",err);
    fprintf(stderr, "CRITICAL ERROR in read_archive(): %s\n",archive_error_string(a));
    exit(EXIT_FAILURE);
  }

  if (!fcompleted) {
    fprintf(stderr, "CRITICAL ERROR in read_archive(): The file header loop was aborted by the infinite loop guard\n");
    exit(EXIT_FAILURE);
  }
}
Beispiel #25
0
bool extractXZ(FILE *sfp, std::string dest)
{
    struct archive *a;
    struct archive *ext;
    struct archive_entry *entry;
    int flags;
    int r;

    /* Select which attributes we want to restore. */
    flags = ARCHIVE_EXTRACT_TIME;
    flags |= ARCHIVE_EXTRACT_PERM;
    flags |= ARCHIVE_EXTRACT_ACL;
    flags |= ARCHIVE_EXTRACT_FFLAGS;

    a = archive_read_new();
    archive_read_support_format_all(a);
    archive_read_support_filter_all(a);
    ext = archive_write_disk_new();
    archive_write_disk_set_options(ext, flags);
    archive_write_disk_set_standard_lookup(ext);
    if ((r = archive_read_open_FILE(a, sfp))) {
      std::cout<<archive_error_string(ext)<<std::endl;
      return false;
    }
    for (;;) {
      r = archive_read_next_header(a, &entry);
      if (r == ARCHIVE_EOF)
        break;
      if (r < ARCHIVE_OK)
        fprintf(stderr, "%s\n", archive_error_string(a));
      if (r < ARCHIVE_WARN) {
          fprintf(stderr, "warn 1\n");
          return false;
      }
      std::string path = archive_entry_pathname(entry);
      //std::cout<<"old path: "<< path<<std::endl;
      archive_entry_set_pathname(entry, (dest + "/" + path).c_str());
      r = archive_write_header(ext, entry);
      if (r < ARCHIVE_OK)
        fprintf(stderr, "%s\n", archive_error_string(ext));
      else if (archive_entry_size(entry) > 0) {
        r = copy_data(a, ext);
        if (r < ARCHIVE_OK)
          fprintf(stderr, "%s\n", archive_error_string(ext));
        if (r < ARCHIVE_WARN) {
            fprintf(stderr, "warn 2\n");
            return false;
        }
      }
      r = archive_write_finish_entry(ext);
      if (r < ARCHIVE_OK)
        fprintf(stderr, "%s\n", archive_error_string(ext));
      if (r < ARCHIVE_WARN) {
          fprintf(stderr, "warn 3\n");
          return false;
      }
    }
    archive_read_close(a);
    archive_read_free(a);
    archive_write_close(ext);
    archive_write_free(ext);
    return true;
}
Beispiel #26
0
static void
mode_in(struct cpio *cpio)
{
	struct archive *a;
	struct archive_entry *entry;
	struct archive *ext;
	const char *destpath;
	int r;

	ext = archive_write_disk_new();
	if (ext == NULL)
		lafe_errc(1, 0, "Couldn't allocate restore object");
	r = archive_write_disk_set_options(ext, cpio->extract_flags);
	if (r != ARCHIVE_OK)
		lafe_errc(1, 0, "%s", archive_error_string(ext));
	a = archive_read_new();
	if (a == NULL)
		lafe_errc(1, 0, "Couldn't allocate archive object");
	archive_read_support_compression_all(a);
	archive_read_support_format_all(a);

	if (archive_read_open_file(a, cpio->filename, cpio->bytes_per_block))
		lafe_errc(1, archive_errno(a),
		    "%s", archive_error_string(a));
	for (;;) {
		r = archive_read_next_header(a, &entry);
		if (r == ARCHIVE_EOF)
			break;
		if (r != ARCHIVE_OK) {
			lafe_errc(1, archive_errno(a),
			    "%s", archive_error_string(a));
		}
		if (lafe_excluded(cpio->matching, archive_entry_pathname(entry)))
			continue;
		if (cpio->option_rename) {
			destpath = cpio_rename(archive_entry_pathname(entry));
			archive_entry_set_pathname(entry, destpath);
		} else
			destpath = archive_entry_pathname(entry);
		if (destpath == NULL)
			continue;
		if (cpio->verbose)
			fprintf(stdout, "%s\n", destpath);
		if (cpio->uid_override >= 0)
			archive_entry_set_uid(entry, cpio->uid_override);
		if (cpio->gid_override >= 0)
			archive_entry_set_gid(entry, cpio->gid_override);
		r = archive_write_header(ext, entry);
		if (r != ARCHIVE_OK) {
			fprintf(stderr, "%s: %s\n",
			    archive_entry_pathname(entry),
			    archive_error_string(ext));
		} else if (archive_entry_size(entry) > 0) {
			r = extract_data(a, ext);
			if (r != ARCHIVE_OK)
				cpio->return_value = 1;
		}
	}
	r = archive_read_close(a);
	if (r != ARCHIVE_OK)
		lafe_errc(1, 0, "%s", archive_error_string(a));
	r = archive_write_close(ext);
	if (r != ARCHIVE_OK)
		lafe_errc(1, 0, "%s", archive_error_string(ext));
	if (!cpio->quiet) {
		int64_t blocks = (archive_position_uncompressed(a) + 511)
			      / 512;
		fprintf(stderr, "%lu %s\n", (unsigned long)blocks,
		    blocks == 1 ? "block" : "blocks");
	}
	archive_read_finish(a);
	archive_write_finish(ext);
	exit(cpio->return_value);
}
Beispiel #27
0
void Package::readPackageFile(const std::string &package_path)
{
    if (!package_path.empty())
        mPackagePath = package_path;

    boost::filesystem::path unpacked_dir = mWorkDir;
    unpacked_dir /= mPackagePath.stem();
    mUnpackedDir = unpacked_dir;

    const void *buf;

    int r;

    struct archive *a = archive_read_new();
    struct archive_entry *entry;

    archive_read_support_compression_bzip2(a);
    archive_read_support_format_tar(a);


    struct archive *ext = archive_write_disk_new();
    int flags = ARCHIVE_EXTRACT_TIME | ARCHIVE_EXTRACT_PERM | ARCHIVE_EXTRACT_ACL | ARCHIVE_EXTRACT_FFLAGS;
    archive_write_disk_set_options(ext, flags);
    archive_write_disk_set_standard_lookup(ext);

    r = archive_read_open_filename(a, package_path.c_str(), 16384);
    if (r != ARCHIVE_OK) {
        archive_read_free(a);
        archive_write_free(ext);
        throw Exception(std::string("archive_read_open_filename() failed for file: ") + package_path);
    }

    while (true) {

        r = archive_read_next_header(a, &entry);
        if (r == ARCHIVE_EOF) {
            break;
        }
        if (r < ARCHIVE_OK) {
            std::cerr << archive_error_string(ext) << std::endl;
        }
        if (r < ARCHIVE_WARN) {
            archive_read_free(a);
            archive_write_free(ext);
            throw Exception(std::string("archive_read_next_header() failed:") + archive_error_string(a));
        }

        std::cout << std::string("extract: ") << archive_entry_pathname(entry) << std::endl;
        archive_entry_set_pathname(entry, (mUnpackedDir.string() + std::string("/") + archive_entry_pathname(entry)).c_str());

        r = archive_write_header(ext, entry);
        if (r < ARCHIVE_OK) {
            archive_read_free(a);
            archive_write_free(ext);
            throw Exception(std::string("archive_write_header() failed:") + archive_error_string(ext));
        } else if (archive_entry_size(entry) > 0) {

            size_t size;
            int64_t offset;
            while (true) {
                r = archive_read_data_block(a, &buf, &size, &offset);
                if (r == ARCHIVE_EOF)
                    break;
                if (r < ARCHIVE_WARN) {
                    archive_read_free(a);
                    archive_write_free(ext);
                    throw Exception(std::string(archive_error_string(ext)));
                }
                if (r < ARCHIVE_OK) {
                    std::cerr << archive_error_string(ext) << std::endl;
                    break;
                }

                r = archive_write_data_block(ext, buf, size, offset);
                if (r < ARCHIVE_WARN) {
                    archive_read_free(a);
                    archive_write_free(ext);
                    throw Exception(std::string(archive_error_string(ext)));
                }
                if (r < ARCHIVE_OK) {
                    std::cerr << archive_error_string(ext) << std::endl;
                    break;
                }
            }


            r = archive_write_finish_entry(ext);
            if (r < ARCHIVE_OK)
                std::cerr << archive_error_string(ext) << std::endl;
            if (r < ARCHIVE_WARN) {
                archive_read_free(a);
                archive_write_free(ext);
                throw Exception(std::string(archive_error_string(ext)));
            }
        }
    }
    archive_read_close(a);
    archive_read_free(a);
    archive_write_close(ext);
    archive_write_free(ext);
}
	RESULTCODE ArchiveProcessorImpl::Decompress()
	{
		const char* tpath = GetArchivePath();
		if(tpath==NULL)
		{
			return AG_FAILURE;
		}
		struct archive *a;
		struct archive *ext;
		struct archive_entry *entry;
		int flags;
		int r;

		/* Select which attributes we want to restore. */
		flags = ARCHIVE_EXTRACT_TIME;
		flags |= ARCHIVE_EXTRACT_PERM;
		flags |= ARCHIVE_EXTRACT_ACL;
		flags |= ARCHIVE_EXTRACT_FFLAGS;

		a = archive_read_new();
		archive_read_support_format_all(a);
		archive_read_support_compression_all(a);

		ext = archive_write_disk_new();
		archive_write_disk_set_options(ext, flags);
		archive_write_disk_set_standard_lookup(ext);
		if((r = archive_read_open_filename(a, tpath, 10240)))
		{
			return AG_FAILURE;
		}

		while(true)
		{
			r = archive_read_next_header(a, &entry);
			if( r== ARCHIVE_EOF)
			{
				break;
			}
			if( r < ARCHIVE_OK)
			{
				fprintf(stderr, "%s\n", archive_error_string(a));
			}
			if( r< ARCHIVE_WARN)
			{
				break;
			}

			r = archive_write_header(ext, entry);
			if (r < ARCHIVE_OK)
			{
				fprintf(stderr, "%s\n", archive_error_string(ext));
			}
			else if (archive_entry_size(entry) > 0) 
			{
				r = copy_data(a, ext);
			}
			if (r < ARCHIVE_OK)
			{
				fprintf(stderr, "%s\n", archive_error_string(ext));
			}
			if (r < ARCHIVE_WARN)
			{
				break;
			}

			r = archive_write_finish_entry(ext);
			if (r < ARCHIVE_OK)
			{
				fprintf(stderr, "%s\n", archive_error_string(ext));
			}
			if(r < ARCHIVE_WARN)
			{
				break;
			}
		}	

		archive_read_close(a);
		archive_read_free(a);	

		archive_write_close(ext);
		archive_write_free(ext);


		//return r==ARCHIVE_OK ? AG_SUCCESS : AG_FAILURE;
		return AG_SUCCESS;
	}
Beispiel #29
0
static bool extract_theme(const std::string &path, const std::string &target,
                          const std::string &theme_name)
{
    mb::autoclose::archive in(archive_read_new(), archive_read_free);
    if (!in) {
        LOGE("%s: Out of memory when creating archive reader", __FUNCTION__);
        return false;
    }
    mb::autoclose::archive out(archive_write_disk_new(), archive_write_free);
    if (!out) {
        LOGE("%s: Out of memory when creating disk writer", __FUNCTION__);
        return false;
    }

    archive_read_support_format_zip(in.get());

    // Set up disk writer parameters. We purposely don't extract any file
    // metadata
    int flags = ARCHIVE_EXTRACT_SECURE_SYMLINKS
            | ARCHIVE_EXTRACT_SECURE_NODOTDOT;

    archive_write_disk_set_standard_lookup(out.get());
    archive_write_disk_set_options(out.get(), flags);

    if (archive_read_open_filename(in.get(), path.c_str(), 10240) != ARCHIVE_OK) {
        LOGE("%s: Failed to open file: %s",
             path.c_str(), archive_error_string(in.get()));
        return false;
    }

    archive_entry *entry;
    int ret;
    std::string target_path;

    std::string common_prefix("theme/common/");
    std::string theme_prefix("theme/");
    theme_prefix += theme_name;
    theme_prefix += '/';

    while (true) {
        ret = archive_read_next_header(in.get(), &entry);
        if (ret == ARCHIVE_EOF) {
            break;
        } else if (ret == ARCHIVE_RETRY) {
            LOGW("%s: Retrying header read", path.c_str());
            continue;
        } else if (ret != ARCHIVE_OK) {
            LOGE("%s: Failed to read header: %s",
                 path.c_str(), archive_error_string(in.get()));
            return false;
        }

        const char *path = archive_entry_pathname(entry);
        if (!path || !*path) {
            LOGE("%s: Header has null or empty filename", path);
            return false;
        }

        const char *suffix;

        if (mb::util::starts_with(path, common_prefix)) {
            suffix = path + common_prefix.size();
        } else if (mb::util::starts_with(path, theme_prefix)) {
            suffix = path + theme_prefix.size();
        } else {
            LOGV("Skipping: %s", path);
            continue;
        }

        // Build path
        target_path = target;
        if (target_path.back() != '/' && *suffix != '/') {
            target_path += '/';
        }
        target_path += suffix;

        LOGV("Extracting: %s -> %s", path, target_path.c_str());

        archive_entry_set_pathname(entry, target_path.c_str());

        // Extract file
        ret = archive_read_extract2(in.get(), entry, out.get());
        if (ret != ARCHIVE_OK) {
            LOGE("%s: %s", archive_entry_pathname(entry),
                 archive_error_string(in.get()));
            return false;
        }
    }

    if (archive_read_close(in.get()) != ARCHIVE_OK) {
        LOGE("%s: Failed to close file: %s",
             path.c_str(), archive_error_string(in.get()));
        return false;
    }

    return true;
}
Beispiel #30
0
bool libarchive_tar_extract(const std::string &filename,
                            const std::string &target,
                            const std::vector<std::string> &patterns)
{
    if (target.empty()) {
        LOGE("%s: Invalid target path for extraction", target.c_str());
        return false;
    }

    autoclose::archive matcher(archive_match_new(), archive_match_free);
    if (!matcher) {
        LOGE("%s: Out of memory when creating matcher", __FUNCTION__);
        return false;
    }
    autoclose::archive in(archive_read_new(), archive_read_free);
    if (!in) {
        LOGE("%s: Out of memory when creating archive reader", __FUNCTION__);
        return false;
    }
    autoclose::archive out(archive_write_disk_new(), archive_write_free);
    if (!out) {
        LOGE("%s: Out of memory when creating disk writer", __FUNCTION__);
        return false;
    }

    // Set up matcher parameters
    for (const std::string &pattern : patterns) {
        if (archive_match_include_pattern(
                matcher.get(), pattern.c_str()) != ARCHIVE_OK) {
            LOGE("Invalid pattern: %s", pattern.c_str());
            return false;
        }
    }

    // Set up archive reader parameters
    //archive_read_support_format_gnutar(in.get());
    archive_read_support_format_tar(in.get());
    //archive_read_support_filter_bzip2(in.get());
    //archive_read_support_filter_gzip(in.get());
    //archive_read_support_filter_xz(in.get());

    // Set up disk writer parameters
    archive_write_disk_set_standard_lookup(out.get());
    archive_write_disk_set_options(out.get(), LIBARCHIVE_DISK_WRITER_FLAGS);

    if (archive_read_open_filename(
            in.get(), filename.c_str(), 10240) != ARCHIVE_OK) {
        LOGE("%s: Failed to open file: %s",
             filename.c_str(), archive_error_string(in.get()));
        return false;
    }

    archive_entry *entry;
    int ret;
    std::string target_path;

    while (true) {
        ret = archive_read_next_header(in.get(), &entry);
        if (ret == ARCHIVE_EOF) {
            break;
        } else if (ret == ARCHIVE_RETRY) {
            LOGW("%s: Retrying header read", filename.c_str());
            continue;
        } else if (ret != ARCHIVE_OK) {
            LOGE("%s: Failed to read header: %s",
                 filename.c_str(), archive_error_string(in.get()));
            return false;
        }

        const char *path = archive_entry_pathname(entry);
        if (!path || !*path) {
            LOGE("%s: Header has null or empty filename", filename.c_str());
            return false;
        }

        LOGV("%s", path);

        // Build path
        target_path = target;
        if (target_path.back() != '/' && *path != '/') {
            target_path += '/';
        }
        target_path += path;

        archive_entry_set_pathname(entry, target_path.c_str());

        // Check pattern matches
        if (archive_match_excluded(matcher.get(), entry)) {
            continue;
        }

        // Extract file
        ret = archive_read_extract2(in.get(), entry, out.get());
        if (ret != ARCHIVE_OK) {
            LOGE("%s: %s", archive_entry_pathname(entry),
                 archive_error_string(in.get()));
            return false;
        }
    }

    if (archive_read_close(in.get()) != ARCHIVE_OK) {
        LOGE("%s: %s", filename.c_str(), archive_error_string(in.get()));
        return false;
    }

    // Check that all patterns were matched
    const char *pattern;
    while ((ret = archive_match_path_unmatched_inclusions_next(
            matcher.get(), &pattern)) == ARCHIVE_OK) {
        LOGE("%s: Pattern not matched: %s", filename.c_str(), pattern);
    }
    if (ret != ARCHIVE_EOF) {
        LOGE("%s: %s", filename.c_str(), archive_error_string(matcher.get()));
        return false;
    }

    return archive_match_path_unmatched_inclusions(matcher.get()) == 0;
}