XBPS Library API  0.19
The X Binary Package System
plist_archive_entry.c
1 /*-
2  * Copyright (c) 2008-2012 Juan Romero Pardines.
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  * 1. Redistributions of source code must retain the above copyright
9  * notice, this list of conditions and the following disclaimer.
10  * 2. Redistributions in binary form must reproduce the above copyright
11  * notice, this list of conditions and the following disclaimer in the
12  * documentation and/or other materials provided with the distribution.
13  *
14  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
15  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
16  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
17  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
18  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
19  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
20  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
21  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
22  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
23  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
24  */
25 
26 #include <stdio.h>
27 #include <stdbool.h>
28 #include <stdlib.h>
29 #include <string.h>
30 #include <errno.h>
31 #include <zlib.h>
32 
33 #include "xbps_api_impl.h"
34 
35 /*
36  * Takes a compressed data buffer, decompresses it and returns the
37  * new buffer uncompressed if all was right.
38  */
39 #define _READ_CHUNK 8192
40 
41 static char *
42 _xbps_uncompress_plist_data(char *xml, size_t len)
43 {
44  z_stream strm;
45  unsigned char *out;
46  char *uncomp_xml = NULL;
47  size_t have;
48  ssize_t totalsize = 0;
49  int rv = 0;
50 
51  assert(xml != NULL);
52 
53  /* Decompress the mmap'ed buffer with zlib */
54  strm.zalloc = Z_NULL;
55  strm.zfree = Z_NULL;
56  strm.opaque = Z_NULL;
57  strm.avail_in = 0;
58  strm.next_in = Z_NULL;
59 
60  /* 15+16 to use gzip method */
61  if (inflateInit2(&strm, 15+16) != Z_OK)
62  return NULL;
63 
64  strm.avail_in = len;
65  strm.next_in = (unsigned char *)xml;
66 
67  /* Output buffer (uncompressed) */
68  if ((uncomp_xml = malloc(_READ_CHUNK)) == NULL) {
69  (void)inflateEnd(&strm);
70  return NULL;
71  }
72 
73  /* temp output buffer for inflate */
74  if ((out = malloc(_READ_CHUNK)) == NULL) {
75  (void)inflateEnd(&strm);
76  free(uncomp_xml);
77  return NULL;
78  }
79 
80  /* Inflate the input buffer and copy into 'uncomp_xml' */
81  do {
82  strm.avail_out = _READ_CHUNK;
83  strm.next_out = out;
84  rv = inflate(&strm, Z_NO_FLUSH);
85  switch (rv) {
86  case Z_DATA_ERROR:
87  case Z_STREAM_ERROR:
88  case Z_NEED_DICT:
89  case Z_MEM_ERROR:
90  case Z_BUF_ERROR:
91  case Z_VERSION_ERROR:
92  (void)inflateEnd(&strm);
93  free(uncomp_xml);
94  free(out);
95  return NULL;
96  }
97  have = _READ_CHUNK - strm.avail_out;
98  totalsize += have;
99  uncomp_xml = realloc(uncomp_xml, totalsize);
100  memcpy(uncomp_xml + totalsize - have, out, have);
101  } while (strm.avail_out == 0);
102 
103  /* we are done */
104  (void)inflateEnd(&strm);
105  free(out);
106 
107  return uncomp_xml;
108 }
109 #undef _READ_CHUNK
110 
111 prop_dictionary_t HIDDEN
112 xbps_dictionary_from_archive_entry(struct archive *ar,
113  struct archive_entry *entry)
114 {
115  prop_dictionary_t d = NULL;
116  size_t buflen;
117  ssize_t nbytes = -1;
118  char *buf, *uncomp_buf;
119 
120  assert(ar != NULL);
121  assert(entry != NULL);
122 
123  buflen = (size_t)archive_entry_size(entry);
124  buf = malloc(buflen);
125  if (buf == NULL)
126  return NULL;
127 
128  nbytes = archive_read_data(ar, buf, buflen);
129  if ((size_t)nbytes != buflen) {
130  free(buf);
131  return NULL;
132  }
133 
134  /* If blob is already a dictionary we are done */
135  d = prop_dictionary_internalize(buf);
136  if (prop_object_type(d) == PROP_TYPE_DICTIONARY)
137  goto out;
138 
139  /* Try to uncompress blob */
140  uncomp_buf = _xbps_uncompress_plist_data(buf, buflen);
141  if (uncomp_buf == NULL) {
142  /* Error while decompressing */
143  free(buf);
144  return NULL;
145  } else {
146  /* We have the uncompressed data */
147  d = prop_dictionary_internalize(uncomp_buf);
148  free(uncomp_buf);
149  }
150 
151 out:
152  free(buf);
153  return d;
154 }