packages.c 10.4 KB
Newer Older
Bernhard Link's avatar
Bernhard Link committed
1
/*  This file is part of "reprepro"
2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
 *  Copyright (C) 2003 Bernhard R. Link
 *  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
 */
Bernhard Link's avatar
Bernhard Link committed
17 18
#include <config.h>

19
#include <assert.h>
Bernhard Link's avatar
Bernhard Link committed
20 21 22 23 24 25 26 27
#include <errno.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <stdio.h>
#include <malloc.h>
#include <string.h>
#include <db.h>
#include <zlib.h>
Bernhard Link's avatar
Bernhard Link committed
28
#include "error.h"
29
#include "strlist.h"
30
#include "names.h"
Bernhard Link's avatar
Bernhard Link committed
31 32
#include "md5sum.h"
#include "dirs.h"
33
#include "reference.h"
34
#include "files.h"
35
#include "target.h"
36 37
#include "packages.h"

Bernhard Link's avatar
Bernhard Link committed
38 39 40 41 42
#define CLEARDBT(dbt) {memset(&dbt,0,sizeof(dbt));}
#define SETDBT(dbt,datastr) {const char *my = datastr;memset(&dbt,0,sizeof(dbt));dbt.data=(void *)my;dbt.size=strlen(my)+1;}

extern int verbose;

43 44 45
// to make sure the problems do not arise there:
int isopen = 0;

Bernhard Link's avatar
Bernhard Link committed
46
/* release the packages-database initialized got be packages_initialize */
47
retvalue packages_done(packagesdb db) {
Bernhard Link's avatar
Bernhard Link committed
48
	int r;
49

50 51 52 53
	isopen--;
	if( isopen < 0 )
		fprintf(stderr,"isopen: %d\n",isopen);

54
	r = db->database->close(db->database,0);
Bernhard Link's avatar
Bernhard Link committed
55 56
	free(db->identifier);
	free(db);
Bernhard Link's avatar
Bernhard Link committed
57 58 59 60
	if( r < 0 )
		return RET_DBERR(r);
	else
		return RET_OK;
61 62
}

63
retvalue packages_init(packagesdb *db,const char *dbpath,const char *codename,const char *component,const char *architecture,const char *suffix) {
64 65 66
	char * identifier;
	retvalue r;

67
	identifier = calc_identifier(codename,component,architecture,suffix);
68 69 70 71 72 73
	if( ! identifier )
		return RET_ERROR_OOM;

	r = packages_initialize(db,dbpath,identifier);
	free(identifier);
	return r;
Bernhard Link's avatar
Bernhard Link committed
74 75 76
}

