Radish alpha
H
rad:z3QDZAW2FAfuLvihrhiyDC9fAD8G9
HardenedBSD Package Manager
Radicle
Git
Merge branch 'integrity-rework'
Vsevolod Stakhov committed 11 years ago
commit 2064515ce1ecbf527ecc3d543d74a5b857b3781b
parent 19ad724
9 files changed +858 -339
modified external/Makefile.am
@@ -60,6 +60,8 @@ noinst_HEADERS= expat/amiga/expat_68k.h \
		uthash/utarray.h \
		uthash/uthash.h \
		uthash/utlist.h \
+
		include/tree.h \
+
		include/siphash.h \
		config.h

EXTRA_LTLIBRARIES=	libelf.la
added external/include/siphash.h
@@ -0,0 +1,329 @@
+
/* ==========================================================================
+
 * siphash.h - SipHash-2-4 in a single header file
+
 * --------------------------------------------------------------------------
+
 * Derived by William Ahern from the reference implementation[1] published[2]
+
 * by Jean-Philippe Aumasson and Daniel J. Berstein. Licensed in kind.
+
 *
+
 * 1. https://www.131002.net/siphash/siphash24.c
+
 * 2. https://www.131002.net/siphash/
+
 * --------------------------------------------------------------------------
+
 * HISTORY:
+
 *
+
 * 2012-11-04 - Born.
+
 * --------------------------------------------------------------------------
+
 * USAGE:
+
 *
+
 * SipHash-2-4 takes as input two 64-bit words as the key, some number of
+
 * message bytes, and outputs a 64-bit word as the message digest. This
+
 * implementation employs two data structures: a struct sipkey for
+
 * representing the key, and a struct siphash for representing the hash
+
 * state.
+
 *
+
 * For converting a 16-byte unsigned char array to a key, use either the
+
 * macro sip_keyof or the routine sip_tokey. The former instantiates a
+
 * compound literal key, while the latter requires a key object as a
+
 * parameter.
+
 *
+
 * 	unsigned char secret[16];
+
 * 	arc4random_buf(secret, sizeof secret);
+
 * 	struct sipkey *key = sip_keyof(secret);
+
 *
+
 * For hashing a message, use either the convenience macro siphash24 or the
+
 * routines sip24_init, sip24_update, and sip24_final.
+
 *
+
 * 	struct siphash state;
+
 * 	void *msg;
+
 * 	size_t len;
+
 * 	uint64_t hash;
+
 *
+
 * 	sip24_init(&state, key);
+
 * 	sip24_update(&state, msg, len);
+
 * 	hash = sip24_final(&state);
+
 *
+
 * or
+
 *
+
 * 	hash = siphash24(msg, len, key);
+
 *
+
 * To convert the 64-bit hash value to a canonical 8-byte little-endian
+
 * binary representation, use either the macro sip_binof or the routine
+
 * sip_tobin. The former instantiates and returns a compound literal array,
+
 * while the latter requires an array object as a parameter.
+
 * --------------------------------------------------------------------------
+
 * NOTES:
+
 *
+
 * o Neither sip_keyof, sip_binof, nor siphash24 will work with compilers
+
 *   lacking compound literal support. Instead, you must use the lower-level
+
 *   interfaces which take as parameters the temporary state objects.
+
 *
+
 * o Uppercase macros may evaluate parameters more than once. Lowercase
+
 *   macros should not exhibit any such side effects.
+
 * ==========================================================================
+
 */
+
#ifndef SIPHASH_H
+
#define SIPHASH_H
+

+
#include <stddef.h> /* size_t */
+
#include <stdint.h> /* uint64_t uint32_t uint8_t */
+

+

+
#define SIP_ROTL(x, b) (uint64_t)(((x) << (b)) | ( (x) >> (64 - (b))))
+

+
#define SIP_U32TO8_LE(p, v) \
+
	(p)[0] = (uint8_t)((v) >>  0); (p)[1] = (uint8_t)((v) >>  8); \
+
	(p)[2] = (uint8_t)((v) >> 16); (p)[3] = (uint8_t)((v) >> 24);
+

+
#define SIP_U64TO8_LE(p, v) \
+
	SIP_U32TO8_LE((p) + 0, (uint32_t)((v) >>  0)); \
+
	SIP_U32TO8_LE((p) + 4, (uint32_t)((v) >> 32));
+

+
#define SIP_U8TO64_LE(p) \
+
	(((uint64_t)((p)[0]) <<  0) | \
+
	 ((uint64_t)((p)[1]) <<  8) | \
+
	 ((uint64_t)((p)[2]) << 16) | \
+
	 ((uint64_t)((p)[3]) << 24) | \
+
	 ((uint64_t)((p)[4]) << 32) | \
+
	 ((uint64_t)((p)[5]) << 40) | \
+
	 ((uint64_t)((p)[6]) << 48) | \
+
	 ((uint64_t)((p)[7]) << 56))
+

+

+
#define SIPHASH_INITIALIZER { 0, 0, 0, 0, { 0 }, 0, 0 }
+

+
struct siphash {
+
	uint64_t v0, v1, v2, v3;
+

+
	unsigned char buf[8], *p;
+
	uint64_t c;
+
}; /* struct siphash */
+

+

+
#define SIP_KEYLEN 16
+

+
struct sipkey {
+
	uint64_t k[2];
+
}; /* struct sipkey */
+

+
#define sip_keyof(k) sip_tokey(&(struct sipkey){ { 0 } }, (k))
+

+
static inline struct sipkey *sip_tokey(struct sipkey *key, const void *src) {
+
	key->k[0] = SIP_U8TO64_LE((const unsigned char *)src);
+
	key->k[1] = SIP_U8TO64_LE((const unsigned char *)src + 8);
+
	return key;
+
} /* sip_tokey() */
+

+

+
#define sip_binof(v) sip_tobin((unsigned char[8]){ 0 }, (v))
+

+
static inline void *sip_tobin(void *dst, uint64_t u64) {
+
	SIP_U64TO8_LE((unsigned char *)dst, u64);
+
	return dst;
+
} /* sip_tobin() */
+

+

+
static inline void sip_round(struct siphash *H, const int rounds) {
+
	int i;
+

+
	for (i = 0; i < rounds; i++) {
+
		H->v0 += H->v1;
+
		H->v1 = SIP_ROTL(H->v1, 13);
+
		H->v1 ^= H->v0;
+
		H->v0 = SIP_ROTL(H->v0, 32);
+

+
		H->v2 += H->v3;
+
		H->v3 = SIP_ROTL(H->v3, 16);
+
		H->v3 ^= H->v2;
+

+
		H->v0 += H->v3;
+
		H->v3 = SIP_ROTL(H->v3, 21);
+
		H->v3 ^= H->v0;
+

+
		H->v2 += H->v1;
+
		H->v1 = SIP_ROTL(H->v1, 17);
+
		H->v1 ^= H->v2;
+
		H->v2 = SIP_ROTL(H->v2, 32);
+
	}
+
} /* sip_round() */
+

+

+
static inline struct siphash *sip24_init(struct siphash *H, const struct sipkey *key) {
+
	H->v0 = 0x736f6d6570736575ULL ^ key->k[0];
+
	H->v1 = 0x646f72616e646f6dULL ^ key->k[1];
+
	H->v2 = 0x6c7967656e657261ULL ^ key->k[0];
+
	H->v3 = 0x7465646279746573ULL ^ key->k[1];
+

+
	H->p = H->buf;
+
	H->c = 0;
+

+
	return H;
+
} /* sip24_init() */
+

+

+
#define sip_endof(a) (&(a)[sizeof (a) / sizeof *(a)])
+

