Imported from pacman-2.9.6.tar.gz

This commit is contained in:
Judd Vinet 2005-06-10 21:31:25 +00:00
parent d48cc3bf5d
commit d05f0047a0
18 changed files with 489 additions and 254 deletions

View file

@ -1,5 +1,16 @@
VERSION DESCRIPTION VERSION DESCRIPTION
----------------------------------------------------------------------------- -----------------------------------------------------------------------------
2.9.6 - added a pacman-optimize script to try and defragment the DB
- modified NoUpgrade behaviour to avoid extracting files
that are missing from the filesystem -- this helps in
situations where the admin does not want the file there, eg,
remove index.html so index.php takes precedence
- fixed a bug where files would sometimes go missing if they
moved from one package to another
- add db_remove() which is responsible for clearing out stale
hash table entries when packages are removed
- added cache support to makepkg
- patch from Aurelien Foret fixes a few memory leaks
2.9.5 - bugfix: missing files after re-ordering packages wrt 2.9.5 - bugfix: missing files after re-ordering packages wrt
deps with --upgrade deps with --upgrade
- added "Repository" line to -Si output - added "Repository" line to -Si output

View file

@ -34,7 +34,7 @@ INSTALL_PROGRAM = @INSTALL_PROGRAM@ $(AM_INSTALL_PROGRAM_FLAGS)
INSTALL_DATA = @INSTALL_DATA@ INSTALL_DATA = @INSTALL_DATA@
INSTALL_SCRIPT = @INSTALL_SCRIPT@ INSTALL_SCRIPT = @INSTALL_SCRIPT@
PACVER = 2.9.5 PACVER = 2.9.6
TOPDIR = @srcdir@ TOPDIR = @srcdir@
SRCDIR = $(TOPDIR)/src/ SRCDIR = $(TOPDIR)/src/
@ -106,6 +106,7 @@ install: pacman vercmp convertdb man
$(INSTALL) -D -m0755 $(SCRDIR)makeworld $(DESTDIR)$(BINDIR)/makeworld $(INSTALL) -D -m0755 $(SCRDIR)makeworld $(DESTDIR)$(BINDIR)/makeworld
$(INSTALL) -D -m0755 $(SCRDIR)gensync $(DESTDIR)$(BINDIR)/gensync $(INSTALL) -D -m0755 $(SCRDIR)gensync $(DESTDIR)$(BINDIR)/gensync
$(INSTALL) -D -m0755 $(SCRDIR)updatesync $(DESTDIR)$(BINDIR)/updatesync $(INSTALL) -D -m0755 $(SCRDIR)updatesync $(DESTDIR)$(BINDIR)/updatesync
$(INSTALL) -D -m0755 $(SCRDIR)pacman-optimize $(DESTDIR)$(BINDIR)/pacman-optimize
$(INSTALL) -D -m0644 $(MANSRC)pacman.8 $(DESTDIR)$(MANDIR)/man8/pacman.8 $(INSTALL) -D -m0644 $(MANSRC)pacman.8 $(DESTDIR)$(MANDIR)/man8/pacman.8
$(INSTALL) -D -m0644 $(MANSRC)makepkg.8 $(DESTDIR)$(MANDIR)/man8/makepkg.8 $(INSTALL) -D -m0644 $(MANSRC)makepkg.8 $(DESTDIR)$(MANDIR)/man8/makepkg.8
$(INSTALL) -D -m0644 etc/pacman.conf $(DESTDIR)/etc/pacman.conf $(INSTALL) -D -m0644 etc/pacman.conf $(DESTDIR)/etc/pacman.conf

View file

@ -81,7 +81,7 @@ Output more status and error messages.
Specify an alternate configuration file. Specify an alternate configuration file.
.TP .TP
.B "\-\-noconfirm" .B "\-\-noconfirm"
Bypass any and all "Are you sure?" messages. It's not a good to do this Bypass any and all "Are you sure?" messages. It's not a good idea to do this
unless you want to run pacman from a script. unless you want to run pacman from a script.
.SH SYNC OPTIONS .SH SYNC OPTIONS
.TP .TP

View file

@ -12,8 +12,8 @@ export CHOST="i686-pc-linux-gnu"
# Pentium Pro/Pentium II/Pentium III+/Pentium 4/Athlon exclusive (binaries # Pentium Pro/Pentium II/Pentium III+/Pentium 4/Athlon exclusive (binaries
# will use the P6 instruction set and only run on P6+ systems) # will use the P6 instruction set and only run on P6+ systems)
export CFLAGS="-march=i686 -O2 -pipe" export CFLAGS="-march=i686 -O2 -pipe -Wl,-O1"
export CXXFLAGS="-march=i686 -O2 -pipe" export CXXFLAGS="-march=i686 -O2 -pipe -Wl,-O1"
# Pentium Pro/Pentium II/Pentium III+/Pentium 4/Athlon optimized (but binaries # Pentium Pro/Pentium II/Pentium III+/Pentium 4/Athlon optimized (but binaries
# will run on any x86 system) # will run on any x86 system)
#export CFLAGS="-mcpu=i686 -O2 -pipe" #export CFLAGS="-mcpu=i686 -O2 -pipe"
@ -26,7 +26,7 @@ export CXXFLAGS="-march=i686 -O2 -pipe"
export USE_FAKEROOT="y" export USE_FAKEROOT="y"
# Enable colorized output messages # Enable colorized output messages
export USE_COLOR="n" export USE_COLOR="y"
# Specify a fixed directory where all packages will be placed # Specify a fixed directory where all packages will be placed
#export PKGDEST=/home/packages #export PKGDEST=/home/packages

View file

