#include "hash.h"
struct hashBucket {
- void * key;
- void ** data;
+ const void * key;
+ const void ** data;
int dataCount;
struct hashBucket * next;
};
int hashEqualityString(const void * key1, const void * key2)
{
- char *k1 = (char *)key1;
- char *k2 = (char *)key2;
+ const char *k1 = (const char *)key1;
+ const char *k2 = (const char *)key2;
return strcmp(k1, k2);
}
return ht;
}
-void htAddEntry(hashTable ht, const void * key, void * data)
+void htAddEntry(hashTable ht, const void * key, const void * data)
{
unsigned int hash;
struct hashBucket * b, * ob;
if (!b) {
b = malloc(sizeof(*b));
if (ht->keySize) {
- b->key = malloc(ht->keySize);
- memcpy(b->key, key, ht->keySize);
+ char *k = malloc(ht->keySize);
+ memcpy(k, key, ht->keySize);
+ b->key = k;
} else {
b->key = (void *) key;
}
for (i = 0; i < ht->numBuckets; i++) {
b = ht->buckets[i];
- if (ht->keySize && b) free(b->key);
+ if (ht->keySize && b) xfree(b->key);
while (b) {
n = b->next;
- if (b->data) free(b->data); /* XXX ==> LEAK */
+ if (b->data) xfree(b->data);
free(b);
b = n;
}
if (!(b = findEntry(ht, key))) return 0; else return 1;
}
-int htGetEntry(hashTable ht, const void * key, void *** data,
- int * dataCount, void ** tableKey)
+int htGetEntry(hashTable ht, const void * key, const void *** data,
+ int * dataCount, const void ** tableKey)
{
struct hashBucket * b;
memory, but may be usefull anyway */
hashTable htCreate(int numBuckets, int keySize, hashFunctionType fn,
hashEqualityType eq);
-void htAddEntry(hashTable ht, const void * key, void * data);
+void htAddEntry(hashTable ht, const void * key, const void * data);
void htFree(hashTable ht);
/* returns 0 on success, 1 if the item is not found. tableKey may be NULL */
-int htGetEntry(hashTable ht, const void * key, void *** data, int * dataCount,
- void ** tableKey);
+int htGetEntry(hashTable ht, const void * key, const void *** data, int * dataCount,
+ const void ** tableKey);
/* returns 1 if the item is present, 0 otherwise */
int htHasEntry(hashTable ht, const void * key);
for (i = 0; i < fi->fc; i++) {
int otherPkgNum, otherFileNum;
- struct fileInfo ** recs;
+ const struct fileInfo ** recs;
int numRecs;
if (XFA_SKIPPING(fi->actions[i]))
fixupSize = 0;
}
- htGetEntry(ht, &fi->fps[i], (void ***) &recs, &numRecs, NULL);
+ /*
+ * Retrieve all records that apply to this file. Note that the
+ * file info records were built in the same order as the packages
+ * will be installed and removed so the records for an overlapped
+ * files will be sorted in exactly the same order.
+ */
+ htGetEntry(ht, &fi->fps[i], (const void ***) &recs, &numRecs, NULL);
- /* We need to figure out the current fate of this file. So,
- work backwards from this file and look for a final action
- we can work against. */
+ /*
+ * If this package is being added, look only at other packages
+ * being added -- removed packages dance to a different tune.
+ * If both this and the other package are being added, overlapped
+ * files must be identical (or marked as a conflict). The
+ * disposition of already installed config files leads to
+ * a small amount of extra complexity.
+ *
+ * If this package is being removed, then there are two cases that
+ * need to be worried about:
+ * If the other package is being added, then skip any overlapped files
+ * so that this package removal doesn't nuke the overlapped files
+ * that were just installed.
+ * If both this and the other package are being removed, then each
+ * file removal from preceding packages needs to be skipped so that
+ * the file removal occurs only on the last occurence of an overlapped
+ * file in the transaction set.
+ *
+ */
+
+ /* Locate this overlapped file in the set of added/removed packages. */
for (j = 0; recs[j] != fi; j++)
;
+ /* Find what the previous disposition of this file was. */
otherFileNum = -1; /* keep gcc quiet */
for (otherPkgNum = j - 1; otherPkgNum >= 0; otherPkgNum--) {
-#if XXX_ERASED_PACKAGES_LAST
- if (recs[otherPkgNum]->type != TR_ADDED)
+ /* Added packages need only look at other added packages. */
+ if (fi->type == TR_ADDED && recs[otherPkgNum]->type != TR_ADDED)
continue;
-#endif
/* TESTME: there are more efficient searches in the world... */
for (otherFileNum = 0; otherFileNum < recs[otherPkgNum]->fc;
if (FP_EQUAL(fi->fps[i], recs[otherPkgNum]->fps[otherFileNum]))
break;
}
+ /* XXX is this test still necessary? */
if (recs[otherPkgNum]->actions[otherFileNum] != FA_UNKNOWN)
break;
}
struct stat sb;
case TR_ADDED:
if (otherPkgNum < 0) {
+ /* XXX is this test still necessary? */
if (fi->actions[i] != FA_UNKNOWN)
break;
if ((fi->fflags[i] & RPMFILE_CONFIG) && !lstat(fi->fl[i], &sb)) {
+ /* Here is a non-overlapped pre-existing config file. */
fi->actions[i] = (fi->fflags[i] & RPMFILE_NOREPLACE)
? FA_ALTNAME : FA_BACKUP;
} else {
break;
}
+ /* Mark added overlapped nnon-identical files as a conflict. */
if (probs && filecmp(recs[otherPkgNum]->fmodes[otherFileNum],
recs[otherPkgNum]->fmd5s[otherFileNum],
recs[otherPkgNum]->flinks[otherFileNum],
fi->ap->h, fi->fl[i], recs[otherPkgNum]->ap->h, 0);
}
+ /* Try to get the disk accounting correct even if a conflict. */
fixupSize = recs[otherPkgNum]->fsizes[otherFileNum];
- /* FIXME: is this right??? it locks us into the config
- file handling choice we already made, which may very
- well be exactly right. What about noreplace files?? */
if ((fi->fflags[i] & RPMFILE_CONFIG) && !lstat(fi->fl[i], &sb)) {
+ /* Here is an overlapped pre-existing config file. */
fi->actions[i] = (fi->fflags[i] & RPMFILE_NOREPLACE)
? FA_ALTNAME : FA_SKIP;
} else {
fi->actions[i] = FA_SKIP;
break;
#else
+ /* Here is an overlapped added file we don't want to nuke */
if (recs[otherPkgNum]->actions[otherFileNum] != FA_REMOVE) {
/* On updates, don't remove files. */
fi->actions[i] = FA_SKIP;
break;
}
- /* Remove file on last occurrence. Other package should skip. */
+ /* Here is an overlapped removed file: skip in previous. */
recs[otherPkgNum]->actions[otherFileNum] = FA_SKIP;
#endif
}
break;
}
+ /* Here is a pre-existing modified config file that needs saving. */
{ char mdsum[50];
if (!mdfile(fi->fl[i], mdsum) && strcmp(fi->fmd5s[i], mdsum)) {
fi->actions[i] = FA_BACKUP;
break;
}
}
- /* FIXME: config files may need to be saved */
fi->actions[i] = FA_REMOVE;
break;
}