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