@ -2,7 +2,7 @@
# #
# gensync # gensync
# #
# Copyright (c) 2002-2004 by Judd Vinet <jvinet@zeroflux.org> # Copyright (c) 2002-2005 by Judd Vinet <jvinet@zeroflux.org>
# #
# This program is free software; you can redistribute it and/or modify # 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 # it under the terms of the GNU General Public License as published by
@ -20,7 +20,7 @@
# USA. # USA.
# #
myver='2.9.2' myver='2.9.6'
usage() { usage() {
echo "gensync $myver" echo "gensync $myver"

View file

@ -2,7 +2,7 @@
# #
# makepkg # makepkg
# #
# Copyright (c) 2002-2004 by Judd Vinet <jvinet@zeroflux.org> # Copyright (c) 2002-2005 by Judd Vinet <jvinet@zeroflux.org>
# #
# This program is free software; you can redistribute it and/or modify # 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 # it under the terms of the GNU General Public License as published by
@ -20,7 +20,7 @@
# USA. # USA.
# #
myver='2.9.2' myver='2.9.6'
startdir=`pwd` startdir=`pwd`
PKGDEST=$startdir PKGDEST=$startdir
USE_COLOR="n" USE_COLOR="n"
@ -357,7 +357,7 @@ if [ "`id -u`" != "0" ]; then
fi fi
fi fi
msg "Making package: $pkgname (`date`)" msg "Making package: $pkgname $pkgver-$pkgrel (`date`)"
unset deplist makedeplist unset deplist makedeplist
if [ `type -p pacman` -a "$NODEPS" = "0" ]; then if [ `type -p pacman` -a "$NODEPS" = "0" ]; then
@ -552,6 +552,9 @@ if [ "$NOBUILD" = "1" ]; then
exit 0 exit 0
fi fi
# use ccache if it's available
[ -d /usr/lib/ccache/bin ] && export PATH=/usr/lib/ccache/bin:$PATH
# build # build
msg "Starting build()..." msg "Starting build()..."
build 2>&1 build 2>&1

View file

@ -2,7 +2,7 @@
# #
# makeworld # makeworld
# #
# Copyright (c) 2002-2004 by Judd Vinet <jvinet@zeroflux.org> # Copyright (c) 2002-2005 by Judd Vinet <jvinet@zeroflux.org>
# #
# This program is free software; you can redistribute it and/or modify # 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 # it under the terms of the GNU General Public License as published by
@ -20,8 +20,8 @@
# USA. # USA.
# #
version="2.9.6"
toplevel=`pwd` toplevel=`pwd`
version="2.9.2"
usage() { usage() {
echo "makeworld version $version" echo "makeworld version $version"
@ -106,12 +106,12 @@ fi
# convert a (possibly) relative path to absolute # convert a (possibly) relative path to absolute
cd $dest cd $dest
dest=`pwd` dest=`pwd`
cd - cd - &>/dev/null
sd=`date +"[%b %d %H:%M]"` sd=`date +"[%b %d %H:%M]"`
for category in $*; do for category in $*; do
for port in `find $toplevel/$category -type d -maxdepth 1 -mindepth 1 | sort`; do for port in `find $toplevel/$category -maxdepth 1 -mindepth 1 -type d | sort`; do
cd $port cd $port
if [ -f PKGBUILD ]; then if [ -f PKGBUILD ]; then
. PKGBUILD . PKGBUILD

114
scripts/pacman-optimize Executable file
View file

@ -0,0 +1,114 @@
#!/bin/bash
#
# pacman-optimize
#
# Copyright (c) 2002-2005 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, write to the Free Software
# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
# USA.
#
myver='2.9.6'
usage() {
echo "pacman-optimize $myver"
echo "usage: $0 [pacman_db_root]"
echo
echo "pacman-optimize is a little hack that should improve the performance"
echo "of pacman when reading/writing to its filesystem-based database."
echo
echo "Because pacman uses many small files to keep track of packages,"
echo "there is a tendency for these files to become fragmented over time."
echo "This script attempts to relocate these small files into one"
echo "contiguous location on your hard drive. The result is that the hard"
echo "drive should be able to read them faster, since the hard drive head"
echo "does not have to move around the disk as much."
echo
}
die() {
echo "pacman-optimize: $*" >&2
exit 1
}
die_r() {
rm -f /tmp/pacman.lck
die $*
}
dbroot="/var/lib/pacman"
if [ "$1" != "" ]; then
if [ "$1" = "-h" -o "$1" = "--help" ]; then
usage
exit 0
fi
dbroot=$1
fi
if [ "`id -u`" != 0 ]; then
die "You must be root to optimize the database"
fi
# make sure pacman isn't running
if [ -f /tmp/pacman.lck ]; then
die "Pacman lockfile was found. Cannot run while pacman is running."
fi
if [ ! -d $dbroot ]; then
die "$dbroot does not exist or is not a directory"
fi
# don't let pacman run while we do this
touch /tmp/pacman.lck
# step 1: sum the old db
echo "==> md5sum'ing the old database..."
tar c $dbroot 2>/dev/null | md5sum >/tmp/pacsums.old
# step 1: copy the entire db directory to a new one
echo "==> copying $dbroot..."
cp -a $dbroot $dbroot.new || die_r "error copying $dbroot"
# step 2: switch the directory names and sum the new one
echo "==> md5sum'ing the new database..."
mv $dbroot $dbroot.bak || die_r "error renaming $dbroot"
mv $dbroot.new $dbroot || die_r "error renaming $dbroot.new"
tar c $dbroot 2>/dev/null | md5sum >/tmp/pacsums.new
# step 3: compare sums
echo "==> checking integrity..."
diff /tmp/pacsums.old /tmp/pacsums.new >/dev/null 2>&1
if [ $? -ne 0 ]; then
# failed, move the old one back into place
rm -rf $dbroot
mv $dbroot.bak $dbroot
die_r "integrity check FAILED, reverting to old databse"
fi
# step 4: remove the backup
echo "==> removing old database..."
rm -rf $dbroot.bak || die_r "error removing backup $dbroot.bak"
# remove the lock and sum files
rm -f /tmp/pacman.lck /tmp/pacsums.old /tmp/pacsums.new
echo
echo "Finished. Your pacman database has been optimized."
echo
exit 0

View file

@ -3,7 +3,7 @@
# updatesync # updatesync
# #
# Copyright (c) 2004 by Jason Chu <jason@archlinux.org> # Copyright (c) 2004 by Jason Chu <jason@archlinux.org>
# Derived from gensync (c) 2002-2004 Judd Vinet <jvinet@zeroflux.org> # Derived from gensync (c) 2002-2005 Judd Vinet <jvinet@zeroflux.org>
# #
# This program is free software; you can redistribute it and/or modify # 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 # it under the terms of the GNU General Public License as published by
@ -21,7 +21,7 @@
# USA. # USA.
# #
myver='2.9.2' myver='2.9.6'
usage() { usage() {
echo "updatesync $myver" echo "updatesync $myver"

125
src/db.c
View file

@ -137,21 +137,32 @@ pkginfo_t* db_scan(pacdb_t *db, char *target, unsigned int inforeq)
char *ptr = NULL; char *ptr = NULL;
int found = 0; int found = 0;
/* hash table for caching directory names */ /* initialize the hash table */
static strhash_t* htable = NULL; if(!db_htable) {
db_htable = new_strhash(951);
if (!htable) }
htable = new_strhash(951);
snprintf(path, PATH_MAX, "%s/", db->path); snprintf(path, PATH_MAX, "%s/", db->path);
path_len = strlen(path); path_len = strlen(path);
/* TODO:
*
* Currently we're using a hash table to cache the directory
* name of each package we db_scan() for. This saves us from
* having to scan the db directory for the full
* pkgname-pkgver-pkgrel dir name, but we still have to issue
* a db_read() call to get the actual package data.
*
* A more efficient method may be to cache the package data
* itself.
*/
if(target != NULL) { if(target != NULL) {
/* search for a specific package (by name only) */ /* search for a specific package (by name only) */
/* See if we have the path cached. */ /* See if we have the path cached. */
strcat(path, target); strcat(path, target);
if (strhash_isin(htable, path)) { if(strhash_isin(db_htable, path)) {
struct dirent* pkgdir; struct dirent* pkgdir;
pkginfo_t* pkg; pkginfo_t* pkg;
@ -159,7 +170,7 @@ pkginfo_t* db_scan(pacdb_t *db, char *target, unsigned int inforeq)
* Actually it only uses the d_name field. */ * Actually it only uses the d_name field. */
MALLOC(pkgdir, sizeof(struct dirent)); MALLOC(pkgdir, sizeof(struct dirent));
strcpy(pkgdir->d_name, strhash_get(htable, path)); strcpy(pkgdir->d_name, strhash_get(db_htable, path));
pkg = db_read(db, pkgdir, inforeq); pkg = db_read(db, pkgdir, inforeq);
FREE(pkgdir); FREE(pkgdir);
@ -242,8 +253,8 @@ pkginfo_t* db_scan(pacdb_t *db, char *target, unsigned int inforeq)
* data: xrally-1.1.1-1 * data: xrally-1.1.1-1
*/ */
if (!strhash_isin(htable, path)) { if(!strhash_isin(db_htable, path)) {
strhash_add(htable, strdup(path), strdup(ent->d_name)); strhash_add(db_htable, strdup(path), strdup(ent->d_name));
} }
} }
} }
@ -595,6 +606,40 @@ int db_write(pacdb_t *db, pkginfo_t *info, unsigned int inforeq)
return(0); return(0);
} }
/*
* Remove a package record from the database
*/
void db_remove(pacdb_t *db, pkginfo_t *target)
{
char topdir[PATH_MAX];
char path[PATH_MAX];
snprintf(topdir, PATH_MAX, "%s/%s-%s", db->path,
target->name, target->version);
/* DESC */
snprintf(path, PATH_MAX, "%s/desc", topdir);
unlink(path);
/* FILES */
snprintf(path, PATH_MAX, "%s/files", topdir);
unlink(path);
/* DEPENDS */
snprintf(path, PATH_MAX, "%s/depends", topdir);
unlink(path);
/* INSTALL */
snprintf(path, PATH_MAX, "%s/install", topdir);
unlink(path);
/* directory */
rmdir(topdir);
/* remove the entry from the hash table */
if(db_htable) {
/*clear_strhash(db_htable);*/
snprintf(topdir, PATH_MAX, "%s/%s", db->path, target->name);
strhash_remove(db_htable, topdir);
}
}
void db_search(pacdb_t *db, PMList *cache, const char *treename, PMList *needles) void db_search(pacdb_t *db, PMList *cache, const char *treename, PMList *needles)
{ {
PMList *i, *j; PMList *i, *j;
@ -655,7 +700,7 @@ void db_search(pacdb_t *db, PMList *cache, const char *treename, PMList *needles
} }
PMList* db_find_conflicts(pacdb_t *db, PMList *targets, char *root) PMList* db_find_conflicts(pacdb_t *db, PMList *targets, char *root, PMList **skip_list)
{ {
PMList *i, *j, *k; PMList *i, *j, *k;
char *filestr = NULL; char *filestr = NULL;
@ -663,6 +708,7 @@ PMList* db_find_conflicts(pacdb_t *db, PMList *targets, char *root)
char *str = NULL; char *str = NULL;
struct stat buf, buf2; struct stat buf, buf2;
PMList *conflicts = NULL; PMList *conflicts = NULL;
strhash_t** htables; strhash_t** htables;
int target_num = 0; int target_num = 0;
int d = 0; int d = 0;
@ -680,42 +726,12 @@ PMList* db_find_conflicts(pacdb_t *db, PMList *targets, char *root)
for(d = 0, i = targets; i; i = i->next, d++) { for(d = 0, i = targets; i; i = i->next, d++) {
htables[d] = new_strhash(151); htables[d] = new_strhash(151);
strhash_add_list(htables[d], ((pkginfo_t*)i->data)->files); strhash_add_list(htables[d], ((pkginfo_t*)i->data)->files);
} }
htables[target_num] = new_strhash(151); htables[target_num] = new_strhash(151);
/* CHECK 1: check every db package against every target package */ /* CHECK 1: check every target against every target */
/* XXX: I've disabled the database-against-targets check for now, as the
* many many strcmp() calls slow it down heavily and most of the
* checking is redundant to the targets-against-filesystem check.
* This will be re-enabled if I can improve performance significantly.
*
pkginfo_t *info = NULL;
char *dbstr = NULL;
rewinddir(db->dir);
while((info = db_scan(db, NULL, INFRQ_DESC | INFRQ_FILES)) != NULL) {
for(i = info->files; i; i = i->next) {
dbstr = (char*)i->data;
if(dbstr == NULL || rindex(dbstr, '/') == dbstr+strlen(dbstr)-1)
continue;
for(d = 0, j = targets; j; j = j->next, d++) {
pkginfo_t *targ = (pkginfo_t*)j->data;
if(strcmp(info->name, targ->name) && strhash_isin(htables[d], dbstr)) {
MALLOC(str, 512);
snprintf(str, 512, "%s: exists in \"%s\" (target) and \"%s\" (installed)", dbstr,
targ->name, info->name);
conflicts = list_add(conflicts, str);
}
}
}
}*/
/* CHECK 2: check every target against every target */
for(d = 0, i = targets; i; i = i->next, d++) { for(d = 0, i = targets; i; i = i->next, d++) {
pkginfo_t *p1 = (pkginfo_t*)i->data; pkginfo_t *p1 = (pkginfo_t*)i->data;
for(e = d, j = i; j; j = j->next, e++) { for(e = d, j = i; j; j = j->next, e++) {
@ -741,7 +757,7 @@ PMList* db_find_conflicts(pacdb_t *db, PMList *targets, char *root)
} }
} }
/* CHECK 3: check every target against the filesystem */ /* CHECK 2: check every target against the filesystem */
for(i = targets; i; i = i->next) { for(i = targets; i; i = i->next) {
pkginfo_t *p = (pkginfo_t*)i->data; pkginfo_t *p = (pkginfo_t*)i->data;
pkginfo_t *dbpkg = NULL; pkginfo_t *dbpkg = NULL;
@ -769,6 +785,7 @@ PMList* db_find_conflicts(pacdb_t *db, PMList *targets, char *root)
snprintf(str, PATH_MAX, "%s%s", root, (char*)k->data); snprintf(str, PATH_MAX, "%s%s", root, (char*)k->data);
stat(str, &buf2); stat(str, &buf2);
if(buf.st_ino == buf2.st_ino && buf.st_dev == buf2.st_dev) { if(buf.st_ino == buf2.st_ino && buf.st_dev == buf2.st_dev) {
printf("inodes match: %s and %s\n", path, str);
ok = 1; ok = 1;
} }
} }
@ -785,7 +802,26 @@ PMList* db_find_conflicts(pacdb_t *db, PMList *targets, char *root)
dbpkg2 = db_scan(db, p1->name, INFRQ_DESC | INFRQ_FILES); dbpkg2 = db_scan(db, p1->name, INFRQ_DESC | INFRQ_FILES);
/* If it used to exist in there, but doesn't anymore */ /* If it used to exist in there, but doesn't anymore */
if(dbpkg2 && !is_in(filestr, p1->files) && is_in(filestr, dbpkg2->files)) { if(dbpkg2 && !is_in(filestr, p1->files) && is_in(filestr, dbpkg2->files)) {
/*printf("file %s moved from %s to %s\n", filestr, p1->name, p->name);*/
ok = 1; ok = 1;
/* Add to the "skip list" of files that we shouldn't remove during an upgrade.
*
* This is a workaround for the following scenario:
*
* - the old package A provides file X
* - the new package A does not
* - the new package B provides file X
* - package A depends on B, so B is upgraded first
*
* Package B is upgraded, so file X is installed. Then package A
* is upgraded, and it *removes* file X, since it no longer exists
* in package A.
*
* Our workaround is to scan through all "old" packages and all "new"
* ones, looking for files that jump to different packages.
*/
*skip_list = list_add(*skip_list, filestr);
} }
FREEPKG(dbpkg2); FREEPKG(dbpkg2);
} }
@ -801,6 +837,11 @@ PMList* db_find_conflicts(pacdb_t *db, PMList *targets, char *root)
FREEPKG(dbpkg); FREEPKG(dbpkg);
} }
/* free up the hash tables */
for(d = 0; d <= target_num; d++) {
free_strhash(htables[d]);
}
return(conflicts); return(conflicts);
} }

View file

@ -22,6 +22,7 @@
#define _PAC_DB_H #define _PAC_DB_H
#include <dirent.h> #include <dirent.h>
#include "strhash.h"
/* info requests for db_read */ /* info requests for db_read */
#define INFRQ_DESC 0x01 #define INFRQ_DESC 0x01
@ -35,6 +36,9 @@ typedef struct __pacdb_t {
DIR* dir; DIR* dir;
} pacdb_t; } pacdb_t;
/* hash table for caching db_scan() results */
static strhash_t* db_htable;
pacdb_t* db_open(char *root, char *dbpath, char *treename); pacdb_t* db_open(char *root, char *dbpath, char *treename);
void db_close(pacdb_t *db); void db_close(pacdb_t *db);
int db_getlastupdate(const char *dbpath, char *ts); int db_getlastupdate(const char *dbpath, char *ts);
@ -43,8 +47,9 @@ PMList* db_loadpkgs(pacdb_t *db);
pkginfo_t* db_scan(pacdb_t *db, char *target, unsigned int inforeq); pkginfo_t* db_scan(pacdb_t *db, char *target, unsigned int inforeq);
pkginfo_t* db_read(pacdb_t *db, struct dirent *ent, unsigned int inforeq); pkginfo_t* db_read(pacdb_t *db, struct dirent *ent, unsigned int inforeq);
int db_write(pacdb_t *db, pkginfo_t *info, unsigned int inforeq); int db_write(pacdb_t *db, pkginfo_t *info, unsigned int inforeq);
void db_remove(pacdb_t *db, pkginfo_t *target);
void db_search(pacdb_t *db, PMList *cache, const char *treename, PMList *needles); void db_search(pacdb_t *db, PMList *cache, const char *treename, PMList *needles);
PMList* db_find_conflicts(pacdb_t *db, PMList* targets, char *root); PMList* db_find_conflicts(pacdb_t *db, PMList* targets, char *root, PMList **skip_list);
PMList *whatprovides(pacdb_t *db, char* package); PMList *whatprovides(pacdb_t *db, char* package);
PMList *find_groups(pacdb_t *db); PMList *find_groups(pacdb_t *db);
PMList *pkg_ingroup(pacdb_t *db, char *group); PMList *pkg_ingroup(pacdb_t *db, char *group);

