librazor/razor.c
author Kristian H?gsberg <krh@redhat.com>
Fri Jun 20 21:38:29 2008 -0400 (2008-06-20)
changeset 253 338a577cdfd2
parent 248 057933050c42
child 254 ccb1c11968ab
permissions -rw-r--r--
Fix the razor_set_diff() callback prototype.

The old proto type didn't let us pass the razor_package.
rhughes@241
     1
/*
rhughes@241
     2
 * Copyright (C) 2008  Kristian Høgsberg <krh@redhat.com>
rhughes@241
     3
 * Copyright (C) 2008  Red Hat, Inc
rhughes@241
     4
 *
rhughes@241
     5
 * This program is free software; you can redistribute it and/or modify
rhughes@241
     6
 * it under the terms of the GNU General Public License as published by
rhughes@241
     7
 * the Free Software Foundation; either version 2 of the License, or
rhughes@241
     8
 * (at your option) any later version.
rhughes@241
     9
 *
rhughes@241
    10
 * This program is distributed in the hope that it will be useful,
rhughes@241
    11
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
rhughes@241
    12
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
rhughes@241
    13
 * GNU General Public License for more details.
rhughes@241
    14
 *
rhughes@241
    15
 * You should have received a copy of the GNU General Public License along
rhughes@241
    16
 * with this program; if not, write to the Free Software Foundation, Inc.,
rhughes@241
    17
 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
rhughes@241
    18
 */
rhughes@241
    19
rhughes@241
    20
#define _GNU_SOURCE
rhughes@241
    21
rhughes@241
    22
#include <stdlib.h>
rhughes@241
    23
#include <stddef.h>
rhughes@241
    24
#include <stdint.h>
rhughes@241
    25
#include <stdio.h>
rhughes@241
    26
#include <string.h>
rhughes@241
    27
#include <sys/types.h>
rhughes@241
    28
#include <sys/stat.h>
rhughes@241
    29
#include <sys/mman.h>
rhughes@241
    30
#include <unistd.h>
rhughes@241
    31
#include <fcntl.h>
rhughes@241
    32
#include <errno.h>
rhughes@241
    33
#include <ctype.h>
rhughes@241
    34
#include <fnmatch.h>
rhughes@241
    35
krh@253
    36
#include "razor-internal.h"
rhughes@241
    37
#include "razor.h"
rhughes@241
    38
krh@248
    39
void *
rhughes@241
    40
zalloc(size_t size)
rhughes@241
    41
{
rhughes@241
    42
	void *p;
rhughes@241
    43
rhughes@241
    44
	p = malloc(size);
rhughes@241
    45
	memset(p, 0, size);
rhughes@241
    46
rhughes@241
    47
	return p;
rhughes@241
    48
}
rhughes@241
    49
rhughes@241
    50
struct razor_set_section razor_sections[] = {
rhughes@241
    51
	{ RAZOR_STRING_POOL,	offsetof(struct razor_set, string_pool) },
rhughes@241
    52
	{ RAZOR_PACKAGES,	offsetof(struct razor_set, packages) },
rhughes@241
    53
	{ RAZOR_PROPERTIES,	offsetof(struct razor_set, properties) },
rhughes@241
    54
	{ RAZOR_FILES,		offsetof(struct razor_set, files) },
rhughes@241
    55
	{ RAZOR_PACKAGE_POOL,	offsetof(struct razor_set, package_pool) },
rhughes@241
    56
	{ RAZOR_PROPERTY_POOL,	offsetof(struct razor_set, property_pool) },
rhughes@241
    57
	{ RAZOR_FILE_POOL,	offsetof(struct razor_set, file_pool) },
rhughes@241
    58
};
rhughes@241
    59
rhughes@241
    60
struct razor_set *
rhughes@241
    61