+
static inline struct siphash *sip24_update(struct siphash *H, const void *src, size_t len) {
+
	const unsigned char *p = src, *pe = p + len;
+
	uint64_t m;
+

+
	do {
+
		while (p < pe && H->p < sip_endof(H->buf))
+
			*H->p++ = *p++;
+

+
		if (H->p < sip_endof(H->buf))
+
			break;
+

+
		m = SIP_U8TO64_LE(H->buf);
+
		H->v3 ^= m;
+
		sip_round(H, 2);
+
		H->v0 ^= m;
+

+
		H->p = H->buf;
+
		H->c += 8;
+
	} while (p < pe);
+

+
	return H;
+
} /* sip24_update() */
+

+

+
static inline uint64_t sip24_final(struct siphash *H) {
+
	char left = H->p - H->buf;
+
	uint64_t b = (H->c + left) << 56;
+

+
	switch (left) {
+
	case 7: b |= (uint64_t)H->buf[6] << 48;
+
	case 6: b |= (uint64_t)H->buf[5] << 40;
+
	case 5: b |= (uint64_t)H->buf[4] << 32;
+
	case 4: b |= (uint64_t)H->buf[3] << 24;
+
	case 3: b |= (uint64_t)H->buf[2] << 16;
+
	case 2: b |= (uint64_t)H->buf[1] << 8;
+
	case 1: b |= (uint64_t)H->buf[0] << 0;
+
	case 0: break;
+
	}
+

+
	H->v3 ^= b;
+
	sip_round(H, 2);
+
	H->v0 ^= b;
+
	H->v2 ^= 0xff;
+
	sip_round(H, 4);
+

+
	return H->v0 ^ H->v1 ^ H->v2  ^ H->v3;
+
} /* sip24_final() */
+

+

+
#define siphash24(src, len, key) \
+
	sip24_final(sip24_update(sip24_init(&(struct siphash)SIPHASH_INITIALIZER, (key)), (src), (len)))
+

+

+
#if SIPHASH_MAIN
+

+
/*
+
 * SipHash-2-4 output with
+
 * k = 00 01 02 ...
+
 * and
+
 * in = (empty string)
+
 * in = 00 (1 byte)
+
 * in = 00 01 (2 bytes)
+
 * in = 00 01 02 (3 bytes)
+
 * ...
+
 * in = 00 01 02 ... 3e (63 bytes)
+
 */
+
static inline _Bool sip24_valid(void) {
+
	static const unsigned char vectors[64][8] = {
+
		{ 0x31, 0x0e, 0x0e, 0xdd, 0x47, 0xdb, 0x6f, 0x72, },
+
		{ 0xfd, 0x67, 0xdc, 0x93, 0xc5, 0x39, 0xf8, 0x74, },
+
		{ 0x5a, 0x4f, 0xa9, 0xd9, 0x09, 0x80, 0x6c, 0x0d, },
+
		{ 0x2d, 0x7e, 0xfb, 0xd7, 0x96, 0x66, 0x67, 0x85, },
+
		{ 0xb7, 0x87, 0x71, 0x27, 0xe0, 0x94, 0x27, 0xcf, },
+
		{ 0x8d, 0xa6, 0x99, 0xcd, 0x64, 0x55, 0x76, 0x18, },
+
		{ 0xce, 0xe3, 0xfe, 0x58, 0x6e, 0x46, 0xc9, 0xcb, },
+
		{ 0x37, 0xd1, 0x01, 0x8b, 0xf5, 0x00, 0x02, 0xab, },
+
		{ 0x62, 0x24, 0x93, 0x9a, 0x79, 0xf5, 0xf5, 0x93, },
+
		{ 0xb0, 0xe4, 0xa9, 0x0b, 0xdf, 0x82, 0x00, 0x9e, },
+
		{ 0xf3, 0xb9, 0xdd, 0x94, 0xc5, 0xbb, 0x5d, 0x7a, },
+
		{ 0xa7, 0xad, 0x6b, 0x22, 0x46, 0x2f, 0xb3, 0xf4, },
+
		{ 0xfb, 0xe5, 0x0e, 0x86, 0xbc, 0x8f, 0x1e, 0x75, },
+
		{ 0x90, 0x3d, 0x84, 0xc0, 0x27, 0x56, 0xea, 0x14, },
+
		{ 0xee, 0xf2, 0x7a, 0x8e, 0x90, 0xca, 0x23, 0xf7, },
+
		{ 0xe5, 0x45, 0xbe, 0x49, 0x61, 0xca, 0x29, 0xa1, },
+
		{ 0xdb, 0x9b, 0xc2, 0x57, 0x7f, 0xcc, 0x2a, 0x3f, },
+
		{ 0x94, 0x47, 0xbe, 0x2c, 0xf5, 0xe9, 0x9a, 0x69, },
+
		{ 0x9c, 0xd3, 0x8d, 0x96, 0xf0, 0xb3, 0xc1, 0x4b, },
+
		{ 0xbd, 0x61, 0x79, 0xa7, 0x1d, 0xc9, 0x6d, 0xbb, },
+
		{ 0x98, 0xee, 0xa2, 0x1a, 0xf2, 0x5c, 0xd6, 0xbe, },
+
		{ 0xc7, 0x67, 0x3b, 0x2e, 0xb0, 0xcb, 0xf2, 0xd0, },
+
		{ 0x88, 0x3e, 0xa3, 0xe3, 0x95, 0x67, 0x53, 0x93, },
+
		{ 0xc8, 0xce, 0x5c, 0xcd, 0x8c, 0x03, 0x0c, 0xa8, },
+
		{ 0x94, 0xaf, 0x49, 0xf6, 0xc6, 0x50, 0xad, 0xb8, },
+
		{ 0xea, 0xb8, 0x85, 0x8a, 0xde, 0x92, 0xe1, 0xbc, },
+
		{ 0xf3, 0x15, 0xbb, 0x5b, 0xb8, 0x35, 0xd8, 0x17, },
+
		{ 0xad, 0xcf, 0x6b, 0x07, 0x63, 0x61, 0x2e, 0x2f, },
+
		{ 0xa5, 0xc9, 0x1d, 0xa7, 0xac, 0xaa, 0x4d, 0xde, },
+
		{ 0x71, 0x65, 0x95, 0x87, 0x66, 0x50, 0xa2, 0xa6, },
+
		{ 0x28, 0xef, 0x49, 0x5c, 0x53, 0xa3, 0x87, 0xad, },
+
		{ 0x42, 0xc3, 0x41, 0xd8, 0xfa, 0x92, 0xd8, 0x32, },
+
		{ 0xce, 0x7c, 0xf2, 0x72, 0x2f, 0x51, 0x27, 0x71, },
+
		{ 0xe3, 0x78, 0x59, 0xf9, 0x46, 0x23, 0xf3, 0xa7, },
+
		{ 0x38, 0x12, 0x05, 0xbb, 0x1a, 0xb0, 0xe0, 0x12, },
+
		{ 0xae, 0x97, 0xa1, 0x0f, 0xd4, 0x34, 0xe0, 0x15, },
+
		{ 0xb4, 0xa3, 0x15, 0x08, 0xbe, 0xff, 0x4d, 0x31, },
+
		{ 0x81, 0x39, 0x62, 0x29, 0xf0, 0x90, 0x79, 0x02, },
+
		{ 0x4d, 0x0c, 0xf4, 0x9e, 0xe5, 0xd4, 0xdc, 0xca, },
+
		{ 0x5c, 0x73, 0x33, 0x6a, 0x76, 0xd8, 0xbf, 0x9a, },
+
		{ 0xd0, 0xa7, 0x04, 0x53, 0x6b, 0xa9, 0x3e, 0x0e, },
+
		{ 0x92, 0x59, 0x58, 0xfc, 0xd6, 0x42, 0x0c, 0xad, },
+
		{ 0xa9, 0x15, 0xc2, 0x9b, 0xc8, 0x06, 0x73, 0x18, },
+
		{ 0x95, 0x2b, 0x79, 0xf3, 0xbc, 0x0a, 0xa6, 0xd4, },
+
		{ 0xf2, 0x1d, 0xf2, 0xe4, 0x1d, 0x45, 0x35, 0xf9, },
+
		{ 0x87, 0x57, 0x75, 0x19, 0x04, 0x8f, 0x53, 0xa9, },
+
		{ 0x10, 0xa5, 0x6c, 0xf5, 0xdf, 0xcd, 0x9a, 0xdb, },
+
		{ 0xeb, 0x75, 0x09, 0x5c, 0xcd, 0x98, 0x6c, 0xd0, },
+
		{ 0x51, 0xa9, 0xcb, 0x9e, 0xcb, 0xa3, 0x12, 0xe6, },
+
		{ 0x96, 0xaf, 0xad, 0xfc, 0x2c, 0xe6, 0x66, 0xc7, },
+
		{ 0x72, 0xfe, 0x52, 0x97, 0x5a, 0x43, 0x64, 0xee, },
+
		{ 0x5a, 0x16, 0x45, 0xb2, 0x76, 0xd5, 0x92, 0xa1, },
+
		{ 0xb2, 0x74, 0xcb, 0x8e, 0xbf, 0x87, 0x87, 0x0a, },
+
		{ 0x6f, 0x9b, 0xb4, 0x20, 0x3d, 0xe7, 0xb3, 0x81, },
+
		{ 0xea, 0xec, 0xb2, 0xa3, 0x0b, 0x22, 0xa8, 0x7f, },
+
		{ 0x99, 0x24, 0xa4, 0x3c, 0xc1, 0x31, 0x57, 0x24, },
+
		{ 0xbd, 0x83, 0x8d, 0x3a, 0xaf, 0xbf, 0x8d, 0xb7, },
+
		{ 0x0b, 0x1a, 0x2a, 0x32, 0x65, 0xd5, 0x1a, 0xea, },
+
		{ 0x13, 0x50, 0x79, 0xa3, 0x23, 0x1c, 0xe6, 0x60, },
+
		{ 0x93, 0x2b, 0x28, 0x46, 0xe4, 0xd7, 0x06, 0x66, },
+
		{ 0xe1, 0x91, 0x5f, 0x5c, 0xb1, 0xec, 0xa4, 0x6c, },
+
		{ 0xf3, 0x25, 0x96, 0x5c, 0xa1, 0x6d, 0x62, 0x9f, },
+
		{ 0x57, 0x5f, 0xf2, 0x8e, 0x60, 0x38, 0x1b, 0xe5, },
+
		{ 0x72, 0x45, 0x06, 0xeb, 0x4c, 0x32, 0x8a, 0x95, }
+
	};
+
	unsigned char in[64];
+
	struct sipkey k;
+
	size_t i;
+

+
	sip_tokey(&k, "\000\001\002\003\004\005\006\007\010\011\012\013\014\015\016\017");
+

+
	for (i = 0; i < sizeof in; ++i) {
+
		in[i] = i;
+

+
		if (siphash24(in, i, &k) != SIP_U8TO64_LE(vectors[i]))
+
			return 0;
+
	}
+

+
	return 1;
+
} /* sip24_valid() */
+