/* initialize the packages-database for <identifier> */
77 78
retvalue packages_initialize(packagesdb *db,const char *dbpath,const char *identifier) {
	packagesdb pkgs;
Bernhard Link's avatar
Bernhard Link committed
79
	char *filename;
80
	int dbret;
81
	retvalue r;
Bernhard Link's avatar
Bernhard Link committed
82

83
	filename=calc_dirconcat(dbpath,"packages.db");
84
	if( !filename )
85
		return RET_ERROR_OOM;
86 87
	r = dirs_make_parent(filename);
	if( RET_WAS_ERROR(r) ) {
Bernhard Link's avatar
Bernhard Link committed
88
		free(filename);
89 90 91 92 93 94
		return r;
	}
	pkgs = malloc(sizeof(struct s_packagesdb));
	if( pkgs == NULL ) {
		free(filename);
		return RET_ERROR_OOM;
Bernhard Link's avatar
Bernhard Link committed
95
	}
96 97
	pkgs->identifier = strdup(identifier);
	if( pkgs->identifier == NULL ) {
Bernhard Link's avatar
Bernhard Link committed
98
		free(filename);
99 100
		free(pkgs);
		return RET_ERROR_OOM;
Bernhard Link's avatar
Bernhard Link committed
101
	}
102
	pkgs->wasmodified = 0;
103 104 105
	
	if ((dbret = db_create(&pkgs->database, NULL, 0)) != 0) {
		fprintf(stderr, "db_create: %s:%s %s\n", filename,identifier,db_strerror(dbret));
Bernhard Link's avatar
Bernhard Link committed
106
		free(filename);
107 108 109 110
		free(pkgs->identifier);
		free(pkgs);
		return RET_DBERR(dbret);
	}
111 112 113
	isopen++;
	if( isopen > 1 )
		fprintf(stderr,"isopen: %d\n",isopen);
114 115 116 117 118 119 120
	if ((dbret = pkgs->database->open(pkgs->database, filename, identifier, DB_BTREE, DB_CREATE, 0664)) != 0) {
		pkgs->database->err(pkgs->database, dbret, "%s(%s)", filename,identifier);
		(void)pkgs->database->close(pkgs->database,0);
		free(filename);
		free(pkgs->identifier);
		free(pkgs);
		return RET_DBERR(dbret);
Bernhard Link's avatar
Bernhard Link committed
121 122
	}                     
	free(filename);
123 124
	*db = pkgs;
	return RET_OK;
Bernhard Link's avatar
Bernhard Link committed
125 126
}

Bernhard Link's avatar
Bernhard Link committed
127
/* replace a save chunk with another */
128
static retvalue packages_replace(packagesdb db,const char *package,const char *chunk) {
Bernhard Link's avatar
Bernhard Link committed
129
	int dbret;
Bernhard Link's avatar
Bernhard Link committed
130 131 132
	DBT key,data;

	SETDBT(key,package);
133
	if ((dbret = db->database->del(db->database, NULL, &key, 0)) == 0) {
134
		db->wasmodified = 1;
Bernhard Link's avatar
Bernhard Link committed
135
		if( verbose > 2 )
136
			printf("db: removed old '%s' from '%s'.\n", (const char *)key.data,db->identifier);
Bernhard Link's avatar
Bernhard Link committed
137
	} else {
138
		db->database->err(db->database, dbret, "packages.db, while removing old %s:",package);
Bernhard Link's avatar
Bernhard Link committed
139
		if( dbret != DB_NOTFOUND )
Bernhard Link's avatar
Bernhard Link committed
140
			return RET_DBERR(dbret);
Bernhard Link's avatar
Bernhard Link committed
141 142 143
	}
	SETDBT(key,package);
	SETDBT(data,chunk);
144
	if ((dbret = db->database->put(db->database, NULL, &key, &data, DB_NOOVERWRITE)) == 0) {
145
		db->wasmodified = 1;
Bernhard Link's avatar
Bernhard Link committed
146
		if( verbose > 2 )
147
			printf("db: '%s' added to '%s'.\n", (const char *)key.data,db->identifier);
Bernhard Link's avatar
Bernhard Link committed
148
		return RET_OK;
Bernhard Link's avatar
Bernhard Link committed
149
	} else {
150
		db->database->err(db->database, dbret, "packages.db(%s):",db->identifier);
Bernhard Link's avatar
Bernhard Link committed
151
		return RET_DBERR(dbret);
Bernhard Link's avatar
Bernhard Link committed
152 153 154
	}
}