razor_set_create(void)
rhughes@241
    62
{
rhughes@241
    63
	struct razor_set *set;
rhughes@241
    64
	struct razor_entry *e;
rhughes@241
    65
	char *empty;
rhughes@241
    66
rhughes@241
    67
	set = zalloc(sizeof *set);
rhughes@241
    68
rhughes@241
    69
	e = array_add(&set->files, sizeof *e);
rhughes@241
    70
	empty = array_add(&set->string_pool, 1);
rhughes@241
    71
	*empty = '\0';
rhughes@241
    72
	e->name = 0;
rhughes@241
    73
	e->flags = RAZOR_ENTRY_LAST;
rhughes@241
    74
	e->start = 0;
rhughes@241
    75
	list_set_empty(&e->packages);
rhughes@241
    76
rhughes@241
    77
	return set;
rhughes@241
    78
}
rhughes@241
    79
rhughes@241
    80
struct razor_set *
rhughes@241
    81
razor_set_open(const char *filename)
rhughes@241
    82
{
rhughes@241
    83
	struct razor_set *set;
rhughes@241
    84
	struct razor_set_section *s;
rhughes@241
    85
	struct stat stat;
rhughes@241
    86
	struct array *array;
rhughes@241
    87
	int fd;
rhughes@241
    88
rhughes@241
    89
	set = zalloc(sizeof *set);
rhughes@241
    90
	fd = open(filename, O_RDONLY);
rhughes@241
    91
	if (fstat(fd, &stat) < 0)
rhughes@241
    92
		return NULL;
rhughes@241
    93
	set->header = mmap(NULL, stat.st_size, PROT_READ, MAP_PRIVATE, fd, 0);
rhughes@241
    94
	if (set->header == MAP_FAILED) {
rhughes@241
    95
		free(set);
rhughes@241
    96
		return NULL;
rhughes@241
    97
	}
rhughes@241
    98
rhughes@241
    99
	for (s = set->header->sections; ~s->type; s++) {
rhughes@241
   100
		if (s->type >= ARRAY_SIZE(razor_sections))
rhughes@241
   101
			continue;
rhughes@241
   102
		if (s->type != razor_sections[s->type].type)
rhughes@241
   103
			continue;
rhughes@241
   104
		array = (void *) set + razor_sections[s->type].offset;
rhughes@241
   105
		array->data = (void *) set->header + s->offset;
rhughes@241
   106
		array->size = s->size;
rhughes@241
   107
		array->alloc = s->size;
rhughes@241
   108
	}
rhughes@241
   109
	close(fd);
rhughes@241
   110
rhughes@241
   111
	return set;
rhughes@241
   112
}
rhughes@241
   113
rhughes@241
   114
void
rhughes@241
   115
razor_set_destroy(struct razor_set *set)
rhughes@241
   116
{
rhughes@241
   117
	unsigned int size;
rhughes@241
   118
	struct array *a;
rhughes@241
   119
	int i;
rhughes@241
   120
rhughes@241
   121
	if (set->header) {
rhughes@241
   122
		for (i = 0; set->header->sections[i].type; i++)
rhughes@241
   123
			;
rhughes@241
   124
		size = set->header->sections[i].type;
rhughes@241
   125
		munmap(set->header, size);
rhughes@241
   126
	} else {
rhughes@241
   127
		for (i = 0; i < ARRAY_SIZE(razor_sections); i++) {
rhughes@241
   128
			a = (void *) set + razor_sections[i].offset;
rhughes@241
   129
			free(a->data);
rhughes@241
   130
		}
rhughes@241
   131
	}
rhughes@241
   132
rhughes@241
   133
	free(set);
rhughes@241
   134
}
rhughes@241
   135
rhughes@241
   136
int
rhughes@241
   137