+

+
#include <stdio.h>
+

+
int main(void) {
+
	_Bool ok = sip24_valid();
+

+
	if (ok)
+
		puts("OK");
+
	else
+
		puts("FAIL");
+

+
	return !ok;
+
} /* main() */
+

+
#endif /* SIPHASH_MAIN */
+

+

+
#endif /* SIPHASH_H */
added external/include/tree.h
@@ -0,0 +1,212 @@
+
/* tree.h -- AVL trees (in the spirit of BSD's 'queue.h')	-*- C -*-	*/
+

+
/* Copyright (c) 2005 Ian Piumarta
+
 * 
+
 * All rights reserved.
+
 * 
+
 * Permission is hereby granted, free of charge, to any person obtaining a copy
+
 * of this software and associated documentation files (the 'Software'), to deal
+
 * in the Software without restriction, including without limitation the rights
+
 * to use, copy, modify, merge, publish, distribute, and/or sell copies of the
+
 * Software, and to permit persons to whom the Software is furnished to do so,
+
 * provided that the above copyright notice(s) and this permission notice appear
+
 * in all copies of the Software and that both the above copyright notice(s) and
+
 * this permission notice appear in supporting documentation.
+
 *
+
 * THE SOFTWARE IS PROVIDED 'AS IS'.  USE ENTIRELY AT YOUR OWN RISK.
+
 */
+

+
/* This file defines an AVL balanced binary tree [Georgii M. Adelson-Velskii and
+
 * Evgenii M. Landis, 'An algorithm for the organization of information',
+
 * Doklady Akademii Nauk SSSR, 146:263-266, 1962 (Russian).  Also in Myron
+
 * J. Ricci (trans.), Soviet Math, 3:1259-1263, 1962 (English)].
+
 * 
+
 * An AVL tree is headed by pointers to the root node and to a function defining
+
 * the ordering relation between nodes.  Each node contains an arbitrary payload
+
 * plus three fields per tree entry: the depth of the subtree for which it forms
+
 * the root and two pointers to child nodes (singly-linked for minimum space, at
+
 * the expense of direct access to the parent node given a pointer to one of the
+
 * children).  The tree is rebalanced after every insertion or removal.  The
+
 * tree may be traversed in two directions: forward (in-order left-to-right) and
+
 * reverse (in-order, right-to-left).
+
 * 
+
 * Because of the recursive nature of many of the operations on trees it is
+
 * necessary to define a number of helper functions for each type of tree node.
+
 * The macro TREE_DEFINE(node_tag, entry_name) defines these functions with
+
 * unique names according to the node_tag.  This macro should be invoked,
+
 * thereby defining the necessary functions, once per node tag in the program.
+
 * 
+
 * For details on the use of these macros, see the tree(3) manual page.
+
 */
+

+
#ifndef __tree_h
+
#define __tree_h
+

+

+
#define TREE_DELTA_MAX	1
+

+
#define TREE_ENTRY(type)			\
+
  struct {					\
+
    struct type	*avl_left;			\
+
    struct type	*avl_right;			\
+
    int		 avl_height;			\
+
  }
+

+
#define TREE_HEAD(name, type)				\
+
  struct name {						\
+
    struct type *th_root;				\
+
    int  (*th_cmp)(struct type *lhs, struct type *rhs);	\
+
  }
+

+
#define TREE_INITIALIZER(cmp) { 0, cmp }
+

+
#define TREE_DELTA(self, field)								\
+
  (( (((self)->field.avl_left)  ? (self)->field.avl_left->field.avl_height  : 0))	\
+
   - (((self)->field.avl_right) ? (self)->field.avl_right->field.avl_height : 0))
+

+
/* Recursion prevents the following from being defined as macros. */
+

+
#define TREE_DEFINE(node, field)									\
+
													\
+
  struct node *TREE_BALANCE_##node##_##field(struct node *);						\
+
													\
+
  struct node *TREE_ROTL_##node##_##field(struct node *self)						\
+
  {													\
+
    struct node *r= self->field.avl_right;								\
+
    self->field.avl_right= r->field.avl_left;								\
+
    r->field.avl_left= TREE_BALANCE_##node##_##field(self);						\
+
    return TREE_BALANCE_##node##_##field(r);								\
+
  }													\
+
													\
+
  struct node *TREE_ROTR_##node##_##field(struct node *self)						\
+
  {													\
+
    struct node *l= self->field.avl_left;								\
+
    self->field.avl_left= l->field.avl_right;								\
+
    l->field.avl_right= TREE_BALANCE_##node##_##field(self);						\
+
    return TREE_BALANCE_##node##_##field(l);								\
+
  }													\
+
													\
+
  struct node *TREE_BALANCE_##node##_##field(struct node *self)						\
