1 /*#############################################################################
3 # Pakfire - The IPFire package management system #
4 # Copyright (C) 2013 Pakfire development team #
6 # This program is free software: you can redistribute it and/or modify #
7 # it under the terms of the GNU General Public License as published by #
8 # the Free Software Foundation, either version 3 of the License, or #
9 # (at your option) any later version. #
11 # This program is distributed in the hope that it will be useful, #
12 # but WITHOUT ANY WARRANTY; without even the implied warranty of #
13 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the #
14 # GNU General Public License for more details. #
16 # You should have received a copy of the GNU General Public License #
17 # along with this program. If not, see <http://www.gnu.org/licenses/>. #
19 #############################################################################*/
26 #include <solv/repo.h>
27 #include <solv/repo_solv.h>
28 #include <solv/repo_write.h>
32 #include <pakfire/constants.h>
33 #include <pakfire/errno.h>
34 #include <pakfire/logging.h>
35 #include <pakfire/package.h>
36 #include <pakfire/pakfire.h>
37 #include <pakfire/private.h>
38 #include <pakfire/repo.h>
39 #include <pakfire/types.h>
40 #include <pakfire/util.h>
42 const uint8_t XZ_HEADER_MAGIC
[] = { 0xFD, '7', 'z', 'X', 'Z', 0x00 };
43 const size_t XZ_HEADER_LENGTH
= sizeof(XZ_HEADER_MAGIC
);
45 struct pakfire_repo_appdata
{
54 struct pakfire_repo_appdata
* appdata
;
58 static void free_repo_appdata(struct pakfire_repo_appdata
* appdata
) {
59 // repodata is being destroyed with the repository
62 pakfire_free(appdata
->baseurl
);
64 pakfire_free(appdata
);
67 void pakfire_repo_free_all(Pakfire pakfire
) {
68 Pool
* pool
= pakfire_get_solv_pool(pakfire
);
74 free_repo_appdata(repo
->appdata
);
79 PAKFIRE_EXPORT PakfireRepo
pakfire_repo_create(Pakfire pakfire
, const char* name
) {
80 PakfireRepo repo
= pakfire_calloc(1, sizeof(*repo
));
82 DEBUG("Allocated Repo at %p\n", repo
);
85 repo
->pakfire
= pakfire_ref(pakfire
);
87 // Allocate a libsolv repository
88 Pool
* pool
= pakfire_get_solv_pool(pakfire
);
89 repo
->repo
= repo_create(pool
, name
);
91 // Allocate repository appdata
92 repo
->appdata
= repo
->repo
->appdata
= \
93 calloc(1, sizeof(*repo
->appdata
));
95 repo
->appdata
->repodata
= repo_add_repodata(repo
->repo
,
96 REPO_EXTEND_SOLVABLES
|REPO_LOCALPOOL
|REPO_NO_INTERNALIZE
|REPO_NO_LOCATION
);
102 PakfireRepo
pakfire_repo_create_from_repo(Pakfire pakfire
, Repo
* r
) {
103 PakfireRepo repo
= r
->appdata
= pakfire_calloc(1, sizeof(*repo
));
105 DEBUG("Allocated Repo at %p\n", repo
);
108 repo
->pakfire
= pakfire_ref(pakfire
);
110 // Reference repository
112 repo
->appdata
= r
->appdata
;
118 PAKFIRE_EXPORT PakfireRepo
pakfire_repo_ref(PakfireRepo repo
) {
124 static void pakfire_repo_free(PakfireRepo repo
) {
125 pakfire_unref(repo
->pakfire
);
128 DEBUG("Released Repo at %p\n", repo
);
131 PAKFIRE_EXPORT PakfireRepo
pakfire_repo_unref(PakfireRepo repo
) {
135 if (--repo
->nrefs
> 0)
138 pakfire_repo_free(repo
);
142 PAKFIRE_EXPORT Pakfire
pakfire_repo_get_pakfire(PakfireRepo repo
) {
143 return pakfire_ref(repo
->pakfire
);
146 Repo
* pakfire_repo_get_repo(PakfireRepo repo
) {
150 Repodata
* pakfire_repo_get_repodata(PakfireRepo repo
) {
151 return repo
->appdata
->repodata
;
154 PAKFIRE_EXPORT
int pakfire_repo_identical(PakfireRepo repo1
, PakfireRepo repo2
) {
155 Repo
* r1
= repo1
->repo
;
156 Repo
* r2
= repo2
->repo
;
158 return strcmp(r1
->name
, r2
->name
);
161 PAKFIRE_EXPORT
int pakfire_repo_cmp(PakfireRepo repo1
, PakfireRepo repo2
) {
162 Repo
* r1
= repo1
->repo
;
163 Repo
* r2
= repo2
->repo
;
165 if (r1
->priority
> r2
->priority
)
168 else if (r1
->priority
< r2
->priority
)
171 return strcmp(r1
->name
, r2
->name
);
174 PAKFIRE_EXPORT
int pakfire_repo_count(PakfireRepo repo
) {
175 Pool
* pool
= pakfire_get_solv_pool(repo
->pakfire
);
178 for (int i
= 2; i
< pool
->nsolvables
; i
++) {
179 Solvable
* s
= pool
->solvables
+ i
;
180 if (s
->repo
&& s
->repo
== repo
->repo
)
187 PAKFIRE_EXPORT
void pakfire_repo_internalize(PakfireRepo repo
) {
188 repo_internalize(repo
->repo
);
191 PAKFIRE_EXPORT
const char* pakfire_repo_get_name(PakfireRepo repo
) {
192 return repo
->repo
->name
;
195 PAKFIRE_EXPORT
void pakfire_repo_set_name(PakfireRepo repo
, const char* name
) {
196 repo
->repo
->name
= pakfire_strdup(name
);
199 PAKFIRE_EXPORT
int pakfire_repo_get_enabled(PakfireRepo repo
) {
200 return !repo
->repo
->disabled
;
203 PAKFIRE_EXPORT
void pakfire_repo_set_enabled(PakfireRepo repo
, int enabled
) {
204 repo
->repo
->disabled
= !enabled
;
206 pakfire_pool_has_changed(repo
->pakfire
);
209 // Returns a default priority based on the repository configuration
210 static int pakfire_repo_auto_priority(PakfireRepo repo
) {
211 // The @system repository has a priority of zero
212 if (pakfire_repo_is_installed_repo(repo
) == 0)
215 if (repo
->appdata
->baseurl
) {
217 if (pakfire_string_startswith(repo
->appdata
->baseurl
, "https://"))
221 if (pakfire_string_startswith(repo
->appdata
->baseurl
, "http://"))
225 if (pakfire_string_startswith(repo
->appdata
->baseurl
, "dir://"))
233 PAKFIRE_EXPORT
int pakfire_repo_get_priority(PakfireRepo repo
) {
234 if (repo
->repo
->priority
> 0)
235 return repo
->repo
->priority
;
237 return pakfire_repo_auto_priority(repo
);
240 PAKFIRE_EXPORT
void pakfire_repo_set_priority(PakfireRepo repo
, int priority
) {
241 repo
->repo
->priority
= priority
;
244 PAKFIRE_EXPORT
const char* pakfire_repo_get_baseurl(PakfireRepo repo
) {
245 return repo
->appdata
->baseurl
;
248 PAKFIRE_EXPORT
int pakfire_repo_set_baseurl(PakfireRepo repo
, const char* baseurl
) {
249 if (repo
->appdata
->baseurl
)
250 pakfire_free(repo
->appdata
->baseurl
);
252 repo
->appdata
->baseurl
= pakfire_strdup(baseurl
);
256 PAKFIRE_EXPORT
int pakfire_repo_is_installed_repo(PakfireRepo repo
) {
257 PakfireRepo installed_repo
= pakfire_get_installed_repo(repo
->pakfire
);
259 int r
= pakfire_repo_identical(repo
, installed_repo
);
261 pakfire_repo_unref(installed_repo
);
266 PAKFIRE_EXPORT
int pakfire_repo_read_solv(PakfireRepo repo
, const char* filename
, int flags
) {
267 FILE* f
= fopen(filename
, "rb");
272 int ret
= pakfire_repo_read_solv_fp(repo
, f
, flags
);
283 // XXX This should actually be larger than one byte, but fread()
284 // in _xz_read() somehow segfaults when this is larger
288 static ssize_t
_xz_read(void* data
, char* buffer
, size_t size
) {
289 struct xz_cookie
* cookie
= (struct xz_cookie
*)data
;
293 // Return nothing after we are done
297 lzma_action action
= LZMA_RUN
;
299 // Set output to allocated buffer
300 cookie
->stream
.next_out
= (uint8_t *)buffer
;
301 cookie
->stream
.avail_out
= size
;
304 // Read something when the input buffer is empty
305 if (cookie
->stream
.avail_in
== 0) {
306 cookie
->stream
.next_in
= cookie
->buffer
;
307 cookie
->stream
.avail_in
= fread(cookie
->buffer
,
308 1, sizeof(cookie
->buffer
), cookie
->f
);
310 // Break if the input file could not be read
311 if (ferror(cookie
->f
))
314 // Finish after we have reached the end of the input file
315 if (feof(cookie
->f
)) {
316 action
= LZMA_FINISH
;
321 lzma_ret ret
= lzma_code(&cookie
->stream
, action
);
323 // If the stream has ended, we just send the
324 // remaining output and mark that we are done.
325 if (ret
== LZMA_STREAM_END
) {
327 return size
- cookie
->stream
.avail_out
;
330 // Break on all other unexpected errors
334 // When we have read enough to fill the entire output buffer, we return
335 if (cookie
->stream
.avail_out
== 0)
343 static int _xz_close(void* data
) {
344 struct xz_cookie
* cookie
= (struct xz_cookie
*)data
;
347 lzma_end(&cookie
->stream
);
355 static FILE* decompression_proxy(FILE* f
) {
358 // Search for XZ header
359 for (unsigned int i
= 0; i
< XZ_HEADER_LENGTH
; i
++) {
360 fread(&buffer
, 1, 1, f
);
362 if (buffer
!= XZ_HEADER_MAGIC
[i
])
366 // Reset to beginning
367 fseek(f
, 0, SEEK_SET
);
369 // If we get here, an XZ header was found
370 struct xz_cookie cookie
= {
372 .stream
= LZMA_STREAM_INIT
,
376 // Initialise the decoder
377 lzma_ret ret
= lzma_stream_decoder(&cookie
.stream
, UINT64_MAX
, 0);
381 cookie_io_functions_t functions
= {
388 return fopencookie(&cookie
, "rb", functions
);
391 fseek(f
, 0, SEEK_SET
);
395 PAKFIRE_EXPORT
int pakfire_repo_read_solv_fp(PakfireRepo repo
, FILE *f
, int flags
) {
396 f
= decompression_proxy(f
);
398 int ret
= repo_add_solv(repo
->repo
, f
, flags
);
407 return PAKFIRE_E_SOLV_NOT_SOLV
;
409 // Unsupported version
411 return PAKFIRE_E_SOLV_UNSUPPORTED
;
415 return PAKFIRE_E_EOF
;
422 return PAKFIRE_E_SOLV_CORRUPTED
;
425 pakfire_pool_has_changed(repo
->pakfire
);
430 PAKFIRE_EXPORT
int pakfire_repo_write_solv(PakfireRepo repo
, const char* filename
, int flags
) {
431 FILE* f
= fopen(filename
, "wb");
436 int ret
= pakfire_repo_write_solv_fp(repo
, f
, flags
);
442 PAKFIRE_EXPORT
int pakfire_repo_write_solv_fp(PakfireRepo repo
, FILE *f
, int flags
) {
443 pakfire_repo_internalize(repo
);
445 return repo_write(repo
->repo
, f
);
448 PAKFIRE_EXPORT PakfirePackage
pakfire_repo_add_package(PakfireRepo repo
) {
449 Id id
= repo_add_solvable(repo
->repo
);
451 return pakfire_package_create(repo
->pakfire
, id
);
456 static char* pakfire_repo_get_cache_prefix(PakfireRepo repo
) {
457 char* prefix
= pakfire_calloc(1, STRING_SIZE
+ 1);
459 snprintf(prefix
, STRING_SIZE
, "repodata/%s", pakfire_repo_get_name(repo
));
464 static char* pakfire_repo_make_cache_path(PakfireRepo repo
, const char* path
) {
465 char* prefix
= pakfire_repo_get_cache_prefix(repo
);
467 // Add the prefix for the repository first
468 char* cache_path
= pakfire_path_join(prefix
, path
);
469 pakfire_free(prefix
);
474 PAKFIRE_EXPORT
int pakfire_repo_clean(PakfireRepo repo
) {
475 char* cache_path
= pakfire_repo_make_cache_path(repo
, NULL
);
478 return pakfire_cache_destroy(repo
->pakfire
, cache_path
);
483 PAKFIRE_EXPORT
char* pakfire_repo_cache_get_path(PakfireRepo repo
, const char* path
) {
484 char* repo_cache_path
= pakfire_repo_make_cache_path(repo
, path
);
486 char* cache_path
= pakfire_get_cache_path(repo
->pakfire
, repo_cache_path
);
487 pakfire_free(repo_cache_path
);
492 PAKFIRE_EXPORT
FILE* pakfire_repo_cache_open(PakfireRepo repo
, const char* path
, const char* mode
) {
493 char* cache_path
= pakfire_repo_make_cache_path(repo
, path
);
495 FILE* f
= pakfire_cache_open(repo
->pakfire
, cache_path
, mode
);
496 pakfire_free(cache_path
);
501 PAKFIRE_EXPORT
int pakfire_repo_cache_access(PakfireRepo repo
, const char* path
, int mode
) {
502 char* cache_path
= pakfire_repo_make_cache_path(repo
, path
);
504 int r
= pakfire_cache_access(repo
->pakfire
, cache_path
, mode
);
505 pakfire_free(cache_path
);
510 PAKFIRE_EXPORT
time_t pakfire_repo_cache_age(PakfireRepo repo
, const char* path
) {
511 char* cache_path
= pakfire_repo_make_cache_path(repo
, path
);
513 time_t t
= pakfire_cache_age(repo
->pakfire
, cache_path
);
514 pakfire_free(cache_path
);