probably right :-( */
#define BLOCK_ROUND(size, block) (((size) + (block) - 1) / (block))
-static rpmProblemSet psCreate(void);
-static void psAppend(rpmProblemSet probs, rpmProblemType type,
- const void * key, Header h, const char * str1,
- Header altHeader, unsigned long ulong1);
-static int archOkay(Header h);
-static int osOkay(Header h);
-static Header relocateFileList(struct availablePackage * alp,
- rpmProblemSet probs, Header h,
- enum fileActions * actions,
- int allowBadRelocate);
-static int psTrim(rpmProblemSet filter, rpmProblemSet target);
-static int sharedCmp(const void * one, const void * two);
-static enum fileActions decideFileFate(const char * filespec, short dbMode,
- char * dbMd5, char * dbLink, short newMode,
- char * newMd5, char * newLink, int newFlags,
- int brokenMd5);
-enum fileTypes whatis(short mode);
-static int filecmp(short mode1, char * md51, char * link1,
- short mode2, char * md52, char * link2);
-static int handleInstInstalledFiles(struct fileInfo * fi, rpmdb db,
- struct sharedFileInfo * shared,
- int sharedCount, int reportConflicts,
- rpmProblemSet probs);
-static int handleRmvdInstalledFiles(struct fileInfo * fi, rpmdb db,
- struct sharedFileInfo * shared,
- int sharedCount);
-void handleOverlappedFiles(struct fileInfo * fi, hashTable ht,
- rpmProblemSet probs, struct diskspaceInfo * dsl);
-static int ensureOlder(rpmdb db, Header new, int dbOffset, rpmProblemSet probs,
- const void * key);
-static void skipFiles(struct fileInfo * fi, int noDocs);
+#define XSTRCMP(a, b) ((!(a) && !(b)) || ((a) && (b) && !strcmp((a), (b))))
static void freeFi(struct fileInfo *fi)
{
}
}
-#define XSTRCMP(a, b) ((!(a) && !(b)) || ((a) && (b) && !strcmp((a), (b))))
-
-#define NOTIFY(_x) if (notify) notify _x
+void rpmtransSetScriptFd(rpmTransactionSet ts, FD_t fd)
+{
+ ts->scriptFd = fd;
+}
-/* Return -1 on error, > 0 if newProbs is set, 0 if everything
- happened */
-int rpmRunTransactions(rpmTransactionSet ts, rpmCallbackFunction notify,
- void * notifyData, rpmProblemSet okProbs,
- rpmProblemSet * newProbs, int flags, int ignoreSet) {
- int i, j;
- int rc, ourrc = 0;
- struct availablePackage * alp;
+static rpmProblemSet psCreate(void)
+{
rpmProblemSet probs;
- dbiIndexSet dbi, * matches;
- Header * hdrs;
- int fileCount;
- int totalFileCount = 0;
- hashTable ht;
- struct fileInfo * flList, * fi;
- struct sharedFileInfo * shared, * sharedList;
- int numShared;
- int flEntries;
- int last;
- int lastFailed;
- int beingRemoved;
- char * currDir, * chptr;
- FD_t fd;
- const char ** filesystems;
- int filesystemCount;
- struct diskspaceInfo * di = NULL;
- int oc;
-
- /* FIXME: what if the same package is included in ts twice? */
-
- if (!(ignoreSet & RPMPROB_FILTER_DISKSPACE) &&
- !rpmGetFilesystemList(&filesystems, &filesystemCount)) {
- struct stat sb;
- di = alloca(sizeof(*di) * (filesystemCount + 1));
+ probs = malloc(sizeof(*probs));
+ probs->numProblems = probs->numProblemsAlloced = 0;
+ probs->probs = NULL;
- for (i = 0; (i < filesystemCount) && di; i++) {
-#if STATFS_IN_SYS_STATVFS
- struct statvfs sfb;
- if (statvfs(filesystems[i], &sfb))
-#else
- struct statfs sfb;
-# if STAT_STATFS4
-/* this platform has the 4-argument version of the statfs call. The last two
- * should be the size of struct statfs and 0, respectively. The 0 is the
- * filesystem type, and is always 0 when statfs is called on a mounted
- * filesystem, as we're doing.
- */
- if (statfs(filesystems[i], &sfb, sizeof(sfb), 0))
-# else
- if (statfs(filesystems[i], &sfb))
-# endif
-#endif
- {
- di = NULL;
- } else {
- di[i].block = sfb.f_bsize;
- di[i].needed = 0;
-#ifdef STATFS_HAS_F_BAVAIL
- di[i].avail = sfb.f_bavail;
-#else
-/* FIXME: the statfs struct doesn't have a member to tell how many blocks are
- * available for non-superusers. f_blocks - f_bfree is probably too big, but
- * it's about all we can do.
- */
- di[i].avail = sfb.f_blocks - sfb.f_bfree;
-#endif
+ return probs;
+}
+static void psAppend(rpmProblemSet probs, rpmProblemType type,
+ const void * key, Header h, const char * str1,
+ Header altH, unsigned long ulong1)
+{
+ if (probs->numProblems == probs->numProblemsAlloced) {
+ if (probs->numProblemsAlloced)
+ probs->numProblemsAlloced *= 2;
+ else
+ probs->numProblemsAlloced = 2;
+ probs->probs = realloc(probs->probs,
+ probs->numProblemsAlloced * sizeof(*probs->probs));
+ }
- stat(filesystems[i], &sb);
- di[i].dev = sb.st_dev;
- }
- }
+ probs->probs[probs->numProblems].type = type;
+ probs->probs[probs->numProblems].key = key;
+ probs->probs[probs->numProblems].h = headerLink(h);
+ probs->probs[probs->numProblems].ulong1 = ulong1;
+ if (str1)
+ probs->probs[probs->numProblems].str1 = strdup(str1);
+ else
+ probs->probs[probs->numProblems].str1 = NULL;
- if (di) di[i].block = 0;
- }
+ if (altH)
+ probs->probs[probs->numProblems].altH = headerLink(altH);
+ else
+ probs->probs[probs->numProblems].altH = NULL;
- probs = psCreate();
- *newProbs = probs;
- hdrs = alloca(sizeof(*hdrs) * ts->addedPackages.size);
+ probs->probs[probs->numProblems++].ignoreProblem = 0;
+}
- /* The ordering doesn't matter here */
- for (alp = ts->addedPackages.list; (alp - ts->addedPackages.list) <
- ts->addedPackages.size; alp++) {
- if (!archOkay(alp->h) && !(ignoreSet & RPMPROB_FILTER_IGNOREARCH))
- psAppend(probs, RPMPROB_BADARCH, alp->key, alp->h, NULL, NULL, 0);
+static int archOkay(Header h)
+{
+ int_8 * pkgArchNum;
+ void * pkgArch;
+ int type, count, archNum;
- if (!osOkay(alp->h) && !(ignoreSet & RPMPROB_FILTER_IGNOREOS)) {
- psAppend(probs, RPMPROB_BADOS, alp->key, alp->h, NULL, NULL, 0);
+ /* make sure we're trying to install this on the proper architecture */
+ headerGetEntry(h, RPMTAG_ARCH, &type, (void **) &pkgArch, &count);
+ if (type == RPM_INT8_TYPE) {
+ /* old arch handling */
+ rpmGetArchInfo(NULL, &archNum);
+ pkgArchNum = pkgArch;
+ if (archNum != *pkgArchNum) {
+ return 0;
+ }
+ } else {
+ /* new arch handling */
+ if (!rpmMachineScore(RPM_MACHTABLE_INSTARCH, pkgArch)) {
+ return 0;
}
+ }
- if (!(ignoreSet & RPMPROB_FILTER_OLDPACKAGE)) {
- rc = rpmdbFindPackage(ts->db, alp->name, &dbi);
- if (rc == 2) {
- return -1;
- } else if (!rc) {
- for (i = 0; i < dbi.count; i++)
- ensureOlder(ts->db, alp->h, dbi.recs[i].recOffset,
- probs, alp->key);
+ return 1;
+}
- dbiFreeIndexRecord(dbi);
- }
- }
+static int osOkay(Header h)
+{
+ void * pkgOs;
+ int type, count;
- rc = findMatches(ts->db, alp->name, alp->version, alp->release, &dbi);
- if (rc == 2) {
- return -1;
- } else if (!rc) {
- if (!(ignoreSet & RPMPROB_FILTER_REPLACEPKG))
- psAppend(probs, RPMPROB_PKG_INSTALLED, alp->key, alp->h, NULL,
- NULL, 0);
- dbiFreeIndexRecord(dbi);
+ /* make sure we're trying to install this on the proper os */
+ headerGetEntry(h, RPMTAG_OS, &type, (void **) &pkgOs, &count);
+ if (type == RPM_INT8_TYPE) {
+ /* v1 packages and v2 packages both used improper OS numbers, so just
+ deal with it hope things work */
+ return 1;
+ } else {
+ /* new os handling */
+ if (!rpmMachineScore(RPM_MACHTABLE_INSTOS, pkgOs)) {
+ return 0;
}
-
- if (headerGetEntry(alp->h, RPMTAG_FILENAMES, NULL, NULL, &fileCount))
- totalFileCount += fileCount;
}
- /* FIXME: it seems a bit silly to read in all of these headers twice */
- /* The ordering doesn't matter here */
- for (i = 0; i < ts->numRemovedPackages; i++) {
- Header h;
+ return 1;
+}
- if ((h = rpmdbGetRecord(ts->db, ts->removedPackages[i]))) {
- if (headerGetEntry(h, RPMTAG_FILENAMES, NULL, NULL,
- &fileCount))
- totalFileCount += fileCount;
- headerFree(h); /* XXX ==> LEAK */
- }
+void rpmProblemSetFree(rpmProblemSet probs)
+{
+ int i;
+
+ for (i = 0; i < probs->numProblems; i++) {
+ headerFree(probs->probs[i].h);
+ if (probs->probs[i].str1) free(probs->probs[i].str1);
+ if (probs->probs[i].altH) headerFree(probs->probs[i].altH);
}
+ free(probs);
+}
- flEntries = ts->addedPackages.size + ts->numRemovedPackages;
- flList = alloca(sizeof(*flList) * (flEntries));
+static Header relocateFileList(struct availablePackage * alp,
+ rpmProblemSet probs, Header origH,
+ enum fileActions * actions,
+ int allowBadRelocate)
+{
+ int numValid, numRelocations;
+ int i, j, madeSwap, rc;
+ rpmRelocation * nextReloc, * relocations = NULL;
+ rpmRelocation * rawRelocations = alp->relocs;
+ rpmRelocation tmpReloc;
+ char ** validRelocations, ** actualRelocations;
+ char ** names;
+ char ** origNames;
+ int len = 0;
+ char * newName;
+ int_32 fileCount;
+ Header h;
+ int relocated = 0;
- ht = htCreate(totalFileCount * 2, 0, fpHashFunction, fpEqual);
+ if (!headerGetEntry(origH, RPMTAG_PREFIXES, NULL,
+ (void **) &validRelocations, &numValid))
+ numValid = 0;
- /* FIXME?: we'd be better off assembling one very large file list and
- calling fpLookupList only once. I'm not sure that the speedup is
- worth the trouble though. */
- for (fi = flList, oc = 0; oc < ts->orderCount; fi++, oc++) {
- memset(fi, 0, sizeof(*fi));
+ if (!rawRelocations && !numValid) return headerLink(origH);
- if (ts->order[oc].type == TR_ADDED) {
- i = ts->order[oc].u.addedIndex;
- alp = ts->addedPackages.list + ts->order[oc].u.addedIndex;
+ h = headerCopy(origH);
- if (!headerGetEntryMinMemory(alp->h, RPMTAG_FILENAMES, NULL,
- NULL, &fi->fc)) {
- fi->h = headerLink(alp->h);
- hdrs[i] = headerLink(fi->h);
- continue;
- }
+ if (rawRelocations) {
+ for (i = 0; rawRelocations[i].newPath || rawRelocations[i].oldPath;
+ i++) ;
+ numRelocations = i;
+ } else {
+ numRelocations = 0;
+ }
+ relocations = alloca(sizeof(*relocations) * numRelocations);
- fi->actions = calloc(sizeof(*fi->actions), fi->fc);
- hdrs[i] = relocateFileList(alp, probs, alp->h, fi->actions,
- ignoreSet & RPMPROB_FILTER_FORCERELOCATE);
- fi->h = headerLink(hdrs[i]);
- fi->type = TR_ADDED;
- fi->ap = alp;
+ for (i = 0; i < numRelocations; i++) {
+ /* FIXME: default relocations (oldPath == NULL) need to be handled
+ in the UI, not rpmlib */
+
+ relocations[i].oldPath =
+ alloca(strlen(rawRelocations[i].oldPath) + 1);
+ strcpy(relocations[i].oldPath, rawRelocations[i].oldPath);
+ stripTrailingSlashes(relocations[i].oldPath);
+
+ if (rawRelocations[i].newPath) {
+ relocations[i].newPath =
+ alloca(strlen(rawRelocations[i].newPath) + 1);
+ strcpy(relocations[i].newPath, rawRelocations[i].newPath);
+ stripTrailingSlashes(relocations[i].newPath);
} else {
- fi->record = ts->order[oc].u.removed.dboffset;
- fi->h = rpmdbGetRecord(ts->db, fi->record);
- if (!fi->h) {
- /* ACK! */
- continue;
- }
- fi->type = TR_REMOVED;
+ relocations[i].newPath = NULL;
}
- if (!headerGetEntry(fi->h, RPMTAG_FILENAMES, NULL,
- (void **) &fi->fl, &fi->fc)) {
- /* This catches removed packages w/ no file lists */
- fi->fc = 0;
- continue;
+ if (relocations[i].newPath) {
+ for (j = 0; j < numValid; j++)
+ if (!strcmp(validRelocations[j],
+ relocations[i].oldPath)) break;
+ if (j == numValid && !allowBadRelocate)
+ psAppend(probs, RPMPROB_BADRELOCATE, alp->key, alp->h,
+ relocations[i].oldPath, NULL,0 );
}
+ }
- /* actions is initialized earlier for added packages */
- if (!fi->actions)
- fi->actions = calloc(sizeof(*fi->actions), fi->fc);
-
- headerGetEntry(fi->h, RPMTAG_FILEMODES, NULL,
- (void **) &fi->fmodes, NULL);
- headerGetEntry(fi->h, RPMTAG_FILEFLAGS, NULL,
- (void **) &fi->fflags, NULL);
- headerGetEntry(fi->h, RPMTAG_FILESIZES, NULL,
- (void **) &fi->fsizes, NULL);
- headerGetEntry(fi->h, RPMTAG_FILESTATES, NULL,
- (void **) &fi->fstates, NULL);
-
- if (ts->order[oc].type == TR_REMOVED) {
- headerGetEntry(fi->h, RPMTAG_FILEMD5S, NULL,
- (void **) &fi->fmd5s, NULL);
- headerGetEntry(fi->h, RPMTAG_FILELINKTOS, NULL,
- (void **) &fi->flinks, NULL);
- fi->fsizes = memcpy(malloc(fi->fc * sizeof(*fi->fsizes)),
- fi->fsizes, fi->fc * sizeof(*fi->fsizes));
- fi->fflags = memcpy(malloc(fi->fc * sizeof(*fi->fflags)),
- fi->fflags, fi->fc * sizeof(*fi->fflags));
- fi->fmodes = memcpy(malloc(fi->fc * sizeof(*fi->fmodes)),
- fi->fmodes, fi->fc * sizeof(*fi->fmodes));
- fi->fstates = memcpy(malloc(fi->fc * sizeof(*fi->fstates)),
- fi->fstates, fi->fc * sizeof(*fi->fstates));
- headerFree(fi->h);
- fi->h = NULL;
- } else {
- /* ADDED package */
+ /* stupid bubble sort, but it's probably faster here */
+ for (i = 0; i < numRelocations; i++) {
+ madeSwap = 0;
+ for (j = 1; j < numRelocations; j++) {
+ if (strcmp(relocations[j - 1].oldPath,
+ relocations[j].oldPath) > 0) {
+ tmpReloc = relocations[j - 1];
+ relocations[j - 1] = relocations[j];
+ relocations[j] = tmpReloc;
+ madeSwap = 1;
+ }
+ }
+ if (!madeSwap) break;
+ }
- headerGetEntryMinMemory(fi->h, RPMTAG_FILEMD5S, NULL,
- (void **) &fi->fmd5s, NULL);
- headerGetEntryMinMemory(fi->h, RPMTAG_FILELINKTOS, NULL,
- (void **) &fi->flinks, NULL);
+ if (numValid) {
+ actualRelocations = malloc(sizeof(*actualRelocations) * numValid);
+ for (i = 0; i < numValid; i++) {
+ for (j = 0; j < numRelocations; j++) {
+ if (!strcmp(validRelocations[i], relocations[j].oldPath)) {
+ actualRelocations[i] = relocations[j].newPath;
+ break;
+ }
+ }
- /* 0 makes for noops */
- fi->replacedSizes = calloc(fi->fc, sizeof(*fi->replacedSizes));
- skipFiles(fi, flags & RPMTRANS_FLAG_NODOCS);
+ if (j == numRelocations)
+ actualRelocations[i] = validRelocations[i];
}
- fi->fps = malloc(fi->fc * sizeof(*fi->fps));
+ headerAddEntry(h, RPMTAG_INSTPREFIXES, RPM_STRING_ARRAY_TYPE,
+ (void **) actualRelocations, numValid);
+
+ free(actualRelocations);
+ free(validRelocations);
}
- chptr = currentDirectory();
- currDir = alloca(strlen(chptr) + 1);
- strcpy(currDir, chptr);
- free(chptr);
- chdir("/");
- chroot(ts->root);
+ headerGetEntry(h, RPMTAG_FILENAMES, NULL, (void **) &names,
+ &fileCount);
- for (fi = flList; (fi - flList) < flEntries; fi++) {
- fpLookupList(fi->fl, fi->fps, fi->fc, 1);
- for (i = 0; i < fi->fc; i++) {
- if (fi->actions[i] != FA_SKIP && fi->actions[i] != FA_SKIPNSTATE)
- htAddEntry(ht, fi->fps + i, fi);
+ /* go through things backwards so that /usr/local relocations take
+ precedence over /usr ones */
+ for (i = fileCount - 1; i >= 0; i--) {
+ for (j = numRelocations - 1; j >= 0; j--) {
+ nextReloc = relocations + j;
+ len = strlen(relocations[j].oldPath);
+ rc = (!strncmp(relocations[j].oldPath, names[i], len) &&
+ ((names[i][len] == '/') || !names[i][len]));
+ if (rc) break;
}
- }
- NOTIFY((NULL, RPMCALLBACK_TRANS_START, 6, flEntries, NULL, notifyData));
+ if (j >= 0) {
+ nextReloc = relocations + j;
+ if (nextReloc->newPath) {
+ newName = alloca(strlen(nextReloc->newPath) +
+ strlen(names[i]) + 1);
+ strcpy(newName, nextReloc->newPath);
+ strcat(newName, names[i] + len);
+ rpmMessage(RPMMESS_DEBUG, _("relocating %s to %s\n"),
+ names[i], newName);
+ names[i] = newName;
+ relocated = 1;
+ } else if (actions) {
+ actions[i] = FA_SKIPNSTATE;
+ rpmMessage(RPMMESS_DEBUG, _("excluding %s\n"), names[i]);
+ }
+ }
+ }
- for (fi = flList; (fi - flList) < flEntries; fi++) {
- int k, ro;
- int knownBad;
+ if (relocated) {
+ headerGetEntry(h, RPMTAG_FILENAMES, NULL, (void **) &origNames, NULL);
+ headerAddEntry(h, RPMTAG_ORIGFILENAMES, RPM_STRING_ARRAY_TYPE,
+ origNames, fileCount);
+ free(origNames);
+ headerModifyEntry(h, RPMTAG_FILENAMES, RPM_STRING_ARRAY_TYPE,
+ names, fileCount);
+ }
- NOTIFY((NULL, RPMCALLBACK_TRANS_PROGRESS, (fi - flList), flEntries,
- NULL, notifyData));
+ free(names);
- matches = malloc(sizeof(*matches) * fi->fc);
- if (rpmdbFindFpList(ts->db, fi->fps, matches, fi->fc)) return 1;
+ return h;
+}
- numShared = 0;
- for (i = 0; i < fi->fc; i++)
- numShared += matches[i].count;
+static int psTrim(rpmProblemSet filter, rpmProblemSet target)
+{
+ /* As the problem sets are generated in an order solely dependent
+ on the ordering of the packages in the transaction, and that
+ ordering can't be changed, the problem sets must be parallel to
+ on another. Additionally, the filter set must be a subset of the
+ target set, given the operations available on transaction set.
+ This is good, as it lets us perform this trim in linear time, rather
+ then logarithmic or quadratic. */
+ rpmProblem * f, * t;
+ int gotProblems = 0;
- shared = sharedList = malloc(sizeof(*sharedList) * (numShared + 1));
- knownBad = 0;
- for (i = 0; i < fi->fc; i++) {
- /* Take care not to mark files as replaced in packages that will
- have been removed before we got here. */
- for (j = 0; j < matches[i].count; j++) {
- ro = matches[i].recs[j].recOffset;
- if (ro != knownBad) {
- for (k = 0; k < ts->orderCount; k++) {
- if (ts->order[k].type == TR_REMOVED &&
- ts->order[k].u.removed.dboffset == ro) break;
- }
- if (k < ts->orderCount) {
- knownBad = ro;
- }
- }
+ f = filter->probs;
+ t = target->probs;
- shared->pkgFileNum = i;
- shared->otherPkg = matches[i].recs[j].recOffset;
- shared->otherFileNum = matches[i].recs[j].fileNumber;
- shared->isRemoved = (knownBad == ro);
- shared++;
- }
- dbiFreeIndexRecord(matches[i]);
+ while ((f - filter->probs) < filter->numProblems) {
+ if (!f->ignoreProblem) {
+ f++;
+ continue;
+ }
+ while ((t - target->probs) < target->numProblems) {
+ if (f->h == t->h && f->type == t->type && t->key == f->key &&
+ XSTRCMP(f->str1, t->str1))
+ break;
+ t++;
+ gotProblems = 1;
}
- numShared = shared - sharedList;
- shared->otherPkg = -1;
- free(matches);
-
- qsort(sharedList, numShared, sizeof(*shared), sharedCmp);
- i = 0;
- while (i < numShared) {
- last = i + 1;
- j = sharedList[i].otherPkg;
- while ((sharedList[last].otherPkg == j) && (last < numShared))
- last++;
- last--;
+ if ((t - target->probs) == target->numProblems) {
+ /* this can't happen ;-) lets be sane if it doesn though */
+ break;
+ }
- for (j = 0; j < ts->numRemovedPackages; j++) {
- if (ts->removedPackages[j] == sharedList[i].otherPkg)
- break;
- }
- beingRemoved = (j < ts->numRemovedPackages);
+ t->ignoreProblem = f->ignoreProblem;
+ t++, f++;
+ }
- if (fi->type == TR_ADDED)
- handleInstInstalledFiles(fi, ts->db, sharedList + i,
- last - i + 1,
- !(beingRemoved ||
- (ignoreSet & RPMPROB_FILTER_REPLACEOLDFILES)),
- probs);
- else if (fi->type == TR_REMOVED && !beingRemoved)
- handleRmvdInstalledFiles(fi, ts->db, sharedList + i,
- last - i + 1);
+ if ((t - target->probs) < target->numProblems)
+ gotProblems = 1;
- i = last + 1;
- }
+ return gotProblems;
+}
- free(sharedList);
+static int sharedCmp(const void * one, const void * two)
+{
+ const struct sharedFileInfo * a = one;
+ const struct sharedFileInfo * b = two;
- handleOverlappedFiles(fi, ht,
- (ignoreSet & RPMPROB_FILTER_REPLACENEWFILES) ? NULL : probs, di);
+ if (a->otherPkg < b->otherPkg)
+ return -1;
+ else if (a->otherPkg > b->otherPkg)
+ return 1;
- if (di && fi->type == TR_ADDED && fi->fc) {
- for (i = 0; i < filesystemCount; i++) {
- if (adj_fs_blocks(di[i].needed) > di[i].avail) {
- psAppend(probs, RPMPROB_DISKSPACE, fi->ap->key, fi->ap->h,
- filesystems[i], NULL,
- (adj_fs_blocks(di[i].needed) - di[i].avail) *
- di[i].block);
- }
- }
- }
- }
+ return 0;
+}
- NOTIFY((NULL, RPMCALLBACK_TRANS_STOP, 6, flEntries, NULL, notifyData));
+static enum fileTypes whatis(short mode)
+{
+ enum fileTypes result;
- chroot(".");
- chdir(currDir);
+ if (S_ISDIR(mode))
+ result = XDIR;
+ else if (S_ISCHR(mode))
+ result = CDEV;
+ else if (S_ISBLK(mode))
+ result = BDEV;
+ else if (S_ISLNK(mode))
+ result = LINK;
+ else if (S_ISSOCK(mode))
+ result = SOCK;
+ else if (S_ISFIFO(mode))
+ result = PIPE;
+ else
+ result = REG;
+
+ return result;
+}
- htFree(ht);
+static enum fileActions decideFileFate(const char * filespec, short dbMode,
+ char * dbMd5, char * dbLink, short newMode,
+ char * newMd5, char * newLink, int newFlags,
+ int brokenMd5)
+{
+ char buffer[1024];
+ char * dbAttr, * newAttr;
+ enum fileTypes dbWhat, newWhat, diskWhat;
+ struct stat sb;
+ int i, rc;
+ int save = (newFlags & RPMFILE_NOREPLACE) ? FA_ALTNAME : FA_SAVE;
- for (oc = 0, fi = flList; oc < ts->orderCount; oc++, fi++) {
- if (fi->fc) {
- free(fi->fl); fi->fl = NULL;
- if (fi->type == TR_ADDED) {
- free(fi->fmd5s); fi->fmd5s = NULL;
- free(fi->flinks); fi->flinks = NULL;
- free(fi->fps); fi->fps = NULL;
- }
- }
+ if (lstat(filespec, &sb)) {
+ /* the file doesn't exist on the disk create it unless the new
+ package has marked it as missingok */
+ if (newFlags & RPMFILE_MISSINGOK) {
+ rpmMessage(RPMMESS_DEBUG, _("%s skipped due to missingok flag\n"),
+ filespec);
+ return FA_SKIP;
+ } else
+ return FA_CREATE;
}
- if ((flags & RPMTRANS_FLAG_BUILD_PROBS) ||
- (probs->numProblems && (!okProbs || psTrim(okProbs, probs)))) {
- *newProbs = probs;
+ diskWhat = whatis(sb.st_mode);
+ dbWhat = whatis(dbMode);
+ newWhat = whatis(newMode);
- for (alp = ts->addedPackages.list, fi = flList;
- (alp - ts->addedPackages.list) < ts->addedPackages.size;
- alp++, fi++) {
- headerFree(hdrs[alp - ts->addedPackages.list]);
- }
+ /* RPM >= 2.3.10 shouldn't create config directories -- we'll ignore
+ them in older packages as well */
+ if (newWhat == XDIR)
+ return FA_CREATE;
- freeFl(ts, flList);
- return ts->orderCount;
+ if (diskWhat != newWhat) {
+ return save;
+ } else if (newWhat != dbWhat && diskWhat != dbWhat) {
+ return save;
+ } else if (dbWhat != newWhat) {
+ return FA_CREATE;
+ } else if (dbWhat != LINK && dbWhat != REG) {
+ return FA_CREATE;
}
- lastFailed = -2;
- for (oc = 0, fi = flList; oc < ts->orderCount; oc++, fi++) {
- if (ts->order[oc].type == TR_ADDED) {
- alp = ts->addedPackages.list + ts->order[oc].u.addedIndex;
- i = ts->order[oc].u.addedIndex;
-
- if (alp->fd) {
- fd = alp->fd;
- } else {
- fd = notify(fi->h, RPMCALLBACK_INST_OPEN_FILE, 0, 0,
- alp->key, notifyData);
- if (fd) {
- Header h;
-
- headerFree(hdrs[i]);
- rc = rpmReadPackageHeader(fd, &h, NULL, NULL, NULL);
- if (rc) {
- notify(fi->h, RPMCALLBACK_INST_CLOSE_FILE, 0, 0,
- alp->key, notifyData);
- ourrc++;
- fd = NULL;
- } else {
- hdrs[i] = relocateFileList(alp, probs, h, NULL, 1);
- headerFree(h);
- }
- }
- }
-
- if (fd) {
- if (installBinaryPackage(ts->root, ts->db, fd,
- hdrs[i], flags, notify,
- notifyData, alp->key, fi->actions,
- fi->fc ? fi->replaced : NULL,
- ts->scriptFd)) {
- ourrc++;
- lastFailed = i;
- }
- } else {
- ourrc++;
- lastFailed = i;
- }
+ if (dbWhat == REG) {
+ if (brokenMd5)
+ rc = mdfileBroken(filespec, buffer);
+ else
+ rc = mdfile(filespec, buffer);
- headerFree(hdrs[i]);
+ if (rc) {
+ /* assume the file has been removed, don't freak */
+ return FA_CREATE;
+ }
+ dbAttr = dbMd5;
+ newAttr = newMd5;
+ } else /* dbWhat == LINK */ {
+ memset(buffer, 0, sizeof(buffer));
+ i = readlink(filespec, buffer, sizeof(buffer) - 1);
+ if (i == -1) {
+ /* assume the file has been removed, don't freak */
+ return FA_CREATE;
+ }
+ dbAttr = dbLink;
+ newAttr = newLink;
+ }
- if (!alp->fd && fd)
- notify(fi->h, RPMCALLBACK_INST_CLOSE_FILE, 0, 0, alp->key,
- notifyData);
- } else if (ts->order[oc].u.removed.dependsOnIndex != lastFailed) {
- if (removeBinaryPackage(ts->root, ts->db, fi->record,
- flags, fi->actions, ts->scriptFd))
+ /* this order matters - we'd prefer to CREATE the file if at all
+ possible in case something else (like the timestamp) has changed */
- ourrc++;
- }
+ if (!strcmp(dbAttr, buffer)) {
+ /* this config file has never been modified, so
+ just replace it */
+ return FA_CREATE;
}
- freeFl(ts, flList);
+ if (!strcmp(dbAttr, newAttr)) {
+ /* this file is the same in all versions of this package */
+ return FA_SKIP;
+ }
- if (ourrc)
- return -1;
- else
- return 0;
+ /* the config file on the disk has been modified, but
+ the ones in the two packages are different. It would
+ be nice if RPM was smart enough to at least try and
+ merge the difference ala CVS, but... */
+
+ return save;
}
-void rpmtransSetScriptFd(rpmTransactionSet ts, FD_t fd) {
- ts->scriptFd = fd;
-}
+static int filecmp(short mode1, char * md51, char * link1,
+ short mode2, char * md52, char * link2)
+{
+ enum fileTypes what1, what2;
-static rpmProblemSet psCreate(void) {
- rpmProblemSet probs;
+ what1 = whatis(mode1);
+ what2 = whatis(mode2);
- probs = malloc(sizeof(*probs));
- probs->numProblems = probs->numProblemsAlloced = 0;
- probs->probs = NULL;
+ if (what1 != what2) return 1;
- return probs;
+ if (what1 == LINK)
+ return strcmp(link1, link2);
+ else if (what1 == REG)
+ return strcmp(md51, md52);
+
+ return 0;
}
-static void psAppend(rpmProblemSet probs, rpmProblemType type,
- const void * key, Header h, const char * str1,
- Header altH, unsigned long ulong1) {
- if (probs->numProblems == probs->numProblemsAlloced) {
- if (probs->numProblemsAlloced)
- probs->numProblemsAlloced *= 2;
- else
- probs->numProblemsAlloced = 2;
- probs->probs = realloc(probs->probs,
- probs->numProblemsAlloced * sizeof(*probs->probs));
- }
+static int handleInstInstalledFiles(struct fileInfo * fi, rpmdb db,
+ struct sharedFileInfo * shared,
+ int sharedCount, int reportConflicts,
+ rpmProblemSet probs)
+{
+ Header h;
+ int i;
+ char ** otherMd5s, ** otherLinks;
+ char * otherStates;
+ uint_32 * otherFlags, * otherSizes;
+ uint_16 * otherModes;
+ int otherFileNum;
+ int fileNum;
+ int numReplaced = 0;
- probs->probs[probs->numProblems].type = type;
- probs->probs[probs->numProblems].key = key;
- probs->probs[probs->numProblems].h = headerLink(h);
- probs->probs[probs->numProblems].ulong1 = ulong1;
- if (str1)
- probs->probs[probs->numProblems].str1 = strdup(str1);
- else
- probs->probs[probs->numProblems].str1 = NULL;
+ if (!(h = rpmdbGetRecord(db, shared->otherPkg)))
+ return 1;
- if (altH)
- probs->probs[probs->numProblems].altH = headerLink(altH);
- else
- probs->probs[probs->numProblems].altH = NULL;
+ headerGetEntryMinMemory(h, RPMTAG_FILEMD5S, NULL,
+ (void **) &otherMd5s, NULL);
+ headerGetEntryMinMemory(h, RPMTAG_FILELINKTOS, NULL,
+ (void **) &otherLinks, NULL);
+ headerGetEntryMinMemory(h, RPMTAG_FILESTATES, NULL,
+ (void **) &otherStates, NULL);
+ headerGetEntryMinMemory(h, RPMTAG_FILEMODES, NULL,
+ (void **) &otherModes, NULL);
+ headerGetEntryMinMemory(h, RPMTAG_FILEFLAGS, NULL,
+ (void **) &otherFlags, NULL);
+ headerGetEntryMinMemory(h, RPMTAG_FILESIZES, NULL,
+ (void **) &otherSizes, NULL);
- probs->probs[probs->numProblems++].ignoreProblem = 0;
-}
-
-static int archOkay(Header h) {
- int_8 * pkgArchNum;
- void * pkgArch;
- int type, count, archNum;
-
- /* make sure we're trying to install this on the proper architecture */
- headerGetEntry(h, RPMTAG_ARCH, &type, (void **) &pkgArch, &count);
- if (type == RPM_INT8_TYPE) {
- /* old arch handling */
- rpmGetArchInfo(NULL, &archNum);
- pkgArchNum = pkgArch;
- if (archNum != *pkgArchNum) {
- return 0;
- }
- } else {
- /* new arch handling */
- if (!rpmMachineScore(RPM_MACHTABLE_INSTARCH, pkgArch)) {
- return 0;
- }
- }
+ fi->replaced = malloc(sizeof(*fi->replaced) * sharedCount);
- return 1;
-}
+ for (i = 0; i < sharedCount; i++, shared++) {
+ otherFileNum = shared->otherFileNum;
+ fileNum = shared->pkgFileNum;
+ if (otherStates[otherFileNum] == RPMFILE_STATE_NORMAL) {
+ if (filecmp(otherModes[otherFileNum],
+ otherMd5s[otherFileNum],
+ otherLinks[otherFileNum],
+ fi->fmodes[fileNum],
+ fi->fmd5s[fileNum],
+ fi->flinks[fileNum])) {
+ if (reportConflicts)
+ psAppend(probs, RPMPROB_FILE_CONFLICT, fi->ap->key,
+ fi->ap->h, fi->fl[fileNum], h,0 );
+ if (!(otherFlags[otherFileNum] | fi->fflags[fileNum])
+ & RPMFILE_CONFIG) {
+ if (!shared->isRemoved)
+ fi->replaced[numReplaced++] = *shared;
+ }
+ }
-static int osOkay(Header h) {
- void * pkgOs;
- int type, count;
+ if ((otherFlags[otherFileNum] | fi->fflags[fileNum])
+ & RPMFILE_CONFIG) {
+ fi->actions[fileNum] = decideFileFate(fi->fl[fileNum],
+ otherModes[otherFileNum],
+ otherMd5s[otherFileNum],
+ otherLinks[otherFileNum],
+ fi->fmodes[fileNum],
+ fi->fmd5s[fileNum],
+ fi->flinks[fileNum],
+ fi->fflags[fileNum],
+ !headerIsEntry(h, RPMTAG_RPMVERSION));
+ }
- /* make sure we're trying to install this on the proper os */
- headerGetEntry(h, RPMTAG_OS, &type, (void **) &pkgOs, &count);
- if (type == RPM_INT8_TYPE) {
- /* v1 packages and v2 packages both used improper OS numbers, so just
- deal with it hope things work */
- return 1;
- } else {
- /* new os handling */
- if (!rpmMachineScore(RPM_MACHTABLE_INSTOS, pkgOs)) {
- return 0;
+ fi->replacedSizes[fileNum] = otherSizes[otherFileNum];
}
}
- return 1;
-}
+ free(otherMd5s);
+ free(otherLinks);
+ headerFree(h);
-void rpmProblemSetFree(rpmProblemSet probs) {
- int i;
+ fi->replaced = realloc(fi->replaced,
+ sizeof(*fi->replaced) * (numReplaced + 1));
+ fi->replaced[numReplaced].otherPkg = 0;
- for (i = 0; i < probs->numProblems; i++) {
- headerFree(probs->probs[i].h);
- if (probs->probs[i].str1) free(probs->probs[i].str1);
- if (probs->probs[i].altH) headerFree(probs->probs[i].altH);
- }
- free(probs);
+ return 0;
}
-static Header relocateFileList(struct availablePackage * alp,
- rpmProblemSet probs, Header origH,
- enum fileActions * actions,
- int allowBadRelocate) {
- int numValid, numRelocations;
- int i, j, madeSwap, rc;
- rpmRelocation * nextReloc, * relocations = NULL;
- rpmRelocation * rawRelocations = alp->relocs;
- rpmRelocation tmpReloc;
- char ** validRelocations, ** actualRelocations;
- char ** names;
- char ** origNames;
- int len = 0;
- char * newName;
- int_32 fileCount;
+static int handleRmvdInstalledFiles(struct fileInfo * fi, rpmdb db,
+ struct sharedFileInfo * shared,
+ int sharedCount)
+{
Header h;
- int relocated = 0;
-
- if (!headerGetEntry(origH, RPMTAG_PREFIXES, NULL,
- (void **) &validRelocations, &numValid))
- numValid = 0;
+ int otherFileNum;
+ int fileNum;
+ char * otherStates;
+ int i;
+
+ if (!(h = rpmdbGetRecord(db, shared->otherPkg)))
+ return 1;
- if (!rawRelocations && !numValid) return headerLink(origH);
+ headerGetEntryMinMemory(h, RPMTAG_FILESTATES, NULL,
+ (void **) &otherStates, NULL);
- h = headerCopy(origH);
+ for (i = 0; i < sharedCount; i++, shared++) {
+ otherFileNum = shared->otherFileNum;
+ fileNum = shared->pkgFileNum;
- if (rawRelocations) {
- for (i = 0; rawRelocations[i].newPath || rawRelocations[i].oldPath;
- i++) ;
- numRelocations = i;
- } else {
- numRelocations = 0;
+ if (otherStates[otherFileNum] == RPMFILE_STATE_NORMAL)
+ fi->actions[fileNum] = FA_SKIP;
}
- relocations = alloca(sizeof(*relocations) * numRelocations);
- for (i = 0; i < numRelocations; i++) {
- /* FIXME: default relocations (oldPath == NULL) need to be handled
- in the UI, not rpmlib */
+ headerFree(h);
- relocations[i].oldPath =
- alloca(strlen(rawRelocations[i].oldPath) + 1);
- strcpy(relocations[i].oldPath, rawRelocations[i].oldPath);
- stripTrailingSlashes(relocations[i].oldPath);
+ return 0;
+}
- if (rawRelocations[i].newPath) {
- relocations[i].newPath =
- alloca(strlen(rawRelocations[i].newPath) + 1);
- strcpy(relocations[i].newPath, rawRelocations[i].newPath);
- stripTrailingSlashes(relocations[i].newPath);
- } else {
- relocations[i].newPath = NULL;
- }
+static void handleOverlappedFiles(struct fileInfo * fi, hashTable ht,
+ rpmProblemSet probs, struct diskspaceInfo * dsl)
+{
+ int i, j;
+ struct fileInfo ** recs;
+ int numRecs;
+ int otherPkgNum, otherFileNum;
+ struct stat sb;
+ char mdsum[50];
+ int rc;
+ struct diskspaceInfo * ds = NULL;
+ uint_32 fixupSize = 0;
+
+ for (i = 0; i < fi->fc; i++) {
+ if (fi->actions[i] == FA_SKIP || fi->actions[i] == FA_SKIPNSTATE)
+ continue;
- if (relocations[i].newPath) {
- for (j = 0; j < numValid; j++)
- if (!strcmp(validRelocations[j],
- relocations[i].oldPath)) break;
- if (j == numValid && !allowBadRelocate)
- psAppend(probs, RPMPROB_BADRELOCATE, alp->key, alp->h,
- relocations[i].oldPath, NULL,0 );
- }
- }
+ if (dsl) {
+ ds = dsl;
+ while (ds->block && ds->dev != fi->fps[i].dev) ds++;
+ if (!ds->block) ds = NULL;
+ fixupSize = 0;
+ }
- /* stupid bubble sort, but it's probably faster here */
- for (i = 0; i < numRelocations; i++) {
- madeSwap = 0;
- for (j = 1; j < numRelocations; j++) {
- if (strcmp(relocations[j - 1].oldPath,
- relocations[j].oldPath) > 0) {
- tmpReloc = relocations[j - 1];
- relocations[j - 1] = relocations[j];
- relocations[j] = tmpReloc;
- madeSwap = 1;
- }
- }
- if (!madeSwap) break;
- }
+ htGetEntry(ht, &fi->fps[i], (void ***) &recs, &numRecs, NULL);
- if (numValid) {
- actualRelocations = malloc(sizeof(*actualRelocations) * numValid);
- for (i = 0; i < numValid; i++) {
- for (j = 0; j < numRelocations; j++) {
- if (!strcmp(validRelocations[i], relocations[j].oldPath)) {
- actualRelocations[i] = relocations[j].newPath;
+ /* 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. */
+ for (j = 0; recs[j] != fi; j++);
+
+ otherPkgNum = j - 1;
+ otherFileNum = -1; /* keep gcc quiet */
+ while (otherPkgNum >= 0) {
+ if (recs[otherPkgNum]->type == TR_ADDED) {
+ /* TESTME: there are more efficient searches in the world... */
+ for (otherFileNum = 0; otherFileNum < recs[otherPkgNum]->fc;
+ otherFileNum++)
+ if (FP_EQUAL(fi->fps[i],
+ recs[otherPkgNum]->fps[otherFileNum]))
+ break;
+ if ((otherFileNum >= 0) &&
+ (recs[otherPkgNum]->actions[otherFileNum] != FA_UNKNOWN))
break;
- }
}
-
- if (j == numRelocations)
- actualRelocations[i] = validRelocations[i];
+ otherPkgNum--;
}
- headerAddEntry(h, RPMTAG_INSTPREFIXES, RPM_STRING_ARRAY_TYPE,
- (void **) actualRelocations, numValid);
-
- free(actualRelocations);
- free(validRelocations);
- }
+ if (fi->type == TR_ADDED && otherPkgNum < 0) {
+ if (fi->actions[i] == FA_UNKNOWN) {
+ if ((fi->fflags[i] & RPMFILE_CONFIG) &&
+ !lstat(fi->fl[i], &sb)) {
+ fi->actions[i] = (fi->fflags[i] & RPMFILE_NOREPLACE)
+ ? FA_ALTNAME : FA_BACKUP;
+ } else {
+ fi->actions[i] = FA_CREATE;
+ }
+ }
+ } else if (fi->type == TR_ADDED) {
+ if (probs && filecmp(recs[otherPkgNum]->fmodes[otherFileNum],
+ recs[otherPkgNum]->fmd5s[otherFileNum],
+ recs[otherPkgNum]->flinks[otherFileNum],
+ fi->fmodes[i],
+ fi->fmd5s[i],
+ fi->flinks[i])) {
+ psAppend(probs, RPMPROB_NEW_FILE_CONFLICT, fi->ap->key,
+ fi->ap->h, fi->fl[i], recs[otherPkgNum]->ap->h, 0);
+ }
- headerGetEntry(h, RPMTAG_FILENAMES, NULL, (void **) &names,
- &fileCount);
+ fixupSize = recs[otherPkgNum]->fsizes[otherFileNum];
- /* go through things backwards so that /usr/local relocations take
- precedence over /usr ones */
- for (i = fileCount - 1; i >= 0; i--) {
- for (j = numRelocations - 1; j >= 0; j--) {
- nextReloc = relocations + j;
- len = strlen(relocations[j].oldPath);
- rc = (!strncmp(relocations[j].oldPath, names[i], len) &&
- ((names[i][len] == '/') || !names[i][len]));
- if (rc) break;
- }
-
- if (j >= 0) {
- nextReloc = relocations + j;
- if (nextReloc->newPath) {
- newName = alloca(strlen(nextReloc->newPath) +
- strlen(names[i]) + 1);
- strcpy(newName, nextReloc->newPath);
- strcat(newName, names[i] + len);
- rpmMessage(RPMMESS_DEBUG, _("relocating %s to %s\n"),
- names[i], newName);
- names[i] = newName;
- relocated = 1;
- } else if (actions) {
- actions[i] = FA_SKIPNSTATE;
- rpmMessage(RPMMESS_DEBUG, _("excluding %s\n"), names[i]);
+ /* 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?? */
+ fi->actions[i] = FA_CREATE;
+ } else if (fi->type == TR_REMOVED && otherPkgNum >= 0) {
+ fi->actions[i] = FA_SKIP;
+ } else if (fi->type == TR_REMOVED) {
+ if (fi->actions[i] != FA_SKIP && fi->actions[i] != FA_SKIPNSTATE &&
+ fi->fstates[i] == RPMFILE_STATE_NORMAL ) {
+ if (S_ISREG(fi->fmodes[i]) &&
+ (fi->fflags[i] & RPMFILE_CONFIG)) {
+ rc = mdfile(fi->fl[i], mdsum);
+ if (!rc && strcmp(fi->fmd5s[i], mdsum)) {
+ fi->actions[i] = FA_BACKUP;
+ } else {
+ /* FIXME: config files may need to be saved */
+ fi->actions[i] = FA_REMOVE;
+ }
+ } else {
+ fi->actions[i] = FA_REMOVE;
+ }
}
- }
- }
-
- if (relocated) {
- headerGetEntry(h, RPMTAG_FILENAMES, NULL, (void **) &origNames, NULL);
- headerAddEntry(h, RPMTAG_ORIGFILENAMES, RPM_STRING_ARRAY_TYPE,
- origNames, fileCount);
- free(origNames);
- headerModifyEntry(h, RPMTAG_FILENAMES, RPM_STRING_ARRAY_TYPE,
- names, fileCount);
- }
+ }
- free(names);
+ if (ds) {
+ uint_32 s = BLOCK_ROUND(fi->fsizes[i], ds->block);
- return h;
-}
+ switch (fi->actions[i]) {
+ case FA_BACKUP:
+ case FA_SAVE:
+ case FA_ALTNAME:
+ ds->needed += s;
+ break;
-static int psTrim(rpmProblemSet filter, rpmProblemSet target) {
- /* As the problem sets are generated in an order solely dependent
- on the ordering of the packages in the transaction, and that
- ordering can't be changed, the problem sets must be parallel to
- on another. Additionally, the filter set must be a subset of the
- target set, given the operations available on transaction set.
- This is good, as it lets us perform this trim in linear time, rather
- then logarithmic or quadratic. */
- rpmProblem * f, * t;
- int gotProblems = 0;
+ /* FIXME: If a two packages share a file (same md5sum), and
+ that file is being replaced on disk, will ds->needed get
+ decremented twice? Quite probably! */
+ case FA_CREATE:
+ ds->needed += s;
+ ds->needed -= BLOCK_ROUND(fi->replacedSizes[i], ds->block);
+ break;
- f = filter->probs;
- t = target->probs;
+ case FA_REMOVE:
+ ds->needed -= s;
+ break;
- while ((f - filter->probs) < filter->numProblems) {
- if (!f->ignoreProblem) {
- f++;
- continue;
- }
- while ((t - target->probs) < target->numProblems) {
- if (f->h == t->h && f->type == t->type && t->key == f->key &&
- XSTRCMP(f->str1, t->str1))
+ default:
break;
- t++;
- gotProblems = 1;
- }
+ }
- if ((t - target->probs) == target->numProblems) {
- /* this can't happen ;-) lets be sane if it doesn though */
- break;
+ ds->needed -= BLOCK_ROUND(fixupSize, ds->block);
}
-
- t->ignoreProblem = f->ignoreProblem;
- t++, f++;
}
+}
- if ((t - target->probs) < target->numProblems)
- gotProblems = 1;
+static int ensureOlder(rpmdb db, Header new, int dbOffset, rpmProblemSet probs,
+ const void * key)
+{
+ Header old;
+ int result, rc = 0;
- return gotProblems;
-}
+ old = rpmdbGetRecord(db, dbOffset);
+ if (old == NULL) return 1;
-static int sharedCmp(const void * one, const void * two) {
- const struct sharedFileInfo * a = one;
- const struct sharedFileInfo * b = two;
+ result = rpmVersionCompare(old, new);
+ if (result <= 0)
+ rc = 0;
+ else if (result > 0) {
+ rc = 1;
+ psAppend(probs, RPMPROB_OLDPACKAGE, key, new, NULL, old, 0);
+ }
- if (a->otherPkg < b->otherPkg)
- return -1;
- else if (a->otherPkg > b->otherPkg)
- return 1;
+ headerFree(old);
- return 0;
+ return rc;
}
-static enum fileActions decideFileFate(const char * filespec, short dbMode,
- char * dbMd5, char * dbLink, short newMode,
- char * newMd5, char * newLink, int newFlags,
- int brokenMd5) {
- char buffer[1024];
- char * dbAttr, * newAttr;
- enum fileTypes dbWhat, newWhat, diskWhat;
- struct stat sb;
- int i, rc;
- int save = (newFlags & RPMFILE_NOREPLACE) ? FA_ALTNAME : FA_SAVE;
+static void skipFiles(struct fileInfo * fi, int noDocs)
+{
+ int i, j;
+ char ** netsharedPaths = NULL, ** nsp;
+ char ** fileLangs, ** languages, ** lang;
+ char * oneLang[2] = { NULL, NULL };
+ int freeLanguages = 0;
+ char * chptr;
- if (lstat(filespec, &sb)) {
- /* the file doesn't exist on the disk create it unless the new
- package has marked it as missingok */
- if (newFlags & RPMFILE_MISSINGOK) {
- rpmMessage(RPMMESS_DEBUG, _("%s skipped due to missingok flag\n"),
- filespec);
- return FA_SKIP;
- } else
- return FA_CREATE;
- }
+ if (!noDocs)
+ noDocs = rpmExpandNumeric("%{_excludedocs}");
- diskWhat = whatis(sb.st_mode);
- dbWhat = whatis(dbMode);
- newWhat = whatis(newMode);
+ { const char *tmpPath = rpmExpand("%{_netsharedpath}", NULL);
+ if (tmpPath && *tmpPath != '%')
+ netsharedPaths = splitString(tmpPath, strlen(tmpPath), ':');
+ xfree(tmpPath);
+ }
- /* RPM >= 2.3.10 shouldn't create config directories -- we'll ignore
- them in older packages as well */
- if (newWhat == XDIR)
- return FA_CREATE;
+ if (!headerGetEntry(fi->h, RPMTAG_FILELANGS, NULL, (void **) &fileLangs,
+ NULL))
+ fileLangs = NULL;
- if (diskWhat != newWhat) {
- return save;
- } else if (newWhat != dbWhat && diskWhat != dbWhat) {
- return save;
- } else if (dbWhat != newWhat) {
- return FA_CREATE;
- } else if (dbWhat != LINK && dbWhat != REG) {
- return FA_CREATE;
+ if ((chptr = getenv("LINGUAS"))) {
+ languages = splitString(chptr, strlen(chptr), ':');
+ freeLanguages = 1;
+ } else if ((oneLang[0] = getenv("LANG"))) {
+ languages = oneLang;
+ } else {
+ oneLang[0] = "en";
+ languages = oneLang;
}
- if (dbWhat == REG) {
- if (brokenMd5)
- rc = mdfileBroken(filespec, buffer);
- else
- rc = mdfile(filespec, buffer);
+ for (i = 0; i < fi->fc; i++) {
+ if (fi->actions[i] == FA_SKIP || fi->actions[i] == FA_SKIPNSTATE)
+ continue;
- if (rc) {
- /* assume the file has been removed, don't freak */
- return FA_CREATE;
+ /* netsharedPaths are not relative to the current root (though
+ they do need to take package relocations into account) */
+ for (nsp = netsharedPaths; nsp && *nsp; nsp++) {
+ j = strlen(*nsp);
+ if (!strncmp(fi->fl[i], *nsp, j) &&
+ (fi->fl[i][j] == '\0' ||
+ fi->fl[i][j] == '/'))
+ break;
}
- dbAttr = dbMd5;
- newAttr = newMd5;
- } else /* dbWhat == LINK */ {
- memset(buffer, 0, sizeof(buffer));
- i = readlink(filespec, buffer, sizeof(buffer) - 1);
- if (i == -1) {
- /* assume the file has been removed, don't freak */
- return FA_CREATE;
+
+ if (nsp && *nsp) {
+ fi->actions[i] = FA_SKIPNSTATE;
+ continue;
}
- dbAttr = dbLink;
- newAttr = newLink;
- }
- /* this order matters - we'd prefer to CREATE the file if at all
- possible in case something else (like the timestamp) has changed */
+ if (fileLangs && languages && *fileLangs[i]) {
+ for (lang = languages; *lang; lang++) {
+ const char *l, *le;
+ for (l = fileLangs[i]; *l; l = le) {
+ for (le = l; *le && *le != '|'; le++)
+ ;
+ if ((le-l) > 0 && !strncmp(*lang, l, (le-l)))
+ goto lingo;
+ if (*le == '|') le++; /* skip over | */
+ }
+ }
+ lingo:
+ if (!*lang) {
+ fi->actions[i] = FA_SKIPNSTATE;
+ continue;
+ }
+ }
- if (!strcmp(dbAttr, buffer)) {
- /* this config file has never been modified, so
- just replace it */
- return FA_CREATE;
+ if (noDocs && (fi->fflags[i] & RPMFILE_DOC))
+ fi->actions[i] = FA_SKIPNSTATE;
}
- if (!strcmp(dbAttr, newAttr)) {
- /* this file is the same in all versions of this package */
- return FA_SKIP;
- }
+ if (netsharedPaths) freeSplitString(netsharedPaths);
+ if (fileLangs) free(fileLangs);
+ if (freeLanguages) freeSplitString(languages);
+}
- /* the config file on the disk has been modified, but
- the ones in the two packages are different. It would
- be nice if RPM was smart enough to at least try and
- merge the difference ala CVS, but... */
-
- return save;
-}
+#define NOTIFY(_x) if (notify) notify _x
-enum fileTypes whatis(short mode) {
- enum fileTypes result;
+/* Return -1 on error, > 0 if newProbs is set, 0 if everything happened */
- if (S_ISDIR(mode))
- result = XDIR;
- else if (S_ISCHR(mode))
- result = CDEV;
- else if (S_ISBLK(mode))
- result = BDEV;
- else if (S_ISLNK(mode))
- result = LINK;
- else if (S_ISSOCK(mode))
- result = SOCK;
- else if (S_ISFIFO(mode))
- result = PIPE;
- else
- result = REG;
-
- return result;
-}
+int rpmRunTransactions(rpmTransactionSet ts, rpmCallbackFunction notify,
+ void * notifyData, rpmProblemSet okProbs,
+ rpmProblemSet * newProbs, int flags, int ignoreSet)
+{
+ int i, j;
+ int rc, ourrc = 0;
+ struct availablePackage * alp;
+ rpmProblemSet probs;
+ dbiIndexSet dbi, * matches;
+ Header * hdrs;
+ int fileCount;
+ int totalFileCount = 0;
+ hashTable ht;
+ struct fileInfo * flList, * fi;
+ struct sharedFileInfo * shared, * sharedList;
+ int numShared;
+ int flEntries;
+ int last;
+ int lastFailed;
+ int beingRemoved;
+ char * currDir, * chptr;
+ FD_t fd;
+ const char ** filesystems;
+ int filesystemCount;
+ struct diskspaceInfo * di = NULL;
+ int oc;
-static int filecmp(short mode1, char * md51, char * link1,
- short mode2, char * md52, char * link2) {
- enum fileTypes what1, what2;
+ /* FIXME: what if the same package is included in ts twice? */
- what1 = whatis(mode1);
- what2 = whatis(mode2);
+ if (!(ignoreSet & RPMPROB_FILTER_DISKSPACE) &&
+ !rpmGetFilesystemList(&filesystems, &filesystemCount)) {
+ struct stat sb;
- if (what1 != what2) return 1;
+ di = alloca(sizeof(*di) * (filesystemCount + 1));
- if (what1 == LINK)
- return strcmp(link1, link2);
- else if (what1 == REG)
- return strcmp(md51, md52);
+ for (i = 0; (i < filesystemCount) && di; i++) {
+#if STATFS_IN_SYS_STATVFS
+ struct statvfs sfb;
+ if (statvfs(filesystems[i], &sfb))
+#else
+ struct statfs sfb;
+# if STAT_STATFS4
+/* this platform has the 4-argument version of the statfs call. The last two
+ * should be the size of struct statfs and 0, respectively. The 0 is the
+ * filesystem type, and is always 0 when statfs is called on a mounted
+ * filesystem, as we're doing.
+ */
+ if (statfs(filesystems[i], &sfb, sizeof(sfb), 0))
+# else
+ if (statfs(filesystems[i], &sfb))
+# endif
+#endif
+ {
+ di = NULL;
+ } else {
+ di[i].block = sfb.f_bsize;
+ di[i].needed = 0;
+#ifdef STATFS_HAS_F_BAVAIL
+ di[i].avail = sfb.f_bavail;
+#else
+/* FIXME: the statfs struct doesn't have a member to tell how many blocks are
+ * available for non-superusers. f_blocks - f_bfree is probably too big, but
+ * it's about all we can do.
+ */
+ di[i].avail = sfb.f_blocks - sfb.f_bfree;
+#endif
- return 0;
-}
-static int handleInstInstalledFiles(struct fileInfo * fi, rpmdb db,
- struct sharedFileInfo * shared,
- int sharedCount, int reportConflicts,
- rpmProblemSet probs) {
- Header h;
- int i;
- char ** otherMd5s, ** otherLinks;
- char * otherStates;
- uint_32 * otherFlags, * otherSizes;
- uint_16 * otherModes;
- int otherFileNum;
- int fileNum;
- int numReplaced = 0;
+ stat(filesystems[i], &sb);
+ di[i].dev = sb.st_dev;
+ }
+ }
- if (!(h = rpmdbGetRecord(db, shared->otherPkg)))
- return 1;
+ if (di) di[i].block = 0;
+ }
- headerGetEntryMinMemory(h, RPMTAG_FILEMD5S, NULL,
- (void **) &otherMd5s, NULL);
- headerGetEntryMinMemory(h, RPMTAG_FILELINKTOS, NULL,
- (void **) &otherLinks, NULL);
- headerGetEntryMinMemory(h, RPMTAG_FILESTATES, NULL,
- (void **) &otherStates, NULL);
- headerGetEntryMinMemory(h, RPMTAG_FILEMODES, NULL,
- (void **) &otherModes, NULL);
- headerGetEntryMinMemory(h, RPMTAG_FILEFLAGS, NULL,
- (void **) &otherFlags, NULL);
- headerGetEntryMinMemory(h, RPMTAG_FILESIZES, NULL,
- (void **) &otherSizes, NULL);
+ probs = psCreate();
+ *newProbs = probs;
+ hdrs = alloca(sizeof(*hdrs) * ts->addedPackages.size);
- fi->replaced = malloc(sizeof(*fi->replaced) * sharedCount);
+ /* The ordering doesn't matter here */
+ for (alp = ts->addedPackages.list; (alp - ts->addedPackages.list) <
+ ts->addedPackages.size; alp++) {
+ if (!archOkay(alp->h) && !(ignoreSet & RPMPROB_FILTER_IGNOREARCH))
+ psAppend(probs, RPMPROB_BADARCH, alp->key, alp->h, NULL, NULL, 0);
- for (i = 0; i < sharedCount; i++, shared++) {
- otherFileNum = shared->otherFileNum;
- fileNum = shared->pkgFileNum;
- if (otherStates[otherFileNum] == RPMFILE_STATE_NORMAL) {
- if (filecmp(otherModes[otherFileNum],
- otherMd5s[otherFileNum],
- otherLinks[otherFileNum],
- fi->fmodes[fileNum],
- fi->fmd5s[fileNum],
- fi->flinks[fileNum])) {
- if (reportConflicts)
- psAppend(probs, RPMPROB_FILE_CONFLICT, fi->ap->key,
- fi->ap->h, fi->fl[fileNum], h,0 );
- if (!(otherFlags[otherFileNum] | fi->fflags[fileNum])
- & RPMFILE_CONFIG) {
- if (!shared->isRemoved)
- fi->replaced[numReplaced++] = *shared;
- }
- }
+ if (!osOkay(alp->h) && !(ignoreSet & RPMPROB_FILTER_IGNOREOS)) {
+ psAppend(probs, RPMPROB_BADOS, alp->key, alp->h, NULL, NULL, 0);
+ }
- if ((otherFlags[otherFileNum] | fi->fflags[fileNum])
- & RPMFILE_CONFIG) {
- fi->actions[fileNum] = decideFileFate(fi->fl[fileNum],
- otherModes[otherFileNum],
- otherMd5s[otherFileNum],
- otherLinks[otherFileNum],
- fi->fmodes[fileNum],
- fi->fmd5s[fileNum],
- fi->flinks[fileNum],
- fi->fflags[fileNum],
- !headerIsEntry(h, RPMTAG_RPMVERSION));
+ if (!(ignoreSet & RPMPROB_FILTER_OLDPACKAGE)) {
+ rc = rpmdbFindPackage(ts->db, alp->name, &dbi);
+ if (rc == 2) {
+ return -1;
+ } else if (!rc) {
+ for (i = 0; i < dbi.count; i++)
+ ensureOlder(ts->db, alp->h, dbi.recs[i].recOffset,
+ probs, alp->key);
+
+ dbiFreeIndexRecord(dbi);
}
+ }
- fi->replacedSizes[fileNum] = otherSizes[otherFileNum];
+ rc = findMatches(ts->db, alp->name, alp->version, alp->release, &dbi);
+ if (rc == 2) {
+ return -1;
+ } else if (!rc) {
+ if (!(ignoreSet & RPMPROB_FILTER_REPLACEPKG))
+ psAppend(probs, RPMPROB_PKG_INSTALLED, alp->key, alp->h, NULL,
+ NULL, 0);
+ dbiFreeIndexRecord(dbi);
}
- }
- free(otherMd5s);
- free(otherLinks);
- headerFree(h);
+ if (headerGetEntry(alp->h, RPMTAG_FILENAMES, NULL, NULL, &fileCount))
+ totalFileCount += fileCount;
+ }
- fi->replaced = realloc(fi->replaced,
- sizeof(*fi->replaced) * (numReplaced + 1));
- fi->replaced[numReplaced].otherPkg = 0;
+ /* FIXME: it seems a bit silly to read in all of these headers twice */
+ /* The ordering doesn't matter here */
+ for (i = 0; i < ts->numRemovedPackages; i++) {
+ Header h;
- return 0;
-}
+ if ((h = rpmdbGetRecord(ts->db, ts->removedPackages[i]))) {
+ if (headerGetEntry(h, RPMTAG_FILENAMES, NULL, NULL,
+ &fileCount))
+ totalFileCount += fileCount;
+ headerFree(h); /* XXX ==> LEAK */
+ }
+ }
-static int handleRmvdInstalledFiles(struct fileInfo * fi, rpmdb db,
- struct sharedFileInfo * shared,
- int sharedCount) {
- Header h;
- int otherFileNum;
- int fileNum;
- char * otherStates;
- int i;
-
- if (!(h = rpmdbGetRecord(db, shared->otherPkg)))
- return 1;
+ flEntries = ts->addedPackages.size + ts->numRemovedPackages;
+ flList = alloca(sizeof(*flList) * (flEntries));
- headerGetEntryMinMemory(h, RPMTAG_FILESTATES, NULL,
- (void **) &otherStates, NULL);
+ ht = htCreate(totalFileCount * 2, 0, fpHashFunction, fpEqual);
- for (i = 0; i < sharedCount; i++, shared++) {
- otherFileNum = shared->otherFileNum;
- fileNum = shared->pkgFileNum;
+ /* FIXME?: we'd be better off assembling one very large file list and
+ calling fpLookupList only once. I'm not sure that the speedup is
+ worth the trouble though. */
+ for (fi = flList, oc = 0; oc < ts->orderCount; fi++, oc++) {
+ memset(fi, 0, sizeof(*fi));
- if (otherStates[otherFileNum] == RPMFILE_STATE_NORMAL)
- fi->actions[fileNum] = FA_SKIP;
- }
+ if (ts->order[oc].type == TR_ADDED) {
+ i = ts->order[oc].u.addedIndex;
+ alp = ts->addedPackages.list + ts->order[oc].u.addedIndex;
- headerFree(h);
+ if (!headerGetEntryMinMemory(alp->h, RPMTAG_FILENAMES, NULL,
+ NULL, &fi->fc)) {
+ fi->h = headerLink(alp->h);
+ hdrs[i] = headerLink(fi->h);
+ continue;
+ }
- return 0;
-}
+ fi->actions = calloc(sizeof(*fi->actions), fi->fc);
+ hdrs[i] = relocateFileList(alp, probs, alp->h, fi->actions,
+ ignoreSet & RPMPROB_FILTER_FORCERELOCATE);
+ fi->h = headerLink(hdrs[i]);
+ fi->type = TR_ADDED;
+ fi->ap = alp;
+ } else {
+ fi->record = ts->order[oc].u.removed.dboffset;
+ fi->h = rpmdbGetRecord(ts->db, fi->record);
+ if (!fi->h) {
+ /* ACK! */
+ continue;
+ }
+ fi->type = TR_REMOVED;
+ }
-void handleOverlappedFiles(struct fileInfo * fi, hashTable ht,
- rpmProblemSet probs, struct diskspaceInfo * dsl) {
- int i, j;
- struct fileInfo ** recs;
- int numRecs;
- int otherPkgNum, otherFileNum;
- struct stat sb;
- char mdsum[50];
- int rc;
- struct diskspaceInfo * ds = NULL;
- uint_32 fixupSize = 0;
-
- for (i = 0; i < fi->fc; i++) {
- if (fi->actions[i] == FA_SKIP || fi->actions[i] == FA_SKIPNSTATE)
+ if (!headerGetEntry(fi->h, RPMTAG_FILENAMES, NULL,
+ (void **) &fi->fl, &fi->fc)) {
+ /* This catches removed packages w/ no file lists */
+ fi->fc = 0;
continue;
+ }
- if (dsl) {
- ds = dsl;
- while (ds->block && ds->dev != fi->fps[i].dev) ds++;
- if (!ds->block) ds = NULL;
- fixupSize = 0;
- }
+ /* actions is initialized earlier for added packages */
+ if (!fi->actions)
+ fi->actions = calloc(sizeof(*fi->actions), fi->fc);
- htGetEntry(ht, &fi->fps[i], (void ***) &recs, &numRecs, NULL);
+ headerGetEntry(fi->h, RPMTAG_FILEMODES, NULL,
+ (void **) &fi->fmodes, NULL);
+ headerGetEntry(fi->h, RPMTAG_FILEFLAGS, NULL,
+ (void **) &fi->fflags, NULL);
+ headerGetEntry(fi->h, RPMTAG_FILESIZES, NULL,
+ (void **) &fi->fsizes, NULL);
+ headerGetEntry(fi->h, RPMTAG_FILESTATES, NULL,
+ (void **) &fi->fstates, 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. */
- for (j = 0; recs[j] != fi; j++);
+ if (ts->order[oc].type == TR_REMOVED) {
+ headerGetEntry(fi->h, RPMTAG_FILEMD5S, NULL,
+ (void **) &fi->fmd5s, NULL);
+ headerGetEntry(fi->h, RPMTAG_FILELINKTOS, NULL,
+ (void **) &fi->flinks, NULL);
+ fi->fsizes = memcpy(malloc(fi->fc * sizeof(*fi->fsizes)),
+ fi->fsizes, fi->fc * sizeof(*fi->fsizes));
+ fi->fflags = memcpy(malloc(fi->fc * sizeof(*fi->fflags)),
+ fi->fflags, fi->fc * sizeof(*fi->fflags));
+ fi->fmodes = memcpy(malloc(fi->fc * sizeof(*fi->fmodes)),
+ fi->fmodes, fi->fc * sizeof(*fi->fmodes));
+ fi->fstates = memcpy(malloc(fi->fc * sizeof(*fi->fstates)),
+ fi->fstates, fi->fc * sizeof(*fi->fstates));
+ headerFree(fi->h);
+ fi->h = NULL;
+ } else {
+ /* ADDED package */
- otherPkgNum = j - 1;
- otherFileNum = -1; /* keep gcc quiet */
- while (otherPkgNum >= 0) {
- if (recs[otherPkgNum]->type == TR_ADDED) {
- /* TESTME: there are more efficient searches in the world... */
- for (otherFileNum = 0; otherFileNum < recs[otherPkgNum]->fc;
- otherFileNum++)
- if (FP_EQUAL(fi->fps[i],
- recs[otherPkgNum]->fps[otherFileNum]))
- break;
- if ((otherFileNum >= 0) &&
- (recs[otherPkgNum]->actions[otherFileNum] != FA_UNKNOWN))
- break;
- }
- otherPkgNum--;
+ headerGetEntryMinMemory(fi->h, RPMTAG_FILEMD5S, NULL,
+ (void **) &fi->fmd5s, NULL);
+ headerGetEntryMinMemory(fi->h, RPMTAG_FILELINKTOS, NULL,
+ (void **) &fi->flinks, NULL);
+
+ /* 0 makes for noops */
+ fi->replacedSizes = calloc(fi->fc, sizeof(*fi->replacedSizes));
+ skipFiles(fi, flags & RPMTRANS_FLAG_NODOCS);
}
- if (fi->type == TR_ADDED && otherPkgNum < 0) {
- if (fi->actions[i] == FA_UNKNOWN) {
- if ((fi->fflags[i] & RPMFILE_CONFIG) &&
- !lstat(fi->fl[i], &sb)) {
- fi->actions[i] = (fi->fflags[i] & RPMFILE_NOREPLACE)
- ? FA_ALTNAME : FA_BACKUP;
- } else {
- fi->actions[i] = FA_CREATE;
- }
- }
- } else if (fi->type == TR_ADDED) {
- if (probs && filecmp(recs[otherPkgNum]->fmodes[otherFileNum],
- recs[otherPkgNum]->fmd5s[otherFileNum],
- recs[otherPkgNum]->flinks[otherFileNum],
- fi->fmodes[i],
- fi->fmd5s[i],
- fi->flinks[i])) {
- psAppend(probs, RPMPROB_NEW_FILE_CONFLICT, fi->ap->key,
- fi->ap->h, fi->fl[i], recs[otherPkgNum]->ap->h, 0);
- }
+ fi->fps = malloc(fi->fc * sizeof(*fi->fps));
+ }
- fixupSize = recs[otherPkgNum]->fsizes[otherFileNum];
+ chptr = currentDirectory();
+ currDir = alloca(strlen(chptr) + 1);
+ strcpy(currDir, chptr);
+ free(chptr);
+ chdir("/");
+ chroot(ts->root);
+
+ for (fi = flList; (fi - flList) < flEntries; fi++) {
+ fpLookupList(fi->fl, fi->fps, fi->fc, 1);
+ for (i = 0; i < fi->fc; i++) {
+ if (fi->actions[i] != FA_SKIP && fi->actions[i] != FA_SKIPNSTATE)
+ htAddEntry(ht, fi->fps + i, fi);
+ }
+ }
+
+ NOTIFY((NULL, RPMCALLBACK_TRANS_START, 6, flEntries, NULL, notifyData));
+
+ for (fi = flList; (fi - flList) < flEntries; fi++) {
+ int k, ro;
+ int knownBad;
+
+ NOTIFY((NULL, RPMCALLBACK_TRANS_PROGRESS, (fi - flList), flEntries,
+ NULL, notifyData));
+
+ matches = malloc(sizeof(*matches) * fi->fc);
+ if (rpmdbFindFpList(ts->db, fi->fps, matches, fi->fc)) return 1;
+
+ numShared = 0;
+ for (i = 0; i < fi->fc; i++)
+ numShared += matches[i].count;
- /* 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?? */
- fi->actions[i] = FA_CREATE;
- } else if (fi->type == TR_REMOVED && otherPkgNum >= 0) {
- fi->actions[i] = FA_SKIP;
- } else if (fi->type == TR_REMOVED) {
- if (fi->actions[i] != FA_SKIP && fi->actions[i] != FA_SKIPNSTATE &&
- fi->fstates[i] == RPMFILE_STATE_NORMAL ) {
- if (S_ISREG(fi->fmodes[i]) &&
- (fi->fflags[i] & RPMFILE_CONFIG)) {
- rc = mdfile(fi->fl[i], mdsum);
- if (!rc && strcmp(fi->fmd5s[i], mdsum)) {
- fi->actions[i] = FA_BACKUP;
- } else {
- /* FIXME: config files may need to be saved */
- fi->actions[i] = FA_REMOVE;
+ shared = sharedList = malloc(sizeof(*sharedList) * (numShared + 1));
+ knownBad = 0;
+ for (i = 0; i < fi->fc; i++) {
+ /* Take care not to mark files as replaced in packages that will
+ have been removed before we got here. */
+ for (j = 0; j < matches[i].count; j++) {
+ ro = matches[i].recs[j].recOffset;
+ if (ro != knownBad) {
+ for (k = 0; k < ts->orderCount; k++) {
+ if (ts->order[k].type == TR_REMOVED &&
+ ts->order[k].u.removed.dboffset == ro) break;
+ }
+ if (k < ts->orderCount) {
+ knownBad = ro;
}
- } else {
- fi->actions[i] = FA_REMOVE;
}
+
+ shared->pkgFileNum = i;
+ shared->otherPkg = matches[i].recs[j].recOffset;
+ shared->otherFileNum = matches[i].recs[j].fileNumber;
+ shared->isRemoved = (knownBad == ro);
+ shared++;
}
+ dbiFreeIndexRecord(matches[i]);
}
+ numShared = shared - sharedList;
+ shared->otherPkg = -1;
+ free(matches);
- if (ds) {
- uint_32 s = BLOCK_ROUND(fi->fsizes[i], ds->block);
-
- switch (fi->actions[i]) {
- case FA_BACKUP:
- case FA_SAVE:
- case FA_ALTNAME:
- ds->needed += s;
- break;
-
- /* FIXME: If a two packages share a file (same md5sum), and
- that file is being replaced on disk, will ds->needed get
- decremented twice? Quite probably! */
- case FA_CREATE:
- ds->needed += s;
- ds->needed -= BLOCK_ROUND(fi->replacedSizes[i], ds->block);
- break;
+ qsort(sharedList, numShared, sizeof(*shared), sharedCmp);
- case FA_REMOVE:
- ds->needed -= s;
- break;
+ i = 0;
+ while (i < numShared) {
+ last = i + 1;
+ j = sharedList[i].otherPkg;
+ while ((sharedList[last].otherPkg == j) && (last < numShared))
+ last++;
+ last--;
- default:
- break;
+ for (j = 0; j < ts->numRemovedPackages; j++) {
+ if (ts->removedPackages[j] == sharedList[i].otherPkg)
+ break;
}
+ beingRemoved = (j < ts->numRemovedPackages);
- ds->needed -= BLOCK_ROUND(fixupSize, ds->block);
+ if (fi->type == TR_ADDED)
+ handleInstInstalledFiles(fi, ts->db, sharedList + i,
+ last - i + 1,
+ !(beingRemoved ||
+ (ignoreSet & RPMPROB_FILTER_REPLACEOLDFILES)),
+ probs);
+ else if (fi->type == TR_REMOVED && !beingRemoved)
+ handleRmvdInstalledFiles(fi, ts->db, sharedList + i,
+ last - i + 1);
+
+ i = last + 1;
}
- }
-}
-static int ensureOlder(rpmdb db, Header new, int dbOffset, rpmProblemSet probs,
- const void * key) {
- Header old;
- int result, rc = 0;
+ free(sharedList);
- old = rpmdbGetRecord(db, dbOffset);
- if (old == NULL) return 1;
+ handleOverlappedFiles(fi, ht,
+ (ignoreSet & RPMPROB_FILTER_REPLACENEWFILES) ? NULL : probs, di);
- result = rpmVersionCompare(old, new);
- if (result <= 0)
- rc = 0;
- else if (result > 0) {
- rc = 1;
- psAppend(probs, RPMPROB_OLDPACKAGE, key, new, NULL, old, 0);
+ if (di && fi->type == TR_ADDED && fi->fc) {
+ for (i = 0; i < filesystemCount; i++) {
+ if (adj_fs_blocks(di[i].needed) > di[i].avail) {
+ psAppend(probs, RPMPROB_DISKSPACE, fi->ap->key, fi->ap->h,
+ filesystems[i], NULL,
+ (adj_fs_blocks(di[i].needed) - di[i].avail) *
+ di[i].block);
+ }
+ }
+ }
}
- headerFree(old);
-
- return rc;
-}
+ NOTIFY((NULL, RPMCALLBACK_TRANS_STOP, 6, flEntries, NULL, notifyData));
-static void skipFiles(struct fileInfo * fi, int noDocs) {
- int i, j;
- char ** netsharedPaths = NULL, ** nsp;
- char ** fileLangs, ** languages, ** lang;
- char * oneLang[2] = { NULL, NULL };
- int freeLanguages = 0;
- char * chptr;
+ chroot(".");
+ chdir(currDir);
- if (!noDocs)
- noDocs = rpmExpandNumeric("%{_excludedocs}");
+ htFree(ht);
- { const char *tmpPath = rpmExpand("%{_netsharedpath}", NULL);
- if (tmpPath && *tmpPath != '%')
- netsharedPaths = splitString(tmpPath, strlen(tmpPath), ':');
- xfree(tmpPath);
+ for (oc = 0, fi = flList; oc < ts->orderCount; oc++, fi++) {
+ if (fi->fc) {
+ free(fi->fl); fi->fl = NULL;
+ if (fi->type == TR_ADDED) {
+ free(fi->fmd5s); fi->fmd5s = NULL;
+ free(fi->flinks); fi->flinks = NULL;
+ free(fi->fps); fi->fps = NULL;
+ }
+ }
}
- if (!headerGetEntry(fi->h, RPMTAG_FILELANGS, NULL, (void **) &fileLangs,
- NULL))
- fileLangs = NULL;
+ if ((flags & RPMTRANS_FLAG_BUILD_PROBS) ||
+ (probs->numProblems && (!okProbs || psTrim(okProbs, probs)))) {
+ *newProbs = probs;
- if ((chptr = getenv("LINGUAS"))) {
- languages = splitString(chptr, strlen(chptr), ':');
- freeLanguages = 1;
- } else if ((oneLang[0] = getenv("LANG"))) {
- languages = oneLang;
- } else {
- oneLang[0] = "en";
- languages = oneLang;
- }
+ for (alp = ts->addedPackages.list, fi = flList;
+ (alp - ts->addedPackages.list) < ts->addedPackages.size;
+ alp++, fi++) {
+ headerFree(hdrs[alp - ts->addedPackages.list]);
+ }
- for (i = 0; i < fi->fc; i++) {
- if (fi->actions[i] == FA_SKIP || fi->actions[i] == FA_SKIPNSTATE)
- continue;
+ freeFl(ts, flList);
+ return ts->orderCount;
+ }
- /* netsharedPaths are not relative to the current root (though
- they do need to take package relocations into account) */
- for (nsp = netsharedPaths; nsp && *nsp; nsp++) {
- j = strlen(*nsp);
- if (!strncmp(fi->fl[i], *nsp, j) &&
- (fi->fl[i][j] == '\0' ||
- fi->fl[i][j] == '/'))
- break;
- }
+ lastFailed = -2;
+ for (oc = 0, fi = flList; oc < ts->orderCount; oc++, fi++) {
+ if (ts->order[oc].type == TR_ADDED) {
+ alp = ts->addedPackages.list + ts->order[oc].u.addedIndex;
+ i = ts->order[oc].u.addedIndex;
- if (nsp && *nsp) {
- fi->actions[i] = FA_SKIPNSTATE;
- continue;
- }
+ if (alp->fd) {
+ fd = alp->fd;
+ } else {
+ fd = notify(fi->h, RPMCALLBACK_INST_OPEN_FILE, 0, 0,
+ alp->key, notifyData);
+ if (fd) {
+ Header h;
- if (fileLangs && languages && *fileLangs[i]) {
- for (lang = languages; *lang; lang++) {
- const char *l, *le;
- for (l = fileLangs[i]; *l; l = le) {
- for (le = l; *le && *le != '|'; le++)
- ;
- if ((le-l) > 0 && !strncmp(*lang, l, (le-l)))
- goto lingo;
- if (*le == '|') le++; /* skip over | */
+ headerFree(hdrs[i]);
+ rc = rpmReadPackageHeader(fd, &h, NULL, NULL, NULL);
+ if (rc) {
+ notify(fi->h, RPMCALLBACK_INST_CLOSE_FILE, 0, 0,
+ alp->key, notifyData);
+ ourrc++;
+ fd = NULL;
+ } else {
+ hdrs[i] = relocateFileList(alp, probs, h, NULL, 1);
+ headerFree(h);
+ }
}
}
- lingo:
- if (!*lang) {
- fi->actions[i] = FA_SKIPNSTATE;
- continue;
+
+ if (fd) {
+ if (installBinaryPackage(ts->root, ts->db, fd,
+ hdrs[i], flags, notify,
+ notifyData, alp->key, fi->actions,
+ fi->fc ? fi->replaced : NULL,
+ ts->scriptFd)) {
+ ourrc++;
+ lastFailed = i;
+ }
+ } else {
+ ourrc++;
+ lastFailed = i;
}
- }
- if (noDocs && (fi->fflags[i] & RPMFILE_DOC))
- fi->actions[i] = FA_SKIPNSTATE;
+ headerFree(hdrs[i]);
+
+ if (!alp->fd && fd)
+ notify(fi->h, RPMCALLBACK_INST_CLOSE_FILE, 0, 0, alp->key,
+ notifyData);
+ } else if (ts->order[oc].u.removed.dependsOnIndex != lastFailed) {
+ if (removeBinaryPackage(ts->root, ts->db, fi->record,
+ flags, fi->actions, ts->scriptFd))
+
+ ourrc++;
+ }
}
- if (netsharedPaths) freeSplitString(netsharedPaths);
- if (fileLangs) free(fileLangs);
- if (freeLanguages) freeSplitString(languages);
+ freeFl(ts, flList);
+
+ if (ourrc)
+ return -1;
+ else
+ return 0;
}