static int read_open_memory_internal(struct archive *a, void *buff, size_t size, size_t read_size, int fullapi) { struct read_memory_data *mine; mine = (struct read_memory_data *)malloc(sizeof(*mine)); if (mine == NULL) { archive_set_error(a, ENOMEM, "No memory"); return (ARCHIVE_FATAL); } memset(mine, 0, sizeof(*mine)); mine->buffer = (unsigned char *)buff; mine->end = mine->buffer + size; mine->read_size = read_size; mine->copy_buff_offset = 32; mine->copy_buff_size = read_size + mine->copy_buff_offset * 2; mine->copy_buff = malloc(mine->copy_buff_size); memset(mine->copy_buff, 0xA5, mine->copy_buff_size); if (fullapi) return (archive_read_open2(a, mine, memory_read_open, memory_read, memory_read_skip, memory_read_close)); else return (archive_read_open2(a, mine, NULL, memory_read, NULL, memory_read_close)); }
bool OdinPatcher::Impl::openInputArchive() { assert(aInput == nullptr); aInput = archive_read_new(); // TODO: Eventually support tar within a zip since many people distribute // stock firmware packages in this format //archive_read_support_format_zip(aInput); archive_read_support_format_tar(aInput); archive_read_support_filter_gzip(aInput); archive_read_support_filter_xz(aInput); // Our callbacks use io::File, which supports LFS on Android. Also allows // progress info by counting number of bytes read. int ret = archive_read_open2(aInput, this, &Impl::laOpenCb, &Impl::laReadCb, &Impl::laSkipCb, &Impl::laCloseCb); if (ret != ARCHIVE_OK) { LOGW("libarchive: Failed to open for reading: %s", archive_error_string(aInput)); archive_read_free(aInput); aInput = nullptr; error = ErrorCode::ArchiveReadOpenError; return false; } return true; }
int archive_read_open_qiodevice(struct archive *a, QIODevice *device) { if (device == 0) { qDebug () << "archive_read_open_qiodevice"; archive_set_error(a, -1, "Invalid QIODevice"); return ARCHIVE_FATAL; } if (!device->isOpen() && !device->open(QIODevice::ReadOnly)) { qDebug () << "archive_read_open_qiodevice"; archive_set_error(a, -1, "Could not open QIODevice for reading"); return ARCHIVE_FATAL; } if (!device->isReadable()) { qDebug () << "archive_read_open_qiodevice"; archive_set_error(a, -1, "Could not open QIODevice for reading"); return ARCHIVE_FATAL; } struct read_qiodevice_data *data = new read_qiodevice_data; if (data == 0) { qDebug () << "archive_read_open_qiodevice"; archive_set_error(a, -1, "No Memory"); return ARCHIVE_FATAL; } data->device = device; device->reset(); // Seek to begining of file device->setTextModeEnabled(false); // Binary mode return (archive_read_open2(a, data, NULL, qiodevice_read, qiodevice_read_skip, qiodevice_read_close)); }
int archive_read_open_filename(struct archive *a, const char *filename, size_t block_size) { struct read_file_data *mine; if (filename == NULL || filename[0] == '\0') { mine = (struct read_file_data *)malloc(sizeof(*mine)); if (mine == NULL) { archive_set_error(a, ENOMEM, "No memory"); return (ARCHIVE_FATAL); } mine->filename[0] = '\0'; } else { mine = (struct read_file_data *)malloc(sizeof(*mine) + strlen(filename)); if (mine == NULL) { archive_set_error(a, ENOMEM, "No memory"); return (ARCHIVE_FATAL); } strcpy(mine->filename, filename); } mine->block_size = block_size; mine->buffer = NULL; mine->fd = -1; /* lseek() almost never works; disable it by default. See below. */ mine->can_skip = 0; return (archive_read_open2(a, mine, file_open, file_read, file_skip, file_close)); }
/* * Open the archive */ int archive_read_open(struct archive *a, void *client_data, archive_open_callback *client_opener, archive_read_callback *client_reader, archive_close_callback *client_closer) { /* Old archive_read_open() is just a thin shell around * archive_read_open2. */ return archive_read_open2(a, client_data, client_opener, client_reader, NULL, client_closer); }
static void test(int formatted, archive_open_callback *o, archive_read_callback *r, archive_skip_callback *s, archive_close_callback *c, int rv, const char *msg) { struct archive* a = archive_read_new(); if (formatted) assertEqualInt(ARCHIVE_OK, archive_read_support_format_empty(a)); assertEqualInt(rv, archive_read_open2(a, NULL, o, r, s, c)); assertEqualString(msg, archive_error_string(a)); archive_read_free(a); }
/* * Don't use _open_memory2() in production code; the archive_read_open_memory() * version is the one you really want. This is just here so that * test harnesses can exercise block operations inside the library. */ int archive_read_open_memory2(struct archive *a, void *buff, size_t size, size_t read_size) { struct read_memory_data *mine; mine = (struct read_memory_data *)malloc(sizeof(*mine)); if (mine == NULL) { archive_set_error(a, ENOMEM, "No memory"); return (ARCHIVE_FATAL); } memset(mine, 0, sizeof(*mine)); mine->buffer = (unsigned char *)buff; mine->end = mine->buffer + size; mine->read_size = read_size; return (archive_read_open2(a, mine, memory_read_open, memory_read, memory_read_skip, memory_read_close)); }
/** * archive_read_open_multitape(a, machinenum, tapename): * Open the multitape tape ${tapename} for reading (and skipping) and * associate it with the archive $a$. Return a cookie which can be passed * to the multitape layer. */ void * archive_read_open_multitape(struct archive * a, uint64_t machinenum, const char * tapename) { struct multitape_read_internal * d; /* Clear any error messages from the archive. */ archive_clear_error(a); if ((d = readtape_open(machinenum, tapename)) == NULL) { archive_set_error(a, errno, "Error opening archive"); return (NULL); } if (archive_read_open2(a, d, NULL, read_read, read_skip, read_close)) return (NULL); else return (d); }
int archive_read_open_fd(struct archive *a, int fd, size_t block_size) { struct stat st; struct read_fd_data *mine; void *b; archive_clear_error(a); if (fstat(fd, &st) != 0) { archive_set_error(a, errno, "Can't stat fd %d", fd); return (ARCHIVE_FATAL); } mine = (struct read_fd_data *)malloc(sizeof(*mine)); b = malloc(block_size); if (mine == NULL || b == NULL) { archive_set_error(a, ENOMEM, "No memory"); free(mine); free(b); return (ARCHIVE_FATAL); } mine->block_size = block_size; mine->buffer = b; mine->fd = fd; /* * Skip support is a performance optimization for anything * that supports lseek(). On FreeBSD, only regular files and * raw disk devices support lseek() and there's no portable * way to determine if a device is a raw disk device, so we * only enable this optimization for regular files. */ if (S_ISREG(st.st_mode)) { archive_read_extract_set_skip_file(a, st.st_dev, st.st_ino); mine->can_skip = 1; } else mine->can_skip = 0; #if defined(__CYGWIN__) || defined(_WIN32) setmode(mine->fd, O_BINARY); #endif return (archive_read_open2(a, mine, NULL, file_read, file_skip, file_close)); }
int archive_read_open_FILE(struct archive *a, FILE *f) { struct stat st; struct read_FILE_data *mine; size_t block_size = 128 * 1024; void *b; archive_clear_error(a); mine = (struct read_FILE_data *)malloc(sizeof(*mine)); b = malloc(block_size); if (mine == NULL || b == NULL) { archive_set_error(a, ENOMEM, "No memory"); free(mine); free(b); return (ARCHIVE_FATAL); } mine->block_size = block_size; mine->buffer = b; mine->f = f; /* * If we can't fstat() the file, it may just be that it's not * a file. (FILE * objects can wrap many kinds of I/O * streams, some of which don't support fileno()).) */ if (fstat(fileno(mine->f), &st) == 0 && S_ISREG(st.st_mode)) { archive_read_extract_set_skip_file(a, st.st_dev, st.st_ino); /* Enable the seek optimization only for regular files. */ mine->can_skip = 1; } else mine->can_skip = 0; #if defined(__CYGWIN__) || defined(_WIN32) setmode(fileno(mine->f), O_BINARY); #endif return (archive_read_open2(a, mine, NULL, file_read, file_skip, file_close)); }
int archive_read_open_filename(struct archive *a, const char *filename, size_t block_size) { struct stat st; struct read_file_data *mine; void *b; int fd; archive_clear_error(a); if (filename == NULL || filename[0] == '\0') { /* We used to invoke archive_read_open_fd(a,0,block_size) * here, but that doesn't (and shouldn't) handle the * end-of-file flush when reading stdout from a pipe. * Basically, read_open_fd() is intended for folks who * are willing to handle such details themselves. This * API is intended to be a little smarter for folks who * want easy handling of the common case. */ filename = ""; /* Normalize NULL to "" */ fd = 0; #if defined(__CYGWIN__) || defined(_WIN32) setmode(0, O_BINARY); #endif } else { fd = open(filename, O_RDONLY | O_BINARY); if (fd < 0) { archive_set_error(a, errno, "Failed to open '%s'", filename); return (ARCHIVE_FATAL); } } if (fstat(fd, &st) != 0) { archive_set_error(a, errno, "Can't stat '%s'", filename); return (ARCHIVE_FATAL); } mine = (struct read_file_data *)calloc(1, sizeof(*mine) + strlen(filename)); b = malloc(block_size); if (mine == NULL || b == NULL) { archive_set_error(a, ENOMEM, "No memory"); free(mine); free(b); return (ARCHIVE_FATAL); } strcpy(mine->filename, filename); mine->block_size = block_size; mine->buffer = b; mine->fd = fd; /* Remember mode so close can decide whether to flush. */ mine->st_mode = st.st_mode; /* If we're reading a file from disk, ensure that we don't overwrite it with an extracted file. */ if (S_ISREG(st.st_mode)) { archive_read_extract_set_skip_file(a, st.st_dev, st.st_ino); /* * Enabling skip here is a performance optimization * for anything that supports lseek(). On FreeBSD * (and probably many other systems), only regular * files and raw disk devices support lseek() (on * other input types, lseek() returns success but * doesn't actually change the file pointer, which * just completely screws up the position-tracking * logic). In addition, I've yet to find a portable * way to determine if a device is a raw disk device. * So I don't see a way to do much better than to only * enable this optimization for regular files. */ mine->can_skip = 1; } return (archive_read_open2(a, mine, NULL, file_read, file_skip, file_close)); }
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 foreign_t archive_open_stream(term_t data, term_t handle, term_t options) { IOSTREAM *datas; archive_wrapper *ar; term_t tail = PL_copy_term_ref(options); term_t head = PL_new_term_ref(); term_t arg = PL_new_term_ref(); if ( !PL_get_stream_handle(data, &datas) ) return FALSE; if ( !(datas->flags & SIO_INPUT) ) { PL_release_stream(datas); return PL_domain_error("input_stream", data); } ar = PL_malloc(sizeof(*ar)); memset(ar, 0, sizeof(*ar)); ar->data = datas; ar->magic = ARCHIVE_MAGIC; if ( !PL_unify_blob(handle, ar, sizeof(*ar), &archive_blob) ) return FALSE; while( PL_get_list_ex(tail, head, tail) ) { atom_t name; int arity; if ( !PL_get_name_arity(head, &name, &arity) || !PL_get_arg(1, head, arg) ) return PL_type_error("option", head); if ( name == ATOM_compression || name == ATOM_filter ) { atom_t c; if ( !PL_get_atom_ex(arg, &c) ) return FALSE; if ( c == ATOM_all ) ar->type |= FILTER_ALL; #ifdef FILTER_BZIP2 else if ( c == ATOM_bzip2 ) ar->type |= FILTER_BZIP2; #endif #ifdef FILTER_COMPRESS else if ( c == ATOM_compress ) ar->type |= FILTER_COMPRESS; #endif #ifdef FILTER_GZIP else if ( c == ATOM_gzip ) ar->type |= FILTER_GZIP; #endif #ifdef FILTER_GRZIP else if ( c == ATOM_grzip ) ar->type |= FILTER_GRZIP; #endif #ifdef FILTER_LRZIP else if ( c == ATOM_lrzip ) ar->type |= FILTER_LRZIP; #endif #ifdef FILTER_LZIP else if ( c == ATOM_lzip ) ar->type |= FILTER_LZIP; #endif #ifdef FILTER_LZMA else if ( c == ATOM_lzma ) ar->type |= FILTER_LZMA; #endif #ifdef FILTER_LZOP else if ( c == ATOM_lzop ) ar->type |= FILTER_LZOP; #endif #ifdef FILTER_NONE else if ( c == ATOM_none ) ar->type |= FILTER_NONE; #endif #ifdef FILTER_RPM else if ( c == ATOM_rpm ) ar->type |= FILTER_RPM; #endif #ifdef FILTER_UU else if ( c == ATOM_uu ) ar->type |= FILTER_UU; #endif #ifdef FILTER_XZ else if ( c == ATOM_xz ) ar->type |= FILTER_XZ; #endif else return PL_domain_error("filter", arg); } else if ( name == ATOM_format ) { atom_t f; if ( !PL_get_atom_ex(arg, &f) ) return FALSE; if ( f == ATOM_all ) ar->type |= FORMAT_ALL; #ifdef FORMAT_7ZIP else if ( f == ATOM_7zip ) ar->type |= FORMAT_7ZIP; #endif #ifdef FORMAT_AR else if ( f == ATOM_ar ) ar->type |= FORMAT_AR; #endif #ifdef FORMAT_CAB else if ( f == ATOM_cab ) ar->type |= FORMAT_CAB; #endif #ifdef FORMAT_CPIO else if ( f == ATOM_cpio ) ar->type |= FORMAT_CPIO; #endif #ifdef FORMAT_EMPTY else if ( f == ATOM_empty ) ar->type |= FORMAT_EMPTY; #endif #ifdef FORMAT_GNUTAR else if ( f == ATOM_gnutar ) ar->type |= FORMAT_GNUTAR; #endif #ifdef FORMAT_ISO9960 else if ( f == ATOM_iso9960 ) ar->type |= FORMAT_ISO9960; #endif #ifdef FORMAT_LHA else if ( f == ATOM_lha ) ar->type |= FORMAT_LHA; #endif #ifdef FORMAT_MTREE else if ( f == ATOM_mtree ) ar->type |= FORMAT_MTREE; #endif #ifdef FORMAT_RAR else if ( f == ATOM_rar ) ar->type |= FORMAT_RAR; #endif #ifdef FORMAT_RAW else if ( f == ATOM_raw ) ar->type |= FORMAT_RAW; #endif #ifdef FORMAT_TAR else if ( f == ATOM_tar ) ar->type |= FORMAT_TAR; #endif #ifdef FORMAT_XAR else if ( f == ATOM_xar ) ar->type |= FORMAT_XAR; #endif #ifdef FORMAT_ZIP else if ( f == ATOM_zip ) ar->type |= FORMAT_ZIP; #endif else return PL_domain_error("format", arg); } else if ( name == ATOM_close_parent ) { if ( !PL_get_bool_ex(arg, &ar->close_parent) ) return FALSE; } } if ( !PL_get_nil_ex(tail) ) return FALSE; if ( !(ar->type & FILTER_ALL) ) ar->type |= FILTER_ALL; if ( !(ar->type & FORMAT_MASK) ) ar->type |= FORMAT_ALL; if ( !(ar->archive = archive_read_new()) ) return PL_resource_error("memory"); if ( (ar->type & FILTER_ALL) == FILTER_ALL ) { archive_read_support_filter_all(ar->archive); } else { #ifdef FILTER_BZIP2 enable_type(ar, FILTER_BZIP2, archive_read_support_filter_bzip2); #endif #ifdef FILTER_COMPRESS enable_type(ar, FILTER_COMPRESS, archive_read_support_filter_compress); #endif #ifdef FILTER_GZIP enable_type(ar, FILTER_GZIP, archive_read_support_filter_gzip); #endif #ifdef FILTER_GRZIP enable_type(ar, FILTER_GRZIP, archive_read_support_filter_grzip); #endif #ifdef FILTER_LRZIP enable_type(ar, FILTER_LRZIP, archive_read_support_filter_lrzip); #endif #ifdef FILTER_LZIP enable_type(ar, FILTER_LZIP, archive_read_support_filter_lzip); #endif #ifdef FILTER_LZMA enable_type(ar, FILTER_LZMA, archive_read_support_filter_lzma); #endif #ifdef FILTER_LZOP enable_type(ar, FILTER_LZOP, archive_read_support_filter_lzop); #endif #ifdef FILTER_NONE enable_type(ar, FILTER_NONE, archive_read_support_filter_none); #endif #ifdef FILTER_RPM enable_type(ar, FILTER_RPM, archive_read_support_filter_rpm); #endif #ifdef FILTER_UU enable_type(ar, FILTER_UU, archive_read_support_filter_uu); #endif #ifdef FILTER_XZ enable_type(ar, FILTER_XZ, archive_read_support_filter_xz); #endif } if ( (ar->type & FORMAT_ALL) == FORMAT_ALL ) { archive_read_support_format_all(ar->archive); #ifdef FORMAT_RAW enable_type(ar, FORMAT_RAW, archive_read_support_format_raw); #endif } else { #ifdef FORMAT_7ZIP enable_type(ar, FORMAT_7ZIP, archive_read_support_format_7zip); #endif #ifdef FORMAT_AR enable_type(ar, FORMAT_AR, archive_read_support_format_ar); #endif #ifdef FORMAT_CAB enable_type(ar, FORMAT_CAB, archive_read_support_format_cab); #endif #ifdef FORMAT_CPIO enable_type(ar, FORMAT_CPIO, archive_read_support_format_cpio); #endif #ifdef FORMAT_EMPTY enable_type(ar, FORMAT_EMPTY, archive_read_support_format_empty); #endif #ifdef FORMAT_GNUTAR enable_type(ar, FORMAT_GNUTAR, archive_read_support_format_gnutar); #endif #ifdef FORMAT_ISO9960 enable_type(ar, FORMAT_ISO9960, archive_read_support_format_iso9660); #endif #ifdef FORMAT_LHA enable_type(ar, FORMAT_LHA, archive_read_support_format_lha); #endif #ifdef FORMAT_MTREE enable_type(ar, FORMAT_MTREE, archive_read_support_format_mtree); #endif #ifdef FORMAT_RAR enable_type(ar, FORMAT_RAR, archive_read_support_format_rar); #endif #ifdef FORMAT_RAW enable_type(ar, FORMAT_RAW, archive_read_support_format_raw); #endif #ifdef FORMAT_TAR enable_type(ar, FORMAT_TAR, archive_read_support_format_tar); #endif #ifdef FORMAT_XAR enable_type(ar, FORMAT_XAR, archive_read_support_format_xar); #endif #ifdef FORMAT_ZIP enable_type(ar, FORMAT_ZIP, archive_read_support_format_zip); #endif } #ifdef HAVE_ARCHIVE_READ_OPEN1 archive_read_set_callback_data(ar->archive, ar); archive_read_set_open_callback(ar->archive, ar_open); archive_read_set_read_callback(ar->archive, ar_read); archive_read_set_skip_callback(ar->archive, ar_skip); archive_read_set_seek_callback(ar->archive, ar_seek); archive_read_set_close_callback(ar->archive, ar_close); if ( archive_read_open1(ar->archive) == ARCHIVE_OK ) { ar->status = AR_OPENED; return TRUE; } #else if ( archive_read_open2(ar->archive, ar, ar_open, ar_read, ar_skip, ar_close) == ARCHIVE_OK ) { ar->status = AR_OPENED; return TRUE; } #endif return archive_error(ar); }