示例#1
0
struct mp_archive *mp_archive_new(struct mp_log *log, struct stream *src,
                                  int flags)
{
    struct mp_archive *mpa = talloc_zero(NULL, struct mp_archive);
    mpa->log = log;
    mpa->locale = newlocale(LC_ALL_MASK, "C.UTF-8", (locale_t)0);
    if (!mpa->locale)
        goto err;
    mpa->arch = archive_read_new();
    mpa->primary_src = src;
    if (!mpa->arch)
        goto err;

    // first volume is the primary streame
    if (!add_volume(log ,mpa, src, src->url))
        goto err;

    // try to open other volumes
    char** volumes = find_volumes(src);
    for (int i = 0; volumes[i]; i++) {
        if (!add_volume(log, mpa, NULL, volumes[i])) {
            talloc_free(volumes);
            goto err;
        }
    }
    talloc_free(volumes);

    locale_t oldlocale = uselocale(mpa->locale);

    archive_read_support_format_7zip(mpa->arch);
    archive_read_support_format_iso9660(mpa->arch);
    archive_read_support_format_rar(mpa->arch);
    archive_read_support_format_zip(mpa->arch);
    archive_read_support_filter_bzip2(mpa->arch);
    archive_read_support_filter_gzip(mpa->arch);
    archive_read_support_filter_xz(mpa->arch);
    if (flags & MP_ARCHIVE_FLAG_UNSAFE) {
        archive_read_support_format_gnutar(mpa->arch);
        archive_read_support_format_tar(mpa->arch);
    }

    archive_read_set_read_callback(mpa->arch, read_cb);
    archive_read_set_skip_callback(mpa->arch, skip_cb);
    archive_read_set_switch_callback(mpa->arch, switch_cb);
    archive_read_set_open_callback(mpa->arch, open_cb);
    archive_read_set_close_callback(mpa->arch, close_cb);
    if (mpa->primary_src->seekable)
        archive_read_set_seek_callback(mpa->arch, seek_cb);
    bool fail = archive_read_open1(mpa->arch) < ARCHIVE_OK;

    uselocale(oldlocale);

    if (fail)
        goto err;
    return mpa;

err:
    mp_archive_free(mpa);
    return NULL;
}
示例#2
0
int
archive_read_open_filename_w(struct archive *a, const wchar_t *wfilename,
    size_t block_size)
{
	struct read_file_data *mine = (struct read_file_data *)calloc(1,
		sizeof(*mine) + wcslen(wfilename) * sizeof(wchar_t));
	if (!mine)
	{
		archive_set_error(a, ENOMEM, "No memory");
		return (ARCHIVE_FATAL);
	}
	mine->fd = -1;
	mine->block_size = block_size;

	if (wfilename == NULL || wfilename[0] == L'\0') {
		mine->filename_type = FNT_STDIN;
	} else {
#if defined(_WIN32) && !defined(__CYGWIN__)
		mine->filename_type = FNT_WCS;
		wcscpy(mine->filename.w, wfilename);
#else
		/*
		 * POSIX system does not support a wchar_t interface for
		 * open() system call, so we have to translate a whcar_t
		 * filename to multi-byte one and use it.
		 */
		struct archive_string fn;

		archive_string_init(&fn);
		if (archive_string_append_from_wcs(&fn, wfilename,
		    wcslen(wfilename)) != 0) {
			if (errno == ENOMEM)
				archive_set_error(a, errno,
				    "Can't allocate memory");
			else
				archive_set_error(a, EINVAL,
				    "Failed to convert a wide-character"
				    " filename to a multi-byte filename");
			archive_string_free(&fn);
			free(mine);
			return (ARCHIVE_FATAL);
		}
		mine->filename_type = FNT_MBS;
		strcpy(mine->filename.m, fn.s);
		archive_string_free(&fn);
#endif
	}
	if (archive_read_append_callback_data(a, mine) != (ARCHIVE_OK))
		return (ARCHIVE_FATAL);
	archive_read_set_open_callback(a, file_open);
	archive_read_set_read_callback(a, file_read);
	archive_read_set_skip_callback(a, file_skip);
	archive_read_set_close_callback(a, file_close);
	archive_read_set_switch_callback(a, file_switch);
	archive_read_set_seek_callback(a, file_seek);

	return (archive_read_open1(a));
}
示例#3
0
int
archive_read_open_filenames(struct archive *a, const char **filenames,
    size_t block_size)
{
	struct read_file_data *mine;
	const char *filename = NULL;
	if (filenames)
		filename = *(filenames++);

	archive_clear_error(a);
	do
	{
		if (filename == NULL)
			filename = "";
		mine = (struct read_file_data *)calloc(1,
			sizeof(*mine) + strlen(filename));
		if (mine == NULL)
			goto no_memory;
		strcpy(mine->filename.m, filename);
		mine->block_size = block_size;
		mine->fd = -1;
		mine->buffer = NULL;
		mine->st_mode = mine->use_lseek = 0;
		if (filename == NULL || filename[0] == '\0') {
			mine->filename_type = FNT_STDIN;
		} else
			mine->filename_type = FNT_MBS;
		if (archive_read_append_callback_data(a, mine) != (ARCHIVE_OK))
			return (ARCHIVE_FATAL);
		if (filenames == NULL)
			break;
		filename = *(filenames++);
	} while (filename != NULL && filename[0] != '\0');
	archive_read_set_open_callback(a, file_open);
	archive_read_set_read_callback(a, file_read);
	archive_read_set_skip_callback(a, file_skip);
	archive_read_set_close_callback(a, file_close);
	archive_read_set_switch_callback(a, file_switch);
	archive_read_set_seek_callback(a, file_seek);

	return (archive_read_open1(a));
no_memory:
	archive_set_error(a, ENOMEM, "No memory");
	return (ARCHIVE_FATAL);
}
示例#4
0
文件: archive.c 项目: mstorsjo/vlc
static int archive_init( private_sys_t* p_sys, stream_t* source )
{
    /* CREATE ARCHIVE HANDLE */

    p_sys->p_archive = archive_read_new();

    if( unlikely( !p_sys->p_archive ) )
    {
        msg_Dbg( p_sys->p_obj, "unable to create libarchive handle" );
        return VLC_EGENERIC;
    }

    /* SETUP SEEKING */

    p_sys->b_seekable_archive = false;

    if( vlc_stream_Control( source, STREAM_CAN_SEEK,
        &p_sys->b_seekable_source ) )
    {
        msg_Warn( p_sys->p_obj, "unable to query whether source stream can seek" );
        p_sys->b_seekable_source = false;
    }

    if( p_sys->b_seekable_source )
    {
        if( archive_read_set_seek_callback( p_sys->p_archive,
            libarchive_seek_cb ) )
        {
            msg_Err( p_sys->p_obj, "archive_read_set_callback failed, aborting." );
            return VLC_EGENERIC;
        }
    }

    /* ENABLE ALL FORMATS/FILTERS */

    archive_read_support_filter_all( p_sys->p_archive );
    archive_read_support_format_all( p_sys->p_archive );

    /* REGISTER CALLBACK DATA */

    if( archive_read_set_switch_callback( p_sys->p_archive,
        libarchive_jump_cb ) )
    {
        msg_Err( p_sys->p_obj, "archive_read_set_switch_callback failed, aborting." );
        return VLC_EGENERIC;
    }

    for( size_t i = 0; i < p_sys->i_callback_data; ++i )
    {
        if( archive_read_append_callback_data( p_sys->p_archive,
            p_sys->pp_callback_data[i] ) )
        {
            return VLC_EGENERIC;
        }
    }

    /* OPEN THE ARCHIVE */

    if( archive_read_open2( p_sys->p_archive, p_sys->pp_callback_data[0], NULL,
        libarchive_read_cb, libarchive_skip_cb, libarchive_exit_cb ) )
    {
        msg_Dbg( p_sys->p_obj, "libarchive: %s",
          archive_error_string( p_sys->p_archive ) );

        return VLC_EGENERIC;
    }

    return VLC_SUCCESS;
}
示例#5
0
文件: access.c 项目: 9034725985/vlc
int AccessOpen(vlc_object_t *p_object)
{
    access_t *p_access = (access_t*)p_object;
    const char *sep = strchr(p_access->psz_location, ARCHIVE_SEP_CHAR);
    if (sep == NULL)
        return VLC_EGENERIC;

    char *psz_base = strdup(p_access->psz_location);
    if (unlikely(psz_base == NULL))
        return VLC_ENOMEM;

    char *psz_name = psz_base + (sep - p_access->psz_location);
    *(psz_name++) = '\0';

    if (decode_URI(psz_base) == NULL)
    {
        free(psz_base);
        return VLC_EGENERIC;
    }

    access_sys_t *p_sys = p_access->p_sys = calloc(1, sizeof(access_sys_t));
    p_sys->p_archive = archive_read_new();
    if (!p_sys->p_archive)
    {
        msg_Err(p_access, "can't create libarchive instance: %s",
                archive_error_string(p_sys->p_archive));
        free(psz_base);
        goto error;
    }

    EnableArchiveFormats(p_sys->p_archive);

    /* Set up the switch callback for multiple volumes handling */
    archive_read_set_switch_callback(p_sys->p_archive, SwitchCallback);

    /* !Warn: sucks because libarchive can't guess format without reading 1st header
     *        and it can't tell either if volumes are missing neither set following
     *        volumes after the first Open().
     *        We need to know volumes uri in advance then :/
     */

    /* Try to list existing volumes */
    char **ppsz_files = NULL;
    unsigned int i_files = 0;
    FindVolumes(p_access, p_sys->p_archive, psz_base, &ppsz_files, &i_files);

    p_sys->i_callback_data = 1 + i_files;
    p_sys->p_callback_data = malloc(sizeof(callback_data_t) * p_sys->i_callback_data);
    if (!p_sys->p_callback_data)
    {
        for(unsigned int i=0; i<i_files; i++)
            free(ppsz_files[i]);
        free(ppsz_files);
        free(psz_base);
        AccessClose(p_object);
        return VLC_ENOMEM;
    }

    /* set up our callback struct for our main uri */
    p_sys->p_callback_data[0].psz_uri = psz_base;
    p_sys->p_callback_data[0].p_access = p_access;
    archive_read_append_callback_data(p_sys->p_archive, &p_sys->p_callback_data[0]);

    /* and register other volumes */
    for(unsigned int i=0; i<i_files; i++)
    {
        p_sys->p_callback_data[1+i].psz_uri = ppsz_files[i];
        p_sys->p_callback_data[1+i].p_access = p_access;
        archive_read_append_callback_data(p_sys->p_archive, &p_sys->p_callback_data[1+i]);
    }
    free(ppsz_files);

    if (archive_read_open2(p_sys->p_archive, &p_sys->p_callback_data[0],
                           OpenCallback, ReadCallback, SkipCallback, CloseCallback) != ARCHIVE_OK)
    {
        msg_Err(p_access, "can't open archive: %s",
                archive_error_string(p_sys->p_archive));
        AccessClose(p_object);
        return VLC_EGENERIC;
    }

    bool b_present = false;
    while(archive_read_next_header(p_sys->p_archive, &p_sys->p_entry) == ARCHIVE_OK)
    {
        if (!strcmp(archive_entry_pathname(p_sys->p_entry), psz_name))
        {
            b_present = true;
            break;
        }
        msg_Dbg(p_access, "skipping entry %s != %s", archive_entry_pathname(p_sys->p_entry), psz_name);
    }

    if (!b_present)
    {
        msg_Err(p_access, "entry '%s' not found in archive", psz_name);
        /* entry not found */
        goto error;
    }

    msg_Dbg(p_access, "reading entry %s %"PRId64, archive_entry_pathname(p_sys->p_entry),
                                                  archive_entry_size(p_sys->p_entry));

    /* try to guess if it is seekable or not (does not depend on backend) */
    p_sys->b_seekable = (archive_seek_data(p_sys->p_archive, 0, SEEK_SET) >= 0);

    p_access->pf_read    = Read;
    p_access->pf_block   = NULL; /* libarchive's zerocopy keeps owning block :/ */
    p_access->pf_control = Control;
    p_access->pf_seek    = Seek;

    access_InitFields(p_access);

    return VLC_SUCCESS;

error:
    AccessClose(p_object);
    return VLC_EGENERIC;
}
static void
test_customized_multiple_data_objects(void)
{
  char buff[64];
  static const char *reffiles[] =
  {
    "test_read_splitted_rar_aa",
    "test_read_splitted_rar_ab",
    "test_read_splitted_rar_ac",
    "test_read_splitted_rar_ad",
    NULL
  };
  const char test_txt[] = "test text document\r\n";
  int size = sizeof(test_txt)-1;
  struct archive_entry *ae;
  struct archive *a;
  struct mydata *mydata;
  const char *filename = *reffiles;
  int i;

  extract_reference_files(reffiles);
  assert((a = archive_read_new()) != NULL);
  assertA(0 == archive_read_support_filter_all(a));
  assertA(0 == archive_read_support_format_all(a));

  for (i = 0; filename != NULL;)
  {
    assert((mydata = (struct mydata *)calloc(1, sizeof(*mydata))) != NULL);
    assert((mydata->filename =
      (char *)calloc(1, strlen(filename) + 1)) != NULL);
    strcpy(mydata->filename, filename);
    mydata->fd = -1;
    filename = reffiles[++i];
    assertA(0 == archive_read_append_callback_data(a, mydata));
  }
	assertA(0 == archive_read_set_open_callback(a, file_open));
	assertA(0 == archive_read_set_read_callback(a, file_read));
	assertA(0 == archive_read_set_skip_callback(a, file_skip));
	assertA(0 == archive_read_set_close_callback(a, file_close));
	assertA(0 == archive_read_set_switch_callback(a, file_switch));
  assertA(0 == archive_read_set_seek_callback(a, file_seek));
  assertA(0 == archive_read_open1(a));

  /* First header. */
  assertA(0 == archive_read_next_header(a, &ae));
  assertEqualString("test.txt", archive_entry_pathname(ae));
  assertA((int)archive_entry_mtime(ae));
  assertA((int)archive_entry_ctime(ae));
  assertA((int)archive_entry_atime(ae));
  assertEqualInt(20, archive_entry_size(ae));
  assertEqualInt(33188, archive_entry_mode(ae));
  assertA(size == archive_read_data(a, buff, size));
  assertEqualMem(buff, test_txt, size);

  /* Second header. */
  assertA(0 == archive_read_next_header(a, &ae));
  assertEqualString("testlink", archive_entry_pathname(ae));
  assertA((int)archive_entry_mtime(ae));
  assertA((int)archive_entry_ctime(ae));
  assertA((int)archive_entry_atime(ae));
  assertEqualInt(0, archive_entry_size(ae));
  assertEqualInt(41471, archive_entry_mode(ae));
  assertEqualString("test.txt", archive_entry_symlink(ae));
  assertEqualIntA(a, 0, archive_read_data(a, buff, sizeof(buff)));

  /* Third header. */
  assertA(0 == archive_read_next_header(a, &ae));
  assertEqualString("testdir/test.txt", archive_entry_pathname(ae));
  assertA((int)archive_entry_mtime(ae));
  assertA((int)archive_entry_ctime(ae));
  assertA((int)archive_entry_atime(ae));
  assertEqualInt(20, archive_entry_size(ae));
  assertEqualInt(33188, archive_entry_mode(ae));
  assertA(size == archive_read_data(a, buff, size));
  assertEqualMem(buff, test_txt, size);

  /* Fourth header. */
  assertA(0 == archive_read_next_header(a, &ae));
  assertEqualString("testdir", archive_entry_pathname(ae));
  assertA((int)archive_entry_mtime(ae));
  assertA((int)archive_entry_ctime(ae));
  assertA((int)archive_entry_atime(ae));
  assertEqualInt(0, archive_entry_size(ae));
  assertEqualInt(16877, archive_entry_mode(ae));

  /* Fifth header. */
  assertA(0 == archive_read_next_header(a, &ae));
  assertEqualString("testemptydir", archive_entry_pathname(ae));
  assertA((int)archive_entry_mtime(ae));
  assertA((int)archive_entry_ctime(ae));
  assertA((int)archive_entry_atime(ae));
  assertEqualInt(0, archive_entry_size(ae));
  assertEqualInt(16877, archive_entry_mode(ae));

  /* Test EOF */
  assertA(1 == archive_read_next_header(a, &ae));
  assertEqualInt(5, archive_file_count(a));
  assertEqualIntA(a, ARCHIVE_OK, archive_read_close(a));
  assertEqualInt(ARCHIVE_OK, archive_read_free(a));
}