View file

@ -67,17 +67,14 @@ PMList* list_new()
void list_free(PMList *list) void list_free(PMList *list)
{ {
if(list == NULL) { PMList *ptr, *it = list;
return;
while(it) {
ptr = it->next;
free(it->data);
free(it);
it = ptr;
} }
if(list->data != NULL) {
free(list->data);
list->data = NULL;
}
if(list->next != NULL) {
list_free(list->next);
}
free(list);
return; return;
} }

View file

@ -22,7 +22,7 @@
#define _PAC_PACCONF_H #define _PAC_PACCONF_H
#ifndef PACVER #ifndef PACVER
#define PACVER "2.9.5" #define PACVER "2.9.6"
#endif #endif
#ifndef PACDBDIR #ifndef PACDBDIR

View file

@ -240,7 +240,7 @@ int main(int argc, char *argv[])
/* start the requested operation */ /* start the requested operation */
switch(pmo_op) { switch(pmo_op) {
case PM_ADD: ret = pacman_add(db_local, pm_targets, NULL); break; case PM_ADD: ret = pacman_add(db_local, pm_targets, NULL); break;
case PM_REMOVE: ret = pacman_remove(db_local, pm_targets); break; case PM_REMOVE: ret = pacman_remove(db_local, pm_targets, NULL); break;
case PM_UPGRADE: ret = pacman_upgrade(db_local, pm_targets, NULL); break; case PM_UPGRADE: ret = pacman_upgrade(db_local, pm_targets, NULL); break;
case PM_QUERY: ret = pacman_query(db_local, pm_targets); break; case PM_QUERY: ret = pacman_query(db_local, pm_targets); break;
case PM_SYNC: ret = pacman_sync(db_local, pm_targets); break; case PM_SYNC: ret = pacman_sync(db_local, pm_targets); break;
@ -1323,7 +1323,7 @@ int pacman_sync(pacdb_t *db, PMList *targets)
int oldval = pmo_nodeps; int oldval = pmo_nodeps;
/* we make pacman_remove() skip dependency checks by setting pmo_nodeps high */ /* we make pacman_remove() skip dependency checks by setting pmo_nodeps high */
pmo_nodeps = 1; pmo_nodeps = 1;
retcode = pacman_remove(db, rmtargs); retcode = pacman_remove(db, rmtargs, NULL);
pmo_nodeps = oldval; pmo_nodeps = oldval;
FREELIST(rmtargs); FREELIST(rmtargs);
if(retcode == 1) { if(retcode == 1) {
@ -1356,7 +1356,7 @@ int pacman_sync(pacdb_t *db, PMList *targets)
int oldval = pmo_nodeps; int oldval = pmo_nodeps;
/* we make pacman_remove() skip dependency checks by setting pmo_nodeps high */ /* we make pacman_remove() skip dependency checks by setting pmo_nodeps high */
pmo_nodeps = 1; pmo_nodeps = 1;
allgood = !pacman_remove(db, rmtargs); allgood = !pacman_remove(db, rmtargs, NULL);
pmo_nodeps = oldval; pmo_nodeps = oldval;
if(!allgood) { if(!allgood) {
fprintf(stderr, "package removal failed. aborting...\n"); fprintf(stderr, "package removal failed. aborting...\n");
@ -1367,11 +1367,17 @@ int pacman_sync(pacdb_t *db, PMList *targets)
allgood = !pacman_upgrade(db, files, dependonly); allgood = !pacman_upgrade(db, files, dependonly);
} }
/* propagate replaced packages' requiredby fields to their new owners */ /* propagate replaced packages' requiredby fields to their new owners */
/* XXX: segfault */
if(allgood) { if(allgood) {
for(i = final; i; i = i->next) { for(i = final; i; i = i->next) {
syncpkg_t *sync = (syncpkg_t*)i->data; syncpkg_t *sync = (syncpkg_t*)i->data;
if(sync->replaces) { if(sync->replaces) {
pkginfo_t *new = db_scan(db, sync->pkg->name, INFRQ_DEPENDS); pkginfo_t *new;
new = db_scan(db, sync->pkg->name, INFRQ_DEPENDS);
if(!new) {
fprintf(stderr, "Something has gone terribly wrong. I'll probably segfault now.\n");
fflush(stderr);
}
for(j = sync->replaces; j; j = j->next) { for(j = sync->replaces; j; j = j->next) {
pkginfo_t *old = (pkginfo_t*)j->data; pkginfo_t *old = (pkginfo_t*)j->data;
/* merge lists */ /* merge lists */
@ -1448,6 +1454,8 @@ int pacman_add(pacdb_t *db, PMList *targets, PMList *dependonly)
struct stat buf; struct stat buf;
PMList *targ, *lp, *j, *k; PMList *targ, *lp, *j, *k;
PMList *alltargs = NULL; PMList *alltargs = NULL;
PMList *skiplist = NULL;
unsigned short real_pmo_upgrade; unsigned short real_pmo_upgrade;
tartype_t gztype = { tartype_t gztype = {
(openfunc_t) gzopen_frontend, (openfunc_t) gzopen_frontend,
@ -1646,7 +1654,7 @@ int pacman_add(pacdb_t *db, PMList *targets, PMList *dependonly)
alltargs = k; alltargs = k;
/* make sure pacman_remove does it's own dependency check */ /* make sure pacman_remove does it's own dependency check */
pmo_upgrade = 0; pmo_upgrade = 0;
retcode = pacman_remove(db, rmtargs); retcode = pacman_remove(db, rmtargs, NULL);
list_free(rmtargs); list_free(rmtargs);
if(retcode == 1) { if(retcode == 1) {
fprintf(stderr, "\n%s aborted.\n", oldupg ? "upgrade" : "install"); fprintf(stderr, "\n%s aborted.\n", oldupg ? "upgrade" : "install");
@ -1683,7 +1691,7 @@ int pacman_add(pacdb_t *db, PMList *targets, PMList *dependonly)
if(!pmo_force) { if(!pmo_force) {
printf("checking for file conflicts... "); printf("checking for file conflicts... ");
fflush(stdout); fflush(stdout);
lp = db_find_conflicts(db, alltargs, pmo_root); lp = db_find_conflicts(db, alltargs, pmo_root, &skiplist);
if(lp) { if(lp) {
printf("\nerror: the following file conflicts were found:\n"); printf("\nerror: the following file conflicts were found:\n");
for(j = lp; j; j = j->next) { for(j = lp; j; j = j->next) {
@ -1738,7 +1746,7 @@ int pacman_add(pacdb_t *db, PMList *targets, PMList *dependonly)
/* copy over the install reason */ /* copy over the install reason */
info->reason = oldpkg->reason; info->reason = oldpkg->reason;
vprint("removing old package first...\n"); vprint("removing old package first...\n");
retcode = pacman_remove(db, tmp); retcode = pacman_remove(db, tmp, skiplist);
FREELIST(tmp); FREELIST(tmp);
if(retcode == 1) { if(retcode == 1) {
fprintf(stderr, "\nupgrade aborted.\n"); fprintf(stderr, "\nupgrade aborted.\n");
@ -1793,7 +1801,20 @@ int pacman_add(pacdb_t *db, PMList *targets, PMList *dependonly)
snprintf(expath, PATH_MAX, "%s%s", pmo_root, pathname); snprintf(expath, PATH_MAX, "%s%s", pmo_root, pathname);
} }
if(!stat(expath, &buf) && !S_ISDIR(buf.st_mode)) { /* if a file is in NoUpgrade and missing from the filesystem,
* then we never extract it.
*
* eg, /home/httpd/html/index.html may be removed so index.php
* could be used
*/
if(stat(expath, &buf) && is_in(pathname, pmo_noupgrade)) {
vprint("%s is in NoUpgrade - skipping\n", pathname);
logaction(stderr, "warning: %s is in NoUpgrade -- skipping extraction", pathname);
tar_skip_regfile(tar);
continue;
}
if(!notouch && !stat(expath, &buf) && !S_ISDIR(buf.st_mode)) {
/* file already exists */ /* file already exists */
if(is_in(pathname, pmo_noupgrade)) { if(is_in(pathname, pmo_noupgrade)) {
notouch = 1; notouch = 1;
@ -1916,7 +1937,6 @@ int pacman_add(pacdb_t *db, PMList *targets, PMList *dependonly)
vprint("%s is in NoUpgrade - skipping\n", pathname); vprint("%s is in NoUpgrade - skipping\n", pathname);
strncat(expath, ".pacnew", PATH_MAX); strncat(expath, ".pacnew", PATH_MAX);
logaction(stderr, "warning: extracting %s%s as %s", pmo_root, pathname, expath); logaction(stderr, "warning: extracting %s%s as %s", pmo_root, pathname, expath);
/*tar_skip_regfile(tar);*/
} }
if(pmo_force) { if(pmo_force) {
/* if pmo_force was used, then unlink() each file (whether it's there /* if pmo_force was used, then unlink() each file (whether it's there
@ -1980,6 +2000,7 @@ int pacman_add(pacdb_t *db, PMList *targets, PMList *dependonly)
continue; continue;
} }
} }
FREEPKG(tmpp);
} }
vprint("Updating database..."); vprint("Updating database...");
@ -2019,6 +2040,7 @@ int pacman_add(pacdb_t *db, PMList *targets, PMList *dependonly)
if(provides) { if(provides) {
/* use the first one */ /* use the first one */
depinfo = db_scan(db, provides->data, INFRQ_DEPENDS); depinfo = db_scan(db, provides->data, INFRQ_DEPENDS);
FREELIST(provides);
if(depinfo == NULL) { if(depinfo == NULL) {
/* wtf */ /* wtf */
continue; continue;
@ -2066,7 +2088,7 @@ int pacman_add(pacdb_t *db, PMList *targets, PMList *dependonly)
return(ret); return(ret);
} }
int pacman_remove(pacdb_t *db, PMList *targets) int pacman_remove(pacdb_t *db, PMList *targets, PMList *skiplist)
{ {
char line[PATH_MAX+1]; char line[PATH_MAX+1];
char pm_install[PATH_MAX+1]; char pm_install[PATH_MAX+1];
@ -2137,8 +2159,17 @@ int pacman_remove(pacdb_t *db, PMList *targets)
for(j = lp; j; j = j->next) { for(j = lp; j; j = j->next) {
depmissing_t* miss = (depmissing_t*)j->data; depmissing_t* miss = (depmissing_t*)j->data;
info = db_scan(db, miss->depend.name, INFRQ_ALL); info = db_scan(db, miss->depend.name, INFRQ_ALL);
if(info == NULL) {
fprintf(stderr, "error: %s is not installed, even though it is required\n", miss->depend.name);
fprintf(stderr, " by an installed package (%s)\n\n", miss->target);
fprintf(stderr, "cannot complete a cascade removal with a broken dependency chain\n");
FREELISTPKGS(alltargs);
return(1);
}
if(!is_pkgin(info, alltargs)) { if(!is_pkgin(info, alltargs)) {
alltargs = list_add(alltargs, info); alltargs = list_add(alltargs, info);
} else {
FREEPKG(info);
} }
} }
list_free(lp); list_free(lp);
@ -2198,16 +2229,19 @@ int pacman_remove(pacdb_t *db, PMList *targets)
/* iterate through the list backwards, unlinking files */ /* iterate through the list backwards, unlinking files */
for(lp = list_last(info->files); lp; lp = lp->prev) { for(lp = list_last(info->files); lp; lp = lp->prev) {
int nb = 0; int nb = 0;
if(needbackup((char*)lp->data, info->backup)) { char *file;
file = (char*)lp->data;
if(needbackup(file, info->backup)) {
nb = 1; nb = 1;
} }
if(!nb && pmo_upgrade) { if(!nb && pmo_upgrade) {
/* check pmo_noupgrade */ /* check pmo_noupgrade */
if(is_in((char*)lp->data, pmo_noupgrade)) { if(is_in(file, pmo_noupgrade)) {
nb = 1; nb = 1;
} }
} }
snprintf(line, PATH_MAX, "%s%s", pmo_root, (char*)lp->data); snprintf(line, PATH_MAX, "%s%s", pmo_root, file);
if(lstat(line, &buf)) { if(lstat(line, &buf)) {
vprint("file %s does not exist\n", line); vprint("file %s does not exist\n", line);
continue; continue;
@ -2217,6 +2251,19 @@ int pacman_remove(pacdb_t *db, PMList *targets)
if(rmdir(line)) { if(rmdir(line)) {
/* this is okay, other packages are probably using it. */ /* this is okay, other packages are probably using it. */
} }
} else {
/* check the "skip list" before removing the file
*
* see the big comment block in db_find_conflicts() for an explanation
*/
int skipit = 0;
for(j = skiplist; j; j = j->next) {
if(!strcmp(file, (char*)j->data)) {
skipit = 1;
}
}
if(skipit) {
vprint("skipping removal of %s (it has moved to another package)\n", file);
} else { } else {
/* if the file is flagged, back it up to .pacsave */ /* if the file is flagged, back it up to .pacsave */
if(nb) { if(nb) {
@ -2244,6 +2291,7 @@ int pacman_remove(pacdb_t *db, PMList *targets)
} }
} }
} }
}
if(!pmo_upgrade) { if(!pmo_upgrade) {
/* run the post-remove script if it exists */ /* run the post-remove script if it exists */
@ -2252,27 +2300,11 @@ int pacman_remove(pacdb_t *db, PMList *targets)
} }
/* remove the package from the database */ /* remove the package from the database */
snprintf(line, PATH_MAX, "%s%s/%s/%s-%s", pmo_root, pmo_dbpath, db->treename, db_remove(db, info);
info->name, info->version);
/* DESC */
snprintf(pm_install, PATH_MAX, "%s/desc", line);
unlink(pm_install);
/* FILES */
snprintf(pm_install, PATH_MAX, "%s/files", line);
unlink(pm_install);
/* DEPENDS */
snprintf(pm_install, PATH_MAX, "%s/depends", line);
unlink(pm_install);
/* INSTALL */
snprintf(pm_install, PATH_MAX, "%s/install", line);
unlink(pm_install);
/* directory */
rmdir(line);
/* update dependency packages' REQUIREDBY fields */ /* update dependency packages' REQUIREDBY fields */
for(lp = info->depends; lp; lp = lp->next) { for(lp = info->depends; lp; lp = lp->next) {
PMList *j; PMList *k;
if(splitdep((char*)lp->data, &depend)) { if(splitdep((char*)lp->data, &depend)) {
continue; continue;
@ -2298,9 +2330,9 @@ int pacman_remove(pacdb_t *db, PMList *targets)
} }
} }
/* splice out this entry from requiredby */ /* splice out this entry from requiredby */
for(j = depinfo->requiredby; j; j = j->next) { for(k = depinfo->requiredby; k; k = k->next) {
if(!strcmp((char*)j->data, info->name)) { if(!strcmp((char*)k->data, info->name)) {
depinfo->requiredby = list_remove(depinfo->requiredby, j); depinfo->requiredby = list_remove(depinfo->requiredby, k);
break; break;
} }
} }
@ -2673,6 +2705,7 @@ PMList* removedeps(pacdb_t *db, PMList *targs)
FREELIST(k); FREELIST(k);
} }
if(is_pkgin(dep, targs)) { if(is_pkgin(dep, targs)) {
FREEPKG(dep);
continue; continue;
} }
/* see if it was explicitly installed */ /* see if it was explicitly installed */
@ -2687,10 +2720,11 @@ PMList* removedeps(pacdb_t *db, PMList *targs)
if(!is_pkgin(dummy, targs)) { if(!is_pkgin(dummy, targs)) {
needed = 1; needed = 1;
} }
FREEPKG(dummy);
} }
FREEPKG(dep);
if(!needed) { if(!needed) {
/* add it to the target list */ /* add it to the target list */
freepkg(dep);
dep = db_scan(db, depend.name, INFRQ_ALL); dep = db_scan(db, depend.name, INFRQ_ALL);
newtargs = list_add(newtargs, dep); newtargs = list_add(newtargs, dep);
newtargs = removedeps(db, newtargs); newtargs = removedeps(db, newtargs);
@ -2922,6 +2956,8 @@ PMList* checkdeps(pacdb_t *db, unsigned short op, PMList *targets)
strncpy(miss->depend.version, depend.version, 64); strncpy(miss->depend.version, depend.version, 64);
if(!list_isin(baddeps, miss)) { if(!list_isin(baddeps, miss)) {
baddeps = list_add(baddeps, miss); baddeps = list_add(baddeps, miss);
} else {
FREE(miss);
} }
} }
FREEPKG(p); FREEPKG(p);
@ -2969,6 +3005,8 @@ PMList* checkdeps(pacdb_t *db, unsigned short op, PMList *targets)
strncpy(miss->depend.name, dp->name, 256); strncpy(miss->depend.name, dp->name, 256);
if(!list_isin(baddeps, miss)) { if(!list_isin(baddeps, miss)) {
baddeps = list_add(baddeps, miss); baddeps = list_add(baddeps, miss);
} else {
FREE(miss);
} }
} }
} }
@ -3002,6 +3040,8 @@ PMList* checkdeps(pacdb_t *db, unsigned short op, PMList *targets)
strncpy(miss->depend.name, otp->name, 256); strncpy(miss->depend.name, otp->name, 256);
if(!list_isin(baddeps, miss)) { if(!list_isin(baddeps, miss)) {
baddeps = list_add(baddeps, miss); baddeps = list_add(baddeps, miss);
} else {
FREE(miss);
} }
} }
} }
@ -3036,6 +3076,8 @@ PMList* checkdeps(pacdb_t *db, unsigned short op, PMList *targets)
strncpy(miss->depend.name, info->name, 256); strncpy(miss->depend.name, info->name, 256);
if(!list_isin(baddeps, miss)) { if(!list_isin(baddeps, miss)) {
baddeps = list_add(baddeps, miss); baddeps = list_add(baddeps, miss);
} else {
FREE(miss);
} }
} }
} }
@ -3063,6 +3105,8 @@ PMList* checkdeps(pacdb_t *db, unsigned short op, PMList *targets)
strncpy(miss->depend.name, k->data, 256); strncpy(miss->depend.name, k->data, 256);
if(!list_isin(baddeps, miss)) { if(!list_isin(baddeps, miss)) {
baddeps = list_add(baddeps, miss); baddeps = list_add(baddeps, miss);
} else {
FREE(miss);
} }
} }
}*/ }*/
@ -3178,6 +3222,8 @@ PMList* checkdeps(pacdb_t *db, unsigned short op, PMList *targets)
strncpy(miss->depend.version, depend.version, 64); strncpy(miss->depend.version, depend.version, 64);
if(!list_isin(baddeps, miss)) { if(!list_isin(baddeps, miss)) {
baddeps = list_add(baddeps, miss); baddeps = list_add(baddeps, miss);
} else {
FREE(miss);
} }
} }
} }
@ -3200,6 +3246,8 @@ PMList* checkdeps(pacdb_t *db, unsigned short op, PMList *targets)
strncpy(miss->depend.name, (char*)j->data, 256); strncpy(miss->depend.name, (char*)j->data, 256);
if(!list_isin(baddeps, miss)) { if(!list_isin(baddeps, miss)) {
baddeps = list_add(baddeps, miss); baddeps = list_add(baddeps, miss);
} else {
FREE(miss);
} }
} }
} }
@ -3326,10 +3374,10 @@ int runscriptlet(char *installfn, char *script, char *ver, char *oldver)
vprint("Executing %s script...\n", script); vprint("Executing %s script...\n", script);
if(oldver) { if(oldver) {
snprintf(cmdline, PATH_MAX, "echo \"umask 0022; source %s %s %s %s\" | chroot %s /bin/sh", snprintf(cmdline, PATH_MAX, "echo \"umask 0022; source %s %s %s %s\" | /usr/sbin/chroot %s /bin/sh",
scriptpath, script, ver, oldver, pmo_root); scriptpath, script, ver, oldver, pmo_root);
} else { } else {
snprintf(cmdline, PATH_MAX, "echo \"umask 0022; source %s %s %s\" | chroot %s /bin/sh", snprintf(cmdline, PATH_MAX, "echo \"umask 0022; source %s %s %s\" | /usr/sbin/chroot %s /bin/sh",
scriptpath, script, ver, pmo_root); scriptpath, script, ver, pmo_root);
} }
vprint("%s\n", cmdline); vprint("%s\n", cmdline);