razor_set_write_to_fd(struct razor_set *set, int fd)
rhughes@241
   138
{
rhughes@241
   139
	char data[4096];
rhughes@241
   140
	struct razor_set_header *header = (struct razor_set_header *) data;
rhughes@241
   141
	struct array *a;
rhughes@241
   142
	uint32_t offset;
rhughes@241
   143
	int i;
rhughes@241
   144
rhughes@241
   145
	memset(data, 0, sizeof data);
rhughes@241
   146
	header->magic = RAZOR_MAGIC;
rhughes@241
   147
	header->version = RAZOR_VERSION;
rhughes@241
   148
	offset = sizeof data;
rhughes@241
   149
rhughes@241
   150
	for (i = 0; i < ARRAY_SIZE(razor_sections); i++) {
rhughes@241
   151
		if (razor_sections[i].type != i)
rhughes@241
   152
			continue;
rhughes@241
   153
		a = (void *) set + razor_sections[i].offset;
rhughes@241
   154
		header->sections[i].type = i;
rhughes@241
   155
		header->sections[i].offset = offset;
rhughes@241
   156
		header->sections[i].size = a->size;
rhughes@241
   157
		offset += ALIGN(a->size, 4096);
rhughes@241
   158
	}
rhughes@241
   159
rhughes@241
   160
	header->sections[i].type = ~0;
rhughes@241
   161
	header->sections[i].offset = 0;
rhughes@241
   162
	header->sections[i].size = 0;
rhughes@241
   163
rhughes@241
   164
	razor_write(fd, data, sizeof data);
rhughes@241
   165
	memset(data, 0, sizeof data);
rhughes@241
   166
	for (i = 0; i < ARRAY_SIZE(razor_sections); i++) {
rhughes@241
   167
		if (razor_sections[i].type != i)
rhughes@241
   168
			continue;
rhughes@241
   169
		a = (void *) set + razor_sections[i].offset;
rhughes@241
   170
		razor_write(fd, a->data, a->size);
rhughes@241
   171
		razor_write(fd, data, ALIGN(a->size, 4096) - a->size);
rhughes@241
   172
	}
rhughes@241
   173
rhughes@241
   174
	return 0;
rhughes@241
   175
}
rhughes@241
   176
rhughes@241
   177
int
rhughes@241
   178
razor_set_write(struct razor_set *set, const char *filename)
rhughes@241
   179
{
rhughes@241
   180
	int fd, status;
rhughes@241
   181
rhughes@241
   182
	fd = open(filename, O_CREAT | O_WRONLY | O_TRUNC, 0666);
rhughes@241
   183
	if (fd < 0)
rhughes@241
   184
		return -1;
rhughes@241
   185
rhughes@241
   186
	status = razor_set_write_to_fd(set, fd);
rhughes@241
   187
	if (status) {
rhughes@241
   188
	    close(fd);
rhughes@241
   189
	    return status;
rhughes@241
   190
	}
rhughes@241
   191
rhughes@241
   192
	return close(fd);
rhughes@241
   193
}
rhughes@241
   194
rhughes@241
   195
void
rhughes@241
   196
razor_build_evr(char *evr_buf, int size, const char *epoch,
rhughes@241
   197
		const char *version, const char *release)
rhughes@241
   198
{
rhughes@241
   199
	int len;
rhughes@241
   200
rhughes@241
   201
	if (!version || !*version) {
rhughes@241
   202
		*evr_buf = '\0';
rhughes@241
   203
		return;
rhughes@241
   204
	}
rhughes@241
   205
rhughes@241
   206
	if (epoch && *epoch && strcmp(epoch, "0") != 0) {
rhughes@241
   207
		len = snprintf(evr_buf, size, "%s:", epoch);
rhughes@241
   208
		evr_buf += len;
rhughes@241
   209
		size -= len;
rhughes@241
   210
	}
rhughes@241
   211
	len = snprintf(evr_buf, size, "%s", version);
rhughes@241
   212
	evr_buf += len;
rhughes@241
   213
	size -= len;
rhughes@241
   214
	if (release && *release)
rhughes@241
   215
		snprintf(evr_buf, size, "-%s", release);
rhughes@241
   216
}
rhughes@241
   217
krh@248
   218
int
krh@248
   219
