diff -rNubB src/pacman-2.9.8/src/db.c /home/devik/proj/pacman-2.9.8/src/db.c --- src/pacman-2.9.8/src/db.c 2006-01-31 01:27:42.000000000 +0100 +++ /home/devik/proj/pacman-2.9.8/src/db.c 2006-08-31 23:43:26.000000000 +0200 @@ -23,6 +23,7 @@ #include #include #include +#include #include #include #include @@ -33,41 +34,13 @@ #include "util.h" #include "db.h" -/* Open a database and return a pacdb_t handle */ -pacdb_t* db_open(char *root, char *pkgdir, char *treename) -{ - pacdb_t *db = NULL; - - MALLOC(db, sizeof(pacdb_t)); - MALLOC(db->path, strlen(root)+strlen(pkgdir)+strlen(treename)+2); - sprintf(db->path, "%s%s/%s", root, pkgdir, treename); - db->dir = opendir(db->path); - if(db->dir == NULL) { - return(NULL); - } - strncpy(db->treename, treename, sizeof(db->treename)-1); - - return(db); -} - -void db_close(pacdb_t* db) -{ - if(db) { - if(db->dir) { - closedir(db->dir); - } - FREE(db->path); - } - FREE(db); - - return; -} +extern unsigned short pmo_gdbm; /* reads dbpath/.lastupdate and populates *ts with the contents. * *ts should be malloc'ed and should be at least 15 bytes. * * Returns 0 on success, 1 on error - * + * Note, this is on the filesystem even if DBM is in use. */ int db_getlastupdate(const char *dbpath, char *ts) { @@ -118,8 +91,8 @@ pkginfo_t *info; PMList *cache = NULL; - rewinddir(db->dir); - while((info = db_scan(db, NULL, INFRQ_DESC | INFRQ_DEPENDS)) != NULL) { + db->ops->rewind(db); + while((info = db->ops->scan(db, NULL, INFRQ_DESC | INFRQ_DEPENDS)) != NULL) { /* add to the collective */ cache = list_add_sorted(cache, info, pkgcmp); } @@ -127,7 +100,7 @@ return(cache); } -pkginfo_t* db_scan(pacdb_t *db, char *target, unsigned int inforeq) +pkginfo_t* db_file_scan(pacdb_t *db, char *target, unsigned int inforeq) { struct dirent *ent = NULL; struct stat sbuf; @@ -163,18 +136,7 @@ /* See if we have the path cached. */ strcat(path, target); if(strhash_isin(db_htable, path)) { - struct dirent* pkgdir; - pkginfo_t* pkg; - - /* db_read() wants 'struct dirent' so lets give it one. - * Actually it only uses the d_name field. */ - - MALLOC(pkgdir, sizeof(struct dirent)); - strcpy(pkgdir->d_name, strhash_get(db_htable, path)); - - pkg = db_read(db, pkgdir, inforeq); - FREE(pkgdir); - return pkg; + return db_read(db,strhash_get(db_htable, path), inforeq); } path[path_len] = '\0'; @@ -258,10 +220,11 @@ } } } - return(db_read(db, ent, inforeq)); + return(db_read(db, ent->d_name, inforeq)); } -pkginfo_t* db_read(pacdb_t *db, struct dirent *ent, unsigned int inforeq) +/* ent is name recognized by ops->fopen(db,ent,"part","mode") */ +pkginfo_t* db_read(pacdb_t *db, const char *ent, unsigned int inforeq) { FILE *fp = NULL; struct stat buf; @@ -269,25 +232,16 @@ char path[PATH_MAX]; char line[512]; - if(ent == NULL) { - return(NULL); - } + assert(ent); /* we always load DESC */ inforeq |= INFRQ_DESC; - snprintf(path, PATH_MAX, "%s/%s", db->path, ent->d_name); - if(stat(path, &buf)) { - /* directory doesn't exist or can't be opened */ - return(NULL); - } - info = newpkg(); /* DESC */ if(inforeq & INFRQ_DESC) { - snprintf(path, PATH_MAX, "%s/%s/desc", db->path, ent->d_name); - fp = fopen(path, "r"); + fp = db->ops->fopen(db,ent,"desc", "r"); if(fp == NULL) { fprintf(stderr, "error: %s: %s\n", path, strerror(errno)); FREEPKG(info); @@ -410,8 +364,7 @@ /* FILES */ if(inforeq & INFRQ_FILES) { - snprintf(path, PATH_MAX, "%s/%s/files", db->path, ent->d_name); - fp = fopen(path, "r"); + fp = db->ops->fopen(db,ent,"files", "r"); if(fp == NULL) { fprintf(stderr, "error: %s: %s\n", path, strerror(errno)); FREEPKG(info); @@ -437,8 +390,7 @@ /* DEPENDS */ if(inforeq & INFRQ_DEPENDS) { - snprintf(path, PATH_MAX, "%s/%s/depends", db->path, ent->d_name); - fp = fopen(path, "r"); + fp = db->ops->fopen(db,ent,"depends", "r"); if(fp == NULL) { fprintf(stderr, "db_read: error: %s: %s\n", path, strerror(errno)); FREEPKG(info); @@ -475,9 +427,9 @@ fclose(fp); } - /* INSTALL */ + /* INSTALL TODO */ if(inforeq & INFRQ_ALL) { - snprintf(path, PATH_MAX, "%s/%s/install", db->path, ent->d_name); + snprintf(path, PATH_MAX, "%s/%s/install", db->path, ent); if(!stat(path, &buf)) { info->scriptlet = 1; } @@ -486,32 +438,31 @@ return(info); } +void db_file_mkpkg(pacdb_t *db,const char *pkg) +{ + char buf[PATH_MAX]; + snprintf(buf, PATH_MAX, "%s/%s", db->path, pkg); + mkdir(buf, 0755); +} + int db_write(pacdb_t *db, pkginfo_t *info, unsigned int inforeq) { char topdir[PATH_MAX]; FILE *fp = NULL; - char path[PATH_MAX]; - mode_t oldmask; PMList *lp = NULL; if(info == NULL) { return(1); } - snprintf(topdir, PATH_MAX, "%s/%s-%s", db->path, - info->name, info->version); - oldmask = umask(0000); - mkdir(topdir, 0755); - /* make sure we have a sane umask */ - umask(0022); + snprintf(topdir, PATH_MAX, "%s-%s", info->name, info->version); + db->ops->mkpkg(db,topdir); /* DESC */ if(inforeq & INFRQ_DESC) { - snprintf(path, PATH_MAX, "%s/desc", topdir); - fp = fopen(path, "w"); + fp = db->ops->fopen(db,topdir,"desc", "w"); if(fp == NULL) { perror("db_write"); - umask(oldmask); return(1); } fputs("%NAME%\n", fp); @@ -549,11 +500,9 @@ /* FILES */ if(inforeq & INFRQ_FILES) { - snprintf(path, PATH_MAX, "%s/files", topdir); - fp = fopen(path, "w"); + fp = db->ops->fopen(db,topdir,"files", "w"); if(fp == NULL) { perror("db_write"); - umask(oldmask); return(1); } fputs("%FILES%\n", fp); @@ -571,11 +520,9 @@ /* DEPENDS */ if(inforeq & INFRQ_DEPENDS) { - snprintf(path, PATH_MAX, "%s/depends", topdir); - fp = fopen(path, "w"); + fp = db->ops->fopen(db,topdir,"depends", "w"); if(fp == NULL) { perror("db_write"); - umask(oldmask); return(1); } fputs("%DEPENDS%\n", fp); @@ -604,14 +551,13 @@ /* INSTALL */ /* nothing needed here (script is automatically extracted) */ - umask(oldmask); return(0); } /* * Remove a package record from the database */ -void db_remove(pacdb_t *db, pkginfo_t *target) +void db_file_remove(pacdb_t *db, pkginfo_t *target) { char topdir[PATH_MAX]; char path[PATH_MAX]; @@ -870,7 +816,7 @@ PMList *pkgs, *i = NULL; pkginfo_t *info; - rewinddir(db->dir); + db->ops->rewind(db); while((info = db_scan(db, NULL, INFRQ_DESC | INFRQ_DEPENDS)) != NULL) { if(is_in(package, info->provides)) { i = list_add(i, strdup(info->name)); @@ -893,7 +839,7 @@ PMList *lp = NULL; pkginfo_t *info; - rewinddir(db->dir); + db->ops->rewind(db); while((info = db_scan(db, NULL, INFRQ_DESC)) != NULL) { for(lp = info->groups; lp; lp = lp->next) { if(!is_in((char*)lp->data, i)) { @@ -918,7 +864,7 @@ PMList *lp = NULL; pkginfo_t *info; - rewinddir(db->dir); + db->ops->rewind(db); while((info = db_scan(db, NULL, INFRQ_DESC)) != NULL) { for(lp = info->groups; lp; lp = lp->next) { if(!strcmp((char*)lp->data, group)) { @@ -933,4 +879,67 @@ return(pkg); } +static int db_file_rewind(pacdb_t *db) +{ + rewinddir(db->dir); + return 0; +} + +FILE *db_file_fopen(pacdb_t *db,const char *pkg,const char *section,const char *mode) +{ + char buf[PATH_MAX]; FILE *f; + mode_t oldmask = umask(0022); + snprintf(buf,PATH_MAX,"%s/%s",pkg,section); + f = fopen(buf,mode); + umask(oldmask); + return f; +} + +extern struct pacdb_vtable db_dbm_ops; +struct pacdb_vtable db_file_ops = { + db_file_rewind, + db_file_scan, + db_file_fopen, + db_file_mkpkg, + db_file_remove +}; + +/* Open a database and return a pacdb_t handle. It attempts to + * open it as DBM if possible. + **/ +pacdb_t* db_open(char *root, char *pkgdir, char *treename) +{ + pacdb_t *db = NULL; + + MALLOC(db, sizeof(pacdb_t)); + memset(db,0,sizeof(pacdb_t)); + MALLOC(db->path, strlen(root)+strlen(pkgdir)+strlen(treename)+5); + strncpy(db->treename, treename, sizeof(db->treename)-1); + if(pmo_gdbm) { + sprintf(db->path, "%s%s/%s/db", root, pkgdir, treename); + db->ops = &db_dbm_ops; + db->dbm = gdbm_open(db->path, 0, GDBM_WRCREAT, 0644, NULL); + if(db->dbm) + return(db); + } else { + sprintf(db->path, "%s%s/%s", root, pkgdir, treename); + if ((db->dir = opendir(db->path)) != NULL) { + db->ops = &db_file_ops; + return(db); + } + } + db_close(db); + return(NULL); +} + +void db_close(pacdb_t* db) +{ + if(db) { + if(db->dir) closedir(db->dir); + if(db->dbm) gdbm_close(db->dbm); + FREE(db->path); + } + FREE(db); +} + /* vim: set ts=2 sw=2 noet: */ diff -rNubB src/pacman-2.9.8/src/db.h /home/devik/proj/pacman-2.9.8/src/db.h --- src/pacman-2.9.8/src/db.h 2006-01-31 01:27:43.000000000 +0100 +++ /home/devik/proj/pacman-2.9.8/src/db.h 2006-08-31 22:47:55.000000000 +0200 @@ -22,6 +22,7 @@ #define _PAC_DB_H #include +#include #include "strhash.h" /* info requests for db_read */ @@ -30,12 +31,27 @@ #define INFRQ_FILES 0x04 #define INFRQ_ALL 0xFF +struct pacdb_vtable; typedef struct __pacdb_t { char *path; - char treename[128]; - DIR* dir; + char treename[128]; /* path to the tree or to GDBM file */ + + DIR* dir; /* directory if used or ... */ + GDBM_FILE dbm; /* ... database, one of them is NULL */ + datum nkey; /* next key to be used in DBM scan */ + + struct pacdb_vtable *ops; + } pacdb_t; +struct pacdb_vtable { + int (*rewind)(pacdb_t *db); + pkginfo_t* (*scan)(pacdb_t *db, char *target, unsigned int inforeq); + FILE *(*fopen)(pacdb_t *db,const char *pkg,const char *section,const char *mode); + void (*mkpkg)(pacdb_t *db,const char *pkg); + void (*remove)(pacdb_t *db, pkginfo_t *target); +}; + /* hash table for caching db_scan() results */ static strhash_t* db_htable; @@ -44,10 +60,18 @@ int db_getlastupdate(const char *dbpath, char *ts); int db_setlastupdate(const char *dbpath, const char *ts); PMList* db_loadpkgs(pacdb_t *db); -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); + +static pkginfo_t* db_scan(pacdb_t *db, char *target, unsigned int inforeq) +{ + return db->ops->scan(db,target,inforeq); +} + +pkginfo_t* db_read(pacdb_t *db, const char *ent, unsigned int inforeq); int db_write(pacdb_t *db, pkginfo_t *info, unsigned int inforeq); -void db_remove(pacdb_t *db, pkginfo_t *target); +static void db_remove(pacdb_t *db, pkginfo_t *target) +{ + db->ops->remove(db,target); +} 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 **skip_list); PMList *whatprovides(pacdb_t *db, char* package); diff -rNubB src/pacman-2.9.8/src/dbm.c /home/devik/proj/pacman-2.9.8/src/dbm.c --- src/pacman-2.9.8/src/dbm.c 1970-01-01 01:00:00.000000000 +0100 +++ /home/devik/proj/pacman-2.9.8/src/dbm.c 2006-08-31 23:41:37.000000000 +0200 @@ -0,0 +1,241 @@ +/* + * dbm.c + * + * Copyright (c) 2006 by Martin Devera + * + * 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. + * + * Implements in-GDBM database storage + */ + +#include "config.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "package.h" +#include "util.h" +#include "db.h" + +/* We use keys in format: TAG \t STRING \0, TAG is chapter name + * (files,depends...) or special name VER which maps bare package + * name to the one with version added + */ + +/* non reentrant ! */ +static datum mk_tagged_key(const char *tag,const char *str) +{ + static char buf[128]; + datum key; + snprintf(buf,128,"%s\t%s",tag,str); + key.dptr = buf; + key.dsize = strlen(buf); + return key; +} + +static const char *pkg_base(const char *pkg) +{ + static char buf[128]; char *p; + strncpy(buf,pkg,128); + if ((p=rindex(buf,'-')) != NULL) *p = 0; + if ((p=rindex(buf,'-')) != NULL) *p = 0; + return buf; +} + +int tgz_to_dbm(char *archive, const char *dir) +{ + GDBM_FILE db; + char path[PATH_MAX]; + TAR *tar = NULL; + tartype_t gztype = { + (openfunc_t) gzopen_frontend, + (closefunc_t)gzclose, + (readfunc_t) gzread, + (writefunc_t)gzwrite + }; + /* open the .tar.gz package */ + if(tar_open(&tar, archive, &gztype, O_RDONLY, 0, TAR_GNU) == -1) { + perror(archive); + return(1); + } + snprintf(path,PATH_MAX,"%s/db",dir); + db = gdbm_open(path, 0, GDBM_NEWDB|GDBM_FAST, 0644, NULL); + if (!db) { + perror(path); + tar_close(tar); + return(1); + } + while(!th_read(tar)) { + char *path = th_get_pathname(tar); + char *pkg = strsep(&path,"/"); + datum data,full; + int aligned_sz,i; + if (!pkg || !path || !TH_ISREG(tar)) continue; + data.dsize = th_get_size(tar)+1; + aligned_sz = (data.dsize+T_BLOCKSIZE-2) & ~(T_BLOCKSIZE-1); + data.dptr = malloc(aligned_sz+1); + data.dptr[data.dsize] = 0; + full.dptr = pkg; + full.dsize = strlen(pkg)+1; + for (i=0;inkey = gdbm_firstkey(db->dbm); + return 0; +} + +struct cookie_def { + GDBM_FILE write_db; + char *pkg; + char *section; + datum data; + int rpos; +}; + +ssize_t cook_read(void *cookie, char *buffer, size_t size) +{ + struct cookie_def *c = (struct cookie_def*)cookie; + int rem = c->data.dsize-c->rpos; + if(size > rem) size = rem; + memcpy(buffer,c->data.dptr+c->rpos,size); + c->rpos += size; + return size; +} + +ssize_t cook_write(void *cookie, const char *buffer, size_t size) +{ + struct cookie_def *c = (struct cookie_def*)cookie; + c->data.dsize += size; + c->data.dptr = realloc(c->data.dptr,c->data.dsize); + memcpy(c->data.dptr+c->data.dsize-size,buffer,size); + return size; +} + +int cook_seek(void *cookie, _IO_off64_t *position, int whence) +{ + return -1; +} + +int cook_close(void *cookie) +{ + int rv = 0; + struct cookie_def *c = (struct cookie_def*)cookie; + if (c->write_db) + rv = gdbm_store(c->write_db,mk_tagged_key(c->section,c->pkg),c->data,GDBM_REPLACE)?-1:0; + free(c->data.dptr); + free(c->section); + free(c->pkg); + free(c); +} + +cookie_io_functions_t cops = { + cook_read, + cook_write, + cook_seek, + cook_close }; +FILE *dbm_fopen(pacdb_t *db,const char *pkg,const char *section,const char *mode) +{ + struct cookie_def *cook = calloc(1,sizeof(struct cookie_def)); + if (mode[0]=='w') + cook->write_db = db->dbm; + else { + cook->data = gdbm_fetch(db->dbm,mk_tagged_key(section,pkg)); + if (!cook->data.dptr) { + free(cook); + return NULL; + } + } + cook->section = strdup(section); + cook->pkg = strdup(pkg); + return fopencookie(cook,mode,cops); +} + +void dbm_mkpkg(pacdb_t *db,const char *pkg) +{ + datum d; + d.dsize = strlen(pkg)+1; + d.dptr = (char*)pkg; + gdbm_store(db->dbm,mk_tagged_key("VER",pkg_base(pkg)),d,GDBM_REPLACE); +} + +void dbm_remove(pacdb_t *db, pkginfo_t *target) +{ + char name[PATH_MAX]; + + snprintf(name, PATH_MAX, "%s-%s", target->name, target->version); + gdbm_delete(db->dbm,mk_tagged_key("VER",target->name)); + gdbm_delete(db->dbm,mk_tagged_key("depends",target->name)); + gdbm_delete(db->dbm,mk_tagged_key("desc",target->name)); + gdbm_delete(db->dbm,mk_tagged_key("files",target->name)); + gdbm_delete(db->dbm,mk_tagged_key("install",target->name)); +} + +static pkginfo_t* dbm_scan(pacdb_t *db, char *target, unsigned int inforeq) +{ + datum data; + pkginfo_t *pkg; + if(target != NULL) { + /* search for a specific package (by name only) */ + data = gdbm_fetch(db->dbm,mk_tagged_key("VER",target)); + } else { + /* normal iteration: return next VER item */ + while (db->nkey.dptr && strncmp(db->nkey.dptr,"VER\t",4)) + db->nkey = gdbm_nextkey (db->dbm, db->nkey); + if(!db->nkey.dptr) return NULL; + data = gdbm_fetch(db->dbm,db->nkey); + db->nkey = gdbm_nextkey (db->dbm, db->nkey); + } + if(!data.dptr) return NULL; + pkg = db_read(db, data.dptr, inforeq); + free(data.dptr); + return pkg; +} +struct pacdb_vtable db_dbm_ops = { + dbm_rewind, + dbm_scan, + dbm_fopen, + dbm_mkpkg, + dbm_remove +}; diff -rNubB src/pacman-2.9.8/src/pacman.c /home/devik/proj/pacman-2.9.8/src/pacman.c --- src/pacman-2.9.8/src/pacman.c 2006-01-31 01:27:43.000000000 +0100 +++ /home/devik/proj/pacman-2.9.8/src/pacman.c 2006-09-01 00:17:25.000000000 +0200 @@ -98,6 +98,7 @@ PMList *pmo_ignorepkg = NULL; PMList *pmo_holdpkg = NULL; unsigned short pmo_chomp = 0; +unsigned short pmo_gdbm = 0; unsigned short pmo_usesyslog = 0; unsigned short pmo_nopassiveftp = 0; @@ -2597,7 +2598,7 @@ } if(rel2abs(package, rpath, sizeof(rpath)-1)) { int gotcha = 0; - rewinddir(db->dir); + db->ops->rewind(db); while((info = db_scan(db, NULL, INFRQ_DESC | INFRQ_FILES)) != NULL && !gotcha) { for(lp = info->files; lp && !gotcha; lp = lp->next) { sprintf(path, "%s%s", pmo_root, (char*)lp->data); @@ -3269,7 +3270,7 @@ } } /* check database against targets */ - rewinddir(db->dir); + db->ops->rewind(db); while((info = db_scan(db, NULL, INFRQ_DESC | INFRQ_DEPENDS)) != NULL) { for(j = info->conflicts; j; j = j->next) { int conflict = 0; @@ -3824,6 +3825,8 @@ vprint("config: usesyslog\n"); } else if(!strcmp(key, "ILOVECANDY")) { pmo_chomp = 1; + } else if(!strcmp(key, "USEGDBM")) { + pmo_gdbm = 1; } else { fprintf(stderr, "config: line %d: syntax error\n", linenum); return(1); Binární soubory src/pacman-2.9.8/src/pacman.o a /home/devik/proj/pacman-2.9.8/src/pacman.o jsou různé diff -rNubB src/pacman-2.9.8/src/pacsync.c /home/devik/proj/pacman-2.9.8/src/pacsync.c --- src/pacman-2.9.8/src/pacsync.c 2006-01-31 01:27:43.000000000 +0100 +++ /home/devik/proj/pacman-2.9.8/src/pacsync.c 2006-08-31 22:37:40.000000000 +0200 @@ -54,6 +54,7 @@ extern unsigned short pmo_nopassiveftp; extern unsigned short pmo_noprogressbar; extern unsigned short pmo_chomp; +extern unsigned short pmo_gdbm; /* sync servers */ extern PMList *pmc_syncs; @@ -116,7 +117,8 @@ /* uncompress the sync database */ vprint("unpacking %s...\n", path); - if(unpack(path, ldir, NULL)) { + if((pmo_gdbm && tgz_to_dbm(path,ldir)) || + (!pmo_gdbm && unpack(path, ldir, NULL))) { return(1); }