4 * Copyright (c) 2006-2010 Pacman Development Team <pacman-dev@archlinux.org>
5 * Copyright (c) 2002-2006 by Judd Vinet <jvinet@zeroflux.org>
6 * Copyright (c) 2005 by Aurelien Foret <orelien@chez.com>
7 * Copyright (c) 2005, 2006 by Christian Hamar <krics@linuxforum.hu>
8 * Copyright (c) 2005, 2006 by Miklos Vajna <vmiklos@frugalware.org>
10 * This program is free software; you can redistribute it and/or modify
11 * it under the terms of the GNU General Public License as published by
12 * the Free Software Foundation; either version 2 of the License, or
13 * (at your option) any later version.
15 * This program is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 * GNU General Public License for more details.
20 * You should have received a copy of the GNU General Public License
21 * along with this program. If not, see <http://www.gnu.org/licenses/>.
32 #include <sys/types.h>
37 #include <archive_entry.h>
41 #include "alpm_list.h"
49 /** \addtogroup alpm_packages Package Functions
50 * @brief Functions to manipulate libalpm packages
55 * @param pkg package pointer to free
56 * @return 0 on success, -1 on error (pm_errno is set accordingly)
58 int SYMEXPORT
alpm_pkg_free(pmpkg_t
*pkg
)
62 ASSERT(pkg
!= NULL
, RET_ERR(PM_ERR_WRONG_ARGS
, -1));
64 /* Only free packages loaded in user space */
65 if(pkg
->origin
== PKG_FROM_FILE
) {
72 /** Check the integrity (with md5) of a package from the sync cache.
73 * @param pkg package pointer
74 * @return 0 on success, -1 on error (pm_errno is set accordingly)
76 int SYMEXPORT
alpm_pkg_checkmd5sum(pmpkg_t
*pkg
)
83 ASSERT(pkg
!= NULL
, RET_ERR(PM_ERR_WRONG_ARGS
, -1));
84 /* We only inspect packages from sync repositories */
85 ASSERT(pkg
->origin
== PKG_FROM_SYNCDB
, RET_ERR(PM_ERR_PKG_INVALID
, -1));
87 fpath
= _alpm_filecache_find(alpm_pkg_get_filename(pkg
));
89 retval
= _alpm_test_md5sum(fpath
, alpm_pkg_get_md5sum(pkg
));
93 } else if (retval
== 1) {
94 pm_errno
= PM_ERR_PKG_INVALID
;
101 /* Default package accessor functions. These will get overridden by any
102 * backend logic that needs lazy access, such as the local database through
103 * a lazy-load cache. However, the defaults will work just fine for fully-
104 * populated package structures. */
105 const char *_pkg_get_filename(pmpkg_t
*pkg
) { return pkg
->filename
; }
106 const char *_pkg_get_name(pmpkg_t
*pkg
) { return pkg
->name
; }
107 const char *_pkg_get_version(pmpkg_t
*pkg
) { return pkg
->version
; }
108 const char *_pkg_get_desc(pmpkg_t
*pkg
) { return pkg
->desc
; }
109 const char *_pkg_get_url(pmpkg_t
*pkg
) { return pkg
->url
; }
110 time_t _pkg_get_builddate(pmpkg_t
*pkg
) { return pkg
->builddate
; }
111 time_t _pkg_get_installdate(pmpkg_t
*pkg
) { return pkg
->installdate
; }
112 const char *_pkg_get_packager(pmpkg_t
*pkg
) { return pkg
->packager
; }
113 const char *_pkg_get_md5sum(pmpkg_t
*pkg
) { return pkg
->md5sum
; }
114 const char *_pkg_get_arch(pmpkg_t
*pkg
) { return pkg
->arch
; }
115 off_t
_pkg_get_size(pmpkg_t
*pkg
) { return pkg
->size
; }
116 off_t
_pkg_get_isize(pmpkg_t
*pkg
) { return pkg
->isize
; }
117 pmpkgreason_t
_pkg_get_reason(pmpkg_t
*pkg
) { return pkg
->reason
; }
118 int _pkg_has_force(pmpkg_t
*pkg
) { return pkg
->force
; }
120 alpm_list_t
*_pkg_get_licenses(pmpkg_t
*pkg
) { return pkg
->licenses
; }
121 alpm_list_t
*_pkg_get_groups(pmpkg_t
*pkg
) { return pkg
->groups
; }
122 alpm_list_t
*_pkg_get_depends(pmpkg_t
*pkg
) { return pkg
->depends
; }
123 alpm_list_t
*_pkg_get_optdepends(pmpkg_t
*pkg
) { return pkg
->optdepends
; }
124 alpm_list_t
*_pkg_get_conflicts(pmpkg_t
*pkg
) { return pkg
->conflicts
; }
125 alpm_list_t
*_pkg_get_provides(pmpkg_t
*pkg
) { return pkg
->provides
; }
126 alpm_list_t
*_pkg_get_replaces(pmpkg_t
*pkg
) { return pkg
->replaces
; }
127 alpm_list_t
*_pkg_get_deltas(pmpkg_t
*pkg
) { return pkg
->deltas
; }
128 alpm_list_t
*_pkg_get_files(pmpkg_t
*pkg
) { return pkg
->files
; }
129 alpm_list_t
*_pkg_get_backup(pmpkg_t
*pkg
) { return pkg
->backup
; }
131 /** The standard package operations struct. Get fields directly from the
132 * struct itself with no abstraction layer or any type of lazy loading.
134 struct pkg_operations default_pkg_ops
= {
135 .get_filename
= _pkg_get_filename
,
136 .get_name
= _pkg_get_name
,
137 .get_version
= _pkg_get_version
,
138 .get_desc
= _pkg_get_desc
,
139 .get_url
= _pkg_get_url
,
140 .get_builddate
= _pkg_get_builddate
,
141 .get_installdate
= _pkg_get_installdate
,
142 .get_packager
= _pkg_get_packager
,
143 .get_md5sum
= _pkg_get_md5sum
,
144 .get_arch
= _pkg_get_arch
,
145 .get_size
= _pkg_get_size
,
146 .get_isize
= _pkg_get_isize
,
147 .get_reason
= _pkg_get_reason
,
148 .has_force
= _pkg_has_force
,
149 .get_licenses
= _pkg_get_licenses
,
150 .get_groups
= _pkg_get_groups
,
151 .get_depends
= _pkg_get_depends
,
152 .get_optdepends
= _pkg_get_optdepends
,
153 .get_conflicts
= _pkg_get_conflicts
,
154 .get_provides
= _pkg_get_provides
,
155 .get_replaces
= _pkg_get_replaces
,
156 .get_deltas
= _pkg_get_deltas
,
157 .get_files
= _pkg_get_files
,
158 .get_backup
= _pkg_get_backup
,
161 /* Public functions for getting package information. These functions
162 * delegate the hard work to the function callbacks attached to each
163 * package, which depend on where the package was loaded from. */
164 const char SYMEXPORT
*alpm_pkg_get_filename(pmpkg_t
*pkg
)
166 return pkg
->ops
->get_filename(pkg
);
169 const char SYMEXPORT
*alpm_pkg_get_name(pmpkg_t
*pkg
)
171 return pkg
->ops
->get_name(pkg
);
174 const char SYMEXPORT
*alpm_pkg_get_version(pmpkg_t
*pkg
)
176 return pkg
->ops
->get_version(pkg
);
179 const char SYMEXPORT
*alpm_pkg_get_desc(pmpkg_t
*pkg
)
181 return pkg
->ops
->get_desc(pkg
);
184 const char SYMEXPORT
*alpm_pkg_get_url(pmpkg_t
*pkg
)
186 return pkg
->ops
->get_url(pkg
);
189 time_t SYMEXPORT
alpm_pkg_get_builddate(pmpkg_t
*pkg
)
191 return pkg
->ops
->get_builddate(pkg
);
194 time_t SYMEXPORT
alpm_pkg_get_installdate(pmpkg_t
*pkg
)
196 return pkg
->ops
->get_installdate(pkg
);
199 const char SYMEXPORT
*alpm_pkg_get_packager(pmpkg_t
*pkg
)
201 return pkg
->ops
->get_packager(pkg
);
204 const char SYMEXPORT
*alpm_pkg_get_md5sum(pmpkg_t
*pkg
)
206 return pkg
->ops
->get_md5sum(pkg
);
209 const char SYMEXPORT
*alpm_pkg_get_arch(pmpkg_t
*pkg
)
211 return pkg
->ops
->get_arch(pkg
);
214 off_t SYMEXPORT
alpm_pkg_get_size(pmpkg_t
*pkg
)
216 return pkg
->ops
->get_size(pkg
);
219 off_t SYMEXPORT
alpm_pkg_get_isize(pmpkg_t
*pkg
)
221 return pkg
->ops
->get_isize(pkg
);
224 pmpkgreason_t SYMEXPORT
alpm_pkg_get_reason(pmpkg_t
*pkg
)
226 return pkg
->ops
->get_reason(pkg
);
229 int SYMEXPORT
alpm_pkg_has_force(pmpkg_t
*pkg
)
231 return pkg
->ops
->has_force(pkg
);
234 alpm_list_t SYMEXPORT
*alpm_pkg_get_licenses(pmpkg_t
*pkg
)
236 return pkg
->ops
->get_licenses(pkg
);
239 alpm_list_t SYMEXPORT
*alpm_pkg_get_groups(pmpkg_t
*pkg
)
241 return pkg
->ops
->get_groups(pkg
);
244 alpm_list_t SYMEXPORT
*alpm_pkg_get_depends(pmpkg_t
*pkg
)
246 return pkg
->ops
->get_depends(pkg
);
249 alpm_list_t SYMEXPORT
*alpm_pkg_get_optdepends(pmpkg_t
*pkg
)
251 return pkg
->ops
->get_optdepends(pkg
);
254 alpm_list_t SYMEXPORT
*alpm_pkg_get_conflicts(pmpkg_t
*pkg
)
256 return pkg
->ops
->get_conflicts(pkg
);
259 alpm_list_t SYMEXPORT
*alpm_pkg_get_provides(pmpkg_t
*pkg
)
261 return pkg
->ops
->get_provides(pkg
);
264 alpm_list_t SYMEXPORT
*alpm_pkg_get_replaces(pmpkg_t
*pkg
)
266 return pkg
->ops
->get_replaces(pkg
);
269 alpm_list_t SYMEXPORT
*alpm_pkg_get_deltas(pmpkg_t
*pkg
)
271 return pkg
->ops
->get_deltas(pkg
);
274 alpm_list_t SYMEXPORT
*alpm_pkg_get_files(pmpkg_t
*pkg
)
276 return pkg
->ops
->get_files(pkg
);
279 alpm_list_t SYMEXPORT
*alpm_pkg_get_backup(pmpkg_t
*pkg
)
281 return pkg
->ops
->get_backup(pkg
);
284 pmdb_t SYMEXPORT
*alpm_pkg_get_db(pmpkg_t
*pkg
)
287 ASSERT(pkg
!= NULL
, return(NULL
));
288 ASSERT(pkg
->origin
!= PKG_FROM_FILE
, return(NULL
));
290 return(pkg
->origin_data
.db
);
294 * Open a package changelog for reading. Similar to fopen in functionality,
295 * except that the returned 'file stream' could really be from an archive
296 * as well as from the database.
297 * @param pkg the package to read the changelog of (either file or db)
298 * @return a 'file stream' to the package changelog
300 void SYMEXPORT
*alpm_pkg_changelog_open(pmpkg_t
*pkg
)
302 return pkg
->ops
->changelog_open(pkg
);
306 * Read data from an open changelog 'file stream'. Similar to fread in
307 * functionality, this function takes a buffer and amount of data to read. If an
308 * error occurs pm_errno will be set.
310 * @param ptr a buffer to fill with raw changelog data
311 * @param size the size of the buffer
312 * @param pkg the package that the changelog is being read from
313 * @param fp a 'file stream' to the package changelog
314 * @return the number of characters read, or 0 if there is no more data or an
317 size_t SYMEXPORT
alpm_pkg_changelog_read(void *ptr
, size_t size
,
318 const pmpkg_t
*pkg
, const void *fp
)
320 return pkg
->ops
->changelog_read(ptr
, size
, pkg
, fp
);
324 int SYMEXPORT alpm_pkg_changelog_feof(const pmpkg_t *pkg, void *fp)
326 return pkg->ops->changelog_feof(pkg, fp);
331 * Close a package changelog for reading. Similar to fclose in functionality,
332 * except that the 'file stream' could really be from an archive as well as
334 * @param pkg the package that the changelog was read from
335 * @param fp a 'file stream' to the package changelog
336 * @return whether closing the package changelog stream was successful
338 int SYMEXPORT
alpm_pkg_changelog_close(const pmpkg_t
*pkg
, void *fp
)
340 return pkg
->ops
->changelog_close(pkg
, fp
);
343 int SYMEXPORT
alpm_pkg_has_scriptlet(pmpkg_t
*pkg
)
348 ASSERT(handle
!= NULL
, return(-1));
349 ASSERT(pkg
!= NULL
, return(-1));
351 if(pkg
->origin
== PKG_FROM_LOCALDB
352 && !(pkg
->infolevel
& INFRQ_SCRIPTLET
)) {
353 _alpm_db_read(pkg
->origin_data
.db
, pkg
, INFRQ_SCRIPTLET
);
355 return pkg
->scriptlet
;
358 static void find_requiredby(pmpkg_t
*pkg
, pmdb_t
*db
, alpm_list_t
**reqs
)
360 const alpm_list_t
*i
;
361 for(i
= _alpm_db_get_pkgcache(db
); i
; i
= i
->next
) {
365 pmpkg_t
*cachepkg
= i
->data
;
366 if(_alpm_dep_edge(cachepkg
, pkg
)) {
367 const char *cachepkgname
= cachepkg
->name
;
368 if(alpm_list_find_str(*reqs
, cachepkgname
) == 0) {
369 *reqs
= alpm_list_add(*reqs
, strdup(cachepkgname
));
376 * @brief Compute the packages requiring a given package.
377 * @param pkg a package
378 * @return the list of packages requiring pkg
380 alpm_list_t SYMEXPORT
*alpm_pkg_compute_requiredby(pmpkg_t
*pkg
)
382 const alpm_list_t
*i
;
383 alpm_list_t
*reqs
= NULL
;
386 if(pkg
->origin
== PKG_FROM_FILE
) {
387 /* The sane option; search locally for things that require this. */
388 db
= alpm_option_get_localdb();
389 find_requiredby(pkg
, db
, &reqs
);
391 /* We have a DB package. if it is a local package, then we should
392 * only search the local DB; else search all known sync databases. */
393 db
= pkg
->origin_data
.db
;
395 find_requiredby(pkg
, db
, &reqs
);
397 for(i
= handle
->dbs_sync
; i
; i
= i
->next
) {
399 find_requiredby(pkg
, db
, &reqs
);
400 reqs
= alpm_list_msort(reqs
, alpm_list_count(reqs
), _alpm_str_cmp
);
409 pmpkg_t
*_alpm_pkg_new(void)
415 CALLOC(pkg
, 1, sizeof(pmpkg_t
), RET_ERR(PM_ERR_MEMORY
, NULL
));
420 pmpkg_t
*_alpm_pkg_dup(pmpkg_t
*pkg
)
427 CALLOC(newpkg
, 1, sizeof(pmpkg_t
), RET_ERR(PM_ERR_MEMORY
, NULL
));
429 STRDUP(newpkg
->filename
, pkg
->filename
, RET_ERR(PM_ERR_MEMORY
, newpkg
));
430 STRDUP(newpkg
->name
, pkg
->name
, RET_ERR(PM_ERR_MEMORY
, newpkg
));
431 STRDUP(newpkg
->version
, pkg
->version
, RET_ERR(PM_ERR_MEMORY
, newpkg
));
432 STRDUP(newpkg
->desc
, pkg
->desc
, RET_ERR(PM_ERR_MEMORY
, newpkg
));
433 STRDUP(newpkg
->url
, pkg
->url
, RET_ERR(PM_ERR_MEMORY
, newpkg
));
434 newpkg
->builddate
= pkg
->builddate
;
435 newpkg
->installdate
= pkg
->installdate
;
436 STRDUP(newpkg
->packager
, pkg
->packager
, RET_ERR(PM_ERR_MEMORY
, newpkg
));
437 STRDUP(newpkg
->md5sum
, pkg
->md5sum
, RET_ERR(PM_ERR_MEMORY
, newpkg
));
438 STRDUP(newpkg
->arch
, pkg
->arch
, RET_ERR(PM_ERR_MEMORY
, newpkg
));
439 newpkg
->size
= pkg
->size
;
440 newpkg
->isize
= pkg
->isize
;
441 newpkg
->scriptlet
= pkg
->scriptlet
;
442 newpkg
->force
= pkg
->force
;
443 newpkg
->reason
= pkg
->reason
;
445 newpkg
->licenses
= alpm_list_strdup(pkg
->licenses
);
446 newpkg
->replaces
= alpm_list_strdup(pkg
->replaces
);
447 newpkg
->groups
= alpm_list_strdup(pkg
->groups
);
448 newpkg
->files
= alpm_list_strdup(pkg
->files
);
449 newpkg
->backup
= alpm_list_strdup(pkg
->backup
);
450 for(i
= pkg
->depends
; i
; i
= alpm_list_next(i
)) {
451 newpkg
->depends
= alpm_list_add(newpkg
->depends
, _alpm_dep_dup(i
->data
));
453 newpkg
->optdepends
= alpm_list_strdup(pkg
->optdepends
);
454 newpkg
->conflicts
= alpm_list_strdup(pkg
->conflicts
);
455 newpkg
->provides
= alpm_list_strdup(pkg
->provides
);
456 newpkg
->deltas
= alpm_list_copy_data(pkg
->deltas
, sizeof(pmdelta_t
));
459 newpkg
->origin
= pkg
->origin
;
460 newpkg
->ops
= pkg
->ops
;
461 if(newpkg
->origin
== PKG_FROM_FILE
) {
462 newpkg
->origin_data
.file
= strdup(pkg
->origin_data
.file
);
464 newpkg
->origin_data
.db
= pkg
->origin_data
.db
;
466 newpkg
->infolevel
= pkg
->infolevel
;
471 void _alpm_pkg_free(pmpkg_t
*pkg
)
487 FREELIST(pkg
->licenses
);
488 FREELIST(pkg
->replaces
);
489 FREELIST(pkg
->groups
);
490 FREELIST(pkg
->files
);
491 FREELIST(pkg
->backup
);
492 alpm_list_free_inner(pkg
->depends
, (alpm_list_fn_free
)_alpm_dep_free
);
493 alpm_list_free(pkg
->depends
);
494 FREELIST(pkg
->optdepends
);
495 FREELIST(pkg
->conflicts
);
496 FREELIST(pkg
->provides
);
497 alpm_list_free_inner(pkg
->deltas
, (alpm_list_fn_free
)_alpm_delta_free
);
498 alpm_list_free(pkg
->deltas
);
499 alpm_list_free(pkg
->delta_path
);
500 alpm_list_free(pkg
->removes
);
502 if(pkg
->origin
== PKG_FROM_FILE
) {
503 FREE(pkg
->origin_data
.file
);
508 /* This function should be used when removing a target from upgrade/sync target list
509 * Case 1: If pkg is a loaded package file (PKG_FROM_FILE), it will be freed.
510 * Case 2: If pkg is a pkgcache entry (PKG_FROM_CACHE), it won't be freed,
511 * only the transaction specific fields of pkg will be freed.
513 void _alpm_pkg_free_trans(pmpkg_t
*pkg
)
521 if(pkg
->origin
== PKG_FROM_FILE
) {
526 alpm_list_free(pkg
->removes
);
530 /* Is spkg an upgrade for locapkg? */
531 int _alpm_pkg_compare_versions(pmpkg_t
*spkg
, pmpkg_t
*localpkg
)
537 cmp
= alpm_pkg_vercmp(alpm_pkg_get_version(spkg
),
538 alpm_pkg_get_version(localpkg
));
540 if(cmp
< 0 && alpm_pkg_has_force(spkg
)) {
547 /* Helper function for comparing packages
549 int _alpm_pkg_cmp(const void *p1
, const void *p2
)
551 pmpkg_t
*pkg1
= (pmpkg_t
*)p1
;
552 pmpkg_t
*pkg2
= (pmpkg_t
*)p2
;
553 return(strcoll(pkg1
->name
, pkg2
->name
));
556 /* Test for existence of a package in a alpm_list_t*
559 pmpkg_t
*_alpm_pkg_find(alpm_list_t
*haystack
, const char *needle
)
565 if(needle
== NULL
|| haystack
== NULL
) {
569 for(lp
= haystack
; lp
; lp
= lp
->next
) {
570 pmpkg_t
*info
= lp
->data
;
572 if(info
&& strcmp(info
->name
, needle
) == 0) {
579 /** Test if a package should be ignored.
581 * Checks if the package is ignored via IgnorePkg, or if the package is
582 * in a group ignored via IgnoreGrp.
584 * @param pkg the package to test
586 * @return 1 if the package should be ignored, 0 otherwise
588 int _alpm_pkg_should_ignore(pmpkg_t
*pkg
)
590 alpm_list_t
*groups
= NULL
;
592 /* first see if the package is ignored */
593 if(alpm_list_find_str(handle
->ignorepkg
, alpm_pkg_get_name(pkg
))) {
597 /* next see if the package is in a group that is ignored */
598 for(groups
= handle
->ignoregrp
; groups
; groups
= alpm_list_next(groups
)) {
599 char *grp
= (char *)alpm_list_getdata(groups
);
600 if(alpm_list_find_str(alpm_pkg_get_groups(pkg
), grp
)) {
608 /* vim: set ts=2 sw=2 noet: */