From d1cc1ef6c31dc193adcf48a9aea4a95830c7ae56 Mon Sep 17 00:00:00 2001 From: Dan McGee Date: Tue, 15 Feb 2011 16:56:44 -0600 Subject: Fix some database size estimation problems * Use stat() and not lstat(); we don't care for the size of the symlink if it is one, we want the size of the reference file. * FS#22896, fix local database estimation on platforms that don't abide by the nlink assumption for number of children. * Fix a missing newline on an error message. Signed-off-by: Dan McGee --- lib/libalpm/be_local.c | 32 ++++++++++++++++++++++++++------ lib/libalpm/be_sync.c | 9 +++++---- lib/libalpm/pkghash.c | 2 +- 3 files changed, 32 insertions(+), 11 deletions(-) diff --git a/lib/libalpm/be_local.c b/lib/libalpm/be_local.c index 58582705..c1e86a63 100644 --- a/lib/libalpm/be_local.c +++ b/lib/libalpm/be_local.c @@ -367,7 +367,8 @@ static int is_dir(const char *path, struct dirent *entry) static int local_db_populate(pmdb_t *db) { - int est_count, count = 0; + size_t est_count; + int count = 0; struct stat buf; struct dirent *ent = NULL; const char *dbpath; @@ -379,17 +380,36 @@ static int local_db_populate(pmdb_t *db) dbpath = _alpm_db_path(db); if(dbpath == NULL) { - return(-1); + RET_ERR(PM_ERR_DB_OPEN, -1); } dbdir = opendir(dbpath); if(dbdir == NULL) { - return(0); + if(errno == ENOENT) { + /* no database existing yet is not an error */ + return(0); + } + RET_ERR(PM_ERR_DB_OPEN, -1); } if(fstat(dirfd(dbdir), &buf) != 0) { - return(0); + RET_ERR(PM_ERR_DB_OPEN, -1); + } + 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((ent = readdir(dbdir)) != NULL) { + est_count++; + } + rewinddir(dbdir); + } + if(est_count >= 2) { + /* subtract the two extra pointers to get # of children */ + est_count -= 2; } - /* subtract the two always-there pointers to get # of children */ - est_count = (int)buf.st_nlink - 2; /* initialize hash at 50% full */ db->pkgcache = _alpm_pkghash_create(est_count * 2); diff --git a/lib/libalpm/be_sync.c b/lib/libalpm/be_sync.c index 4e9b4d31..69f7663d 100644 --- a/lib/libalpm/be_sync.c +++ b/lib/libalpm/be_sync.c @@ -171,7 +171,7 @@ static int sync_db_read(pmdb_t *db, struct archive *archive, * Unweighted Avg 2543.39 118.74 190.16 137.93 * Average of Avgs 2564.44 124.08 191.06 143.46 */ -static int estimate_package_count(struct stat *st, struct archive *archive) +static size_t estimate_package_count(struct stat *st, struct archive *archive) { unsigned int per_package; @@ -199,12 +199,13 @@ static int estimate_package_count(struct stat *st, struct archive *archive) /* assume it is at least somewhat compressed */ per_package = 200; } - return((int)(st->st_size / per_package) + 1); + return((size_t)(st->st_size / per_package) + 1); } static int sync_db_populate(pmdb_t *db) { - int est_count, count = 0; + size_t est_count; + int count = 0; struct stat buf; struct archive *archive; struct archive_entry *entry; @@ -227,7 +228,7 @@ static int sync_db_populate(pmdb_t *db) archive_read_finish(archive); RET_ERR(PM_ERR_DB_OPEN, 1); } - if(lstat(_alpm_db_path(db), &buf) != 0) { + if(stat(_alpm_db_path(db), &buf) != 0) { RET_ERR(PM_ERR_DB_OPEN, 1); } est_count = estimate_package_count(&buf, archive); diff --git a/lib/libalpm/pkghash.c b/lib/libalpm/pkghash.c index 23b7493a..db98f94b 100644 --- a/lib/libalpm/pkghash.c +++ b/lib/libalpm/pkghash.c @@ -70,7 +70,7 @@ pmpkghash_t *_alpm_pkghash_create(size_t size) } if(hash->buckets < size) { - _alpm_log(PM_LOG_ERROR, _("database larger than maximum size")); + _alpm_log(PM_LOG_ERROR, _("database larger than maximum size\n")); free(hash); return(NULL); } -- cgit v1.2.3-24-g4f1b