Bernhard Link's avatar
Bernhard Link committed
155
/* save a given chunk in the database */
156
static retvalue packages_add(packagesdb db,const char *package,const char *chunk) {
Bernhard Link's avatar
Bernhard Link committed
157
	int dbret;
Bernhard Link's avatar
Bernhard Link committed
158 159 160 161
	DBT key,data;

	SETDBT(key,package);
	SETDBT(data,chunk);
162
	if ((dbret = db->database->put(db->database, NULL, &key, &data, DB_NOOVERWRITE)) == 0) {
163
		db->wasmodified = 1;
Bernhard Link's avatar
Bernhard Link committed
164
		if( verbose > 2 )
165
			printf("db: '%s' added to '%s'.\n", (const char *)key.data,db->identifier);
Bernhard Link's avatar
Bernhard Link committed
166
		return RET_OK;
Bernhard Link's avatar
Bernhard Link committed
167
	} else {
168
		db->database->err(db->database, dbret, "packages.db(%s):",db->identifier);
Bernhard Link's avatar
Bernhard Link committed
169
		return RET_DBERR(dbret);
Bernhard Link's avatar
Bernhard Link committed
170 171
	}
}
Bernhard Link's avatar
Bernhard Link committed
172 173

/* get the saved chunk from the database */
174
retvalue packages_get(packagesdb db,const char *package,char **chunk) {
Bernhard Link's avatar
Bernhard Link committed
175
	int dbret;
Bernhard Link's avatar
Bernhard Link committed
176 177 178 179 180
	DBT key,data;

	SETDBT(key,package);
	CLEARDBT(data);

181
	if( (dbret = db->database->get(db->database, NULL, &key, &data, 0)) == 0){
182 183 184 185 186 187 188 189
		char *c;
		c = strdup(data.data);
		if( c == NULL ) 
			return RET_ERROR_OOM;
		else {
			*chunk = c;
			return RET_OK;
		}
Bernhard Link's avatar
Bernhard Link committed
190
	} else if( dbret == DB_NOTFOUND ){
191
		return RET_NOTHING;
Bernhard Link's avatar
Bernhard Link committed
192
	} else {
193
		 db->database->err(db->database, dbret, "packages.db(%s):",db->identifier);
194
		 return RET_DBERR(dbret);
Bernhard Link's avatar
Bernhard Link committed
195 196 197
	}
}

Bernhard Link's avatar
Bernhard Link committed
198
/* remove a given chunk from the database */
199
retvalue packages_remove(packagesdb db,const char *package) {
Bernhard Link's avatar
Bernhard Link committed
200
	int dbret;
Bernhard Link's avatar
Bernhard Link committed
201 202 203
	DBT key;

	SETDBT(key,package);
204
	if ((dbret = db->database->del(db->database, NULL, &key, 0)) == 0) {
205
		db->wasmodified = 1;
Bernhard Link's avatar
Bernhard Link committed
206
		if( verbose > 2 )
207
			printf("db: '%s' removed from '%s'.\n", (const char *)key.data,db->identifier);
Bernhard Link's avatar
Bernhard Link committed
208
		return RET_OK;
Bernhard Link's avatar
Bernhard Link committed
209
	} else {
210
		db->database->err(db->database, dbret, "packages.db:");
Bernhard Link's avatar
Bernhard Link committed
211
		return RET_DBERR(dbret);
Bernhard Link's avatar
Bernhard Link committed
212 213 214
	}
}

Bernhard Link's avatar
Bernhard Link committed
215
/* check for existance of the given version of a package in the arch, */
216
retvalue package_check(packagesdb db,const char *package) {
Bernhard Link's avatar
Bernhard Link committed
217
	int dbret;
Bernhard Link's avatar
Bernhard Link committed
218 219 220 221 222
	DBT key,data;

	SETDBT(key,package);
	CLEARDBT(data);

223
	if( (dbret = db->database->get(db->database, NULL, &key, &data, 0)) == 0){
Bernhard Link's avatar
Bernhard Link committed
224 225 226
		return RET_OK;
	} else if( dbret == DB_NOTFOUND ){
		return RET_NOTHING;
Bernhard Link's avatar
Bernhard Link committed
227
	} else {
228
		 db->database->err(db->database, dbret, "packages.db(%s):",db->identifier);
Bernhard Link's avatar
Bernhard Link committed
229
		 return RET_DBERR(dbret);
Bernhard Link's avatar
Bernhard Link committed
230 231 232
	}
}