View file

@ -33,7 +33,7 @@
#define min(X, Y) ((X) < (Y) ? (X) : (Y)) #define min(X, Y) ((X) < (Y) ? (X) : (Y))
int pacman_add(pacdb_t *db, PMList *targets, PMList *dependonly); int pacman_add(pacdb_t *db, PMList *targets, PMList *dependonly);
int pacman_remove(pacdb_t *db, PMList *targets); int pacman_remove(pacdb_t *db, PMList *targets, PMList *skiplist);
int pacman_upgrade(pacdb_t *db, PMList *targets, PMList *dependonly); int pacman_upgrade(pacdb_t *db, PMList *targets, PMList *dependonly);
int pacman_query(pacdb_t *db, PMList *targets); int pacman_query(pacdb_t *db, PMList *targets);
int pacman_sync(pacdb_t *db, PMList *targets); int pacman_sync(pacdb_t *db, PMList *targets);

View file

@ -441,6 +441,13 @@ int downloadfiles_forreal(PMList *servers, const char *localpath,
snprintf(completefile, PATH_MAX, "%s/%s", localpath, fn); snprintf(completefile, PATH_MAX, "%s/%s", localpath, fn);
rename(output, completefile); rename(output, completefile);
} else if(filedone < 0) { } else if(filedone < 0) {
if(!pmo_xfercommand) {
if(!strcmp(server->protocol, "ftp") && !pmo_proxyhost) {
FtpQuit(control);
} else if(!strcmp(server->protocol, "http") || (pmo_proxyhost && strcmp(server->protocol, "file"))) {
HttpQuit(control);
}
}
return(-1); return(-1);
} }
printf("\n"); printf("\n");

