summaryrefslogtreecommitdiff
path: root/lib/libalpm
diff options
context:
space:
mode:
Diffstat (limited to 'lib/libalpm')
-rw-r--r--lib/libalpm/Makefile.am11
-rw-r--r--lib/libalpm/add.c131
-rw-r--r--lib/libalpm/add.h2
-rw-r--r--lib/libalpm/alpm.c15
-rw-r--r--lib/libalpm/alpm.h71
-rw-r--r--lib/libalpm/alpm_list.c10
-rw-r--r--lib/libalpm/alpm_list.h8
-rw-r--r--lib/libalpm/backup.c2
-rw-r--r--lib/libalpm/backup.h2
-rw-r--r--lib/libalpm/be_files.c977
-rw-r--r--lib/libalpm/be_local.c921
-rw-r--r--lib/libalpm/be_package.c176
-rw-r--r--lib/libalpm/be_sync.c404
-rw-r--r--lib/libalpm/cache.c291
-rw-r--r--lib/libalpm/cache.h44
-rw-r--r--lib/libalpm/conflict.c19
-rw-r--r--lib/libalpm/conflict.h2
-rw-r--r--lib/libalpm/db.c280
-rw-r--r--lib/libalpm/db.h54
-rw-r--r--lib/libalpm/delta.c2
-rw-r--r--lib/libalpm/delta.h5
-rw-r--r--lib/libalpm/deps.c131
-rw-r--r--lib/libalpm/deps.h6
-rw-r--r--lib/libalpm/diskspace.c337
-rw-r--r--lib/libalpm/diskspace.h46
-rw-r--r--lib/libalpm/dload.c21
-rw-r--r--lib/libalpm/dload.h2
-rw-r--r--lib/libalpm/error.c15
-rw-r--r--lib/libalpm/graph.h2
-rw-r--r--lib/libalpm/group.c2
-rw-r--r--lib/libalpm/group.h2
-rw-r--r--lib/libalpm/handle.c16
-rw-r--r--lib/libalpm/handle.h5
-rw-r--r--lib/libalpm/log.c2
-rw-r--r--lib/libalpm/log.h2
-rw-r--r--lib/libalpm/md5.c13
-rw-r--r--lib/libalpm/package.c456
-rw-r--r--lib/libalpm/package.h90
-rw-r--r--lib/libalpm/po/Makefile.in.in167
-rw-r--r--lib/libalpm/po/POTFILES.in3
-rw-r--r--lib/libalpm/remove.c45
-rw-r--r--lib/libalpm/remove.h2
-rw-r--r--lib/libalpm/sync.c42
-rw-r--r--lib/libalpm/sync.h2
-rw-r--r--lib/libalpm/trans.c17
-rw-r--r--lib/libalpm/trans.h2
-rw-r--r--lib/libalpm/util.c368
-rw-r--r--lib/libalpm/util.h38
-rw-r--r--lib/libalpm/version.c159
49 files changed, 3245 insertions, 2175 deletions
diff --git a/lib/libalpm/Makefile.am b/lib/libalpm/Makefile.am
index 3473a73a..da663cb5 100644
--- a/lib/libalpm/Makefile.am
+++ b/lib/libalpm/Makefile.am
@@ -25,20 +25,20 @@ libalpm_la_SOURCES = \
alpm.h alpm.c \
alpm_list.h alpm_list.c \
backup.h backup.c \
- be_files.c \
+ be_local.c \
be_package.c \
- cache.h cache.c \
+ be_sync.c \
conflict.h conflict.c \
db.h db.c \
delta.h delta.c \
deps.h deps.c \
+ diskspace.h diskspace.c \
dload.h dload.c \
error.c \
graph.h \
group.h group.c \
handle.h handle.c \
log.h log.c \
- md5.h md5.c \
package.h package.c \
remove.h remove.c \
sync.h sync.c \
@@ -46,6 +46,11 @@ libalpm_la_SOURCES = \
util.h util.c \
version.c
+if !HAVE_LIBSSL
+libalpm_la_SOURCES += \
+ md5.h md5.c
+endif
+
libalpm_la_LDFLAGS = -no-undefined -version-info $(LIB_VERSION_INFO)
libalpm_la_LIBADD = $(LTLIBINTL)
diff --git a/lib/libalpm/add.c b/lib/libalpm/add.c
index f39a0ecf..d4c56def 100644
--- a/lib/libalpm/add.c
+++ b/lib/libalpm/add.c
@@ -1,7 +1,7 @@
/*
* add.c
*
- * Copyright (c) 2006-2010 Pacman Development Team <pacman-dev@archlinux.org>
+ * Copyright (c) 2006-2011 Pacman Development Team <pacman-dev@archlinux.org>
* Copyright (c) 2002-2006 by Judd Vinet <jvinet@zeroflux.org>
*
* This program is free software; you can redistribute it and/or modify
@@ -40,7 +40,6 @@
#include "alpm_list.h"
#include "trans.h"
#include "util.h"
-#include "cache.h"
#include "log.h"
#include "backup.h"
#include "package.h"
@@ -54,7 +53,7 @@
* @param target the name of the file target to add
* @return 0 on success, -1 on error (pm_errno is set accordingly)
*/
-int SYMEXPORT alpm_add_target(char *target)
+int SYMEXPORT alpm_add_target(const char *target)
{
pmpkg_t *pkg = NULL;
const char *pkgname, *pkgver;
@@ -110,6 +109,31 @@ error:
return(-1);
}
+static int perform_extraction(struct archive *archive,
+ struct archive_entry *entry, const char *filename, const char *origname)
+{
+ int ret;
+ const int archive_flags = ARCHIVE_EXTRACT_OWNER |
+ ARCHIVE_EXTRACT_PERM |
+ ARCHIVE_EXTRACT_TIME;
+
+ archive_entry_set_pathname(entry, filename);
+
+ ret = archive_read_extract(archive, entry, archive_flags);
+ if(ret == ARCHIVE_WARN && archive_errno(archive) != ENOSPC) {
+ /* operation succeeded but a "non-critical" error was encountered */
+ _alpm_log(PM_LOG_WARNING, _("warning given when extracting %s (%s)\n"),
+ origname, archive_error_string(archive));
+ } else if(ret != ARCHIVE_OK) {
+ _alpm_log(PM_LOG_ERROR, _("could not extract %s (%s)\n"),
+ origname, archive_error_string(archive));
+ alpm_logaction("error: could not extract %s (%s)\n",
+ origname, archive_error_string(archive));
+ return(1);
+ }
+ return(0);
+}
+
static int extract_single_file(struct archive *archive,
struct archive_entry *entry, pmpkg_t *newpkg, pmpkg_t *oldpkg,
pmtrans_t *trans, pmdb_t *db)
@@ -120,9 +144,6 @@ static int extract_single_file(struct archive *archive,
int needbackup = 0, notouch = 0;
char *hash_orig = NULL;
char *entryname_orig = NULL;
- const int archive_flags = ARCHIVE_EXTRACT_OWNER |
- ARCHIVE_EXTRACT_PERM |
- ARCHIVE_EXTRACT_TIME;
int errors = 0;
entryname = archive_entry_pathname(entry);
@@ -277,18 +298,10 @@ static int extract_single_file(struct archive *archive,
int ret;
snprintf(checkfile, PATH_MAX, "%s.paccheck", filename);
- archive_entry_set_pathname(entry, checkfile);
-
- ret = archive_read_extract(archive, entry, archive_flags);
- if(ret == ARCHIVE_WARN) {
- /* operation succeeded but a non-critical error was encountered */
- _alpm_log(PM_LOG_DEBUG, "warning extracting %s (%s)\n",
- entryname_orig, archive_error_string(archive));
- } else if(ret != ARCHIVE_OK) {
- _alpm_log(PM_LOG_ERROR, _("could not extract %s (%s)\n"),
- entryname_orig, archive_error_string(archive));
- alpm_logaction("error: could not extract %s (%s)\n",
- entryname_orig, archive_error_string(archive));
+
+ ret = perform_extraction(archive, entry, checkfile, entryname_orig);
+ if(ret == 1) {
+ /* error */
FREE(hash_orig);
FREE(entryname_orig);
return(1);
@@ -430,18 +443,9 @@ static int extract_single_file(struct archive *archive,
unlink(filename);
}
- archive_entry_set_pathname(entry, filename);
-
- ret = archive_read_extract(archive, entry, archive_flags);
- if(ret == ARCHIVE_WARN) {
- /* operation succeeded but a non-critical error was encountered */
- _alpm_log(PM_LOG_DEBUG, "warning extracting %s (%s)\n",
- entryname_orig, archive_error_string(archive));
- } else if(ret != ARCHIVE_OK) {
- _alpm_log(PM_LOG_ERROR, _("could not extract %s (%s)\n"),
- entryname_orig, archive_error_string(archive));
- alpm_logaction("error: could not extract %s (%s)\n",
- entryname_orig, archive_error_string(archive));
+ ret = perform_extraction(archive, entry, filename, entryname_orig);
+ if(ret == 1) {
+ /* error */
FREE(entryname_orig);
return(1);
}
@@ -473,8 +477,8 @@ static int extract_single_file(struct archive *archive,
return(errors);
}
-static int commit_single_pkg(pmpkg_t *newpkg, int pkg_current, int pkg_count,
- pmtrans_t *trans, pmdb_t *db)
+static int commit_single_pkg(pmpkg_t *newpkg, size_t pkg_current,
+ size_t pkg_count, pmtrans_t *trans, pmdb_t *db)
{
int i, ret = 0, errors = 0;
char scriptlet[PATH_MAX+1];
@@ -498,7 +502,7 @@ static int commit_single_pkg(pmpkg_t *newpkg, int pkg_current, int pkg_count,
oldpkg = _alpm_pkg_dup(local);
/* make sure all infos are loaded because the database entry
* will be removed soon */
- _alpm_db_read(oldpkg->origin_data.db, oldpkg, INFRQ_ALL);
+ _alpm_local_db_read(oldpkg->origin_data.db, oldpkg, INFRQ_ALL);
EVENT(trans, PM_TRANS_EVT_UPGRADE_START, newpkg, oldpkg);
_alpm_log(PM_LOG_DEBUG, "upgrading package %s-%s\n",
@@ -544,7 +548,7 @@ static int commit_single_pkg(pmpkg_t *newpkg, int pkg_current, int pkg_count,
/* prepare directory for database entries so permission are correct after
changelog/install script installation (FS#12263) */
- if(_alpm_db_prepare(db, newpkg)) {
+ if(_alpm_local_db_prepare(db, newpkg)) {
alpm_logaction("error: could not create database entry %s-%s\n",
alpm_pkg_get_name(newpkg), alpm_pkg_get_version(newpkg));
pm_errno = PM_ERR_DB_WRITE;
@@ -556,6 +560,7 @@ static int commit_single_pkg(pmpkg_t *newpkg, int pkg_current, int pkg_count,
struct archive *archive;
struct archive_entry *entry;
char cwd[PATH_MAX] = "";
+ int restore_cwd = 0;
_alpm_log(PM_LOG_DEBUG, "extracting files\n");
@@ -579,11 +584,16 @@ static int commit_single_pkg(pmpkg_t *newpkg, int pkg_current, int pkg_count,
/* save the cwd so we can restore it later */
if(getcwd(cwd, PATH_MAX) == NULL) {
_alpm_log(PM_LOG_ERROR, _("could not get current working directory\n"));
- cwd[0] = 0;
+ } else {
+ restore_cwd = 1;
}
/* libarchive requires this for extracting hard links */
- chdir(handle->root);
+ if(chdir(handle->root) != 0) {
+ _alpm_log(PM_LOG_ERROR, _("could not change directory to %s (%s)\n"), handle->root, strerror(errno));
+ ret = -1;
+ goto cleanup;
+ }
/* call PROGRESS once with 0 percent, as we sort-of skip that here */
if(is_upgrade) {
@@ -595,31 +605,31 @@ static int commit_single_pkg(pmpkg_t *newpkg, int pkg_current, int pkg_count,
}
for(i = 0; archive_read_next_header(archive, &entry) == ARCHIVE_OK; i++) {
- double percent;
+ int percent;
if(newpkg->size != 0) {
/* Using compressed size for calculations here, as newpkg->isize is not
* exact when it comes to comparing to the ACTUAL uncompressed size
* (missing metadata sizes) */
int64_t pos = archive_position_compressed(archive);
- percent = (double)pos / (double)newpkg->size;
+ percent = (pos * 100) / newpkg->size;
_alpm_log(PM_LOG_DEBUG, "decompression progress: "
- "%f%% (%"PRId64" / %jd)\n",
- percent*100.0, pos, (intmax_t)newpkg->size);
- if(percent >= 1.0) {
- percent = 1.0;
+ "%d%% (%"PRId64" / %jd)\n",
+ percent, pos, (intmax_t)newpkg->size);
+ if(percent >= 100) {
+ percent = 100;
}
} else {
- percent = 0.0;
+ percent = 0;
}
if(is_upgrade) {
PROGRESS(trans, PM_TRANS_PROGRESS_UPGRADE_START,
- alpm_pkg_get_name(newpkg), (int)(percent * 100), pkg_count,
+ alpm_pkg_get_name(newpkg), percent, pkg_count,
pkg_current);
} else {
PROGRESS(trans, PM_TRANS_PROGRESS_ADD_START,
- alpm_pkg_get_name(newpkg), (int)(percent * 100), pkg_count,
+ alpm_pkg_get_name(newpkg), percent, pkg_count,
pkg_current);
}
@@ -629,9 +639,9 @@ static int commit_single_pkg(pmpkg_t *newpkg, int pkg_current, int pkg_count,
}
archive_read_finish(archive);
- /* restore the old cwd is we have it */
- if(strlen(cwd)) {
- chdir(cwd);
+ /* restore the old cwd if we have it */
+ if(restore_cwd && chdir(cwd) != 0) {
+ _alpm_log(PM_LOG_ERROR, _("could not change directory to %s (%s)\n"), cwd, strerror(errno));
}
if(errors) {
@@ -656,7 +666,7 @@ static int commit_single_pkg(pmpkg_t *newpkg, int pkg_current, int pkg_count,
_alpm_log(PM_LOG_DEBUG, "updating database\n");
_alpm_log(PM_LOG_DEBUG, "adding database entry '%s'\n", newpkg->name);
- if(_alpm_db_write(db, newpkg, INFRQ_ALL)) {
+ if(_alpm_local_db_write(db, newpkg, INFRQ_ALL)) {
_alpm_log(PM_LOG_ERROR, _("could not update database entry %s-%s\n"),
alpm_pkg_get_name(newpkg), alpm_pkg_get_version(newpkg));
alpm_logaction("error: could not update database entry %s-%s\n",
@@ -705,7 +715,8 @@ cleanup:
int _alpm_upgrade_packages(pmtrans_t *trans, pmdb_t *db)
{
- int pkg_count, pkg_current;
+ size_t pkg_count, pkg_current;
+ int skip_ldconfig = 0, ret = 0;
alpm_list_t *targ;
ALPM_LOG_FUNC;
@@ -723,18 +734,28 @@ int _alpm_upgrade_packages(pmtrans_t *trans, pmdb_t *db)
/* loop through our package list adding/upgrading one at a time */
for(targ = trans->add; targ; targ = targ->next) {
if(handle->trans->state == STATE_INTERRUPTED) {
- return(0);
+ return(ret);
}
pmpkg_t *newpkg = (pmpkg_t *)targ->data;
- commit_single_pkg(newpkg, pkg_current, pkg_count, trans, db);
+ if(commit_single_pkg(newpkg, pkg_current, pkg_count, trans, db)) {
+ /* something screwed up on the commit, abort the trans */
+ trans->state = STATE_INTERRUPTED;
+ pm_errno = PM_ERR_TRANS_ABORT;
+ /* running ldconfig at this point could possibly screw system */
+ skip_ldconfig = 1;
+ ret = -1;
+ }
+
pkg_current++;
}
- /* run ldconfig if it exists */
- _alpm_ldconfig(handle->root);
+ if(!skip_ldconfig) {
+ /* run ldconfig if it exists */
+ _alpm_ldconfig(handle->root);
+ }
- return(0);
+ return(ret);
}
/* vim: set ts=2 sw=2 noet: */
diff --git a/lib/libalpm/add.h b/lib/libalpm/add.h
index eb37dc78..afc7be26 100644
--- a/lib/libalpm/add.h
+++ b/lib/libalpm/add.h
@@ -1,7 +1,7 @@
/*
* add.h
*
- * Copyright (c) 2006-2010 Pacman Development Team <pacman-dev@archlinux.org>
+ * Copyright (c) 2006-2011 Pacman Development Team <pacman-dev@archlinux.org>
* Copyright (c) 2002-2006 by Judd Vinet <jvinet@zeroflux.org>
*
* This program is free software; you can redistribute it and/or modify
diff --git a/lib/libalpm/alpm.c b/lib/libalpm/alpm.c
index 51b9e25b..2a9f4605 100644
--- a/lib/libalpm/alpm.c
+++ b/lib/libalpm/alpm.c
@@ -1,7 +1,7 @@
/*
* alpm.c
*
- * Copyright (c) 2006-2010 Pacman Development Team <pacman-dev@archlinux.org>
+ * Copyright (c) 2006-2011 Pacman Development Team <pacman-dev@archlinux.org>
* Copyright (c) 2002-2006 by Judd Vinet <jvinet@zeroflux.org>
* Copyright (c) 2005 by Aurelien Foret <orelien@chez.com>
* Copyright (c) 2005 by Christian Hamar <krics@linuxforum.hu>
@@ -23,6 +23,11 @@
#include "config.h"
+/* connection caching setup */
+#ifdef HAVE_LIBFETCH
+#include <fetch.h>
+#endif
+
/* libalpm */
#include "alpm.h"
#include "alpm_list.h"
@@ -54,6 +59,10 @@ int SYMEXPORT alpm_initialize(void)
bindtextdomain("libalpm", LOCALEDIR);
#endif
+#ifdef HAVE_LIBFETCH
+ fetchConnectionCacheInit(5, 1);
+#endif
+
return(0);
}
@@ -73,6 +82,10 @@ int SYMEXPORT alpm_release(void)
_alpm_handle_free(handle);
handle = NULL;
+#ifdef HAVE_LIBFETCH
+ fetchConnectionCacheClose();
+#endif
+
return(0);
}
diff --git a/lib/libalpm/alpm.h b/lib/libalpm/alpm.h
index 33291325..a540bc4f 100644
--- a/lib/libalpm/alpm.h
+++ b/lib/libalpm/alpm.h
@@ -1,7 +1,7 @@
/*
* alpm.h
*
- * Copyright (c) 2006-2010 Pacman Development Team <pacman-dev@archlinux.org>
+ * Copyright (c) 2006-2011 Pacman Development Team <pacman-dev@archlinux.org>
* Copyright (c) 2002-2006 by Judd Vinet <jvinet@zeroflux.org>
* Copyright (c) 2005 by Aurelien Foret <orelien@chez.com>
* Copyright (c) 2005 by Christian Hamar <krics@linuxforum.hu>
@@ -97,66 +97,69 @@ typedef int (*alpm_cb_fetch)(const char *url, const char *localpath,
* Options
*/
-alpm_cb_log alpm_option_get_logcb();
+alpm_cb_log alpm_option_get_logcb(void);
void alpm_option_set_logcb(alpm_cb_log cb);
-alpm_cb_download alpm_option_get_dlcb();
+alpm_cb_download alpm_option_get_dlcb(void);
void alpm_option_set_dlcb(alpm_cb_download cb);
-alpm_cb_fetch alpm_option_get_fetchcb();
+alpm_cb_fetch alpm_option_get_fetchcb(void);
void alpm_option_set_fetchcb(alpm_cb_fetch cb);
-alpm_cb_totaldl alpm_option_get_totaldlcb();
+alpm_cb_totaldl alpm_option_get_totaldlcb(void);
void alpm_option_set_totaldlcb(alpm_cb_totaldl cb);
-const char *alpm_option_get_root();
+const char *alpm_option_get_root(void);
int alpm_option_set_root(const char *root);
-const char *alpm_option_get_dbpath();
+const char *alpm_option_get_dbpath(void);
int alpm_option_set_dbpath(const char *dbpath);
-alpm_list_t *alpm_option_get_cachedirs();
+alpm_list_t *alpm_option_get_cachedirs(void);
int alpm_option_add_cachedir(const char *cachedir);
void alpm_option_set_cachedirs(alpm_list_t *cachedirs);
int alpm_option_remove_cachedir(const char *cachedir);
-const char *alpm_option_get_logfile();
+const char *alpm_option_get_logfile(void);
int alpm_option_set_logfile(const char *logfile);
-const char *alpm_option_get_lockfile();
+const char *alpm_option_get_lockfile(void);
/* no set_lockfile, path is determined from dbpath */
-int alpm_option_get_usesyslog();
+int alpm_option_get_usesyslog(void);
void alpm_option_set_usesyslog(int usesyslog);
-alpm_list_t *alpm_option_get_noupgrades();
+alpm_list_t *alpm_option_get_noupgrades(void);
void alpm_option_add_noupgrade(const char *pkg);
void alpm_option_set_noupgrades(alpm_list_t *noupgrade);
int alpm_option_remove_noupgrade(const char *pkg);
-alpm_list_t *alpm_option_get_noextracts();
+alpm_list_t *alpm_option_get_noextracts(void);
void alpm_option_add_noextract(const char *pkg);
void alpm_option_set_noextracts(alpm_list_t *noextract);
int alpm_option_remove_noextract(const char *pkg);
-alpm_list_t *alpm_option_get_ignorepkgs();
+alpm_list_t *alpm_option_get_ignorepkgs(void);
void alpm_option_add_ignorepkg(const char *pkg);
void alpm_option_set_ignorepkgs(alpm_list_t *ignorepkgs);
int alpm_option_remove_ignorepkg(const char *pkg);
-alpm_list_t *alpm_option_get_ignoregrps();
+alpm_list_t *alpm_option_get_ignoregrps(void);
void alpm_option_add_ignoregrp(const char *grp);
void alpm_option_set_ignoregrps(alpm_list_t *ignoregrps);
int alpm_option_remove_ignoregrp(const char *grp);
-const char *alpm_option_get_arch();
+const char *alpm_option_get_arch(void);
void alpm_option_set_arch(const char *arch);
-int alpm_option_get_usedelta();
+int alpm_option_get_usedelta(void);
void alpm_option_set_usedelta(int usedelta);
-pmdb_t *alpm_option_get_localdb();
-alpm_list_t *alpm_option_get_syncdbs();
+int alpm_option_get_checkspace(void);
+void alpm_option_set_checkspace(int checkspace);
+
+pmdb_t *alpm_option_get_localdb(void);
+alpm_list_t *alpm_option_get_syncdbs(void);
/*
* Install reasons -- ie, why the package was installed
@@ -235,7 +238,6 @@ size_t alpm_pkg_changelog_read(void *ptr, size_t size,
/*int alpm_pkg_changelog_feof(const pmpkg_t *pkg, void *fp);*/
int alpm_pkg_changelog_close(const pmpkg_t *pkg, void *fp);
int alpm_pkg_has_scriptlet(pmpkg_t *pkg);
-int alpm_pkg_has_force(pmpkg_t *pkg);
off_t alpm_pkg_download_size(pmpkg_t *newpkg);
alpm_list_t *alpm_pkg_unused_deltas(pmpkg_t *pkg);
@@ -368,6 +370,10 @@ typedef enum _pmtransevt_t {
* The repository's tree name is passed to the callback.
*/
PM_TRANS_EVT_RETRIEVE_START,
+ /** Disk space usage will be computed for a package */
+ PM_TRANS_EVT_DISKSPACE_START,
+ /** Disk space usage was computed for a package */
+ PM_TRANS_EVT_DISKSPACE_DONE,
} pmtransevt_t;
/*@}*/
@@ -386,7 +392,9 @@ typedef enum _pmtransprog_t {
PM_TRANS_PROGRESS_ADD_START,
PM_TRANS_PROGRESS_UPGRADE_START,
PM_TRANS_PROGRESS_REMOVE_START,
- PM_TRANS_PROGRESS_CONFLICTS_START
+ PM_TRANS_PROGRESS_CONFLICTS_START,
+ PM_TRANS_PROGRESS_DISKSPACE_START,
+ PM_TRANS_PROGRESS_INTEGRITY_START,
} pmtransprog_t;
/* Transaction Event callback */
@@ -397,11 +405,11 @@ typedef void (*alpm_trans_cb_conv)(pmtransconv_t, void *, void *,
void *, int *);
/* Transaction Progress callback */
-typedef void (*alpm_trans_cb_progress)(pmtransprog_t, const char *, int, int, int);
+typedef void (*alpm_trans_cb_progress)(pmtransprog_t, const char *, int, size_t, size_t);
-int alpm_trans_get_flags();
-alpm_list_t * alpm_trans_get_add();
-alpm_list_t * alpm_trans_get_remove();
+int alpm_trans_get_flags(void);
+alpm_list_t * alpm_trans_get_add(void);
+alpm_list_t * alpm_trans_get_remove(void);
int alpm_trans_init(pmtransflag_t flags,
alpm_trans_cb_event cb_event, alpm_trans_cb_conv conv,
alpm_trans_cb_progress cb_progress);
@@ -411,10 +419,10 @@ int alpm_trans_interrupt(void);
int alpm_trans_release(void);
int alpm_sync_sysupgrade(int enable_downgrade);
-int alpm_sync_target(char *target);
-int alpm_sync_dbtarget(char *db, char *target);
-int alpm_add_target(char *target);
-int alpm_remove_target(char *target);
+int alpm_sync_target(const char *target);
+int alpm_sync_dbtarget(const char *db, const char *target);
+int alpm_add_target(const char *target);
+int alpm_remove_target(const char *target);
/*
* Dependencies and conflicts
@@ -429,10 +437,9 @@ typedef enum _pmdepmod_t {
PM_DEP_MOD_LT
} pmdepmod_t;
-int alpm_depcmp(pmpkg_t *pkg, pmdepend_t *dep);
alpm_list_t *alpm_checkdeps(alpm_list_t *pkglist, int reversedeps,
alpm_list_t *remove, alpm_list_t *upgrade);
-alpm_list_t *alpm_deptest(pmdb_t *db, alpm_list_t *targets);
+pmpkg_t *alpm_find_satisfier(alpm_list_t *pkgs, const char *depstring);
const char *alpm_miss_get_target(const pmdepmissing_t *miss);
pmdepend_t *alpm_miss_get_dep(pmdepmissing_t *miss);
@@ -480,6 +487,7 @@ enum _pmerrno_t {
PM_ERR_NOT_A_FILE,
PM_ERR_NOT_A_DIR,
PM_ERR_WRONG_ARGS,
+ PM_ERR_DISK_SPACE,
/* Interface */
PM_ERR_HANDLE_NULL,
PM_ERR_HANDLE_NOT_NULL,
@@ -522,6 +530,7 @@ enum _pmerrno_t {
PM_ERR_FILE_CONFLICTS,
/* Misc */
PM_ERR_RETRIEVE,
+ PM_ERR_WRITE,
PM_ERR_INVALID_REGEX,
/* External library errors */
PM_ERR_LIBARCHIVE,
diff --git a/lib/libalpm/alpm_list.c b/lib/libalpm/alpm_list.c
index 80ba1ee7..3f9525e8 100644
--- a/lib/libalpm/alpm_list.c
+++ b/lib/libalpm/alpm_list.c
@@ -1,7 +1,7 @@
/*
* alpm_list.c
*
- * Copyright (c) 2006-2010 Pacman Development Team <pacman-dev@archlinux.org>
+ * Copyright (c) 2006-2011 Pacman Development Team <pacman-dev@archlinux.org>
* Copyright (c) 2002-2006 by Judd Vinet <jvinet@zeroflux.org>
*
* This program is free software; you can redistribute it and/or modify
@@ -269,7 +269,7 @@ alpm_list_t SYMEXPORT *alpm_list_mmerge(alpm_list_t *left, alpm_list_t *right, a
*
* @return the resultant list
*/
-alpm_list_t SYMEXPORT *alpm_list_msort(alpm_list_t *list, int n, alpm_list_fn_cmp fn)
+alpm_list_t SYMEXPORT *alpm_list_msort(alpm_list_t *list, size_t n, alpm_list_fn_cmp fn)
{
if (n > 1) {
alpm_list_t *left = list;
@@ -511,7 +511,7 @@ inline alpm_list_t SYMEXPORT *alpm_list_first(const alpm_list_t *list)
*
* @return an alpm_list_t node for index `n`
*/
-alpm_list_t SYMEXPORT *alpm_list_nth(const alpm_list_t *list, int n)
+alpm_list_t SYMEXPORT *alpm_list_nth(const alpm_list_t *list, size_t n)
{
const alpm_list_t *i = list;
while(n--) {
@@ -574,9 +574,9 @@ void SYMEXPORT *alpm_list_getdata(const alpm_list_t *node)
*
* @return the number of list items
*/
-int SYMEXPORT alpm_list_count(const alpm_list_t *list)
+size_t SYMEXPORT alpm_list_count(const alpm_list_t *list)
{
- unsigned int i = 0;
+ size_t i = 0;
const alpm_list_t *lp = list;
while(lp) {
++i;
diff --git a/lib/libalpm/alpm_list.h b/lib/libalpm/alpm_list.h
index bd639f7d..ee85a5dd 100644
--- a/lib/libalpm/alpm_list.h
+++ b/lib/libalpm/alpm_list.h
@@ -1,7 +1,7 @@
/*
* alpm_list.h
*
- * Copyright (c) 2006-2010 Pacman Development Team <pacman-dev@archlinux.org>
+ * Copyright (c) 2006-2011 Pacman Development Team <pacman-dev@archlinux.org>
* Copyright (c) 2002-2006 by Judd Vinet <jvinet@zeroflux.org>
*
* This program is free software; you can redistribute it and/or modify
@@ -56,7 +56,7 @@ alpm_list_t *alpm_list_add(alpm_list_t *list, void *data);
alpm_list_t *alpm_list_add_sorted(alpm_list_t *list, void *data, alpm_list_fn_cmp fn);
alpm_list_t *alpm_list_join(alpm_list_t *first, alpm_list_t *second);
alpm_list_t *alpm_list_mmerge(alpm_list_t *left, alpm_list_t *right, alpm_list_fn_cmp fn);
-alpm_list_t *alpm_list_msort(alpm_list_t *list, int n, alpm_list_fn_cmp fn);
+alpm_list_t *alpm_list_msort(alpm_list_t *list, size_t n, alpm_list_fn_cmp fn);
alpm_list_t *alpm_list_remove(alpm_list_t *haystack, const void *needle, alpm_list_fn_cmp fn, void **data);
alpm_list_t *alpm_list_remove_str(alpm_list_t *haystack, const char *needle, char **data);
alpm_list_t *alpm_list_remove_dupes(const alpm_list_t *list);
@@ -67,13 +67,13 @@ alpm_list_t *alpm_list_reverse(alpm_list_t *list);
/* item accessors */
alpm_list_t *alpm_list_first(const alpm_list_t *list);
-alpm_list_t *alpm_list_nth(const alpm_list_t *list, int n);
+alpm_list_t *alpm_list_nth(const alpm_list_t *list, size_t n);
alpm_list_t *alpm_list_next(const alpm_list_t *list);
alpm_list_t *alpm_list_last(const alpm_list_t *list);
void *alpm_list_getdata(const alpm_list_t *entry);
/* misc */
-int alpm_list_count(const alpm_list_t *list);
+size_t alpm_list_count(const alpm_list_t *list);
void *alpm_list_find(const alpm_list_t *haystack, const void *needle, alpm_list_fn_cmp fn);
void *alpm_list_find_ptr(const alpm_list_t *haystack, const void *needle);
char *alpm_list_find_str(const alpm_list_t *haystack, const char *needle);
diff --git a/lib/libalpm/backup.c b/lib/libalpm/backup.c
index 2ef65a2b..ca955ca4 100644
--- a/lib/libalpm/backup.c
+++ b/lib/libalpm/backup.c
@@ -1,7 +1,7 @@
/*
* backup.c
*
- * Copyright (c) 2006-2010 Pacman Development Team <pacman-dev@archlinux.org>
+ * Copyright (c) 2006-2011 Pacman Development Team <pacman-dev@archlinux.org>
* Copyright (c) 2005 by Judd Vinet <jvinet@zeroflux.org>
* Copyright (c) 2005 by Aurelien Foret <orelien@chez.com>
* Copyright (c) 2005 by Christian Hamar <krics@linuxforum.hu>
diff --git a/lib/libalpm/backup.h b/lib/libalpm/backup.h
index 25469b90..9475aa2a 100644
--- a/lib/libalpm/backup.h
+++ b/lib/libalpm/backup.h
@@ -1,7 +1,7 @@
/*
* backup.h
*
- * Copyright (c) 2006-2010 Pacman Development Team <pacman-dev@archlinux.org>
+ * Copyright (c) 2006-2011 Pacman Development Team <pacman-dev@archlinux.org>
* Copyright (c) 2002-2006 by Judd Vinet <jvinet@zeroflux.org>
*
* This program is free software; you can redistribute it and/or modify
diff --git a/lib/libalpm/be_files.c b/lib/libalpm/be_files.c
deleted file mode 100644
index 0ee8a3bb..00000000
--- a/lib/libalpm/be_files.c
+++ /dev/null
@@ -1,977 +0,0 @@
-/*
- * be_files.c
- *
- * Copyright (c) 2006 by Christian Hamar <krics@linuxforum.hu>
- * Copyright (c) 2006 by Miklos Vajna <vmiklos@frugalware.org>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- */
-
-#include "config.h"
-
-#include <unistd.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <errno.h>
-#include <string.h>
-#include <stdint.h> /* intmax_t */
-#include <sys/stat.h>
-#include <dirent.h>
-#include <ctype.h>
-#include <time.h>
-#include <limits.h> /* PATH_MAX */
-#include <locale.h> /* setlocale */
-
-/* libarchive */
-#include <archive.h>
-#include <archive_entry.h>
-
-/* libalpm */
-#include "db.h"
-#include "alpm_list.h"
-#include "cache.h"
-#include "log.h"
-#include "util.h"
-#include "alpm.h"
-#include "handle.h"
-#include "package.h"
-#include "delta.h"
-#include "deps.h"
-#include "dload.h"
-
-
-static int checkdbdir(pmdb_t *db)
-{
- struct stat buf;
- const char *path = _alpm_db_path(db);
-
- if(stat(path, &buf) != 0) {
- _alpm_log(PM_LOG_DEBUG, "database dir '%s' does not exist, creating it\n",
- path);
- if(_alpm_makepath(path) != 0) {
- RET_ERR(PM_ERR_SYSTEM, -1);
- }
- } else if(!S_ISDIR(buf.st_mode)) {
- _alpm_log(PM_LOG_WARNING, _("removing invalid database: %s\n"), path);
- if(unlink(path) != 0 || _alpm_makepath(path) != 0) {
- RET_ERR(PM_ERR_SYSTEM, -1);
- }
- }
- return(0);
-}
-
-/* create list of directories in db */
-static int dirlist_from_tar(const char *archive, alpm_list_t **dirlist)
-{
- struct archive *_archive;
- struct archive_entry *entry;
-
- if((_archive = archive_read_new()) == NULL)
- RET_ERR(PM_ERR_LIBARCHIVE, -1);
-
- archive_read_support_compression_all(_archive);
- archive_read_support_format_all(_archive);
-
- if(archive_read_open_filename(_archive, archive,
- ARCHIVE_DEFAULT_BYTES_PER_BLOCK) != ARCHIVE_OK) {
- _alpm_log(PM_LOG_ERROR, _("could not open %s: %s\n"), archive,
- archive_error_string(_archive));
- RET_ERR(PM_ERR_PKG_OPEN, -1);
- }
-
- while(archive_read_next_header(_archive, &entry) == ARCHIVE_OK) {
- const struct stat *st;
- const char *entryname; /* the name of the file in the archive */
-
- st = archive_entry_stat(entry);
- entryname = archive_entry_pathname(entry);
-
- if(S_ISDIR(st->st_mode)) {
- char *name = strdup(entryname);
- *dirlist = alpm_list_add(*dirlist, name);
- }
- }
- archive_read_finish(_archive);
-
- *dirlist = alpm_list_msort(*dirlist, alpm_list_count(*dirlist), _alpm_str_cmp);
- return(0);
-}
-
-/* create list of directories in db */
-static int dirlist_from_fs(const char *syncdbpath, alpm_list_t **dirlist)
-{
- DIR *dbdir;
- struct dirent *ent = NULL;
- struct stat sbuf;
- char path[PATH_MAX];
-
- dbdir = opendir(syncdbpath);
- if (dbdir != NULL) {
- while((ent = readdir(dbdir)) != NULL) {
- char *name = ent->d_name;
- size_t len;
- char *entry;
-
- if(strcmp(name, ".") == 0 || strcmp(name, "..") == 0) {
- continue;
- }
-
- /* stat the entry, make sure it's a directory */
- snprintf(path, PATH_MAX, "%s%s", syncdbpath, name);
- if(stat(path, &sbuf) != 0 || !S_ISDIR(sbuf.st_mode)) {
- continue;
- }
-
- len = strlen(name);
- MALLOC(entry, len + 2, RET_ERR(PM_ERR_MEMORY, -1));
- strcpy(entry, name);
- entry[len] = '/';
- entry[len+1] = '\0';
- *dirlist = alpm_list_add(*dirlist, entry);
- }
- closedir(dbdir);
- }
-
- *dirlist = alpm_list_msort(*dirlist, alpm_list_count(*dirlist), _alpm_str_cmp);
- return(0);
-}
-
-/* remove old directories from dbdir */
-static int remove_olddir(const char *syncdbpath, alpm_list_t *dirlist)
-{
- alpm_list_t *i;
- for (i = dirlist; i; i = i->next) {
- const char *name = i->data;
- char *dbdir;
- size_t len = strlen(syncdbpath) + strlen(name) + 2;
- MALLOC(dbdir, len, RET_ERR(PM_ERR_MEMORY, -1));
- snprintf(dbdir, len, "%s%s", syncdbpath, name);
- _alpm_log(PM_LOG_DEBUG, "removing: %s\n", dbdir);
- if(_alpm_rmrf(dbdir) != 0) {
- _alpm_log(PM_LOG_ERROR, _("could not remove database directory %s\n"), dbdir);
- free(dbdir);
- RET_ERR(PM_ERR_DB_REMOVE, -1);
- }
- free(dbdir);
- }
- return(0);
-}
-
-/** Update a package database
- *
- * An update of the package database \a db will be attempted. Unless
- * \a force is true, the update will only be performed if the remote
- * database was modified since the last update.
- *
- * A transaction is necessary for this operation, in order to obtain a
- * database lock. During this transaction the front-end will be informed
- * of the download progress of the database via the download callback.
- *
- * Example:
- * @code
- * pmdb_t *db;
- * int result;
- * db = alpm_list_getdata(alpm_option_get_syncdbs());
- * if(alpm_trans_init(0, NULL, NULL, NULL) == 0) {
- * result = alpm_db_update(0, db);
- * alpm_trans_release();
- *
- * if(result > 0) {
- * printf("Unable to update database: %s\n", alpm_strerrorlast());
- * } else if(result < 0) {
- * printf("Database already up to date\n");
- * } else {
- * printf("Database updated\n");
- * }
- * }
- * @endcode
- *
- * @ingroup alpm_databases
- * @note After a successful update, the \link alpm_db_get_pkgcache()
- * package cache \endlink will be invalidated
- * @param force if true, then forces the update, otherwise update only in case
- * the database isn't up to date
- * @param db pointer to the package database to update
- * @return 0 on success, > 0 on error (pm_errno is set accordingly), < 0 if up
- * to date
- */
-int SYMEXPORT alpm_db_update(int force, pmdb_t *db)
-{
- char *dbfile, *dbfilepath;
- const char *dbpath, *syncdbpath;
- alpm_list_t *newdirlist = NULL, *olddirlist = NULL;
- alpm_list_t *onlynew = NULL, *onlyold = NULL;
- size_t len;
- int ret;
-
- ALPM_LOG_FUNC;
-
- /* Sanity checks */
- ASSERT(handle != NULL, RET_ERR(PM_ERR_HANDLE_NULL, -1));
- ASSERT(db != NULL && db != handle->db_local, RET_ERR(PM_ERR_WRONG_ARGS, -1));
- /* Verify we are in a transaction. This is done _mainly_ because we need a DB
- * lock - if we update without a db lock, we may kludge some other pacman
- * process that _has_ a lock.
- */
- ASSERT(handle->trans != NULL, RET_ERR(PM_ERR_TRANS_NULL, -1));
- ASSERT(handle->trans->state == STATE_INITIALIZED, RET_ERR(PM_ERR_TRANS_NOT_INITIALIZED, -1));
-
- if(!alpm_list_find_ptr(handle->dbs_sync, db)) {
- RET_ERR(PM_ERR_DB_NOT_FOUND, -1);
- }
-
- len = strlen(db->treename) + strlen(DBEXT) + 1;
- MALLOC(dbfile, len, RET_ERR(PM_ERR_MEMORY, -1));
- sprintf(dbfile, "%s" DBEXT, db->treename);
-
- dbpath = alpm_option_get_dbpath();
-
- ret = _alpm_download_single_file(dbfile, db->servers, dbpath, force);
- free(dbfile);
-
- if(ret == 1) {
- /* files match, do nothing */
- pm_errno = 0;
- return(1);
- } else if(ret == -1) {
- /* pm_errno was set by the download code */
- _alpm_log(PM_LOG_DEBUG, "failed to sync db: %s\n", alpm_strerrorlast());
- return(-1);
- }
-
- syncdbpath = _alpm_db_path(db);
-
- /* form the path to the db location */
- len = strlen(dbpath) + strlen(db->treename) + strlen(DBEXT) + 1;
- MALLOC(dbfilepath, len, RET_ERR(PM_ERR_MEMORY, -1));
- sprintf(dbfilepath, "%s%s" DBEXT, dbpath, db->treename);
-
- if(force) {
- /* if forcing update, remove the old dir and extract the db */
- if(_alpm_rmrf(syncdbpath) != 0) {
- _alpm_log(PM_LOG_ERROR, _("could not remove database %s\n"), db->treename);
- RET_ERR(PM_ERR_DB_REMOVE, -1);
- } else {
- _alpm_log(PM_LOG_DEBUG, "database dir %s removed\n", _alpm_db_path(db));
- }
- } else {
- /* if not forcing, only remove and extract what is necessary */
- ret = dirlist_from_tar(dbfilepath, &newdirlist);
- if(ret) {
- goto cleanup;
- }
- ret = dirlist_from_fs(syncdbpath, &olddirlist);
- if(ret) {
- goto cleanup;
- }
-
- alpm_list_diff_sorted(olddirlist, newdirlist, _alpm_str_cmp, &onlyold, &onlynew);
-
- ret = remove_olddir(syncdbpath, onlyold);
- if(ret) {
- goto cleanup;
- }
- }
-
- /* Cache needs to be rebuilt */
- _alpm_db_free_pkgcache(db);
-
- checkdbdir(db);
- ret = _alpm_unpack(dbfilepath, syncdbpath, onlynew, 0);
-
-cleanup:
- FREELIST(newdirlist);
- FREELIST(olddirlist);
- alpm_list_free(onlynew);
- alpm_list_free(onlyold);
-
- free(dbfilepath);
-
- if(ret) {
- RET_ERR(PM_ERR_SYSTEM, -1);
- }
-
- return(0);
-}
-
-
-static int splitname(const char *target, pmpkg_t *pkg)
-{
- /* the format of a db entry is as follows:
- * package-version-rel/
- * package name can contain hyphens, so parse from the back- go back
- * two hyphens and we have split the version from the name.
- */
- char *tmp, *p, *q;
-
- if(target == NULL || pkg == NULL) {
- return(-1);
- }
- STRDUP(tmp, target, RET_ERR(PM_ERR_MEMORY, -1));
- p = tmp + strlen(tmp);
-
- /* do the magic parsing- find the beginning of the version string
- * by doing two iterations of same loop to lop off two hyphens */
- for(q = --p; *q && *q != '-'; q--);
- for(p = --q; *p && *p != '-'; p--);
- if(*p != '-' || p == tmp) {
- return(-1);
- }
-
- /* copy into fields and return */
- if(pkg->version) {
- FREE(pkg->version);
- }
- STRDUP(pkg->version, p+1, RET_ERR(PM_ERR_MEMORY, -1));
- /* insert a terminator at the end of the name (on hyphen)- then copy it */
- *p = '\0';
- if(pkg->name) {
- FREE(pkg->name);
- }
- STRDUP(pkg->name, tmp, RET_ERR(PM_ERR_MEMORY, -1));
-
- free(tmp);
- return(0);
-}
-
-int _alpm_db_populate(pmdb_t *db)
-{
- int count = 0;
- struct dirent *ent = NULL;
- struct stat sbuf;
- char path[PATH_MAX];
- const char *dbpath;
- DIR *dbdir;
-
- ALPM_LOG_FUNC;
-
- ASSERT(db != NULL, RET_ERR(PM_ERR_DB_NULL, -1));
-
- dbpath = _alpm_db_path(db);
- dbdir = opendir(dbpath);
- if(dbdir == NULL) {
- return(0);
- }
- while((ent = readdir(dbdir)) != NULL) {
- const char *name = ent->d_name;
- pmpkg_t *pkg;
-
- if(strcmp(name, ".") == 0 || strcmp(name, "..") == 0) {
- continue;
- }
- /* stat the entry, make sure it's a directory */
- snprintf(path, PATH_MAX, "%s%s", dbpath, name);
- if(stat(path, &sbuf) != 0 || !S_ISDIR(sbuf.st_mode)) {
- continue;
- }
-
- pkg = _alpm_pkg_new();
- if(pkg == NULL) {
- closedir(dbdir);
- return(-1);
- }
- /* split the db entry name */
- if(splitname(name, pkg) != 0) {
- _alpm_log(PM_LOG_ERROR, _("invalid name for database entry '%s'\n"),
- name);
- _alpm_pkg_free(pkg);
- continue;
- }
-
- /* duplicated database entries are not allowed */
- if(_alpm_pkg_find(db->pkgcache, pkg->name)) {
- _alpm_log(PM_LOG_ERROR, _("duplicated database entry '%s'\n"), pkg->name);
- _alpm_pkg_free(pkg);
- continue;
- }
-
- pkg->origin = PKG_FROM_CACHE;
- pkg->origin_data.db = db;
-
- /* explicitly read with only 'BASE' data, accessors will handle the rest */
- if(_alpm_db_read(db, pkg, INFRQ_BASE) == -1) {
- _alpm_log(PM_LOG_ERROR, _("corrupted database entry '%s'\n"), name);
- _alpm_pkg_free(pkg);
- continue;
- }
-
- /* add to the collection */
- _alpm_log(PM_LOG_FUNCTION, "adding '%s' to package cache for db '%s'\n",
- pkg->name, db->treename);
- db->pkgcache = alpm_list_add(db->pkgcache, pkg);
- count++;
- }
-
- closedir(dbdir);
- db->pkgcache = alpm_list_msort(db->pkgcache, count, _alpm_pkg_cmp);
- return(count);
-}
-
-/* Note: the return value must be freed by the caller */
-static char *get_pkgpath(pmdb_t *db, pmpkg_t *info)
-{
- size_t len;
- char *pkgpath;
- const char *dbpath;
-
- dbpath = _alpm_db_path(db);
- len = strlen(dbpath) + strlen(info->name) + strlen(info->version) + 3;
- MALLOC(pkgpath, len, RET_ERR(PM_ERR_MEMORY, NULL));
- sprintf(pkgpath, "%s%s-%s/", dbpath, info->name, info->version);
- return(pkgpath);
-}
-
-int _alpm_db_read(pmdb_t *db, pmpkg_t *info, pmdbinfrq_t inforeq)
-{
- FILE *fp = NULL;
- char path[PATH_MAX];
- char line[513];
- int sline = sizeof(line)-1;
- char *pkgpath = NULL;
-
- ALPM_LOG_FUNC;
-
- if(db == NULL) {
- RET_ERR(PM_ERR_DB_NULL, -1);
- }
-
- if(info == NULL || info->name == NULL || info->version == NULL) {
- _alpm_log(PM_LOG_DEBUG, "invalid package entry provided to _alpm_db_read, skipping\n");
- return(-1);
- }
-
- if(info->origin == PKG_FROM_FILE) {
- _alpm_log(PM_LOG_DEBUG, "request to read database info for a file-based package '%s', skipping...\n", info->name);
- return(-1);
- }
-
- /* bitmask logic here:
- * infolevel: 00001111
- * inforeq: 00010100
- * & result: 00000100
- * == to inforeq? nope, we need to load more info. */
- if((info->infolevel & inforeq) == inforeq) {
- /* already loaded all of this info, do nothing */
- return(0);
- }
- _alpm_log(PM_LOG_FUNCTION, "loading package data for %s : level=0x%x\n",
- info->name, inforeq);
-
- /* clear out 'line', to be certain - and to make valgrind happy */
- memset(line, 0, sline+1);
-
- pkgpath = get_pkgpath(db, info);
-
- if(access(pkgpath, F_OK)) {
- /* directory doesn't exist or can't be opened */
- _alpm_log(PM_LOG_DEBUG, "cannot find '%s-%s' in db '%s'\n",
- info->name, info->version, db->treename);
- goto error;
- }
-
- /* DESC */
- if(inforeq & INFRQ_DESC && !(info->infolevel & INFRQ_DESC)) {
- snprintf(path, PATH_MAX, "%sdesc", pkgpath);
- if((fp = fopen(path, "r")) == NULL) {
- _alpm_log(PM_LOG_ERROR, _("could not open file %s: %s\n"), path, strerror(errno));
- goto error;
- }
- while(!feof(fp)) {
- if(fgets(line, 256, fp) == NULL) {
- break;
- }
- _alpm_strtrim(line);
- if(strcmp(line, "%NAME%") == 0) {
- if(fgets(line, sline, fp) == NULL) {
- goto error;
- }
- if(strcmp(_alpm_strtrim(line), info->name) != 0) {
- _alpm_log(PM_LOG_ERROR, _("%s database is inconsistent: name "
- "mismatch on package %s\n"), db->treename, info->name);
- }
- } else if(strcmp(line, "%VERSION%") == 0) {
- if(fgets(line, sline, fp) == NULL) {
- goto error;
- }
- if(strcmp(_alpm_strtrim(line), info->version) != 0) {
- _alpm_log(PM_LOG_ERROR, _("%s database is inconsistent: version "
- "mismatch on package %s\n"), db->treename, info->name);
- }
- } else if(strcmp(line, "%FILENAME%") == 0) {
- if(fgets(line, sline, fp) == NULL) {
- goto error;
- }
- STRDUP(info->filename, _alpm_strtrim(line), goto error);
- } else if(strcmp(line, "%DESC%") == 0) {
- if(fgets(line, sline, fp) == NULL) {
- goto error;
- }
- STRDUP(info->desc, _alpm_strtrim(line), goto error);
- } else if(strcmp(line, "%GROUPS%") == 0) {
- while(fgets(line, sline, fp) && strlen(_alpm_strtrim(line))) {
- char *linedup;
- STRDUP(linedup, _alpm_strtrim(line), goto error);
- info->groups = alpm_list_add(info->groups, linedup);
- }
- } else if(strcmp(line, "%URL%") == 0) {
- if(fgets(line, sline, fp) == NULL) {
- goto error;
- }
- STRDUP(info->url, _alpm_strtrim(line), goto error);
- } else if(strcmp(line, "%LICENSE%") == 0) {
- while(fgets(line, sline, fp) && strlen(_alpm_strtrim(line))) {
- char *linedup;
- STRDUP(linedup, _alpm_strtrim(line), goto error);
- info->licenses = alpm_list_add(info->licenses, linedup);
- }
- } else if(strcmp(line, "%ARCH%") == 0) {
- if(fgets(line, sline, fp) == NULL) {
- goto error;
- }
- STRDUP(info->arch, _alpm_strtrim(line), goto error);
- } else if(strcmp(line, "%BUILDDATE%") == 0) {
- if(fgets(line, sline, fp) == NULL) {
- goto error;
- }
- _alpm_strtrim(line);
-
- char first = tolower((unsigned char)line[0]);
- if(first > 'a' && first < 'z') {
- struct tm tmp_tm = {0}; /* initialize to null in case of failure */
- setlocale(LC_TIME, "C");
- strptime(line, "%a %b %e %H:%M:%S %Y", &tmp_tm);
- info->builddate = mktime(&tmp_tm);
- setlocale(LC_TIME, "");
- } else {
- info->builddate = atol(line);
- }
- } else if(strcmp(line, "%INSTALLDATE%") == 0) {
- if(fgets(line, sline, fp) == NULL) {
- goto error;
- }
- _alpm_strtrim(line);
-
- char first = tolower((unsigned char)line[0]);
- if(first > 'a' && first < 'z') {
- struct tm tmp_tm = {0}; /* initialize to null in case of failure */
- setlocale(LC_TIME, "C");
- strptime(line, "%a %b %e %H:%M:%S %Y", &tmp_tm);
- info->installdate = mktime(&tmp_tm);
- setlocale(LC_TIME, "");
- } else {
- info->installdate = atol(line);
- }
- } else if(strcmp(line, "%PACKAGER%") == 0) {
- if(fgets(line, sline, fp) == NULL) {
- goto error;
- }
- STRDUP(info->packager, _alpm_strtrim(line), goto error);
- } else if(strcmp(line, "%REASON%") == 0) {
- if(fgets(line, sline, fp) == NULL) {
- goto error;
- }
- info->reason = (pmpkgreason_t)atol(_alpm_strtrim(line));
- } else if(strcmp(line, "%SIZE%") == 0 || strcmp(line, "%CSIZE%") == 0) {
- /* NOTE: the CSIZE and SIZE fields both share the "size" field
- * in the pkginfo_t struct. This can be done b/c CSIZE
- * is currently only used in sync databases, and SIZE is
- * only used in local databases.
- */
- if(fgets(line, sline, fp) == NULL) {
- goto error;
- }
- info->size = atol(_alpm_strtrim(line));
- /* also store this value to isize if isize is unset */
- if(info->isize == 0) {
- info->isize = info->size;
- }
- } else if(strcmp(line, "%ISIZE%") == 0) {
- /* ISIZE (installed size) tag only appears in sync repositories,
- * not the local one. */
- if(fgets(line, sline, fp) == NULL) {
- goto error;
- }
- info->isize = atol(_alpm_strtrim(line));
- } else if(strcmp(line, "%MD5SUM%") == 0) {
- /* MD5SUM tag only appears in sync repositories,
- * not the local one. */
- if(fgets(line, sline, fp) == NULL) {
- goto error;
- }
- STRDUP(info->md5sum, _alpm_strtrim(line), goto error);
- } else if(strcmp(line, "%REPLACES%") == 0) {
- while(fgets(line, sline, fp) && strlen(_alpm_strtrim(line))) {
- char *linedup;
- STRDUP(linedup, _alpm_strtrim(line), goto error);
- info->replaces = alpm_list_add(info->replaces, linedup);
- }
- } else if(strcmp(line, "%FORCE%") == 0) {
- info->force = 1;
- }
- }
- fclose(fp);
- fp = NULL;
- }
-
- /* FILES */
- if(inforeq & INFRQ_FILES && !(info->infolevel & INFRQ_FILES)) {
- snprintf(path, PATH_MAX, "%sfiles", pkgpath);
- if((fp = fopen(path, "r")) == NULL) {
- _alpm_log(PM_LOG_ERROR, _("could not open file %s: %s\n"), path, strerror(errno));
- goto error;
- }
- while(fgets(line, 256, fp)) {
- _alpm_strtrim(line);
- if(strcmp(line, "%FILES%") == 0) {
- while(fgets(line, sline, fp) && strlen(_alpm_strtrim(line))) {
- char *linedup;
- STRDUP(linedup, _alpm_strtrim(line), goto error);
- info->files = alpm_list_add(info->files, linedup);
- }
- } else if(strcmp(line, "%BACKUP%") == 0) {
- while(fgets(line, sline, fp) && strlen(_alpm_strtrim(line))) {
- char *linedup;
- STRDUP(linedup, _alpm_strtrim(line), goto error);
- info->backup = alpm_list_add(info->backup, linedup);
- }
- }
- }
- fclose(fp);
- fp = NULL;
- }
-
- /* DEPENDS */
- if(inforeq & INFRQ_DEPENDS && !(info->infolevel & INFRQ_DEPENDS)) {
- snprintf(path, PATH_MAX, "%sdepends", pkgpath);
- if((fp = fopen(path, "r")) == NULL) {
- _alpm_log(PM_LOG_ERROR, _("could not open file %s: %s\n"), path, strerror(errno));
- goto error;
- }
- while(!feof(fp)) {
- fgets(line, 255, fp);
- _alpm_strtrim(line);
- if(strcmp(line, "%DEPENDS%") == 0) {
- while(fgets(line, sline, fp) && strlen(_alpm_strtrim(line))) {
- pmdepend_t *dep = _alpm_splitdep(_alpm_strtrim(line));
- info->depends = alpm_list_add(info->depends, dep);
- }
- } else if(strcmp(line, "%OPTDEPENDS%") == 0) {
- while(fgets(line, sline, fp) && strlen(_alpm_strtrim(line))) {
- char *linedup;
- STRDUP(linedup, _alpm_strtrim(line), goto error);
- info->optdepends = alpm_list_add(info->optdepends, linedup);
- }
- } else if(strcmp(line, "%CONFLICTS%") == 0) {
- while(fgets(line, sline, fp) && strlen(_alpm_strtrim(line))) {
- char *linedup;
- STRDUP(linedup, _alpm_strtrim(line), goto error);
- info->conflicts = alpm_list_add(info->conflicts, linedup);
- }
- } else if(strcmp(line, "%PROVIDES%") == 0) {
- while(fgets(line, sline, fp) && strlen(_alpm_strtrim(line))) {
- char *linedup;
- STRDUP(linedup, _alpm_strtrim(line), goto error);
- info->provides = alpm_list_add(info->provides, linedup);
- }
- }
- }
- fclose(fp);
- fp = NULL;
- }
-
- /* DELTAS */
- if(inforeq & INFRQ_DELTAS && !(info->infolevel & INFRQ_DELTAS)) {
- snprintf(path, PATH_MAX, "%sdeltas", pkgpath);
- if((fp = fopen(path, "r"))) {
- while(!feof(fp)) {
- fgets(line, 255, fp);
- _alpm_strtrim(line);
- if(strcmp(line, "%DELTAS%") == 0) {
- while(fgets(line, sline, fp) && strlen(_alpm_strtrim(line))) {
- pmdelta_t *delta = _alpm_delta_parse(line);
- if(delta) {
- info->deltas = alpm_list_add(info->deltas, delta);
- }
- }
- }
- }
- fclose(fp);
- fp = NULL;
- }
- }
-
- /* INSTALL */
- if(inforeq & INFRQ_SCRIPTLET && !(info->infolevel & INFRQ_SCRIPTLET)) {
- snprintf(path, PATH_MAX, "%sinstall", pkgpath);
- if(access(path, F_OK) == 0) {
- info->scriptlet = 1;
- }
- }
-
- /* internal */
- info->infolevel |= inforeq;
-
- free(pkgpath);
- return(0);
-
-error:
- free(pkgpath);
- if(fp) {
- fclose(fp);
- }
- return(-1);
-}
-
-int _alpm_db_prepare(pmdb_t *db, pmpkg_t *info)
-{
- mode_t oldmask;
- int retval = 0;
- char *pkgpath = NULL;
-
- if(checkdbdir(db) != 0) {
- return(-1);
- }
-
- oldmask = umask(0000);
- pkgpath = get_pkgpath(db, info);
-
- if((retval = mkdir(pkgpath, 0755)) != 0) {
- _alpm_log(PM_LOG_ERROR, _("could not create directory %s: %s\n"),
- pkgpath, strerror(errno));
- }
-
- free(pkgpath);
- umask(oldmask);
-
- return(retval);
-}
-
-int _alpm_db_write(pmdb_t *db, pmpkg_t *info, pmdbinfrq_t inforeq)
-{
- FILE *fp = NULL;
- char path[PATH_MAX];
- mode_t oldmask;
- alpm_list_t *lp = NULL;
- int retval = 0;
- int local = 0;
- char *pkgpath = NULL;
-
- ALPM_LOG_FUNC;
-
- if(db == NULL || info == NULL) {
- return(-1);
- }
-
- pkgpath = get_pkgpath(db, info);
-
- /* make sure we have a sane umask */
- oldmask = umask(0022);
-
- if(strcmp(db->treename, "local") == 0) {
- local = 1;
- }
-
- /* DESC */
- if(inforeq & INFRQ_DESC) {
- _alpm_log(PM_LOG_DEBUG, "writing %s-%s DESC information back to db\n",
- info->name, info->version);
- snprintf(path, PATH_MAX, "%sdesc", pkgpath);
- if((fp = fopen(path, "w")) == NULL) {
- _alpm_log(PM_LOG_ERROR, _("could not open file %s: %s\n"), path, strerror(errno));
- retval = -1;
- goto cleanup;
- }
- fprintf(fp, "%%NAME%%\n%s\n\n"
- "%%VERSION%%\n%s\n\n", info->name, info->version);
- if(info->desc) {
- fprintf(fp, "%%DESC%%\n"
- "%s\n\n", info->desc);
- }
- if(info->groups) {
- fputs("%GROUPS%\n", fp);
- for(lp = info->groups; lp; lp = lp->next) {
- fprintf(fp, "%s\n", (char *)lp->data);
- }
- fprintf(fp, "\n");
- }
- if(info->replaces) {
- fputs("%REPLACES%\n", fp);
- for(lp = info->replaces; lp; lp = lp->next) {
- fprintf(fp, "%s\n", (char *)lp->data);
- }
- fprintf(fp, "\n");
- }
- if(local) {
- if(info->url) {
- fprintf(fp, "%%URL%%\n"
- "%s\n\n", info->url);
- }
- if(info->licenses) {
- fputs("%LICENSE%\n", fp);
- for(lp = info->licenses; lp; lp = lp->next) {
- fprintf(fp, "%s\n", (char *)lp->data);
- }
- fprintf(fp, "\n");
- }
- if(info->arch) {
- fprintf(fp, "%%ARCH%%\n"
- "%s\n\n", info->arch);
- }
- if(info->builddate) {
- fprintf(fp, "%%BUILDDATE%%\n"
- "%ld\n\n", info->builddate);
- }
- if(info->installdate) {
- fprintf(fp, "%%INSTALLDATE%%\n"
- "%ld\n\n", info->installdate);
- }
- if(info->packager) {
- fprintf(fp, "%%PACKAGER%%\n"
- "%s\n\n", info->packager);
- }
- if(info->isize) {
- /* only write installed size, csize is irrelevant once installed */
- fprintf(fp, "%%SIZE%%\n"
- "%jd\n\n", (intmax_t)info->isize);
- }
- if(info->reason) {
- fprintf(fp, "%%REASON%%\n"
- "%u\n\n", info->reason);
- }
- } else {
- if(info->size) {
- fprintf(fp, "%%CSIZE%%\n"
- "%jd\n\n", (intmax_t)info->size);
- }
- if(info->isize) {
- fprintf(fp, "%%ISIZE%%\n"
- "%jd\n\n", (intmax_t)info->isize);
- }
- if(info->md5sum) {
- fprintf(fp, "%%MD5SUM%%\n"
- "%s\n\n", info->md5sum);
- }
- }
- fclose(fp);
- fp = NULL;
- }
-
- /* FILES */
- if(local && (inforeq & INFRQ_FILES)) {
- _alpm_log(PM_LOG_DEBUG, "writing %s-%s FILES information back to db\n",
- info->name, info->version);
- snprintf(path, PATH_MAX, "%sfiles", pkgpath);
- if((fp = fopen(path, "w")) == NULL) {
- _alpm_log(PM_LOG_ERROR, _("could not open file %s: %s\n"), path, strerror(errno));
- retval = -1;
- goto cleanup;
- }
- if(info->files) {
- fprintf(fp, "%%FILES%%\n");
- for(lp = info->files; lp; lp = lp->next) {
- fprintf(fp, "%s\n", (char *)lp->data);
- }
- fprintf(fp, "\n");
- }
- if(info->backup) {
- fprintf(fp, "%%BACKUP%%\n");
- for(lp = info->backup; lp; lp = lp->next) {
- fprintf(fp, "%s\n", (char *)lp->data);
- }
- fprintf(fp, "\n");
- }
- fclose(fp);
- fp = NULL;
- }
-
- /* DEPENDS */
- if(inforeq & INFRQ_DEPENDS) {
- _alpm_log(PM_LOG_DEBUG, "writing %s-%s DEPENDS information back to db\n",
- info->name, info->version);
- snprintf(path, PATH_MAX, "%sdepends", pkgpath);
- if((fp = fopen(path, "w")) == NULL) {
- _alpm_log(PM_LOG_ERROR, _("could not open file %s: %s\n"), path, strerror(errno));
- retval = -1;
- goto cleanup;
- }
- if(info->depends) {
- fputs("%DEPENDS%\n", fp);
- for(lp = info->depends; lp; lp = lp->next) {
- char *depstring = alpm_dep_compute_string(lp->data);
- fprintf(fp, "%s\n", depstring);
- free(depstring);
- }
- fprintf(fp, "\n");
- }
- if(info->optdepends) {
- fputs("%OPTDEPENDS%\n", fp);
- for(lp = info->optdepends; lp; lp = lp->next) {
- fprintf(fp, "%s\n", (char *)lp->data);
- }
- fprintf(fp, "\n");
- }
- if(info->conflicts) {
- fputs("%CONFLICTS%\n", fp);
- for(lp = info->conflicts; lp; lp = lp->next) {
- fprintf(fp, "%s\n", (char *)lp->data);
- }
- fprintf(fp, "\n");
- }
- if(info->provides) {
- fputs("%PROVIDES%\n", fp);
- for(lp = info->provides; lp; lp = lp->next) {
- fprintf(fp, "%s\n", (char *)lp->data);
- }
- fprintf(fp, "\n");
- }
- fclose(fp);
- fp = NULL;
- }
-
- /* INSTALL */
- /* nothing needed here (script is automatically extracted) */
-
-cleanup:
- umask(oldmask);
- free(pkgpath);
-
- if(fp) {
- fclose(fp);
- }
-
- return(retval);
-}
-
-int _alpm_db_remove(pmdb_t *db, pmpkg_t *info)
-{
- int ret = 0;
- char *pkgpath = NULL;
-
- ALPM_LOG_FUNC;
-
- if(db == NULL || info == NULL) {
- RET_ERR(PM_ERR_DB_NULL, -1);
- }
-
- pkgpath = get_pkgpath(db, info);
-
- ret = _alpm_rmrf(pkgpath);
- free(pkgpath);
- if(ret != 0) {
- ret = -1;
- }
- return(ret);
-}
-
-/* vim: set ts=2 sw=2 noet: */
diff --git a/lib/libalpm/be_local.c b/lib/libalpm/be_local.c
new file mode 100644
index 00000000..ea59ceca
--- /dev/null
+++ b/lib/libalpm/be_local.c
@@ -0,0 +1,921 @@
+/*
+ * be_local.c
+ *
+ * Copyright (c) 2006-2011 Pacman Development Team <pacman-dev@archlinux.org>
+ * Copyright (c) 2002-2006 by Judd Vinet <jvinet@zeroflux.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "config.h"
+
+#include <unistd.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <errno.h>
+#include <string.h>
+#include <stdint.h> /* intmax_t */
+#include <sys/stat.h>
+#include <dirent.h>
+#include <time.h>
+#include <limits.h> /* PATH_MAX */
+#include <locale.h> /* setlocale */
+
+/* libarchive */
+#include <archive.h>
+#include <archive_entry.h>
+
+/* libalpm */
+#include "db.h"
+#include "alpm_list.h"
+#include "log.h"
+#include "util.h"
+#include "alpm.h"
+#include "handle.h"
+#include "package.h"
+#include "group.h"
+#include "deps.h"
+#include "dload.h"
+
+
+#define LAZY_LOAD(info, errret) \
+ do { \
+ ALPM_LOG_FUNC; \
+ ASSERT(handle != NULL, return(errret)); \
+ ASSERT(pkg != NULL, return(errret)); \
+ if(pkg->origin != PKG_FROM_FILE && !(pkg->infolevel & info)) { \
+ _alpm_local_db_read(pkg->origin_data.db, pkg, info); \
+ } \
+ } while(0)
+
+
+/* Cache-specific accessor functions. These implementations allow for lazy
+ * loading by the files backend when a data member is actually needed
+ * rather than loading all pieces of information when the package is first
+ * initialized.
+ */
+
+static const char *_cache_get_filename(pmpkg_t *pkg)
+{
+ LAZY_LOAD(INFRQ_DESC, NULL);
+ return pkg->filename;
+}
+
+static const char *_cache_get_name(pmpkg_t *pkg)
+{
+ ASSERT(pkg != NULL, return(NULL));
+ return pkg->name;
+}
+
+static const char *_cache_get_version(pmpkg_t *pkg)
+{
+ ASSERT(pkg != NULL, return(NULL));
+ return pkg->version;
+}
+
+static const char *_cache_get_desc(pmpkg_t *pkg)
+{
+ LAZY_LOAD(INFRQ_DESC, NULL);
+ return pkg->desc;
+}
+
+static const char *_cache_get_url(pmpkg_t *pkg)
+{
+ LAZY_LOAD(INFRQ_DESC, NULL);
+ return pkg->url;
+}
+
+static time_t _cache_get_builddate(pmpkg_t *pkg)
+{
+ LAZY_LOAD(INFRQ_DESC, 0);
+ return pkg->builddate;
+}
+
+static time_t _cache_get_installdate(pmpkg_t *pkg)
+{
+ LAZY_LOAD(INFRQ_DESC, 0);
+ return pkg->installdate;
+}
+
+static const char *_cache_get_packager(pmpkg_t *pkg)
+{
+ LAZY_LOAD(INFRQ_DESC, NULL);
+ return pkg->packager;
+}
+
+static const char *_cache_get_md5sum(pmpkg_t *pkg)
+{
+ LAZY_LOAD(INFRQ_DESC, NULL);
+ return pkg->md5sum;
+}
+
+static const char *_cache_get_arch(pmpkg_t *pkg)
+{
+ LAZY_LOAD(INFRQ_DESC, NULL);
+ return pkg->arch;
+}
+
+static off_t _cache_get_size(pmpkg_t *pkg)
+{
+ LAZY_LOAD(INFRQ_DESC, -1);
+ return pkg->size;
+}
+
+static off_t _cache_get_isize(pmpkg_t *pkg)
+{
+ LAZY_LOAD(INFRQ_DESC, -1);
+ return pkg->isize;
+}
+
+static pmpkgreason_t _cache_get_reason(pmpkg_t *pkg)
+{
+ LAZY_LOAD(INFRQ_DESC, -1);
+ return pkg->reason;
+}
+
+static alpm_list_t *_cache_get_licenses(pmpkg_t *pkg)
+{
+ LAZY_LOAD(INFRQ_DESC, NULL);
+ return pkg->licenses;
+}
+
+static alpm_list_t *_cache_get_groups(pmpkg_t *pkg)
+{
+ LAZY_LOAD(INFRQ_DESC, NULL);
+ return pkg->groups;
+}
+
+static int _cache_has_scriptlet(pmpkg_t *pkg)
+{
+ ALPM_LOG_FUNC;
+
+ /* Sanity checks */
+ ASSERT(handle != NULL, return(-1));
+ ASSERT(pkg != NULL, return(-1));
+
+ if(!(pkg->infolevel & INFRQ_SCRIPTLET)) {
+ _alpm_local_db_read(pkg->origin_data.db, pkg, INFRQ_SCRIPTLET);
+ }
+ return pkg->scriptlet;
+}
+
+static alpm_list_t *_cache_get_depends(pmpkg_t *pkg)
+{
+ LAZY_LOAD(INFRQ_DESC, NULL);
+ return pkg->depends;
+}
+
+static alpm_list_t *_cache_get_optdepends(pmpkg_t *pkg)
+{
+ LAZY_LOAD(INFRQ_DESC, NULL);
+ return pkg->optdepends;
+}
+
+static alpm_list_t *_cache_get_conflicts(pmpkg_t *pkg)
+{
+ LAZY_LOAD(INFRQ_DESC, NULL);
+ return pkg->conflicts;
+}
+
+static alpm_list_t *_cache_get_provides(pmpkg_t *pkg)
+{
+ LAZY_LOAD(INFRQ_DESC, NULL);
+ return pkg->provides;
+}
+
+static alpm_list_t *_cache_get_replaces(pmpkg_t *pkg)
+{
+ LAZY_LOAD(INFRQ_DESC, NULL);
+ return pkg->replaces;
+}
+
+/* local packages can not have deltas */
+static alpm_list_t *_cache_get_deltas(pmpkg_t *pkg)
+{
+ return NULL;
+}
+
+static alpm_list_t *_cache_get_files(pmpkg_t *pkg)
+{
+ ALPM_LOG_FUNC;
+
+ /* Sanity checks */
+ ASSERT(handle != NULL, return(NULL));
+ ASSERT(pkg != NULL, return(NULL));
+
+ if(pkg->origin == PKG_FROM_LOCALDB
+ && !(pkg->infolevel & INFRQ_FILES)) {
+ _alpm_local_db_read(pkg->origin_data.db, pkg, INFRQ_FILES);
+ }
+ return pkg->files;
+}
+
+static alpm_list_t *_cache_get_backup(pmpkg_t *pkg)
+{
+ ALPM_LOG_FUNC;
+
+ /* Sanity checks */
+ ASSERT(handle != NULL, return(NULL));
+ ASSERT(pkg != NULL, return(NULL));
+
+ if(pkg->origin == PKG_FROM_LOCALDB
+ && !(pkg->infolevel & INFRQ_FILES)) {
+ _alpm_local_db_read(pkg->origin_data.db, pkg, INFRQ_FILES);
+ }
+ return pkg->backup;
+}
+
+/**
+ * Open a package changelog for reading. Similar to fopen in functionality,
+ * except that the returned 'file stream' is from the database.
+ * @param pkg the package (from db) to read the changelog
+ * @return a 'file stream' to the package changelog
+ */
+static void *_cache_changelog_open(pmpkg_t *pkg)
+{
+ ALPM_LOG_FUNC;
+
+ /* Sanity checks */
+ ASSERT(handle != NULL, return(NULL));
+ ASSERT(pkg != NULL, return(NULL));
+
+ char clfile[PATH_MAX];
+ snprintf(clfile, PATH_MAX, "%s/%s/%s-%s/changelog",
+ alpm_option_get_dbpath(),
+ alpm_db_get_name(alpm_pkg_get_db(pkg)),
+ alpm_pkg_get_name(pkg),
+ alpm_pkg_get_version(pkg));
+ return fopen(clfile, "r");
+}
+
+/**
+ * Read data from an open changelog 'file stream'. Similar to fread in
+ * functionality, this function takes a buffer and amount of data to read.
+ * @param ptr a buffer to fill with raw changelog data
+ * @param size the size of the buffer
+ * @param pkg the package that the changelog is being read from
+ * @param fp a 'file stream' to the package changelog
+ * @return the number of characters read, or 0 if there is no more data
+ */
+static size_t _cache_changelog_read(void *ptr, size_t size,
+ const pmpkg_t *pkg, const void *fp)
+{
+ return ( fread(ptr, 1, size, (FILE*)fp) );
+}
+
+/*
+static int _cache_changelog_feof(const pmpkg_t *pkg, void *fp)
+{
+ return( feof((FILE*)fp) );
+}
+*/
+
+/**
+ * Close a package changelog for reading. Similar to fclose in functionality,
+ * except that the 'file stream' is from the database.
+ * @param pkg the package that the changelog was read from
+ * @param fp a 'file stream' to the package changelog
+ * @return whether closing the package changelog stream was successful
+ */
+static int _cache_changelog_close(const pmpkg_t *pkg, void *fp)
+{
+ return( fclose((FILE*)fp) );
+}
+
+
+/** The local database operations struct. Get package fields through
+ * lazy accessor methods that handle any backend loading and caching
+ * logic.
+ */
+static struct pkg_operations local_pkg_ops = {
+ .get_filename = _cache_get_filename,
+ .get_name = _cache_get_name,
+ .get_version = _cache_get_version,
+ .get_desc = _cache_get_desc,
+ .get_url = _cache_get_url,
+ .get_builddate = _cache_get_builddate,
+ .get_installdate = _cache_get_installdate,
+ .get_packager = _cache_get_packager,
+ .get_md5sum = _cache_get_md5sum,
+ .get_arch = _cache_get_arch,
+ .get_size = _cache_get_size,
+ .get_isize = _cache_get_isize,
+ .get_reason = _cache_get_reason,
+ .has_scriptlet = _cache_has_scriptlet,
+ .get_licenses = _cache_get_licenses,
+ .get_groups = _cache_get_groups,
+ .get_depends = _cache_get_depends,
+ .get_optdepends = _cache_get_optdepends,
+ .get_conflicts = _cache_get_conflicts,
+ .get_provides = _cache_get_provides,
+ .get_replaces = _cache_get_replaces,
+ .get_deltas = _cache_get_deltas,
+ .get_files = _cache_get_files,
+ .get_backup = _cache_get_backup,
+
+ .changelog_open = _cache_changelog_open,
+ .changelog_read = _cache_changelog_read,
+ .changelog_close = _cache_changelog_close,
+};
+
+static int checkdbdir(pmdb_t *db)
+{
+ struct stat buf;
+ const char *path = _alpm_db_path(db);
+
+ if(stat(path, &buf) != 0) {
+ _alpm_log(PM_LOG_DEBUG, "database dir '%s' does not exist, creating it\n",
+ path);
+ if(_alpm_makepath(path) != 0) {
+ RET_ERR(PM_ERR_SYSTEM, -1);
+ }
+ } else if(!S_ISDIR(buf.st_mode)) {
+ _alpm_log(PM_LOG_WARNING, _("removing invalid database: %s\n"), path);
+ if(unlink(path) != 0 || _alpm_makepath(path) != 0) {
+ RET_ERR(PM_ERR_SYSTEM, -1);
+ }
+ }
+ return(0);
+}
+
+static int is_dir(const char *path, struct dirent *entry)
+{
+#ifdef HAVE_STRUCT_DIRENT_D_TYPE
+ return(entry->d_type == DT_DIR);
+#else
+ char buffer[PATH_MAX];
+ snprintf(buffer, PATH_MAX, "%s/%s", path, entry->d_name);
+
+ struct stat sbuf;
+ if (!stat(buffer, &sbuf)) {
+ return(S_ISDIR(sbuf.st_mode));
+ }
+
+ return(0);
+#endif
+}
+
+static int local_db_populate(pmdb_t *db)
+{
+ int count = 0;
+ struct dirent *ent = NULL;
+ const char *dbpath;
+ DIR *dbdir;
+
+ ALPM_LOG_FUNC;
+
+ ASSERT(db != NULL, RET_ERR(PM_ERR_DB_NULL, -1));
+
+ dbpath = _alpm_db_path(db);
+ if(dbpath == NULL) {
+ return(-1);
+ }
+ dbdir = opendir(dbpath);
+ if(dbdir == NULL) {
+ return(0);
+ }
+ while((ent = readdir(dbdir)) != NULL) {
+ const char *name = ent->d_name;
+
+ pmpkg_t *pkg;
+
+ if(strcmp(name, ".") == 0 || strcmp(name, "..") == 0) {
+ continue;
+ }
+ if(!is_dir(dbpath, ent)) {
+ continue;
+ }
+
+ pkg = _alpm_pkg_new();
+ if(pkg == NULL) {
+ closedir(dbdir);
+ return(-1);
+ }
+ /* split the db entry name */
+ if(_alpm_splitname(name, pkg) != 0) {
+ _alpm_log(PM_LOG_ERROR, _("invalid name for database entry '%s'\n"),
+ name);
+ _alpm_pkg_free(pkg);
+ continue;
+ }
+
+ /* duplicated database entries are not allowed */
+ if(_alpm_pkg_find(db->pkgcache, pkg->name)) {
+ _alpm_log(PM_LOG_ERROR, _("duplicated database entry '%s'\n"), pkg->name);
+ _alpm_pkg_free(pkg);
+ continue;
+ }
+
+ pkg->origin = PKG_FROM_LOCALDB;
+ pkg->origin_data.db = db;
+ pkg->ops = &local_pkg_ops;
+
+ /* explicitly read with only 'BASE' data, accessors will handle the rest */
+ if(_alpm_local_db_read(db, pkg, INFRQ_BASE) == -1) {
+ _alpm_log(PM_LOG_ERROR, _("corrupted database entry '%s'\n"), name);
+ _alpm_pkg_free(pkg);
+ continue;
+ }
+
+ /* add to the collection */
+ _alpm_log(PM_LOG_FUNCTION, "adding '%s' to package cache for db '%s'\n",
+ pkg->name, db->treename);
+ db->pkgcache = alpm_list_add(db->pkgcache, pkg);
+ count++;
+ }
+
+ closedir(dbdir);
+ db->pkgcache = alpm_list_msort(db->pkgcache, (size_t)count, _alpm_pkg_cmp);
+ return(count);
+}
+
+/* Note: the return value must be freed by the caller */
+static char *get_pkgpath(pmdb_t *db, pmpkg_t *info)
+{
+ size_t len;
+ char *pkgpath;
+ const char *dbpath;
+
+ dbpath = _alpm_db_path(db);
+ len = strlen(dbpath) + strlen(info->name) + strlen(info->version) + 3;
+ MALLOC(pkgpath, len, RET_ERR(PM_ERR_MEMORY, NULL));
+ sprintf(pkgpath, "%s%s-%s/", dbpath, info->name, info->version);
+ return(pkgpath);
+}
+
+
+int _alpm_local_db_read(pmdb_t *db, pmpkg_t *info, pmdbinfrq_t inforeq)
+{
+ FILE *fp = NULL;
+ char path[PATH_MAX];
+ char line[1024];
+ char *pkgpath = NULL;
+
+ ALPM_LOG_FUNC;
+
+ if(db == NULL) {
+ RET_ERR(PM_ERR_DB_NULL, -1);
+ }
+
+ if(info == NULL || info->name == NULL || info->version == NULL) {
+ _alpm_log(PM_LOG_DEBUG, "invalid package entry provided to _alpm_local_db_read, skipping\n");
+ return(-1);
+ }
+
+ if(info->origin != PKG_FROM_LOCALDB) {
+ _alpm_log(PM_LOG_DEBUG,
+ "request to read info for a non-local package '%s', skipping...\n",
+ info->name);
+ return(-1);
+ }
+
+ /* bitmask logic here:
+ * infolevel: 00001111
+ * inforeq: 00010100
+ * & result: 00000100
+ * == to inforeq? nope, we need to load more info. */
+ if((info->infolevel & inforeq) == inforeq) {
+ /* already loaded all of this info, do nothing */
+ return(0);
+ }
+ _alpm_log(PM_LOG_FUNCTION, "loading package data for %s : level=0x%x\n",
+ info->name, inforeq);
+
+ /* clear out 'line', to be certain - and to make valgrind happy */
+ memset(line, 0, sizeof(line));
+
+ pkgpath = get_pkgpath(db, info);
+
+ if(access(pkgpath, F_OK)) {
+ /* directory doesn't exist or can't be opened */
+ _alpm_log(PM_LOG_DEBUG, "cannot find '%s-%s' in db '%s'\n",
+ info->name, info->version, db->treename);
+ goto error;
+ }
+
+ /* DESC */
+ if(inforeq & INFRQ_DESC && !(info->infolevel & INFRQ_DESC)) {
+ snprintf(path, PATH_MAX, "%sdesc", pkgpath);
+ if((fp = fopen(path, "r")) == NULL) {
+ _alpm_log(PM_LOG_ERROR, _("could not open file %s: %s\n"), path, strerror(errno));
+ goto error;
+ }
+ while(!feof(fp)) {
+ if(fgets(line, sizeof(line), fp) == NULL) {
+ break;
+ }
+ _alpm_strtrim(line);
+ if(strcmp(line, "%NAME%") == 0) {
+ if(fgets(line, sizeof(line), fp) == NULL) {
+ goto error;
+ }
+ if(strcmp(_alpm_strtrim(line), info->name) != 0) {
+ _alpm_log(PM_LOG_ERROR, _("%s database is inconsistent: name "
+ "mismatch on package %s\n"), db->treename, info->name);
+ }
+ } else if(strcmp(line, "%VERSION%") == 0) {
+ if(fgets(line, sizeof(line), fp) == NULL) {
+ goto error;
+ }
+ if(strcmp(_alpm_strtrim(line), info->version) != 0) {
+ _alpm_log(PM_LOG_ERROR, _("%s database is inconsistent: version "
+ "mismatch on package %s\n"), db->treename, info->name);
+ }
+ } else if(strcmp(line, "%DESC%") == 0) {
+ if(fgets(line, sizeof(line), fp) == NULL) {
+ goto error;
+ }
+ STRDUP(info->desc, _alpm_strtrim(line), goto error);
+ } else if(strcmp(line, "%GROUPS%") == 0) {
+ while(fgets(line, sizeof(line), fp) && strlen(_alpm_strtrim(line))) {
+ char *linedup;
+ STRDUP(linedup, _alpm_strtrim(line), goto error);
+ info->groups = alpm_list_add(info->groups, linedup);
+ }
+ } else if(strcmp(line, "%URL%") == 0) {
+ if(fgets(line, sizeof(line), fp) == NULL) {
+ goto error;
+ }
+ STRDUP(info->url, _alpm_strtrim(line), goto error);
+ } else if(strcmp(line, "%LICENSE%") == 0) {
+ while(fgets(line, sizeof(line), fp) && strlen(_alpm_strtrim(line))) {
+ char *linedup;
+ STRDUP(linedup, _alpm_strtrim(line), goto error);
+ info->licenses = alpm_list_add(info->licenses, linedup);
+ }
+ } else if(strcmp(line, "%ARCH%") == 0) {
+ if(fgets(line, sizeof(line), fp) == NULL) {
+ goto error;
+ }
+ STRDUP(info->arch, _alpm_strtrim(line), goto error);
+ } else if(strcmp(line, "%BUILDDATE%") == 0) {
+ if(fgets(line, sizeof(line), fp) == NULL) {
+ goto error;
+ }
+ _alpm_strtrim(line);
+ info->builddate = _alpm_parsedate(line);
+ } else if(strcmp(line, "%INSTALLDATE%") == 0) {
+ if(fgets(line, sizeof(line), fp) == NULL) {
+ goto error;
+ }
+ _alpm_strtrim(line);
+ info->installdate = _alpm_parsedate(line);
+ } else if(strcmp(line, "%PACKAGER%") == 0) {
+ if(fgets(line, sizeof(line), fp) == NULL) {
+ goto error;
+ }
+ STRDUP(info->packager, _alpm_strtrim(line), goto error);
+ } else if(strcmp(line, "%REASON%") == 0) {
+ if(fgets(line, sizeof(line), fp) == NULL) {
+ goto error;
+ }
+ info->reason = (pmpkgreason_t)atol(_alpm_strtrim(line));
+ } else if(strcmp(line, "%SIZE%") == 0) {
+ /* NOTE: the CSIZE and SIZE fields both share the "size" field
+ * in the pkginfo_t struct. This can be done b/c CSIZE
+ * is currently only used in sync databases, and SIZE is
+ * only used in local databases.
+ */
+ if(fgets(line, sizeof(line), fp) == NULL) {
+ goto error;
+ }
+ info->size = atol(_alpm_strtrim(line));
+ /* also store this value to isize */
+ info->isize = info->size;
+ } else if(strcmp(line, "%REPLACES%") == 0) {
+ while(fgets(line, sizeof(line), fp) && strlen(_alpm_strtrim(line))) {
+ char *linedup;
+ STRDUP(linedup, _alpm_strtrim(line), goto error);
+ info->replaces = alpm_list_add(info->replaces, linedup);
+ }
+ } else if(strcmp(line, "%DEPENDS%") == 0) {
+ while(fgets(line, sizeof(line), fp) && strlen(_alpm_strtrim(line))) {
+ pmdepend_t *dep = _alpm_splitdep(_alpm_strtrim(line));
+ info->depends = alpm_list_add(info->depends, dep);
+ }
+ } else if(strcmp(line, "%OPTDEPENDS%") == 0) {
+ while(fgets(line, sizeof(line), fp) && strlen(_alpm_strtrim(line))) {
+ char *linedup;
+ STRDUP(linedup, _alpm_strtrim(line), goto error);
+ info->optdepends = alpm_list_add(info->optdepends, linedup);
+ }
+ } else if(strcmp(line, "%CONFLICTS%") == 0) {
+ while(fgets(line, sizeof(line), fp) && strlen(_alpm_strtrim(line))) {
+ char *linedup;
+ STRDUP(linedup, _alpm_strtrim(line), goto error);
+ info->conflicts = alpm_list_add(info->conflicts, linedup);
+ }
+ } else if(strcmp(line, "%PROVIDES%") == 0) {
+ while(fgets(line, sizeof(line), fp) && strlen(_alpm_strtrim(line))) {
+ char *linedup;
+ STRDUP(linedup, _alpm_strtrim(line), goto error);
+ info->provides = alpm_list_add(info->provides, linedup);
+ }
+ }
+ }
+ fclose(fp);
+ fp = NULL;
+ }
+
+ /* FILES */
+ if(inforeq & INFRQ_FILES && !(info->infolevel & INFRQ_FILES)) {
+ snprintf(path, PATH_MAX, "%sfiles", pkgpath);
+ if((fp = fopen(path, "r")) == NULL) {
+ _alpm_log(PM_LOG_ERROR, _("could not open file %s: %s\n"), path, strerror(errno));
+ goto error;
+ }
+ while(fgets(line, sizeof(line), fp)) {
+ _alpm_strtrim(line);
+ if(strcmp(line, "%FILES%") == 0) {
+ while(fgets(line, sizeof(line), fp) && strlen(_alpm_strtrim(line))) {
+ char *linedup;
+ STRDUP(linedup, _alpm_strtrim(line), goto error);
+ info->files = alpm_list_add(info->files, linedup);
+ }
+ } else if(strcmp(line, "%BACKUP%") == 0) {
+ while(fgets(line, sizeof(line), fp) && strlen(_alpm_strtrim(line))) {
+ char *linedup;
+ STRDUP(linedup, _alpm_strtrim(line), goto error);
+ info->backup = alpm_list_add(info->backup, linedup);
+ }
+ }
+ }
+ fclose(fp);
+ fp = NULL;
+ }
+
+ /* INSTALL */
+ if(inforeq & INFRQ_SCRIPTLET && !(info->infolevel & INFRQ_SCRIPTLET)) {
+ snprintf(path, PATH_MAX, "%sinstall", pkgpath);
+ if(access(path, F_OK) == 0) {
+ info->scriptlet = 1;
+ }
+ }
+
+ /* internal */
+ info->infolevel |= inforeq;
+
+ free(pkgpath);
+ return(0);
+
+error:
+ free(pkgpath);
+ if(fp) {
+ fclose(fp);
+ }
+ return(-1);
+}
+
+int _alpm_local_db_prepare(pmdb_t *db, pmpkg_t *info)
+{
+ mode_t oldmask;
+ int retval = 0;
+ char *pkgpath = NULL;
+
+ if(checkdbdir(db) != 0) {
+ return(-1);
+ }
+
+ oldmask = umask(0000);
+ pkgpath = get_pkgpath(db, info);
+
+ if((retval = mkdir(pkgpath, 0755)) != 0) {
+ _alpm_log(PM_LOG_ERROR, _("could not create directory %s: %s\n"),
+ pkgpath, strerror(errno));
+ }
+
+ free(pkgpath);
+ umask(oldmask);
+
+ return(retval);
+}
+
+int _alpm_local_db_write(pmdb_t *db, pmpkg_t *info, pmdbinfrq_t inforeq)
+{
+ FILE *fp = NULL;
+ char path[PATH_MAX];
+ mode_t oldmask;
+ alpm_list_t *lp = NULL;
+ int retval = 0;
+ char *pkgpath = NULL;
+
+ ALPM_LOG_FUNC;
+
+ if(db == NULL || info == NULL) {
+ return(-1);
+ }
+
+ pkgpath = get_pkgpath(db, info);
+
+ /* make sure we have a sane umask */
+ oldmask = umask(0022);
+
+ if(strcmp(db->treename, "local") != 0) {
+ return(-1);
+ }
+
+ /* DESC */
+ if(inforeq & INFRQ_DESC) {
+ _alpm_log(PM_LOG_DEBUG, "writing %s-%s DESC information back to db\n",
+ info->name, info->version);
+ snprintf(path, PATH_MAX, "%sdesc", pkgpath);
+ if((fp = fopen(path, "w")) == NULL) {
+ _alpm_log(PM_LOG_ERROR, _("could not open file %s: %s\n"), path, strerror(errno));
+ retval = -1;
+ goto cleanup;
+ }
+ fprintf(fp, "%%NAME%%\n%s\n\n"
+ "%%VERSION%%\n%s\n\n", info->name, info->version);
+ if(info->desc) {
+ fprintf(fp, "%%DESC%%\n"
+ "%s\n\n", info->desc);
+ }
+ if(info->groups) {
+ fputs("%GROUPS%\n", fp);
+ for(lp = info->groups; lp; lp = lp->next) {
+ fprintf(fp, "%s\n", (char *)lp->data);
+ }
+ fprintf(fp, "\n");
+ }
+ if(info->replaces) {
+ fputs("%REPLACES%\n", fp);
+ for(lp = info->replaces; lp; lp = lp->next) {
+ fprintf(fp, "%s\n", (char *)lp->data);
+ }
+ fprintf(fp, "\n");
+ }
+ if(info->url) {
+ fprintf(fp, "%%URL%%\n"
+ "%s\n\n", info->url);
+ }
+ if(info->licenses) {
+ fputs("%LICENSE%\n", fp);
+ for(lp = info->licenses; lp; lp = lp->next) {
+ fprintf(fp, "%s\n", (char *)lp->data);
+ }
+ fprintf(fp, "\n");
+ }
+ if(info->arch) {
+ fprintf(fp, "%%ARCH%%\n"
+ "%s\n\n", info->arch);
+ }
+ if(info->builddate) {
+ fprintf(fp, "%%BUILDDATE%%\n"
+ "%ld\n\n", info->builddate);
+ }
+ if(info->installdate) {
+ fprintf(fp, "%%INSTALLDATE%%\n"
+ "%ld\n\n", info->installdate);
+ }
+ if(info->packager) {
+ fprintf(fp, "%%PACKAGER%%\n"
+ "%s\n\n", info->packager);
+ }
+ if(info->isize) {
+ /* only write installed size, csize is irrelevant once installed */
+ fprintf(fp, "%%SIZE%%\n"
+ "%jd\n\n", (intmax_t)info->isize);
+ }
+ if(info->reason) {
+ fprintf(fp, "%%REASON%%\n"
+ "%u\n\n", info->reason);
+ }
+ if(info->depends) {
+ fputs("%DEPENDS%\n", fp);
+ for(lp = info->depends; lp; lp = lp->next) {
+ char *depstring = alpm_dep_compute_string(lp->data);
+ fprintf(fp, "%s\n", depstring);
+ free(depstring);
+ }
+ fprintf(fp, "\n");
+ }
+ if(info->optdepends) {
+ fputs("%OPTDEPENDS%\n", fp);
+ for(lp = info->optdepends; lp; lp = lp->next) {
+ fprintf(fp, "%s\n", (char *)lp->data);
+ }
+ fprintf(fp, "\n");
+ }
+ if(info->conflicts) {
+ fputs("%CONFLICTS%\n", fp);
+ for(lp = info->conflicts; lp; lp = lp->next) {
+ fprintf(fp, "%s\n", (char *)lp->data);
+ }
+ fprintf(fp, "\n");
+ }
+ if(info->provides) {
+ fputs("%PROVIDES%\n", fp);
+ for(lp = info->provides; lp; lp = lp->next) {
+ fprintf(fp, "%s\n", (char *)lp->data);
+ }
+ fprintf(fp, "\n");
+ }
+
+ fclose(fp);
+ fp = NULL;
+ }
+
+ /* FILES */
+ if(inforeq & INFRQ_FILES) {
+ _alpm_log(PM_LOG_DEBUG, "writing %s-%s FILES information back to db\n",
+ info->name, info->version);
+ snprintf(path, PATH_MAX, "%sfiles", pkgpath);
+ if((fp = fopen(path, "w")) == NULL) {
+ _alpm_log(PM_LOG_ERROR, _("could not open file %s: %s\n"), path, strerror(errno));
+ retval = -1;
+ goto cleanup;
+ }
+ if(info->files) {
+ fprintf(fp, "%%FILES%%\n");
+ for(lp = info->files; lp; lp = lp->next) {
+ fprintf(fp, "%s\n", (char *)lp->data);
+ }
+ fprintf(fp, "\n");
+ }
+ if(info->backup) {
+ fprintf(fp, "%%BACKUP%%\n");
+ for(lp = info->backup; lp; lp = lp->next) {
+ fprintf(fp, "%s\n", (char *)lp->data);
+ }
+ fprintf(fp, "\n");
+ }
+ fclose(fp);
+ fp = NULL;
+ }
+
+ /* INSTALL */
+ /* nothing needed here (script is automatically extracted) */
+
+cleanup:
+ umask(oldmask);
+ free(pkgpath);
+
+ if(fp) {
+ fclose(fp);
+ }
+
+ return(retval);
+}
+
+int _alpm_local_db_remove(pmdb_t *db, pmpkg_t *info)
+{
+ int ret = 0;
+ char *pkgpath = NULL;
+
+ ALPM_LOG_FUNC;
+
+ if(db == NULL || info == NULL) {
+ RET_ERR(PM_ERR_DB_NULL, -1);
+ }
+
+ pkgpath = get_pkgpath(db, info);
+
+ ret = _alpm_rmrf(pkgpath);
+ free(pkgpath);
+ if(ret != 0) {
+ ret = -1;
+ }
+ return(ret);
+}
+
+struct db_operations local_db_ops = {
+ .populate = local_db_populate,
+ .unregister = _alpm_db_unregister,
+};
+
+pmdb_t *_alpm_db_register_local(void)
+{
+ pmdb_t *db;
+
+ ALPM_LOG_FUNC;
+
+ if(handle->db_local != NULL) {
+ _alpm_log(PM_LOG_WARNING, _("attempt to re-register the 'local' DB\n"));
+ RET_ERR(PM_ERR_DB_NOT_NULL, NULL);
+ }
+
+ _alpm_log(PM_LOG_DEBUG, "registering local database\n");
+
+ db = _alpm_db_new("local", 1);
+ db->ops = &local_db_ops;
+ if(db == NULL) {
+ RET_ERR(PM_ERR_DB_CREATE, NULL);
+ }
+
+ handle->db_local = db;
+ return(db);
+}
+
+
+/* vim: set ts=2 sw=2 noet: */
diff --git a/lib/libalpm/be_package.c b/lib/libalpm/be_package.c
index ff266ae8..c272bd47 100644
--- a/lib/libalpm/be_package.c
+++ b/lib/libalpm/be_package.c
@@ -1,7 +1,7 @@
/*
* be_package.c
*
- * Copyright (c) 2006-2010 Pacman Development Team <pacman-dev@archlinux.org>
+ * Copyright (c) 2006-2011 Pacman Development Team <pacman-dev@archlinux.org>
* Copyright (c) 2002-2006 by Judd Vinet <jvinet@zeroflux.org>
*
* This program is free software; you can redistribute it and/or modify
@@ -24,8 +24,8 @@
#include <stdlib.h>
#include <string.h>
#include <limits.h>
-#include <ctype.h>
#include <locale.h> /* setlocale */
+#include <errno.h>
/* libarchive */
#include <archive.h>
@@ -39,6 +39,109 @@
#include "deps.h" /* _alpm_splitdep */
/**
+ * Open a package changelog for reading. Similar to fopen in functionality,
+ * except that the returned 'file stream' is from an archive.
+ * @param pkg the package (file) to read the changelog
+ * @return a 'file stream' to the package changelog
+ */
+static void *_package_changelog_open(pmpkg_t *pkg)
+{
+ ALPM_LOG_FUNC;
+
+ ASSERT(pkg != NULL, return(NULL));
+
+ struct archive *archive = NULL;
+ struct archive_entry *entry;
+ const char *pkgfile = pkg->origin_data.file;
+
+ if((archive = archive_read_new()) == NULL) {
+ RET_ERR(PM_ERR_LIBARCHIVE, NULL);
+ }
+
+ archive_read_support_compression_all(archive);
+ archive_read_support_format_all(archive);
+
+ if (archive_read_open_filename(archive, pkgfile,
+ ARCHIVE_DEFAULT_BYTES_PER_BLOCK) != ARCHIVE_OK) {
+ RET_ERR(PM_ERR_PKG_OPEN, NULL);
+ }
+
+ while(archive_read_next_header(archive, &entry) == ARCHIVE_OK) {
+ const char *entry_name = archive_entry_pathname(entry);
+
+ if(strcmp(entry_name, ".CHANGELOG") == 0) {
+ return(archive);
+ }
+ }
+ /* we didn't find a changelog */
+ archive_read_finish(archive);
+ errno = ENOENT;
+
+ return(NULL);
+}
+
+/**
+ * Read data from an open changelog 'file stream'. Similar to fread in
+ * functionality, this function takes a buffer and amount of data to read.
+ * @param ptr a buffer to fill with raw changelog data
+ * @param size the size of the buffer
+ * @param pkg the package that the changelog is being read from
+ * @param fp a 'file stream' to the package changelog
+ * @return the number of characters read, or 0 if there is no more data
+ */
+static size_t _package_changelog_read(void *ptr, size_t size,
+ const pmpkg_t *pkg, const void *fp)
+{
+ ssize_t sret = archive_read_data((struct archive*)fp, ptr, size);
+ /* Report error (negative values) */
+ if(sret < 0) {
+ pm_errno = PM_ERR_LIBARCHIVE;
+ return(0);
+ } else {
+ return((size_t)sret);
+ }
+}
+
+/*
+static int _package_changelog_feof(const pmpkg_t *pkg, void *fp)
+{
+ // note: this doesn't quite work, no feof in libarchive
+ return( archive_read_data((struct archive*)fp, NULL, 0) );
+}
+*/
+
+/**
+ * Close a package changelog for reading. Similar to fclose in functionality,
+ * except that the 'file stream' is from an archive.
+ * @param pkg the package (file) that the changelog was read from
+ * @param fp a 'file stream' to the package changelog
+ * @return whether closing the package changelog stream was successful
+ */
+static int _package_changelog_close(const pmpkg_t *pkg, void *fp)
+{
+ return( archive_read_finish((struct archive *)fp) );
+}
+
+/** Package file operations struct accessor. We implement this as a method
+ * rather than a static struct as in be_files because we want to reuse the
+ * majority of the default_pkg_ops struct and add only a few operations of
+ * our own on top.
+ */
+static struct pkg_operations *get_file_pkg_ops(void)
+{
+ static struct pkg_operations file_pkg_ops;
+ static int file_pkg_ops_initialized = 0;
+ if(!file_pkg_ops_initialized) {
+ file_pkg_ops = default_pkg_ops;
+ file_pkg_ops.changelog_open = _package_changelog_open;
+ file_pkg_ops.changelog_read = _package_changelog_read;
+ file_pkg_ops.changelog_close = _package_changelog_close;
+ file_pkg_ops_initialized = 1;
+ }
+ return(&file_pkg_ops);
+}
+
+/**
* Parses the package description file for a package into a pmpkg_t struct.
* @param archive the archive to read from, pointed at the .PKGINFO entry
* @param newpkg an empty pmpkg_t struct to fill with package info
@@ -47,17 +150,22 @@
*/
static int parse_descfile(struct archive *a, pmpkg_t *newpkg)
{
- char line[PATH_MAX];
char *ptr = NULL;
char *key = NULL;
int linenum = 0;
+ struct archive_read_buffer buf;
ALPM_LOG_FUNC;
- /* loop until we reach EOF (where archive_fgets will return NULL) */
- while(_alpm_archive_fgets(line, PATH_MAX, a) != NULL) {
+ memset(&buf, 0, sizeof(buf));
+ /* 512K for a line length seems reasonable */
+ buf.max_line_size = 512 * 1024;
+
+ /* loop until we reach EOF or other error */
+ while(_alpm_archive_fgets(a, &buf) == ARCHIVE_OK) {
+ char *line = _alpm_strtrim(buf.line);
+
linenum++;
- _alpm_strtrim(line);
if(strlen(line) == 0 || line[0] == '#') {
continue;
}
@@ -69,52 +177,42 @@ static int parse_descfile(struct archive *a, pmpkg_t *newpkg)
} else {
key = _alpm_strtrim(key);
ptr = _alpm_strtrim(ptr);
- if(!strcmp(key, "pkgname")) {
+ if(strcmp(key, "pkgname") == 0) {
STRDUP(newpkg->name, ptr, RET_ERR(PM_ERR_MEMORY, -1));
- } else if(!strcmp(key, "pkgver")) {
+ newpkg->name_hash = _alpm_hash_sdbm(newpkg->name);
+ } else if(strcmp(key, "pkgver") == 0) {
STRDUP(newpkg->version, ptr, RET_ERR(PM_ERR_MEMORY, -1));
- } else if(!strcmp(key, "pkgdesc")) {
+ } else if(strcmp(key, "pkgdesc") == 0) {
STRDUP(newpkg->desc, ptr, RET_ERR(PM_ERR_MEMORY, -1));
- } else if(!strcmp(key, "force")) {
- newpkg->force = 1;
- } else if(!strcmp(key, "group")) {
+ } else if(strcmp(key, "group") == 0) {
newpkg->groups = alpm_list_add(newpkg->groups, strdup(ptr));
- } else if(!strcmp(key, "url")) {
+ } else if(strcmp(key, "url") == 0) {
STRDUP(newpkg->url, ptr, RET_ERR(PM_ERR_MEMORY, -1));
- } else if(!strcmp(key, "license")) {
+ } else if(strcmp(key, "license") == 0) {
newpkg->licenses = alpm_list_add(newpkg->licenses, strdup(ptr));
- } else if(!strcmp(key, "builddate")) {
- char first = tolower((unsigned char)ptr[0]);
- if(first > 'a' && first < 'z') {
- struct tm tmp_tm = {0}; /* initialize to null in case of failure */
- setlocale(LC_TIME, "C");
- strptime(ptr, "%a %b %e %H:%M:%S %Y", &tmp_tm);
- newpkg->builddate = mktime(&tmp_tm);
- setlocale(LC_TIME, "");
- } else {
- newpkg->builddate = atol(ptr);
- }
- } else if(!strcmp(key, "packager")) {
+ } else if(strcmp(key, "builddate") == 0) {
+ newpkg->builddate = _alpm_parsedate(ptr);
+ } else if(strcmp(key, "packager") == 0) {
STRDUP(newpkg->packager, ptr, RET_ERR(PM_ERR_MEMORY, -1));
- } else if(!strcmp(key, "arch")) {
+ } else if(strcmp(key, "arch") == 0) {
STRDUP(newpkg->arch, ptr, RET_ERR(PM_ERR_MEMORY, -1));
- } else if(!strcmp(key, "size")) {
+ } else if(strcmp(key, "size") == 0) {
/* size in the raw package is uncompressed (installed) size */
newpkg->isize = atol(ptr);
- } else if(!strcmp(key, "depend")) {
+ } else if(strcmp(key, "depend") == 0) {
pmdepend_t *dep = _alpm_splitdep(ptr);
newpkg->depends = alpm_list_add(newpkg->depends, dep);
- } else if(!strcmp(key, "optdepend")) {
+ } else if(strcmp(key, "optdepend") == 0) {
newpkg->optdepends = alpm_list_add(newpkg->optdepends, strdup(ptr));
- } else if(!strcmp(key, "conflict")) {
+ } else if(strcmp(key, "conflict") == 0) {
newpkg->conflicts = alpm_list_add(newpkg->conflicts, strdup(ptr));
- } else if(!strcmp(key, "replaces")) {
+ } else if(strcmp(key, "replaces") == 0) {
newpkg->replaces = alpm_list_add(newpkg->replaces, strdup(ptr));
- } else if(!strcmp(key, "provides")) {
+ } else if(strcmp(key, "provides") == 0) {
newpkg->provides = alpm_list_add(newpkg->provides, strdup(ptr));
- } else if(!strcmp(key, "backup")) {
+ } else if(strcmp(key, "backup") == 0) {
newpkg->backup = alpm_list_add(newpkg->backup, strdup(ptr));
- } else if(!strcmp(key, "makepkgopt")) {
+ } else if(strcmp(key, "makepkgopt") == 0) {
/* not used atm */
} else {
_alpm_log(PM_LOG_DEBUG, "%s: syntax error in description file line %d\n",
@@ -174,6 +272,8 @@ static pmpkg_t *pkg_load(const char *pkgfile, int full)
newpkg->filename = strdup(pkgfile);
newpkg->size = st.st_size;
+ _alpm_log(PM_LOG_DEBUG, "starting package load for %s\n", pkgfile);
+
/* If full is false, only read through the archive until we find our needed
* metadata. If it is true, read through the entire archive, which serves
* as a verfication of integrity and allows us to create the filelist. */
@@ -232,11 +332,13 @@ static pmpkg_t *pkg_load(const char *pkgfile, int full)
goto pkg_invalid;
}
- archive_read_finish(archive);
+ archive_read_finish(archive);
/* internal fields for package struct */
newpkg->origin = PKG_FROM_FILE;
+ /* TODO eventually kill/move this? */
newpkg->origin_data.file = strdup(pkgfile);
+ newpkg->ops = get_file_pkg_ops();
if(full) {
/* "checking for conflicts" requires a sorted list, ensure that here */
@@ -247,7 +349,7 @@ static pmpkg_t *pkg_load(const char *pkgfile, int full)
} else {
/* get rid of any partial filelist we may have collected, it is invalid */
FREELIST(newpkg->files);
- newpkg->infolevel = INFRQ_BASE | INFRQ_DESC | INFRQ_DEPENDS;
+ newpkg->infolevel = INFRQ_BASE | INFRQ_DESC;
}
return(newpkg);
diff --git a/lib/libalpm/be_sync.c b/lib/libalpm/be_sync.c
new file mode 100644
index 00000000..4676e8a6
--- /dev/null
+++ b/lib/libalpm/be_sync.c
@@ -0,0 +1,404 @@
+/*
+ * be_sync.c
+ *
+ * Copyright (c) 2006-2011 Pacman Development Team <pacman-dev@archlinux.org>
+ * Copyright (c) 2002-2006 by Judd Vinet <jvinet@zeroflux.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "config.h"
+
+#include <errno.h>
+#include <locale.h>
+#include <limits.h>
+
+/* libarchive */
+#include <archive.h>
+#include <archive_entry.h>
+
+/* libalpm */
+#include "util.h"
+#include "log.h"
+#include "alpm.h"
+#include "alpm_list.h"
+#include "package.h"
+#include "handle.h"
+#include "delta.h"
+#include "deps.h"
+#include "dload.h"
+
+/** Update a package database
+ *
+ * An update of the package database \a db will be attempted. Unless
+ * \a force is true, the update will only be performed if the remote
+ * database was modified since the last update.
+ *
+ * A transaction is necessary for this operation, in order to obtain a
+ * database lock. During this transaction the front-end will be informed
+ * of the download progress of the database via the download callback.
+ *
+ * Example:
+ * @code
+ * pmdb_t *db;
+ * int result;
+ * db = alpm_list_getdata(alpm_option_get_syncdbs());
+ * if(alpm_trans_init(0, NULL, NULL, NULL) == 0) {
+ * result = alpm_db_update(0, db);
+ * alpm_trans_release();
+ *
+ * if(result > 0) {
+ * printf("Unable to update database: %s\n", alpm_strerrorlast());
+ * } else if(result < 0) {
+ * printf("Database already up to date\n");
+ * } else {
+ * printf("Database updated\n");
+ * }
+ * }
+ * @endcode
+ *
+ * @ingroup alpm_databases
+ * @note After a successful update, the \link alpm_db_get_pkgcache()
+ * package cache \endlink will be invalidated
+ * @param force if true, then forces the update, otherwise update only in case
+ * the database isn't up to date
+ * @param db pointer to the package database to update
+ * @return 0 on success, > 0 on error (pm_errno is set accordingly), < 0 if up
+ * to date
+ */
+int SYMEXPORT alpm_db_update(int force, pmdb_t *db)
+{
+ char *dbfile, *syncpath;
+ const char *dbpath;
+ struct stat buf;
+ size_t len;
+ int ret;
+
+ ALPM_LOG_FUNC;
+
+ /* Sanity checks */
+ ASSERT(handle != NULL, RET_ERR(PM_ERR_HANDLE_NULL, -1));
+ ASSERT(db != NULL && db != handle->db_local, RET_ERR(PM_ERR_WRONG_ARGS, -1));
+
+ if(!alpm_list_find_ptr(handle->dbs_sync, db)) {
+ RET_ERR(PM_ERR_DB_NOT_FOUND, -1);
+ }
+
+ len = strlen(db->treename) + 4;
+ MALLOC(dbfile, len, RET_ERR(PM_ERR_MEMORY, -1));
+ sprintf(dbfile, "%s.db", db->treename);
+
+ dbpath = alpm_option_get_dbpath();
+ len = strlen(dbpath) + 6;
+ MALLOC(syncpath, len, RET_ERR(PM_ERR_MEMORY, -1));
+ sprintf(syncpath, "%s%s", dbpath, "sync/");
+
+ if(stat(syncpath, &buf) != 0) {
+ _alpm_log(PM_LOG_DEBUG, "database dir '%s' does not exist, creating it\n",
+ syncpath);
+ if(_alpm_makepath(syncpath) != 0) {
+ free(dbfile);
+ free(syncpath);
+ RET_ERR(PM_ERR_SYSTEM, -1);
+ }
+ } else if(!S_ISDIR(buf.st_mode)) {
+ _alpm_log(PM_LOG_WARNING, _("removing invalid file: %s\n"), syncpath);
+ if(unlink(syncpath) != 0 || _alpm_makepath(syncpath) != 0) {
+ free(dbfile);
+ free(syncpath);
+ RET_ERR(PM_ERR_SYSTEM, -1);
+ }
+ }
+
+ ret = _alpm_download_single_file(dbfile, db->servers, syncpath, force);
+ free(dbfile);
+ free(syncpath);
+
+ if(ret == 1) {
+ /* files match, do nothing */
+ pm_errno = 0;
+ return(1);
+ } else if(ret == -1) {
+ /* pm_errno was set by the download code */
+ _alpm_log(PM_LOG_DEBUG, "failed to sync db: %s\n", alpm_strerrorlast());
+ return(-1);
+ }
+
+ /* Cache needs to be rebuilt */
+ _alpm_db_free_pkgcache(db);
+
+ return(0);
+}
+
+/* Forward decl so I don't reorganize the whole file right now */
+static int sync_db_read(pmdb_t *db, struct archive *archive,
+ struct archive_entry *entry, pmpkg_t *likely_pkg);
+
+static int sync_db_populate(pmdb_t *db)
+{
+ int count = 0;
+ struct archive *archive;
+ struct archive_entry *entry;
+ pmpkg_t *pkg = NULL;
+
+ ALPM_LOG_FUNC;
+
+ ASSERT(db != NULL, RET_ERR(PM_ERR_DB_NULL, -1));
+
+ if((archive = archive_read_new()) == NULL)
+ RET_ERR(PM_ERR_LIBARCHIVE, 1);
+
+ archive_read_support_compression_all(archive);
+ archive_read_support_format_all(archive);
+
+ if(archive_read_open_filename(archive, _alpm_db_path(db),
+ ARCHIVE_DEFAULT_BYTES_PER_BLOCK) != ARCHIVE_OK) {
+ _alpm_log(PM_LOG_ERROR, _("could not open %s: %s\n"), _alpm_db_path(db),
+ archive_error_string(archive));
+ RET_ERR(PM_ERR_PKG_OPEN, 1);
+ }
+
+ while(archive_read_next_header(archive, &entry) == ARCHIVE_OK) {
+ const struct stat *st;
+
+ st = archive_entry_stat(entry);
+
+ if(S_ISDIR(st->st_mode)) {
+ const char *name;
+
+ pkg = _alpm_pkg_new();
+ if(pkg == NULL) {
+ archive_read_finish(archive);
+ return(-1);
+ }
+
+ name = archive_entry_pathname(entry);
+
+ if(_alpm_splitname(name, pkg) != 0) {
+ _alpm_log(PM_LOG_ERROR, _("invalid name for database entry '%s'\n"),
+ name);
+ _alpm_pkg_free(pkg);
+ continue;
+ }
+
+ /* duplicated database entries are not allowed */
+ if(_alpm_pkg_find(db->pkgcache, pkg->name)) {
+ _alpm_log(PM_LOG_ERROR, _("duplicated database entry '%s'\n"), pkg->name);
+ _alpm_pkg_free(pkg);
+ continue;
+ }
+
+ pkg->origin = PKG_FROM_SYNCDB;
+ pkg->ops = &default_pkg_ops;
+ pkg->origin_data.db = db;
+
+ /* add to the collection */
+ _alpm_log(PM_LOG_FUNCTION, "adding '%s' to package cache for db '%s'\n",
+ pkg->name, db->treename);
+ db->pkgcache = alpm_list_add(db->pkgcache, pkg);
+ count++;
+ } else {
+ /* we have desc, depends or deltas - parse it */
+ sync_db_read(db, archive, entry, pkg);
+ }
+ }
+
+ db->pkgcache = alpm_list_msort(db->pkgcache, (size_t)count, _alpm_pkg_cmp);
+ archive_read_finish(archive);
+
+ return(count);
+}
+
+#define READ_NEXT(s) do { \
+ if(_alpm_archive_fgets(archive, &buf) != ARCHIVE_OK) goto error; \
+ s = _alpm_strtrim(buf.line); \
+} while(0)
+
+#define READ_AND_STORE(f) do { \
+ READ_NEXT(line); \
+ STRDUP(f, line, goto error); \
+} while(0)
+
+#define READ_AND_STORE_ALL(f) do { \
+ char *linedup; \
+ READ_NEXT(line); \
+ if(strlen(line) == 0) break; \
+ STRDUP(linedup, line, goto error); \
+ f = alpm_list_add(f, linedup); \
+} while(1) /* note the while(1) and not (0) */
+
+static int sync_db_read(pmdb_t *db, struct archive *archive,
+ struct archive_entry *entry, pmpkg_t *likely_pkg)
+{
+ const char *entryname = NULL, *filename;
+ char *pkgname, *p, *q;
+ pmpkg_t *pkg;
+ struct archive_read_buffer buf;
+
+ ALPM_LOG_FUNC;
+
+ if(db == NULL) {
+ RET_ERR(PM_ERR_DB_NULL, -1);
+ }
+
+ if(entry != NULL) {
+ entryname = archive_entry_pathname(entry);
+ }
+ if(entryname == NULL) {
+ _alpm_log(PM_LOG_DEBUG, "invalid archive entry provided to _alpm_sync_db_read, skipping\n");
+ return(-1);
+ }
+
+ _alpm_log(PM_LOG_FUNCTION, "loading package data from archive entry %s\n",
+ entryname);
+
+ memset(&buf, 0, sizeof(buf));
+ /* 512K for a line length seems reasonable */
+ buf.max_line_size = 512 * 1024;
+
+ /* get package and db file names */
+ STRDUP(pkgname, entryname, RET_ERR(PM_ERR_MEMORY, -1));
+ p = pkgname + strlen(pkgname);
+ for(q = --p; *q && *q != '/'; q--);
+ filename = q + 1;
+ for(p = --q; *p && *p != '-'; p--);
+ for(q = --p; *q && *q != '-'; q--);
+ *q = '\0';
+
+ /* package is already in db due to parsing of directory name */
+ if(likely_pkg && strcmp(likely_pkg->name, pkgname) == 0) {
+ pkg = likely_pkg;
+ } else {
+ pkg = _alpm_pkg_find(db->pkgcache, pkgname);
+ }
+ if(pkg == NULL) {
+ _alpm_log(PM_LOG_DEBUG, "package %s not found in %s sync database",
+ pkgname, db->treename);
+ return(-1);
+ }
+
+ if(strcmp(filename, "desc") == 0 || strcmp(filename, "depends") == 0
+ || strcmp(filename, "deltas") == 0) {
+ while(_alpm_archive_fgets(archive, &buf) == ARCHIVE_OK) {
+ char *line = _alpm_strtrim(buf.line);
+
+ if(strcmp(line, "%NAME%") == 0) {
+ READ_NEXT(line);
+ if(strcmp(line, pkg->name) != 0) {
+ _alpm_log(PM_LOG_ERROR, _("%s database is inconsistent: name "
+ "mismatch on package %s\n"), db->treename, pkg->name);
+ }
+ } else if(strcmp(line, "%VERSION%") == 0) {
+ READ_NEXT(line);
+ if(strcmp(line, pkg->version) != 0) {
+ _alpm_log(PM_LOG_ERROR, _("%s database is inconsistent: version "
+ "mismatch on package %s\n"), db->treename, pkg->name);
+ }
+ } else if(strcmp(line, "%FILENAME%") == 0) {
+ READ_AND_STORE(pkg->filename);
+ } else if(strcmp(line, "%DESC%") == 0) {
+ READ_AND_STORE(pkg->desc);
+ } else if(strcmp(line, "%GROUPS%") == 0) {
+ READ_AND_STORE_ALL(pkg->groups);
+ } else if(strcmp(line, "%URL%") == 0) {
+ READ_AND_STORE(pkg->url);
+ } else if(strcmp(line, "%LICENSE%") == 0) {
+ READ_AND_STORE_ALL(pkg->licenses);
+ } else if(strcmp(line, "%ARCH%") == 0) {
+ READ_AND_STORE(pkg->arch);
+ } else if(strcmp(line, "%BUILDDATE%") == 0) {
+ READ_NEXT(line);
+ pkg->builddate = _alpm_parsedate(line);
+ } else if(strcmp(line, "%PACKAGER%") == 0) {
+ READ_AND_STORE(pkg->packager);
+ } else if(strcmp(line, "%CSIZE%") == 0) {
+ /* Note: the CSIZE and SIZE fields both share the "size" field in the
+ * pkginfo_t struct. This can be done b/c CSIZE is currently only used
+ * in sync databases, and SIZE is only used in local databases.
+ */
+ READ_NEXT(line);
+ pkg->size = atol(line);
+ /* also store this value to isize if isize is unset */
+ if(pkg->isize == 0) {
+ pkg->isize = pkg->size;
+ }
+ } else if(strcmp(line, "%ISIZE%") == 0) {
+ READ_NEXT(line);
+ pkg->isize = atol(line);
+ } else if(strcmp(line, "%MD5SUM%") == 0) {
+ READ_AND_STORE(pkg->md5sum);
+ } else if(strcmp(line, "%REPLACES%") == 0) {
+ READ_AND_STORE_ALL(pkg->replaces);
+ } else if(strcmp(line, "%DEPENDS%") == 0) {
+ /* Different than the rest because of the _alpm_splitdep call. */
+ while(1) {
+ READ_NEXT(line);
+ if(strlen(line) == 0) break;
+ pkg->depends = alpm_list_add(pkg->depends, _alpm_splitdep(line));
+ }
+ } else if(strcmp(line, "%OPTDEPENDS%") == 0) {
+ READ_AND_STORE_ALL(pkg->optdepends);
+ } else if(strcmp(line, "%CONFLICTS%") == 0) {
+ READ_AND_STORE_ALL(pkg->conflicts);
+ } else if(strcmp(line, "%PROVIDES%") == 0) {
+ READ_AND_STORE_ALL(pkg->provides);
+ } else if(strcmp(line, "%DELTAS%") == 0) {
+ READ_AND_STORE_ALL(pkg->deltas);
+ }
+ }
+ } else {
+ /* unknown database file */
+ _alpm_log(PM_LOG_DEBUG, "unknown database file: %s", filename);
+ }
+
+error:
+ FREE(pkgname);
+ /* TODO: return 0 always? */
+ return(0);
+}
+
+struct db_operations sync_db_ops = {
+ .populate = sync_db_populate,
+ .unregister = _alpm_db_unregister,
+};
+
+pmdb_t *_alpm_db_register_sync(const char *treename)
+{
+ pmdb_t *db;
+ alpm_list_t *i;
+
+ ALPM_LOG_FUNC;
+
+ for(i = handle->dbs_sync; i; i = i->next) {
+ pmdb_t *sdb = i->data;
+ if(strcmp(treename, sdb->treename) == 0) {
+ _alpm_log(PM_LOG_DEBUG, "attempt to re-register the '%s' database, using existing\n", sdb->treename);
+ return sdb;
+ }
+ }
+
+ _alpm_log(PM_LOG_DEBUG, "registering sync database '%s'\n", treename);
+
+ db = _alpm_db_new(treename, 0);
+ db->ops = &sync_db_ops;
+ if(db == NULL) {
+ RET_ERR(PM_ERR_DB_CREATE, NULL);
+ }
+
+ handle->dbs_sync = alpm_list_add(handle->dbs_sync, db);
+ return(db);
+}
+
+
+/* vim: set ts=2 sw=2 noet: */
diff --git a/lib/libalpm/cache.c b/lib/libalpm/cache.c
deleted file mode 100644
index a9a7edd9..00000000
--- a/lib/libalpm/cache.c
+++ /dev/null
@@ -1,291 +0,0 @@
-/*
- * cache.c
- *
- * Copyright (c) 2006-2010 Pacman Development Team <pacman-dev@archlinux.org>
- * Copyright (c) 2002-2006 by Judd Vinet <jvinet@zeroflux.org>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- */
-
-#include "config.h"
-
-#include <stdio.h>
-#include <stdlib.h>
-#include <errno.h>
-#include <string.h>
-
-/* libalpm */
-#include "cache.h"
-#include "alpm_list.h"
-#include "log.h"
-#include "alpm.h"
-#include "util.h"
-#include "package.h"
-#include "group.h"
-#include "db.h"
-
-/* Returns a new package cache from db.
- * It frees the cache if it already exists.
- */
-int _alpm_db_load_pkgcache(pmdb_t *db)
-{
- ALPM_LOG_FUNC;
-
- if(db == NULL) {
- return(-1);
- }
- _alpm_db_free_pkgcache(db);
-
- _alpm_log(PM_LOG_DEBUG, "loading package cache for repository '%s'\n",
- db->treename);
- if(_alpm_db_populate(db) == -1) {
- _alpm_log(PM_LOG_DEBUG,
- "failed to load package cache for repository '%s'\n", db->treename);
- return(-1);
- }
-
- db->pkgcache_loaded = 1;
- return(0);
-}
-
-void _alpm_db_free_pkgcache(pmdb_t *db)
-{
- ALPM_LOG_FUNC;
-
- if(db == NULL || !db->pkgcache_loaded) {
- return;
- }
-
- _alpm_log(PM_LOG_DEBUG, "freeing package cache for repository '%s'\n",
- db->treename);
-
- alpm_list_free_inner(db->pkgcache, (alpm_list_fn_free)_alpm_pkg_free);
- alpm_list_free(db->pkgcache);
- db->pkgcache = NULL;
- db->pkgcache_loaded = 0;
-
- _alpm_db_free_grpcache(db);
-}
-
-alpm_list_t *_alpm_db_get_pkgcache(pmdb_t *db)
-{
- ALPM_LOG_FUNC;
-
- if(db == NULL) {
- return(NULL);
- }
-
- if(!db->pkgcache_loaded) {
- _alpm_db_load_pkgcache(db);
- }
-
- /* hmmm, still NULL ?*/
- if(!db->pkgcache) {
- _alpm_log(PM_LOG_DEBUG, "warning: pkgcache is NULL for db '%s'\n", db->treename);
- }
-
- return(db->pkgcache);
-}
-
-/* "duplicate" pkg with BASE info (to spare some memory) then add it to pkgcache */
-int _alpm_db_add_pkgincache(pmdb_t *db, pmpkg_t *pkg)
-{
- pmpkg_t *newpkg;
-
- ALPM_LOG_FUNC;
-
- if(db == NULL || !db->pkgcache_loaded || pkg == NULL) {
- return(-1);
- }
-
- newpkg = _alpm_pkg_new();
- if(newpkg == NULL) {
- return(-1);
- }
- newpkg->name = strdup(pkg->name);
- newpkg->version = strdup(pkg->version);
- if(newpkg->name == NULL || newpkg->version == NULL) {
- pm_errno = PM_ERR_MEMORY;
- _alpm_pkg_free(newpkg);
- return(-1);
- }
- newpkg->origin = PKG_FROM_CACHE;
- newpkg->origin_data.db = db;
- newpkg->infolevel = INFRQ_BASE;
-
- _alpm_log(PM_LOG_DEBUG, "adding entry '%s' in '%s' cache\n",
- alpm_pkg_get_name(newpkg), db->treename);
- db->pkgcache = alpm_list_add_sorted(db->pkgcache, newpkg, _alpm_pkg_cmp);
-
- _alpm_db_free_grpcache(db);
-
- return(0);
-}
-
-int _alpm_db_remove_pkgfromcache(pmdb_t *db, pmpkg_t *pkg)
-{
- void *vdata;
- pmpkg_t *data;
-
- ALPM_LOG_FUNC;
-
- if(db == NULL || !db->pkgcache_loaded || pkg == NULL) {
- return(-1);
- }
-
- _alpm_log(PM_LOG_DEBUG, "removing entry '%s' from '%s' cache\n",
- alpm_pkg_get_name(pkg), db->treename);
-
- db->pkgcache = alpm_list_remove(db->pkgcache, pkg, _alpm_pkg_cmp, &vdata);
- data = vdata;
- if(data == NULL) {
- /* package not found */
- _alpm_log(PM_LOG_DEBUG, "cannot remove entry '%s' from '%s' cache: not found\n",
- alpm_pkg_get_name(pkg), db->treename);
- return(-1);
- }
-
- _alpm_pkg_free(data);
-
- _alpm_db_free_grpcache(db);
-
- return(0);
-}
-
-pmpkg_t *_alpm_db_get_pkgfromcache(pmdb_t *db, const char *target)
-{
- ALPM_LOG_FUNC;
-
- if(db == NULL) {
- return(NULL);
- }
-
- alpm_list_t *pkgcache = _alpm_db_get_pkgcache(db);
- if(!pkgcache) {
- _alpm_log(PM_LOG_DEBUG, "warning: failed to get '%s' from NULL pkgcache\n",
- target);
- return(NULL);
- }
-
- return(_alpm_pkg_find(pkgcache, target));
-}
-
-/* Returns a new group cache from db.
- */
-int _alpm_db_load_grpcache(pmdb_t *db)
-{
- alpm_list_t *lp;
-
- ALPM_LOG_FUNC;
-
- if(db == NULL) {
- return(-1);
- }
-
- _alpm_log(PM_LOG_DEBUG, "loading group cache for repository '%s'\n",
- db->treename);
-
- for(lp = _alpm_db_get_pkgcache(db); lp; lp = lp->next) {
- const alpm_list_t *i;
- pmpkg_t *pkg = lp->data;
-
- for(i = alpm_pkg_get_groups(pkg); i; i = i->next) {
- const char *grpname = i->data;
- alpm_list_t *j;
- pmgrp_t *grp = NULL;
- int found = 0;
-
- /* first look through the group cache for a group with this name */
- for(j = db->grpcache; j; j = j->next) {
- grp = j->data;
-
- if(strcmp(grp->name, grpname) == 0
- && !alpm_list_find_ptr(grp->packages, pkg)) {
- grp->packages = alpm_list_add(grp->packages, pkg);
- found = 1;
- break;
- }
- }
- if(found) {
- continue;
- }
- /* we didn't find the group, so create a new one with this name */
- grp = _alpm_grp_new(grpname);
- grp->packages = alpm_list_add(grp->packages, pkg);
- db->grpcache = alpm_list_add(db->grpcache, grp);
- }
- }
-
- db->grpcache_loaded = 1;
- return(0);
-}
-
-void _alpm_db_free_grpcache(pmdb_t *db)
-{
- alpm_list_t *lg;
-
- ALPM_LOG_FUNC;
-
- if(db == NULL || !db->grpcache_loaded) {
- return;
- }
-
- _alpm_log(PM_LOG_DEBUG, "freeing group cache for repository '%s'\n",
- db->treename);
-
- for(lg = db->grpcache; lg; lg = lg->next) {
- _alpm_grp_free(lg->data);
- lg->data = NULL;
- }
- FREELIST(db->grpcache);
- db->grpcache_loaded = 0;
-}
-
-alpm_list_t *_alpm_db_get_grpcache(pmdb_t *db)
-{
- ALPM_LOG_FUNC;
-
- if(db == NULL) {
- return(NULL);
- }
-
- if(!db->grpcache_loaded) {
- _alpm_db_load_grpcache(db);
- }
-
- return(db->grpcache);
-}
-
-pmgrp_t *_alpm_db_get_grpfromcache(pmdb_t *db, const char *target)
-{
- alpm_list_t *i;
-
- ALPM_LOG_FUNC;
-
- if(db == NULL || target == NULL || strlen(target) == 0) {
- return(NULL);
- }
-
- for(i = _alpm_db_get_grpcache(db); i; i = i->next) {
- pmgrp_t *info = i->data;
-
- if(strcmp(info->name, target) == 0) {
- return(info);
- }
- }
-
- return(NULL);
-}
-
-/* vim: set ts=2 sw=2 noet: */
diff --git a/lib/libalpm/cache.h b/lib/libalpm/cache.h
deleted file mode 100644
index 6ddcd186..00000000
--- a/lib/libalpm/cache.h
+++ /dev/null
@@ -1,44 +0,0 @@
-/*
- * cache.h
- *
- * Copyright (c) 2006-2010 Pacman Development Team <pacman-dev@archlinux.org>
- * Copyright (c) 2002-2006 by Judd Vinet <jvinet@zeroflux.org>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- */
-#ifndef _ALPM_CACHE_H
-#define _ALPM_CACHE_H
-
-#include "db.h"
-#include "alpm_list.h"
-#include "group.h"
-#include "package.h"
-
-/* packages */
-int _alpm_db_load_pkgcache(pmdb_t *db);
-void _alpm_db_free_pkgcache(pmdb_t *db);
-int _alpm_db_add_pkgincache(pmdb_t *db, pmpkg_t *pkg);
-int _alpm_db_remove_pkgfromcache(pmdb_t *db, pmpkg_t *pkg);
-alpm_list_t *_alpm_db_get_pkgcache(pmdb_t *db);
-int _alpm_db_ensure_pkgcache(pmdb_t *db, pmdbinfrq_t infolevel);
-pmpkg_t *_alpm_db_get_pkgfromcache(pmdb_t *db, const char *target);
-/* groups */
-int _alpm_db_load_grpcache(pmdb_t *db);
-void _alpm_db_free_grpcache(pmdb_t *db);
-alpm_list_t *_alpm_db_get_grpcache(pmdb_t *db);
-pmgrp_t *_alpm_db_get_grpfromcache(pmdb_t *db, const char *target);
-
-#endif /* _ALPM_CACHE_H */
-
-/* vim: set ts=2 sw=2 noet: */
diff --git a/lib/libalpm/conflict.c b/lib/libalpm/conflict.c
index e36844a8..fc25e7d3 100644
--- a/lib/libalpm/conflict.c
+++ b/lib/libalpm/conflict.c
@@ -1,7 +1,7 @@
/*
* conflict.c
*
- * Copyright (c) 2006-2010 Pacman Development Team <pacman-dev@archlinux.org>
+ * Copyright (c) 2006-2011 Pacman Development Team <pacman-dev@archlinux.org>
* Copyright (c) 2002-2006 by Judd Vinet <jvinet@zeroflux.org>
* Copyright (c) 2005 by Aurelien Foret <orelien@chez.com>
* Copyright (c) 2006 by David Kimpe <dnaku@frugalware.org>
@@ -38,7 +38,6 @@
#include "trans.h"
#include "util.h"
#include "log.h"
-#include "cache.h"
#include "deps.h"
pmconflict_t *_alpm_conflict_new(const char *package1, const char *package2, const char *reason)
@@ -88,8 +87,8 @@ int _alpm_conflict_isin(pmconflict_t *needle, alpm_list_t *haystack)
char *cpkg2 = conflict->package2;
char *npkg1 = needle->package1;
char *npkg2 = needle->package2;
- if((!strcmp(cpkg1, npkg1) && !strcmp(cpkg2, npkg2))
- || (!strcmp(cpkg1, npkg2) && !strcmp(cpkg2, npkg1))) {
+ if((strcmp(cpkg1, npkg1) == 0 && strcmp(cpkg2, npkg2) == 0)
+ || (strcmp(cpkg1, npkg2) == 0 && strcmp(cpkg2, npkg1) == 0)) {
return(1);
}
}
@@ -110,7 +109,7 @@ static int does_conflict(pmpkg_t *pkg1, const char *conflict, pmpkg_t *pkg2)
pmdepend_t *conf = _alpm_splitdep(conflict);
int match = 0;
- match = alpm_depcmp(pkg2, conf);
+ match = _alpm_depcmp(pkg2, conf);
if(match) {
_alpm_log(PM_LOG_DEBUG, "package %s conflicts with %s (by %s)\n",
pkg1name, pkg2name, conflict);
@@ -321,7 +320,7 @@ static alpm_list_t *chk_filedifference(alpm_list_t *filesA, alpm_list_t *filesB)
*/
static alpm_list_t *add_fileconflict(alpm_list_t *conflicts,
pmfileconflicttype_t type, const char *filestr,
- const char* name1, const char* name2)
+ const char* name1, const char* name2)
{
pmfileconflict_t *conflict;
MALLOC(conflict, sizeof(pmfileconflict_t), RET_ERR(PM_ERR_MEMORY, NULL));
@@ -403,8 +402,8 @@ alpm_list_t *_alpm_db_find_fileconflicts(pmdb_t *db, pmtrans_t *trans,
alpm_list_t *upgrade, alpm_list_t *remove)
{
alpm_list_t *i, *j, *conflicts = NULL;
- int numtargs = alpm_list_count(upgrade);
- int current;
+ size_t numtargs = alpm_list_count(upgrade);
+ size_t current;
ALPM_LOG_FUNC;
@@ -426,8 +425,8 @@ alpm_list_t *_alpm_db_find_fileconflicts(pmdb_t *db, pmtrans_t *trans,
continue;
}
- double percent = (double)current / numtargs;
- PROGRESS(trans, PM_TRANS_PROGRESS_CONFLICTS_START, "", (percent * 100),
+ int percent = (current * 100) / numtargs;
+ PROGRESS(trans, PM_TRANS_PROGRESS_CONFLICTS_START, "", percent,
numtargs, current);
/* CHECK 1: check every target against every target */
_alpm_log(PM_LOG_DEBUG, "searching for file conflicts: %s\n",
diff --git a/lib/libalpm/conflict.h b/lib/libalpm/conflict.h
index e60e5b3b..09b4f99b 100644
--- a/lib/libalpm/conflict.h
+++ b/lib/libalpm/conflict.h
@@ -1,7 +1,7 @@
/*
* conflict.h
*
- * Copyright (c) 2006-2010 Pacman Development Team <pacman-dev@archlinux.org>
+ * Copyright (c) 2006-2011 Pacman Development Team <pacman-dev@archlinux.org>
* Copyright (c) 2002-2006 by Judd Vinet <jvinet@zeroflux.org>
*
* This program is free software; you can redistribute it and/or modify
diff --git a/lib/libalpm/db.c b/lib/libalpm/db.c
index c8a91a2b..bf9a70d4 100644
--- a/lib/libalpm/db.c
+++ b/lib/libalpm/db.c
@@ -1,7 +1,7 @@
/*
* db.c
*
- * Copyright (c) 2006-2010 Pacman Development Team <pacman-dev@archlinux.org>
+ * Copyright (c) 2006-2011 Pacman Development Team <pacman-dev@archlinux.org>
* Copyright (c) 2002-2006 by Judd Vinet <jvinet@zeroflux.org>
* Copyright (c) 2005 by Aurelien Foret <orelien@chez.com>
* Copyright (c) 2005 by Christian Hamar <krics@linuxforum.hu>
@@ -29,7 +29,6 @@
#include <errno.h>
#include <string.h>
#include <sys/stat.h>
-#include <dirent.h>
#include <regex.h>
#include <time.h>
@@ -39,8 +38,9 @@
#include "log.h"
#include "util.h"
#include "handle.h"
-#include "cache.h"
#include "alpm.h"
+#include "package.h"
+#include "group.h"
/** \addtogroup alpm_databases Database Functions
* @brief Functions to query and manipulate the database of libalpm
@@ -80,7 +80,7 @@ pmdb_t SYMEXPORT *alpm_db_register_local(void)
}
/* Helper function for alpm_db_unregister{_all} */
-static void _alpm_db_unregister(pmdb_t *db)
+void _alpm_db_unregister(pmdb_t *db)
{
if(db == NULL) {
return;
@@ -96,6 +96,7 @@ static void _alpm_db_unregister(pmdb_t *db)
int SYMEXPORT alpm_db_unregister_all(void)
{
alpm_list_t *i;
+ pmdb_t *db;
ALPM_LOG_FUNC;
@@ -105,13 +106,16 @@ int SYMEXPORT alpm_db_unregister_all(void)
ASSERT(handle->trans == NULL, RET_ERR(PM_ERR_TRANS_NOT_NULL, -1));
/* close local database */
- _alpm_db_unregister(handle->db_local);
- handle->db_local = NULL;
+ db = handle->db_local;
+ if(db) {
+ db->ops->unregister(db);
+ handle->db_local = NULL;
+ }
/* and also sync ones */
for(i = handle->dbs_sync; i; i = i->next) {
- pmdb_t *db = i->data;
- _alpm_db_unregister(db);
+ db = i->data;
+ db->ops->unregister(db);
i->data = NULL;
}
FREELIST(handle->dbs_sync);
@@ -154,7 +158,7 @@ int SYMEXPORT alpm_db_unregister(pmdb_t *db)
RET_ERR(PM_ERR_DB_NOT_FOUND, -1);
}
- _alpm_db_unregister(db);
+ db->ops->unregister(db);
return(0);
}
@@ -168,7 +172,7 @@ int SYMEXPORT alpm_db_setserver(pmdb_t *db, const char *url)
alpm_list_t *i;
int found = 0;
char *newurl;
- int len = 0;
+ size_t len = 0;
ALPM_LOG_FUNC;
@@ -321,7 +325,7 @@ alpm_list_t SYMEXPORT *alpm_db_search(pmdb_t *db, const alpm_list_t* needles)
return(_alpm_db_search(db, needles));
}
-/* Set install reason for a package in db
+/** Set install reason for a package in db
* @param db pointer to the package database
* @param name the name of the package
* @param reason the new install reason
@@ -341,18 +345,14 @@ int SYMEXPORT alpm_db_set_pkgreason(pmdb_t *db, const char *name, pmpkgreason_t
}
_alpm_log(PM_LOG_DEBUG, "setting install reason %u for %s/%s\n", reason, db->treename, name);
- /* read DESC */
- if(_alpm_db_read(db, pkg, INFRQ_DESC)) {
- return(-1);
- }
- if(pkg->reason == reason) {
+ if(alpm_pkg_get_reason(pkg) == reason) {
/* we are done */
return(0);
}
/* set reason (in pkgcache) */
pkg->reason = reason;
/* write DESC */
- if(_alpm_db_write(db, pkg, INFRQ_DESC)) {
+ if(_alpm_local_db_write(db, pkg, INFRQ_DESC)) {
return(-1);
}
@@ -361,7 +361,7 @@ int SYMEXPORT alpm_db_set_pkgreason(pmdb_t *db, const char *name, pmpkgreason_t
/** @} */
-static pmdb_t *_alpm_db_new(const char *treename, int is_local)
+pmdb_t *_alpm_db_new(const char *treename, int is_local)
{
pmdb_t *db;
@@ -409,10 +409,10 @@ const char *_alpm_db_path(pmdb_t *db)
CALLOC(db->_path, 1, pathsize, RET_ERR(PM_ERR_MEMORY, NULL));
sprintf(db->_path, "%s%s/", dbpath, db->treename);
} else {
- pathsize = strlen(dbpath) + 5 + strlen(db->treename) + 2;
+ pathsize = strlen(dbpath) + 5 + strlen(db->treename) + 4;
CALLOC(db->_path, 1, pathsize, RET_ERR(PM_ERR_MEMORY, NULL));
/* all sync DBs now reside in the sync/ subdir of the dbpath */
- sprintf(db->_path, "%ssync/%s/", dbpath, db->treename);
+ sprintf(db->_path, "%ssync/%s.db", dbpath, db->treename);
}
_alpm_log(PM_LOG_DEBUG, "database path for tree %s set to %s\n",
db->treename, db->_path);
@@ -503,52 +503,246 @@ alpm_list_t *_alpm_db_search(pmdb_t *db, const alpm_list_t *needles)
return(ret);
}
-pmdb_t *_alpm_db_register_local(void)
+/* Returns a new package cache from db.
+ * It frees the cache if it already exists.
+ */
+int _alpm_db_load_pkgcache(pmdb_t *db)
{
- pmdb_t *db;
+ ALPM_LOG_FUNC;
+
+ if(db == NULL) {
+ return(-1);
+ }
+ _alpm_db_free_pkgcache(db);
+
+ _alpm_log(PM_LOG_DEBUG, "loading package cache for repository '%s'\n",
+ db->treename);
+ if(db->ops->populate(db) == -1) {
+ _alpm_log(PM_LOG_DEBUG,
+ "failed to load package cache for repository '%s'\n", db->treename);
+ return(-1);
+ }
+ db->pkgcache_loaded = 1;
+ return(0);
+}
+
+void _alpm_db_free_pkgcache(pmdb_t *db)
+{
ALPM_LOG_FUNC;
- if(handle->db_local != NULL) {
- _alpm_log(PM_LOG_WARNING, _("attempt to re-register the 'local' DB\n"));
- RET_ERR(PM_ERR_DB_NOT_NULL, NULL);
+ if(db == NULL || !db->pkgcache_loaded) {
+ return;
}
- _alpm_log(PM_LOG_DEBUG, "registering local database\n");
+ _alpm_log(PM_LOG_DEBUG, "freeing package cache for repository '%s'\n",
+ db->treename);
+
+ alpm_list_free_inner(db->pkgcache, (alpm_list_fn_free)_alpm_pkg_free);
+ alpm_list_free(db->pkgcache);
+ db->pkgcache_loaded = 0;
+
+ _alpm_db_free_grpcache(db);
+}
+
+alpm_list_t *_alpm_db_get_pkgcache(pmdb_t *db)
+{
+ ALPM_LOG_FUNC;
- db = _alpm_db_new("local", 1);
if(db == NULL) {
- RET_ERR(PM_ERR_DB_CREATE, NULL);
+ return(NULL);
}
- handle->db_local = db;
- return(db);
+ if(!db->pkgcache_loaded) {
+ _alpm_db_load_pkgcache(db);
+ }
+
+ /* hmmm, still NULL ?*/
+ if(!db->pkgcache) {
+ _alpm_log(PM_LOG_DEBUG, "warning: pkgcache is NULL for db '%s'\n", db->treename);
+ }
+
+ return(db->pkgcache);
}
-pmdb_t *_alpm_db_register_sync(const char *treename)
+/* "duplicate" pkg then add it to pkgcache */
+int _alpm_db_add_pkgincache(pmdb_t *db, pmpkg_t *pkg)
{
- pmdb_t *db;
- alpm_list_t *i;
+ pmpkg_t *newpkg;
ALPM_LOG_FUNC;
- for(i = handle->dbs_sync; i; i = i->next) {
- pmdb_t *sdb = i->data;
- if(strcmp(treename, sdb->treename) == 0) {
- _alpm_log(PM_LOG_DEBUG, "attempt to re-register the '%s' database, using existing\n", sdb->treename);
- return sdb;
+ if(db == NULL || !db->pkgcache_loaded || pkg == NULL) {
+ return(-1);
+ }
+
+ newpkg = _alpm_pkg_dup(pkg);
+ if(newpkg == NULL) {
+ return(-1);
+ }
+
+ _alpm_log(PM_LOG_DEBUG, "adding entry '%s' in '%s' cache\n",
+ alpm_pkg_get_name(newpkg), db->treename);
+ db->pkgcache = alpm_list_add_sorted(db->pkgcache, newpkg, _alpm_pkg_cmp);
+
+ _alpm_db_free_grpcache(db);
+
+ return(0);
+}
+
+int _alpm_db_remove_pkgfromcache(pmdb_t *db, pmpkg_t *pkg)
+{
+ void *vdata;
+ pmpkg_t *data;
+
+ ALPM_LOG_FUNC;
+
+ if(db == NULL || !db->pkgcache_loaded || pkg == NULL) {
+ return(-1);
+ }
+
+ _alpm_log(PM_LOG_DEBUG, "removing entry '%s' from '%s' cache\n",
+ alpm_pkg_get_name(pkg), db->treename);
+
+ db->pkgcache = alpm_list_remove(db->pkgcache, pkg, _alpm_pkg_cmp, &vdata);
+ data = vdata;
+ if(data == NULL) {
+ /* package not found */
+ _alpm_log(PM_LOG_DEBUG, "cannot remove entry '%s' from '%s' cache: not found\n",
+ alpm_pkg_get_name(pkg), db->treename);
+ return(-1);
+ }
+
+ _alpm_pkg_free(data);
+
+ _alpm_db_free_grpcache(db);
+
+ return(0);
+}
+
+pmpkg_t *_alpm_db_get_pkgfromcache(pmdb_t *db, const char *target)
+{
+ ALPM_LOG_FUNC;
+
+ if(db == NULL) {
+ return(NULL);
+ }
+
+ alpm_list_t *pkgcache = _alpm_db_get_pkgcache(db);
+ if(!pkgcache) {
+ _alpm_log(PM_LOG_DEBUG, "warning: failed to get '%s' from NULL pkgcache\n",
+ target);
+ return(NULL);
+ }
+
+ return(_alpm_pkg_find(pkgcache, target));
+}
+
+/* Returns a new group cache from db.
+ */
+int _alpm_db_load_grpcache(pmdb_t *db)
+{
+ alpm_list_t *lp;
+
+ ALPM_LOG_FUNC;
+
+ if(db == NULL) {
+ return(-1);
+ }
+
+ _alpm_log(PM_LOG_DEBUG, "loading group cache for repository '%s'\n",
+ db->treename);
+
+ for(lp = _alpm_db_get_pkgcache(db); lp; lp = lp->next) {
+ const alpm_list_t *i;
+ pmpkg_t *pkg = lp->data;
+
+ for(i = alpm_pkg_get_groups(pkg); i; i = i->next) {
+ const char *grpname = i->data;
+ alpm_list_t *j;
+ pmgrp_t *grp = NULL;
+ int found = 0;
+
+ /* first look through the group cache for a group with this name */
+ for(j = db->grpcache; j; j = j->next) {
+ grp = j->data;
+
+ if(strcmp(grp->name, grpname) == 0
+ && !alpm_list_find_ptr(grp->packages, pkg)) {
+ grp->packages = alpm_list_add(grp->packages, pkg);
+ found = 1;
+ break;
+ }
+ }
+ if(found) {
+ continue;
+ }
+ /* we didn't find the group, so create a new one with this name */
+ grp = _alpm_grp_new(grpname);
+ grp->packages = alpm_list_add(grp->packages, pkg);
+ db->grpcache = alpm_list_add(db->grpcache, grp);
}
}
- _alpm_log(PM_LOG_DEBUG, "registering sync database '%s'\n", treename);
+ db->grpcache_loaded = 1;
+ return(0);
+}
+
+void _alpm_db_free_grpcache(pmdb_t *db)
+{
+ alpm_list_t *lg;
+
+ ALPM_LOG_FUNC;
+
+ if(db == NULL || !db->grpcache_loaded) {
+ return;
+ }
+
+ _alpm_log(PM_LOG_DEBUG, "freeing group cache for repository '%s'\n",
+ db->treename);
+
+ for(lg = db->grpcache; lg; lg = lg->next) {
+ _alpm_grp_free(lg->data);
+ lg->data = NULL;
+ }
+ FREELIST(db->grpcache);
+ db->grpcache_loaded = 0;
+}
+
+alpm_list_t *_alpm_db_get_grpcache(pmdb_t *db)
+{
+ ALPM_LOG_FUNC;
- db = _alpm_db_new(treename, 0);
if(db == NULL) {
- RET_ERR(PM_ERR_DB_CREATE, NULL);
+ return(NULL);
}
- handle->dbs_sync = alpm_list_add(handle->dbs_sync, db);
- return(db);
+ if(!db->grpcache_loaded) {
+ _alpm_db_load_grpcache(db);
+ }
+
+ return(db->grpcache);
+}
+
+pmgrp_t *_alpm_db_get_grpfromcache(pmdb_t *db, const char *target)
+{
+ alpm_list_t *i;
+
+ ALPM_LOG_FUNC;
+
+ if(db == NULL || target == NULL || strlen(target) == 0) {
+ return(NULL);
+ }
+
+ for(i = _alpm_db_get_grpcache(db); i; i = i->next) {
+ pmgrp_t *info = i->data;
+
+ if(strcmp(info->name, target) == 0) {
+ return(info);
+ }
+ }
+
+ return(NULL);
}
/* vim: set ts=2 sw=2 noet: */
diff --git a/lib/libalpm/db.h b/lib/libalpm/db.h
index 1851b5c9..b7fa7ca6 100644
--- a/lib/libalpm/db.h
+++ b/lib/libalpm/db.h
@@ -1,7 +1,7 @@
/*
* db.h
*
- * Copyright (c) 2006-2010 Pacman Development Team <pacman-dev@archlinux.org>
+ * Copyright (c) 2006-2011 Pacman Development Team <pacman-dev@archlinux.org>
* Copyright (c) 2002-2006 by Judd Vinet <jvinet@zeroflux.org>
* Copyright (c) 2005 by Aurelien Foret <orelien@chez.com>
* Copyright (c) 2006 by Miklos Vajna <vmiklos@frugalware.org>
@@ -23,22 +23,28 @@
#define _ALPM_DB_H
#include "alpm.h"
-#include <limits.h>
#include <time.h>
+/* libarchive */
+#include <archive.h>
+#include <archive_entry.h>
+
/* Database entries */
typedef enum _pmdbinfrq_t {
INFRQ_BASE = 1,
INFRQ_DESC = (1 << 1),
- INFRQ_DEPENDS = (1 << 2),
- INFRQ_FILES = (1 << 3),
- INFRQ_SCRIPTLET = (1 << 4),
- INFRQ_DELTAS = (1 << 5),
- INFRQ_DSIZE = (1 << 6),
+ INFRQ_FILES = (1 << 2),
+ INFRQ_SCRIPTLET = (1 << 3),
+ INFRQ_DSIZE = (1 << 4),
/* ALL should be info stored in the package or database */
- INFRQ_ALL = 0x3F
+ INFRQ_ALL = 0x1F
} pmdbinfrq_t;
+struct db_operations {
+ int (*populate) (pmdb_t *);
+ void (*unregister) (pmdb_t *);
+};
+
/* Database */
struct __pmdb_t {
char *treename;
@@ -46,12 +52,16 @@ struct __pmdb_t {
char *_path;
int pkgcache_loaded;
int grpcache_loaded;
+ /* also indicates whether we are RO or RW */
int is_local;
alpm_list_t *pkgcache;
alpm_list_t *grpcache;
alpm_list_t *servers;
+
+ struct db_operations *ops;
};
+
/* db.c, database general calls */
void _alpm_db_free(pmdb_t *db);
const char *_alpm_db_path(pmdb_t *db);
@@ -59,13 +69,29 @@ int _alpm_db_cmp(const void *d1, const void *d2);
alpm_list_t *_alpm_db_search(pmdb_t *db, const alpm_list_t *needles);
pmdb_t *_alpm_db_register_local(void);
pmdb_t *_alpm_db_register_sync(const char *treename);
+void _alpm_db_unregister(pmdb_t *db);
+pmdb_t *_alpm_db_new(const char *treename, int is_local);
+
+/* be_*.c, backend specific calls */
+int _alpm_local_db_read(pmdb_t *db, pmpkg_t *info, pmdbinfrq_t inforeq);
+int _alpm_local_db_prepare(pmdb_t *db, pmpkg_t *info);
+int _alpm_local_db_write(pmdb_t *db, pmpkg_t *info, pmdbinfrq_t inforeq);
+int _alpm_local_db_remove(pmdb_t *db, pmpkg_t *info);
-/* be.c, backend specific calls */
-int _alpm_db_populate(pmdb_t *db);
-int _alpm_db_read(pmdb_t *db, pmpkg_t *info, pmdbinfrq_t inforeq);
-int _alpm_db_prepare(pmdb_t *db, pmpkg_t *info);
-int _alpm_db_write(pmdb_t *db, pmpkg_t *info, pmdbinfrq_t inforeq);
-int _alpm_db_remove(pmdb_t *db, pmpkg_t *info);
+/* cache bullshit */
+/* packages */
+int _alpm_db_load_pkgcache(pmdb_t *db);
+void _alpm_db_free_pkgcache(pmdb_t *db);
+int _alpm_db_add_pkgincache(pmdb_t *db, pmpkg_t *pkg);
+int _alpm_db_remove_pkgfromcache(pmdb_t *db, pmpkg_t *pkg);
+alpm_list_t *_alpm_db_get_pkgcache(pmdb_t *db);
+int _alpm_db_ensure_pkgcache(pmdb_t *db, pmdbinfrq_t infolevel);
+pmpkg_t *_alpm_db_get_pkgfromcache(pmdb_t *db, const char *target);
+/* groups */
+int _alpm_db_load_grpcache(pmdb_t *db);
+void _alpm_db_free_grpcache(pmdb_t *db);
+alpm_list_t *_alpm_db_get_grpcache(pmdb_t *db);
+pmgrp_t *_alpm_db_get_grpfromcache(pmdb_t *db, const char *target);
#endif /* _ALPM_DB_H */
diff --git a/lib/libalpm/delta.c b/lib/libalpm/delta.c
index 72835005..10c982f2 100644
--- a/lib/libalpm/delta.c
+++ b/lib/libalpm/delta.c
@@ -1,7 +1,7 @@
/*
* delta.c
*
- * Copyright (c) 2006-2010 Pacman Development Team <pacman-dev@archlinux.org>
+ * Copyright (c) 2006-2011 Pacman Development Team <pacman-dev@archlinux.org>
* Copyright (c) 2007-2006 by Judd Vinet <jvinet@zeroflux.org>
*
* This program is free software; you can redistribute it and/or modify
diff --git a/lib/libalpm/delta.h b/lib/libalpm/delta.h
index 76283380..d7a81c47 100644
--- a/lib/libalpm/delta.h
+++ b/lib/libalpm/delta.h
@@ -1,7 +1,7 @@
/*
* delta.h
*
- * Copyright (c) 2006-2010 Pacman Development Team <pacman-dev@archlinux.org>
+ * Copyright (c) 2006-2011 Pacman Development Team <pacman-dev@archlinux.org>
* Copyright (c) 2007-2006 by Judd Vinet <jvinet@zeroflux.org>
*
* This program is free software; you can redistribute it and/or modify
@@ -44,6 +44,9 @@ void _alpm_delta_free(pmdelta_t *delta);
off_t _alpm_shortest_delta_path(alpm_list_t *deltas,
const char *to, alpm_list_t **path);
+/* max percent of package size to download deltas */
+#define MAX_DELTA_RATIO 0.7
+
#endif /* _ALPM_DELTA_H */
/* vim: set ts=2 sw=2 noet: */
diff --git a/lib/libalpm/deps.c b/lib/libalpm/deps.c
index 26f9b16d..a7203b4b 100644
--- a/lib/libalpm/deps.c
+++ b/lib/libalpm/deps.c
@@ -1,7 +1,7 @@
/*
* deps.c
*
- * Copyright (c) 2006-2010 Pacman Development Team <pacman-dev@archlinux.org>
+ * Copyright (c) 2006-2011 Pacman Development Team <pacman-dev@archlinux.org>
* Copyright (c) 2002-2006 by Judd Vinet <jvinet@zeroflux.org>
* Copyright (c) 2005 by Aurelien Foret <orelien@chez.com>
* Copyright (c) 2005, 2006 by Miklos Vajna <vmiklos@frugalware.org>
@@ -34,7 +34,6 @@
#include "graph.h"
#include "package.h"
#include "db.h"
-#include "cache.h"
#include "handle.h"
void _alpm_dep_free(pmdepend_t *dep)
@@ -196,36 +195,25 @@ pmpkg_t *_alpm_find_dep_satisfier(alpm_list_t *pkgs, pmdepend_t *dep)
for(i = pkgs; i; i = alpm_list_next(i)) {
pmpkg_t *pkg = i->data;
- if(alpm_depcmp(pkg, dep)) {
+ if(_alpm_depcmp(pkg, dep)) {
return(pkg);
}
}
return(NULL);
}
-/** Checks dependencies and returns missing ones in a list.
- * Dependencies can include versions with depmod operators.
- * @param db pointer to the local package database
- * @param targets an alpm_list_t* of dependencies strings to satisfy
- * @return an alpm_list_t* of missing dependencies strings
+/** Find a package satisfying a specified dependency.
+ * The dependency can include versions with depmod operators.
+ * @param pkgs an alpm_list_t* of pmpkg_t where the satisfier will be searched
+ * @param depstring package or provision name, versioned or not
+ * @return a pmpkg_t* satisfying depstring
*/
-alpm_list_t SYMEXPORT *alpm_deptest(pmdb_t *db, alpm_list_t *targets)
+pmpkg_t SYMEXPORT *alpm_find_satisfier(alpm_list_t *pkgs, const char *depstring)
{
- alpm_list_t *i, *ret = NULL;
-
- for(i = targets; i; i = alpm_list_next(i)) {
- pmdepend_t *dep;
- char *target;
-
- target = alpm_list_getdata(i);
- dep = _alpm_splitdep(target);
-
- if(!_alpm_find_dep_satisfier(_alpm_db_get_pkgcache(db), dep)) {
- ret = alpm_list_add(ret, target);
- }
- _alpm_dep_free(dep);
- }
- return(ret);
+ pmdepend_t *dep = _alpm_splitdep(depstring);
+ pmpkg_t *pkg = _alpm_find_dep_satisfier(pkgs, dep);
+ _alpm_dep_free(dep);
+ return(pkg);
}
/** Checks dependencies and returns missing ones in a list.
@@ -248,8 +236,8 @@ alpm_list_t SYMEXPORT *alpm_checkdeps(alpm_list_t *pkglist, int reversedeps,
targets = alpm_list_join(alpm_list_copy(remove), alpm_list_copy(upgrade));
for(i = pkglist; i; i = i->next) {
- void *pkg = i->data;
- if(alpm_list_find(targets, pkg, _alpm_pkg_cmp)) {
+ pmpkg_t *pkg = i->data;
+ if(_alpm_pkg_find(targets, pkg->name)) {
modified = alpm_list_add(modified, pkg);
} else {
dblist = alpm_list_add(dblist, pkg);
@@ -331,35 +319,43 @@ static int dep_vercmp(const char *version1, pmdepmod_t mod,
return(equal);
}
-int SYMEXPORT alpm_depcmp(pmpkg_t *pkg, pmdepend_t *dep)
+int _alpm_depcmp(pmpkg_t *pkg, pmdepend_t *dep)
{
alpm_list_t *i;
-
- ALPM_LOG_FUNC;
-
- const char *pkgname = alpm_pkg_get_name(pkg);
- const char *pkgversion = alpm_pkg_get_version(pkg);
int satisfy = 0;
/* check (pkg->name, pkg->version) */
- satisfy = (strcmp(pkgname, dep->name) == 0
- && dep_vercmp(pkgversion, dep->mod, dep->version));
+ if(pkg->name_hash && dep->name_hash
+ && pkg->name_hash != dep->name_hash) {
+ /* skip more expensive checks */
+ } else {
+ satisfy = (strcmp(pkg->name, dep->name) == 0
+ && dep_vercmp(pkg->version, dep->mod, dep->version));
+ if(satisfy) {
+ return(satisfy);
+ }
+ }
/* check provisions, format : "name=version" */
for(i = alpm_pkg_get_provides(pkg); i && !satisfy; i = i->next) {
- char *provname = strdup(i->data);
- char *provver = strchr(provname, '=');
+ const char *provision = i->data;
+ const char *provver = strchr(provision, '=');
if(provver == NULL) { /* no provision version */
satisfy = (dep->mod == PM_DEP_MOD_ANY
- && strcmp(provname, dep->name) == 0);
+ && strcmp(provision, dep->name) == 0);
} else {
- *provver = '\0';
+ /* This is a bit tricker than the old code for performance reasons. To
+ * prevent the need to copy and duplicate strings, strncmp only the name
+ * portion if they are the same length, since there is a version and
+ * operator in play here. Cast is to silence sign conversion warning;
+ * we know provver >= provision if we are here. */
+ size_t namelen = (size_t)(provver - provision);
provver += 1;
- satisfy = (strcmp(provname, dep->name) == 0
+ satisfy = (strlen(dep->name) == namelen
+ && strncmp(provision, dep->name, namelen) == 0
&& dep_vercmp(provver, dep->mod, dep->version));
}
- free(provname);
}
return(satisfy);
@@ -368,52 +364,44 @@ int SYMEXPORT alpm_depcmp(pmpkg_t *pkg, pmdepend_t *dep)
pmdepend_t *_alpm_splitdep(const char *depstring)
{
pmdepend_t *depend;
- char *ptr = NULL;
- char *newstr = NULL;
+ const char *ptr, *version = NULL;
if(depstring == NULL) {
return(NULL);
}
- STRDUP(newstr, depstring, RET_ERR(PM_ERR_MEMORY, NULL));
CALLOC(depend, 1, sizeof(pmdepend_t), RET_ERR(PM_ERR_MEMORY, NULL));
/* Find a version comparator if one exists. If it does, set the type and
* increment the ptr accordingly so we can copy the right strings. */
- if((ptr = strstr(newstr, ">="))) {
+ if((ptr = strstr(depstring, ">="))) {
depend->mod = PM_DEP_MOD_GE;
- *ptr = '\0';
- ptr += 2;
- } else if((ptr = strstr(newstr, "<="))) {
+ version = ptr + 2;
+ } else if((ptr = strstr(depstring, "<="))) {
depend->mod = PM_DEP_MOD_LE;
- *ptr = '\0';
- ptr += 2;
- } else if((ptr = strstr(newstr, "="))) { /* Note: we must do =,<,> checks after <=, >= checks */
+ version = ptr + 2;
+ } else if((ptr = strstr(depstring, "="))) {
+ /* Note: we must do =,<,> checks after <=, >= checks */
depend->mod = PM_DEP_MOD_EQ;
- *ptr = '\0';
- ptr += 1;
- } else if((ptr = strstr(newstr, "<"))) {
+ version = ptr + 1;
+ } else if((ptr = strstr(depstring, "<"))) {
depend->mod = PM_DEP_MOD_LT;
- *ptr = '\0';
- ptr += 1;
- } else if((ptr = strstr(newstr, ">"))) {
+ version = ptr + 1;
+ } else if((ptr = strstr(depstring, ">"))) {
depend->mod = PM_DEP_MOD_GT;
- *ptr = '\0';
- ptr += 1;
+ version = ptr + 1;
} else {
- /* no version specified - copy the name and return it */
+ /* no version specified, leave version and ptr NULL */
depend->mod = PM_DEP_MOD_ANY;
- STRDUP(depend->name, newstr, RET_ERR(PM_ERR_MEMORY, NULL));
- depend->version = NULL;
- free(newstr);
- return(depend);
}
- /* if we get here, we have a version comparator, copy the right parts
- * to the right places */
- STRDUP(depend->name, newstr, RET_ERR(PM_ERR_MEMORY, NULL));
- STRDUP(depend->version, ptr, RET_ERR(PM_ERR_MEMORY, NULL));
- free(newstr);
+ /* copy the right parts to the right places */
+ STRNDUP(depend->name, depstring, ptr - depstring,
+ RET_ERR(PM_ERR_MEMORY, NULL));
+ depend->name_hash = _alpm_hash_sdbm(depend->name);
+ if(version) {
+ STRDUP(depend->version, version, RET_ERR(PM_ERR_MEMORY, NULL));
+ }
return(depend);
}
@@ -424,6 +412,7 @@ pmdepend_t *_alpm_dep_dup(const pmdepend_t *dep)
CALLOC(newdep, 1, sizeof(pmdepend_t), RET_ERR(PM_ERR_MEMORY, NULL));
STRDUP(newdep->name, dep->name, RET_ERR(PM_ERR_MEMORY, NULL));
+ newdep->name_hash = dep->name_hash;
STRDUP(newdep->version, dep->version, RET_ERR(PM_ERR_MEMORY, NULL));
newdep->mod = dep->mod;
@@ -525,7 +514,7 @@ pmpkg_t *_alpm_resolvedep(pmdepend_t *dep, alpm_list_t *dbs,
/* 1. literals */
for(i = dbs; i; i = i->next) {
pmpkg_t *pkg = _alpm_db_get_pkgfromcache(i->data, dep->name);
- if(pkg && alpm_depcmp(pkg, dep) && !_alpm_pkg_find(excluding, pkg->name)) {
+ if(pkg && _alpm_depcmp(pkg, dep) && !_alpm_pkg_find(excluding, pkg->name)) {
if(_alpm_pkg_should_ignore(pkg)) {
int install = 0;
if (prompt) {
@@ -546,7 +535,7 @@ pmpkg_t *_alpm_resolvedep(pmdepend_t *dep, alpm_list_t *dbs,
for(i = dbs; i; i = i->next) {
for(j = _alpm_db_get_pkgcache(i->data); j; j = j->next) {
pmpkg_t *pkg = j->data;
- if(alpm_depcmp(pkg, dep) && strcmp(pkg->name, dep->name) &&
+ if(_alpm_depcmp(pkg, dep) && strcmp(pkg->name, dep->name) != 0 &&
!_alpm_pkg_find(excluding, pkg->name)) {
if(_alpm_pkg_should_ignore(pkg)) {
int install = 0;
@@ -672,7 +661,7 @@ int _alpm_dep_edge(pmpkg_t *pkg1, pmpkg_t *pkg2)
{
alpm_list_t *i;
for(i = alpm_pkg_get_depends(pkg1); i; i = i->next) {
- if(alpm_depcmp(pkg2, i->data)) {
+ if(_alpm_depcmp(pkg2, i->data)) {
return(1);
}
}
diff --git a/lib/libalpm/deps.h b/lib/libalpm/deps.h
index ffc3aeeb..bd5e9a4c 100644
--- a/lib/libalpm/deps.h
+++ b/lib/libalpm/deps.h
@@ -1,7 +1,7 @@
/*
* deps.h
*
- * Copyright (c) 2006-2010 Pacman Development Team <pacman-dev@archlinux.org>
+ * Copyright (c) 2006-2011 Pacman Development Team <pacman-dev@archlinux.org>
* Copyright (c) 2002-2006 by Judd Vinet <jvinet@zeroflux.org>
* Copyright (c) 2005 by Aurelien Foret <orelien@chez.com>
* Copyright (c) 2006 by Miklos Vajna <vmiklos@frugalware.org>
@@ -29,9 +29,10 @@
/* Dependency */
struct __pmdepend_t {
- pmdepmod_t mod;
char *name;
char *version;
+ unsigned long name_hash;
+ pmdepmod_t mod;
};
/* Missing dependency */
@@ -55,6 +56,7 @@ int _alpm_resolvedeps(alpm_list_t *localpkgs, alpm_list_t *dbs_sync, pmpkg_t *pk
int _alpm_dep_edge(pmpkg_t *pkg1, pmpkg_t *pkg2);
pmdepend_t *_alpm_splitdep(const char *depstring);
pmpkg_t *_alpm_find_dep_satisfier(alpm_list_t *pkgs, pmdepend_t *dep);
+int _alpm_depcmp(pmpkg_t *pkg, pmdepend_t *dep);
#endif /* _ALPM_DEPS_H */
diff --git a/lib/libalpm/diskspace.c b/lib/libalpm/diskspace.c
new file mode 100644
index 00000000..dfafdac0
--- /dev/null
+++ b/lib/libalpm/diskspace.c
@@ -0,0 +1,337 @@
+/*
+ * diskspace.c
+ *
+ * Copyright (c) 2010-2011 Pacman Development Team <pacman-dev@archlinux.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "config.h"
+
+#if defined(HAVE_MNTENT_H)
+#include <mntent.h>
+#endif
+#if defined(HAVE_SYS_STATVFS_H)
+#include <sys/statvfs.h>
+#endif
+#if defined(HAVE_SYS_PARAM_H)
+#include <sys/param.h>
+#endif
+#if defined(HAVE_SYS_MOUNT_H)
+#include <sys/mount.h>
+#endif
+#if defined(HAVE_SYS_UCRED_H)
+#include <sys/ucred.h>
+#endif
+#if defined(HAVE_SYS_TYPES_H)
+#include <sys/types.h>
+#endif
+
+/* libarchive */
+#include <archive.h>
+#include <archive_entry.h>
+
+/* libalpm */
+#include "diskspace.h"
+#include "alpm_list.h"
+#include "util.h"
+#include "log.h"
+#include "trans.h"
+#include "handle.h"
+
+static int mount_point_cmp(const void *p1, const void *p2)
+{
+ const alpm_mountpoint_t *mp1 = p1;
+ const alpm_mountpoint_t *mp2 = p2;
+ return(strcmp(mp1->mount_dir, mp2->mount_dir));
+}
+
+static alpm_list_t *mount_point_list(void)
+{
+ alpm_list_t *mount_points = NULL;
+ alpm_mountpoint_t *mp;
+
+#if defined HAVE_GETMNTENT
+ struct mntent *mnt;
+ FILE *fp;
+ FSSTATSTYPE fsp;
+
+ fp = setmntent(MOUNTED, "r");
+
+ if (fp == NULL) {
+ return(NULL);
+ }
+
+ while((mnt = getmntent(fp))) {
+ if(statvfs(mnt->mnt_dir, &fsp) != 0) {
+ _alpm_log(PM_LOG_WARNING,
+ _("could not get filesystem information for %s\n"), mnt->mnt_dir);
+ continue;
+ }
+
+ MALLOC(mp, sizeof(alpm_mountpoint_t), RET_ERR(PM_ERR_MEMORY, NULL));
+ mp->mount_dir = strdup(mnt->mnt_dir);
+ memcpy(&(mp->fsp), &fsp, sizeof(FSSTATSTYPE));
+
+ mp->blocks_needed = 0l;
+ mp->max_blocks_needed = 0l;
+ mp->used = 0;
+
+ mount_points = alpm_list_add(mount_points, mp);
+ }
+
+ endmntent(fp);
+#elif defined HAVE_GETMNTINFO
+ int entries;
+ FSSTATSTYPE *fsp;
+
+ entries = getmntinfo(&fsp, MNT_NOWAIT);
+
+ if (entries < 0) {
+ return NULL;
+ }
+
+ for(; entries-- > 0; fsp++) {
+ MALLOC(mp, sizeof(alpm_mountpoint_t), RET_ERR(PM_ERR_MEMORY, NULL));
+ mp->mount_dir = strdup(fsp->f_mntonname);
+ memcpy(&(mp->fsp), fsp, sizeof(FSSTATSTYPE));
+
+ mp->blocks_needed = 0l;
+ mp->max_blocks_needed = 0l;
+ mp->used = 0;
+
+ mount_points = alpm_list_add(mount_points, mp);
+ }
+#endif
+
+ mount_points = alpm_list_msort(mount_points, alpm_list_count(mount_points),
+ mount_point_cmp);
+ return(mount_points);
+}
+
+static alpm_list_t *match_mount_point(const alpm_list_t *mount_points,
+ const char *file)
+{
+ char real_path[PATH_MAX];
+ snprintf(real_path, PATH_MAX, "%s%s", handle->root, file);
+
+ alpm_list_t *mp = alpm_list_last(mount_points);
+ do {
+ alpm_mountpoint_t *data = mp->data;
+
+ if(strncmp(data->mount_dir, real_path, strlen(data->mount_dir)) == 0) {
+ return(mp);
+ }
+
+ mp = mp->prev;
+ } while (mp != alpm_list_last(mount_points));
+
+ /* should not get here... */
+ return(NULL);
+}
+
+static int calculate_removed_size(const alpm_list_t *mount_points,
+ pmpkg_t *pkg)
+{
+ alpm_list_t *file;
+
+ alpm_list_t *files = alpm_pkg_get_files(pkg);
+ for(file = files; file; file = file->next) {
+ alpm_list_t *mp;
+ alpm_mountpoint_t *data;
+ struct stat st;
+ char path[PATH_MAX];
+ const char *filename = file->data;
+
+ /* skip directories to be consistent with libarchive that reports them
+ * to be zero size and to prevent multiple counting across packages */
+ if(*(filename + strlen(filename) - 1) == '/') {
+ continue;
+ }
+
+ mp = match_mount_point(mount_points, filename);
+ if(mp == NULL) {
+ _alpm_log(PM_LOG_WARNING,
+ _("could not determine mount point for file %s"), filename);
+ continue;
+ }
+
+ snprintf(path, PATH_MAX, "%s%s", handle->root, filename);
+ _alpm_lstat(path, &st);
+
+ /* skip symlinks to be consistent with libarchive that reports them to
+ * be zero size */
+ if(S_ISLNK(st.st_mode)) {
+ continue;
+ }
+
+ data = mp->data;
+ /* the addition of (divisor - 1) performs ceil() with integer division */
+ data->blocks_needed -=
+ (st.st_size + data->fsp.f_bsize - 1l) / data->fsp.f_bsize;
+ }
+
+ return(0);
+}
+
+static int calculate_installed_size(const alpm_list_t *mount_points,
+ pmpkg_t *pkg)
+{
+ int ret=0;
+ struct archive *archive;
+ struct archive_entry *entry;
+ const char *file;
+
+ if ((archive = archive_read_new()) == NULL) {
+ pm_errno = PM_ERR_LIBARCHIVE;
+ ret = -1;
+ goto cleanup;
+ }
+
+ archive_read_support_compression_all(archive);
+ archive_read_support_format_all(archive);
+
+ if(archive_read_open_filename(archive, pkg->origin_data.file,
+ ARCHIVE_DEFAULT_BYTES_PER_BLOCK) != ARCHIVE_OK) {
+ pm_errno = PM_ERR_PKG_OPEN;
+ ret = -1;
+ goto cleanup;
+ }
+
+ while(archive_read_next_header(archive, &entry) == ARCHIVE_OK) {
+ alpm_list_t *mp;
+ alpm_mountpoint_t *data;
+
+ file = archive_entry_pathname(entry);
+
+ /* approximate space requirements for db entries */
+ if(file[0] == '.') {
+ file = alpm_option_get_dbpath();
+ }
+
+ mp = match_mount_point(mount_points, file);
+ if(mp == NULL) {
+ _alpm_log(PM_LOG_WARNING,
+ _("could not determine mount point for file %s"), file);
+ continue;
+ }
+
+ data = mp->data;
+ /* the addition of (divisor - 1) performs ceil() with integer division */
+ data->blocks_needed +=
+ (archive_entry_size(entry) + data->fsp.f_bsize - 1l) / data->fsp.f_bsize;
+ data->used = 1;
+
+ if(archive_read_data_skip(archive)) {
+ _alpm_log(PM_LOG_ERROR, _("error while reading package %s: %s\n"),
+ pkg->name, archive_error_string(archive));
+ pm_errno = PM_ERR_LIBARCHIVE;
+ break;
+ }
+ }
+
+ archive_read_finish(archive);
+
+cleanup:
+ return(ret);
+}
+
+int _alpm_check_diskspace(pmtrans_t *trans, pmdb_t *db_local)
+{
+ alpm_list_t *mount_points, *i;
+ size_t replaces = 0, current = 0, numtargs;
+ int abort = 0;
+ alpm_list_t *targ;
+
+ numtargs = alpm_list_count(trans->add);
+ mount_points = mount_point_list();
+ if(mount_points == NULL) {
+ _alpm_log(PM_LOG_ERROR, _("could not determine filesystem mount points"));
+ return(-1);
+ }
+
+ replaces = alpm_list_count(trans->remove);
+ if(replaces) {
+ numtargs += replaces;
+ for(targ = trans->remove; targ; targ = targ->next, current++) {
+ pmpkg_t *local_pkg;
+ int percent = (current * 100) / numtargs;
+ PROGRESS(trans, PM_TRANS_PROGRESS_DISKSPACE_START, "", percent,
+ numtargs, current);
+
+ local_pkg = targ->data;
+ calculate_removed_size(mount_points, local_pkg);
+ }
+ }
+
+ for(targ = trans->add; targ; targ = targ->next, current++) {
+ pmpkg_t *pkg, *local_pkg;
+ int percent = (current * 100) / numtargs;
+ PROGRESS(trans, PM_TRANS_PROGRESS_DISKSPACE_START, "", percent,
+ numtargs, current);
+
+ pkg = targ->data;
+ /* is this package already installed? */
+ local_pkg = _alpm_db_get_pkgfromcache(db_local, pkg->name);
+ if(local_pkg) {
+ calculate_removed_size(mount_points, local_pkg);
+ }
+ calculate_installed_size(mount_points, pkg);
+
+ for(i = mount_points; i; i = alpm_list_next(i)) {
+ alpm_mountpoint_t *data = i->data;
+ if(data->blocks_needed > data->max_blocks_needed) {
+ data->max_blocks_needed = data->blocks_needed;
+ }
+ }
+ }
+
+ PROGRESS(trans, PM_TRANS_PROGRESS_DISKSPACE_START, "", 100,
+ numtargs, current);
+
+ for(i = mount_points; i; i = alpm_list_next(i)) {
+ alpm_mountpoint_t *data = i->data;
+ if(data->used == 1) {
+ /* cushion is roughly min(5% capacity, 20MiB) */
+ long fivepc = ((long)data->fsp.f_blocks / 20) + 1;
+ long twentymb = (20 * 1024 * 1024 / (long)data->fsp.f_bsize) + 1;
+ long cushion = fivepc < twentymb ? fivepc : twentymb;
+
+ _alpm_log(PM_LOG_DEBUG, "partition %s, needed %ld, cushion %ld, free %ld\n",
+ data->mount_dir, data->max_blocks_needed, cushion,
+ (unsigned long)data->fsp.f_bfree);
+ if(data->max_blocks_needed + cushion >= 0 &&
+ (unsigned long)(data->max_blocks_needed + cushion) > data->fsp.f_bfree) {
+ _alpm_log(PM_LOG_ERROR, _("Partition %s too full: %ld blocks needed, %ld blocks free)\n"),
+ data->mount_dir, data->max_blocks_needed + cushion,
+ (unsigned long)data->fsp.f_bfree);
+ abort = 1;
+ }
+ }
+ }
+
+ for(i = mount_points; i; i = alpm_list_next(i)) {
+ alpm_mountpoint_t *data = i->data;
+ FREE(data->mount_dir);
+ }
+ FREELIST(mount_points);
+
+ if(abort) {
+ RET_ERR(PM_ERR_DISK_SPACE, -1);
+ }
+
+ return(0);
+}
+
+/* vim: set ts=2 sw=2 noet: */
diff --git a/lib/libalpm/diskspace.h b/lib/libalpm/diskspace.h
new file mode 100644
index 00000000..25b9cfbf
--- /dev/null
+++ b/lib/libalpm/diskspace.h
@@ -0,0 +1,46 @@
+/*
+ * diskspace.h
+ *
+ * Copyright (c) 2010-2011 Pacman Development Team <pacman-dev@archlinux.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef _ALPM_DISKSPACE_H
+#define _ALPM_DISKSPACE_H
+
+#if defined(HAVE_SYS_MOUNT_H)
+#include <sys/mount.h>
+#endif
+#if defined(HAVE_SYS_STATVFS_H)
+#include <sys/statvfs.h>
+#endif
+
+#include "alpm.h"
+
+typedef struct __alpm_mountpoint_t {
+ /* mount point information */
+ char *mount_dir;
+ /* storage for additional disk usage calculations */
+ long blocks_needed;
+ long max_blocks_needed;
+ int used;
+ FSSTATSTYPE fsp;
+} alpm_mountpoint_t;
+
+int _alpm_check_diskspace(pmtrans_t *trans, pmdb_t *db_local);
+
+#endif /* _ALPM_DISKSPACE_H */
+
+/* vim: set ts=2 sw=2 noet: */
diff --git a/lib/libalpm/dload.c b/lib/libalpm/dload.c
index c11148d1..cb6d000c 100644
--- a/lib/libalpm/dload.c
+++ b/lib/libalpm/dload.c
@@ -1,7 +1,7 @@
/*
* download.c
*
- * Copyright (c) 2006-2010 Pacman Development Team <pacman-dev@archlinux.org>
+ * Copyright (c) 2006-2011 Pacman Development Team <pacman-dev@archlinux.org>
* Copyright (c) 2002-2006 by Judd Vinet <jvinet@zeroflux.org>
*
* This program is free software; you can redistribute it and/or modify
@@ -29,16 +29,13 @@
#include <sys/types.h>
#include <sys/stat.h>
#include <signal.h>
-#include <limits.h>
-/* the following two are needed on BSD for libfetch */
-#if defined(HAVE_SYS_SYSLIMITS_H)
-#include <sys/syslimits.h> /* PATH_MAX */
-#endif
+/* the following two are needed for FreeBSD's libfetch */
+#include <limits.h> /* PATH_MAX */
#if defined(HAVE_SYS_PARAM_H)
#include <sys/param.h> /* MAXHOSTNAMELEN */
#endif
-#if defined(INTERNAL_DOWNLOAD)
+#ifdef HAVE_LIBFETCH
#include <fetch.h>
#endif
@@ -58,7 +55,7 @@ static char *get_filename(const char *url) {
return(filename);
}
-#if defined(INTERNAL_DOWNLOAD)
+#ifdef HAVE_LIBFETCH
static char *get_destfile(const char *path, const char *filename) {
char *destfile;
/* len = localpath len + filename len + null */
@@ -89,7 +86,7 @@ static const char *gethost(struct url *fileurl)
}
int dload_interrupted;
-static RETSIGTYPE inthandler(int signum)
+static void inthandler(int signum)
{
dload_interrupted = 1;
}
@@ -250,8 +247,8 @@ static int download_internal(const char *url, const char *localpath,
while((nread = fetchIO_read(dlf, buffer, PM_DLBUF_LEN)) > 0) {
check_stop();
size_t nwritten = 0;
- nwritten = fwrite(buffer, 1, nread, localf);
- if((nwritten != nread) || ferror(localf)) {
+ nwritten = fwrite(buffer, 1, (size_t)nread, localf);
+ if((nwritten != (size_t)nread) || ferror(localf)) {
pm_errno = PM_ERR_RETRIEVE;
_alpm_log(PM_LOG_ERROR, _("error writing to file '%s': %s\n"),
tempfile, strerror(errno));
@@ -338,7 +335,7 @@ cleanup:
static int download(const char *url, const char *localpath,
int force) {
if(handle->fetchcb == NULL) {
-#if defined(INTERNAL_DOWNLOAD)
+#ifdef HAVE_LIBFETCH
return(download_internal(url, localpath, force));
#else
RET_ERR(PM_ERR_EXTERNAL_DOWNLOAD, -1);
diff --git a/lib/libalpm/dload.h b/lib/libalpm/dload.h
index e60174e4..63266491 100644
--- a/lib/libalpm/dload.h
+++ b/lib/libalpm/dload.h
@@ -1,7 +1,7 @@
/*
* dload.h
*
- * Copyright (c) 2006-2010 Pacman Development Team <pacman-dev@archlinux.org>
+ * Copyright (c) 2006-2011 Pacman Development Team <pacman-dev@archlinux.org>
* Copyright (c) 2002-2006 by Judd Vinet <jvinet@zeroflux.org>
*
* This program is free software; you can redistribute it and/or modify
diff --git a/lib/libalpm/error.c b/lib/libalpm/error.c
index 8d8d0458..1b144a5a 100644
--- a/lib/libalpm/error.c
+++ b/lib/libalpm/error.c
@@ -1,7 +1,7 @@
/*
* error.c
*
- * Copyright (c) 2006-2010 Pacman Development Team <pacman-dev@archlinux.org>
+ * Copyright (c) 2006-2011 Pacman Development Team <pacman-dev@archlinux.org>
* Copyright (c) 2002-2006 by Judd Vinet <jvinet@zeroflux.org>
*
* This program is free software; you can redistribute it and/or modify
@@ -22,16 +22,13 @@
/* TODO: needed for the libfetch stuff, unfortunately- we should kill it */
#include <stdio.h>
-#include <limits.h>
-/* the following two are needed on BSD for libfetch */
-#if defined(HAVE_SYS_SYSLIMITS_H)
-#include <sys/syslimits.h> /* PATH_MAX */
-#endif
+/* the following two are needed for FreeBSD's libfetch */
+#include <limits.h> /* PATH_MAX */
#if defined(HAVE_SYS_PARAM_H)
#include <sys/param.h> /* MAXHOSTNAMELEN */
#endif
-#if defined(INTERNAL_DOWNLOAD)
+#ifdef HAVE_LIBFETCH
#include <fetch.h> /* fetchLastErrString */
#endif
@@ -60,6 +57,8 @@ const char SYMEXPORT *alpm_strerror(int err)
return _("could not find or read directory");
case PM_ERR_WRONG_ARGS:
return _("wrong or NULL argument passed");
+ case PM_ERR_DISK_SPACE:
+ return _("not enough free disk space");
/* Interface */
case PM_ERR_HANDLE_NULL:
return _("library not initialized");
@@ -145,7 +144,7 @@ const char SYMEXPORT *alpm_strerror(int err)
* error string instead. */
return _("libarchive error");
case PM_ERR_LIBFETCH:
-#if defined(INTERNAL_DOWNLOAD)
+#ifdef HAVE_LIBFETCH
return fetchLastErrString;
#else
/* obviously shouldn't get here... */
diff --git a/lib/libalpm/graph.h b/lib/libalpm/graph.h
index c82e6811..69f65000 100644
--- a/lib/libalpm/graph.h
+++ b/lib/libalpm/graph.h
@@ -1,7 +1,7 @@
/*
* graph.h - helpful graph structure and setup/teardown methods
*
- * Copyright (c) 2006-2010 Pacman Development Team <pacman-dev@archlinux.org>
+ * Copyright (c) 2006-2011 Pacman Development Team <pacman-dev@archlinux.org>
* Copyright (c) 2002-2006 by Judd Vinet <jvinet@zeroflux.org>
*
* This program is free software; you can redistribute it and/or modify
diff --git a/lib/libalpm/group.c b/lib/libalpm/group.c
index 061bb0e4..398c2588 100644
--- a/lib/libalpm/group.c
+++ b/lib/libalpm/group.c
@@ -1,7 +1,7 @@
/*
* group.c
*
- * Copyright (c) 2006-2010 Pacman Development Team <pacman-dev@archlinux.org>
+ * Copyright (c) 2006-2011 Pacman Development Team <pacman-dev@archlinux.org>
* Copyright (c) 2002-2006 by Judd Vinet <jvinet@zeroflux.org>
*
* This program is free software; you can redistribute it and/or modify
diff --git a/lib/libalpm/group.h b/lib/libalpm/group.h
index 5d8cf775..c92684e3 100644
--- a/lib/libalpm/group.h
+++ b/lib/libalpm/group.h
@@ -1,7 +1,7 @@
/*
* group.h
*
- * Copyright (c) 2006-2010 Pacman Development Team <pacman-dev@archlinux.org>
+ * Copyright (c) 2006-2011 Pacman Development Team <pacman-dev@archlinux.org>
* Copyright (c) 2002-2006 by Judd Vinet <jvinet@zeroflux.org>
*
* This program is free software; you can redistribute it and/or modify
diff --git a/lib/libalpm/handle.c b/lib/libalpm/handle.c
index aa34cf45..8872ed0a 100644
--- a/lib/libalpm/handle.c
+++ b/lib/libalpm/handle.c
@@ -1,7 +1,7 @@
/*
* handle.c
*
- * Copyright (c) 2006-2010 Pacman Development Team <pacman-dev@archlinux.org>
+ * Copyright (c) 2006-2011 Pacman Development Team <pacman-dev@archlinux.org>
* Copyright (c) 2002-2006 by Judd Vinet <jvinet@zeroflux.org>
* Copyright (c) 2005 by Aurelien Foret <orelien@chez.com>
* Copyright (c) 2005, 2006 by Miklos Vajna <vmiklos@frugalware.org>
@@ -232,6 +232,15 @@ int SYMEXPORT alpm_option_get_usedelta()
return handle->usedelta;
}
+int SYMEXPORT alpm_option_get_checkspace()
+{
+ if (handle == NULL) {
+ pm_errno = PM_ERR_HANDLE_NULL;
+ return -1;
+ }
+ return handle->checkspace;
+}
+
pmdb_t SYMEXPORT *alpm_option_get_localdb()
{
if (handle == NULL) {
@@ -550,4 +559,9 @@ void SYMEXPORT alpm_option_set_usedelta(int usedelta)
handle->usedelta = usedelta;
}
+void SYMEXPORT alpm_option_set_checkspace(int checkspace)
+{
+ handle->checkspace = checkspace;
+}
+
/* vim: set ts=2 sw=2 noet: */
diff --git a/lib/libalpm/handle.h b/lib/libalpm/handle.h
index 1834994e..fa29d112 100644
--- a/lib/libalpm/handle.h
+++ b/lib/libalpm/handle.h
@@ -1,7 +1,7 @@
/*
* handle.h
*
- * Copyright (c) 2006-2010 Pacman Development Team <pacman-dev@archlinux.org>
+ * Copyright (c) 2006-2011 Pacman Development Team <pacman-dev@archlinux.org>
* Copyright (c) 2002-2006 by Judd Vinet <jvinet@zeroflux.org>
*
* This program is free software; you can redistribute it and/or modify
@@ -60,12 +60,13 @@ typedef struct _pmhandle_t {
int usesyslog; /* Use syslog instead of logfile? */ /* TODO move to frontend */
char *arch; /* Architecture of packages we should allow */
int usedelta; /* Download deltas if possible */
+ int checkspace; /* Check disk space before installing */
} pmhandle_t;
/* global handle variable */
extern pmhandle_t *handle;
-pmhandle_t *_alpm_handle_new();
+pmhandle_t *_alpm_handle_new(void);
void _alpm_handle_free(pmhandle_t *handle);
#endif /* _ALPM_HANDLE_H */
diff --git a/lib/libalpm/log.c b/lib/libalpm/log.c
index 86bb8257..dc4f938a 100644
--- a/lib/libalpm/log.c
+++ b/lib/libalpm/log.c
@@ -1,7 +1,7 @@
/*
* log.c
*
- * Copyright (c) 2006-2010 Pacman Development Team <pacman-dev@archlinux.org>
+ * Copyright (c) 2006-2011 Pacman Development Team <pacman-dev@archlinux.org>
* Copyright (c) 2002-2006 by Judd Vinet <jvinet@zeroflux.org>
*
* This program is free software; you can redistribute it and/or modify
diff --git a/lib/libalpm/log.h b/lib/libalpm/log.h
index d358733f..5ce08e45 100644
--- a/lib/libalpm/log.h
+++ b/lib/libalpm/log.h
@@ -1,7 +1,7 @@
/*
* log.h
*
- * Copyright (c) 2006-2010 Pacman Development Team <pacman-dev@archlinux.org>
+ * Copyright (c) 2006-2011 Pacman Development Team <pacman-dev@archlinux.org>
* Copyright (c) 2002-2006 by Judd Vinet <jvinet@zeroflux.org>
*
* This program is free software; you can redistribute it and/or modify
diff --git a/lib/libalpm/md5.c b/lib/libalpm/md5.c
index 7d2716f2..90635046 100644
--- a/lib/libalpm/md5.c
+++ b/lib/libalpm/md5.c
@@ -36,6 +36,8 @@
* int md5_file( char *path, unsigned char *output )
* to
* int md5_file( const char *path, unsigned char *output )
+ * * use a dynamically-allocated buffer in md5_file, and increase the size
+ * for performance reasons
* * various static/inline changes
*
* NOTE: XySSL has been renamed to PolarSSL, which is available at
@@ -44,6 +46,7 @@
#include <string.h>
#include <stdio.h>
+#include <stdlib.h>
#include "md5.h"
@@ -309,11 +312,16 @@ int md5_file( const char *path, unsigned char output[16] )
FILE *f;
size_t n;
md5_context ctx;
- unsigned char buf[1024];
+ unsigned char *buf;
- if( ( f = fopen( path, "rb" ) ) == NULL )
+ if( ( buf = calloc(8192, sizeof(unsigned char)) ) == NULL )
return( 1 );
+ if( ( f = fopen( path, "rb" ) ) == NULL ) {
+ free( buf );
+ return( 1 );
+ }
+
md5_starts( &ctx );
while( ( n = fread( buf, 1, sizeof( buf ), f ) ) > 0 )
@@ -322,6 +330,7 @@ int md5_file( const char *path, unsigned char output[16] )
md5_finish( &ctx, output );
memset( &ctx, 0, sizeof( md5_context ) );
+ free( buf );
if( ferror( f ) != 0 )
{
diff --git a/lib/libalpm/package.c b/lib/libalpm/package.c
index becbc60f..d4b3b9c0 100644
--- a/lib/libalpm/package.c
+++ b/lib/libalpm/package.c
@@ -1,7 +1,7 @@
/*
* package.c
*
- * Copyright (c) 2006-2010 Pacman Development Team <pacman-dev@archlinux.org>
+ * Copyright (c) 2006-2011 Pacman Development Team <pacman-dev@archlinux.org>
* Copyright (c) 2002-2006 by Judd Vinet <jvinet@zeroflux.org>
* Copyright (c) 2005 by Aurelien Foret <orelien@chez.com>
* Copyright (c) 2005, 2006 by Christian Hamar <krics@linuxforum.hu>
@@ -25,24 +25,18 @@
#include <stdio.h>
#include <stdlib.h>
-#include <limits.h>
#include <string.h>
#include <ctype.h>
#include <errno.h>
#include <sys/types.h>
#include <sys/stat.h>
-/* libarchive */
-#include <archive.h>
-#include <archive_entry.h>
-
/* libalpm */
#include "package.h"
#include "alpm_list.h"
#include "log.h"
#include "util.h"
#include "db.h"
-#include "cache.h"
#include "delta.h"
#include "handle.h"
#include "deps.h"
@@ -63,7 +57,7 @@ int SYMEXPORT alpm_pkg_free(pmpkg_t *pkg)
ASSERT(pkg != NULL, RET_ERR(PM_ERR_WRONG_ARGS, -1));
/* Only free packages loaded in user space */
- if(pkg->origin != PKG_FROM_CACHE) {
+ if(pkg->origin == PKG_FROM_FILE) {
_alpm_pkg_free(pkg);
}
@@ -83,8 +77,7 @@ int SYMEXPORT alpm_pkg_checkmd5sum(pmpkg_t *pkg)
ASSERT(pkg != NULL, RET_ERR(PM_ERR_WRONG_ARGS, -1));
/* We only inspect packages from sync repositories */
- ASSERT(pkg->origin == PKG_FROM_CACHE, RET_ERR(PM_ERR_PKG_INVALID, -1));
- ASSERT(pkg->origin_data.db != handle->db_local, RET_ERR(PM_ERR_PKG_INVALID, -1));
+ ASSERT(pkg->origin == PKG_FROM_SYNCDB, RET_ERR(PM_ERR_PKG_INVALID, -1));
fpath = _alpm_filecache_find(alpm_pkg_get_filename(pkg));
@@ -100,334 +93,189 @@ int SYMEXPORT alpm_pkg_checkmd5sum(pmpkg_t *pkg)
return(retval);
}
+/* Default package accessor functions. These will get overridden by any
+ * backend logic that needs lazy access, such as the local database through
+ * a lazy-load cache. However, the defaults will work just fine for fully-
+ * populated package structures. */
+static const char *_pkg_get_filename(pmpkg_t *pkg) { return pkg->filename; }
+static const char *_pkg_get_name(pmpkg_t *pkg) { return pkg->name; }
+static const char *_pkg_get_version(pmpkg_t *pkg) { return pkg->version; }
+static const char *_pkg_get_desc(pmpkg_t *pkg) { return pkg->desc; }
+static const char *_pkg_get_url(pmpkg_t *pkg) { return pkg->url; }
+static time_t _pkg_get_builddate(pmpkg_t *pkg) { return pkg->builddate; }
+static time_t _pkg_get_installdate(pmpkg_t *pkg) { return pkg->installdate; }
+static const char *_pkg_get_packager(pmpkg_t *pkg) { return pkg->packager; }
+static const char *_pkg_get_md5sum(pmpkg_t *pkg) { return pkg->md5sum; }
+static const char *_pkg_get_arch(pmpkg_t *pkg) { return pkg->arch; }
+static off_t _pkg_get_size(pmpkg_t *pkg) { return pkg->size; }
+static off_t _pkg_get_isize(pmpkg_t *pkg) { return pkg->isize; }
+static pmpkgreason_t _pkg_get_reason(pmpkg_t *pkg) { return pkg->reason; }
+static int _pkg_has_scriptlet(pmpkg_t *pkg) { return pkg->scriptlet; }
+
+static alpm_list_t *_pkg_get_licenses(pmpkg_t *pkg) { return pkg->licenses; }
+static alpm_list_t *_pkg_get_groups(pmpkg_t *pkg) { return pkg->groups; }
+static alpm_list_t *_pkg_get_depends(pmpkg_t *pkg) { return pkg->depends; }
+static alpm_list_t *_pkg_get_optdepends(pmpkg_t *pkg) { return pkg->optdepends; }
+static alpm_list_t *_pkg_get_conflicts(pmpkg_t *pkg) { return pkg->conflicts; }
+static alpm_list_t *_pkg_get_provides(pmpkg_t *pkg) { return pkg->provides; }
+static alpm_list_t *_pkg_get_replaces(pmpkg_t *pkg) { return pkg->replaces; }
+static alpm_list_t *_pkg_get_deltas(pmpkg_t *pkg) { return pkg->deltas; }
+static alpm_list_t *_pkg_get_files(pmpkg_t *pkg) { return pkg->files; }
+static alpm_list_t *_pkg_get_backup(pmpkg_t *pkg) { return pkg->backup; }
+
+/** The standard package operations struct. Get fields directly from the
+ * struct itself with no abstraction layer or any type of lazy loading.
+ */
+struct pkg_operations default_pkg_ops = {
+ .get_filename = _pkg_get_filename,
+ .get_name = _pkg_get_name,
+ .get_version = _pkg_get_version,
+ .get_desc = _pkg_get_desc,
+ .get_url = _pkg_get_url,
+ .get_builddate = _pkg_get_builddate,
+ .get_installdate = _pkg_get_installdate,
+ .get_packager = _pkg_get_packager,
+ .get_md5sum = _pkg_get_md5sum,
+ .get_arch = _pkg_get_arch,
+ .get_size = _pkg_get_size,
+ .get_isize = _pkg_get_isize,
+ .get_reason = _pkg_get_reason,
+ .has_scriptlet = _pkg_has_scriptlet,
+ .get_licenses = _pkg_get_licenses,
+ .get_groups = _pkg_get_groups,
+ .get_depends = _pkg_get_depends,
+ .get_optdepends = _pkg_get_optdepends,
+ .get_conflicts = _pkg_get_conflicts,
+ .get_provides = _pkg_get_provides,
+ .get_replaces = _pkg_get_replaces,
+ .get_deltas = _pkg_get_deltas,
+ .get_files = _pkg_get_files,
+ .get_backup = _pkg_get_backup,
+};
+
+/* Public functions for getting package information. These functions
+ * delegate the hard work to the function callbacks attached to each
+ * package, which depend on where the package was loaded from. */
const char SYMEXPORT *alpm_pkg_get_filename(pmpkg_t *pkg)
{
- ALPM_LOG_FUNC;
-
- /* Sanity checks */
- ASSERT(handle != NULL, return(NULL));
- ASSERT(pkg != NULL, return(NULL));
-
- if(pkg->origin == PKG_FROM_CACHE && !(pkg->infolevel & INFRQ_DESC)) {
- _alpm_db_read(pkg->origin_data.db, pkg, INFRQ_DESC);
- }
-
- return pkg->filename;
+ return pkg->ops->get_filename(pkg);
}
const char SYMEXPORT *alpm_pkg_get_name(pmpkg_t *pkg)
{
- ASSERT(pkg != NULL, return(NULL));
- return pkg->name;
+ return pkg->ops->get_name(pkg);
}
const char SYMEXPORT *alpm_pkg_get_version(pmpkg_t *pkg)
{
- ASSERT(pkg != NULL, return(NULL));
- return pkg->version;
+ return pkg->ops->get_version(pkg);
}
const char SYMEXPORT *alpm_pkg_get_desc(pmpkg_t *pkg)
{
- ALPM_LOG_FUNC;
-
- /* Sanity checks */
- ASSERT(handle != NULL, return(NULL));
- ASSERT(pkg != NULL, return(NULL));
-
- if(pkg->origin == PKG_FROM_CACHE && !(pkg->infolevel & INFRQ_DESC)) {
- _alpm_db_read(pkg->origin_data.db, pkg, INFRQ_DESC);
- }
- return pkg->desc;
+ return pkg->ops->get_desc(pkg);
}
const char SYMEXPORT *alpm_pkg_get_url(pmpkg_t *pkg)
{
- ALPM_LOG_FUNC;
-
- /* Sanity checks */
- ASSERT(handle != NULL, return(NULL));
- ASSERT(pkg != NULL, return(NULL));
-
- if(pkg->origin == PKG_FROM_CACHE && !(pkg->infolevel & INFRQ_DESC)) {
- _alpm_db_read(pkg->origin_data.db, pkg, INFRQ_DESC);
- }
- return pkg->url;
+ return pkg->ops->get_url(pkg);
}
time_t SYMEXPORT alpm_pkg_get_builddate(pmpkg_t *pkg)
{
- ALPM_LOG_FUNC;
-
- /* Sanity checks */
- ASSERT(handle != NULL, return(0));
- ASSERT(pkg != NULL, return(0));
-
- if(pkg->origin == PKG_FROM_CACHE && !(pkg->infolevel & INFRQ_DESC)) {
- _alpm_db_read(pkg->origin_data.db, pkg, INFRQ_DESC);
- }
- return pkg->builddate;
+ return pkg->ops->get_builddate(pkg);
}
time_t SYMEXPORT alpm_pkg_get_installdate(pmpkg_t *pkg)
{
- ALPM_LOG_FUNC;
-
- /* Sanity checks */
- ASSERT(handle != NULL, return(0));
- ASSERT(pkg != NULL, return(0));
-
- if(pkg->origin == PKG_FROM_CACHE && !(pkg->infolevel & INFRQ_DESC)) {
- _alpm_db_read(pkg->origin_data.db, pkg, INFRQ_DESC);
- }
- return pkg->installdate;
+ return pkg->ops->get_installdate(pkg);
}
const char SYMEXPORT *alpm_pkg_get_packager(pmpkg_t *pkg)
{
- ALPM_LOG_FUNC;
-
- /* Sanity checks */
- ASSERT(handle != NULL, return(NULL));
- ASSERT(pkg != NULL, return(NULL));
-
- if(pkg->origin == PKG_FROM_CACHE && !(pkg->infolevel & INFRQ_DESC)) {
- _alpm_db_read(pkg->origin_data.db, pkg, INFRQ_DESC);
- }
- return pkg->packager;
+ return pkg->ops->get_packager(pkg);
}
const char SYMEXPORT *alpm_pkg_get_md5sum(pmpkg_t *pkg)
{
- ALPM_LOG_FUNC;
-
- /* Sanity checks */
- ASSERT(handle != NULL, return(NULL));
- ASSERT(pkg != NULL, return(NULL));
-
- if(pkg->origin == PKG_FROM_CACHE && !(pkg->infolevel & INFRQ_DESC)) {
- _alpm_db_read(pkg->origin_data.db, pkg, INFRQ_DESC);
- }
- return pkg->md5sum;
+ return pkg->ops->get_md5sum(pkg);
}
const char SYMEXPORT *alpm_pkg_get_arch(pmpkg_t *pkg)
{
- ALPM_LOG_FUNC;
-
- /* Sanity checks */
- ASSERT(handle != NULL, return(NULL));
- ASSERT(pkg != NULL, return(NULL));
-
- if(pkg->origin == PKG_FROM_CACHE && !(pkg->infolevel & INFRQ_DESC)) {
- _alpm_db_read(pkg->origin_data.db, pkg, INFRQ_DESC);
- }
- return pkg->arch;
+ return pkg->ops->get_arch(pkg);
}
off_t SYMEXPORT alpm_pkg_get_size(pmpkg_t *pkg)
{
- ALPM_LOG_FUNC;
-
- /* Sanity checks */
- ASSERT(handle != NULL, return(-1));
- ASSERT(pkg != NULL, return(-1));
-
- if(pkg->origin == PKG_FROM_CACHE && !(pkg->infolevel & INFRQ_DESC)) {
- _alpm_db_read(pkg->origin_data.db, pkg, INFRQ_DESC);
- }
- return pkg->size;
+ return pkg->ops->get_size(pkg);
}
off_t SYMEXPORT alpm_pkg_get_isize(pmpkg_t *pkg)
{
- ALPM_LOG_FUNC;
-
- /* Sanity checks */
- ASSERT(handle != NULL, return(-1));
- ASSERT(pkg != NULL, return(-1));
-
- if(pkg->origin == PKG_FROM_CACHE && !(pkg->infolevel & INFRQ_DESC)) {
- _alpm_db_read(pkg->origin_data.db, pkg, INFRQ_DESC);
- }
- return pkg->isize;
+ return pkg->ops->get_isize(pkg);
}
pmpkgreason_t SYMEXPORT alpm_pkg_get_reason(pmpkg_t *pkg)
{
- ALPM_LOG_FUNC;
-
- /* Sanity checks */
- ASSERT(handle != NULL, return(-1));
- ASSERT(pkg != NULL, return(-1));
-
- if(pkg->origin == PKG_FROM_CACHE && !(pkg->infolevel & INFRQ_DESC)) {
- _alpm_db_read(pkg->origin_data.db, pkg, INFRQ_DESC);
- }
- return pkg->reason;
+ return pkg->ops->get_reason(pkg);
}
alpm_list_t SYMEXPORT *alpm_pkg_get_licenses(pmpkg_t *pkg)
{
- ALPM_LOG_FUNC;
-
- /* Sanity checks */
- ASSERT(handle != NULL, return(NULL));
- ASSERT(pkg != NULL, return(NULL));
-
- if(pkg->origin == PKG_FROM_CACHE && !(pkg->infolevel & INFRQ_DESC)) {
- _alpm_db_read(pkg->origin_data.db, pkg, INFRQ_DESC);
- }
- return pkg->licenses;
+ return pkg->ops->get_licenses(pkg);
}
alpm_list_t SYMEXPORT *alpm_pkg_get_groups(pmpkg_t *pkg)
{
- ALPM_LOG_FUNC;
-
- /* Sanity checks */
- ASSERT(handle != NULL, return(NULL));
- ASSERT(pkg != NULL, return(NULL));
-
- if(pkg->origin == PKG_FROM_CACHE && !(pkg->infolevel & INFRQ_DESC)) {
- _alpm_db_read(pkg->origin_data.db, pkg, INFRQ_DESC);
- }
- return pkg->groups;
-}
-
-int SYMEXPORT alpm_pkg_has_force(pmpkg_t *pkg)
-{
- ALPM_LOG_FUNC;
-
- /* Sanity checks */
- ASSERT(handle != NULL, return(-1));
- ASSERT(pkg != NULL, return(-1));
-
- if(pkg->origin == PKG_FROM_CACHE && !(pkg->infolevel & INFRQ_DESC)) {
- _alpm_db_read(pkg->origin_data.db, pkg, INFRQ_DESC);
- }
- return pkg->force;
+ return pkg->ops->get_groups(pkg);
}
alpm_list_t SYMEXPORT *alpm_pkg_get_depends(pmpkg_t *pkg)
{
- ALPM_LOG_FUNC;
-
- /* Sanity checks */
- ASSERT(handle != NULL, return(NULL));
- ASSERT(pkg != NULL, return(NULL));
-
- if(pkg->origin == PKG_FROM_CACHE && !(pkg->infolevel & INFRQ_DEPENDS)) {
- _alpm_db_read(pkg->origin_data.db, pkg, INFRQ_DEPENDS);
- }
- return pkg->depends;
+ return pkg->ops->get_depends(pkg);
}
alpm_list_t SYMEXPORT *alpm_pkg_get_optdepends(pmpkg_t *pkg)
{
- ALPM_LOG_FUNC;
-
- /* Sanity checks */
- ASSERT(handle != NULL, return(NULL));
- ASSERT(pkg != NULL, return(NULL));
-
- if(pkg->origin == PKG_FROM_CACHE && !(pkg->infolevel & INFRQ_DEPENDS)) {
- _alpm_db_read(pkg->origin_data.db, pkg, INFRQ_DEPENDS);
- }
- return pkg->optdepends;
+ return pkg->ops->get_optdepends(pkg);
}
alpm_list_t SYMEXPORT *alpm_pkg_get_conflicts(pmpkg_t *pkg)
{
- ALPM_LOG_FUNC;
-
- /* Sanity checks */
- ASSERT(handle != NULL, return(NULL));
- ASSERT(pkg != NULL, return(NULL));
-
- if(pkg->origin == PKG_FROM_CACHE && !(pkg->infolevel & INFRQ_DEPENDS)) {
- _alpm_db_read(pkg->origin_data.db, pkg, INFRQ_DEPENDS);
- }
- return pkg->conflicts;
+ return pkg->ops->get_conflicts(pkg);
}
alpm_list_t SYMEXPORT *alpm_pkg_get_provides(pmpkg_t *pkg)
{
- ALPM_LOG_FUNC;
-
- /* Sanity checks */
- ASSERT(handle != NULL, return(NULL));
- ASSERT(pkg != NULL, return(NULL));
-
- if(pkg->origin == PKG_FROM_CACHE && !(pkg->infolevel & INFRQ_DEPENDS)) {
- _alpm_db_read(pkg->origin_data.db, pkg, INFRQ_DEPENDS);
- }
- return pkg->provides;
+ return pkg->ops->get_provides(pkg);
}
-alpm_list_t SYMEXPORT *alpm_pkg_get_deltas(pmpkg_t *pkg)
+alpm_list_t SYMEXPORT *alpm_pkg_get_replaces(pmpkg_t *pkg)
{
- ALPM_LOG_FUNC;
-
- /* Sanity checks */
- ASSERT(handle != NULL, return(NULL));
- ASSERT(pkg != NULL, return(NULL));
-
- if(pkg->origin == PKG_FROM_CACHE && !(pkg->infolevel & INFRQ_DELTAS)) {
- _alpm_db_read(pkg->origin_data.db, pkg, INFRQ_DELTAS);
- }
- return pkg->deltas;
+ return pkg->ops->get_replaces(pkg);
}
-alpm_list_t SYMEXPORT *alpm_pkg_get_replaces(pmpkg_t *pkg)
+alpm_list_t SYMEXPORT *alpm_pkg_get_deltas(pmpkg_t *pkg)
{
- ALPM_LOG_FUNC;
-
- /* Sanity checks */
- ASSERT(handle != NULL, return(NULL));
- ASSERT(pkg != NULL, return(NULL));
-
- if(pkg->origin == PKG_FROM_CACHE && !(pkg->infolevel & INFRQ_DESC)) {
- _alpm_db_read(pkg->origin_data.db, pkg, INFRQ_DESC);
- }
- return pkg->replaces;
+ return pkg->ops->get_deltas(pkg);
}
alpm_list_t SYMEXPORT *alpm_pkg_get_files(pmpkg_t *pkg)
{
- ALPM_LOG_FUNC;
-
- /* Sanity checks */
- ASSERT(handle != NULL, return(NULL));
- ASSERT(pkg != NULL, return(NULL));
-
- if(pkg->origin == PKG_FROM_CACHE && pkg->origin_data.db == handle->db_local
- && !(pkg->infolevel & INFRQ_FILES)) {
- _alpm_db_read(pkg->origin_data.db, pkg, INFRQ_FILES);
- }
- return pkg->files;
+ return pkg->ops->get_files(pkg);
}
alpm_list_t SYMEXPORT *alpm_pkg_get_backup(pmpkg_t *pkg)
{
- ALPM_LOG_FUNC;
-
- /* Sanity checks */
- ASSERT(handle != NULL, return(NULL));
- ASSERT(pkg != NULL, return(NULL));
-
- if(pkg->origin == PKG_FROM_CACHE && pkg->origin_data.db == handle->db_local
- && !(pkg->infolevel & INFRQ_FILES)) {
- _alpm_db_read(pkg->origin_data.db, pkg, INFRQ_FILES);
- }
- return pkg->backup;
+ return pkg->ops->get_backup(pkg);
}
pmdb_t SYMEXPORT *alpm_pkg_get_db(pmpkg_t *pkg)
{
/* Sanity checks */
ASSERT(pkg != NULL, return(NULL));
- ASSERT(pkg->origin == PKG_FROM_CACHE, return(NULL));
+ ASSERT(pkg->origin != PKG_FROM_FILE, return(NULL));
return(pkg->origin_data.db);
}
@@ -441,83 +289,31 @@ pmdb_t SYMEXPORT *alpm_pkg_get_db(pmpkg_t *pkg)
*/
void SYMEXPORT *alpm_pkg_changelog_open(pmpkg_t *pkg)
{
- ALPM_LOG_FUNC;
-
- /* Sanity checks */
- ASSERT(handle != NULL, return(NULL));
- ASSERT(pkg != NULL, return(NULL));
-
- if(pkg->origin == PKG_FROM_CACHE) {
- char clfile[PATH_MAX];
- snprintf(clfile, PATH_MAX, "%s/%s/%s-%s/changelog",
- alpm_option_get_dbpath(),
- alpm_db_get_name(handle->db_local),
- alpm_pkg_get_name(pkg),
- alpm_pkg_get_version(pkg));
- return fopen(clfile, "r");
- } else if(pkg->origin == PKG_FROM_FILE) {
- struct archive *archive = NULL;
- struct archive_entry *entry;
- const char *pkgfile = pkg->origin_data.file;
-
- if((archive = archive_read_new()) == NULL) {
- RET_ERR(PM_ERR_LIBARCHIVE, NULL);
- }
-
- archive_read_support_compression_all(archive);
- archive_read_support_format_all(archive);
-
- if (archive_read_open_filename(archive, pkgfile,
- ARCHIVE_DEFAULT_BYTES_PER_BLOCK) != ARCHIVE_OK) {
- RET_ERR(PM_ERR_PKG_OPEN, NULL);
- }
-
- while(archive_read_next_header(archive, &entry) == ARCHIVE_OK) {
- const char *entry_name = archive_entry_pathname(entry);
-
- if(strcmp(entry_name, ".CHANGELOG") == 0) {
- return(archive);
- }
- }
- /* we didn't find a changelog */
- archive_read_finish(archive);
- errno = ENOENT;
- }
- return(NULL);
+ return pkg->ops->changelog_open(pkg);
}
/**
* Read data from an open changelog 'file stream'. Similar to fread in
- * functionality, this function takes a buffer and amount of data to read.
+ * functionality, this function takes a buffer and amount of data to read. If an
+ * error occurs pm_errno will be set.
+ *
* @param ptr a buffer to fill with raw changelog data
* @param size the size of the buffer
* @param pkg the package that the changelog is being read from
* @param fp a 'file stream' to the package changelog
- * @return the number of characters read, or 0 if there is no more data
+ * @return the number of characters read, or 0 if there is no more data or an
+ * error occurred.
*/
size_t SYMEXPORT alpm_pkg_changelog_read(void *ptr, size_t size,
const pmpkg_t *pkg, const void *fp)
{
- size_t ret = 0;
- if(pkg->origin == PKG_FROM_CACHE) {
- ret = fread(ptr, 1, size, (FILE*)fp);
- } else if(pkg->origin == PKG_FROM_FILE) {
- ret = archive_read_data((struct archive*)fp, ptr, size);
- }
- return(ret);
+ return pkg->ops->changelog_read(ptr, size, pkg, fp);
}
/*
int SYMEXPORT alpm_pkg_changelog_feof(const pmpkg_t *pkg, void *fp)
{
- int ret = 0;
- if(pkg->origin == PKG_FROM_CACHE) {
- ret = feof((FILE*)fp);
- } else if(pkg->origin == PKG_FROM_FILE) {
- // note: this doesn't quite work, no feof in libarchive
- ret = archive_read_data((struct archive*)fp, NULL, 0);
- }
- return(ret);
+ return pkg->ops->changelog_feof(pkg, fp);
}
*/
@@ -531,28 +327,12 @@ int SYMEXPORT alpm_pkg_changelog_feof(const pmpkg_t *pkg, void *fp)
*/
int SYMEXPORT alpm_pkg_changelog_close(const pmpkg_t *pkg, void *fp)
{
- int ret = 0;
- if(pkg->origin == PKG_FROM_CACHE) {
- ret = fclose((FILE*)fp);
- } else if(pkg->origin == PKG_FROM_FILE) {
- ret = archive_read_finish((struct archive *)fp);
- }
- return(ret);
+ return pkg->ops->changelog_close(pkg, fp);
}
int SYMEXPORT alpm_pkg_has_scriptlet(pmpkg_t *pkg)
{
- ALPM_LOG_FUNC;
-
- /* Sanity checks */
- ASSERT(handle != NULL, return(-1));
- ASSERT(pkg != NULL, return(-1));
-
- if(pkg->origin == PKG_FROM_CACHE && pkg->origin_data.db == handle->db_local
- && !(pkg->infolevel & INFRQ_SCRIPTLET)) {
- _alpm_db_read(pkg->origin_data.db, pkg, INFRQ_SCRIPTLET);
- }
- return pkg->scriptlet;
+ return pkg->ops->has_scriptlet(pkg);
}
static void find_requiredby(pmpkg_t *pkg, pmdb_t *db, alpm_list_t **reqs)
@@ -626,6 +406,7 @@ pmpkg_t *_alpm_pkg_dup(pmpkg_t *pkg)
CALLOC(newpkg, 1, sizeof(pmpkg_t), RET_ERR(PM_ERR_MEMORY, NULL));
+ newpkg->name_hash = pkg->name_hash;
STRDUP(newpkg->filename, pkg->filename, RET_ERR(PM_ERR_MEMORY, newpkg));
STRDUP(newpkg->name, pkg->name, RET_ERR(PM_ERR_MEMORY, newpkg));
STRDUP(newpkg->version, pkg->version, RET_ERR(PM_ERR_MEMORY, newpkg));
@@ -639,7 +420,6 @@ pmpkg_t *_alpm_pkg_dup(pmpkg_t *pkg)
newpkg->size = pkg->size;
newpkg->isize = pkg->isize;
newpkg->scriptlet = pkg->scriptlet;
- newpkg->force = pkg->force;
newpkg->reason = pkg->reason;
newpkg->licenses = alpm_list_strdup(pkg->licenses);
@@ -657,6 +437,7 @@ pmpkg_t *_alpm_pkg_dup(pmpkg_t *pkg)
/* internal */
newpkg->origin = pkg->origin;
+ newpkg->ops = pkg->ops;
if(newpkg->origin == PKG_FROM_FILE) {
newpkg->origin_data.file = strdup(pkg->origin_data.file);
} else {
@@ -726,21 +507,13 @@ void _alpm_pkg_free_trans(pmpkg_t *pkg)
pkg->removes = NULL;
}
-/* Is spkg an upgrade for locapkg? */
+/* Is spkg an upgrade for localpkg? */
int _alpm_pkg_compare_versions(pmpkg_t *spkg, pmpkg_t *localpkg)
{
- int cmp = 0;
-
ALPM_LOG_FUNC;
- cmp = alpm_pkg_vercmp(alpm_pkg_get_version(spkg),
+ return alpm_pkg_vercmp(alpm_pkg_get_version(spkg),
alpm_pkg_get_version(localpkg));
-
- if(cmp < 0 && alpm_pkg_has_force(spkg)) {
- cmp = 1;
- }
-
- return(cmp);
}
/* Helper function for comparing packages
@@ -749,7 +522,7 @@ int _alpm_pkg_cmp(const void *p1, const void *p2)
{
pmpkg_t *pkg1 = (pmpkg_t *)p1;
pmpkg_t *pkg2 = (pmpkg_t *)p2;
- return(strcmp(pkg1->name, pkg2->name));
+ return(strcoll(pkg1->name, pkg2->name));
}
/* Test for existence of a package in a alpm_list_t*
@@ -758,6 +531,7 @@ int _alpm_pkg_cmp(const void *p1, const void *p2)
pmpkg_t *_alpm_pkg_find(alpm_list_t *haystack, const char *needle)
{
alpm_list_t *lp;
+ unsigned long needle_hash;
ALPM_LOG_FUNC;
@@ -765,11 +539,21 @@ pmpkg_t *_alpm_pkg_find(alpm_list_t *haystack, const char *needle)
return(NULL);
}
+ needle_hash = _alpm_hash_sdbm(needle);
+
for(lp = haystack; lp; lp = lp->next) {
pmpkg_t *info = lp->data;
- if(info && strcmp(info->name, needle) == 0) {
- return(info);
+ if(info) {
+ /* a zero hash will cause a fall-through just in case */
+ if(info->name_hash && info->name_hash != needle_hash) {
+ continue;
+ }
+
+ /* finally: we had hash match, verify string match */
+ if(strcmp(info->name, needle) == 0) {
+ return(info);
+ }
}
}
return(NULL);
diff --git a/lib/libalpm/package.h b/lib/libalpm/package.h
index c8946448..b161d5f1 100644
--- a/lib/libalpm/package.h
+++ b/lib/libalpm/package.h
@@ -1,7 +1,7 @@
/*
* package.h
*
- * Copyright (c) 2006-2010 Pacman Development Team <pacman-dev@archlinux.org>
+ * Copyright (c) 2006-2011 Pacman Development Team <pacman-dev@archlinux.org>
* Copyright (c) 2002-2006 by Judd Vinet <jvinet@zeroflux.org>
* Copyright (c) 2005 by Aurelien Foret <orelien@chez.com>
* Copyright (c) 2006 by David Kimpe <dnaku@frugalware.org>
@@ -31,27 +31,92 @@
#include "db.h"
typedef enum _pmpkgfrom_t {
- PKG_FROM_CACHE = 1,
- PKG_FROM_FILE
+ PKG_FROM_FILE = 1,
+ PKG_FROM_LOCALDB,
+ PKG_FROM_SYNCDB
} pmpkgfrom_t;
+/** Package operations struct. This struct contains function pointers to
+ * all methods used to access data in a package to allow for things such
+ * as lazy package intialization (such as used by the file backend). Each
+ * backend is free to define a stuct containing pointers to a specific
+ * implementation of these methods. Some backends may find using the
+ * defined default_pkg_ops struct to work just fine for their needs.
+ */
+struct pkg_operations {
+ const char *(*get_filename) (pmpkg_t *);
+ const char *(*get_name) (pmpkg_t *);
+ const char *(*get_version) (pmpkg_t *);
+ const char *(*get_desc) (pmpkg_t *);
+ const char *(*get_url) (pmpkg_t *);
+ time_t (*get_builddate) (pmpkg_t *);
+ time_t (*get_installdate) (pmpkg_t *);
+ const char *(*get_packager) (pmpkg_t *);
+ const char *(*get_md5sum) (pmpkg_t *);
+ const char *(*get_arch) (pmpkg_t *);
+ off_t (*get_size) (pmpkg_t *);
+ off_t (*get_isize) (pmpkg_t *);
+ pmpkgreason_t (*get_reason) (pmpkg_t *);
+ int (*has_scriptlet) (pmpkg_t *);
+
+ alpm_list_t *(*get_licenses) (pmpkg_t *);
+ alpm_list_t *(*get_groups) (pmpkg_t *);
+ alpm_list_t *(*get_depends) (pmpkg_t *);
+ alpm_list_t *(*get_optdepends) (pmpkg_t *);
+ alpm_list_t *(*get_conflicts) (pmpkg_t *);
+ alpm_list_t *(*get_provides) (pmpkg_t *);
+ alpm_list_t *(*get_replaces) (pmpkg_t *);
+ alpm_list_t *(*get_deltas) (pmpkg_t *);
+ alpm_list_t *(*get_files) (pmpkg_t *);
+ alpm_list_t *(*get_backup) (pmpkg_t *);
+
+ void *(*changelog_open) (pmpkg_t *);
+ size_t (*changelog_read) (void *, size_t, const pmpkg_t *, const void *);
+ int (*changelog_close) (const pmpkg_t *, void *);
+
+ /* still to add:
+ * checkmd5sum() ?
+ * compute_requiredby()
+ */
+};
+
+/** The standard package operations struct. get fields directly from the
+ * struct itself with no abstraction layer or any type of lazy loading.
+ * The actual definition is in package.c so it can have access to the
+ * default accessor functions which are defined there.
+ */
+extern struct pkg_operations default_pkg_ops;
+
struct __pmpkg_t {
+ unsigned long name_hash;
char *filename;
char *name;
char *version;
char *desc;
char *url;
- time_t builddate;
- time_t installdate;
char *packager;
char *md5sum;
char *arch;
+
+ time_t builddate;
+ time_t installdate;
+
off_t size;
off_t isize;
off_t download_size;
+
int scriptlet;
- int force;
+
pmpkgreason_t reason;
+ pmpkgfrom_t origin;
+ /* origin == PKG_FROM_FILE, use pkg->origin_data.file
+ * origin == PKG_FROM_*DB, use pkg->origin_data.db */
+ union {
+ pmdb_t *db;
+ char *file;
+ } origin_data;
+ pmdbinfrq_t infolevel;
+
alpm_list_t *licenses;
alpm_list_t *replaces;
alpm_list_t *groups;
@@ -64,17 +129,8 @@ struct __pmpkg_t {
alpm_list_t *deltas;
alpm_list_t *delta_path;
alpm_list_t *removes; /* in transaction targets only */
- /* internal */
- pmpkgfrom_t origin;
- /* Replaced 'void *data' with this union as follows:
- origin == PKG_FROM_CACHE, use pkg->origin_data.db
- origin == PKG_FROM_FILE, use pkg->origin_data.file
- */
- union {
- pmdb_t *db;
- char *file;
- } origin_data;
- pmdbinfrq_t infolevel;
+
+ struct pkg_operations *ops;
};
pmpkg_t* _alpm_pkg_new(void);
diff --git a/lib/libalpm/po/Makefile.in.in b/lib/libalpm/po/Makefile.in.in
index 6f2e2e94..83d8838a 100644
--- a/lib/libalpm/po/Makefile.in.in
+++ b/lib/libalpm/po/Makefile.in.in
@@ -1,5 +1,5 @@
# Makefile for PO directory in any package using GNU gettext.
-# Copyright (C) 1995-1997, 2000-2003 by Ulrich Drepper <drepper@gnu.ai.mit.edu>
+# Copyright (C) 1995-1997, 2000-2007, 2009-2010 by Ulrich Drepper <drepper@gnu.ai.mit.edu>
#
# This file can be copied and used freely without restrictions. It can
# be used in projects which are not available under the GNU General Public
@@ -8,10 +8,12 @@
# Please note that the actual code of GNU gettext is covered by the GNU
# General Public License and is *not* in the public domain.
#
-# Origin: gettext-0.13
+# Origin: gettext-0.18
+GETTEXT_MACRO_VERSION = 0.18
PACKAGE = @PACKAGE@
VERSION = @VERSION@
+PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@
SHELL = /bin/sh
@SET_MAKE@
@@ -22,18 +24,38 @@ VPATH = @srcdir@
prefix = @prefix@
exec_prefix = @exec_prefix@
-datadir = @datadir@
datarootdir = @datarootdir@
-localedir = $(datadir)/locale
+datadir = @datadir@
+localedir = @localedir@
gettextsrcdir = $(datadir)/gettext/po
INSTALL = @INSTALL@
INSTALL_DATA = @INSTALL_DATA@
-mkinstalldirs = @INSTALL@ -d
-GMSGFMT = @GMSGFMT@
-MSGFMT = @MSGFMT@
-XGETTEXT = @XGETTEXT@
+# We use $(mkdir_p).
+# In automake <= 1.9.x, $(mkdir_p) is defined either as "mkdir -p --" or as
+# "$(mkinstalldirs)" or as "$(install_sh) -d". For these automake versions,
+# @install_sh@ does not start with $(SHELL), so we add it.
+# In automake >= 1.10, @mkdir_p@ is derived from ${MKDIR_P}, which is defined
+# either as "/path/to/mkdir -p" or ".../install-sh -c -d". For these automake
+# versions, $(mkinstalldirs) and $(install_sh) are unused.
+mkinstalldirs = $(SHELL) @install_sh@ -d
+install_sh = $(SHELL) @install_sh@
+MKDIR_P = @MKDIR_P@
+mkdir_p = @mkdir_p@
+
+GMSGFMT_ = @GMSGFMT@
+GMSGFMT_no = @GMSGFMT@
+GMSGFMT_yes = @GMSGFMT_015@
+GMSGFMT = $(GMSGFMT_$(USE_MSGCTXT))
+MSGFMT_ = @MSGFMT@
+MSGFMT_no = @MSGFMT@
+MSGFMT_yes = @MSGFMT_015@
+MSGFMT = $(MSGFMT_$(USE_MSGCTXT))
+XGETTEXT_ = @XGETTEXT@
+XGETTEXT_no = @XGETTEXT@
+XGETTEXT_yes = @XGETTEXT_015@
+XGETTEXT = $(XGETTEXT_$(USE_MSGCTXT))
MSGMERGE = msgmerge
MSGMERGE_UPDATE = @MSGMERGE@ --update
MSGINIT = msginit
@@ -46,7 +68,7 @@ UPDATEPOFILES = @UPDATEPOFILES@
DUMMYPOFILES = @DUMMYPOFILES@
DISTFILES.common = Makefile.in.in remove-potcdate.sin \
$(DISTFILES.common.extra1) $(DISTFILES.common.extra2) $(DISTFILES.common.extra3)
-DISTFILES = $(DISTFILES.common) Makevars POTFILES.in $(DOMAIN).pot stamp-po \
+DISTFILES = $(DISTFILES.common) Makevars POTFILES.in \
$(POFILES) $(GMOFILES) \
$(DISTFILES.extra1) $(DISTFILES.extra2) $(DISTFILES.extra3)
@@ -57,7 +79,7 @@ CATALOGS = @CATALOGS@
# Makevars gets inserted here. (Don't remove this line!)
.SUFFIXES:
-.SUFFIXES: .po .gmo .mo .sed .sin .nop .po-update
+.SUFFIXES: .po .gmo .mo .sed .sin .nop .po-create .po-update
.po.mo:
@echo "$(MSGFMT) -c -o $@ $<"; \
@@ -66,19 +88,32 @@ CATALOGS = @CATALOGS@
.po.gmo:
@lang=`echo $* | sed -e 's,.*/,,'`; \
test "$(srcdir)" = . && cdcmd="" || cdcmd="cd $(srcdir) && "; \
- echo "$${cdcmd}rm -f $${lang}.gmo && $(GMSGFMT) -c --statistics -o $${lang}.gmo $${lang}.po"; \
- cd $(srcdir) && rm -f $${lang}.gmo && $(GMSGFMT) -c --statistics -o t-$${lang}.gmo $${lang}.po && mv t-$${lang}.gmo $${lang}.gmo
+ echo "$${cdcmd}rm -f $${lang}.gmo && $(GMSGFMT) -c --statistics --verbose -o $${lang}.gmo $${lang}.po"; \
+ cd $(srcdir) && rm -f $${lang}.gmo && $(GMSGFMT) -c --statistics --verbose -o t-$${lang}.gmo $${lang}.po && mv t-$${lang}.gmo $${lang}.gmo
.sin.sed:
sed -e '/^#/d' $< > t-$@
mv t-$@ $@
-all: all-@USE_NLS@
+all: check-macro-version all-@USE_NLS@
all-yes: stamp-po
all-no:
+# Ensure that the gettext macros and this Makefile.in.in are in sync.
+check-macro-version:
+ @test "$(GETTEXT_MACRO_VERSION)" = "@GETTEXT_MACRO_VERSION@" \
+ || { echo "*** error: gettext infrastructure mismatch: using a Makefile.in.in from gettext version $(GETTEXT_MACRO_VERSION) but the autoconf macros are from gettext version @GETTEXT_MACRO_VERSION@" 1>&2; \
+ exit 1; \
+ }
+
+# $(srcdir)/$(DOMAIN).pot is only created when needed. When xgettext finds no
+# internationalized messages, no $(srcdir)/$(DOMAIN).pot is created (because
+# we don't want to bother translators with empty POT files). We assume that
+# LINGUAS is empty in this case, i.e. $(POFILES) and $(GMOFILES) are empty.
+# In this case, stamp-po is a nop (i.e. a phony target).
+
# stamp-po is a timestamp denoting the last time at which the CATALOGS have
# been loosely updated. Its purpose is that when a developer or translator
# checks out the package via CVS, and the $(DOMAIN).pot file is not in CVS,
@@ -88,10 +123,13 @@ all-no:
# $(POFILES) has been designed to not touch files that don't need to be
# changed.
stamp-po: $(srcdir)/$(DOMAIN).pot
- test -z "$(GMOFILES)" || $(MAKE) $(GMOFILES)
- @echo "touch stamp-po"
- @echo timestamp > stamp-poT
- @mv stamp-poT stamp-po
+ test ! -f $(srcdir)/$(DOMAIN).pot || \
+ test -z "$(GMOFILES)" || $(MAKE) $(GMOFILES)
+ @test ! -f $(srcdir)/$(DOMAIN).pot || { \
+ echo "touch stamp-po" && \
+ echo timestamp > stamp-poT && \
+ mv stamp-poT stamp-po; \
+ }
# Note: Target 'all' must not depend on target '$(DOMAIN).pot-update',
# otherwise packages like GCC can not be built if only parts of the source
@@ -100,11 +138,34 @@ stamp-po: $(srcdir)/$(DOMAIN).pot
# This target rebuilds $(DOMAIN).pot; it is an expensive operation.
# Note that $(DOMAIN).pot is not touched if it doesn't need to be changed.
$(DOMAIN).pot-update: $(POTFILES) $(srcdir)/POTFILES.in remove-potcdate.sed
- $(XGETTEXT) --default-domain=$(DOMAIN) --directory=$(top_srcdir) \
- --add-comments=TRANSLATORS: $(XGETTEXT_OPTIONS) \
- --files-from=$(srcdir)/POTFILES.in \
- --copyright-holder='$(COPYRIGHT_HOLDER)' \
- --msgid-bugs-address='$(MSGID_BUGS_ADDRESS)'
+ if LC_ALL=C grep 'GNU @PACKAGE@' $(top_srcdir)/* 2>/dev/null | grep -v 'libtool:' >/dev/null; then \
+ package_gnu='GNU '; \
+ else \
+ package_gnu=''; \
+ fi; \
+ if test -n '$(MSGID_BUGS_ADDRESS)' || test '$(PACKAGE_BUGREPORT)' = '@'PACKAGE_BUGREPORT'@'; then \
+ msgid_bugs_address='$(MSGID_BUGS_ADDRESS)'; \
+ else \
+ msgid_bugs_address='$(PACKAGE_BUGREPORT)'; \
+ fi; \
+ case `$(XGETTEXT) --version | sed 1q | sed -e 's,^[^0-9]*,,'` in \
+ '' | 0.[0-9] | 0.[0-9].* | 0.1[0-5] | 0.1[0-5].* | 0.16 | 0.16.[0-1]*) \
+ $(XGETTEXT) --default-domain=$(DOMAIN) --directory=$(top_srcdir) \
+ --add-comments=TRANSLATORS: $(XGETTEXT_OPTIONS) @XGETTEXT_EXTRA_OPTIONS@ \
+ --files-from=$(srcdir)/POTFILES.in \
+ --copyright-holder='$(COPYRIGHT_HOLDER)' \
+ --msgid-bugs-address="$$msgid_bugs_address" \
+ ;; \
+ *) \
+ $(XGETTEXT) --default-domain=$(DOMAIN) --directory=$(top_srcdir) \
+ --add-comments=TRANSLATORS: $(XGETTEXT_OPTIONS) @XGETTEXT_EXTRA_OPTIONS@ \
+ --files-from=$(srcdir)/POTFILES.in \
+ --copyright-holder='$(COPYRIGHT_HOLDER)' \
+ --package-name="$${package_gnu}@PACKAGE@" \
+ --package-version='@VERSION@' \
+ --msgid-bugs-address="$$msgid_bugs_address" \
+ ;; \
+ esac
test ! -f $(DOMAIN).po || { \
if test -f $(srcdir)/$(DOMAIN).pot; then \
sed -f remove-potcdate.sed < $(srcdir)/$(DOMAIN).pot > $(DOMAIN).1po && \
@@ -130,16 +191,27 @@ $(srcdir)/$(DOMAIN).pot:
# Note that a PO file is not touched if it doesn't need to be changed.
$(POFILES): $(srcdir)/$(DOMAIN).pot
@lang=`echo $@ | sed -e 's,.*/,,' -e 's/\.po$$//'`; \
- test "$(srcdir)" = . && cdcmd="" || cdcmd="cd $(srcdir) && "; \
- echo "$${cdcmd}$(MSGMERGE_UPDATE) $${lang}.po $(DOMAIN).pot"; \
- cd $(srcdir) && $(MSGMERGE_UPDATE) $${lang}.po $(DOMAIN).pot
+ if test -f "$(srcdir)/$${lang}.po"; then \
+ test "$(srcdir)" = . && cdcmd="" || cdcmd="cd $(srcdir) && "; \
+ echo "$${cdcmd}$(MSGMERGE_UPDATE) $(MSGMERGE_OPTIONS) --lang=$${lang} $${lang}.po $(DOMAIN).pot"; \
+ cd $(srcdir) \
+ && { case `$(MSGMERGE_UPDATE) --version | sed 1q | sed -e 's,^[^0-9]*,,'` in \
+ '' | 0.[0-9] | 0.[0-9].* | 0.1[0-7] | 0.1[0-7].*) \
+ $(MSGMERGE_UPDATE) $(MSGMERGE_OPTIONS) $${lang}.po $(DOMAIN).pot;; \
+ *) \
+ $(MSGMERGE_UPDATE) $(MSGMERGE_OPTIONS) --lang=$${lang} $${lang}.po $(DOMAIN).pot;; \
+ esac; \
+ }; \
+ else \
+ $(MAKE) $${lang}.po-create; \
+ fi
install: install-exec install-data
install-exec:
install-data: install-data-@USE_NLS@
if test "$(PACKAGE)" = "gettext-tools"; then \
- $(mkinstalldirs) $(DESTDIR)$(gettextsrcdir); \
+ $(mkdir_p) $(DESTDIR)$(gettextsrcdir); \
for file in $(DISTFILES.common) Makevars.template; do \
$(INSTALL_DATA) $(srcdir)/$$file \
$(DESTDIR)$(gettextsrcdir)/$$file; \
@@ -152,13 +224,12 @@ install-data: install-data-@USE_NLS@
fi
install-data-no: all
install-data-yes: all
- $(mkinstalldirs) $(DESTDIR)$(datadir)
@catalogs='$(CATALOGS)'; \
for cat in $$catalogs; do \
cat=`basename $$cat`; \
lang=`echo $$cat | sed -e 's/\.gmo$$//'`; \
dir=$(localedir)/$$lang/LC_MESSAGES; \
- $(mkinstalldirs) $(DESTDIR)$$dir; \
+ $(mkdir_p) $(DESTDIR)$$dir; \
if test -r $$cat; then realcat=$$cat; else realcat=$(srcdir)/$$cat; fi; \
$(INSTALL_DATA) $$realcat $(DESTDIR)$$dir/$(DOMAIN).mo; \
echo "installing $$realcat as $(DESTDIR)$$dir/$(DOMAIN).mo"; \
@@ -198,19 +269,18 @@ installdirs: installdirs-exec installdirs-data
installdirs-exec:
installdirs-data: installdirs-data-@USE_NLS@
if test "$(PACKAGE)" = "gettext-tools"; then \
- $(mkinstalldirs) $(DESTDIR)$(gettextsrcdir); \
+ $(mkdir_p) $(DESTDIR)$(gettextsrcdir); \
else \
: ; \
fi
installdirs-data-no:
installdirs-data-yes:
- $(mkinstalldirs) $(DESTDIR)$(datadir)
@catalogs='$(CATALOGS)'; \
for cat in $$catalogs; do \
cat=`basename $$cat`; \
lang=`echo $$cat | sed -e 's/\.gmo$$//'`; \
dir=$(localedir)/$$lang/LC_MESSAGES; \
- $(mkinstalldirs) $(DESTDIR)$$dir; \
+ $(mkdir_p) $(DESTDIR)$$dir; \
for lc in '' $(EXTRA_LOCALE_CATEGORIES); do \
if test -n "$$lc"; then \
if (cd $(DESTDIR)$(localedir)/$$lang && LC_ALL=C ls -l -d $$lc 2>/dev/null) | grep ' -> ' >/dev/null; then \
@@ -285,11 +355,14 @@ dist distdir:
$(MAKE) update-po
@$(MAKE) dist2
# This is a separate target because 'update-po' must be executed before.
-dist2: $(DISTFILES)
+dist2: stamp-po $(DISTFILES)
dists="$(DISTFILES)"; \
if test "$(PACKAGE)" = "gettext-tools"; then \
dists="$$dists Makevars.template"; \
fi; \
+ if test -f $(srcdir)/$(DOMAIN).pot; then \
+ dists="$$dists $(DOMAIN).pot stamp-po"; \
+ fi; \
if test -f $(srcdir)/ChangeLog; then \
dists="$$dists ChangeLog"; \
fi; \
@@ -301,9 +374,9 @@ dist2: $(DISTFILES)
if test -f $(srcdir)/LINGUAS; then dists="$$dists LINGUAS"; fi; \
for file in $$dists; do \
if test -f $$file; then \
- cp -p $$file $(distdir); \
+ cp -p $$file $(distdir) || exit 1; \
else \
- cp -p $(srcdir)/$$file $(distdir); \
+ cp -p $(srcdir)/$$file $(distdir) || exit 1; \
fi; \
done
@@ -312,6 +385,13 @@ update-po: Makefile
test -z "$(UPDATEPOFILES)" || $(MAKE) $(UPDATEPOFILES)
$(MAKE) update-gmo
+# General rule for creating PO files.
+
+.nop.po-create:
+ @lang=`echo $@ | sed -e 's/\.po-create$$//'`; \
+ echo "File $$lang.po does not exist. If you are a translator, you can create it through 'msginit'." 1>&2; \
+ exit 1
+
# General rule for updating PO files.
.nop.po-update:
@@ -320,9 +400,15 @@ update-po: Makefile
tmpdir=`pwd`; \
echo "$$lang:"; \
test "$(srcdir)" = . && cdcmd="" || cdcmd="cd $(srcdir) && "; \
- echo "$${cdcmd}$(MSGMERGE) $$lang.po $(DOMAIN).pot -o $$lang.new.po"; \
+ echo "$${cdcmd}$(MSGMERGE) $(MSGMERGE_OPTIONS) --lang=$$lang $$lang.po $(DOMAIN).pot -o $$lang.new.po"; \
cd $(srcdir); \
- if $(MSGMERGE) $$lang.po $(DOMAIN).pot -o $$tmpdir/$$lang.new.po; then \
+ if { case `$(MSGMERGE) --version | sed 1q | sed -e 's,^[^0-9]*,,'` in \
+ '' | 0.[0-9] | 0.[0-9].* | 0.1[0-7] | 0.1[0-7].*) \
+ $(MSGMERGE) $(MSGMERGE_OPTIONS) -o $$tmpdir/$$lang.new.po $$lang.po $(DOMAIN).pot;; \
+ *) \
+ $(MSGMERGE) $(MSGMERGE_OPTIONS) --lang=$$lang -o $$tmpdir/$$lang.new.po $$lang.po $(DOMAIN).pot;; \
+ esac; \
+ }; then \
if cmp $$lang.po $$tmpdir/$$lang.new.po >/dev/null 2>&1; then \
rm -f $$tmpdir/$$lang.new.po; \
else \
@@ -343,10 +429,13 @@ $(DUMMYPOFILES):
update-gmo: Makefile $(GMOFILES)
@:
-Makefile: Makefile.in.in $(top_builddir)/config.status @POMAKEFILEDEPS@
+# Recreate Makefile by invoking config.status. Explicitly invoke the shell,
+# because execution permission bits may not work on the current file system.
+# Use @SHELL@, which is the shell determined by autoconf for the use by its
+# scripts, not $(SHELL) which is hardwired to /bin/sh and may be deficient.
+Makefile: Makefile.in.in Makevars $(top_builddir)/config.status @POMAKEFILEDEPS@
cd $(top_builddir) \
- && CONFIG_FILES=$(subdir)/$@.in CONFIG_HEADERS= \
- $(SHELL) ./config.status
+ && @SHELL@ ./config.status $(subdir)/$@.in po-directories
force:
diff --git a/lib/libalpm/po/POTFILES.in b/lib/libalpm/po/POTFILES.in
index 475cf4b4..65637977 100644
--- a/lib/libalpm/po/POTFILES.in
+++ b/lib/libalpm/po/POTFILES.in
@@ -6,8 +6,9 @@ lib/libalpm/add.c
lib/libalpm/alpm.c
#lib/libalpm/alpm_list.c
lib/libalpm/backup.c
-lib/libalpm/be_files.c
+lib/libalpm/be_local.c
lib/libalpm/be_package.c
+lib/libalpm/be_sync.c
lib/libalpm/cache.c
lib/libalpm/conflict.c
lib/libalpm/db.c
diff --git a/lib/libalpm/remove.c b/lib/libalpm/remove.c
index 153c0426..5fba0b07 100644
--- a/lib/libalpm/remove.c
+++ b/lib/libalpm/remove.c
@@ -1,7 +1,7 @@
/*
* remove.c
*
- * Copyright (c) 2006-2010 Pacman Development Team <pacman-dev@archlinux.org>
+ * Copyright (c) 2006-2011 Pacman Development Team <pacman-dev@archlinux.org>
* Copyright (c) 2002-2006 by Judd Vinet <jvinet@zeroflux.org>
* Copyright (c) 2005 by Aurelien Foret <orelien@chez.com>
* Copyright (c) 2005 by Christian Hamar <krics@linuxforum.hu>
@@ -42,12 +42,11 @@
#include "backup.h"
#include "package.h"
#include "db.h"
-#include "cache.h"
#include "deps.h"
#include "handle.h"
#include "alpm.h"
-int SYMEXPORT alpm_remove_target(char *target)
+int SYMEXPORT alpm_remove_target(const char *target)
{
pmpkg_t *info;
pmtrans_t *trans;
@@ -299,10 +298,12 @@ static void unlink_file(pmpkg_t *info, char *filename, alpm_list_t *skip_remove,
}
}
-int _alpm_upgraderemove_package(pmpkg_t *oldpkg, pmpkg_t *newpkg, pmtrans_t *trans)
+int _alpm_upgraderemove_package(pmpkg_t *oldpkg, pmpkg_t *newpkg,
+ pmtrans_t *trans)
{
alpm_list_t *skip_remove, *b;
alpm_list_t *newfiles, *lp;
+ size_t filenum;
alpm_list_t *files = alpm_pkg_get_files(oldpkg);
const char *pkgname = alpm_pkg_get_name(oldpkg);
@@ -311,9 +312,14 @@ int _alpm_upgraderemove_package(pmpkg_t *oldpkg, pmpkg_t *newpkg, pmtrans_t *tra
_alpm_log(PM_LOG_DEBUG, "removing old package first (%s-%s)\n",
oldpkg->name, oldpkg->version);
+ if(trans->flags & PM_TRANS_FLAG_DBONLY) {
+ goto db;
+ }
+
/* copy the remove skiplist over */
- skip_remove =
- alpm_list_join(alpm_list_strdup(trans->skip_remove),alpm_list_strdup(handle->noupgrade));
+ skip_remove = alpm_list_join(
+ alpm_list_strdup(trans->skip_remove),
+ alpm_list_strdup(handle->noupgrade));
/* Add files in the NEW backup array to the skip_remove array
* so this removal operation doesn't kill them */
/* old package backup list */
@@ -337,6 +343,9 @@ int _alpm_upgraderemove_package(pmpkg_t *oldpkg, pmpkg_t *newpkg, pmtrans_t *tra
}
}
+ filenum = alpm_list_count(files);
+ _alpm_log(PM_LOG_DEBUG, "removing %ld files\n", (unsigned long)filenum);
+
/* iterate through the list backwards, unlinking files */
newfiles = alpm_list_reverse(files);
for(lp = newfiles; lp; lp = alpm_list_next(lp)) {
@@ -345,10 +354,11 @@ int _alpm_upgraderemove_package(pmpkg_t *oldpkg, pmpkg_t *newpkg, pmtrans_t *tra
alpm_list_free(newfiles);
FREELIST(skip_remove);
+db:
/* remove the package from the database */
_alpm_log(PM_LOG_DEBUG, "updating database\n");
_alpm_log(PM_LOG_DEBUG, "removing database entry '%s'\n", pkgname);
- if(_alpm_db_remove(handle->db_local, oldpkg) == -1) {
+ if(_alpm_local_db_remove(handle->db_local, oldpkg) == -1) {
_alpm_log(PM_LOG_ERROR, _("could not remove database entry %s-%s\n"),
pkgname, alpm_pkg_get_version(oldpkg));
}
@@ -365,7 +375,7 @@ int _alpm_remove_packages(pmtrans_t *trans, pmdb_t *db)
{
pmpkg_t *info;
alpm_list_t *targ, *lp;
- int pkg_count;
+ size_t pkg_count;
ALPM_LOG_FUNC;
@@ -379,7 +389,7 @@ int _alpm_remove_packages(pmtrans_t *trans, pmdb_t *db)
char scriptlet[PATH_MAX];
info = (pmpkg_t*)targ->data;
const char *pkgname = NULL;
- int targcount = alpm_list_count(targ);
+ size_t targcount = alpm_list_count(targ);
if(handle->trans->state == STATE_INTERRUPTED) {
return(0);
@@ -402,6 +412,9 @@ int _alpm_remove_packages(pmtrans_t *trans, pmdb_t *db)
if(!(trans->flags & PM_TRANS_FLAG_DBONLY)) {
alpm_list_t *files = alpm_pkg_get_files(info);
+ alpm_list_t *newfiles;
+ size_t filenum;
+
for(lp = files; lp; lp = lp->next) {
if(!can_remove_file(lp->data, NULL)) {
_alpm_log(PM_LOG_DEBUG, "not removing package '%s', can't remove all files\n",
@@ -410,9 +423,8 @@ int _alpm_remove_packages(pmtrans_t *trans, pmdb_t *db)
}
}
- int filenum = alpm_list_count(files);
- alpm_list_t *newfiles;
- _alpm_log(PM_LOG_DEBUG, "removing %d files\n", filenum);
+ filenum = alpm_list_count(files);
+ _alpm_log(PM_LOG_DEBUG, "removing %ld files\n", (unsigned long)filenum);
/* init progress bar */
PROGRESS(trans, PM_TRANS_PROGRESS_REMOVE_START, info->name, 0,
@@ -421,14 +433,13 @@ int _alpm_remove_packages(pmtrans_t *trans, pmdb_t *db)
/* iterate through the list backwards, unlinking files */
newfiles = alpm_list_reverse(files);
for(lp = newfiles; lp; lp = alpm_list_next(lp)) {
- double percent;
+ int percent;
unlink_file(info, lp->data, NULL, trans->flags & PM_TRANS_FLAG_NOSAVE);
/* update progress bar after each file */
- percent = (double)position / (double)filenum;
+ percent = (position * 100) / filenum;
PROGRESS(trans, PM_TRANS_PROGRESS_REMOVE_START, info->name,
- (double)(percent * 100), pkg_count,
- (pkg_count - targcount + 1));
+ percent, pkg_count, (pkg_count - targcount + 1));
position++;
}
alpm_list_free(newfiles);
@@ -447,7 +458,7 @@ int _alpm_remove_packages(pmtrans_t *trans, pmdb_t *db)
/* remove the package from the database */
_alpm_log(PM_LOG_DEBUG, "updating database\n");
_alpm_log(PM_LOG_DEBUG, "removing database entry '%s'\n", pkgname);
- if(_alpm_db_remove(db, info) == -1) {
+ if(_alpm_local_db_remove(db, info) == -1) {
_alpm_log(PM_LOG_ERROR, _("could not remove database entry %s-%s\n"),
pkgname, alpm_pkg_get_version(info));
}
diff --git a/lib/libalpm/remove.h b/lib/libalpm/remove.h
index 55858909..a67e37a1 100644
--- a/lib/libalpm/remove.h
+++ b/lib/libalpm/remove.h
@@ -1,7 +1,7 @@
/*
* remove.h
*
- * Copyright (c) 2006-2010 Pacman Development Team <pacman-dev@archlinux.org>
+ * Copyright (c) 2006-2011 Pacman Development Team <pacman-dev@archlinux.org>
* Copyright (c) 2002-2006 by Judd Vinet <jvinet@zeroflux.org>
*
* This program is free software; you can redistribute it and/or modify
diff --git a/lib/libalpm/sync.c b/lib/libalpm/sync.c
index 4cbaf0cb..dbd15065 100644
--- a/lib/libalpm/sync.c
+++ b/lib/libalpm/sync.c
@@ -1,7 +1,7 @@
/*
* sync.c
*
- * Copyright (c) 2006-2010 Pacman Development Team <pacman-dev@archlinux.org>
+ * Copyright (c) 2006-2011 Pacman Development Team <pacman-dev@archlinux.org>
* Copyright (c) 2002-2006 by Judd Vinet <jvinet@zeroflux.org>
* Copyright (c) 2005 by Aurelien Foret <orelien@chez.com>
* Copyright (c) 2005 by Christian Hamar <krics@linuxforum.hu>
@@ -31,7 +31,7 @@
#include <stdint.h> /* intmax_t */
#include <unistd.h>
#include <time.h>
-#include <dirent.h>
+#include <limits.h>
/* libalpm */
#include "sync.h"
@@ -39,7 +39,6 @@
#include "log.h"
#include "package.h"
#include "db.h"
-#include "cache.h"
#include "deps.h"
#include "conflict.h"
#include "trans.h"
@@ -50,6 +49,7 @@
#include "dload.h"
#include "delta.h"
#include "remove.h"
+#include "diskspace.h"
/** Check for new version of pkg in sync repos
* (only the first occurrence is considered in sync)
@@ -329,7 +329,7 @@ static int sync_target(alpm_list_t *dbs_sync, const char *target)
* @param target the name of the sync target to add
* @return 0 on success, -1 on error (pm_errno is set accordingly)
*/
-int SYMEXPORT alpm_sync_dbtarget(char *dbname, char *target)
+int SYMEXPORT alpm_sync_dbtarget(const char *dbname, const char *target)
{
alpm_list_t *i;
alpm_list_t *dbs_sync;
@@ -362,7 +362,7 @@ int SYMEXPORT alpm_sync_dbtarget(char *dbname, char *target)
* @param target the name of the sync target to add
* @return 0 on success, -1 on error (pm_errno is set accordingly)
*/
-int SYMEXPORT alpm_sync_target(char *target)
+int SYMEXPORT alpm_sync_target(const char *target)
{
alpm_list_t *dbs_sync;
@@ -549,10 +549,10 @@ int _alpm_sync_prepare(pmtrans_t *trans, pmdb_t *db_local, alpm_list_t *dbs_sync
/* if sync1 provides sync2, we remove sync2 from the targets, and vice versa */
pmdepend_t *dep1 = _alpm_splitdep(conflict->package1);
pmdepend_t *dep2 = _alpm_splitdep(conflict->package2);
- if(alpm_depcmp(sync1, dep2)) {
+ if(_alpm_depcmp(sync1, dep2)) {
rsync = sync2;
sync = sync1;
- } else if(alpm_depcmp(sync2, dep1)) {
+ } else if(_alpm_depcmp(sync2, dep1)) {
rsync = sync1;
sync = sync2;
} else {
@@ -822,7 +822,7 @@ int _alpm_sync_commit(pmtrans_t *trans, pmdb_t *db_local, alpm_list_t **data)
{
alpm_list_t *i, *j, *files = NULL;
alpm_list_t *deltas = NULL;
- int replaces = 0;
+ size_t numtargs, current = 0, replaces = 0;
int errors = 0;
const char *cachedir = NULL;
int ret = -1;
@@ -854,7 +854,7 @@ int _alpm_sync_commit(pmtrans_t *trans, pmdb_t *db_local, alpm_list_t **data)
for(j = trans->add; j; j = j->next) {
pmpkg_t *spkg = j->data;
- if(spkg->origin == PKG_FROM_CACHE && current == spkg->origin_data.db) {
+ if(spkg->origin != PKG_FROM_FILE && current == spkg->origin_data.db) {
const char *fname = NULL;
fname = alpm_pkg_get_filename(spkg);
@@ -949,14 +949,18 @@ int _alpm_sync_commit(pmtrans_t *trans, pmdb_t *db_local, alpm_list_t **data)
}
/* Check integrity of packages */
+ numtargs = alpm_list_count(trans->add);
EVENT(trans, PM_TRANS_EVT_INTEGRITY_START, NULL, NULL);
errors = 0;
- for(i = trans->add; i; i = i->next) {
+ for(i = trans->add; i; i = i->next, current++) {
pmpkg_t *spkg = i->data;
+ int percent = (current * 100) / numtargs;
if(spkg->origin == PKG_FROM_FILE) {
continue; /* pkg_load() has been already called, this package is valid */
}
+ PROGRESS(trans, PM_TRANS_PROGRESS_INTEGRITY_START, "", percent,
+ numtargs, current);
const char *filename = alpm_pkg_get_filename(spkg);
const char *md5sum = alpm_pkg_get_md5sum(spkg);
@@ -983,11 +987,14 @@ int _alpm_sync_commit(pmtrans_t *trans, pmdb_t *db_local, alpm_list_t **data)
i->data = pkgfile;
_alpm_pkg_free_trans(spkg); /* spkg has been removed from the target list */
}
+ PROGRESS(trans, PM_TRANS_PROGRESS_INTEGRITY_START, "", 100,
+ numtargs, current);
+ EVENT(trans, PM_TRANS_EVT_INTEGRITY_DONE, NULL, NULL);
if(errors) {
pm_errno = PM_ERR_PKG_INVALID;
goto error;
}
- EVENT(trans, PM_TRANS_EVT_INTEGRITY_DONE, NULL, NULL);
+
if(trans->flags & PM_TRANS_FLAG_DOWNLOADONLY) {
ret = 0;
goto error;
@@ -1018,6 +1025,19 @@ int _alpm_sync_commit(pmtrans_t *trans, pmdb_t *db_local, alpm_list_t **data)
EVENT(trans, PM_TRANS_EVT_FILECONFLICTS_DONE, NULL, NULL);
}
+ /* check available disk space */
+ if(handle->checkspace) {
+ EVENT(trans, PM_TRANS_EVT_DISKSPACE_START, NULL, NULL);
+
+ _alpm_log(PM_LOG_DEBUG, "checking available disk space\n");
+ if(_alpm_check_diskspace(trans, handle->db_local) == -1) {
+ _alpm_log(PM_LOG_ERROR, _("not enough free disk space\n"));
+ goto error;
+ }
+
+ EVENT(trans, PM_TRANS_EVT_DISKSPACE_DONE, NULL, NULL);
+ }
+
/* remove conflicting and to-be-replaced packages */
if(replaces) {
_alpm_log(PM_LOG_DEBUG, "removing conflicting and to-be-replaced packages\n");
diff --git a/lib/libalpm/sync.h b/lib/libalpm/sync.h
index 000a09cc..90a2d40d 100644
--- a/lib/libalpm/sync.h
+++ b/lib/libalpm/sync.h
@@ -1,7 +1,7 @@
/*
* sync.h
*
- * Copyright (c) 2006-2010 Pacman Development Team <pacman-dev@archlinux.org>
+ * Copyright (c) 2006-2011 Pacman Development Team <pacman-dev@archlinux.org>
* Copyright (c) 2002-2006 by Judd Vinet <jvinet@zeroflux.org>
* Copyright (c) 2005 by Aurelien Foret <orelien@chez.com>
* Copyright (c) 2005, 2006 by Miklos Vajna <vmiklos@frugalware.org>
diff --git a/lib/libalpm/trans.c b/lib/libalpm/trans.c
index 02612ec1..804ab7a1 100644
--- a/lib/libalpm/trans.c
+++ b/lib/libalpm/trans.c
@@ -1,7 +1,7 @@
/*
* trans.c
*
- * Copyright (c) 2006-2010 Pacman Development Team <pacman-dev@archlinux.org>
+ * Copyright (c) 2006-2011 Pacman Development Team <pacman-dev@archlinux.org>
* Copyright (c) 2002-2006 by Judd Vinet <jvinet@zeroflux.org>
* Copyright (c) 2005 by Aurelien Foret <orelien@chez.com>
* Copyright (c) 2005 by Christian Hamar <krics@linuxforum.hu>
@@ -31,6 +31,7 @@
#include <sys/stat.h>
#include <sys/statvfs.h>
#include <errno.h>
+#include <limits.h>
/* libalpm */
#include "trans.h"
@@ -44,7 +45,6 @@
#include "sync.h"
#include "alpm.h"
#include "deps.h"
-#include "cache.h"
/** \addtogroup alpm_trans Transaction Functions
* @brief Functions to manipulate libalpm transactions
@@ -323,11 +323,11 @@ static int grep(const char *fn, const char *needle)
}
while(!feof(fp)) {
char line[1024];
- int sline = sizeof(line)-1;
- fgets(line, sline, fp);
- if(feof(fp)) {
+ if(fgets(line, sizeof(line), fp) == NULL) {
continue;
}
+ /* TODO: this will not work if the search string
+ * ends up being split across line reads */
if(strstr(line, needle)) {
fclose(fp);
return(1);
@@ -344,6 +344,7 @@ int _alpm_runscriptlet(const char *root, const char *installfn,
char scriptfn[PATH_MAX];
char cmdline[PATH_MAX];
char tmpdir[PATH_MAX];
+ char *argv[] = { "sh", "-c", cmdline, NULL };
char *scriptpath;
int clean_tmpdir = 0;
int retval = 0;
@@ -371,7 +372,7 @@ int _alpm_runscriptlet(const char *root, const char *installfn,
/* either extract or copy the scriptlet */
snprintf(scriptfn, PATH_MAX, "%s/.INSTALL", tmpdir);
- if(!strcmp(script, "pre_upgrade") || !strcmp(script, "pre_install")) {
+ if(strcmp(script, "pre_upgrade") == 0 || strcmp(script, "pre_install") == 0) {
if(_alpm_unpack_single(installfn, tmpdir, ".INSTALL")) {
retval = 1;
}
@@ -401,7 +402,9 @@ int _alpm_runscriptlet(const char *root, const char *installfn,
scriptpath, script, ver);
}
- retval = _alpm_run_chroot(root, cmdline);
+ _alpm_log(PM_LOG_DEBUG, "executing \"%s\"\n", cmdline);
+
+ retval = _alpm_run_chroot(root, "/bin/sh", argv);
cleanup:
if(clean_tmpdir && _alpm_rmrf(tmpdir)) {
diff --git a/lib/libalpm/trans.h b/lib/libalpm/trans.h
index 51136423..ce2dc529 100644
--- a/lib/libalpm/trans.h
+++ b/lib/libalpm/trans.h
@@ -1,7 +1,7 @@
/*
* trans.h
*
- * Copyright (c) 2006-2010 Pacman Development Team <pacman-dev@archlinux.org>
+ * Copyright (c) 2006-2011 Pacman Development Team <pacman-dev@archlinux.org>
* Copyright (c) 2002-2006 by Judd Vinet <jvinet@zeroflux.org>
* Copyright (c) 2005 by Aurelien Foret <orelien@chez.com>
* Copyright (c) 2005 by Christian Hamar <krics@linuxforum.hu>
diff --git a/lib/libalpm/util.c b/lib/libalpm/util.c
index 32eaa442..089b37cb 100644
--- a/lib/libalpm/util.c
+++ b/lib/libalpm/util.c
@@ -1,7 +1,7 @@
/*
* util.c
*
- * Copyright (c) 2006-2010 Pacman Development Team <pacman-dev@archlinux.org>
+ * Copyright (c) 2006-2011 Pacman Development Team <pacman-dev@archlinux.org>
* Copyright (c) 2002-2006 by Judd Vinet <jvinet@zeroflux.org>
* Copyright (c) 2005 by Aurelien Foret <orelien@chez.com>
* Copyright (c) 2005 by Christian Hamar <krics@linuxforum.hu>
@@ -43,13 +43,18 @@
#include <archive.h>
#include <archive_entry.h>
+#ifdef HAVE_LIBSSL
+#include <openssl/md5.h>
+#else
+#include "md5.h"
+#endif
+
/* libalpm */
#include "util.h"
#include "log.h"
#include "package.h"
#include "alpm.h"
#include "alpm_list.h"
-#include "md5.h"
#include "handle.h"
#ifndef HAVE_STRSEP
@@ -143,7 +148,15 @@ int _alpm_copyfile(const char *src, const char *dest)
/* do the actual file copy */
while((len = fread(buf, 1, CPBUFSIZE, in))) {
- fwrite(buf, 1, len, out);
+ size_t nwritten = 0;
+ nwritten = fwrite(buf, 1, len, out);
+ if((nwritten != len) || ferror(out)) {
+ pm_errno = PM_ERR_WRITE;
+ _alpm_log(PM_LOG_ERROR, _("error writing to file '%s': %s\n"),
+ dest, strerror(errno));
+ ret = -1;
+ goto cleanup;
+ }
}
/* chmod dest to permissions of src, as long as it is not a symlink */
@@ -347,7 +360,7 @@ int _alpm_unpack(const char *archive, const char *prefix, alpm_list_t *list, int
int readret = archive_read_extract(_archive, entry, 0);
if(readret == ARCHIVE_WARN) {
/* operation succeeded but a non-critical error was encountered */
- _alpm_log(PM_LOG_DEBUG, "warning extracting %s (%s)\n",
+ _alpm_log(PM_LOG_WARNING, _("warning given while extracting %s (%s)\n"),
entryname, archive_error_string(_archive));
} else if(readret != ARCHIVE_OK) {
_alpm_log(PM_LOG_ERROR, _("could not extract %s (%s)\n"),
@@ -364,8 +377,8 @@ int _alpm_unpack(const char *archive, const char *prefix, alpm_list_t *list, int
cleanup:
umask(oldmask);
archive_read_finish(_archive);
- if(restore_cwd) {
- chdir(cwd);
+ if(restore_cwd && chdir(cwd) != 0) {
+ _alpm_log(PM_LOG_ERROR, _("could not change directory to %s (%s)\n"), cwd, strerror(errno));
}
return(ret);
}
@@ -398,7 +411,7 @@ int _alpm_rmrf(const char *path)
for(dp = readdir(dirp); dp != NULL; dp = readdir(dirp)) {
if(dp->d_ino) {
sprintf(name, "%s/%s", path, dp->d_name);
- if(strcmp(dp->d_name, "..") && strcmp(dp->d_name, ".")) {
+ if(strcmp(dp->d_name, "..") != 0 && strcmp(dp->d_name, ".") != 0) {
errflag += _alpm_rmrf(name);
}
}
@@ -444,10 +457,11 @@ int _alpm_logaction(int usesyslog, FILE *f, const char *fmt, va_list args)
return(ret);
}
-int _alpm_run_chroot(const char *root, const char *cmd)
+int _alpm_run_chroot(const char *root, const char *path, char *const argv[])
{
char cwd[PATH_MAX];
pid_t pid;
+ int pipefd[2];
int restore_cwd = 0;
int retval = 0;
@@ -466,11 +480,17 @@ int _alpm_run_chroot(const char *root, const char *cmd)
goto cleanup;
}
- _alpm_log(PM_LOG_DEBUG, "executing \"%s\" under chroot \"%s\"\n", cmd, root);
+ _alpm_log(PM_LOG_DEBUG, "executing \"%s\" under chroot \"%s\"\n", path, root);
/* Flush open fds before fork() to avoid cloning buffers */
fflush(NULL);
+ if(pipe(pipefd) == -1) {
+ _alpm_log(PM_LOG_ERROR, _("could not create pipe (%s)\n"), strerror(errno));
+ retval = 1;
+ goto cleanup;
+ }
+
/* fork- parent and child each have seperate code blocks below */
pid = fork();
if(pid == -1) {
@@ -480,62 +500,74 @@ int _alpm_run_chroot(const char *root, const char *cmd)
}
if(pid == 0) {
- FILE *pipe;
/* this code runs for the child only (the actual chroot/exec) */
- _alpm_log(PM_LOG_DEBUG, "chrooting in %s\n", root);
+ close(1);
+ close(2);
+ while(dup2(pipefd[1], 1) == -1 && errno == EINTR);
+ while(dup2(pipefd[1], 2) == -1 && errno == EINTR);
+ close(pipefd[0]);
+ close(pipefd[1]);
+
+ /* use fprintf instead of _alpm_log to send output through the parent */
if(chroot(root) != 0) {
- _alpm_log(PM_LOG_ERROR, _("could not change the root directory (%s)\n"),
- strerror(errno));
+ fprintf(stderr, _("could not change the root directory (%s)\n"), strerror(errno));
exit(1);
}
if(chdir("/") != 0) {
- _alpm_log(PM_LOG_ERROR, _("could not change directory to / (%s)\n"),
- strerror(errno));
+ fprintf(stderr, _("could not change directory to / (%s)\n"), strerror(errno));
exit(1);
}
umask(0022);
- pipe = popen(cmd, "r");
- if(!pipe) {
- _alpm_log(PM_LOG_ERROR, _("call to popen failed (%s)\n"),
- strerror(errno));
- exit(1);
- }
- while(!feof(pipe)) {
- char line[PATH_MAX];
- if(fgets(line, PATH_MAX, pipe) == NULL)
- break;
- alpm_logaction("%s", line);
- EVENT(handle->trans, PM_TRANS_EVT_SCRIPTLET_INFO, line, NULL);
- }
- retval = pclose(pipe);
- exit(WEXITSTATUS(retval));
+ execv(path, argv);
+ fprintf(stderr, _("call to execv failed (%s)\n"), strerror(errno));
+ exit(1);
} else {
/* this code runs for the parent only (wait on the child) */
- pid_t retpid;
int status;
- do {
- retpid = waitpid(pid, &status, 0);
- } while(retpid == -1 && errno == EINTR);
- if(retpid == -1) {
- _alpm_log(PM_LOG_ERROR, _("call to waitpid failed (%s)\n"),
- strerror(errno));
+ FILE *pipe;
+
+ close(pipefd[1]);
+ pipe = fdopen(pipefd[0], "r");
+ if(pipe == NULL) {
+ close(pipefd[0]);
retval = 1;
- goto cleanup;
} else {
- /* check the return status, make sure it is 0 (success) */
- if(WIFEXITED(status)) {
- _alpm_log(PM_LOG_DEBUG, "call to waitpid succeeded\n");
- if(WEXITSTATUS(status) != 0) {
- _alpm_log(PM_LOG_ERROR, _("command failed to execute correctly\n"));
- retval = 1;
- }
+ while(!feof(pipe)) {
+ char line[PATH_MAX];
+ if(fgets(line, PATH_MAX, pipe) == NULL)
+ break;
+ alpm_logaction("%s", line);
+ EVENT(handle->trans, PM_TRANS_EVT_SCRIPTLET_INFO, line, NULL);
+ }
+ fclose(pipe);
+ }
+
+ while(waitpid(pid, &status, 0) == -1) {
+ if(errno != EINTR) {
+ _alpm_log(PM_LOG_ERROR, _("call to waitpid failed (%s)\n"), strerror(errno));
+ retval = 1;
+ goto cleanup;
+ }
+ }
+
+ /* report error from above after the child has exited */
+ if(retval != 0) {
+ _alpm_log(PM_LOG_ERROR, _("could not open pipe (%s)\n"), strerror(errno));
+ goto cleanup;
+ }
+ /* check the return status, make sure it is 0 (success) */
+ if(WIFEXITED(status)) {
+ _alpm_log(PM_LOG_DEBUG, "call to waitpid succeeded\n");
+ if(WEXITSTATUS(status) != 0) {
+ _alpm_log(PM_LOG_ERROR, _("command failed to execute correctly\n"));
+ retval = 1;
}
}
}
cleanup:
- if(restore_cwd) {
- chdir(cwd);
+ if(restore_cwd && chdir(cwd) != 0) {
+ _alpm_log(PM_LOG_ERROR, _("could not change directory to %s (%s)\n"), cwd, strerror(errno));
}
return(retval);
@@ -551,7 +583,8 @@ int _alpm_ldconfig(const char *root)
if(access(line, F_OK) == 0) {
snprintf(line, PATH_MAX, "%ssbin/ldconfig", root);
if(access(line, X_OK) == 0) {
- _alpm_run_chroot(root, "/sbin/ldconfig");
+ char *argv[] = { "ldconfig", NULL };
+ _alpm_run_chroot(root, "/sbin/ldconfig", argv);
}
}
@@ -635,7 +668,7 @@ int _alpm_lstat(const char *path, struct stat *buf)
{
int ret;
char *newpath = strdup(path);
- int len = strlen(newpath);
+ size_t len = strlen(newpath);
/* strip the trailing slash if one exists */
if(len != 0 && newpath[len - 1] == '/') {
@@ -648,6 +681,42 @@ int _alpm_lstat(const char *path, struct stat *buf)
return(ret);
}
+#ifdef HAVE_LIBSSL
+static int md5_file(const char *path, unsigned char output[16])
+{
+ FILE *f;
+ size_t n;
+ MD5_CTX ctx;
+ unsigned char *buf;
+
+ CALLOC(buf, 8192, sizeof(unsigned char), return(1));
+
+ if((f = fopen(path, "rb")) == NULL) {
+ free(buf);
+ return(1);
+ }
+
+ MD5_Init(&ctx);
+
+ while((n = fread(buf, 1, sizeof(buf), f)) > 0) {
+ MD5_Update(&ctx, buf, n);
+ }
+
+ MD5_Final(output, &ctx);
+
+ memset(&ctx, 0, sizeof(MD5_CTX));
+ free(buf);
+
+ if(ferror(f) != 0) {
+ fclose(f);
+ return(2);
+ }
+
+ fclose(f);
+ return(0);
+}
+#endif
+
/** Get the md5 sum of file.
* @param filename name of the file
* @return the checksum on success, NULL on error
@@ -665,6 +734,7 @@ char SYMEXPORT *alpm_compute_md5sum(const char *filename)
/* allocate 32 chars plus 1 for null */
md5sum = calloc(33, sizeof(char));
+ /* defined above for OpenSSL, otherwise defined in md5.h */
ret = md5_file(filename, output);
if (ret > 0) {
@@ -701,33 +771,191 @@ int _alpm_test_md5sum(const char *filepath, const char *md5sum)
return(ret);
}
-char *_alpm_archive_fgets(char *line, size_t size, struct archive *a)
+/* Note: does NOT handle sparse files on purpose for speed. */
+int _alpm_archive_fgets(struct archive *a, struct archive_read_buffer *b)
{
- /* for now, just read one char at a time until we get to a
- * '\n' char. we can optimize this later with an internal
- * buffer. */
- /* leave room for zero terminator */
- char *last = line + size - 1;
- char *i;
-
- for(i = line; i < last; i++) {
- int ret = archive_read_data(a, i, 1);
- /* special check for first read- if null, return null,
- * this indicates EOF */
- if(i == line && (ret <= 0 || *i == '\0')) {
- return(NULL);
+ char *i = NULL;
+ int64_t offset;
+ int done = 0;
+
+ while(1) {
+ /* have we processed this entire block? */
+ if(b->block + b->block_size == b->block_offset) {
+ if(b->ret == ARCHIVE_EOF) {
+ /* reached end of archive on the last read, now we are out of data */
+ goto cleanup;
+ }
+
+ /* zero-copy - this is the entire next block of data. */
+ b->ret = archive_read_data_block(a, (void*)&b->block,
+ &b->block_size, &offset);
+ b->block_offset = b->block;
+
+ /* error or end of archive with no data read, cleanup */
+ if(b->ret < ARCHIVE_OK ||
+ (b->block_size == 0 && b->ret == ARCHIVE_EOF)) {
+ goto cleanup;
+ }
}
- /* check if read value was null or newline */
- if(ret <= 0 || *i == '\0' || *i == '\n') {
- last = i + 1;
- break;
+
+ /* loop through the block looking for EOL characters */
+ for(i = b->block_offset; i < (b->block + b->block_size); i++) {
+ /* check if read value was null or newline */
+ if(*i == '\0' || *i == '\n') {
+ done = 1;
+ break;
+ }
}
+
+ /* allocate our buffer, or ensure our existing one is big enough */
+ if(!b->line) {
+ /* set the initial buffer to the read block_size */
+ CALLOC(b->line, b->block_size + 1, sizeof(char),
+ RET_ERR(PM_ERR_MEMORY, -1));
+ b->line_size = b->block_size + 1;
+ b->line_offset = b->line;
+ } else {
+ size_t needed = (size_t)((b->line_offset - b->line)
+ + (i - b->block_offset) + 1);
+ if(needed > b->max_line_size) {
+ RET_ERR(PM_ERR_MEMORY, -1);
+ }
+ if(needed > b->line_size) {
+ /* need to realloc + copy data to fit total length */
+ char *new;
+ CALLOC(new, needed, sizeof(char), RET_ERR(PM_ERR_MEMORY, -1));
+ memcpy(new, b->line, b->line_size);
+ b->line_size = needed;
+ b->line_offset = new + (b->line_offset - b->line);
+ free(b->line);
+ b->line = new;
+ }
+ }
+
+ if(done) {
+ size_t len = (size_t)(i - b->block_offset);
+ memcpy(b->line_offset, b->block_offset, len);
+ b->line_offset[len] = '\0';
+ b->block_offset = ++i;
+ /* this is the main return point; from here you can read b->line */
+ return(ARCHIVE_OK);
+ } else {
+ /* we've looked through the whole block but no newline, copy it */
+ size_t len = (size_t)(b->block + b->block_size - b->block_offset);
+ memcpy(b->line_offset, b->block_offset, len);
+ b->line_offset += len;
+ b->block_offset = i;
+ }
+ }
+
+cleanup:
+ {
+ int ret = b->ret;
+ FREE(b->line);
+ memset(b, 0, sizeof(b));
+ return(ret);
}
+}
- /* always null terminate the buffer */
- *last = '\0';
+int _alpm_splitname(const char *target, pmpkg_t *pkg)
+{
+ /* the format of a db entry is as follows:
+ * package-version-rel/
+ * package name can contain hyphens, so parse from the back- go back
+ * two hyphens and we have split the version from the name.
+ */
+ const char *version, *end;
+
+ if(target == NULL || pkg == NULL) {
+ return(-1);
+ }
+ end = target + strlen(target);
- return(line);
+ /* remove any trailing '/' */
+ while (*(end - 1) == '/') {
+ --end;
+ }
+
+ /* do the magic parsing- find the beginning of the version string
+ * by doing two iterations of same loop to lop off two hyphens */
+ for(version = end - 1; *version && *version != '-'; version--);
+ for(version = version - 1; *version && *version != '-'; version--);
+ if(*version != '-' || version == target) {
+ return(-1);
+ }
+
+ /* copy into fields and return */
+ if(pkg->version) {
+ FREE(pkg->version);
+ }
+ /* version actually points to the dash, so need to increment 1 and account
+ * for potential end character */
+ STRNDUP(pkg->version, version + 1, end - version - 1,
+ RET_ERR(PM_ERR_MEMORY, -1));
+
+ if(pkg->name) {
+ FREE(pkg->name);
+ }
+ STRNDUP(pkg->name, target, version - target, RET_ERR(PM_ERR_MEMORY, -1));
+ pkg->name_hash = _alpm_hash_sdbm(pkg->name);
+
+ return(0);
+}
+
+/**
+ * Hash the given string to an unsigned long value.
+ * This is the standard sdbm hashing algorithm.
+ * @param str string to hash
+ * @return the hash value of the given string
+ */
+unsigned long _alpm_hash_sdbm(const char *str)
+{
+ unsigned long hash = 0;
+ int c;
+
+ if(!str) {
+ return(hash);
+ }
+ while((c = *str++)) {
+ hash = c + (hash << 6) + (hash << 16) - hash;
+ }
+
+ return(hash);
}
+long _alpm_parsedate(const char *line)
+{
+ if(isalpha((unsigned char)line[0])) {
+ /* initialize to null in case of failure */
+ struct tm tmp_tm = { 0 };
+ setlocale(LC_TIME, "C");
+ strptime(line, "%a %b %e %H:%M:%S %Y", &tmp_tm);
+ setlocale(LC_TIME, "");
+ return(mktime(&tmp_tm));
+ }
+ return(atol(line));
+}
+
+#ifndef HAVE_STRNDUP
+/* A quick and dirty implementation derived from glibc */
+static size_t strnlen(const char *s, size_t max)
+{
+ register const char *p;
+ for(p = s; *p && max--; ++p);
+ return(p - s);
+}
+
+char *strndup(const char *s, size_t n)
+{
+ size_t len = strnlen(s, n);
+ char *new = (char *) malloc(len + 1);
+
+ if (new == NULL)
+ return NULL;
+
+ new[len] = '\0';
+ return (char *) memcpy(new, s, len);
+}
+#endif
+
/* vim: set ts=2 sw=2 noet: */
diff --git a/lib/libalpm/util.h b/lib/libalpm/util.h
index 8a3154a7..015e9bf5 100644
--- a/lib/libalpm/util.h
+++ b/lib/libalpm/util.h
@@ -1,7 +1,7 @@
/*
* util.h
*
- * Copyright (c) 2006-2010 Pacman Development Team <pacman-dev@archlinux.org>
+ * Copyright (c) 2006-2011 Pacman Development Team <pacman-dev@archlinux.org>
* Copyright (c) 2002-2006 by Judd Vinet <jvinet@zeroflux.org>
* Copyright (c) 2005 by Aurelien Foret <orelien@chez.com>
* Copyright (c) 2005 by Christian Hamar <krics@linuxforum.hu>
@@ -27,6 +27,7 @@
#include "config.h"
#include "alpm_list.h"
+#include "package.h" /* pmpkg_t */
#include <stdio.h>
#include <string.h>
@@ -49,6 +50,7 @@
#define CALLOC(p, l, s, action) do { p = calloc(l, s); if(p == NULL) { ALLOC_FAIL(s); action; } } while(0)
/* This strdup macro is NULL safe- copying NULL will yield NULL */
#define STRDUP(r, s, action) do { if(s != NULL) { r = strdup(s); if(r == NULL) { ALLOC_FAIL(strlen(s)); action; } } else { r = NULL; } } while(0)
+#define STRNDUP(r, s, l, action) do { if(s != NULL) { r = strndup(s, l); if(r == NULL) { ALLOC_FAIL(strlen(s)); action; } } else { r = NULL; } } while(0)
#define FREE(p) do { free(p); p = NULL; } while(0)
@@ -58,36 +60,56 @@
_alpm_log(PM_LOG_DEBUG, "returning error %d from %s : %s\n", err, __func__, alpm_strerrorlast()); \
return(ret); } while(0)
+/**
+ * Used as a buffer/state holder for _alpm_archive_fgets().
+ */
+struct archive_read_buffer {
+ char *line;
+ char *line_offset;
+ size_t line_size;
+ size_t max_line_size;
+
+ char *block;
+ char *block_offset;
+ size_t block_size;
+
+ int ret;
+};
+
int _alpm_makepath(const char *path);
int _alpm_makepath_mode(const char *path, mode_t mode);
int _alpm_copyfile(const char *src, const char *dest);
char *_alpm_strtrim(char *str);
-int _alpm_lckmk();
-int _alpm_lckrm();
+int _alpm_lckmk(void);
+int _alpm_lckrm(void);
int _alpm_unpack_single(const char *archive, const char *prefix, const char *fn);
int _alpm_unpack(const char *archive, const char *prefix, alpm_list_t *list, int breakfirst);
int _alpm_rmrf(const char *path);
int _alpm_logaction(int usesyslog, FILE *f, const char *fmt, va_list args);
-int _alpm_run_chroot(const char *root, const char *cmd);
+int _alpm_run_chroot(const char *root, const char *path, char *const argv[]);
int _alpm_ldconfig(const char *root);
int _alpm_str_cmp(const void *s1, const void *s2);
char *_alpm_filecache_find(const char *filename);
const char *_alpm_filecache_setup(void);
int _alpm_lstat(const char *path, struct stat *buf);
int _alpm_test_md5sum(const char *filepath, const char *md5sum);
-char *_alpm_archive_fgets(char *line, size_t size, struct archive *a);
+int _alpm_archive_fgets(struct archive *a, struct archive_read_buffer *b);
+int _alpm_splitname(const char *target, pmpkg_t *pkg);
+unsigned long _alpm_hash_sdbm(const char *str);
+long _alpm_parsedate(const char *line);
#ifndef HAVE_STRSEP
char *strsep(char **, const char *);
#endif
+#ifndef HAVE_STRNDUP
+char *strndup(const char *s, size_t n);
+#endif
+
/* check exported library symbols with: nm -C -D <lib> */
#define SYMEXPORT __attribute__((visibility("default")))
#define SYMHIDDEN __attribute__((visibility("internal")))
-/* max percent of package size to download deltas */
-#define MAX_DELTA_RATIO 0.7
-
#endif /* _ALPM_UTIL_H */
/* vim: set ts=2 sw=2 noet: */
diff --git a/lib/libalpm/version.c b/lib/libalpm/version.c
index fb327df3..eba66210 100644
--- a/lib/libalpm/version.c
+++ b/lib/libalpm/version.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2006-2010 Pacman Development Team <pacman-dev@archlinux.org>
+ * Copyright (c) 2006-2011 Pacman Development Team <pacman-dev@archlinux.org>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -23,23 +23,66 @@
/* libalpm */
#include "util.h"
-/** Compare two version strings and determine which one is 'newer'.
- * Returns a value comparable to the way strcmp works. Returns 1
- * if a is newer than b, 0 if a and b are the same version, or -1
- * if b is newer than a.
- *
- * This function has been adopted from the rpmvercmp function located
- * at lib/rpmvercmp.c, and was most recently updated against rpm
- * version 4.4.2.3. Small modifications have been made to make it more
- * consistent with the libalpm coding style.
- *
- * Keep in mind that the pkgrel is only compared if it is available
- * on both versions handed to this function. For example, comparing
- * 1.5-1 and 1.5 will yield 0; comparing 1.5-1 and 1.5-2 will yield
- * -1 as expected. This is mainly for supporting versioned dependencies
- * that do not include the pkgrel.
+/**
+ * Some functions in this file have been adopted from the rpm source, notably
+ * 'rpmvercmp' located at lib/rpmvercmp.c and 'parseEVR' located at
+ * lib/rpmds.c. It was most recently updated against rpm version 4.8.1. Small
+ * modifications have been made to make it more consistent with the libalpm
+ * coding style.
*/
-int SYMEXPORT alpm_pkg_vercmp(const char *a, const char *b)
+
+/**
+ * Split EVR into epoch, version, and release components.
+ * @param evr [epoch:]version[-release] string
+ * @retval *ep pointer to epoch
+ * @retval *vp pointer to version
+ * @retval *rp pointer to release
+ */
+static void parseEVR(char *evr, const char **ep, const char **vp,
+ const char **rp)
+{
+ const char *epoch;
+ const char *version;
+ const char *release;
+ char *s, *se;
+
+ s = evr;
+ /* s points to epoch terminator */
+ while (*s && isdigit(*s)) s++;
+ /* se points to version terminator */
+ se = strrchr(s, '-');
+
+ if(*s == ':') {
+ epoch = evr;
+ *s++ = '\0';
+ version = s;
+ if(*epoch == '\0') {
+ epoch = "0";
+ }
+ } else {
+ /* different from RPM- always assume 0 epoch */
+ epoch = "0";
+ version = evr;
+ }
+ if(se) {
+ *se++ = '\0';
+ release = se;
+ } else {
+ release = NULL;
+ }
+
+ if(ep) *ep = epoch;
+ if(vp) *vp = version;
+ if(rp) *rp = release;
+}
+
+/**
+ * Compare alpha and numeric segments of two versions.
+ * return 1: a is newer than b
+ * 0: a and b are the same version
+ * -1: b is newer than a
+ */
+static int rpmvercmp(const char *a, const char *b)
{
char oldch1, oldch2;
char *str1, *str2;
@@ -49,13 +92,6 @@ int SYMEXPORT alpm_pkg_vercmp(const char *a, const char *b)
int isnum;
int ret = 0;
- /* libalpm added code. ensure our strings are not null */
- if(!a) {
- if(!b) return(0);
- return(-1);
- }
- if(!b) return(1);
-
/* easy comparison to see if versions are identical */
if(strcmp(a, b) == 0) return(0);
@@ -147,22 +183,6 @@ int SYMEXPORT alpm_pkg_vercmp(const char *a, const char *b)
one = ptr1;
*ptr2 = oldch2;
two = ptr2;
-
- /* libalpm added code. check if version strings have hit the pkgrel
- * portion. depending on which strings have hit, take correct action.
- * this is all based on the premise that we only have one dash in
- * the version string, and it separates pkgver from pkgrel. */
- if(*ptr1 == '-' && *ptr2 == '-') {
- /* no-op, continue comparing since we are equivalent throughout */
- } else if(*ptr1 == '-') {
- /* ptr1 has hit the pkgrel and ptr2 has not. continue version
- * comparison after stripping the pkgrel from ptr1. */
- *ptr1 = '\0';
- } else if(*ptr2 == '-') {
- /* ptr2 has hit the pkgrel and ptr1 has not. continue version
- * comparison after stripping the pkgrel from ptr2. */
- *ptr2 = '\0';
- }
}
/* this catches the case where all numeric and alpha segments have */
@@ -179,7 +199,7 @@ int SYMEXPORT alpm_pkg_vercmp(const char *a, const char *b)
* - if one is an alpha, two is newer.
* - otherwise one is newer.
* */
- if ( ( !*one && !isalpha((int)*two) )
+ if ( (!*one && !isalpha((int)*two))
|| isalpha((int)*one) ) {
ret = -1;
} else {
@@ -192,4 +212,61 @@ cleanup:
return(ret);
}
+/** Compare two version strings and determine which one is 'newer'.
+ * Returns a value comparable to the way strcmp works. Returns 1
+ * if a is newer than b, 0 if a and b are the same version, or -1
+ * if b is newer than a.
+ *
+ * Different epoch values for version strings will override any further
+ * comparison. If no epoch is provided, 0 is assumed.
+ *
+ * Keep in mind that the pkgrel is only compared if it is available
+ * on both versions handed to this function. For example, comparing
+ * 1.5-1 and 1.5 will yield 0; comparing 1.5-1 and 1.5-2 will yield
+ * -1 as expected. This is mainly for supporting versioned dependencies
+ * that do not include the pkgrel.
+ */
+int SYMEXPORT alpm_pkg_vercmp(const char *a, const char *b)
+{
+ char *full1, *full2;
+ const char *epoch1, *ver1, *rel1;
+ const char *epoch2, *ver2, *rel2;
+ int ret;
+
+ /* ensure our strings are not null */
+ if(!a && !b) {
+ return(0);
+ } else if(!a) {
+ return(-1);
+ } else if(!b) {
+ return(1);
+ }
+ /* another quick shortcut- if full version specs are equal */
+ if(strcmp(a, b) == 0) {
+ return(0);
+ }
+
+ /* Parse both versions into [epoch:]version[-release] triplets. We probably
+ * don't need epoch and release to support all the same magic, but it is
+ * easier to just run it all through the same code. */
+ full1 = strdup(a);
+ full2 = strdup(b);
+
+ /* parseEVR modifies passed in version, so have to dupe it first */
+ parseEVR(full1, &epoch1, &ver1, &rel1);
+ parseEVR(full2, &epoch2, &ver2, &rel2);
+
+ ret = rpmvercmp(epoch1, epoch2);
+ if(ret == 0) {
+ ret = rpmvercmp(ver1, ver2);
+ if(ret == 0 && rel1 && rel2) {
+ ret = rpmvercmp(rel1, rel2);
+ }
+ }
+
+ free(full1);
+ free(full2);
+ return(ret);
+}
+
/* vim: set ts=2 sw=2 noet: */