razor_versioncmp(const char *s1, const char *s2)
rhughes@241
   220
{
rhughes@241
   221
	const char *p1, *p2;
rhughes@241
   222
	long n1, n2;
rhughes@241
   223
	int res;
rhughes@241
   224
rhughes@241
   225
	n1 = strtol(s1, (char **) &p1, 10);
rhughes@241
   226
	n2 = strtol(s2, (char **) &p2, 10);
rhughes@241
   227
rhughes@241
   228
	/* Epoch; if one but not the other has an epoch set, default
rhughes@241
   229
	 * the epoch-less version to 0. */
rhughes@241
   230
	res = (*p1 == ':') - (*p2 == ':');
rhughes@241
   231
	if (res < 0) {
rhughes@241
   232
		n1 = 0;
rhughes@241
   233
		p1 = s1;
rhughes@241
   234
		p2++;
rhughes@241
   235
	} else if (res > 0) {
rhughes@241
   236
		p1++;
rhughes@241
   237
		n2 = 0;
rhughes@241
   238
		p2 = s2;
rhughes@241
   239
	}
rhughes@241
   240
rhughes@241
   241
	if (n1 != n2)
rhughes@241
   242
		return n1 - n2;
rhughes@241
   243
	while (*p1 && *p2) {
rhughes@241
   244
		if (*p1 != *p2)
rhughes@241
   245
			return *p1 - *p2;
rhughes@241
   246
		p1++;
rhughes@241
   247
		p2++;
rhughes@241
   248
		if (isdigit(*p1) && isdigit(*p2))
krh@248
   249
			return razor_versioncmp(p1, p2);
rhughes@241
   250
	}
rhughes@241
   251
rhughes@241
   252
	return *p1 - *p2;
rhughes@241
   253
}
rhughes@241
   254
rhughes@241
   255
struct razor_package *
rhughes@241
   256
razor_set_get_package(struct razor_set *set, const char *package)
rhughes@241
   257
{
rhughes@241
   258
	struct razor_package_iterator *pi;
rhughes@241
   259
	struct razor_package *p;
rhughes@241
   260
	const char *name, *version, *arch;
rhughes@241
   261
rhughes@241
   262
	pi = razor_package_iterator_create(set);
rhughes@241
   263
	while (razor_package_iterator_next(pi, &p, &name, &version, &arch)) {
rhughes@241
   264
		if (strcmp(package, name) == 0)
rhughes@241
   265
			break;
rhughes@241
   266
	}
rhughes@241
   267
	razor_package_iterator_destroy(pi);
rhughes@241
   268
rhughes@241
   269
	return p;
rhughes@241
   270
}
rhughes@241
   271
krh@248
   272
struct razor_entry *
krh@248
   273
razor_set_find_entry(struct razor_set *set,
krh@248
   274
		     struct razor_entry *dir, const char *pattern)
rhughes@241
   275
{
rhughes@241
   276
	struct razor_entry *e;
rhughes@241
   277
	const char *n, *pool = set->string_pool.data;
rhughes@241
   278
	int len;
rhughes@241
   279
rhughes@241
   280
	e = (struct razor_entry *) set->files.data + dir->start;
rhughes@241
   281
	do {
rhughes@241
   282
		n = pool + e->name;
rhughes@241
   283
		if (strcmp(pattern + 1, n) == 0)
rhughes@241
   284
			return e;
rhughes@241
   285
		len = strlen(n);
rhughes@241
   286
		if (e->start != 0 && strncmp(pattern + 1, n, len) == 0 &&
rhughes@241
   287
		    pattern[len + 1] == '/') {
krh@248
   288
			return razor_set_find_entry(set, e, pattern + len + 1);
rhughes@241
   289
		}
rhughes@241
   290
	} while (!((e++)->flags & RAZOR_ENTRY_LAST));
rhughes@241
   291
rhughes@241
   292
	return NULL;
rhughes@241
   293
}
rhughes@241
   294
rhughes@241
   295
static void
rhughes@241
   296
list_dir(struct razor_set *set, struct razor_entry *dir,
rhughes@241
   297
	 char *prefix, const char *pattern)
rhughes@241
   298
{
rhughes@241
   299
	struct razor_entry *e;
rhughes@241
   300
	const char *n, *pool = set->string_pool.data;
rhughes@241
   301
rhughes@241
   302
	e = (struct razor_entry *) set->files.data + dir->start;
rhughes@241
   303
	do {
rhughes@241
   304
		n = pool + e->name;
rhughes@241
   305
		if (pattern && pattern[0] && fnmatch(pattern, n, 0) != 0)
rhughes@241
   306
			continue;
rhughes@241
   307
		printf("%s/%s\n", prefix, n);
rhughes@241
   308
		if (e->start) {
rhughes@241
   309
			char *sub = prefix + strlen (prefix);
rhughes@241
   310
			*sub = '/';
rhughes@241
   311
			strcpy (sub + 1, n);
rhughes@241
   312
			list_dir(set, e, prefix, pattern);
rhughes@241
   313
			*sub = '\0';
rhughes@241
   314
		}
rhughes@241
   315
	} while (!((e++)->flags & RAZOR_ENTRY_LAST));
rhughes@241
   316
}
rhughes@241
   317
