diff options
Diffstat (limited to 'lib')
-rw-r--r-- | lib/libalpm/Makefile.am | 10 | ||||
-rw-r--r-- | lib/libalpm/add.c | 23 | ||||
-rw-r--r-- | lib/libalpm/alpm.c | 13 | ||||
-rw-r--r-- | lib/libalpm/alpm.h | 3 | ||||
-rw-r--r-- | lib/libalpm/be_local.c (renamed from lib/libalpm/be_files.c) | 764 | ||||
-rw-r--r-- | lib/libalpm/be_package.c | 156 | ||||
-rw-r--r-- | lib/libalpm/be_sync.c | 449 | ||||
-rw-r--r-- | lib/libalpm/cache.c | 291 | ||||
-rw-r--r-- | lib/libalpm/cache.h | 44 | ||||
-rw-r--r-- | lib/libalpm/conflict.c | 7 | ||||
-rw-r--r-- | lib/libalpm/db.c | 271 | ||||
-rw-r--r-- | lib/libalpm/db.h | 48 | ||||
-rw-r--r-- | lib/libalpm/deps.c | 3 | ||||
-rw-r--r-- | lib/libalpm/dload.c | 8 | ||||
-rw-r--r-- | lib/libalpm/error.c | 4 | ||||
-rw-r--r-- | lib/libalpm/md5.c | 13 | ||||
-rw-r--r-- | lib/libalpm/package.c | 439 | ||||
-rw-r--r-- | lib/libalpm/package.h | 69 | ||||
-rw-r--r-- | lib/libalpm/po/Makefile.in.in | 167 | ||||
-rw-r--r-- | lib/libalpm/po/POTFILES.in | 3 | ||||
-rw-r--r-- | lib/libalpm/remove.c | 5 | ||||
-rw-r--r-- | lib/libalpm/sync.c | 3 | ||||
-rw-r--r-- | lib/libalpm/trans.c | 16 | ||||
-rw-r--r-- | lib/libalpm/util.c | 207 | ||||
-rw-r--r-- | lib/libalpm/util.h | 4 |
25 files changed, 1785 insertions, 1235 deletions
diff --git a/lib/libalpm/Makefile.am b/lib/libalpm/Makefile.am index 3473a73a..bac30389 100644 --- a/lib/libalpm/Makefile.am +++ b/lib/libalpm/Makefile.am @@ -25,9 +25,9 @@ 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 \ @@ -38,7 +38,6 @@ libalpm_la_SOURCES = \ 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 +45,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..2b6b019b 100644 --- a/lib/libalpm/add.c +++ b/lib/libalpm/add.c @@ -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" @@ -498,7 +497,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 +543,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 +555,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 +579,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) { @@ -629,9 +634,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 +661,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", diff --git a/lib/libalpm/alpm.c b/lib/libalpm/alpm.c index 51b9e25b..3f9cfff3 100644 --- a/lib/libalpm/alpm.c +++ b/lib/libalpm/alpm.c @@ -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..3dea6be9 100644 --- a/lib/libalpm/alpm.h +++ b/lib/libalpm/alpm.h @@ -235,7 +235,7 @@ 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); +int alpm_pkg_get_epoch(pmpkg_t *pkg); off_t alpm_pkg_download_size(pmpkg_t *newpkg); alpm_list_t *alpm_pkg_unused_deltas(pmpkg_t *pkg); @@ -522,6 +522,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/be_files.c b/lib/libalpm/be_local.c index 877bc505..22127520 100644 --- a/lib/libalpm/be_files.c +++ b/lib/libalpm/be_local.c @@ -1,8 +1,8 @@ /* - * be_files.c + * be_local.c * - * Copyright (c) 2006 by Christian Hamar <krics@linuxforum.hu> - * Copyright (c) 2006 by Miklos Vajna <vmiklos@frugalware.org> + * 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 @@ -40,317 +40,325 @@ /* 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 "group.h" #include "deps.h" #include "dload.h" -static int checkdbdir(pmdb_t *db) +#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. + */ + +const char *_cache_get_filename(pmpkg_t *pkg) { - struct stat buf; - const char *path = _alpm_db_path(db); + LAZY_LOAD(INFRQ_DESC, NULL); + return pkg->filename; +} - 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); +const char *_cache_get_name(pmpkg_t *pkg) +{ + ASSERT(pkg != NULL, return(NULL)); + return pkg->name; } -/* create list of directories in db */ -static int dirlist_from_tar(const char *archive, alpm_list_t **dirlist) +static const char *_cache_get_version(pmpkg_t *pkg) { - struct archive *_archive; - struct archive_entry *entry; + ASSERT(pkg != NULL, return(NULL)); + return pkg->version; +} - if((_archive = archive_read_new()) == NULL) - RET_ERR(PM_ERR_LIBARCHIVE, -1); +static const char *_cache_get_desc(pmpkg_t *pkg) +{ + LAZY_LOAD(INFRQ_DESC, NULL); + return pkg->desc; +} - archive_read_support_compression_all(_archive); - archive_read_support_format_all(_archive); +const char *_cache_get_url(pmpkg_t *pkg) +{ + LAZY_LOAD(INFRQ_DESC, NULL); + return pkg->url; +} - 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); - } +time_t _cache_get_builddate(pmpkg_t *pkg) +{ + LAZY_LOAD(INFRQ_DESC, 0); + return pkg->builddate; +} - while(archive_read_next_header(_archive, &entry) == ARCHIVE_OK) { - const struct stat *st; - const char *entryname; /* the name of the file in the archive */ +time_t _cache_get_installdate(pmpkg_t *pkg) +{ + LAZY_LOAD(INFRQ_DESC, 0); + return pkg->installdate; +} - st = archive_entry_stat(entry); - entryname = archive_entry_pathname(entry); +const char *_cache_get_packager(pmpkg_t *pkg) +{ + LAZY_LOAD(INFRQ_DESC, NULL); + return pkg->packager; +} - if(S_ISDIR(st->st_mode)) { - char *name = strdup(entryname); - *dirlist = alpm_list_add(*dirlist, name); - } - } - archive_read_finish(_archive); +const char *_cache_get_md5sum(pmpkg_t *pkg) +{ + LAZY_LOAD(INFRQ_DESC, NULL); + return pkg->md5sum; +} - *dirlist = alpm_list_msort(*dirlist, alpm_list_count(*dirlist), _alpm_str_cmp); - return(0); +const char *_cache_get_arch(pmpkg_t *pkg) +{ + LAZY_LOAD(INFRQ_DESC, NULL); + return pkg->arch; } -/* create list of directories in db */ -static int dirlist_from_fs(const char *syncdbpath, alpm_list_t **dirlist) +off_t _cache_get_size(pmpkg_t *pkg) { - DIR *dbdir; - struct dirent *ent = NULL; - struct stat sbuf; - char path[PATH_MAX]; + LAZY_LOAD(INFRQ_DESC, -1); + return pkg->size; +} - dbdir = opendir(syncdbpath); - if (dbdir != NULL) { - while((ent = readdir(dbdir)) != NULL) { - char *name = ent->d_name; - size_t len; - char *entry; +off_t _cache_get_isize(pmpkg_t *pkg) +{ + LAZY_LOAD(INFRQ_DESC, -1); + return pkg->isize; +} - if(strcmp(name, ".") == 0 || strcmp(name, "..") == 0) { - continue; - } +pmpkgreason_t _cache_get_reason(pmpkg_t *pkg) +{ + LAZY_LOAD(INFRQ_DESC, -1); + return pkg->reason; +} - /* 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; - } +alpm_list_t *_cache_get_licenses(pmpkg_t *pkg) +{ + LAZY_LOAD(INFRQ_DESC, NULL); + return pkg->licenses; +} - 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); - } +alpm_list_t *_cache_get_groups(pmpkg_t *pkg) +{ + LAZY_LOAD(INFRQ_DESC, NULL); + return pkg->groups; +} - *dirlist = alpm_list_msort(*dirlist, alpm_list_count(*dirlist), _alpm_str_cmp); - return(0); +int _cache_get_epoch(pmpkg_t *pkg) +{ + LAZY_LOAD(INFRQ_DESC, -1); + return pkg->epoch; } -/* remove old directories from dbdir */ -static int remove_olddir(const char *syncdbpath, alpm_list_t *dirlist) +alpm_list_t *_cache_get_depends(pmpkg_t *pkg) { - 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); + LAZY_LOAD(INFRQ_DEPENDS, NULL); + return pkg->depends; } -/** 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) +alpm_list_t *_cache_get_optdepends(pmpkg_t *pkg) { - 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; + LAZY_LOAD(INFRQ_DEPENDS, NULL); + return pkg->optdepends; +} + +alpm_list_t *_cache_get_conflicts(pmpkg_t *pkg) +{ + LAZY_LOAD(INFRQ_DEPENDS, NULL); + return pkg->conflicts; +} +alpm_list_t *_cache_get_provides(pmpkg_t *pkg) +{ + LAZY_LOAD(INFRQ_DEPENDS, NULL); + return pkg->provides; +} + +alpm_list_t *_cache_get_replaces(pmpkg_t *pkg) +{ + LAZY_LOAD(INFRQ_DESC, NULL); + return pkg->replaces; +} + +alpm_list_t *_cache_get_files(pmpkg_t *pkg) +{ 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); - } + ASSERT(handle != NULL, return(NULL)); + ASSERT(pkg != NULL, return(NULL)); - len = strlen(db->treename) + strlen(DBEXT) + 1; - MALLOC(dbfile, len, RET_ERR(PM_ERR_MEMORY, -1)); - sprintf(dbfile, "%s" DBEXT, db->treename); + if(pkg->origin == PKG_FROM_LOCALDB + && !(pkg->infolevel & INFRQ_FILES)) { + _alpm_local_db_read(pkg->origin_data.db, pkg, INFRQ_FILES); + } + return pkg->files; +} - dbpath = alpm_option_get_dbpath(); +alpm_list_t *_cache_get_backup(pmpkg_t *pkg) +{ + ALPM_LOG_FUNC; - ret = _alpm_download_single_file(dbfile, db->servers, dbpath, force); - free(dbfile); + /* Sanity checks */ + ASSERT(handle != NULL, return(NULL)); + ASSERT(pkg != NULL, return(NULL)); - 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); + if(pkg->origin == PKG_FROM_LOCALDB + && !(pkg->infolevel & INFRQ_FILES)) { + _alpm_local_db_read(pkg->origin_data.db, pkg, INFRQ_FILES); } + return pkg->backup; +} - 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; - } +/** + * 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 + */ +void *_cache_changelog_open(pmpkg_t *pkg) +{ + ALPM_LOG_FUNC; - alpm_list_diff_sorted(olddirlist, newdirlist, _alpm_str_cmp, &onlyold, &onlynew); + /* 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"); +} - ret = remove_olddir(syncdbpath, onlyold); - if(ret) { - goto cleanup; - } - } +/** + * 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 + */ +size_t _cache_changelog_read(void *ptr, size_t size, + const pmpkg_t *pkg, const void *fp) +{ + return ( fread(ptr, 1, size, (FILE*)fp) ); +} - /* Cache needs to be rebuilt */ - _alpm_db_free_pkgcache(db); +/* +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 + */ +int _cache_changelog_close(const pmpkg_t *pkg, void *fp) +{ + return( fclose((FILE*)fp) ); +} - checkdbdir(db); - ret = _alpm_unpack(dbfilepath, syncdbpath, onlynew, 0); +/* We're cheating, local packages can't have deltas anyway. */ +alpm_list_t *_pkg_get_deltas(pmpkg_t *pkg); -cleanup: - FREELIST(newdirlist); - FREELIST(olddirlist); - alpm_list_free(onlynew); - alpm_list_free(onlyold); +/** 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, + .get_epoch = _cache_get_epoch, + .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 = _pkg_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, +}; - free(dbfilepath); +static int checkdbdir(pmdb_t *db) +{ + struct stat buf; + const char *path = _alpm_db_path(db); - if(ret) { - RET_ERR(PM_ERR_SYSTEM, -1); + 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 splitname(const char *target, pmpkg_t *pkg) +static int is_dir(const char *path, struct dirent *entry) { - /* 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); - } +#ifdef DT_DIR + return(entry->d_type == DT_DIR); +#else + char buffer[PATH_MAX]; + snprintf(buffer, PATH_MAX, "%s/%s", path, entry->d_name); - /* 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); + struct stat sbuf; + if (!stat(buffer, &sbuf)) { + return(S_ISDIR(sbuf.st_mode)); } - STRDUP(pkg->name, tmp, RET_ERR(PM_ERR_MEMORY, -1)); - free(tmp); return(0); +#endif } -int _alpm_db_populate(pmdb_t *db) +int _alpm_local_db_populate(pmdb_t *db) { int count = 0; struct dirent *ent = NULL; - struct stat sbuf; - char path[PATH_MAX]; const char *dbpath; DIR *dbdir; @@ -365,14 +373,13 @@ int _alpm_db_populate(pmdb_t *db) } 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)) { + if(!is_dir(dbpath, ent)) { continue; } @@ -382,7 +389,7 @@ int _alpm_db_populate(pmdb_t *db) return(-1); } /* split the db entry name */ - if(splitname(name, pkg) != 0) { + if(_alpm_splitname(name, pkg) != 0) { _alpm_log(PM_LOG_ERROR, _("invalid name for database entry '%s'\n"), name); _alpm_pkg_free(pkg); @@ -397,12 +404,15 @@ int _alpm_db_populate(pmdb_t *db) } /* explicitly read with only 'BASE' data, accessors will handle the rest */ - if(_alpm_db_read(db, pkg, INFRQ_BASE) == -1) { + 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; } - pkg->origin = PKG_FROM_CACHE; + + pkg->origin = PKG_FROM_LOCALDB; + pkg->ops = &local_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", @@ -430,12 +440,12 @@ static char *get_pkgpath(pmdb_t *db, pmpkg_t *info) return(pkgpath); } -int _alpm_db_read(pmdb_t *db, pmpkg_t *info, pmdbinfrq_t inforeq) + +int _alpm_local_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 line[1024]; char *pkgpath = NULL; ALPM_LOG_FUNC; @@ -445,7 +455,7 @@ int _alpm_db_read(pmdb_t *db, pmpkg_t *info, pmdbinfrq_t inforeq) } if(info == NULL || info->name == NULL || info->version == NULL) { - _alpm_log(PM_LOG_DEBUG, "invalid package entry provided to _alpm_db_read, skipping\n"); + _alpm_log(PM_LOG_DEBUG, "invalid package entry provided to _alpm_local_db_read, skipping\n"); return(-1); } @@ -467,7 +477,7 @@ int _alpm_db_read(pmdb_t *db, pmpkg_t *info, pmdbinfrq_t inforeq) info->name, inforeq); /* clear out 'line', to be certain - and to make valgrind happy */ - memset(line, 0, sline+1); + memset(line, 0, sizeof(line)); pkgpath = get_pkgpath(db, info); @@ -486,12 +496,12 @@ int _alpm_db_read(pmdb_t *db, pmpkg_t *info, pmdbinfrq_t inforeq) goto error; } while(!feof(fp)) { - if(fgets(line, 256, fp) == NULL) { + if(fgets(line, sizeof(line), fp) == NULL) { break; } _alpm_strtrim(line); if(strcmp(line, "%NAME%") == 0) { - if(fgets(line, sline, fp) == NULL) { + if(fgets(line, sizeof(line), fp) == NULL) { goto error; } if(strcmp(_alpm_strtrim(line), info->name) != 0) { @@ -499,47 +509,42 @@ int _alpm_db_read(pmdb_t *db, pmpkg_t *info, pmdbinfrq_t inforeq) "mismatch on package %s\n"), db->treename, info->name); } } else if(strcmp(line, "%VERSION%") == 0) { - if(fgets(line, sline, fp) == NULL) { + 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, "%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) { + 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, sline, fp) && strlen(_alpm_strtrim(line))) { + 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, sline, fp) == NULL) { + 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, sline, fp) && strlen(_alpm_strtrim(line))) { + 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, sline, fp) == NULL) { + 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, sline, fp) == NULL) { + if(fgets(line, sizeof(line), fp) == NULL) { goto error; } _alpm_strtrim(line); @@ -555,7 +560,7 @@ int _alpm_db_read(pmdb_t *db, pmpkg_t *info, pmdbinfrq_t inforeq) info->builddate = atol(line); } } else if(strcmp(line, "%INSTALLDATE%") == 0) { - if(fgets(line, sline, fp) == NULL) { + if(fgets(line, sizeof(line), fp) == NULL) { goto error; } _alpm_strtrim(line); @@ -571,51 +576,44 @@ int _alpm_db_read(pmdb_t *db, pmpkg_t *info, pmdbinfrq_t inforeq) info->installdate = atol(line); } } else if(strcmp(line, "%PACKAGER%") == 0) { - if(fgets(line, sline, fp) == NULL) { + 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, sline, fp) == NULL) { + if(fgets(line, sizeof(line), fp) == NULL) { goto error; } info->reason = (pmpkgreason_t)atol(_alpm_strtrim(line)); - } else if(strcmp(line, "%SIZE%") == 0 || strcmp(line, "%CSIZE%") == 0) { + } 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, sline, fp) == NULL) { + if(fgets(line, sizeof(line), 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); + /* also store this value to isize */ + info->isize = info->size; } else if(strcmp(line, "%REPLACES%") == 0) { - while(fgets(line, sline, fp) && strlen(_alpm_strtrim(line))) { + 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, "%EPOCH%") == 0) { + if(fgets(line, sizeof(line), fp) == NULL) { + goto error; + } + info->epoch = atoi(_alpm_strtrim(line)); } else if(strcmp(line, "%FORCE%") == 0) { - info->force = 1; + /* For backward compatibility, treat force as a non-zero epoch + * but only if we didn't already have a known epoch value. */ + if(!info->epoch) { + info->epoch = 1; + } } } fclose(fp); @@ -629,16 +627,16 @@ int _alpm_db_read(pmdb_t *db, pmpkg_t *info, pmdbinfrq_t inforeq) _alpm_log(PM_LOG_ERROR, _("could not open file %s: %s\n"), path, strerror(errno)); goto error; } - while(fgets(line, 256, fp)) { + while(fgets(line, sizeof(line), fp)) { _alpm_strtrim(line); if(strcmp(line, "%FILES%") == 0) { - while(fgets(line, sline, fp) && strlen(_alpm_strtrim(line))) { + 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, sline, fp) && strlen(_alpm_strtrim(line))) { + 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); @@ -657,27 +655,29 @@ int _alpm_db_read(pmdb_t *db, pmpkg_t *info, pmdbinfrq_t inforeq) goto error; } while(!feof(fp)) { - fgets(line, 255, fp); + if(fgets(line, sizeof(line), fp) == NULL) { + break; + } _alpm_strtrim(line); if(strcmp(line, "%DEPENDS%") == 0) { - while(fgets(line, sline, fp) && strlen(_alpm_strtrim(line))) { + 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, sline, fp) && strlen(_alpm_strtrim(line))) { + 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, sline, fp) && strlen(_alpm_strtrim(line))) { + 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, sline, fp) && strlen(_alpm_strtrim(line))) { + 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); @@ -688,27 +688,6 @@ int _alpm_db_read(pmdb_t *db, pmpkg_t *info, pmdbinfrq_t inforeq) fp = NULL; } - /* DELTAS */ - if(inforeq & 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) { snprintf(path, PATH_MAX, "%sinstall", pkgpath); @@ -731,7 +710,7 @@ error: return(-1); } -int _alpm_db_prepare(pmdb_t *db, pmpkg_t *info) +int _alpm_local_db_prepare(pmdb_t *db, pmpkg_t *info) { mode_t oldmask; int retval = 0; @@ -755,14 +734,13 @@ int _alpm_db_prepare(pmdb_t *db, pmpkg_t *info) return(retval); } -int _alpm_db_write(pmdb_t *db, pmpkg_t *info, pmdbinfrq_t inforeq) +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; - int local = 0; char *pkgpath = NULL; ALPM_LOG_FUNC; @@ -776,8 +754,8 @@ int _alpm_db_write(pmdb_t *db, pmpkg_t *info, pmdbinfrq_t inforeq) /* make sure we have a sane umask */ oldmask = umask(0022); - if(strcmp(db->treename, "local") == 0) { - local = 1; + if(strcmp(db->treename, "local") != 0) { + return(-1); } /* DESC */ @@ -810,66 +788,53 @@ int _alpm_db_write(pmdb_t *db, pmpkg_t *info, pmdbinfrq_t inforeq) } fprintf(fp, "\n"); } - if(info->force) { - fprintf(fp, "%%FORCE%%\n\n"); + if(info->epoch) { + fprintf(fp, "%%EPOCH%%\n" + "%d\n\n", info->epoch); } - 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); + 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); + } + fclose(fp); fp = NULL; } /* FILES */ - if(local && (inforeq & INFRQ_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); @@ -954,7 +919,7 @@ cleanup: return(retval); } -int _alpm_db_remove(pmdb_t *db, pmpkg_t *info) +int _alpm_local_db_remove(pmdb_t *db, pmpkg_t *info) { int ret = 0; char *pkgpath = NULL; @@ -975,4 +940,33 @@ int _alpm_db_remove(pmdb_t *db, pmpkg_t *info) return(ret); } +struct db_operations local_db_ops = { + .populate = _alpm_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..254f830b 100644 --- a/lib/libalpm/be_package.c +++ b/lib/libalpm/be_package.c @@ -26,6 +26,7 @@ #include <limits.h> #include <ctype.h> #include <locale.h> /* setlocale */ +#include <errno.h> /* libarchive */ #include <archive.h> @@ -39,6 +40,114 @@ #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 + */ +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; + int ret = ARCHIVE_OK; + + 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((ret = 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 + */ +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); + } +} + +/* +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 + */ +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. The static file_pkg_ops variable inside this function + * lets us only initialize an operations struct once which can always be + * accessed by this method. + */ +static struct pkg_operations *get_file_pkg_ops() +{ + static struct pkg_operations *file_pkg_ops = NULL; + /* determine whether our static file_pkg_ops struct has been initialized */ + if(!file_pkg_ops) { + MALLOC(file_pkg_ops, sizeof(struct pkg_operations), + RET_ERR(PM_ERR_MEMORY, NULL)); + memcpy(file_pkg_ops, &default_pkg_ops, sizeof(struct pkg_operations)); + file_pkg_ops->changelog_open = _package_changelog_open; + file_pkg_ops->changelog_read = _package_changelog_read; + file_pkg_ops->changelog_close = _package_changelog_close; + } + 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 @@ -69,21 +178,26 @@ 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")) { + } 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, "force") == 0) { + /* For backward compatibility, like in sync_db_read */ + if(!newpkg->epoch) { + newpkg->epoch = 1; + } + } else if(strcmp(key, "epoch") == 0) { + newpkg->epoch = atoi(ptr); + } 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")) { + } else if(strcmp(key, "builddate") == 0) { char first = tolower((unsigned char)ptr[0]); if(first > 'a' && first < 'z') { struct tm tmp_tm = {0}; /* initialize to null in case of failure */ @@ -94,27 +208,27 @@ static int parse_descfile(struct archive *a, pmpkg_t *newpkg) } else { newpkg->builddate = atol(ptr); } - } else if(!strcmp(key, "packager")) { + } 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", @@ -232,11 +346,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 */ diff --git a/lib/libalpm/be_sync.c b/lib/libalpm/be_sync.c new file mode 100644 index 00000000..e1c76638 --- /dev/null +++ b/lib/libalpm/be_sync.c @@ -0,0 +1,449 @@ +/* + * be_sync.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 <errno.h> +#include <dirent.h> +#include <ctype.h> +#include <locale.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; + 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/"); + + 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); +} + +int _alpm_sync_db_populate(pmdb_t *db) +{ + int count = 0; + struct archive *archive; + struct archive_entry *entry; + const char * archive_path; + + 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; + const char *name; + pmpkg_t *pkg; + + st = archive_entry_stat(entry); + + if(S_ISDIR(st->st_mode)) { + archive_path = archive_entry_pathname(entry); + + 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 */ + _alpm_sync_db_read(db, archive, entry); + } + } + + db->pkgcache = alpm_list_msort(db->pkgcache, count, _alpm_pkg_cmp); + archive_read_finish(archive); + + return(count); +} + +int _alpm_sync_db_read(pmdb_t *db, struct archive *archive, struct archive_entry *entry) +{ + char line[1024]; + const char *entryname; + char *filename, *pkgname, *p, *q; + pmpkg_t *pkg; + + ALPM_LOG_FUNC; + + if(db == NULL) { + RET_ERR(PM_ERR_DB_NULL, -1); + } + + if(entry == NULL) { + _alpm_log(PM_LOG_DEBUG, "invalid archive entry provided to _alpm_sync_db_read, skipping\n"); + return(-1); + } + + entryname = archive_entry_pathname(entry); + + _alpm_log(PM_LOG_FUNCTION, "loading package data from archive entry %s\n", + entryname); + + /* 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--); + STRDUP(filename, q+1, RET_ERR(PM_ERR_MEMORY, -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 */ + 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) { + while(_alpm_archive_fgets(line, sizeof(line), archive) != NULL) { + _alpm_strtrim(line); + if(strcmp(line, "%NAME%") == 0) { + if(_alpm_archive_fgets(line, sizeof(line), archive) == NULL) { + goto error; + } + if(strcmp(_alpm_strtrim(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) { + if(_alpm_archive_fgets(line, sizeof(line), archive) == NULL) { + goto error; + } + if(strcmp(_alpm_strtrim(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) { + if(_alpm_archive_fgets(line, sizeof(line), archive) == NULL) { + goto error; + } + STRDUP(pkg->filename, _alpm_strtrim(line), goto error); + } else if(strcmp(line, "%DESC%") == 0) { + if(_alpm_archive_fgets(line, sizeof(line), archive) == NULL) { + goto error; + } + STRDUP(pkg->desc, _alpm_strtrim(line), goto error); + } else if(strcmp(line, "%GROUPS%") == 0) { + while(_alpm_archive_fgets(line, sizeof(line), archive) && strlen(_alpm_strtrim(line))) { + char *linedup; + STRDUP(linedup, _alpm_strtrim(line), goto error); + pkg->groups = alpm_list_add(pkg->groups, linedup); + } + } else if(strcmp(line, "%URL%") == 0) { + if(_alpm_archive_fgets(line, sizeof(line), archive) == NULL) { + goto error; + } + STRDUP(pkg->url, _alpm_strtrim(line), goto error); + } else if(strcmp(line, "%LICENSE%") == 0) { + while(_alpm_archive_fgets(line, sizeof(line), archive) && + strlen(_alpm_strtrim(line))) { + char *linedup; + STRDUP(linedup, _alpm_strtrim(line), goto error); + pkg->licenses = alpm_list_add(pkg->licenses, linedup); + } + } else if(strcmp(line, "%ARCH%") == 0) { + if(_alpm_archive_fgets(line, sizeof(line), archive) == NULL) { + goto error; + } + STRDUP(pkg->arch, _alpm_strtrim(line), goto error); + } else if(strcmp(line, "%BUILDDATE%") == 0) { + if(_alpm_archive_fgets(line, sizeof(line), archive) == 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); + pkg->builddate = mktime(&tmp_tm); + setlocale(LC_TIME, ""); + } else { + pkg->builddate = atol(line); + } + } else if(strcmp(line, "%PACKAGER%") == 0) { + if(_alpm_archive_fgets(line, sizeof(line), archive) == NULL) { + goto error; + } + STRDUP(pkg->packager, _alpm_strtrim(line), goto error); + } 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. + */ + if(_alpm_archive_fgets(line, sizeof(line), archive) == NULL) { + goto error; + } + pkg->size = atol(_alpm_strtrim(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) { + if(_alpm_archive_fgets(line, sizeof(line), archive) == NULL) { + goto error; + } + pkg->isize = atol(_alpm_strtrim(line)); + } else if(strcmp(line, "%MD5SUM%") == 0) { + if(_alpm_archive_fgets(line, sizeof(line), archive) == NULL) { + goto error; + } + STRDUP(pkg->md5sum, _alpm_strtrim(line), goto error); + } else if(strcmp(line, "%REPLACES%") == 0) { + while(_alpm_archive_fgets(line, sizeof(line), archive) && + strlen(_alpm_strtrim(line))) { + char *linedup; + STRDUP(linedup, _alpm_strtrim(line), goto error); + pkg->replaces = alpm_list_add(pkg->replaces, linedup); + } + } else if(strcmp(line, "%EPOCH%") == 0) { + if(_alpm_archive_fgets(line, sizeof(line), archive) == NULL) { + goto error; + } + pkg->epoch = atoi(_alpm_strtrim(line)); + } else if(strcmp(line, "%FORCE%") == 0) { + /* For backward compatibility, treat force as a non-zero epoch + * but only if we didn't already have a known epoch value. */ + if(!pkg->epoch) { + pkg->epoch = 1; + } + } + } + } else if(strcmp(filename, "depends") == 0) { + while(_alpm_archive_fgets(line, sizeof(line), archive) != NULL) { + _alpm_strtrim(line); + if(strcmp(line, "%DEPENDS%") == 0) { + while(_alpm_archive_fgets(line, sizeof(line), archive) && + strlen(_alpm_strtrim(line))) { + pmdepend_t *dep = _alpm_splitdep(_alpm_strtrim(line)); + pkg->depends = alpm_list_add(pkg->depends, dep); + } + } else if(strcmp(line, "%OPTDEPENDS%") == 0) { + while(_alpm_archive_fgets(line, sizeof(line), archive) && + strlen(_alpm_strtrim(line))) { + char *linedup; + STRDUP(linedup, _alpm_strtrim(line), goto error); + pkg->optdepends = alpm_list_add(pkg->optdepends, linedup); + } + } else if(strcmp(line, "%CONFLICTS%") == 0) { + while(_alpm_archive_fgets(line, sizeof(line), archive) && + strlen(_alpm_strtrim(line))) { + char *linedup; + STRDUP(linedup, _alpm_strtrim(line), goto error); + pkg->conflicts = alpm_list_add(pkg->conflicts, linedup); + } + } else if(strcmp(line, "%PROVIDES%") == 0) { + while(_alpm_archive_fgets(line, sizeof(line), archive) && + strlen(_alpm_strtrim(line))) { + char *linedup; + STRDUP(linedup, _alpm_strtrim(line), goto error); + pkg->provides = alpm_list_add(pkg->provides, linedup); + } + } + } + } else if(strcmp(filename, "deltas") == 0) { + while(_alpm_archive_fgets(line, sizeof(line), archive) != NULL) { + _alpm_strtrim(line); + if(strcmp(line, "%DELTAS%") == 0) { + while(_alpm_archive_fgets(line, sizeof(line), archive) && strlen(_alpm_strtrim(line))) { + pmdelta_t *delta = _alpm_delta_parse(line); + if(delta) { + pkg->deltas = alpm_list_add(pkg->deltas, delta); + } + } + } + } + } else { + /* unknown database file */ + _alpm_log(PM_LOG_DEBUG, "unknown database file: %s", filename); + } + +error: + FREE(pkgname); + FREE(filename); + return(0); +} + +struct db_operations sync_db_ops = { + .populate = _alpm_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..f3cb9b59 100644 --- a/lib/libalpm/conflict.c +++ b/lib/libalpm/conflict.c @@ -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); } } @@ -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)); diff --git a/lib/libalpm/db.c b/lib/libalpm/db.c index c8a91a2b..79d20d49 100644 --- a/lib/libalpm/db.c +++ b/lib/libalpm/db.c @@ -39,8 +39,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 +81,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 +97,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 +107,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 +159,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); } @@ -321,7 +326,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 @@ -342,7 +347,7 @@ 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)) { + if(_alpm_local_db_read(db, pkg, INFRQ_DESC)) { return(-1); } if(pkg->reason == reason) { @@ -352,7 +357,7 @@ int SYMEXPORT alpm_db_set_pkgreason(pmdb_t *db, const char *name, pmpkgreason_t /* 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 +366,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 +414,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 +508,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..5352e9ee 100644 --- a/lib/libalpm/db.h +++ b/lib/libalpm/db.h @@ -26,6 +26,10 @@ #include <limits.h> #include <time.h> +/* libarchive */ +#include <archive.h> +#include <archive_entry.h> + /* Database entries */ typedef enum _pmdbinfrq_t { INFRQ_BASE = 1, @@ -33,12 +37,16 @@ typedef enum _pmdbinfrq_t { INFRQ_DEPENDS = (1 << 2), INFRQ_FILES = (1 << 3), INFRQ_SCRIPTLET = (1 << 4), - INFRQ_DELTAS = (1 << 5), - INFRQ_DSIZE = (1 << 6), + INFRQ_DSIZE = (1 << 5), /* ALL should be info stored in the package or database */ INFRQ_ALL = 0x3F } pmdbinfrq_t; +struct db_operations { + int (*populate) (pmdb_t *); + void (*unregister) (pmdb_t *); +}; + /* Database */ struct __pmdb_t { char *treename; @@ -46,12 +54,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 +71,33 @@ 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_populate(pmdb_t *db); +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); + +int _alpm_sync_db_populate(pmdb_t *db); +int _alpm_sync_db_read(pmdb_t *db, struct archive *archive, struct archive_entry *entry); -/* 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/deps.c b/lib/libalpm/deps.c index 26f9b16d..0d8683c2 100644 --- a/lib/libalpm/deps.c +++ b/lib/libalpm/deps.c @@ -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) @@ -546,7 +545,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; diff --git a/lib/libalpm/dload.c b/lib/libalpm/dload.c index c11148d1..9b59f520 100644 --- a/lib/libalpm/dload.c +++ b/lib/libalpm/dload.c @@ -38,7 +38,7 @@ #include <sys/param.h> /* MAXHOSTNAMELEN */ #endif -#if defined(INTERNAL_DOWNLOAD) +#ifdef HAVE_LIBFETCH #include <fetch.h> #endif @@ -58,7 +58,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 */ @@ -251,7 +251,7 @@ static int download_internal(const char *url, const char *localpath, check_stop(); size_t nwritten = 0; nwritten = fwrite(buffer, 1, nread, localf); - if((nwritten != nread) || ferror(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 +338,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/error.c b/lib/libalpm/error.c index 8d8d0458..c83f606e 100644 --- a/lib/libalpm/error.c +++ b/lib/libalpm/error.c @@ -31,7 +31,7 @@ #include <sys/param.h> /* MAXHOSTNAMELEN */ #endif -#if defined(INTERNAL_DOWNLOAD) +#ifdef HAVE_LIBFETCH #include <fetch.h> /* fetchLastErrString */ #endif @@ -145,7 +145,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/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..f4322bf1 100644 --- a/lib/libalpm/package.c +++ b/lib/libalpm/package.c @@ -32,17 +32,12 @@ #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 +58,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 +78,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 +94,194 @@ 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. */ +const char *_pkg_get_filename(pmpkg_t *pkg) { return pkg->filename; } +const char *_pkg_get_name(pmpkg_t *pkg) { return pkg->name; } +const char *_pkg_get_version(pmpkg_t *pkg) { return pkg->version; } +const char *_pkg_get_desc(pmpkg_t *pkg) { return pkg->desc; } +const char *_pkg_get_url(pmpkg_t *pkg) { return pkg->url; } +time_t _pkg_get_builddate(pmpkg_t *pkg) { return pkg->builddate; } +time_t _pkg_get_installdate(pmpkg_t *pkg) { return pkg->installdate; } +const char *_pkg_get_packager(pmpkg_t *pkg) { return pkg->packager; } +const char *_pkg_get_md5sum(pmpkg_t *pkg) { return pkg->md5sum; } +const char *_pkg_get_arch(pmpkg_t *pkg) { return pkg->arch; } +off_t _pkg_get_size(pmpkg_t *pkg) { return pkg->size; } +off_t _pkg_get_isize(pmpkg_t *pkg) { return pkg->isize; } +pmpkgreason_t _pkg_get_reason(pmpkg_t *pkg) { return pkg->reason; } +int _pkg_get_epoch(pmpkg_t *pkg) { return pkg->epoch; } + +alpm_list_t *_pkg_get_licenses(pmpkg_t *pkg) { return pkg->licenses; } +alpm_list_t *_pkg_get_groups(pmpkg_t *pkg) { return pkg->groups; } +alpm_list_t *_pkg_get_depends(pmpkg_t *pkg) { return pkg->depends; } +alpm_list_t *_pkg_get_optdepends(pmpkg_t *pkg) { return pkg->optdepends; } +alpm_list_t *_pkg_get_conflicts(pmpkg_t *pkg) { return pkg->conflicts; } +alpm_list_t *_pkg_get_provides(pmpkg_t *pkg) { return pkg->provides; } +alpm_list_t *_pkg_get_replaces(pmpkg_t *pkg) { return pkg->replaces; } +alpm_list_t *_pkg_get_deltas(pmpkg_t *pkg) { return pkg->deltas; } +alpm_list_t *_pkg_get_files(pmpkg_t *pkg) { return pkg->files; } +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, + .get_epoch = _pkg_get_epoch, + .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) +int SYMEXPORT alpm_pkg_get_epoch(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_epoch(pkg); } -alpm_list_t SYMEXPORT *alpm_pkg_get_groups(pmpkg_t *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->groups; + return pkg->ops->get_licenses(pkg); } -int SYMEXPORT alpm_pkg_has_force(pmpkg_t *pkg) +alpm_list_t SYMEXPORT *alpm_pkg_get_groups(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 +295,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,13 +333,7 @@ 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) @@ -548,9 +344,9 @@ int SYMEXPORT alpm_pkg_has_scriptlet(pmpkg_t *pkg) ASSERT(handle != NULL, return(-1)); ASSERT(pkg != NULL, return(-1)); - if(pkg->origin == PKG_FROM_CACHE && pkg->origin_data.db == handle->db_local + if(pkg->origin == PKG_FROM_LOCALDB && !(pkg->infolevel & INFRQ_SCRIPTLET)) { - _alpm_db_read(pkg->origin_data.db, pkg, INFRQ_SCRIPTLET); + _alpm_local_db_read(pkg->origin_data.db, pkg, INFRQ_SCRIPTLET); } return pkg->scriptlet; } @@ -639,7 +435,7 @@ 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->epoch = pkg->epoch; newpkg->reason = pkg->reason; newpkg->licenses = alpm_list_strdup(pkg->licenses); @@ -657,6 +453,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 +523,25 @@ 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; + int spkg_epoch, localpkg_epoch; ALPM_LOG_FUNC; - cmp = alpm_pkg_vercmp(alpm_pkg_get_version(spkg), - alpm_pkg_get_version(localpkg)); + spkg_epoch = alpm_pkg_get_epoch(spkg); + localpkg_epoch = alpm_pkg_get_epoch(localpkg); - if(cmp < 0 && alpm_pkg_has_force(spkg)) { - cmp = 1; + if(spkg_epoch > localpkg_epoch) { + return(1); + } else if(spkg_epoch < localpkg_epoch) { + return(-1); } - return(cmp); + /* equal epoch values, move on to version comparison */ + return alpm_pkg_vercmp(alpm_pkg_get_version(spkg), + alpm_pkg_get_version(localpkg)); } /* Helper function for comparing packages @@ -749,7 +550,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* diff --git a/lib/libalpm/package.h b/lib/libalpm/package.h index c8946448..77f8f8fd 100644 --- a/lib/libalpm/package.h +++ b/lib/libalpm/package.h @@ -31,10 +31,65 @@ #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 (*get_epoch) (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: + * free() + * dup() + * checkmd5sum() ? + * has_scriptlet() + * 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 { char *filename; char *name; @@ -50,7 +105,7 @@ struct __pmpkg_t { off_t isize; off_t download_size; int scriptlet; - int force; + int epoch; pmpkgreason_t reason; alpm_list_t *licenses; alpm_list_t *replaces; @@ -67,14 +122,16 @@ struct __pmpkg_t { /* 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 + origin == PKG_FROM_FILE, use pkg->origin_data.file + origin == PKG_FROM_*DB, use pkg->origin_data.db */ - union { + 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..b2137b19 100644 --- a/lib/libalpm/remove.c +++ b/lib/libalpm/remove.c @@ -42,7 +42,6 @@ #include "backup.h" #include "package.h" #include "db.h" -#include "cache.h" #include "deps.h" #include "handle.h" #include "alpm.h" @@ -348,7 +347,7 @@ int _alpm_upgraderemove_package(pmpkg_t *oldpkg, pmpkg_t *newpkg, pmtrans_t *tra /* 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)); } @@ -447,7 +446,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/sync.c b/lib/libalpm/sync.c index 57097fd1..1e73b8b0 100644 --- a/lib/libalpm/sync.c +++ b/lib/libalpm/sync.c @@ -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" @@ -834,7 +833,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); diff --git a/lib/libalpm/trans.c b/lib/libalpm/trans.c index 49fc0f67..4dac5981 100644 --- a/lib/libalpm/trans.c +++ b/lib/libalpm/trans.c @@ -44,7 +44,6 @@ #include "sync.h" #include "alpm.h" #include "deps.h" -#include "cache.h" /** \addtogroup alpm_trans Transaction Functions * @brief Functions to manipulate libalpm transactions @@ -107,7 +106,7 @@ static alpm_list_t *check_arch(alpm_list_t *pkgs) for(i = pkgs; i; i = i->next) { pmpkg_t *pkg = i->data; const char *pkgarch = alpm_pkg_get_arch(pkg); - if(strcmp(pkgarch,arch) && strcmp(pkgarch,"any")) { + if(strcmp(pkgarch,arch) != 0 && strcmp(pkgarch,"any") != 0) { char *string; const char *pkgname = alpm_pkg_get_name(pkg); const char *pkgver = alpm_pkg_get_version(pkg); @@ -323,11 +322,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 +343,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 +371,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 +401,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/util.c b/lib/libalpm/util.c index 32eaa442..26612418 100644 --- a/lib/libalpm/util.c +++ b/lib/libalpm/util.c @@ -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 */ @@ -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); } } @@ -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) { @@ -730,4 +800,49 @@ char *_alpm_archive_fgets(char *line, size_t size, struct archive *a) return(line); } +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. + */ + char *tmp, *p, *q; + + if(target == NULL || pkg == NULL) { + return(-1); + } + STRDUP(tmp, target, RET_ERR(PM_ERR_MEMORY, -1)); + p = tmp + strlen(tmp); + + /* remove any trailing '/' */ + while (*(p - 1) == '/') { + --p; + *p = '\0'; + } + + /* 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); +} + /* vim: set ts=2 sw=2 noet: */ diff --git a/lib/libalpm/util.h b/lib/libalpm/util.h index 8a3154a7..75e2c45f 100644 --- a/lib/libalpm/util.h +++ b/lib/libalpm/util.h @@ -27,6 +27,7 @@ #include "config.h" #include "alpm_list.h" +#include "package.h" /* pmpkg_t */ #include <stdio.h> #include <string.h> @@ -68,7 +69,7 @@ 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); @@ -76,6 +77,7 @@ 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_splitname(const char *target, pmpkg_t *pkg); #ifndef HAVE_STRSEP char *strsep(char **, const char *); |