233
/* action to be called by packages_forall */
Bernhard Link's avatar
Bernhard Link committed
234
//typedef retvalue per_package_action(void *data,const char *package,const char *chunk);
Bernhard Link's avatar
Bernhard Link committed
235

236
/* call action once for each saved chunk: */
237
retvalue packages_foreach(packagesdb db,per_package_action action,void *privdata, int force) {
Bernhard Link's avatar
Bernhard Link committed
238 239
	DBC *cursor;
	DBT key,data;
Bernhard Link's avatar
Bernhard Link committed
240 241
	int dbret;
	retvalue ret,r;
Bernhard Link's avatar
Bernhard Link committed
242 243

	cursor = NULL;
244 245
	if( (dbret = db->database->cursor(db->database,NULL,&cursor,0)) != 0 ) {
		db->database->err(db->database, dbret, "packages.db(%s):",db->identifier);
246
		return RET_ERROR;
Bernhard Link's avatar
Bernhard Link committed
247 248 249 250
	}
	CLEARDBT(key);	
	CLEARDBT(data);	

Bernhard Link's avatar
Bernhard Link committed
251 252
	ret = RET_NOTHING;
	while( (dbret=cursor->c_get(cursor,&key,&data,DB_NEXT)) == 0 ) {
253
		r = action(privdata,(const char*)key.data,(const char*)data.data);
Bernhard Link's avatar
Bernhard Link committed
254
		RET_UPDATE(ret,r);
255 256 257
		if( RET_WAS_ERROR(r) && !force ) {
			if( verbose > 0 )
				fprintf(stderr,"packages_foreach: Stopping procession of further packages due to privious errors\n");
258
			break;
259
		}
260 261
		CLEARDBT(key);	
		CLEARDBT(data);	
Bernhard Link's avatar
Bernhard Link committed
262 263
	}

Bernhard Link's avatar
Bernhard Link committed
264
	if( dbret != 0 && dbret != DB_NOTFOUND ) {
265
		db->database->err(db->database, dbret, "packages.db(%s):",db->identifier);
Bernhard Link's avatar
Bernhard Link committed
266
		return RET_DBERR(dbret);
Bernhard Link's avatar
Bernhard Link committed
267
	}
Bernhard Link's avatar
Bernhard Link committed
268
	if( (dbret = cursor->c_close(cursor)) != 0 ) {
269
		db->database->err(db->database, dbret, "packages.db(%s):",db->identifier);
Bernhard Link's avatar
Bernhard Link committed
270
		return RET_DBERR(dbret);
Bernhard Link's avatar
Bernhard Link committed
271 272
	}

Bernhard Link's avatar
Bernhard Link committed
273
	return ret;
Bernhard Link's avatar
Bernhard Link committed
274 275
}

276

Bernhard Link's avatar
Bernhard Link committed
277
static retvalue printout(void *data,const char *package,const char *chunk) {
278
	FILE *pf = data;
279
	size_t l;
280

281 282
	l = strlen(chunk);
	if( fwrite(chunk,l,1,pf) != 1 || fwrite("\n",1,1,pf) != 1 )
283
		return RET_ERROR;
284 285 286 287
	else {
		if( chunk[l-1] != '\n' )
			if( fwrite("\n",1,1,pf) != 1 )
				return RET_ERROR;
288
		return RET_OK;
289
	}
290 291
}

Bernhard Link's avatar
Bernhard Link committed
292
static retvalue zprintout(void *data,const char *package,const char *chunk) {
293
	gzFile pf = data;
294
	size_t l;
295

296 297 298
	l = strlen(chunk);
	if( gzwrite(pf,(const voidp)chunk,l) != l || gzwrite(pf,"\n",1) != 1 )
		return RET_ERROR;
299 300 301 302
	else {
		if( chunk[l-1] != '\n' )
			if( gzwrite(pf,"\n",1) != 1 )
				return RET_ERROR;
303
		return RET_OK;
304
	}
305 306 307
}

