4 * Copyright (c) 2002-2007 by Judd Vinet <jvinet@zeroflux.org>
5 * Copyright (c) 2005 by Aurelien Foret <orelien@chez.com>
6 * Copyright (c) 2005, 2006 by Christian Hamar <krics@linuxforum.hu>
7 * Copyright (c) 2005, 2006 by Miklos Vajna <vmiklos@frugalware.org>
9 * This program is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License as published by
11 * the Free Software Foundation; either version 2 of the License, or
12 * (at your option) any later version.
14 * This program is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 * GNU General Public License for more details.
19 * You should have received a copy of the GNU General Public License
20 * along with this program. If not, see <http://www.gnu.org/licenses/>.
31 #include <sys/types.h>
34 #include <locale.h> /* setlocale */
38 #include <archive_entry.h>
42 #include "alpm_list.h"
52 /** \addtogroup alpm_packages Package Functions
53 * @brief Functions to manipulate libalpm packages
57 /** Create a package from a file.
58 * @param filename location of the package tarball
59 * @param full whether to stop the load after metadata is read or continue
60 * through the full archive
61 * @param pkg address of the package pointer
62 * @return 0 on success, -1 on error (pm_errno is set accordingly)
64 int SYMEXPORT
alpm_pkg_load(const char *filename
, unsigned short full
,
67 _alpm_log(PM_LOG_FUNCTION
, "enter alpm_pkg_load\n");
70 ASSERT(filename
!= NULL
&& strlen(filename
) != 0,
71 RET_ERR(PM_ERR_WRONG_ARGS
, -1));
72 ASSERT(pkg
!= NULL
, RET_ERR(PM_ERR_WRONG_ARGS
, -1));
74 *pkg
= _alpm_pkg_load(filename
, full
);
76 /* pm_errno is set by pkg_load */
84 * @param pkg package pointer to free
85 * @return 0 on success, -1 on error (pm_errno is set accordingly)
87 int SYMEXPORT
alpm_pkg_free(pmpkg_t
*pkg
)
89 _alpm_log(PM_LOG_FUNCTION
, "enter alpm_pkg_free\n");
91 ASSERT(pkg
!= NULL
, RET_ERR(PM_ERR_WRONG_ARGS
, -1));
93 /* Only free packages loaded in user space */
94 if(pkg
->origin
!= PKG_FROM_CACHE
) {
101 /** Check the integrity (with md5) of a package from the sync cache.
102 * @param pkg package pointer
103 * @return 0 on success, -1 on error (pm_errno is set accordingly)
105 int SYMEXPORT
alpm_pkg_checkmd5sum(pmpkg_t
*pkg
)
113 ASSERT(pkg
!= NULL
, RET_ERR(PM_ERR_WRONG_ARGS
, -1));
114 /* We only inspect packages from sync repositories */
115 ASSERT(pkg
->origin
== PKG_FROM_CACHE
, RET_ERR(PM_ERR_PKG_INVALID
, -1));
116 ASSERT(pkg
->origin_data
.db
!= handle
->db_local
, RET_ERR(PM_ERR_PKG_INVALID
, -1));
118 fpath
= _alpm_filecache_find(alpm_pkg_get_filename(pkg
));
119 md5sum
= alpm_get_md5sum(fpath
);
122 _alpm_log(PM_LOG_ERROR
, _("could not get md5sum for package %s-%s\n"),
123 alpm_pkg_get_name(pkg
), alpm_pkg_get_version(pkg
));
124 pm_errno
= PM_ERR_NOT_A_FILE
;
127 if(strcmp(md5sum
, alpm_pkg_get_md5sum(pkg
)) == 0) {
128 _alpm_log(PM_LOG_DEBUG
, "md5sums for package %s-%s match\n",
129 alpm_pkg_get_name(pkg
), alpm_pkg_get_version(pkg
));
131 _alpm_log(PM_LOG_ERROR
, _("md5sums do not match for package %s-%s\n"),
132 alpm_pkg_get_name(pkg
), alpm_pkg_get_version(pkg
));
133 pm_errno
= PM_ERR_PKG_INVALID
;
144 /** Compare versions.
145 * @param ver1 first version
146 * @param ver2 secont version
147 * @return postive, 0 or negative if ver1 is less, equal or more
148 * than ver2, respectively.
150 int SYMEXPORT
alpm_pkg_vercmp(const char *ver1
, const char *ver2
)
154 return(_alpm_versioncmp(ver1
, ver2
));
157 const char SYMEXPORT
*alpm_pkg_get_filename(pmpkg_t
*pkg
)
162 ASSERT(handle
!= NULL
, return(NULL
));
163 ASSERT(pkg
!= NULL
, return(NULL
));
165 if(pkg
->filename
== NULL
|| strlen(pkg
->filename
) == 0) {
166 /* construct the file name, it's not in the desc file */
167 if(pkg
->origin
== PKG_FROM_CACHE
&& !(pkg
->infolevel
& INFRQ_DESC
)) {
168 _alpm_db_read(pkg
->origin_data
.db
, pkg
, INFRQ_DESC
);
170 char buffer
[PATH_MAX
];
171 if(pkg
->arch
&& strlen(pkg
->arch
) > 0) {
172 snprintf(buffer
, PATH_MAX
, "%s-%s-%s" PKGEXT
,
173 pkg
->name
, pkg
->version
, pkg
->arch
);
175 snprintf(buffer
, PATH_MAX
, "%s-%s" PKGEXT
,
176 pkg
->name
, pkg
->version
);
178 STRDUP(pkg
->filename
, buffer
, RET_ERR(PM_ERR_MEMORY
, NULL
));
181 return pkg
->filename
;
184 const char SYMEXPORT
*alpm_pkg_get_name(pmpkg_t
*pkg
)
189 ASSERT(handle
!= NULL
, return(NULL
));
190 ASSERT(pkg
!= NULL
, return(NULL
));
192 if(pkg
->origin
== PKG_FROM_CACHE
&& !(pkg
->infolevel
& INFRQ_BASE
)) {
193 _alpm_db_read(pkg
->origin_data
.db
, pkg
, INFRQ_BASE
);
198 const char SYMEXPORT
*alpm_pkg_get_version(pmpkg_t
*pkg
)
203 ASSERT(handle
!= NULL
, return(NULL
));
204 ASSERT(pkg
!= NULL
, return(NULL
));
206 if(pkg
->origin
== PKG_FROM_CACHE
&& !(pkg
->infolevel
& INFRQ_BASE
)) {
207 _alpm_db_read(pkg
->origin_data
.db
, pkg
, INFRQ_BASE
);
212 const char SYMEXPORT
*alpm_pkg_get_desc(pmpkg_t
*pkg
)
217 ASSERT(handle
!= NULL
, return(NULL
));
218 ASSERT(pkg
!= NULL
, return(NULL
));
220 if(pkg
->origin
== PKG_FROM_CACHE
&& !(pkg
->infolevel
& INFRQ_DESC
)) {
221 _alpm_db_read(pkg
->origin_data
.db
, pkg
, INFRQ_DESC
);
226 const char SYMEXPORT
*alpm_pkg_get_url(pmpkg_t
*pkg
)
231 ASSERT(handle
!= NULL
, return(NULL
));
232 ASSERT(pkg
!= NULL
, return(NULL
));
234 if(pkg
->origin
== PKG_FROM_CACHE
&& !(pkg
->infolevel
& INFRQ_DESC
)) {
235 _alpm_db_read(pkg
->origin_data
.db
, pkg
, INFRQ_DESC
);
240 time_t SYMEXPORT
alpm_pkg_get_builddate(pmpkg_t
*pkg
)
245 ASSERT(handle
!= NULL
, return(0));
246 ASSERT(pkg
!= NULL
, return(0));
248 if(pkg
->origin
== PKG_FROM_CACHE
&& !(pkg
->infolevel
& INFRQ_DESC
)) {
249 _alpm_db_read(pkg
->origin_data
.db
, pkg
, INFRQ_DESC
);
251 return pkg
->builddate
;
254 time_t SYMEXPORT
alpm_pkg_get_installdate(pmpkg_t
*pkg
)
259 ASSERT(handle
!= NULL
, return(0));
260 ASSERT(pkg
!= NULL
, return(0));
262 if(pkg
->origin
== PKG_FROM_CACHE
&& !(pkg
->infolevel
& INFRQ_DESC
)) {
263 _alpm_db_read(pkg
->origin_data
.db
, pkg
, INFRQ_DESC
);
265 return pkg
->installdate
;
268 const char SYMEXPORT
*alpm_pkg_get_packager(pmpkg_t
*pkg
)
273 ASSERT(handle
!= NULL
, return(NULL
));
274 ASSERT(pkg
!= NULL
, return(NULL
));
276 if(pkg
->origin
== PKG_FROM_CACHE
&& !(pkg
->infolevel
& INFRQ_DESC
)) {
277 _alpm_db_read(pkg
->origin_data
.db
, pkg
, INFRQ_DESC
);
279 return pkg
->packager
;
282 const char SYMEXPORT
*alpm_pkg_get_md5sum(pmpkg_t
*pkg
)
287 ASSERT(handle
!= NULL
, return(NULL
));
288 ASSERT(pkg
!= NULL
, return(NULL
));
290 if(pkg
->origin
== PKG_FROM_CACHE
&& !(pkg
->infolevel
& INFRQ_DESC
)) {
291 _alpm_db_read(pkg
->origin_data
.db
, pkg
, INFRQ_DESC
);
296 const char SYMEXPORT
*alpm_pkg_get_arch(pmpkg_t
*pkg
)
301 ASSERT(handle
!= NULL
, return(NULL
));
302 ASSERT(pkg
!= NULL
, return(NULL
));
304 if(pkg
->origin
== PKG_FROM_CACHE
&& !(pkg
->infolevel
& INFRQ_DESC
)) {
305 _alpm_db_read(pkg
->origin_data
.db
, pkg
, INFRQ_DESC
);
310 unsigned long SYMEXPORT
alpm_pkg_get_size(pmpkg_t
*pkg
)
315 ASSERT(handle
!= NULL
, return(-1));
316 ASSERT(pkg
!= NULL
, return(-1));
318 if(pkg
->origin
== PKG_FROM_CACHE
&& !(pkg
->infolevel
& INFRQ_DESC
)) {
319 _alpm_db_read(pkg
->origin_data
.db
, pkg
, INFRQ_DESC
);
324 unsigned long SYMEXPORT
alpm_pkg_get_isize(pmpkg_t
*pkg
)
329 ASSERT(handle
!= NULL
, return(-1));
330 ASSERT(pkg
!= NULL
, return(-1));
332 if(pkg
->origin
== PKG_FROM_CACHE
&& !(pkg
->infolevel
& INFRQ_DESC
)) {
333 _alpm_db_read(pkg
->origin_data
.db
, pkg
, INFRQ_DESC
);
338 pmpkgreason_t SYMEXPORT
alpm_pkg_get_reason(pmpkg_t
*pkg
)
343 ASSERT(handle
!= NULL
, return(-1));
344 ASSERT(pkg
!= NULL
, return(-1));
346 if(pkg
->origin
== PKG_FROM_CACHE
&& !(pkg
->infolevel
& INFRQ_DESC
)) {
347 _alpm_db_read(pkg
->origin_data
.db
, pkg
, INFRQ_DESC
);
352 alpm_list_t SYMEXPORT
*alpm_pkg_get_licenses(pmpkg_t
*pkg
)
357 ASSERT(handle
!= NULL
, return(NULL
));
358 ASSERT(pkg
!= NULL
, return(NULL
));
360 if(pkg
->origin
== PKG_FROM_CACHE
&& !(pkg
->infolevel
& INFRQ_DESC
)) {
361 _alpm_db_read(pkg
->origin_data
.db
, pkg
, INFRQ_DESC
);
363 return pkg
->licenses
;
366 alpm_list_t SYMEXPORT
*alpm_pkg_get_groups(pmpkg_t
*pkg
)
371 ASSERT(handle
!= NULL
, return(NULL
));
372 ASSERT(pkg
!= NULL
, return(NULL
));
374 if(pkg
->origin
== PKG_FROM_CACHE
&& !(pkg
->infolevel
& INFRQ_DESC
)) {
375 _alpm_db_read(pkg
->origin_data
.db
, pkg
, INFRQ_DESC
);
380 alpm_list_t SYMEXPORT
*alpm_pkg_get_depends(pmpkg_t
*pkg
)
385 ASSERT(handle
!= NULL
, return(NULL
));
386 ASSERT(pkg
!= NULL
, return(NULL
));
388 if(pkg
->origin
== PKG_FROM_CACHE
&& !(pkg
->infolevel
& INFRQ_DEPENDS
)) {
389 _alpm_db_read(pkg
->origin_data
.db
, pkg
, INFRQ_DEPENDS
);
394 alpm_list_t SYMEXPORT
*alpm_pkg_get_optdepends(pmpkg_t
*pkg
)
399 ASSERT(handle
!= NULL
, return(NULL
));
400 ASSERT(pkg
!= NULL
, return(NULL
));
402 if(pkg
->origin
== PKG_FROM_CACHE
&& !(pkg
->infolevel
& INFRQ_DEPENDS
)) {
403 _alpm_db_read(pkg
->origin_data
.db
, pkg
, INFRQ_DEPENDS
);
405 return pkg
->optdepends
;
408 alpm_list_t SYMEXPORT
*alpm_pkg_get_conflicts(pmpkg_t
*pkg
)
413 ASSERT(handle
!= NULL
, return(NULL
));
414 ASSERT(pkg
!= NULL
, return(NULL
));
416 if(pkg
->origin
== PKG_FROM_CACHE
&& !(pkg
->infolevel
& INFRQ_DEPENDS
)) {
417 _alpm_db_read(pkg
->origin_data
.db
, pkg
, INFRQ_DEPENDS
);
419 return pkg
->conflicts
;
422 alpm_list_t SYMEXPORT
*alpm_pkg_get_provides(pmpkg_t
*pkg
)
427 ASSERT(handle
!= NULL
, return(NULL
));
428 ASSERT(pkg
!= NULL
, return(NULL
));
430 if(pkg
->origin
== PKG_FROM_CACHE
&& !(pkg
->infolevel
& INFRQ_DEPENDS
)) {
431 _alpm_db_read(pkg
->origin_data
.db
, pkg
, INFRQ_DEPENDS
);
433 return pkg
->provides
;
436 alpm_list_t SYMEXPORT
*alpm_pkg_get_deltas(pmpkg_t
*pkg
)
441 ASSERT(handle
!= NULL
, return(NULL
));
442 ASSERT(pkg
!= NULL
, return(NULL
));
444 if(pkg
->origin
== PKG_FROM_CACHE
&& !(pkg
->infolevel
& INFRQ_DELTAS
)) {
445 _alpm_db_read(pkg
->origin_data
.db
, pkg
, INFRQ_DELTAS
);
450 alpm_list_t SYMEXPORT
*alpm_pkg_get_replaces(pmpkg_t
*pkg
)
455 ASSERT(handle
!= NULL
, return(NULL
));
456 ASSERT(pkg
!= NULL
, return(NULL
));
458 if(pkg
->origin
== PKG_FROM_CACHE
&& !(pkg
->infolevel
& INFRQ_DESC
)) {
459 _alpm_db_read(pkg
->origin_data
.db
, pkg
, INFRQ_DESC
);
461 return pkg
->replaces
;
464 alpm_list_t SYMEXPORT
*alpm_pkg_get_files(pmpkg_t
*pkg
)
469 ASSERT(handle
!= NULL
, return(NULL
));
470 ASSERT(pkg
!= NULL
, return(NULL
));
472 if(pkg
->origin
== PKG_FROM_CACHE
&& pkg
->origin_data
.db
== handle
->db_local
473 && !(pkg
->infolevel
& INFRQ_FILES
)) {
474 _alpm_db_read(pkg
->origin_data
.db
, pkg
, INFRQ_FILES
);
479 alpm_list_t SYMEXPORT
*alpm_pkg_get_backup(pmpkg_t
*pkg
)
484 ASSERT(handle
!= NULL
, return(NULL
));
485 ASSERT(pkg
!= NULL
, return(NULL
));
487 if(pkg
->origin
== PKG_FROM_CACHE
&& pkg
->origin_data
.db
== handle
->db_local
488 && !(pkg
->infolevel
& INFRQ_FILES
)) {
489 _alpm_db_read(pkg
->origin_data
.db
, pkg
, INFRQ_FILES
);
495 * Open a package changelog for reading. Similar to fopen in functionality,
496 * except that the returned 'file stream' could really be from an archive
497 * as well as from the database.
498 * @param pkg the package to read the changelog of (either file or db)
499 * @return a 'file stream' to the package changelog
501 void SYMEXPORT
*alpm_pkg_changelog_open(pmpkg_t
*pkg
)
506 ASSERT(handle
!= NULL
, return(NULL
));
507 ASSERT(pkg
!= NULL
, return(NULL
));
509 if(pkg
->origin
== PKG_FROM_CACHE
) {
510 char clfile
[PATH_MAX
];
511 snprintf(clfile
, PATH_MAX
, "%s/%s/%s-%s/changelog",
512 alpm_option_get_dbpath(),
513 alpm_db_get_name(handle
->db_local
),
514 alpm_pkg_get_name(pkg
),
515 alpm_pkg_get_version(pkg
));
516 return fopen(clfile
, "r");
517 } else if(pkg
->origin
== PKG_FROM_FILE
) {
518 struct archive
*archive
= NULL
;
519 struct archive_entry
*entry
;
520 const char *pkgfile
= pkg
->origin_data
.file
;
521 int ret
= ARCHIVE_OK
;
523 if((archive
= archive_read_new()) == NULL
) {
524 RET_ERR(PM_ERR_LIBARCHIVE_ERROR
, NULL
);
527 archive_read_support_compression_all(archive
);
528 archive_read_support_format_all(archive
);
530 if (archive_read_open_filename(archive
, pkgfile
,
531 ARCHIVE_DEFAULT_BYTES_PER_BLOCK
) != ARCHIVE_OK
) {
532 RET_ERR(PM_ERR_PKG_OPEN
, NULL
);
535 while((ret
= archive_read_next_header(archive
, &entry
)) == ARCHIVE_OK
) {
536 const char *entry_name
= archive_entry_pathname(entry
);
538 if(strcmp(entry_name
, ".CHANGELOG") == 0) {
542 /* we didn't find a changelog */
543 archive_read_finish(archive
);
550 * Read data from an open changelog 'file stream'. Similar to fread in
551 * functionality, this function takes a buffer and amount of data to read.
552 * @param ptr a buffer to fill with raw changelog data
553 * @param size the size of the buffer
554 * @param pkg the package that the changelog is being read from
555 * @param fp a 'file stream' to the package changelog
556 * @return the number of characters read, or 0 if there is no more data
558 size_t SYMEXPORT
alpm_pkg_changelog_read(void *ptr
, size_t size
,
559 const pmpkg_t
*pkg
, const void *fp
)
562 if(pkg
->origin
== PKG_FROM_CACHE
) {
563 ret
= fread(ptr
, 1, size
, (FILE*)fp
);
564 } else if(pkg
->origin
== PKG_FROM_FILE
) {
565 ret
= archive_read_data((struct archive
*)fp
, ptr
, size
);
571 int SYMEXPORT alpm_pkg_changelog_feof(const pmpkg_t *pkg, void *fp)
574 if(pkg->origin == PKG_FROM_CACHE) {
575 ret = feof((FILE*)fp);
576 } else if(pkg->origin == PKG_FROM_FILE) {
577 // note: this doesn't quite work, no feof in libarchive
578 ret = archive_read_data((struct archive*)fp, NULL, 0);
585 * Close a package changelog for reading. Similar to fclose in functionality,
586 * except that the 'file stream' could really be from an archive as well as
588 * @param pkg the package that the changelog was read from
589 * @param fp a 'file stream' to the package changelog
590 * @return whether closing the package changelog stream was successful
592 int SYMEXPORT
alpm_pkg_changelog_close(const pmpkg_t
*pkg
, void *fp
)
595 if(pkg
->origin
== PKG_FROM_CACHE
) {
596 ret
= fclose((FILE*)fp
);
597 } else if(pkg
->origin
== PKG_FROM_FILE
) {
598 ret
= archive_read_finish((struct archive
*)fp
);
603 unsigned short SYMEXPORT
alpm_pkg_has_scriptlet(pmpkg_t
*pkg
)
608 ASSERT(handle
!= NULL
, return(-1));
609 ASSERT(pkg
!= NULL
, return(-1));
611 if(pkg
->origin
== PKG_FROM_CACHE
&& pkg
->origin_data
.db
== handle
->db_local
612 && !(pkg
->infolevel
& INFRQ_SCRIPTLET
)) {
613 _alpm_db_read(pkg
->origin_data
.db
, pkg
, INFRQ_SCRIPTLET
);
615 return pkg
->scriptlet
;
619 * @brief Compute the packages requiring a given package.
620 * @param pkg a package
621 * @return the list of packages requiring pkg
623 * A depends on B through n depends <=> A listed in B's requiredby n times
624 * n == 0 or 1 in almost all cases */
625 alpm_list_t SYMEXPORT
*alpm_pkg_compute_requiredby(pmpkg_t
*pkg
)
627 const alpm_list_t
*i
, *j
;
628 alpm_list_t
*reqs
= NULL
;
630 pmdb_t
*localdb
= alpm_option_get_localdb();
631 for(i
= _alpm_db_get_pkgcache(localdb
); i
; i
= i
->next
) {
635 pmpkg_t
*cachepkg
= i
->data
;
636 const char *cachepkgname
= alpm_pkg_get_name(cachepkg
);
638 for(j
= alpm_pkg_get_depends(cachepkg
); j
; j
= j
->next
) {
639 pmdepend_t
*dep
= j
->data
;
641 if(alpm_depcmp(pkg
, dep
)) {
642 _alpm_log(PM_LOG_DEBUG
, "adding '%s' in requiredby field for '%s'\n",
643 cachepkgname
, pkg
->name
);
644 reqs
= alpm_list_add(reqs
, strdup(cachepkgname
));
653 /* this function was taken from rpm 4.0.4 and rewritten */
654 int _alpm_versioncmp(const char *a
, const char *b
)
656 char str1
[64], str2
[64];
659 char *rel1
= NULL
, *rel2
= NULL
;
670 strncpy(str1
, a
, 64);
672 strncpy(str2
, b
, 64);
675 /* lose the release number */
676 for(one
= str1
; *one
&& *one
!= '-'; one
++);
681 for(two
= str2
; *two
&& *two
!= '-'; two
++);
690 while(*one
|| *two
) {
691 while(*one
&& !isalnum((int)*one
)) one
++;
692 while(*two
&& !isalnum((int)*two
)) two
++;
697 /* find the next segment for each string */
698 if(isdigit((int)*ptr1
)) {
700 while(*ptr1
&& isdigit((int)*ptr1
)) ptr1
++;
703 while(*ptr1
&& isalpha((int)*ptr1
)) ptr1
++;
705 if(isdigit((int)*ptr2
)) {
707 while(*ptr2
&& isdigit((int)*ptr2
)) ptr2
++;
710 while(*ptr2
&& isalpha((int)*ptr2
)) ptr2
++;
718 /* see if we ran out of segments on one string */
719 if(one
== ptr1
&& two
!= ptr2
) {
720 return(is2num
? -1 : 1);
722 if(one
!= ptr1
&& two
== ptr2
) {
723 return(is1num
? 1 : -1);
726 /* see if we have a type mismatch (ie, one is alpha and one is digits) */
727 if(is1num
&& !is2num
) return(1);
728 if(!is1num
&& is2num
) return(-1);
730 if(is1num
) while(*one
== '0') one
++;
731 if(is2num
) while(*two
== '0') two
++;
733 rc
= strverscmp(one
, two
);
742 if((!*one
) && (!*two
)) {
743 /* compare release numbers */
744 if(rel1
&& rel2
&& strlen(rel1
) && strlen(rel2
)) return(_alpm_versioncmp(rel1
, rel2
));
748 return(*one
? 1 : -1);
752 pmpkg_t
*_alpm_pkg_new(const char *name
, const char *version
)
758 CALLOC(pkg
, 1, sizeof(pmpkg_t
), RET_ERR(PM_ERR_MEMORY
, NULL
));
761 STRDUP(pkg
->name
, name
, RET_ERR(PM_ERR_MEMORY
, pkg
));
765 STRDUP(pkg
->version
, version
, RET_ERR(PM_ERR_MEMORY
, pkg
));
771 pmpkg_t
*_alpm_pkg_dup(pmpkg_t
*pkg
)
778 CALLOC(newpkg
, 1, sizeof(pmpkg_t
), RET_ERR(PM_ERR_MEMORY
, NULL
));
780 STRDUP(newpkg
->filename
, pkg
->filename
, RET_ERR(PM_ERR_MEMORY
, newpkg
));
781 STRDUP(newpkg
->name
, pkg
->name
, RET_ERR(PM_ERR_MEMORY
, newpkg
));
782 STRDUP(newpkg
->version
, pkg
->version
, RET_ERR(PM_ERR_MEMORY
, newpkg
));
783 STRDUP(newpkg
->desc
, pkg
->desc
, RET_ERR(PM_ERR_MEMORY
, newpkg
));
784 STRDUP(newpkg
->url
, pkg
->url
, RET_ERR(PM_ERR_MEMORY
, newpkg
));
785 newpkg
->builddate
= pkg
->builddate
;
786 newpkg
->installdate
= pkg
->installdate
;
787 STRDUP(newpkg
->packager
, pkg
->packager
, RET_ERR(PM_ERR_MEMORY
, newpkg
));
788 STRDUP(newpkg
->md5sum
, pkg
->md5sum
, RET_ERR(PM_ERR_MEMORY
, newpkg
));
789 STRDUP(newpkg
->arch
, pkg
->arch
, RET_ERR(PM_ERR_MEMORY
, newpkg
));
790 newpkg
->size
= pkg
->size
;
791 newpkg
->isize
= pkg
->isize
;
792 newpkg
->scriptlet
= pkg
->scriptlet
;
793 newpkg
->force
= pkg
->force
;
794 newpkg
->reason
= pkg
->reason
;
796 newpkg
->licenses
= alpm_list_strdup(alpm_pkg_get_licenses(pkg
));
797 newpkg
->replaces
= alpm_list_strdup(alpm_pkg_get_replaces(pkg
));
798 newpkg
->groups
= alpm_list_strdup(alpm_pkg_get_groups(pkg
));
799 newpkg
->files
= alpm_list_strdup(alpm_pkg_get_files(pkg
));
800 newpkg
->backup
= alpm_list_strdup(alpm_pkg_get_backup(pkg
));
801 for(i
= alpm_pkg_get_depends(pkg
); i
; i
= alpm_list_next(i
)) {
802 newpkg
->depends
= alpm_list_add(newpkg
->depends
, _alpm_dep_dup(i
->data
));
804 newpkg
->optdepends
= alpm_list_strdup(alpm_pkg_get_optdepends(pkg
));
805 newpkg
->conflicts
= alpm_list_strdup(alpm_pkg_get_conflicts(pkg
));
806 newpkg
->provides
= alpm_list_strdup(alpm_pkg_get_provides(pkg
));
807 newpkg
->deltas
= alpm_list_copy_data(alpm_pkg_get_deltas(pkg
),
811 newpkg
->origin
= pkg
->origin
;
812 if(newpkg
->origin
== PKG_FROM_FILE
) {
813 newpkg
->origin_data
.file
= strdup(pkg
->origin_data
.file
);
815 newpkg
->origin_data
.db
= pkg
->origin_data
.db
;
817 newpkg
->infolevel
= pkg
->infolevel
;
822 void _alpm_pkg_free(pmpkg_t
*pkg
)
838 FREELIST(pkg
->licenses
);
839 FREELIST(pkg
->replaces
);
840 FREELIST(pkg
->groups
);
841 FREELIST(pkg
->files
);
842 FREELIST(pkg
->backup
);
843 alpm_list_free_inner(pkg
->depends
, (alpm_list_fn_free
)_alpm_dep_free
);
844 alpm_list_free(pkg
->depends
);
845 FREELIST(pkg
->optdepends
);
846 FREELIST(pkg
->conflicts
);
847 FREELIST(pkg
->provides
);
848 alpm_list_free_inner(pkg
->deltas
, (alpm_list_fn_free
)_alpm_delta_free
);
849 alpm_list_free(pkg
->deltas
);
851 if(pkg
->origin
== PKG_FROM_FILE
) {
852 FREE(pkg
->origin_data
.file
);
857 /* Is pkgB an upgrade for pkgA ? */
858 int _alpm_pkg_compare_versions(pmpkg_t
*local_pkg
, pmpkg_t
*pkg
)
864 if(pkg
->origin
== PKG_FROM_CACHE
) {
865 /* ensure we have the /desc file, which contains the 'force' option */
866 _alpm_db_read(pkg
->origin_data
.db
, pkg
, INFRQ_DESC
);
869 /* compare versions and see if we need to upgrade */
870 cmp
= _alpm_versioncmp(alpm_pkg_get_version(pkg
), alpm_pkg_get_version(local_pkg
));
872 if(cmp
!= 0 && pkg
->force
) {
874 _alpm_log(PM_LOG_WARNING
, _("%s: forcing upgrade to version %s\n"),
875 alpm_pkg_get_name(pkg
), alpm_pkg_get_version(pkg
));
877 /* local version is newer */
878 pmdb_t
*db
= pkg
->origin_data
.db
;
879 _alpm_log(PM_LOG_WARNING
, _("%s: local (%s) is newer than %s (%s)\n"),
880 alpm_pkg_get_name(local_pkg
), alpm_pkg_get_version(local_pkg
),
881 alpm_db_get_name(db
), alpm_pkg_get_version(pkg
));
888 /* Helper function for comparing packages
890 int _alpm_pkg_cmp(const void *p1
, const void *p2
)
892 pmpkg_t
*pk1
= (pmpkg_t
*)p1
;
893 pmpkg_t
*pk2
= (pmpkg_t
*)p2
;
895 return(strcmp(alpm_pkg_get_name(pk1
), alpm_pkg_get_name(pk2
)));
898 /* Parses the package description file for the current package
899 * TODO: this should ALL be in a backend interface (be_files), we should
900 * be dealing with the abstracted concepts only in this file
901 * Returns: 0 on success, 1 on error
904 static int parse_descfile(const char *descfile
, pmpkg_t
*info
)
914 if((fp
= fopen(descfile
, "r")) == NULL
) {
915 _alpm_log(PM_LOG_ERROR
, _("could not open file %s: %s\n"), descfile
, strerror(errno
));
920 fgets(line
, PATH_MAX
, fp
);
923 if(strlen(line
) == 0 || line
[0] == '#') {
927 key
= strsep(&ptr
, "=");
928 if(key
== NULL
|| ptr
== NULL
) {
929 _alpm_log(PM_LOG_DEBUG
, "%s: syntax error in description file line %d\n",
930 info
->name
[0] != '\0' ? info
->name
: "error", linenum
);
932 key
= _alpm_strtrim(key
);
933 ptr
= _alpm_strtrim(ptr
);
934 if(!strcmp(key
, "pkgname")) {
935 STRDUP(info
->name
, ptr
, RET_ERR(PM_ERR_MEMORY
, -1));
936 } else if(!strcmp(key
, "pkgver")) {
937 STRDUP(info
->version
, ptr
, RET_ERR(PM_ERR_MEMORY
, -1));
938 } else if(!strcmp(key
, "pkgdesc")) {
939 STRDUP(info
->desc
, ptr
, RET_ERR(PM_ERR_MEMORY
, -1));
940 } else if(!strcmp(key
, "group")) {
941 info
->groups
= alpm_list_add(info
->groups
, strdup(ptr
));
942 } else if(!strcmp(key
, "url")) {
943 STRDUP(info
->url
, ptr
, RET_ERR(PM_ERR_MEMORY
, -1));
944 } else if(!strcmp(key
, "license")) {
945 info
->licenses
= alpm_list_add(info
->licenses
, strdup(ptr
));
946 } else if(!strcmp(key
, "builddate")) {
947 char first
= tolower(ptr
[0]);
948 if(first
> 'a' && first
< 'z') {
949 struct tm tmp_tm
= {0}; //initialize to null incase of failure
950 setlocale(LC_TIME
, "C");
951 strptime(ptr
, "%a %b %e %H:%M:%S %Y", &tmp_tm
);
952 info
->builddate
= mktime(&tmp_tm
);
953 setlocale(LC_TIME
, "");
955 info
->builddate
= atol(ptr
);
957 } else if(!strcmp(key
, "packager")) {
958 STRDUP(info
->packager
, ptr
, RET_ERR(PM_ERR_MEMORY
, -1));
959 } else if(!strcmp(key
, "arch")) {
960 STRDUP(info
->arch
, ptr
, RET_ERR(PM_ERR_MEMORY
, -1));
961 } else if(!strcmp(key
, "size")) {
962 /* size in the raw package is uncompressed (installed) size */
963 info
->isize
= atol(ptr
);
964 } else if(!strcmp(key
, "depend")) {
965 pmdepend_t
*dep
= _alpm_splitdep(ptr
);
966 info
->depends
= alpm_list_add(info
->depends
, dep
);
967 } else if(!strcmp(key
, "optdepend")) {
968 info
->optdepends
= alpm_list_add(info
->optdepends
, strdup(ptr
));
969 } else if(!strcmp(key
, "conflict")) {
970 info
->conflicts
= alpm_list_add(info
->conflicts
, strdup(ptr
));
971 } else if(!strcmp(key
, "replaces")) {
972 info
->replaces
= alpm_list_add(info
->replaces
, strdup(ptr
));
973 } else if(!strcmp(key
, "provides")) {
974 info
->provides
= alpm_list_add(info
->provides
, strdup(ptr
));
975 } else if(!strcmp(key
, "backup")) {
976 info
->backup
= alpm_list_add(info
->backup
, strdup(ptr
));
978 _alpm_log(PM_LOG_DEBUG
, "%s: syntax error in description file line %d\n",
979 info
->name
[0] != '\0' ? info
->name
: "error", linenum
);
992 * Load a package and create the corresponding pmpkg_t struct.
993 * @param pkgfile path to the package file
994 * @param full whether to stop the load after metadata is read or continue
995 * through the full archive
996 * @return An information filled pmpkg_t struct
998 pmpkg_t
*_alpm_pkg_load(const char *pkgfile
, unsigned short full
)
1000 int ret
= ARCHIVE_OK
;
1002 struct archive
*archive
;
1003 struct archive_entry
*entry
;
1004 pmpkg_t
*info
= NULL
;
1005 char *descfile
= NULL
;
1011 if(pkgfile
== NULL
|| strlen(pkgfile
) == 0) {
1012 RET_ERR(PM_ERR_WRONG_ARGS
, NULL
);
1015 if((archive
= archive_read_new()) == NULL
) {
1016 RET_ERR(PM_ERR_LIBARCHIVE_ERROR
, NULL
);
1019 archive_read_support_compression_all(archive
);
1020 archive_read_support_format_all(archive
);
1022 if (archive_read_open_filename(archive
, pkgfile
,
1023 ARCHIVE_DEFAULT_BYTES_PER_BLOCK
) != ARCHIVE_OK
) {
1024 RET_ERR(PM_ERR_PKG_OPEN
, NULL
);
1027 info
= _alpm_pkg_new(NULL
, NULL
);
1029 archive_read_finish(archive
);
1030 RET_ERR(PM_ERR_MEMORY
, NULL
);
1033 if(stat(pkgfile
, &st
) == 0) {
1034 info
->size
= st
.st_size
;
1037 /* TODO there is no reason to make temp files to read
1038 * from a libarchive archive, it can be done by reading
1039 * directly from the archive
1040 * See: archive_read_data_into_buffer
1041 * requires changes 'parse_descfile' as well
1044 /* If full is false, only read through the archive until we find our needed
1045 * metadata. If it is true, read through the entire archive, which serves
1046 * as a verfication of integrity and allows us to create the filelist. */
1047 while((ret
= archive_read_next_header(archive
, &entry
)) == ARCHIVE_OK
) {
1048 const char *entry_name
= archive_entry_pathname(entry
);
1050 /* NOTE: we used to look for .FILELIST, but it is easier (and safer) for
1051 * us to just generate this on our own. */
1052 if(strcmp(entry_name
, ".PKGINFO") == 0) {
1053 /* extract this file into /tmp. it has info for us */
1054 descfile
= strdup("/tmp/alpm_XXXXXX");
1055 fd
= mkstemp(descfile
);
1056 if(archive_read_data_into_fd(archive
, fd
) != ARCHIVE_OK
) {
1057 _alpm_log(PM_LOG_ERROR
, _("error extracting package description file to %s\n"),
1061 /* parse the info file */
1062 if(parse_descfile(descfile
, info
) == -1) {
1063 _alpm_log(PM_LOG_ERROR
, _("could not parse package description file in %s\n"),
1067 if(info
->name
== NULL
|| strlen(info
->name
) == 0) {
1068 _alpm_log(PM_LOG_ERROR
, _("missing package name in %s\n"), pkgfile
);
1071 if(info
->version
== NULL
|| strlen(info
->version
) == 0) {
1072 _alpm_log(PM_LOG_ERROR
, _("missing package version in %s\n"), pkgfile
);
1080 } else if(strcmp(entry_name
, ".INSTALL") == 0) {
1081 info
->scriptlet
= 1;
1082 } else if(*entry_name
== '.') {
1083 /* for now, ignore all files starting with '.' that haven't
1084 * already been handled (for future possibilities) */
1086 /* Keep track of all files for filelist generation */
1087 info
->files
= alpm_list_add(info
->files
, strdup(entry_name
));
1090 if(archive_read_data_skip(archive
)) {
1091 _alpm_log(PM_LOG_ERROR
, _("error while reading package %s: %s\n"),
1092 pkgfile
, archive_error_string(archive
));
1093 pm_errno
= PM_ERR_LIBARCHIVE_ERROR
;
1097 /* if we are not doing a full read, see if we have all we need */
1098 if(!full
&& config
) {
1103 if(ret
!= ARCHIVE_EOF
&& ret
!= ARCHIVE_OK
) { /* An error occured */
1104 _alpm_log(PM_LOG_ERROR
, _("error while reading package %s: %s\n"),
1105 pkgfile
, archive_error_string(archive
));
1106 pm_errno
= PM_ERR_LIBARCHIVE_ERROR
;
1111 _alpm_log(PM_LOG_ERROR
, _("missing package metadata in %s\n"), pkgfile
);
1115 archive_read_finish(archive
);
1117 /* internal fields for package struct */
1118 info
->origin
= PKG_FROM_FILE
;
1119 info
->origin_data
.file
= strdup(pkgfile
);
1122 /* "checking for conflicts" requires a sorted list, so we ensure that here */
1123 _alpm_log(PM_LOG_DEBUG
, "sorting package filelist for %s\n", pkgfile
);
1124 info
->files
= alpm_list_msort(info
->files
, alpm_list_count(info
->files
),
1126 info
->infolevel
= INFRQ_ALL
;
1128 /* get rid of any partial filelist we may have collected, as it is invalid */
1129 FREELIST(info
->files
);
1130 info
->infolevel
= INFRQ_BASE
| INFRQ_DESC
| INFRQ_DEPENDS
;
1136 pm_errno
= PM_ERR_PKG_INVALID
;
1145 _alpm_pkg_free(info
);
1146 archive_read_finish(archive
);
1151 /* Test for existence of a package in a alpm_list_t*
1154 pmpkg_t
*_alpm_pkg_find(const char *needle
, alpm_list_t
*haystack
)
1160 if(needle
== NULL
|| haystack
== NULL
) {
1164 for(lp
= haystack
; lp
; lp
= lp
->next
) {
1165 pmpkg_t
*info
= lp
->data
;
1167 if(info
&& strcmp(alpm_pkg_get_name(info
), needle
) == 0) {
1174 /** Test if a package should be ignored.
1176 * Checks if the package is ignored via IgnorePkg, or if the package is
1177 * in a group ignored via IgnoreGrp.
1179 * @param pkg the package to test
1181 * @return 1 if the package should be ignored, 0 otherwise
1183 int _alpm_pkg_should_ignore(pmpkg_t
*pkg
)
1185 alpm_list_t
*groups
= NULL
;
1187 /* first see if the package is ignored */
1188 if(alpm_list_find_str(handle
->ignorepkg
, alpm_pkg_get_name(pkg
))) {
1192 /* next see if the package is in a group that is ignored */
1193 for(groups
= handle
->ignoregrp
; groups
; groups
= alpm_list_next(groups
)) {
1194 char *grp
= (char *)alpm_list_getdata(groups
);
1195 if(alpm_list_find_str(alpm_pkg_get_groups(pkg
), grp
)) {
1203 /* vim: set ts=2 sw=2 noet: */