rhughes@241
   318
void
rhughes@241
   319
razor_set_list_files(struct razor_set *set, const char *pattern)
rhughes@241
   320
{
rhughes@241
   321
	struct razor_entry *e;
rhughes@241
   322
	char buffer[512], *p, *base;
rhughes@241
   323
rhughes@241
   324
	if (pattern == NULL || !strcmp (pattern, "/")) {
rhughes@241
   325
		buffer[0] = '\0';
rhughes@241
   326
		list_dir(set, set->files.data, buffer, NULL);
rhughes@241
   327
		return;
rhughes@241
   328
	}
rhughes@241
   329
rhughes@241
   330
	strcpy(buffer, pattern);
krh@248
   331
	e = razor_set_find_entry(set, set->files.data, buffer);
rhughes@241
   332
	if (e && e->start > 0) {
rhughes@241
   333
		base = NULL;
rhughes@241
   334
	} else {
rhughes@241
   335
		p = strrchr(buffer, '/');
rhughes@241
   336
		if (p) {
rhughes@241
   337
			*p = '\0';
rhughes@241
   338
			base = p + 1;
rhughes@241
   339
		} else {
rhughes@241
   340
			base = NULL;
rhughes@241
   341
		}
rhughes@241
   342
	}
krh@248
   343
	e = razor_set_find_entry(set, set->files.data, buffer);
rhughes@241
   344
	if (e->start != 0)
rhughes@241
   345
		list_dir(set, e, buffer, base);
rhughes@241
   346
}
rhughes@241
   347
rhughes@241
   348
static struct list *
rhughes@241
   349
list_package_files(struct razor_set *set, struct list *r,
rhughes@241
   350
		   struct razor_entry *dir, uint32_t end,
rhughes@241
   351
		   char *prefix)
rhughes@241
   352
{
rhughes@241
   353
	struct razor_entry *e, *f, *entries;
rhughes@241
   354
	uint32_t next, file;
rhughes@241
   355
	char *pool;
rhughes@241
   356
	int len;
rhughes@241
   357
rhughes@241
   358
	entries = (struct razor_entry *) set->files.data;
rhughes@241
   359
	pool = set->string_pool.data;
rhughes@241
   360
rhughes@241
   361
	e = entries + dir->start;
rhughes@241
   362
	do {
rhughes@241
   363
		if (entries + r->data == e) {
rhughes@241
   364
			printf("%s/%s\n", prefix, pool + e->name);
rhughes@241
   365
			r = list_next(r);
rhughes@241
   366
			if (!r)
rhughes@241
   367
				return NULL;
rhughes@241
   368
			if (r->data >= end)
rhughes@241
   369
				return r;
rhughes@241
   370
		}
rhughes@241
   371
	} while (!((e++)->flags & RAZOR_ENTRY_LAST));
rhughes@241
   372
rhughes@241
   373
	e = entries + dir->start;
rhughes@241
   374
	do {
rhughes@241
   375
		if (e->start == 0)
rhughes@241
   376
			continue;
rhughes@241
   377
rhughes@241
   378
		if (e->flags & RAZOR_ENTRY_LAST)
rhughes@241
   379
			next = end;
rhughes@241
   380
		else {
rhughes@241
   381
			f = e + 1;
rhughes@241
   382
			while (f->start == 0 && !(f->flags & RAZOR_ENTRY_LAST))
rhughes@241
   383
				f++;
rhughes@241
   384
			if (f->start == 0)
rhughes@241
   385
				next = end;
rhughes@241
   386
			else
rhughes@241
   387
				next = f->start;
rhughes@241
   388
		}
rhughes@241
   389
rhughes@241
   390
		file = r->data;
rhughes@241
   391
		if (e->start <= file && file < next) {
rhughes@241
   392
			len = strlen(prefix);
rhughes@241
   393
			prefix[len] = '/';
rhughes@241
   394
			strcpy(prefix + len + 1, pool + e->name);
rhughes@241
   395
			r = list_package_files(set, r, e, next, prefix);
rhughes@241
   396
			prefix[len] = '\0';
rhughes@241
   397
		}
rhughes@241
   398
	} while (!((e++)->flags & RAZOR_ENTRY_LAST) && r != NULL);
rhughes@241
   399
rhughes@241
   400
	return r;
rhughes@241
   401
}
rhughes@241
   402
