/*- * Copyright (c) 2008-2011 Juan Romero Pardines. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include #include #include #include #include #include #include #include "xbps_api_impl.h" /* * Takes a compressed data buffer, decompresses it and returns the * new buffer uncompressed if all was right. */ #define _READ_CHUNK 512 static char * _xbps_uncompress_plist_data(char *xml, size_t len) { z_stream strm; unsigned char out[_READ_CHUNK]; char *uncomp_xml = NULL; size_t have; ssize_t totalsize = 0; int rv = 0; assert(xml != NULL); /* Decompress the mmap'ed buffer with zlib */ strm.zalloc = Z_NULL; strm.zfree = Z_NULL; strm.opaque = Z_NULL; strm.avail_in = 0; strm.next_in = Z_NULL; /* 15+16 to use gzip method */ if (inflateInit2(&strm, 15+16) != Z_OK) return NULL; strm.avail_in = len; strm.next_in = (unsigned char *)xml; /* Output buffer (uncompressed) */ uncomp_xml = malloc(_READ_CHUNK); if (uncomp_xml == NULL) { (void)inflateEnd(&strm); return NULL; } /* Inflate the input buffer and copy into 'uncomp_xml' */ do { strm.avail_out = _READ_CHUNK; strm.next_out = out; rv = inflate(&strm, Z_NO_FLUSH); switch (rv) { case Z_DATA_ERROR: /* * Wrong compressed data or uncompressed, try * normal method as last resort. */ (void)inflateEnd(&strm); free(uncomp_xml); errno = EAGAIN; return NULL; case Z_STREAM_ERROR: case Z_NEED_DICT: case Z_MEM_ERROR: (void)inflateEnd(&strm); free(uncomp_xml); return NULL; } have = _READ_CHUNK - strm.avail_out; totalsize += have; uncomp_xml = realloc(uncomp_xml, totalsize); memcpy(uncomp_xml + totalsize - have, out, have); } while (strm.avail_out == 0); /* we are done */ (void)inflateEnd(&strm); return uncomp_xml; } #undef _READ_CHUNK prop_dictionary_t HIDDEN xbps_read_dict_from_archive_entry(struct archive *ar, struct archive_entry *entry) { prop_dictionary_t d = NULL; size_t buflen = 0; ssize_t nbytes = -1; char *buf, *uncomp_buf; assert(ar != NULL); assert(entry != NULL); buflen = (size_t)archive_entry_size(entry); buf = malloc(buflen); if (buf == NULL) return NULL; nbytes = archive_read_data(ar, buf, buflen); if ((size_t)nbytes != buflen) { free(buf); return NULL; } uncomp_buf = _xbps_uncompress_plist_data(buf, buflen); if (uncomp_buf == NULL) { if (errno && errno != EAGAIN) { /* Error while decompressing */ free(buf); return NULL; } else if (errno == EAGAIN) { /* Not a compressed data, try again */ errno = 0; d = prop_dictionary_internalize(buf); free(buf); } } else { /* We have the uncompressed data */ d = prop_dictionary_internalize(uncomp_buf); free(uncomp_buf); free(buf); } if (d == NULL) return NULL; else if (prop_object_type(d) != PROP_TYPE_DICTIONARY) { prop_object_release(d); return NULL; } return d; }