XBPS Library API 20260501
The X Binary Package System
archive.c
1/*-
2 * Copyright (c) 2008-2014 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
32#include <archive.h>
33#include <archive_entry.h>
34
35#include "fetch.h"
36#include "xbps_api_impl.h"
37
38int HIDDEN
39xbps_archive_errno(struct archive *ar)
40{
41 int err = archive_errno(ar);
42 return err == -1 ? EINVAL : err;
43}
44
45char HIDDEN *
46xbps_archive_get_file(struct archive *ar, struct archive_entry *entry)
47{
48 int64_t entry_size;
49 size_t used = 0;
50 size_t len;
51 char *buf;
52 int r;
53
54 assert(ar != NULL);
55 assert(entry != NULL);
56
57 entry_size = archive_entry_size(entry);
58 if (entry_size < 0 || (uint64_t)entry_size >= SIZE_MAX) {
59 errno = EOVERFLOW;
60 return NULL;
61 }
62 len = entry_size;
63
64 buf = malloc(len + 1);
65 if (!buf) {
67 errno = ENOMEM;
68 return NULL;
69 }
70
71 for (;;) {
72 ssize_t rd = archive_read_data(ar, buf + used, len - used);
73 if (rd == ARCHIVE_FATAL || rd == ARCHIVE_WARN) {
74 const char *pname = archive_entry_pathname(entry);
75 if (!pname)
77 r = -xbps_archive_errno(ar);
79 "failed to read archive entry: %s: %s\n",
80 pname, archive_error_string(ar));
81 goto err;
82 } else if (rd == ARCHIVE_RETRY) {
83 continue;
84 }
85 used += rd;
86 if (rd == 0 || used == len)
87 break;
88 }
89 if (used < len) {
90 const char *pname = archive_entry_pathname(entry);
91 if (!pname)
93 r = -EIO;
95 "failed to read archive entry: %s: could not read enough "
96 "data: %s\n", pname, strerror(-r));
97 goto err;
98 }
99
100 buf[len] = '\0';
101 return buf;
102err:
103 free(buf);
104 errno = -r;
105 return NULL;
106}
107
108xbps_dictionary_t HIDDEN
109xbps_archive_get_dictionary(struct archive *ar, struct archive_entry *entry)
110{
111 xbps_dictionary_t d = NULL;
112 char *buf;
113
114 if ((buf = xbps_archive_get_file(ar, entry)) == NULL)
115 return NULL;
116
117 /* If blob is already a dictionary we are done */
118 d = xbps_dictionary_internalize(buf);
119 free(buf);
120 return d;
121}
122
123int
124xbps_archive_append_buf(struct archive *ar, const void *buf, const size_t buflen,
125 const char *fname, const mode_t mode, const char *uname, const char *gname)
126{
127 struct archive_entry *entry;
128
129 assert(ar);
130 assert(buf);
131 assert(fname);
132 assert(uname);
133 assert(gname);
134
135 entry = archive_entry_new();
136 if (!entry)
137 return -xbps_archive_errno(ar);
138
139 archive_entry_set_filetype(entry, AE_IFREG);
140 archive_entry_set_perm(entry, mode);
141 archive_entry_set_uname(entry, uname);
142 archive_entry_set_gname(entry, gname);
143 archive_entry_set_pathname(entry, fname);
144 archive_entry_set_size(entry, buflen);
145
146 if (archive_write_header(ar, entry) != ARCHIVE_OK) {
147 archive_entry_free(entry);
148 return -xbps_archive_errno(ar);
149 }
150 if (archive_write_data(ar, buf, buflen) != ARCHIVE_OK) {
151 archive_entry_free(entry);
152 return -xbps_archive_errno(ar);
153 }
154 if (archive_write_finish_entry(ar) != ARCHIVE_OK) {
155 archive_entry_free(entry);
156 return -xbps_archive_errno(ar);
157 }
158 archive_entry_free(entry);
159
160 return 0;
161}
162
163struct fetch_archive {
164 struct url *url;
165 struct fetchIO *fetch;
166 char buffer[32768];
167};
168
169static int
170fetch_archive_open(struct archive *a, void *client_data)
171{
172 struct fetch_archive *f = client_data;
173
174 f->fetch = fetchGet(f->url, NULL);
175 if (!f->fetch) {
176 const char *errstr = xbps_fetch_error_string();
177 int err;
178 switch (fetchLastErrCode) {
179 case FETCH_UNAVAIL:
180 err = ENOENT;
181 break;
182 default:
183 err = EIO;
184 break;
185 }
186 archive_set_error(a, err, "%s", errstr ? errstr : "unknown fetch error");
187 return ARCHIVE_FATAL;
188 }
189
190 return ARCHIVE_OK;
191}
192
193static ssize_t
194fetch_archive_read(struct archive *a UNUSED, void *client_data, const void **buf)
195{
196 struct fetch_archive *f = client_data;
197 ssize_t rd;
198
199 *buf = f->buffer;
200 rd = fetchIO_read(f->fetch, f->buffer, sizeof(f->buffer));
201 if (rd == -1) {
202 const char *errstr = xbps_fetch_error_string();
203 archive_set_error(a, EIO, "%s", errstr ? errstr : "unknown fetch error");
204 return -1;
205 }
206 return rd;
207}
208
209static int
210fetch_archive_close(struct archive *a UNUSED, void *client_data)
211{
212 struct fetch_archive *f = client_data;
213
214 if (f->fetch != NULL)
215 fetchIO_close(f->fetch);
216 fetchFreeURL(f->url);
217 free(f);
218
219 return 0;
220}
221
222struct archive HIDDEN *
223xbps_archive_read_new(void)
224{
225 struct archive *ar = archive_read_new();
226 if (!ar)
227 return NULL;
228 archive_read_support_filter_gzip(ar);
229 archive_read_support_filter_bzip2(ar);
230 archive_read_support_filter_xz(ar);
231 archive_read_support_filter_lz4(ar);
232 archive_read_support_filter_zstd(ar);
233 archive_read_support_format_tar(ar);
234 return ar;
235}
236
237int HIDDEN
238xbps_archive_read_open(struct archive *ar, const char *filename)
239{
240 int r = archive_read_open_filename(ar, filename, 4096);
241 if (r == ARCHIVE_FATAL)
242 return -xbps_archive_errno(ar);
243 return 0;
244}
245
246int HIDDEN
247xbps_archive_read_open_remote(struct archive *ar, const char *url)
248{
249 struct url *furl;
250 struct fetch_archive *f;
251 int r;
252
253 furl = fetchParseURL(url);
254 if (!furl)
255 return -EINVAL;
256
257 f = calloc(1, sizeof(*f));
258 if (!f) {
259 r = -errno;
260 fetchFreeURL(furl);
261 return r;
262 }
263 f->url = furl;
264
265 r = archive_read_open(ar, f, fetch_archive_open, fetch_archive_read,
266 fetch_archive_close);
267 if (r == ARCHIVE_FATAL) {
268 return -xbps_archive_errno(ar);
269 }
270
271 return 0;
272}
int xbps_archive_append_buf(struct archive *ar, const void *buf, const size_t buflen, const char *fname, const mode_t mode, const char *uname, const char *gname)
Definition archive.c:124
const char * xbps_fetch_error_string(void)
Definition download.c:89
#define xbps_unreachable()
Log and abort for code that should be unreachable.
Definition xbps.h:783
#define xbps_error_oom()
Log out of memory condition.
Definition xbps.h:776
void xbps_error_printf(const char *fmt,...)
Prints error messages to stderr.
Definition log.c:93