View file

@ -16,7 +16,7 @@
You should have received a copy of the GNU General Public License You should have received a copy of the GNU General Public License
along with evtgen; see the file COPYING. If not, write to along with evtgen; see the file COPYING. If not, write to
the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
*/ */
/* Copyright (C) 2004 Tommi Rantala <tommi.rantala@cs.helsinki.fi> /* Copyright (C) 2004 Tommi Rantala <tommi.rantala@cs.helsinki.fi>
* *
@ -24,8 +24,8 @@
*/ */
/* /*
** strhash.c -- string hash utility functions ** strhash.c -- string hash utility functions
*/ */
#include <stdlib.h> #include <stdlib.h>
#include <stdio.h> #include <stdio.h>
@ -35,62 +35,54 @@
#include "list.h" #include "list.h"
#include "strhash.h" #include "strhash.h"
void void strhash_add_list(strhash_t *hash, PMList* list)
strhash_add_list(strhash_t *hash, PMList* list)
{ {
for(; list; list = list->next) for(; list; list = list->next) {
strhash_add(hash, list->data, NULL); strhash_add(hash, list->data, NULL);
}
} }
strhash_t * strhash_t* new_strhash(size_t hsize)
new_strhash(size_t hsize)
{ {
strhash_t *h; strhash_t *h;
MALLOC(h, sizeof (strhash_t)); MALLOC(h, sizeof(strhash_t));
h->size = hsize; h->size = hsize;
h->elmts = 0; h->elmts = 0;
h->hash = DEFAULT_STRHASH_FUNCTION; h->hash = DEFAULT_STRHASH_FUNCTION;
MALLOC(h->htable, hsize * sizeof (strhash_elmt_t *)); MALLOC(h->htable, hsize * sizeof(strhash_elmt_t *));
memset(h->htable, 0, hsize * sizeof(strhash_elmt_t *)); memset(h->htable, 0, hsize * sizeof(strhash_elmt_t *));
return (h); return(h);
} }
void void clear_strhash(strhash_t *hash)
clear_strhash(strhash_t *hash)
{ {
int i; int i;
strhash_elmt_t *tmp; strhash_elmt_t *tmp;
strhash_elmt_t *tmp_next; strhash_elmt_t *tmp_next;
for (i = 0; i < hash->size; i++) for(i = 0; i < hash->size; i++) {
{
tmp = hash->htable[i]; tmp = hash->htable[i];
while (tmp) while(tmp) {
{
tmp_next = tmp->next; tmp_next = tmp->next;
free(tmp); free(tmp);
tmp = tmp_next; tmp = tmp_next;
} }
} }
hash->elmts = 0; hash->elmts = 0;
memset(hash->htable, 0, hash->size * sizeof (void *)); memset(hash->htable, 0, hash->size * sizeof(void *));
} }
void free_strhash(strhash_t *hash)
void
free_strhash(strhash_t *hash)
{ {
int i; int i;
strhash_elmt_t *tmp; strhash_elmt_t *tmp;
strhash_elmt_t *tmp_next; strhash_elmt_t *tmp_next;
for (i = 0; i < hash->size; i++) for(i = 0; i < hash->size; i++) {
{
tmp = hash->htable[i]; tmp = hash->htable[i];
while (tmp) while(tmp) {
{
tmp_next = tmp->next; tmp_next = tmp->next;
free(tmp); free(tmp);
tmp = tmp_next; tmp = tmp_next;
@ -101,13 +93,12 @@ free_strhash(strhash_t *hash)
free(hash); free(hash);
} }
void void strhash_add(strhash_t *hash, char *key, char *data)
strhash_add(strhash_t *hash, char *key, char *data)
{ {
strhash_elmt_t *elmt; strhash_elmt_t *elmt;
unsigned long hcode; unsigned long hcode;
MALLOC(elmt, sizeof (strhash_elmt_t)); MALLOC(elmt, sizeof(strhash_elmt_t));
elmt->key = key; elmt->key = key;
elmt->data = data; elmt->data = data;
@ -117,56 +108,72 @@ strhash_add(strhash_t *hash, char *key, char *data)
hash->elmts++; hash->elmts++;
} }
/* 1: Yes, the key exists in the hash table. void strhash_remove(strhash_t *hash, char *key)
* 0: No, its not here. {
*/ unsigned long hcode;
strhash_elmt_t *elmt;
strhash_elmt_t *prev = NULL;
int hcode = hash->hash(key) % hash->size;
strhash_isin(strhash_t *hash, char* key)
elmt = hash->htable[hcode];
for(; elmt; elmt = elmt->next) {
if(!strcmp(key, elmt->key)) {
if(prev) {
prev->next = elmt->next;
} else {
hash->htable[hcode] = elmt->next;
}
FREE(elmt);
return;
}
prev = elmt;
}
}
/* 1: Yes, the key exists in the hash table.
* 0: No, it's not here.
*/
int strhash_isin(strhash_t *hash, char* key)
{ {
strhash_elmt_t *elmt; strhash_elmt_t *elmt;
elmt = hash->htable[hash->hash(key) % hash->size]; elmt = hash->htable[hash->hash(key) % hash->size];
for (; elmt; elmt = elmt->next) for(; elmt; elmt = elmt->next) {
{ if(!strcmp(key, elmt->key)) {
if (!strcmp(key, elmt->key))
return 1; return 1;
} }
}
return 0; return 0;
} }
char* char* strhash_get(strhash_t *hash, char* key)
strhash_get(strhash_t *hash, char* key)
{ {
strhash_elmt_t *elmt; strhash_elmt_t *elmt;
elmt = hash->htable[hash->hash(key) % hash->size]; elmt = hash->htable[hash->hash(key) % hash->size];
for (; elmt; elmt = elmt->next) for(; elmt; elmt = elmt->next) {
{ if(!strcmp(key, elmt->key)) {
if (!strcmp(key, elmt->key))
return elmt->data; return elmt->data;
} }
}
return NULL; return NULL;
} }
/* /*
** fast hash function samples ** fast hash function samples
*/ */
unsigned long strhash_pjw(char *key)
unsigned long
strhash_pjw(char *key)
{ {
unsigned long h; unsigned long h;
unsigned long g; unsigned long g;
h = 0; h = 0;
while (*key) while(*key) {
{
h = (h << 4) + *key++; h = (h << 4) + *key++;
if ((g = h & 0xF0000000U) != 0) if((g = h & 0xF0000000U) != 0) {
{
h = h ^ (g >> 24); h = h ^ (g >> 24);
h = h ^ g; h = h ^ g;
} }
@ -175,21 +182,21 @@ strhash_pjw(char *key)
return (h); return (h);
} }
int int strhash_collide_count(strhash_t *hash)
strhash_collide_count(strhash_t *hash)
{ {
int count; int count;
int i; int i;
count = 0; count = 0;
for (i = 0; i < hash->size; i++) for(i = 0; i < hash->size; i++) {
{
strhash_elmt_t *tmp; strhash_elmt_t *tmp;
for (tmp = hash->htable[i]; tmp; tmp = tmp->next) for(tmp = hash->htable[i]; tmp; tmp = tmp->next) {
if (tmp->next) if(tmp->next) {
count++; count++;
} }
}
}
return (count); return(count);
} }

View file

@ -55,6 +55,7 @@ void strhash_add_list(strhash_t *hash, PMList* list);
strhash_t *new_strhash(size_t hsize); strhash_t *new_strhash(size_t hsize);
void free_strhash(strhash_t *hash); void free_strhash(strhash_t *hash);
void clear_strhash(strhash_t *hash); void clear_strhash(strhash_t *hash);
void strhash_remove(strhash_t *hash, char *key);
void strhash_add(strhash_t *hash, char *key, char *data); void strhash_add(strhash_t *hash, char *key, char *data);
int strhash_isin(strhash_t *hash, char* key); int strhash_isin(strhash_t *hash, char* key);
char* strhash_get(strhash_t *hash, char* key); char* strhash_get(strhash_t *hash, char* key);