/* print the database to a "Packages" or "Sources" file */
308
static retvalue packages_printout(packagesdb packagesdb,const char *filename) {
Bernhard Link's avatar
Bernhard Link committed
309 310
	retvalue ret;
	int r;
311
	FILE *pf;
Bernhard Link's avatar
Bernhard Link committed
312

313 314 315
	pf = fopen(filename,"wb");
	if( !pf ) {
		fprintf(stderr,"Error creating '%s': %m\n",filename);
Bernhard Link's avatar
Bernhard Link committed
316
		return RET_ERRNO(errno);
Bernhard Link's avatar
Bernhard Link committed
317
	}
318
	ret = packages_foreach(packagesdb,printout,pf,0);
Bernhard Link's avatar
Bernhard Link committed
319 320
	r = fclose(pf);
	if( r != 0 )
Bernhard Link's avatar
Bernhard Link committed
321
		RET_ENDUPDATE(ret,RET_ERRNO(errno));
322 323
	return ret;
}
Bernhard Link's avatar
Bernhard Link committed
324

325
/* print the database to a "Packages.gz" or "Sources.gz" file */
326
static retvalue packages_zprintout(packagesdb packagesdb,const char *filename) {
Bernhard Link's avatar
Bernhard Link committed
327 328
	retvalue ret;
	int r;
329
	gzFile pf;
Bernhard Link's avatar
Bernhard Link committed
330 331 332 333

	pf = gzopen(filename,"wb");
	if( !pf ) {
		fprintf(stderr,"Error creating '%s': %m\n",filename);
Bernhard Link's avatar
Bernhard Link committed
334 335
		/* if errno is zero, it's a memory error: */
		return RET_ERRNO(errno);
Bernhard Link's avatar
Bernhard Link committed
336
	}
337
	ret = packages_foreach(packagesdb,zprintout,pf,0);
Bernhard Link's avatar
Bernhard Link committed
338 339
	r = gzclose(pf);
	if( r < 0 )
Bernhard Link's avatar
Bernhard Link committed
340
		RET_ENDUPDATE(ret,RET_ZERRNO(r));
341
	return ret;
Bernhard Link's avatar
Bernhard Link committed
342
}
343

344 345 346
retvalue packages_export(packagesdb packagesdb,const char *filename,indexcompression compression) {
	assert( compression >= 0 && compression <= ic_max );

347
	if( verbose > 4 ) {
348 349 350
		fprintf(stderr,"  writing to '%s'...\n",filename);
	}

351 352 353 354 355 356 357 358 359 360 361
	switch( compression ) {
		case ic_uncompressed:
			return packages_printout(packagesdb,filename);
		case ic_gzip:
			return packages_zprintout(packagesdb,filename);
		default:
			assert(0);
			return RET_ERROR;
	}
}

362
retvalue packages_insert(DB *referencesdb, packagesdb packagesdb,
363 364 365
		const char *packagename, const char *controlchunk,
		const struct strlist *files,
		const struct strlist *oldfiles) {
366
		
367 368 369 370 371

	retvalue result,r;

	/* mark it as needed by this distribution */

372
	r = references_insert(referencesdb,packagesdb->identifier,files,oldfiles);
373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391

	if( RET_WAS_ERROR(r) )
		return r;

	/* Add package to the distribution's database */

	if( oldfiles != NULL ) {
		result = packages_replace(packagesdb,packagename,controlchunk);

	} else {
		result = packages_add(packagesdb,packagename,controlchunk);
	}

	if( RET_WAS_ERROR(result) )
		return result;

	/* remove old references to files */

	if( oldfiles != NULL ) {
392
		r = references_delete(referencesdb,packagesdb->identifier,
393 394 395 396 397 398 399
				oldfiles,files);
		RET_UPDATE(result,r);
	}

	return result;
}