+
  {													\
+
    int delta= TREE_DELTA(self, field);									\
+
													\
+
    if (delta < -TREE_DELTA_MAX)									\
+
      {													\
+
	if (TREE_DELTA(self->field.avl_right, field) > 0)						\
+
	  self->field.avl_right= TREE_ROTR_##node##_##field(self->field.avl_right);			\
+
	return TREE_ROTL_##node##_##field(self);							\
+
      }													\
+
    else if (delta > TREE_DELTA_MAX)									\
+
      {													\
+
	if (TREE_DELTA(self->field.avl_left, field) < 0)						\
+
	  self->field.avl_left= TREE_ROTL_##node##_##field(self->field.avl_left);			\
+
	return TREE_ROTR_##node##_##field(self);							\
+
      }													\
+
    self->field.avl_height= 0;										\
+
    if (self->field.avl_left && (self->field.avl_left->field.avl_height > self->field.avl_height))	\
+
      self->field.avl_height= self->field.avl_left->field.avl_height;					\
+
    if (self->field.avl_right && (self->field.avl_right->field.avl_height > self->field.avl_height))	\
+
      self->field.avl_height= self->field.avl_right->field.avl_height;					\
+
    self->field.avl_height += 1;									\
+
    return self;											\
+
  }													\
+
													\
+
  struct node *TREE_INSERT_##node##_##field								\
+
    (struct node *self, struct node *elm, int (*compare)(struct node *lhs, struct node *rhs))		\
+
  {													\
+
    if (!self)												\
+
      return elm;											\
+
    if (compare(elm, self) < 0)										\
+
      self->field.avl_left= TREE_INSERT_##node##_##field(self->field.avl_left, elm, compare);		\
+
    else												\
+
      self->field.avl_right= TREE_INSERT_##node##_##field(self->field.avl_right, elm, compare);		\
+
    return TREE_BALANCE_##node##_##field(self);								\
+
  }													\
+
													\
+
  struct node *TREE_FIND_##node##_##field								\
+
    (struct node *self, struct node *elm, int (*compare)(struct node *lhs, struct node *rhs))		\
+
  {													\
+
    if (!self)												\
+
      return 0;												\
+
    if (compare(elm, self) == 0)									\
+
      return self;											\
+
    if (compare(elm, self) < 0)										\
+
      return TREE_FIND_##node##_##field(self->field.avl_left, elm, compare);				\
+
    else												\
+
      return TREE_FIND_##node##_##field(self->field.avl_right, elm, compare);				\
+
  }													\
+
													\
+
  struct node *TREE_MOVE_RIGHT_##node##_##field(struct node *self, struct node *rhs)					\
+
  {													\
+
    if (!self)												\
+
      return rhs;											\
+
    self->field.avl_right= TREE_MOVE_RIGHT_##node##_##field(self->field.avl_right, rhs);					\
+
    return TREE_BALANCE_##node##_##field(self);								\
+
  }													\
+
													\
+
  struct node *TREE_REMOVE_##node##_##field								\
+
    (struct node *self, struct node *elm, int (*compare)(struct node *lhs, struct node *rhs))		\
+
  {													\
+
    if (!self) return 0;										\
+
													\
+
    if (compare(elm, self) == 0)									\
+
      {													\
+
	struct node *tmp= TREE_MOVE_RIGHT_##node##_##field(self->field.avl_left, self->field.avl_right);			\
+
	self->field.avl_left= 0;									\
+
	self->field.avl_right= 0;									\
+
	return tmp;											\
+
      }													\
+
    if (compare(elm, self) < 0)										\
+
      self->field.avl_left= TREE_REMOVE_##node##_##field(self->field.avl_left, elm, compare);		\
+
    else												\
+
      self->field.avl_right= TREE_REMOVE_##node##_##field(self->field.avl_right, elm, compare);		\
+
    return TREE_BALANCE_##node##_##field(self);								\
+
  }													\
+
													\
+
  void TREE_FORWARD_APPLY_ALL_##node##_##field								\
+
    (struct node *self, void (*function)(struct node *node, void *data), void *data)			\
+
  {													\
+
    if (self)												\
+
      {													\
+
	TREE_FORWARD_APPLY_ALL_##node##_##field(self->field.avl_left, function, data);			\
+
	function(self, data);										\
+
	TREE_FORWARD_APPLY_ALL_##node##_##field(self->field.avl_right, function, data);			\
+
      }													\
+
  }													\
+
													\
+
  void TREE_REVERSE_APPLY_ALL_##node##_##field								\
+
    (struct node *self, void (*function)(struct node *node, void *data), void *data)			\
+
  {													\
+
    if (self)												\
+
      {													\
+
	TREE_REVERSE_APPLY_ALL_##node##_##field(self->field.avl_right, function, data);			\
+
	function(self, data);										\
+
	TREE_REVERSE_APPLY_ALL_##node##_##field(self->field.avl_left, function, data);			\
+
      }													\
+
  }
+