rhughes@241
   403
void
rhughes@241
   404
razor_set_list_package_files(struct razor_set *set, const char *name)
rhughes@241
   405
{
rhughes@241
   406
	struct razor_package *package;
rhughes@241
   407
	struct list *r;
rhughes@241
   408
	uint32_t end;
rhughes@241
   409
	char buffer[512];
rhughes@241
   410
rhughes@241
   411
	package = razor_set_get_package(set, name);
rhughes@241
   412
rhughes@241
   413
	r = list_first(&package->files, &set->file_pool);
rhughes@241
   414
	end = set->files.size / sizeof (struct razor_entry);
rhughes@241
   415
	buffer[0] = '\0';
rhughes@241
   416
	list_package_files(set, r, set->files.data, end, buffer);
rhughes@241
   417
}
rhughes@241
   418
rhughes@241
   419
/* The diff order matters.  We should sort the packages so that a
rhughes@241
   420
 * REMOVE of a package comes before the INSTALL, and so that all
rhughes@241
   421
 * requires for a package have been installed before the package.
rhughes@241
   422
 **/
rhughes@241
   423
rhughes@241
   424
void
rhughes@241
   425
razor_set_diff(struct razor_set *set, struct razor_set *upstream,
krh@253
   426
	       razor_diff_callback_t callback, void *data)
rhughes@241
   427
{
rhughes@241
   428
 	struct razor_package_iterator *pi1, *pi2;
rhughes@241
   429
 	struct razor_package *p1, *p2;
rhughes@241
   430
	const char *name1, *name2, *version1, *version2, *arch1, *arch2;
rhughes@241
   431
	int res;
rhughes@241
   432
rhughes@241
   433
	pi1 = razor_package_iterator_create(set);
rhughes@241
   434
	pi2 = razor_package_iterator_create(upstream);
rhughes@241
   435
rhughes@241
   436
	razor_package_iterator_next(pi1, &p1, &name1, &version1, &arch1);
rhughes@241
   437
	razor_package_iterator_next(pi2, &p2, &name2, &version2, &arch2);
rhughes@241
   438
rhughes@241
   439
	while (p1 || p2) {
rhughes@241
   440
		if (p1 && p2) {
rhughes@241
   441
			res = strcmp(name1, name2);
rhughes@241
   442
			if (res == 0)
krh@248
   443
				res = razor_versioncmp(version1, version2);
rhughes@241
   444
		} else {
rhughes@241
   445
			res = 0;
rhughes@241
   446
		}
rhughes@241
   447
rhughes@241
   448
		if (p2 == NULL || res < 0)
krh@253
   449
			callback(RAZOR_DIFF_ACTION_REMOVE,
krh@253
   450
				 p1, name1, version1, arch1, data);
rhughes@241
   451
		else if (p1 == NULL || res > 0)
krh@253
   452
			callback(RAZOR_DIFF_ACTION_ADD,
krh@253
   453
				 p2, name2, version2, arch2, data);
rhughes@241
   454
rhughes@241
   455
		if (p1 != NULL && res <= 0)
rhughes@241
   456
			razor_package_iterator_next(pi1, &p1,
rhughes@241
   457
						    &name1, &version1, &arch1);
rhughes@241
   458
		if (p2 != NULL && res >= 0)
rhughes@241
   459
			razor_package_iterator_next(pi2, &p2,
rhughes@241
   460
						    &name2, &version2, &arch2);
rhughes@241
   461
	}
rhughes@241
   462
rhughes@241
   463
	razor_package_iterator_destroy(pi1);
rhughes@241
   464
	razor_package_iterator_destroy(pi2);
rhughes@241
   465
}