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; }
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)); }
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); }
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; }
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)); }