+
#define TREE_INSERT(head, node, field, elm)						\
+
  ((head)->th_root= TREE_INSERT_##node##_##field((head)->th_root, (elm), (head)->th_cmp))
+

+
#define TREE_FIND(head, node, field, elm)				\
+
  (TREE_FIND_##node##_##field((head)->th_root, (elm), (head)->th_cmp))
+

+
#define TREE_REMOVE(head, node, field, elm)						\
+
  ((head)->th_root= TREE_REMOVE_##node##_##field((head)->th_root, (elm), (head)->th_cmp))
+

+
#define TREE_DEPTH(head, field)			\
+
  ((head)->th_root->field.avl_height)
+

+
#define TREE_FORWARD_APPLY(head, node, field, function, data)	\
+
  TREE_FORWARD_APPLY_ALL_##node##_##field((head)->th_root, function, data)
+

+
#define TREE_REVERSE_APPLY(head, node, field, function, data)	\
+
  TREE_REVERSE_APPLY_ALL_##node##_##field((head)->th_root, function, data)
+

+
#define TREE_INIT(head, cmp) do {		\
+
    (head)->th_root= 0;				\
+
    (head)->th_cmp= (cmp);			\
+
  } while (0)
+

+

+
#endif /* __tree_h */
modified libpkg/Makefile.am
@@ -9,6 +9,7 @@ pkg_common_cflags= -I$(top_srcdir)/libpkg \
			-I$(top_srcdir)/external/picosat \
			-I$(top_srcdir)/external/uthash \
			-I$(top_srcdir)/external/sqlite \
+
			-I$(top_srcdir)/external/include \
			-DPREFIX=\"$(prefix)\" \
			-Wno-pointer-sign
libpkg_la_SOURCES=	pkg.c \
modified libpkg/pkg_jobs.c
@@ -2143,6 +2143,7 @@ pkg_jobs_check_conflicts(struct pkg_jobs *j)
	int ret = EPKG_OK, res, added = 0;

	pkg_emit_integritycheck_begin();
+
	j->conflicts_registered = 0;

	DL_FOREACH(j->jobs, ps) {
		if (ps->type == PKG_SOLVED_DELETE || ps->type == PKG_SOLVED_UPGRADE_REMOVE) {
@@ -2153,25 +2154,19 @@ pkg_jobs_check_conflicts(struct pkg_jobs *j)

			if (p->type == PKG_REMOTE)
				pkgdb_ensure_loaded(j->db, p, PKG_LOAD_FILES|PKG_LOAD_DIRS);
-
			else if (p->type != PKG_FILE)
-
				continue;
		}
-
		if ((res = pkg_conflicts_append_pkg(p, j)) != EPKG_OK)
+
		if ((res = pkg_conflicts_append_chain(ps->items[0], j)) != EPKG_OK)
			ret = res;
		else
			added ++;

	}

-
	if (added > 0) {
-
		pkg_debug(1, "check integrity for %d items added", added);
-
		if ((res = pkg_conflicts_integrity_check(j)) != EPKG_OK) {
-
			pkg_emit_integritycheck_finished(j->conflicts_registered);
-
			return (res);
-
		}
-
	}
+
	pkg_debug(1, "check integrity for %d items added", added);

	pkg_emit_integritycheck_finished(j->conflicts_registered);
+
	if (j->conflicts_registered > 0)
+
		ret = EPKG_CONFLICT;

	return (ret);
}
modified libpkg/pkg_jobs_conflicts.c
@@ -35,12 +35,15 @@
#include "private/pkg.h"
#include "private/pkgdb.h"
#include "private/pkg_jobs.h"
+
#include "siphash.h"

struct pkg_conflict_chain {
	struct pkg_job_request *req;
	struct pkg_conflict_chain *next;
};

+
TREE_DEFINE(pkg_jobs_conflict_item, entry);
+

static int
pkg_conflicts_chain_cmp_cb(struct pkg_conflict_chain *a, struct pkg_conflict_chain *b)
{
@@ -179,161 +182,340 @@ pkg_conflicts_register(struct pkg *p1, struct pkg *p2, enum pkg_conflict_type ty
}


+

static int
-
pkg_conflicts_add_missing(struct pkg_jobs *j, const char *uid)
+
pkg_conflicts_item_cmp(struct pkg_jobs_conflict_item *a,
+
	struct pkg_jobs_conflict_item *b)
+
{
+
	return (b->hash - a->hash);
+
}
+

+
/*
+
 * Checks whether we need to add a conflict between two packages
+
 */
+
static bool
+
pkg_conflicts_need_conflict(struct pkg_jobs *j, struct pkg *p1, struct pkg *p2)
{
-
	struct pkg *npkg;
+
	struct pkg_file *fcur, *ftmp, *ff;
+
	struct pkg_dir *df;
+
	const char *uid1, *uid2;
+
	struct pkg_conflict *c;

+
	pkg_get(p1, PKG_UNIQUEID, &uid1);
+
	pkg_get(p2, PKG_UNIQUEID, &uid2);

-
	npkg = pkg_jobs_universe_get_local(j->universe, uid, 0);
-
	if (npkg == NULL) {
-
		npkg = pkg_jobs_universe_get_remote(j->universe, uid, 0);
-
		pkg_debug(2, "conflicts: add missing remote %s(%d)", uid);
-
	}
-
	else {
-
		pkg_debug(2, "conflicts: add missing local %s(%d)", uid);
-
	}
+
	assert(pkgdb_ensure_loaded(j->db, p1, PKG_LOAD_FILES|PKG_LOAD_DIRS) == EPKG_OK);
+
	assert(pkgdb_ensure_loaded(j->db, p2, PKG_LOAD_FILES|PKG_LOAD_DIRS) == EPKG_OK);

-
	if (npkg == NULL) {
-
		pkg_emit_error("cannot register conflict with non-existing %s",
-
				uid);
-
		return (EPKG_FATAL);
+
	/*
+
	 * Check if we already have this conflict registered
+
	 */
+
	HASH_FIND_STR(p1->conflicts, uid2, c);
+
	if (c != NULL)
+
		return false;
+

+
	/*
+
	 * We need to check all files and dirs and find the similar ones
+
	 */
+
	HASH_ITER(hh, p1->files, fcur, ftmp) {
+
		HASH_FIND_STR(p2->files, fcur->path, ff);
+
		if (ff != NULL)
+
			return (true);
+
		HASH_FIND_STR(p2->dirs, fcur->path, df);
+
		if (df != NULL)
+
			return (true);
	}
+
	/* XXX pkg dirs are terribly broken */

-
	return pkg_jobs_universe_process(j->universe, npkg);
+
	/* No common paths are found in p1 and p2 */
+
	return (false);
}

-

+
/*
+
 * Just insert new conflicts items to the packages
+
 */
static void
-
pkg_conflicts_register_universe(struct pkg_jobs *j,
-
		struct pkg_job_universe_item *u1,
-
		struct pkg_job_universe_item *u2, bool local_only,
-
		enum pkg_conflict_type type)
+
pkg_conflicts_register_unsafe(struct pkg *p1, struct pkg *p2,
+
	const char *path,
+
	enum pkg_conflict_type type)
{
+
	const char *uid1, *uid2;
+
	struct pkg_conflict *c1, *c2;
+

+
	pkg_get(p1, PKG_UNIQUEID, &uid1);
+
	pkg_get(p2, PKG_UNIQUEID, &uid2);

-
	pkg_conflicts_register(u1->pkg, u2->pkg, type);
+
	pkg_conflict_new(&c1);
+
	pkg_conflict_new(&c2);
+
	c1->type = c2->type = type;
+
	sbuf_set(&c1->uniqueid, uid2);
+
	sbuf_set(&c2->uniqueid, uid1);
+
	HASH_ADD_KEYPTR(hh, p1->conflicts, pkg_conflict_uniqueid(c1),
+
		sbuf_size(c1->uniqueid), c1);
+
	HASH_ADD_KEYPTR(hh, p2->conflicts, pkg_conflict_uniqueid(c2),
+
		sbuf_size(c2->uniqueid), c2);
+
	pkg_debug(2, "registering conflict between %s and %s on path %s",
+
		uid1, uid2, path);
}

-
static void
-
pkg_conflicts_add_from_pkgdb_local(const char *o1, const char *o2, void *ud)
+
/*
+
 * Register conflicts between packages in the universe chains
+
 */
+
static bool
+
pkg_conflicts_register_chain(struct pkg_jobs *j, struct pkg_job_universe_item *u1,
+
	struct pkg_job_universe_item *u2, const char *path)
{
-
	struct pkg_jobs *j = (struct pkg_jobs *)ud;
-
	struct pkg_job_universe_item *u1, *u2, *cur1, *cur2;
-
	struct pkg_conflict *c;
-
	const char *dig1, *dig2;
+
	struct pkg_job_universe_item *cur1, *cur2;
+
	const char *uid1, *uid2;
+
	bool ret = false;

-
	u1 = pkg_jobs_universe_find(j->universe, o1);
-
	u2 = pkg_jobs_universe_find(j->universe, o2);
+
	cur1 = u1;

-
	if (u1 == NULL && u2 == NULL) {
-
		pkg_emit_error("cannot register conflict with non-existing %s and %s",
-
				o1, o2);
-
		return;
-
	}
-
	else if (u1 == NULL) {
-
		if (pkg_conflicts_add_missing(j, o1) != EPKG_OK)
-
			return;
-
		u1 = pkg_jobs_universe_find(j->universe, o1);
-
	}
-
	else if (u2 == NULL) {
-
		if (pkg_conflicts_add_missing(j, o2) != EPKG_OK)
-
			return;
-
		u2 = pkg_jobs_universe_find(j->universe, o2);
-
	}
-
	else {
-
		/* Maybe we have registered this conflict already */
-
		HASH_FIND(hh, u1->pkg->conflicts, o2, strlen(o2), c);
-
		if (c != NULL)
-
			return;
-
	}
+
	do {

-
	/*
-
	 * Here we have some unit but we do not know, where is a conflict, e.g.
-
	 * if we have several units U1 and U2 with the same uniqueid O that are in
-
	 * the conflict with some origin O' provided by U1' and U2'. So we can
-
	 * register the conflicts between all units in the chain.
-
	 */
-
	LL_FOREACH(u1, cur1) {
-
		LL_FOREACH(u2, cur2) {
-
			if (cur1->pkg->type == PKG_INSTALLED && cur2->pkg->type != PKG_INSTALLED) {
-
				pkg_get(cur1->pkg, PKG_DIGEST, &dig1);
-
				pkg_get(cur2->pkg, PKG_DIGEST, &dig2);
-
				pkg_conflicts_register_universe(j, cur1, cur2, true, PKG_CONFLICT_REMOTE_LOCAL);
-
				pkg_debug(2, "register conflict between local %s(%s) <-> remote %s(%s)",
-
						o1, dig1, o2, dig2);
-
				j->conflicts_registered ++;
+
		cur2 = u2;
+
		do {
+
			struct pkg *p1 = cur1->pkg, *p2 = cur2->pkg;
+
			pkg_get(p1, PKG_UNIQUEID, &uid1);
+
			pkg_get(p2, PKG_UNIQUEID, &uid2);
+

+
			if (p1->type == PKG_INSTALLED && p2->type == PKG_INSTALLED) {
+
				/* Local and local packages cannot conflict */
+
				continue;
			}
-
			else if (cur2->pkg->type == PKG_INSTALLED && cur1->pkg->type != PKG_INSTALLED) {
-
				pkg_get(cur1->pkg, PKG_DIGEST, &dig1);
-
				pkg_get(cur2->pkg, PKG_DIGEST, &dig2);
-
				pkg_conflicts_register_universe(j, cur1, cur2, true, PKG_CONFLICT_REMOTE_LOCAL);
-
				pkg_debug(2, "register conflict between local %s(%s) <-> remote %s(%s)",
-
						o2, dig2, o1, dig1);
-
				j->conflicts_registered ++;
+
			else if (p1->type == PKG_INSTALLED || p2->type == PKG_INSTALLED) {
+
				/* local <-> remote conflict */
+
				if (pkg_conflicts_need_conflict(j, p1, p2)) {
+
					pkg_conflicts_register_unsafe(p1, p2, path,
+
						PKG_CONFLICT_REMOTE_LOCAL);
+
					j->conflicts_registered ++;
+
					ret = true;
+
				}
			}
+
			else {
+
				/* two remote packages */
+
				if (pkg_conflicts_need_conflict(j, p1, p2)) {
+
					pkg_conflicts_register_unsafe(p1, p2, path,
+
						PKG_CONFLICT_REMOTE_REMOTE);
+
					j->conflicts_registered ++;
+
					ret = true;
+
				}
+
			}
+
			cur2 = cur2->prev;
+
		} while (cur2 != u2);
+

+
		cur1 = cur1->prev;
+
	} while (cur1 != u1);
+

+
	return (ret);
+
}
+

+
/*
+
 * Check whether the specified path is registered locally and returns
+
 * the package that contains that path or NULL if no conflict was found
+
 */
+
static struct pkg *
+
pkg_conflicts_check_local_path(const char *path, const char *uid,
+
	struct pkg_jobs *j)
+
{
+
	const char sql_local_conflict[] = ""
+
		"SELECT p.name || '~' || p.origin as uniqueid FROM packages AS p "
+
		"LEFT JOIN files AS f "
+
		"ON p.id = f.package_id "
+
		"WHERE f.path = ?1;";
+
	sqlite3_stmt *stmt;
+
	int ret;
+
	struct pkg *p = NULL;
+
	struct pkg_conflict *c;
+
	const char *uido;
+

+
	pkg_debug(4, "Pkgdb: running '%s'", sql_local_conflict);
+
	ret = sqlite3_prepare_v2(j->db->sqlite, sql_local_conflict, -1,
+
		&stmt, NULL);
+
	if (ret != SQLITE_OK) {
+
		ERROR_SQLITE(j->db->sqlite, sql_local_conflict);
+
		return (NULL);
+
	}
+

+
	sqlite3_bind_text(stmt, 1,
+
		path, -1, SQLITE_STATIC);
+
	sqlite3_bind_text(stmt, 2,
+
		uid, -1, SQLITE_STATIC);
+

+
	if (sqlite3_step(stmt) != SQLITE_DONE) {
+
		/*
+
		 * We have found the conflict with some other chain, so find that chain
+
		 * or update the universe
+
		 */
+
		p = pkg_jobs_universe_get_local(j->universe,
+
			sqlite3_column_text(stmt, 0), 0);
+
		assert(p != NULL);
+

+
		pkg_get(p, PKG_UNIQUEID, &uido);
+
		assert(strcmp(uid, uido) != 0);
+

+
		HASH_FIND_STR(p->conflicts, uid, c);
+
		if (c == NULL) {
+
			/* We need to register the conflict between two universe chains */
+
			sqlite3_finalize(stmt);
+
			return (p);
		}
	}
+

+
	sqlite3_finalize(stmt);
+
	return (NULL);
}

-
static void
-
pkg_conflicts_add_from_pkgdb_remote(const char *o1, const char *o2, void *ud)
+
static struct pkg_job_universe_item *
+
pkg_conflicts_check_all_paths(struct pkg_jobs *j, const char *path,
+
	struct pkg_job_universe_item *it, struct sipkey *k)
{
-
	struct pkg_jobs *j = (struct pkg_jobs *)ud;
-
	struct pkg_job_universe_item *u1, *u2, *cur1, *cur2;
+
	const char *uid1, *uid2;
+
	struct pkg_jobs_conflict_item *cit, test;
	struct pkg_conflict *c;
-
	const char *dig1, *dig2;
+
	uint64_t sipkey;

-
	u1 = pkg_jobs_universe_find(j->universe, o1);
-
	u2 = pkg_jobs_universe_find(j->universe, o2);
+
	sipkey = siphash24(path, strlen(path), k);
+
	test.hash = sipkey;
+
	cit = TREE_FIND(j->conflict_items, pkg_jobs_conflict_item, entry, &test);

-
	/*
-
	 * In case of remote conflict we need to register it only between remote
-
	 * packets
-
	 */
-

-
	if (u1 == NULL || u2 == NULL) {
-
		pkg_emit_error("cannot register remote conflict with non-existing %s and %s",
-
				o1, o2);
-
		return;
+
	if (cit == NULL) {
+
		/* New entry */
+
		cit = calloc(1, sizeof(*cit));
+
		if (cit == NULL) {
+
			pkg_emit_errno("malloc failed", "pkg_conflicts_check_all_paths");
+
		}
+
		else {
+
			cit->hash = sipkey;
+
			cit->item = it;
+
			TREE_INSERT(j->conflict_items, pkg_jobs_conflict_item, entry, cit);
+
		}
	}
	else {
-
		/* Maybe we have registered this conflict already */
-
		HASH_FIND(hh, u1->pkg->conflicts, o2, strlen(o2), c);
-
		if (c != NULL)
-
			return;
-
	}
+
		/* Check the same package */
+
		if (cit->item == it)
+
			return (NULL);
+

+
		pkg_get(it->pkg, PKG_UNIQUEID, &uid1);
+
		pkg_get(cit->item->pkg, PKG_UNIQUEID, &uid2);
+
		if (strcmp(uid1, uid2) == 0) {
+
			/* The same upgrade chain, just upgrade item for speed */
+
			cit->item = it;
+
			return (NULL);
+
		}

-
	LL_FOREACH(u1, cur1) {
-
		if (cur1->pkg->type != PKG_INSTALLED) {
-
			HASH_FIND(hh, cur1->pkg->conflicts, o2, strlen(o2), c);
-
			if (c == NULL) {
-
				LL_FOREACH(u2, cur2) {
-
					HASH_FIND(hh, cur2->pkg->conflicts, o1, strlen(o1), c);
-
					if (c == NULL && cur2->pkg->type != PKG_INSTALLED) {
-
						/* No need to update priorities */
-
						pkg_conflicts_register(cur1->pkg, cur2->pkg, PKG_CONFLICT_REMOTE_REMOTE);
-
						j->conflicts_registered ++;
-
						pkg_get(cur1->pkg, PKG_DIGEST, &dig1);
-
						pkg_get(cur2->pkg, PKG_DIGEST, &dig2);
-
						pkg_debug(2, "register conflict between remote %s(%s) <-> %s(%s)",
-
								o1, dig1, o2, dig2);
-
						break;
-
					}
-
				}
-
			}
+
		/* Here we can have either collision or a real conflict */
+
		HASH_FIND_STR(it->pkg->conflicts, uid2, c);
+
		if (c != NULL || !pkg_conflicts_register_chain(j, it, cit->item, path)) {
+
			/*
+
			 * Collision found, change the key following the
+
			 * Cuckoo principle
+
			 */
+
			pkg_debug(2, "found a collision on path %s between %s and %s, key: %lu",
+
				path, uid1, uid2, (unsigned long)k->k[0]);
+
			k->k[0] ++;
+
			return (pkg_conflicts_check_all_paths(j, path, it, k));
		}
+

+
		return (cit->item);
	}
+

+
	return (NULL);
}

-
int
-
pkg_conflicts_append_pkg(struct pkg *p, struct pkg_jobs *j)
+
static void
+
pkg_conflicts_check_chain_conflict(struct pkg_job_universe_item *it,
+
	struct pkg_job_universe_item *local, struct pkg_jobs *j)
{
-
	/* Now we can get conflicts only from pkgdb */
-
	return (pkgdb_integrity_append(j->db, p, pkg_conflicts_add_from_pkgdb_remote, j));
+
	struct pkg_file *fcur, *ftmp, *ff;
+
	const char *uid;
+
	struct pkg *p;
+
	struct pkg_job_universe_item *cun;
+
	struct sipkey k;
+

+
	pkg_get(it->pkg, PKG_UNIQUEID, &uid);
+

+
	HASH_ITER(hh, it->pkg->files, fcur, ftmp) {
+
		/* Initialize sip key with zero */
+
		memset(&k, 0, sizeof(k));
+
		/* Check in hash tree */
+
		cun = pkg_conflicts_check_all_paths(j, fcur->path, it, &k);
+

+
		if (local != NULL) {
+
			/* Filter only new files for remote packages */
+
			HASH_FIND_STR(local->pkg->files, fcur->path, ff);
+
			if (ff != NULL)
+
				continue;
+
		}
+
		/* Check for local conflict in db */
+
		p = pkg_conflicts_check_local_path(fcur->path, uid, j);
+
		if (p != NULL) {
+
			pkg_jobs_universe_process_item(j->universe, p, &cun);
+
			assert(cun != NULL);
+
			pkg_conflicts_register_chain(j, it, cun, fcur->path);
+
		}
+
	}
+
	/* XXX: dirs are currently broken terribly */
+
#if 0
+
	struct pkg_dir *dcur, *dtmp, *df;
+
	HASH_ITER(hh, it->pkg->dirs, dcur, dtmp) {
+
		memset(&k, 0, sizeof(k));
+
		cun = pkg_conflicts_check_all_paths(j, dcur->path, it, &k);
+

+
		if (local != NULL) {
+
			HASH_FIND_STR(local->pkg->dirs, dcur->path, df);
+
			if (df != NULL)
+
				continue;
+
		}
+
		/* Check for local conflict in db */
+
		p = pkg_conflicts_check_local_path(dcur->path, uid, j);
+
		if (p != NULL) {
+
			pkg_jobs_universe_process_item(j->universe, p, &cun);
+
			assert(cun != NULL);
+
			pkg_conflicts_register_chain(j, it, cun, dcur->path);
+
		}
+
	}
+
#endif
}

int
-
pkg_conflicts_integrity_check(struct pkg_jobs *j)
+
pkg_conflicts_append_chain(struct pkg_job_universe_item *it,
+
	struct pkg_jobs *j)
{
-
	return (pkgdb_integrity_check(j->db, pkg_conflicts_add_from_pkgdb_local, j));
+
	struct pkg_job_universe_item *lp = NULL, *cur;
+

+
	/* Ensure that we have a tree initialized */
+
	if (j->conflict_items == NULL) {
+
		j->conflict_items = malloc(sizeof(*j->conflict_items));
+
		TREE_INIT(j->conflict_items, pkg_conflicts_item_cmp);
+
	}
+

+
	/* Find local package */
+
	cur = it->prev;
+
	while (cur != it) {
+
		if (cur->pkg->type == PKG_INSTALLED) {
+
			lp = cur;
+
			if (pkgdb_ensure_loaded(j->db, cur->pkg, PKG_LOAD_FILES|PKG_LOAD_DIRS)
+
							!= EPKG_OK)
+
				return (EPKG_FATAL);
+

+
			/* Local package is found */
+
			break;
+
		}
+
		cur = cur->prev;
+
	}
+

+
	/*
+
	 * Now we go through the all packages in the chain and check them against
+
	 * conflicts with the locally installed files
+
	 */
+
	cur = it;
+
	do {
+
		if (cur != lp)
+
			pkg_conflicts_check_chain_conflict(cur, lp, j);
+

+
		cur = cur->prev;
+
	} while (cur != it);
+

+
	return (EPKG_OK);
}
modified libpkg/pkgdb.c
@@ -2359,210 +2359,6 @@ pkgdb_compact(struct pkgdb *db)
	return (sql_exec(db->sqlite, "VACUUM;"));
}

-
int
-
pkgdb_integrity_append(struct pkgdb *db, struct pkg *p,
-
		conflict_func_cb cb, void *cbdata)
-
{
-
	int		 ret = EPKG_OK;
-
	sqlite3_stmt	*stmt = NULL;
-
	sqlite3_stmt	*stmt_conflicts = NULL;
-
	struct pkg_file	*file = NULL;
-
	const char *puid;
-

-
	const char	 sql[] = ""
-
		"INSERT INTO integritycheck (uid, path)"
-
		"values (?1, ?2);";
-
	const char	 sql_conflicts[] = ""
-
		"SELECT uid FROM integritycheck where path=?1;";
-

-
	assert(db != NULL && p != NULL);
-

-
	sql_exec(db->sqlite, "CREATE TEMP TABLE IF NOT EXISTS integritycheck ("
-
			"uid TEXT, "
-
			"path TEXT UNIQUE);"
-
		);
-

-
	pkg_debug(4, "Pkgdb: running '%s'", sql);
-
	if (sqlite3_prepare_v2(db->sqlite, sql, -1, &stmt, NULL)
-
	    != SQLITE_OK) {
-
		ERROR_SQLITE(db->sqlite, sql);
-
		return (EPKG_FATAL);
-
	}
-

-
	pkg_get(p, PKG_UNIQUEID, &puid);
-

-
	pkg_debug(4, "Pkgdb: test conflicts for %s", puid);
-
	while (pkg_files(p, &file) == EPKG_OK) {
-
		const char	*uid;
-
		const char	*pkg_path = pkg_file_path(file);
-
		struct pkg_event_conflict *conflicts_list = NULL, *cur;
-

-
		pkg_get(p, PKG_UNIQUEID, &uid);
-
		sqlite3_bind_text(stmt, 1, uid, -1, SQLITE_STATIC);
-
		sqlite3_bind_text(stmt, 2, pkg_path, -1, SQLITE_STATIC);
-

-
		if (sqlite3_step(stmt) != SQLITE_DONE) {
-

-
			pkg_debug(4, "Pkgdb: running '%s'", sql_conflicts);
-
			if (sqlite3_prepare_v2(db->sqlite, sql_conflicts,
-
			    -1, &stmt_conflicts, NULL) != SQLITE_OK) {
-
				ERROR_SQLITE(db->sqlite, sql_conflicts);
-
				sqlite3_finalize(stmt);
-
				return (EPKG_FATAL);
-
			}
-

-
			sqlite3_bind_text(stmt_conflicts, 1, pkg_path,
-
			    -1, SQLITE_STATIC);
-
			cur = conflicts_list;
-
			while (sqlite3_step(stmt_conflicts) != SQLITE_DONE) {
-

-
				cur = calloc(1, sizeof (struct pkg_event_conflict));
-
				cur->uid = strdup(sqlite3_column_text(stmt_conflicts, 0));
-
				pkg_debug(3, "found conflict between %s and %s on path %s",
-
						puid, cur->uid, pkg_path);
-
				LL_PREPEND(conflicts_list, cur);
-

-
				if (cb != NULL)
-
					cb (puid, cur->uid, cbdata);
-
			}
-
			sqlite3_finalize(stmt_conflicts);
-
			pkg_emit_integritycheck_conflict(uid, pkg_path, conflicts_list);
-

-
			cur = conflicts_list;
-
			while (cur) {
-
				free(cur->uid);
-
				cur = cur->next;
-
				free(conflicts_list);
-
				conflicts_list = cur;
-
			}
-
			ret = EPKG_CONFLICT;
-
		}
-
		sqlite3_reset(stmt);
-
	}
-
	sqlite3_finalize(stmt);
-

-
	return (ret);
-
}
-

-
int
-
pkgdb_integrity_check(struct pkgdb *db, conflict_func_cb cb, void *cbdata)
-
{
-
	int		 ret, retcode = EPKG_OK;
-
	sqlite3_stmt	*stmt;
-
	sqlite3_stmt	*stmt_conflicts;
-
	struct sbuf	*conflictmsg = NULL;
-
	struct sbuf	*uniqueid;
-

-
	assert (db != NULL);
-

-
	const char	 sql_local_conflict[] = ""
-
		"SELECT p.name, p.version, p.origin, p.name || '~' || p.origin as uniqueid FROM packages AS p, files AS f "
-
		"WHERE p.id = f.package_id AND f.path = ?1;";
-

-
	const char	 sql_conflicts[] = ""
-
		"SELECT uid FROM integritycheck WHERE path = ?1;";
-

-
	const char sql_integrity_prepare[] = ""
-
		"SELECT f.path FROM files as f, integritycheck as i "
-
		"LEFT JOIN packages as p ON "
-
		"p.id = f.package_id "
-
		"WHERE f.path = i.path AND "
-
		"p.name || '~' || p.origin != i.uid "
-
		"GROUP BY f.path";
-

-
	/*
-
	 * Select paths that are both in integritycheck and local table but their
-
	 * UIDs are different
-
	 */
-
	pkg_debug(4, "Pkgdb: running '%s'", sql_integrity_prepare);
-
	if (sqlite3_prepare_v2(db->sqlite,
-
		sql_integrity_prepare,
-
		-1, &stmt, NULL) != SQLITE_OK) {
-
		ERROR_SQLITE(db->sqlite, sql_integrity_prepare);
-
		return (EPKG_FATAL);
-
	}
-

-
	conflictmsg = sbuf_new_auto();
-
	uniqueid = sbuf_new_auto();
-

-
	while (sqlite3_step(stmt) != SQLITE_DONE) {
-
		const char *conflict_path;
-

-
		sbuf_clear(conflictmsg);
-
		sbuf_clear(uniqueid);
-

-
		/*
-
		 * Conflict found on path, so find the corresponding local
-
		 * package
-
		 */
-
		pkg_debug(4, "Pkgdb: running '%s'", sql_local_conflict);
-
		ret = sqlite3_prepare_v2(db->sqlite, sql_local_conflict, -1,
-
		    &stmt_conflicts, NULL);
-
		if (ret != SQLITE_OK) {
-
			ERROR_SQLITE(db->sqlite, sql_local_conflict);
-
			sqlite3_finalize(stmt);
-
			sbuf_delete(uniqueid);
-
			sbuf_delete(conflictmsg);
-
			return (EPKG_FATAL);
-
		}
-

-
		conflict_path = sqlite3_column_text(stmt, 0);
-
		sqlite3_bind_text(stmt_conflicts, 1,
-
			conflict_path, -1, SQLITE_STATIC);
-

-
		sqlite3_step(stmt_conflicts);
-

-
		sbuf_printf(conflictmsg,
-
		    "WARNING: locally installed %s-%s conflicts on %s with:\n",
-
		    sqlite3_column_text(stmt_conflicts, 0),
-
		    sqlite3_column_text(stmt_conflicts, 1),
-
		    sqlite3_column_text(stmt, 0));
-
		sbuf_cpy(uniqueid, sqlite3_column_text(stmt_conflicts, 3));
-
		sqlite3_finalize(stmt_conflicts);
-

-
		/*
-
		 * Now match local and remote conflicting packages
-
		 */
-
		pkg_debug(4, "Pkgdb: running '%s'", sql_conflicts);
-
		ret = sqlite3_prepare_v2(db->sqlite, sql_conflicts, -1,
-
		    &stmt_conflicts, NULL);
-
		if (ret != SQLITE_OK) {
-
			ERROR_SQLITE(db->sqlite, sql_conflicts);
-
			sqlite3_finalize(stmt);
-
			sbuf_delete(conflictmsg);
-
			sbuf_delete(uniqueid);
-
			return (EPKG_FATAL);
-
		}
-

-
		sbuf_finish(uniqueid);
-

-
		sqlite3_bind_text(stmt_conflicts, 1,
-
		    sqlite3_column_text(stmt, 0), -1, SQLITE_STATIC);
-

-
		while (sqlite3_step(stmt_conflicts) != SQLITE_DONE) {
-
			/* Append UID of conflicting remote package */
-
			sbuf_printf(conflictmsg, "\t- %s\n",
-
			    sqlite3_column_text(stmt_conflicts, 0));
-
			if (cb != NULL)
-
				cb (sbuf_data(uniqueid), sqlite3_column_text(stmt_conflicts, 0), cbdata);
-
		}
-

-
		sbuf_finish(conflictmsg);
-
		sqlite3_finalize(stmt_conflicts);
-

-
		//pkg_emit_error("%s", sbuf_get(conflictmsg));
-
		retcode = EPKG_CONFLICT;
-
	}
-

-
	sqlite3_finalize(stmt);
-
	sbuf_delete(conflictmsg);
-
	sbuf_delete(uniqueid);
-

-
	assert (sql_exec(db->sqlite, "DROP TABLE IF EXISTS integritycheck") == EPKG_OK);
-

-
	return (retcode);
-
}
-

struct pkgdb_it *
pkgdb_integrity_conflict_local(struct pkgdb *db, const char *uniqueid)
{
modified libpkg/private/pkg.h
@@ -528,13 +528,6 @@ const char* packing_format_to_string(pkg_formats format);
int pkg_delete_files(struct pkg *pkg, unsigned force);
int pkg_delete_dirs(struct pkgdb *db, struct pkg *pkg);

-
typedef void (*conflict_func_cb)(const char *, const char *, void *);
-
int pkgdb_integrity_append(struct pkgdb *db, struct pkg *p,
-
		conflict_func_cb cb, void *cbdata);
-
int pkgdb_integrity_check(struct pkgdb *db, conflict_func_cb cb, void *cbdata);
-
struct pkgdb_it *pkgdb_integrity_conflict_local(struct pkgdb *db,
-
						const char *uniqueid);
-

int pkg_set_mtree(struct pkg *, const char *mtree);

/* pkgdb commands */
modified libpkg/private/pkg_jobs.h
@@ -35,6 +35,7 @@
#include "private/utils.h"
#include "private/pkg.h"
#include "pkg.h"
+
#include "tree.h"

struct pkg_jobs;
struct job_pattern;
@@ -97,6 +98,12 @@ struct pkg_jobs_universe {
	size_t nitems;
};

+
struct pkg_jobs_conflict_item {
+
	uint64_t hash;
+
	struct pkg_job_universe_item *item;
+
	TREE_ENTRY(pkg_jobs_conflict_item) entry;
+
};
+

struct pkg_jobs {
	struct pkg_jobs_universe *universe;
	struct pkg_job_request	*request_add;
@@ -112,6 +119,7 @@ struct pkg_jobs {
	bool need_fetch;
	const char *reponame;
	const char *destdir;
+
	TREE_HEAD(, pkg_jobs_conflict_item) *conflict_items;
	struct job_pattern *patterns;
};

@@ -208,7 +216,8 @@ int pkg_conflicts_request_resolve(struct pkg_jobs *j);
/*
 * Append conflicts to a package
 */
-
int pkg_conflicts_append_pkg(struct pkg *p, struct pkg_jobs *j);
+
int pkg_conflicts_append_chain(struct pkg_job_universe_item *it,
+
	struct pkg_jobs *j);
/*
 * Perform integrity check for the jobs specified
 */