static alpm_pkg_t *load_pkg_for_entry(alpm_db_t *db, const char *entryname, const char **entry_filename, alpm_pkg_t *likely_pkg) { char *pkgname = NULL, *pkgver = NULL; unsigned long pkgname_hash; alpm_pkg_t *pkg; /* get package and db file names */ if(entry_filename) { char *fname = strrchr(entryname, '/'); if(fname) { *entry_filename = fname + 1; } else { *entry_filename = NULL; } } if(_alpm_splitname(entryname, &pkgname, &pkgver, &pkgname_hash) != 0) { _alpm_log(db->handle, ALPM_LOG_ERROR, _("invalid name for database entry '%s'\n"), entryname); return NULL; } if(likely_pkg && pkgname_hash == likely_pkg->name_hash && strcmp(likely_pkg->name, pkgname) == 0) { pkg = likely_pkg; } else { pkg = _alpm_pkghash_find(db->pkgcache, pkgname); } if(pkg == NULL) { pkg = _alpm_pkg_new(); if(pkg == NULL) { RET_ERR(db->handle, ALPM_ERR_MEMORY, NULL); } pkg->name = pkgname; pkg->version = pkgver; pkg->name_hash = pkgname_hash; pkg->origin = ALPM_PKG_FROM_SYNCDB; pkg->origin_data.db = db; pkg->ops = &default_pkg_ops; pkg->ops->get_validation = _sync_get_validation; pkg->handle = db->handle; /* add to the collection */ _alpm_log(db->handle, ALPM_LOG_FUNCTION, "adding '%s' to package cache for db '%s'\n", pkg->name, db->treename); db->pkgcache = _alpm_pkghash_add(db->pkgcache, pkg); } else { free(pkgname); free(pkgver); } return pkg; }
static int local_db_populate(alpm_db_t *db) { size_t est_count; int count = 0; struct stat buf; struct dirent *ent = NULL; const char *dbpath; DIR *dbdir; if(db->status & DB_STATUS_INVALID) { RET_ERR(db->handle, ALPM_ERR_DB_INVALID, -1); } /* note: DB_STATUS_MISSING is not fatal for local database */ dbpath = _alpm_db_path(db); if(dbpath == NULL) { /* pm_errno set in _alpm_db_path() */ return -1; } dbdir = opendir(dbpath); if(dbdir == NULL) { if(errno == ENOENT) { /* no database existing yet is not an error */ db->status &= ~DB_STATUS_EXISTS; db->status |= DB_STATUS_MISSING; return 0; } RET_ERR(db->handle, ALPM_ERR_DB_OPEN, -1); } if(fstat(dirfd(dbdir), &buf) != 0) { RET_ERR(db->handle, ALPM_ERR_DB_OPEN, -1); } db->status |= DB_STATUS_EXISTS; db->status &= ~DB_STATUS_MISSING; if(buf.st_nlink >= 2) { est_count = buf.st_nlink; } else { /* Some filesystems don't subscribe to the two-implicit links school of * thought, e.g. BTRFS, HFS+. See * http://kerneltrap.org/mailarchive/linux-btrfs/2010/1/23/6723483/thread */ est_count = 0; while(readdir(dbdir) != NULL) { est_count++; } rewinddir(dbdir); } if(est_count >= 2) { /* subtract the two extra pointers to get # of children */ est_count -= 2; } /* initialize hash at 50% full */ db->pkgcache = _alpm_pkghash_create(est_count * 2); if(db->pkgcache == NULL){ closedir(dbdir); RET_ERR(db->handle, ALPM_ERR_MEMORY, -1); } while((ent = readdir(dbdir)) != NULL) { const char *name = ent->d_name; alpm_pkg_t *pkg; if(strcmp(name, ".") == 0 || strcmp(name, "..") == 0) { continue; } if(!is_dir(dbpath, ent)) { continue; } pkg = _alpm_pkg_new(); if(pkg == NULL) { closedir(dbdir); RET_ERR(db->handle, ALPM_ERR_MEMORY, -1); } /* split the db entry name */ if(_alpm_splitname(name, &(pkg->name), &(pkg->version), &(pkg->name_hash)) != 0) { _alpm_log(db->handle, ALPM_LOG_ERROR, _("invalid name for database entry '%s'\n"), name); _alpm_pkg_free(pkg); continue; } /* duplicated database entries are not allowed */ if(_alpm_pkghash_find(db->pkgcache, pkg->name)) { _alpm_log(db->handle, ALPM_LOG_ERROR, _("duplicated database entry '%s'\n"), pkg->name); _alpm_pkg_free(pkg); continue; } pkg->origin = PKG_FROM_LOCALDB; pkg->origin_data.db = db; pkg->ops = &local_pkg_ops; pkg->handle = db->handle; /* explicitly read with only 'BASE' data, accessors will handle the rest */ if(local_db_read(pkg, INFRQ_BASE) == -1) { _alpm_log(db->handle, ALPM_LOG_ERROR, _("corrupted database entry '%s'\n"), name); _alpm_pkg_free(pkg); continue; } /* add to the collection */ _alpm_log(db->handle, ALPM_LOG_FUNCTION, "adding '%s' to package cache for db '%s'\n", pkg->name, db->treename); db->pkgcache = _alpm_pkghash_add(db->pkgcache, pkg); count++; } closedir(dbdir); if(count > 0) { db->pkgcache->list = alpm_list_msort(db->pkgcache->list, (size_t)count, _alpm_pkg_cmp); } _alpm_log(db->handle, ALPM_LOG_DEBUG, "added %d packages to package cache for db '%s'\n", count, db->treename); return count; }