~ubuntu-branches/ubuntu/edgy/rpm/edgy

« back to all changes in this revision

Viewing changes to lib/transaction.c

  • Committer: Bazaar Package Importer
  • Author(s): Joey Hess
  • Date: 2002-01-22 20:56:57 UTC
  • Revision ID: james.westby@ubuntu.com-20020122205657-l74j50mr9z8ofcl5
Tags: upstream-4.0.3
ImportĀ upstreamĀ versionĀ 4.0.3

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/** \ingroup rpmtrans
 
2
 * \file lib/transaction.c
 
3
 */
 
4
 
 
5
#include "system.h"
 
6
 
 
7
#include <rpmlib.h>
 
8
#include <rpmmacro.h>   /* XXX for rpmExpand */
 
9
 
 
10
#include "psm.h"
 
11
#include "fprint.h"
 
12
#include "rpmhash.h"
 
13
#include "md5.h"
 
14
#include "misc.h" /* XXX stripTrailingChar, splitString, currentDirectory */
 
15
#include "rpmdb.h"
 
16
 
 
17
/*@-redecl -exportheadervar@*/
 
18
extern const char * chroot_prefix;
 
19
/*@=redecl =exportheadervar@*/
 
20
 
 
21
/* XXX FIXME: merge with existing (broken?) tests in system.h */
 
22
/* portability fiddles */
 
23
#if STATFS_IN_SYS_STATVFS
 
24
# include <sys/statvfs.h>
 
25
#else
 
26
# if STATFS_IN_SYS_VFS
 
27
#  include <sys/vfs.h>
 
28
# else
 
29
#  if STATFS_IN_SYS_MOUNT
 
30
#   include <sys/mount.h>
 
31
#  else
 
32
#   if STATFS_IN_SYS_STATFS
 
33
#    include <sys/statfs.h>
 
34
#   endif
 
35
#  endif
 
36
# endif
 
37
#endif
 
38
 
 
39
#include "debug.h"
 
40
 
 
41
/*@access FD_t@*/               /* XXX compared with NULL */
 
42
/*@access Header@*/             /* XXX compared with NULL */
 
43
/*@access dbiIndexSet@*/
 
44
/*@access rpmdb@*/
 
45
/*@access rpmTransactionSet@*/
 
46
/*@access TFI_t@*/
 
47
/*@access PSM_t@*/
 
48
/*@access rpmProblemSet@*/
 
49
/*@access rpmProblem@*/
 
50
 
 
51
struct diskspaceInfo {
 
52
    dev_t dev;                  /*!< file system device number. */
 
53
    signed long bneeded;        /*!< no. of blocks needed. */
 
54
    signed long ineeded;        /*!< no. of inodes needed. */
 
55
    int bsize;                  /*!< file system block size. */
 
56
    signed long bavail;         /*!< no. of blocks available. */
 
57
    signed long iavail;         /*!< no. of inodes available. */
 
58
};
 
59
 
 
60
/* Adjust for root only reserved space. On linux e2fs, this is 5%. */
 
61
#define adj_fs_blocks(_nb)      (((_nb) * 21) / 20)
 
62
 
 
63
/* argon thought a shift optimization here was a waste of time...  he's
 
64
   probably right :-( */
 
65
#define BLOCK_ROUND(size, block) (((size) + (block) - 1) / (block))
 
66
 
 
67
#define XSTRCMP(a, b) ((!(a) && !(b)) || ((a) && (b) && !strcmp((a), (b))))
 
68
 
 
69
static /*@null@*/ void * freeFl(rpmTransactionSet ts,
 
70
                /*@only@*/ /*@null@*/ TFI_t flList)
 
71
        /*@*/
 
72
{
 
73
    if (flList) {
 
74
        TFI_t fi;
 
75
        int oc;
 
76
 
 
77
        /*@-usereleased@*/
 
78
        for (oc = 0, fi = flList; oc < ts->orderCount; oc++, fi++)
 
79
            freeFi(fi);
 
80
        flList = _free(flList);
 
81
        /*@=usereleased@*/
 
82
    }
 
83
    return NULL;
 
84
}
 
85
 
 
86
void rpmtransSetScriptFd(rpmTransactionSet ts, FD_t fd)
 
87
{
 
88
    ts->scriptFd = (fd ? fdLink(fd, "rpmtransSetScriptFd") : NULL);
 
89
}
 
90
 
 
91
int rpmtransGetKeys(const rpmTransactionSet ts, const void *** ep, int * nep)
 
92
{
 
93
    int rc = 0;
 
94
 
 
95
    if (nep) *nep = ts->orderCount;
 
96
    if (ep) {
 
97
        const void ** e;
 
98
        int oc;
 
99
 
 
100
        *ep = e = xmalloc(ts->orderCount * sizeof(*e));
 
101
        for (oc = 0; oc < ts->orderCount; oc++, e++) {
 
102
            switch (ts->order[oc].type) {
 
103
            case TR_ADDED:
 
104
                if (ts->addedPackages.list) {
 
105
                    struct availablePackage * alp;
 
106
                    alp = ts->addedPackages.list + ts->order[oc].u.addedIndex;
 
107
                    *e = alp->key;
 
108
                    break;
 
109
                }
 
110
                /*@fallthrough@*/
 
111
            default:
 
112
            case TR_REMOVED:
 
113
                /*@-mods@*/     /* FIX: double indirection. */
 
114
                *e = NULL;
 
115
                /*@=mods@*/
 
116
                break;
 
117
            }
 
118
        }
 
119
    }
 
120
    return rc;
 
121
}
 
122
 
 
123
static rpmProblemSet psCreate(void)
 
124
        /*@*/
 
125
{
 
126
    rpmProblemSet probs;
 
127
 
 
128
    probs = xmalloc(sizeof(*probs));    /* XXX memory leak */
 
129
    probs->numProblems = probs->numProblemsAlloced = 0;
 
130
    probs->probs = NULL;
 
131
 
 
132
    return probs;
 
133
}
 
134
 
 
135
static void psAppend(rpmProblemSet probs, rpmProblemType type,
 
136
                const struct availablePackage * alp,
 
137
                const char * dn, const char *bn,
 
138
                Header altH, unsigned long ulong1)
 
139
        /*@modifies probs, alp @*/
 
140
{
 
141
    rpmProblem p;
 
142
    char *t;
 
143
 
 
144
    if (probs->numProblems == probs->numProblemsAlloced) {
 
145
        if (probs->numProblemsAlloced)
 
146
            probs->numProblemsAlloced *= 2;
 
147
        else
 
148
            probs->numProblemsAlloced = 2;
 
149
        probs->probs = xrealloc(probs->probs,
 
150
                        probs->numProblemsAlloced * sizeof(*probs->probs));
 
151
    }
 
152
 
 
153
    p = probs->probs + probs->numProblems++;
 
154
    p->type = type;
 
155
    /*@-assignexpose@*/
 
156
    p->key = alp->key;
 
157
    /*@=assignexpose@*/
 
158
    p->ulong1 = ulong1;
 
159
    p->ignoreProblem = 0;
 
160
 
 
161
    if (dn || bn) {
 
162
        p->str1 =
 
163
            t = xmalloc((dn ? strlen(dn) : 0) + (bn ? strlen(bn) : 0) + 1);
 
164
        if (dn) t = stpcpy(t, dn);
 
165
        if (bn) t = stpcpy(t, bn);
 
166
    } else
 
167
        p->str1 = NULL;
 
168
 
 
169
    if (alp) {
 
170
        p->h = headerLink(alp->h);
 
171
        p->pkgNEVR =
 
172
            t = xmalloc(strlen(alp->name) +
 
173
                        strlen(alp->version) +
 
174
                        strlen(alp->release) + sizeof("--"));
 
175
        t = stpcpy(t, alp->name);
 
176
        t = stpcpy(t, "-");
 
177
        t = stpcpy(t, alp->version);
 
178
        t = stpcpy(t, "-");
 
179
        t = stpcpy(t, alp->release);
 
180
    } else {
 
181
        p->h = NULL;
 
182
        p->pkgNEVR = NULL;
 
183
    }
 
184
 
 
185
    if (altH) {
 
186
        const char * n, * v, * r;
 
187
        (void) headerNVR(altH, &n, &v, &r);
 
188
        p->altNEVR =
 
189
            t = xmalloc(strlen(n) + strlen(v) + strlen(r) + sizeof("--"));
 
190
        t = stpcpy(t, n);
 
191
        t = stpcpy(t, "-");
 
192
        t = stpcpy(t, v);
 
193
        t = stpcpy(t, "-");
 
194
        t = stpcpy(t, r);
 
195
    } else
 
196
        p->altNEVR = NULL;
 
197
}
 
198
 
 
199
static int archOkay(Header h)
 
200
        /*@*/
 
201
{
 
202
    void * pkgArch;
 
203
    int type, count;
 
204
 
 
205
    /* make sure we're trying to install this on the proper architecture */
 
206
    (void) headerGetEntry(h, RPMTAG_ARCH, &type, (void **) &pkgArch, &count);
 
207
#ifndef DYING
 
208
    if (type == RPM_INT8_TYPE) {
 
209
        int_8 * pkgArchNum;
 
210
        int archNum;
 
211
 
 
212
        /* old arch handling */
 
213
        rpmGetArchInfo(NULL, &archNum);
 
214
        pkgArchNum = pkgArch;
 
215
        if (archNum != *pkgArchNum) {
 
216
            return 0;
 
217
        }
 
218
    } else
 
219
#endif
 
220
    {
 
221
        /* new arch handling */
 
222
        if (!rpmMachineScore(RPM_MACHTABLE_INSTARCH, pkgArch)) {
 
223
            return 0;
 
224
        }
 
225
    }
 
226
 
 
227
    return 1;
 
228
}
 
229
 
 
230
static int osOkay(Header h)
 
231
        /*@*/
 
232
{
 
233
    void * pkgOs;
 
234
    int type, count;
 
235
 
 
236
    /* make sure we're trying to install this on the proper os */
 
237
    (void) headerGetEntry(h, RPMTAG_OS, &type, (void **) &pkgOs, &count);
 
238
#ifndef DYING
 
239
    if (type == RPM_INT8_TYPE) {
 
240
        /* v1 packages and v2 packages both used improper OS numbers, so just
 
241
           deal with it hope things work */
 
242
        return 1;
 
243
    } else
 
244
#endif
 
245
    {
 
246
        /* new os handling */
 
247
        if (!rpmMachineScore(RPM_MACHTABLE_INSTOS, pkgOs)) {
 
248
            return 0;
 
249
        }
 
250
    }
 
251
 
 
252
    return 1;
 
253
}
 
254
 
 
255
void rpmProblemSetFree(rpmProblemSet probs)
 
256
{
 
257
    int i;
 
258
 
 
259
    for (i = 0; i < probs->numProblems; i++) {
 
260
        rpmProblem p = probs->probs + i;
 
261
        p->h = headerFree(p->h);
 
262
        p->pkgNEVR = _free(p->pkgNEVR);
 
263
        p->altNEVR = _free(p->altNEVR);
 
264
        p->str1 = _free(p->str1);
 
265
    }
 
266
    free(probs);
 
267
}
 
268
 
 
269
static /*@observer@*/ const char *const ftstring (fileTypes ft)
 
270
        /*@*/
 
271
{
 
272
    switch (ft) {
 
273
    case XDIR:  return "directory";
 
274
    case CDEV:  return "char dev";
 
275
    case BDEV:  return "block dev";
 
276
    case LINK:  return "link";
 
277
    case SOCK:  return "sock";
 
278
    case PIPE:  return "fifo/pipe";
 
279
    case REG:   return "file";
 
280
    default:    return "unknown file type";
 
281
    }
 
282
    /*@notreached@*/
 
283
}
 
284
 
 
285
static fileTypes whatis(uint_16 mode)
 
286
        /*@*/
 
287
{
 
288
    if (S_ISDIR(mode))  return XDIR;
 
289
    if (S_ISCHR(mode))  return CDEV;
 
290
    if (S_ISBLK(mode))  return BDEV;
 
291
    if (S_ISLNK(mode))  return LINK;
 
292
    if (S_ISSOCK(mode)) return SOCK;
 
293
    if (S_ISFIFO(mode)) return PIPE;
 
294
    return REG;
 
295
}
 
296
 
 
297
#define alloca_strdup(_s)       strcpy(alloca(strlen(_s)+1), (_s))
 
298
 
 
299
/**
 
300
 * Relocate files in header.
 
301
 * @todo multilib file dispositions need to be checked.
 
302
 * @param ts            transaction set
 
303
 * @param fi            transaction element file info
 
304
 * @param alp           available package
 
305
 * @param origH         package header
 
306
 * @param actions       file dispositions
 
307
 * @return              header with relocated files
 
308
 */
 
309
static Header relocateFileList(const rpmTransactionSet ts, TFI_t fi,
 
310
                struct availablePackage * alp,
 
311
                Header origH, fileAction * actions)
 
312
        /*@modifies ts, fi, alp, origH, actions @*/
 
313
{
 
314
    HGE_t hge = fi->hge;
 
315
    HAE_t hae = fi->hae;
 
316
    HME_t hme = fi->hme;
 
317
    HFD_t hfd = (fi->hfd ? fi->hfd : headerFreeData);
 
318
    static int _printed = 0;
 
319
    rpmProblemSet probs = ts->probs;
 
320
    int allowBadRelocate = (ts->ignoreSet & RPMPROB_FILTER_FORCERELOCATE);
 
321
    rpmRelocation * rawRelocations = alp->relocs;
 
322
    rpmRelocation * relocations = NULL;
 
323
    int numRelocations;
 
324
    const char ** validRelocations;
 
325
    rpmTagType validType;
 
326
    int numValid;
 
327
    const char ** baseNames;
 
328
    const char ** dirNames;
 
329
    int_32 * dirIndexes;
 
330
    int_32 * newDirIndexes;
 
331
    int_32 fileCount;
 
332
    int_32 dirCount;
 
333
    uint_32 * fFlags = NULL;
 
334
    uint_16 * fModes = NULL;
 
335
    char * skipDirList;
 
336
    Header h;
 
337
    int nrelocated = 0;
 
338
    int fileAlloced = 0;
 
339
    char * fn = NULL;
 
340
    int haveRelocatedFile = 0;
 
341
    int reldel = 0;
 
342
    int len;
 
343
    int i, j;
 
344
 
 
345
    if (!hge(origH, RPMTAG_PREFIXES, &validType,
 
346
                        (void **) &validRelocations, &numValid))
 
347
        numValid = 0;
 
348
 
 
349
    numRelocations = 0;
 
350
    if (rawRelocations)
 
351
        while (rawRelocations[numRelocations].newPath ||
 
352
               rawRelocations[numRelocations].oldPath)
 
353
            numRelocations++;
 
354
 
 
355
    /*
 
356
     * If no relocations are specified (usually the case), then return the
 
357
     * original header. If there are prefixes, however, then INSTPREFIXES
 
358
     * should be added, but, since relocateFileList() can be called more
 
359
     * than once for the same header, don't bother if already present.
 
360
     */
 
361
    if (rawRelocations == NULL || numRelocations == 0) {
 
362
        if (numValid) {
 
363
            if (!headerIsEntry(origH, RPMTAG_INSTPREFIXES))
 
364
                (void) hae(origH, RPMTAG_INSTPREFIXES,
 
365
                        validType, validRelocations, numValid);
 
366
            validRelocations = hfd(validRelocations, validType);
 
367
        }
 
368
        /* XXX FIXME multilib file actions need to be checked. */
 
369
        return headerLink(origH);
 
370
    }
 
371
 
 
372
#ifdef DYING
 
373
    h = headerCopy(origH);
 
374
#else
 
375
    h = headerLink(origH);
 
376
#endif
 
377
 
 
378
    relocations = alloca(sizeof(*relocations) * numRelocations);
 
379
 
 
380
    /* Build sorted relocation list from raw relocations. */
 
381
    for (i = 0; i < numRelocations; i++) {
 
382
        char * t;
 
383
 
 
384
        /*
 
385
         * Default relocations (oldPath == NULL) are handled in the UI,
 
386
         * not rpmlib.
 
387
         */
 
388
        if (rawRelocations[i].oldPath == NULL) continue; /* XXX can't happen */
 
389
 
 
390
        /* FIXME: Trailing /'s will confuse us greatly. Internal ones will 
 
391
           too, but those are more trouble to fix up. :-( */
 
392
        t = alloca_strdup(rawRelocations[i].oldPath);
 
393
        relocations[i].oldPath = (t[0] == '/' && t[1] == '\0')
 
394
            ? t
 
395
            : stripTrailingChar(t, '/');
 
396
 
 
397
        /* An old path w/o a new path is valid, and indicates exclusion */
 
398
        if (rawRelocations[i].newPath) {
 
399
            int del;
 
400
 
 
401
            t = alloca_strdup(rawRelocations[i].newPath);
 
402
            relocations[i].newPath = (t[0] == '/' && t[1] == '\0')
 
403
                ? t
 
404
                : stripTrailingChar(t, '/');
 
405
 
 
406
            /*@-nullpass@*/     /* FIX:  relocations[i].oldPath == NULL */
 
407
            /* Verify that the relocation's old path is in the header. */
 
408
            for (j = 0; j < numValid; j++)
 
409
                if (!strcmp(validRelocations[j], relocations[i].oldPath))
 
410
                    /*@innerbreak@*/ break;
 
411
            /* XXX actions check prevents problem from being appended twice. */
 
412
            if (j == numValid && !allowBadRelocate && actions)
 
413
                psAppend(probs, RPMPROB_BADRELOCATE, alp,
 
414
                         relocations[i].oldPath, NULL, NULL, 0);
 
415
            del =
 
416
                strlen(relocations[i].newPath) - strlen(relocations[i].oldPath);
 
417
            /*@=nullpass@*/
 
418
 
 
419
            if (del > reldel)
 
420
                reldel = del;
 
421
        } else {
 
422
            relocations[i].newPath = NULL;
 
423
        }
 
424
    }
 
425
 
 
426
    /* stupid bubble sort, but it's probably faster here */
 
427
    for (i = 0; i < numRelocations; i++) {
 
428
        int madeSwap;
 
429
        madeSwap = 0;
 
430
        for (j = 1; j < numRelocations; j++) {
 
431
            rpmRelocation tmpReloc;
 
432
            if (relocations[j - 1].oldPath == NULL || /* XXX can't happen */
 
433
                relocations[j    ].oldPath == NULL || /* XXX can't happen */
 
434
        strcmp(relocations[j - 1].oldPath, relocations[j].oldPath) <= 0)
 
435
                continue;
 
436
            tmpReloc = relocations[j - 1];
 
437
            relocations[j - 1] = relocations[j];
 
438
            relocations[j] = tmpReloc;
 
439
            madeSwap = 1;
 
440
        }
 
441
        if (!madeSwap) break;
 
442
    }
 
443
 
 
444
    if (!_printed) {
 
445
        _printed = 1;
 
446
        rpmMessage(RPMMESS_DEBUG, _("========== relocations\n"));
 
447
        for (i = 0; i < numRelocations; i++) {
 
448
            if (relocations[i].oldPath == NULL) continue; /* XXX can't happen */
 
449
            if (relocations[i].newPath == NULL)
 
450
                rpmMessage(RPMMESS_DEBUG, _("%5d exclude  %s\n"),
 
451
                        i, relocations[i].oldPath);
 
452
            else
 
453
                rpmMessage(RPMMESS_DEBUG, _("%5d relocate %s -> %s\n"),
 
454
                        i, relocations[i].oldPath, relocations[i].newPath);
 
455
        }
 
456
    }
 
457
 
 
458
    /* Add relocation values to the header */
 
459
    if (numValid) {
 
460
        const char ** actualRelocations;
 
461
        int numActual;
 
462
 
 
463
        actualRelocations = xmalloc(numValid * sizeof(*actualRelocations));
 
464
        numActual = 0;
 
465
        for (i = 0; i < numValid; i++) {
 
466
            for (j = 0; j < numRelocations; j++) {
 
467
                if (relocations[j].oldPath == NULL || /* XXX can't happen */
 
468
                    strcmp(validRelocations[i], relocations[j].oldPath))
 
469
                    continue;
 
470
                /* On install, a relocate to NULL means skip the path. */
 
471
                if (relocations[j].newPath) {
 
472
                    actualRelocations[numActual] = relocations[j].newPath;
 
473
                    numActual++;
 
474
                }
 
475
                /*@innerbreak@*/ break;
 
476
            }
 
477
            if (j == numRelocations) {
 
478
                actualRelocations[numActual] = validRelocations[i];
 
479
                numActual++;
 
480
            }
 
481
        }
 
482
 
 
483
        if (numActual)
 
484
            (void) hae(h, RPMTAG_INSTPREFIXES, RPM_STRING_ARRAY_TYPE,
 
485
                       (void **) actualRelocations, numActual);
 
486
 
 
487
        actualRelocations = _free(actualRelocations);
 
488
        validRelocations = hfd(validRelocations, validType);
 
489
    }
 
490
 
 
491
    (void) hge(h, RPMTAG_BASENAMES, NULL, (void **) &baseNames, &fileCount);
 
492
    (void) hge(h, RPMTAG_DIRINDEXES, NULL, (void **) &dirIndexes, NULL);
 
493
    (void) hge(h, RPMTAG_DIRNAMES, NULL, (void **) &dirNames, &dirCount);
 
494
    (void) hge(h, RPMTAG_FILEFLAGS, NULL, (void **) &fFlags, NULL);
 
495
    (void) hge(h, RPMTAG_FILEMODES, NULL, (void **) &fModes, NULL);
 
496
 
 
497
    skipDirList = alloca(dirCount * sizeof(*skipDirList));
 
498
    memset(skipDirList, 0, dirCount * sizeof(*skipDirList));
 
499
 
 
500
    newDirIndexes = alloca(sizeof(*newDirIndexes) * fileCount);
 
501
    memcpy(newDirIndexes, dirIndexes, sizeof(*newDirIndexes) * fileCount);
 
502
    dirIndexes = newDirIndexes;
 
503
 
 
504
    /*
 
505
     * For all relocations, we go through sorted file/relocation lists 
 
506
     * backwards so that /usr/local relocations take precedence over /usr 
 
507
     * ones.
 
508
     */
 
509
 
 
510
    /* Relocate individual paths. */
 
511
 
 
512
    for (i = fileCount - 1; i >= 0; i--) {
 
513
        fileTypes ft;
 
514
        int fnlen;
 
515
 
 
516
        /*
 
517
         * If only adding libraries of different arch into an already
 
518
         * installed package, skip all other files.
 
519
         */
 
520
        if (alp->multiLib && !isFileMULTILIB((fFlags[i]))) {
 
521
            if (actions) {
 
522
                actions[i] = FA_SKIPMULTILIB;
 
523
                rpmMessage(RPMMESS_DEBUG, _("excluding multilib path %s%s\n"), 
 
524
                        dirNames[dirIndexes[i]], baseNames[i]);
 
525
            }
 
526
            continue;
 
527
        }
 
528
 
 
529
        len = reldel +
 
530
                strlen(dirNames[dirIndexes[i]]) + strlen(baseNames[i]) + 1;
 
531
        if (len >= fileAlloced) {
 
532
            fileAlloced = len * 2;
 
533
            fn = xrealloc(fn, fileAlloced);
 
534
        }
 
535
        *fn = '\0';
 
536
        fnlen = stpcpy( stpcpy(fn, dirNames[dirIndexes[i]]), baseNames[i]) - fn;
 
537
 
 
538
        /*
 
539
         * See if this file path needs relocating.
 
540
         */
 
541
        /*
 
542
         * XXX FIXME: Would a bsearch of the (already sorted) 
 
543
         * relocation list be a good idea?
 
544
         */
 
545
        for (j = numRelocations - 1; j >= 0; j--) {
 
546
            if (relocations[j].oldPath == NULL) continue; /* XXX can't happen */
 
547
            len = strcmp(relocations[j].oldPath, "/")
 
548
                ? strlen(relocations[j].oldPath)
 
549
                : 0;
 
550
 
 
551
            if (fnlen < len)
 
552
                continue;
 
553
            /*
 
554
             * Only subdirectories or complete file paths may be relocated. We
 
555
             * don't check for '\0' as our directory names all end in '/'.
 
556
             */
 
557
            if (!(fn[len] == '/' || fnlen == len))
 
558
                continue;
 
559
 
 
560
            if (strncmp(relocations[j].oldPath, fn, len))
 
561
                continue;
 
562
            /*@innerbreak@*/ break;
 
563
        }
 
564
        if (j < 0) continue;
 
565
 
 
566
        ft = whatis(fModes[i]);
 
567
 
 
568
        /* On install, a relocate to NULL means skip the path. */
 
569
        if (relocations[j].newPath == NULL) {
 
570
            if (ft == XDIR) {
 
571
                /* Start with the parent, looking for directory to exclude. */
 
572
                for (j = dirIndexes[i]; j < dirCount; j++) {
 
573
                    len = strlen(dirNames[j]) - 1;
 
574
                    while (len > 0 && dirNames[j][len-1] == '/') len--;
 
575
                    if (fnlen != len)
 
576
                        continue;
 
577
                    if (strncmp(fn, dirNames[j], fnlen))
 
578
                        continue;
 
579
                    /*@innerbreak@*/ break;
 
580
                }
 
581
                if (j < dirCount)
 
582
                    skipDirList[j] = 1;
 
583
            }
 
584
            if (actions) {
 
585
                actions[i] = FA_SKIPNSTATE;
 
586
                rpmMessage(RPMMESS_DEBUG, _("excluding %s %s\n"),
 
587
                        ftstring(ft), fn);
 
588
            }
 
589
            continue;
 
590
        }
 
591
 
 
592
        /* Relocation on full paths only, please. */
 
593
        if (fnlen != len) continue;
 
594
 
 
595
        if (actions)
 
596
            rpmMessage(RPMMESS_DEBUG, _("relocating %s to %s\n"),
 
597
                    fn, relocations[j].newPath);
 
598
        nrelocated++;
 
599
 
 
600
        strcpy(fn, relocations[j].newPath);
 
601
        {   char * te = strrchr(fn, '/');
 
602
            if (te) {
 
603
                if (te > fn) te++;      /* root is special */
 
604
                fnlen = te - fn;
 
605
            } else
 
606
                te = fn + strlen(fn);
 
607
            /*@-nullpass -nullderef@*/  /* LCL: te != NULL here. */
 
608
            if (strcmp(baseNames[i], te)) /* basename changed too? */
 
609
                baseNames[i] = alloca_strdup(te);
 
610
            *te = '\0';                 /* terminate new directory name */
 
611
            /*@=nullpass =nullderef@*/
 
612
        }
 
613
 
 
614
        /* Does this directory already exist in the directory list? */
 
615
        for (j = 0; j < dirCount; j++) {
 
616
            if (fnlen != strlen(dirNames[j]))
 
617
                continue;
 
618
            if (strncmp(fn, dirNames[j], fnlen))
 
619
                continue;
 
620
            /*@innerbreak@*/ break;
 
621
        }
 
622
        
 
623
        if (j < dirCount) {
 
624
            dirIndexes[i] = j;
 
625
            continue;
 
626
        }
 
627
 
 
628
        /* Creating new paths is a pita */
 
629
        if (!haveRelocatedFile) {
 
630
            const char ** newDirList;
 
631
 
 
632
            haveRelocatedFile = 1;
 
633
            newDirList = xmalloc((dirCount + 1) * sizeof(*newDirList));
 
634
            for (j = 0; j < dirCount; j++)
 
635
                newDirList[j] = alloca_strdup(dirNames[j]);
 
636
            dirNames = hfd(dirNames, RPM_STRING_ARRAY_TYPE);
 
637
            dirNames = newDirList;
 
638
        } else {
 
639
            dirNames = xrealloc(dirNames, 
 
640
                               sizeof(*dirNames) * (dirCount + 1));
 
641
        }
 
642
 
 
643
        dirNames[dirCount] = alloca_strdup(fn);
 
644
        dirIndexes[i] = dirCount;
 
645
        dirCount++;
 
646
    }
 
647
 
 
648
    /* Finish off by relocating directories. */
 
649
    for (i = dirCount - 1; i >= 0; i--) {
 
650
        for (j = numRelocations - 1; j >= 0; j--) {
 
651
 
 
652
            if (relocations[j].oldPath == NULL) continue; /* XXX can't happen */
 
653
            len = strcmp(relocations[j].oldPath, "/")
 
654
                ? strlen(relocations[j].oldPath)
 
655
                : 0;
 
656
 
 
657
            if (len && strncmp(relocations[j].oldPath, dirNames[i], len))
 
658
                continue;
 
659
 
 
660
            /*
 
661
             * Only subdirectories or complete file paths may be relocated. We
 
662
             * don't check for '\0' as our directory names all end in '/'.
 
663
             */
 
664
            if (dirNames[i][len] != '/')
 
665
                continue;
 
666
 
 
667
            if (relocations[j].newPath) { /* Relocate the path */
 
668
                const char * s = relocations[j].newPath;
 
669
                char * t = alloca(strlen(s) + strlen(dirNames[i]) - len + 1);
 
670
 
 
671
                (void) stpcpy( stpcpy(t, s) , dirNames[i] + len);
 
672
                if (actions)
 
673
                    rpmMessage(RPMMESS_DEBUG,
 
674
                        _("relocating directory %s to %s\n"), dirNames[i], t);
 
675
                dirNames[i] = t;
 
676
                nrelocated++;
 
677
            }
 
678
        }
 
679
    }
 
680
 
 
681
    /* Save original filenames in header and replace (relocated) filenames. */
 
682
    if (nrelocated) {
 
683
        int c;
 
684
        void * p;
 
685
        rpmTagType t;
 
686
 
 
687
        p = NULL;
 
688
        (void) hge(h, RPMTAG_BASENAMES, &t, &p, &c);
 
689
        (void) hae(h, RPMTAG_ORIGBASENAMES, t, p, c);
 
690
        p = hfd(p, t);
 
691
 
 
692
        p = NULL;
 
693
        (void) hge(h, RPMTAG_DIRNAMES, &t, &p, &c);
 
694
        (void) hae(h, RPMTAG_ORIGDIRNAMES, t, p, c);
 
695
        p = hfd(p, t);
 
696
 
 
697
        p = NULL;
 
698
        (void) hge(h, RPMTAG_DIRINDEXES, &t, &p, &c);
 
699
        (void) hae(h, RPMTAG_ORIGDIRINDEXES, t, p, c);
 
700
        p = hfd(p, t);
 
701
 
 
702
        (void) hme(h, RPMTAG_BASENAMES, RPM_STRING_ARRAY_TYPE,
 
703
                          baseNames, fileCount);
 
704
        fi->bnl = hfd(fi->bnl, RPM_STRING_ARRAY_TYPE);
 
705
        (void) hge(h, RPMTAG_BASENAMES, NULL, (void **) &fi->bnl, &fi->fc);
 
706
 
 
707
        (void) hme(h, RPMTAG_DIRNAMES, RPM_STRING_ARRAY_TYPE,
 
708
                          dirNames, dirCount);
 
709
        fi->dnl = hfd(fi->dnl, RPM_STRING_ARRAY_TYPE);
 
710
        (void) hge(h, RPMTAG_DIRNAMES, NULL, (void **) &fi->dnl, &fi->dc);
 
711
 
 
712
        (void) hme(h, RPMTAG_DIRINDEXES, RPM_INT32_TYPE,
 
713
                          dirIndexes, fileCount);
 
714
        (void) hge(h, RPMTAG_DIRINDEXES, NULL, (void **) &fi->dil, NULL);
 
715
    }
 
716
 
 
717
    baseNames = hfd(baseNames, RPM_STRING_ARRAY_TYPE);
 
718
    dirNames = hfd(dirNames, RPM_STRING_ARRAY_TYPE);
 
719
    fn = _free(fn);
 
720
 
 
721
    return h;
 
722
}
 
723
 
 
724
/*
 
725
 * As the problem sets are generated in an order solely dependent
 
726
 * on the ordering of the packages in the transaction, and that
 
727
 * ordering can't be changed, the problem sets must be parallel to
 
728
 * one another. Additionally, the filter set must be a subset of the
 
729
 * target set, given the operations available on transaction set.
 
730
 * This is good, as it lets us perform this trim in linear time, rather
 
731
 * then logarithmic or quadratic.
 
732
 */
 
733
static int psTrim(rpmProblemSet filter, rpmProblemSet target)
 
734
        /*@modifies target @*/
 
735
{
 
736
    rpmProblem f = filter->probs;
 
737
    rpmProblem t = target->probs;
 
738
    int gotProblems = 0;
 
739
 
 
740
    while ((f - filter->probs) < filter->numProblems) {
 
741
        if (!f->ignoreProblem) {
 
742
            f++;
 
743
            continue;
 
744
        }
 
745
        while ((t - target->probs) < target->numProblems) {
 
746
            /*@-nullpass@*/     /* LCL: looks good to me */
 
747
            if (f->h == t->h && f->type == t->type && t->key == f->key &&
 
748
                     XSTRCMP(f->str1, t->str1))
 
749
                /*@innerbreak@*/ break;
 
750
            /*@=nullpass@*/
 
751
            t++;
 
752
            gotProblems = 1;
 
753
        }
 
754
 
 
755
        if ((t - target->probs) == target->numProblems) {
 
756
            /* this can't happen ;-) lets be sane if it doesn though */
 
757
            break;
 
758
        }
 
759
 
 
760
        t->ignoreProblem = f->ignoreProblem;
 
761
        t++, f++;
 
762
    }
 
763
 
 
764
    if ((t - target->probs) < target->numProblems)
 
765
        gotProblems = 1;
 
766
 
 
767
    return gotProblems;
 
768
}
 
769
 
 
770
static int sharedCmp(const void * one, const void * two)
 
771
        /*@*/
 
772
{
 
773
    const struct sharedFileInfo * a = one;
 
774
    const struct sharedFileInfo * b = two;
 
775
 
 
776
    if (a->otherPkg < b->otherPkg)
 
777
        return -1;
 
778
    else if (a->otherPkg > b->otherPkg)
 
779
        return 1;
 
780
 
 
781
    return 0;
 
782
}
 
783
 
 
784
static fileAction decideFileFate(const char * dirName,
 
785
                        const char * baseName, short dbMode,
 
786
                        const char * dbMd5, const char * dbLink, short newMode,
 
787
                        const char * newMd5, const char * newLink, int newFlags,
 
788
                        int brokenMd5, rpmtransFlags transFlags)
 
789
        /*@*/
 
790
{
 
791
    char buffer[1024];
 
792
    const char * dbAttr, * newAttr;
 
793
    fileTypes dbWhat, newWhat, diskWhat;
 
794
    struct stat sb;
 
795
    int i, rc;
 
796
    int save = (newFlags & RPMFILE_NOREPLACE) ? FA_ALTNAME : FA_SAVE;
 
797
    char * filespec = alloca(strlen(dirName) + strlen(baseName) + 1);
 
798
 
 
799
    (void) stpcpy( stpcpy(filespec, dirName), baseName);
 
800
 
 
801
    if (lstat(filespec, &sb)) {
 
802
        /*
 
803
         * The file doesn't exist on the disk. Create it unless the new
 
804
         * package has marked it as missingok, or allfiles is requested.
 
805
         */
 
806
        if (!(transFlags & RPMTRANS_FLAG_ALLFILES) &&
 
807
           (newFlags & RPMFILE_MISSINGOK)) {
 
808
            rpmMessage(RPMMESS_DEBUG, _("%s skipped due to missingok flag\n"),
 
809
                        filespec);
 
810
            return FA_SKIP;
 
811
        } else {
 
812
            return FA_CREATE;
 
813
        }
 
814
    }
 
815
 
 
816
    diskWhat = whatis(sb.st_mode);
 
817
    dbWhat = whatis(dbMode);
 
818
    newWhat = whatis(newMode);
 
819
 
 
820
    /* RPM >= 2.3.10 shouldn't create config directories -- we'll ignore
 
821
       them in older packages as well */
 
822
    if (newWhat == XDIR) {
 
823
        return FA_CREATE;
 
824
    }
 
825
 
 
826
    if (diskWhat != newWhat) {
 
827
        return save;
 
828
    } else if (newWhat != dbWhat && diskWhat != dbWhat) {
 
829
        return save;
 
830
    } else if (dbWhat != newWhat) {
 
831
        return FA_CREATE;
 
832
    } else if (dbWhat != LINK && dbWhat != REG) {
 
833
        return FA_CREATE;
 
834
    }
 
835
 
 
836
    if (dbWhat == REG) {
 
837
        if (brokenMd5)
 
838
            rc = mdfileBroken(filespec, buffer);
 
839
        else
 
840
            rc = mdfile(filespec, buffer);
 
841
 
 
842
        if (rc) {
 
843
            /* assume the file has been removed, don't freak */
 
844
            return FA_CREATE;
 
845
        }
 
846
        dbAttr = dbMd5;
 
847
        newAttr = newMd5;
 
848
    } else /* dbWhat == LINK */ {
 
849
        memset(buffer, 0, sizeof(buffer));
 
850
        i = readlink(filespec, buffer, sizeof(buffer) - 1);
 
851
        if (i == -1) {
 
852
            /* assume the file has been removed, don't freak */
 
853
            return FA_CREATE;
 
854
        }
 
855
        dbAttr = dbLink;
 
856
        newAttr = newLink;
 
857
     }
 
858
 
 
859
    /* this order matters - we'd prefer to CREATE the file if at all
 
860
       possible in case something else (like the timestamp) has changed */
 
861
 
 
862
    if (!strcmp(dbAttr, buffer)) {
 
863
        /* this config file has never been modified, so just replace it */
 
864
        return FA_CREATE;
 
865
    }
 
866
 
 
867
    if (!strcmp(dbAttr, newAttr)) {
 
868
        /* this file is the same in all versions of this package */
 
869
        return FA_SKIP;
 
870
    }
 
871
 
 
872
    /*
 
873
     * The config file on the disk has been modified, but
 
874
     * the ones in the two packages are different. It would
 
875
     * be nice if RPM was smart enough to at least try and
 
876
     * merge the difference ala CVS, but...
 
877
     */
 
878
    return save;
 
879
}
 
880
 
 
881
static int filecmp(short mode1, const char * md51, const char * link1,
 
882
                   short mode2, const char * md52, const char * link2)
 
883
        /*@*/
 
884
{
 
885
    fileTypes what1 = whatis(mode1);
 
886
    fileTypes what2 = whatis(mode2);
 
887
 
 
888
    if (what1 != what2) return 1;
 
889
 
 
890
    if (what1 == LINK)
 
891
        return strcmp(link1, link2);
 
892
    else if (what1 == REG)
 
893
        return strcmp(md51, md52);
 
894
 
 
895
    return 0;
 
896
}
 
897
 
 
898
static int handleInstInstalledFiles(TFI_t fi, /*@null@*/ rpmdb db,
 
899
                                    struct sharedFileInfo * shared,
 
900
                                    int sharedCount, int reportConflicts,
 
901
                                    rpmProblemSet probs,
 
902
                                    rpmtransFlags transFlags)
 
903
        /*@modifies fi, db, probs @*/
 
904
{
 
905
    HGE_t hge = fi->hge;
 
906
    HFD_t hfd = (fi->hfd ? fi->hfd : headerFreeData);
 
907
    rpmTagType oltype, omtype;
 
908
    Header h;
 
909
    int i;
 
910
    const char ** otherMd5s;
 
911
    const char ** otherLinks;
 
912
    const char * otherStates;
 
913
    uint_32 * otherFlags;
 
914
    uint_32 * otherSizes;
 
915
    uint_16 * otherModes;
 
916
    int numReplaced = 0;
 
917
 
 
918
    rpmdbMatchIterator mi;
 
919
 
 
920
    mi = rpmdbInitIterator(db, RPMDBI_PACKAGES, &shared->otherPkg, sizeof(shared->otherPkg));
 
921
    h = rpmdbNextIterator(mi);
 
922
    if (h == NULL) {
 
923
        mi = rpmdbFreeIterator(mi);
 
924
        return 1;
 
925
    }
 
926
 
 
927
    (void) hge(h, RPMTAG_FILEMD5S, &omtype, (void **) &otherMd5s, NULL);
 
928
    (void) hge(h, RPMTAG_FILELINKTOS, &oltype, (void **) &otherLinks, NULL);
 
929
    (void) hge(h, RPMTAG_FILESTATES, NULL, (void **) &otherStates, NULL);
 
930
    (void) hge(h, RPMTAG_FILEMODES, NULL, (void **) &otherModes, NULL);
 
931
    (void) hge(h, RPMTAG_FILEFLAGS, NULL, (void **) &otherFlags, NULL);
 
932
    (void) hge(h, RPMTAG_FILESIZES, NULL, (void **) &otherSizes, NULL);
 
933
 
 
934
    fi->replaced = xmalloc(sharedCount * sizeof(*fi->replaced));
 
935
 
 
936
    for (i = 0; i < sharedCount; i++, shared++) {
 
937
        int otherFileNum, fileNum;
 
938
        otherFileNum = shared->otherFileNum;
 
939
        fileNum = shared->pkgFileNum;
 
940
 
 
941
        /* XXX another tedious segfault, assume file state normal. */
 
942
        if (otherStates && otherStates[otherFileNum] != RPMFILE_STATE_NORMAL)
 
943
            continue;
 
944
 
 
945
        if (XFA_SKIPPING(fi->actions[fileNum]))
 
946
            continue;
 
947
 
 
948
        if (filecmp(otherModes[otherFileNum],
 
949
                        otherMd5s[otherFileNum],
 
950
                        otherLinks[otherFileNum],
 
951
                        fi->fmodes[fileNum],
 
952
                        fi->fmd5s[fileNum],
 
953
                        fi->flinks[fileNum])) {
 
954
            if (reportConflicts)
 
955
                psAppend(probs, RPMPROB_FILE_CONFLICT, fi->ap,
 
956
                        fi->dnl[fi->dil[fileNum]], fi->bnl[fileNum], h, 0);
 
957
            if (!(otherFlags[otherFileNum] | fi->fflags[fileNum])
 
958
                        & RPMFILE_CONFIG) {
 
959
                /*@-assignexpose@*/
 
960
                if (!shared->isRemoved)
 
961
                    fi->replaced[numReplaced++] = *shared;
 
962
                /*@=assignexpose@*/
 
963
            }
 
964
        }
 
965
 
 
966
        if ((otherFlags[otherFileNum] | fi->fflags[fileNum]) & RPMFILE_CONFIG) {
 
967
            fi->actions[fileNum] = decideFileFate(
 
968
                        fi->dnl[fi->dil[fileNum]],
 
969
                        fi->bnl[fileNum],
 
970
                        otherModes[otherFileNum],
 
971
                        otherMd5s[otherFileNum],
 
972
                        otherLinks[otherFileNum],
 
973
                        fi->fmodes[fileNum],
 
974
                        fi->fmd5s[fileNum],
 
975
                        fi->flinks[fileNum],
 
976
                        fi->fflags[fileNum],
 
977
                        !headerIsEntry(h, RPMTAG_RPMVERSION),
 
978
                        transFlags);
 
979
        }
 
980
 
 
981
        fi->replacedSizes[fileNum] = otherSizes[otherFileNum];
 
982
    }
 
983
 
 
984
    otherMd5s = hfd(otherMd5s, omtype);
 
985
    otherLinks = hfd(otherLinks, oltype);
 
986
    mi = rpmdbFreeIterator(mi);
 
987
 
 
988
    fi->replaced = xrealloc(fi->replaced,       /* XXX memory leak */
 
989
                           sizeof(*fi->replaced) * (numReplaced + 1));
 
990
    fi->replaced[numReplaced].otherPkg = 0;
 
991
 
 
992
    return 0;
 
993
}
 
994
 
 
995
static int handleRmvdInstalledFiles(TFI_t fi, /*@null@*/ rpmdb db,
 
996
                                    struct sharedFileInfo * shared,
 
997
                                    int sharedCount)
 
998
        /*@modifies fi, db @*/
 
999
{
 
1000
    HGE_t hge = fi->hge;
 
1001
    Header h;
 
1002
    const char * otherStates;
 
1003
    int i;
 
1004
   
 
1005
    rpmdbMatchIterator mi;
 
1006
 
 
1007
    mi = rpmdbInitIterator(db, RPMDBI_PACKAGES,
 
1008
                        &shared->otherPkg, sizeof(shared->otherPkg));
 
1009
    h = rpmdbNextIterator(mi);
 
1010
    if (h == NULL) {
 
1011
        mi = rpmdbFreeIterator(mi);
 
1012
        return 1;
 
1013
    }
 
1014
 
 
1015
    (void) hge(h, RPMTAG_FILESTATES, NULL, (void **) &otherStates, NULL);
 
1016
 
 
1017
    for (i = 0; i < sharedCount; i++, shared++) {
 
1018
        int otherFileNum, fileNum;
 
1019
        otherFileNum = shared->otherFileNum;
 
1020
        fileNum = shared->pkgFileNum;
 
1021
 
 
1022
        if (otherStates[otherFileNum] != RPMFILE_STATE_NORMAL)
 
1023
            continue;
 
1024
 
 
1025
        fi->actions[fileNum] = FA_SKIP;
 
1026
    }
 
1027
 
 
1028
    mi = rpmdbFreeIterator(mi);
 
1029
 
 
1030
    return 0;
 
1031
}
 
1032
 
 
1033
/**
 
1034
 * Update disk space needs on each partition for this package.
 
1035
 */
 
1036
static void handleOverlappedFiles(TFI_t fi, hashTable ht,
 
1037
                           rpmProblemSet probs, struct diskspaceInfo * dsl)
 
1038
        /*@modifies fi, probs, dsl @*/
 
1039
{
 
1040
    int i, j;
 
1041
    struct diskspaceInfo * ds = NULL;
 
1042
    uint_32 fixupSize = 0;
 
1043
    char * filespec = NULL;
 
1044
    int fileSpecAlloced = 0;
 
1045
  
 
1046
    for (i = 0; i < fi->fc; i++) {
 
1047
        int otherPkgNum, otherFileNum;
 
1048
        const TFI_t * recs;
 
1049
        int numRecs;
 
1050
 
 
1051
        if (XFA_SKIPPING(fi->actions[i]))
 
1052
            continue;
 
1053
 
 
1054
        j = strlen(fi->dnl[fi->dil[i]]) + strlen(fi->bnl[i]) + 1;
 
1055
        if (j > fileSpecAlloced) {
 
1056
            fileSpecAlloced = j * 2;
 
1057
            filespec = xrealloc(filespec, fileSpecAlloced);
 
1058
        }
 
1059
 
 
1060
        (void) stpcpy( stpcpy( filespec, fi->dnl[fi->dil[i]]), fi->bnl[i]);
 
1061
 
 
1062
        if (dsl) {
 
1063
            ds = dsl;
 
1064
            while (ds->bsize && ds->dev != fi->fps[i].entry->dev) ds++;
 
1065
            if (!ds->bsize) ds = NULL;
 
1066
            fixupSize = 0;
 
1067
        }
 
1068
 
 
1069
        /*
 
1070
         * Retrieve all records that apply to this file. Note that the
 
1071
         * file info records were built in the same order as the packages
 
1072
         * will be installed and removed so the records for an overlapped
 
1073
         * files will be sorted in exactly the same order.
 
1074
         */
 
1075
        (void) htGetEntry(ht, &fi->fps[i], (const void ***) &recs, &numRecs, NULL);
 
1076
 
 
1077
        /*
 
1078
         * If this package is being added, look only at other packages
 
1079
         * being added -- removed packages dance to a different tune.
 
1080
         * If both this and the other package are being added, overlapped
 
1081
         * files must be identical (or marked as a conflict). The
 
1082
         * disposition of already installed config files leads to
 
1083
         * a small amount of extra complexity.
 
1084
         *
 
1085
         * If this package is being removed, then there are two cases that
 
1086
         * need to be worried about:
 
1087
         * If the other package is being added, then skip any overlapped files
 
1088
         * so that this package removal doesn't nuke the overlapped files
 
1089
         * that were just installed.
 
1090
         * If both this and the other package are being removed, then each
 
1091
         * file removal from preceding packages needs to be skipped so that
 
1092
         * the file removal occurs only on the last occurence of an overlapped
 
1093
         * file in the transaction set.
 
1094
         *
 
1095
         */
 
1096
 
 
1097
        /* Locate this overlapped file in the set of added/removed packages. */
 
1098
        for (j = 0; j < numRecs && recs[j] != fi; j++)
 
1099
            {};
 
1100
 
 
1101
        /* Find what the previous disposition of this file was. */
 
1102
        otherFileNum = -1;                      /* keep gcc quiet */
 
1103
        for (otherPkgNum = j - 1; otherPkgNum >= 0; otherPkgNum--) {
 
1104
            /* Added packages need only look at other added packages. */
 
1105
            if (fi->type == TR_ADDED && recs[otherPkgNum]->type != TR_ADDED)
 
1106
                continue;
 
1107
 
 
1108
            /* TESTME: there are more efficient searches in the world... */
 
1109
            for (otherFileNum = 0; otherFileNum < recs[otherPkgNum]->fc;
 
1110
                 otherFileNum++) {
 
1111
 
 
1112
                /* If the addresses are the same, so are the values. */
 
1113
                if ((fi->fps + i) == (recs[otherPkgNum]->fps + otherFileNum))
 
1114
                    /*@innerbreak@*/ break;
 
1115
 
 
1116
                /* Otherwise, compare fingerprints by value. */
 
1117
                /*@-nullpass@*/ /* LCL: looks good to me */
 
1118
                if (FP_EQUAL(fi->fps[i], recs[otherPkgNum]->fps[otherFileNum]))
 
1119
                    /*@innerbreak@*/ break;
 
1120
                /*@=nullpass@*/
 
1121
 
 
1122
            }
 
1123
            /* XXX is this test still necessary? */
 
1124
            if (recs[otherPkgNum]->actions[otherFileNum] != FA_UNKNOWN)
 
1125
                /*@innerbreak@*/ break;
 
1126
        }
 
1127
 
 
1128
        switch (fi->type) {
 
1129
        case TR_ADDED:
 
1130
          { struct stat sb;
 
1131
            if (otherPkgNum < 0) {
 
1132
                /* XXX is this test still necessary? */
 
1133
                if (fi->actions[i] != FA_UNKNOWN)
 
1134
                    break;
 
1135
                if ((fi->fflags[i] & RPMFILE_CONFIG) && 
 
1136
                        !lstat(filespec, &sb)) {
 
1137
                    /* Here is a non-overlapped pre-existing config file. */
 
1138
                    fi->actions[i] = (fi->fflags[i] & RPMFILE_NOREPLACE)
 
1139
                        ? FA_ALTNAME : FA_BACKUP;
 
1140
                } else {
 
1141
                    fi->actions[i] = FA_CREATE;
 
1142
                }
 
1143
                break;
 
1144
            }
 
1145
 
 
1146
            /* Mark added overlapped non-identical files as a conflict. */
 
1147
            if (probs && filecmp(recs[otherPkgNum]->fmodes[otherFileNum],
 
1148
                        recs[otherPkgNum]->fmd5s[otherFileNum],
 
1149
                        recs[otherPkgNum]->flinks[otherFileNum],
 
1150
                        fi->fmodes[i],
 
1151
                        fi->fmd5s[i],
 
1152
                        fi->flinks[i])) {
 
1153
                psAppend(probs, RPMPROB_NEW_FILE_CONFLICT, fi->ap,
 
1154
                                filespec, NULL, recs[otherPkgNum]->ap->h, 0);
 
1155
            }
 
1156
 
 
1157
            /* Try to get the disk accounting correct even if a conflict. */
 
1158
            fixupSize = recs[otherPkgNum]->fsizes[otherFileNum];
 
1159
 
 
1160
            if ((fi->fflags[i] & RPMFILE_CONFIG) && !lstat(filespec, &sb)) {
 
1161
                /* Here is an overlapped  pre-existing config file. */
 
1162
                fi->actions[i] = (fi->fflags[i] & RPMFILE_NOREPLACE)
 
1163
                        ? FA_ALTNAME : FA_SKIP;
 
1164
            } else {
 
1165
                fi->actions[i] = FA_CREATE;
 
1166
            }
 
1167
          } break;
 
1168
        case TR_REMOVED:
 
1169
            if (otherPkgNum >= 0) {
 
1170
                /* Here is an overlapped added file we don't want to nuke. */
 
1171
                if (recs[otherPkgNum]->actions[otherFileNum] != FA_ERASE) {
 
1172
                    /* On updates, don't remove files. */
 
1173
                    fi->actions[i] = FA_SKIP;
 
1174
                    break;
 
1175
                }
 
1176
                /* Here is an overlapped removed file: skip in previous. */
 
1177
                recs[otherPkgNum]->actions[otherFileNum] = FA_SKIP;
 
1178
            }
 
1179
            if (XFA_SKIPPING(fi->actions[i]))
 
1180
                break;
 
1181
            if (fi->fstates && fi->fstates[i] != RPMFILE_STATE_NORMAL)
 
1182
                break;
 
1183
            if (!(S_ISREG(fi->fmodes[i]) && (fi->fflags[i] & RPMFILE_CONFIG))) {
 
1184
                fi->actions[i] = FA_ERASE;
 
1185
                break;
 
1186
            }
 
1187
                
 
1188
            /* Here is a pre-existing modified config file that needs saving. */
 
1189
            {   char mdsum[50];
 
1190
                if (!mdfile(filespec, mdsum) && strcmp(fi->fmd5s[i], mdsum)) {
 
1191
                    fi->actions[i] = FA_BACKUP;
 
1192
                    break;
 
1193
                }
 
1194
            }
 
1195
            fi->actions[i] = FA_ERASE;
 
1196
            break;
 
1197
        }
 
1198
 
 
1199
        if (ds) {
 
1200
            uint_32 s = BLOCK_ROUND(fi->fsizes[i], ds->bsize);
 
1201
 
 
1202
            switch (fi->actions[i]) {
 
1203
              case FA_BACKUP:
 
1204
              case FA_SAVE:
 
1205
              case FA_ALTNAME:
 
1206
                ds->ineeded++;
 
1207
                ds->bneeded += s;
 
1208
                break;
 
1209
 
 
1210
            /*
 
1211
             * FIXME: If two packages share a file (same md5sum), and
 
1212
             * that file is being replaced on disk, will ds->bneeded get
 
1213
             * decremented twice? Quite probably!
 
1214
             */
 
1215
              case FA_CREATE:
 
1216
                ds->bneeded += s;
 
1217
                ds->bneeded -= BLOCK_ROUND(fi->replacedSizes[i], ds->bsize);
 
1218
                break;
 
1219
 
 
1220
              case FA_ERASE:
 
1221
                ds->ineeded--;
 
1222
                ds->bneeded -= s;
 
1223
                break;
 
1224
 
 
1225
              default:
 
1226
                break;
 
1227
            }
 
1228
 
 
1229
            ds->bneeded -= BLOCK_ROUND(fixupSize, ds->bsize);
 
1230
        }
 
1231
    }
 
1232
    if (filespec) free(filespec);
 
1233
}
 
1234
 
 
1235
static int ensureOlder(struct availablePackage * alp, Header old,
 
1236
                rpmProblemSet probs)
 
1237
        /*@modifies alp, probs @*/
 
1238
{
 
1239
    int result, rc = 0;
 
1240
 
 
1241
    if (old == NULL) return 1;
 
1242
 
 
1243
    result = rpmVersionCompare(old, alp->h);
 
1244
    if (result <= 0)
 
1245
        rc = 0;
 
1246
    else if (result > 0) {
 
1247
        rc = 1;
 
1248
        psAppend(probs, RPMPROB_OLDPACKAGE, alp, NULL, NULL, old, 0);
 
1249
    }
 
1250
 
 
1251
    return rc;
 
1252
}
 
1253
 
 
1254
static void skipFiles(const rpmTransactionSet ts, TFI_t fi)
 
1255
        /*@modifies fi @*/
 
1256
{
 
1257
    int noDocs = (ts->transFlags & RPMTRANS_FLAG_NODOCS);
 
1258
    char ** netsharedPaths = NULL;
 
1259
    const char ** languages;
 
1260
    const char * dn, * bn;
 
1261
    int dnlen, bnlen, ix;
 
1262
    const char * s;
 
1263
    int * drc;
 
1264
    char * dff;
 
1265
    int i, j;
 
1266
 
 
1267
    if (!noDocs)
 
1268
        noDocs = rpmExpandNumeric("%{_excludedocs}");
 
1269
 
 
1270
    {   const char *tmpPath = rpmExpand("%{_netsharedpath}", NULL);
 
1271
        if (tmpPath && *tmpPath != '%')
 
1272
            netsharedPaths = splitString(tmpPath, strlen(tmpPath), ':');
 
1273
        tmpPath = _free(tmpPath);
 
1274
    }
 
1275
 
 
1276
    s = rpmExpand("%{_install_langs}", NULL);
 
1277
    if (!(s && *s != '%'))
 
1278
        s = _free(s);
 
1279
    if (s) {
 
1280
        languages = (const char **) splitString(s, strlen(s), ':');
 
1281
        s = _free(s);
 
1282
    } else
 
1283
        languages = NULL;
 
1284
 
 
1285
    /* Compute directory refcount, skip directory if now empty. */
 
1286
    drc = alloca(fi->dc * sizeof(*drc));
 
1287
    memset(drc, 0, fi->dc * sizeof(*drc));
 
1288
    dff = alloca(fi->dc * sizeof(*dff));
 
1289
    memset(dff, 0, fi->dc * sizeof(*dff));
 
1290
 
 
1291
    for (i = 0; i < fi->fc; i++) {
 
1292
        char **nsp;
 
1293
 
 
1294
        bn = fi->bnl[i];
 
1295
        bnlen = strlen(bn);
 
1296
        ix = fi->dil[i];
 
1297
        dn = fi->dnl[ix];
 
1298
        dnlen = strlen(dn);
 
1299
 
 
1300
        drc[ix]++;
 
1301
 
 
1302
        /* Don't bother with skipped files */
 
1303
        if (XFA_SKIPPING(fi->actions[i])) {
 
1304
            drc[ix]--;
 
1305
            continue;
 
1306
        }
 
1307
 
 
1308
        /*
 
1309
         * Skip net shared paths.
 
1310
         * Net shared paths are not relative to the current root (though
 
1311
         * they do need to take package relocations into account).
 
1312
         */
 
1313
        for (nsp = netsharedPaths; nsp && *nsp; nsp++) {
 
1314
            int len;
 
1315
 
 
1316
            len = strlen(*nsp);
 
1317
            if (dnlen >= len) {
 
1318
                if (strncmp(dn, *nsp, len)) continue;
 
1319
                /* Only directories or complete file paths can be net shared */
 
1320
                if (!(dn[len] == '/' || dn[len] == '\0')) continue;
 
1321
            } else {
 
1322
                if (len < (dnlen + bnlen)) continue;
 
1323
                if (strncmp(dn, *nsp, dnlen)) continue;
 
1324
                if (strncmp(bn, (*nsp) + dnlen, bnlen)) continue;
 
1325
                len = dnlen + bnlen;
 
1326
                /* Only directories or complete file paths can be net shared */
 
1327
                if (!((*nsp)[len] == '/' || (*nsp)[len] == '\0')) continue;
 
1328
            }
 
1329
 
 
1330
            /*@innerbreak@*/ break;
 
1331
        }
 
1332
 
 
1333
        if (nsp && *nsp) {
 
1334
            drc[ix]--;  dff[ix] = 1;
 
1335
            fi->actions[i] = FA_SKIPNETSHARED;
 
1336
            continue;
 
1337
        }
 
1338
 
 
1339
        /*
 
1340
         * Skip i18n language specific files.
 
1341
         */
 
1342
        if (fi->flangs && languages && *fi->flangs[i]) {
 
1343
            const char **lang, *l, *le;
 
1344
            for (lang = languages; *lang != '\0'; lang++) {
 
1345
                if (!strcmp(*lang, "all"))
 
1346
                    /*@innerbreak@*/ break;
 
1347
                for (l = fi->flangs[i]; *l != '\0'; l = le) {
 
1348
                    for (le = l; *le != '\0' && *le != '|'; le++)
 
1349
                        {};
 
1350
                    if ((le-l) > 0 && !strncmp(*lang, l, (le-l)))
 
1351
                        /*@innerbreak@*/ break;
 
1352
                    if (*le == '|') le++;       /* skip over | */
 
1353
                }
 
1354
                if (*l != '\0')
 
1355
                    /*@innerbreak@*/ break;
 
1356
            }
 
1357
            if (*lang == NULL) {
 
1358
                drc[ix]--;      dff[ix] = 1;
 
1359
                fi->actions[i] = FA_SKIPNSTATE;
 
1360
                continue;
 
1361
            }
 
1362
        }
 
1363
 
 
1364
        /*
 
1365
         * Skip documentation if requested.
 
1366
         */
 
1367
        if (noDocs && (fi->fflags[i] & RPMFILE_DOC)) {
 
1368
            drc[ix]--;  dff[ix] = 1;
 
1369
            fi->actions[i] = FA_SKIPNSTATE;
 
1370
            continue;
 
1371
        }
 
1372
    }
 
1373
 
 
1374
    /* Skip (now empty) directories that had skipped files. */
 
1375
    for (j = 0; j < fi->dc; j++) {
 
1376
 
 
1377
        if (drc[j]) continue;   /* dir still has files. */
 
1378
        if (!dff[j]) continue;  /* dir was not emptied here. */
 
1379
        
 
1380
        /* Find parent directory and basename. */
 
1381
        dn = fi->dnl[j];        dnlen = strlen(dn) - 1;
 
1382
        bn = dn + dnlen;        bnlen = 0;
 
1383
        while (bn > dn && bn[-1] != '/') {
 
1384
                bnlen++;
 
1385
                dnlen--;
 
1386
                bn--;
 
1387
        }
 
1388
 
 
1389
        /* If explicitly included in the package, skip the directory. */
 
1390
        for (i = 0; i < fi->fc; i++) {
 
1391
            const char * dir;
 
1392
 
 
1393
            if (XFA_SKIPPING(fi->actions[i]))
 
1394
                continue;
 
1395
            if (whatis(fi->fmodes[i]) != XDIR)
 
1396
                continue;
 
1397
            dir = fi->dnl[fi->dil[i]];
 
1398
            if (strlen(dir) != dnlen)
 
1399
                continue;
 
1400
            if (strncmp(dir, dn, dnlen))
 
1401
                continue;
 
1402
            if (strlen(fi->bnl[i]) != bnlen)
 
1403
                continue;
 
1404
            if (strncmp(fi->bnl[i], bn, bnlen))
 
1405
                continue;
 
1406
            rpmMessage(RPMMESS_DEBUG, _("excluding directory %s\n"), dn);
 
1407
            fi->actions[i] = FA_SKIPNSTATE;
 
1408
            /*@innerbreak@*/ break;
 
1409
        }
 
1410
    }
 
1411
 
 
1412
    if (netsharedPaths) freeSplitString(netsharedPaths);
 
1413
#ifdef  DYING   /* XXX freeFi will deal with this later. */
 
1414
    fi->flangs = _free(fi->flangs);
 
1415
#endif
 
1416
    if (languages) freeSplitString((char **)languages);
 
1417
}
 
1418
 
 
1419
/**
 
1420
 * Iterator across transaction elements, forward on install, backward on erase.
 
1421
 */
 
1422
struct tsIterator_s {
 
1423
/*@kept@*/ rpmTransactionSet ts;        /*!< transaction set. */
 
1424
    int reverse;                        /*!< reversed traversal? */
 
1425
    int ocsave;                         /*!< last returned iterator index. */
 
1426
    int oc;                             /*!< iterator index. */
 
1427
};
 
1428
 
 
1429
/**
 
1430
 * Return transaction element order count.
 
1431
 * @param a             transaction element iterator
 
1432
 * @return              element order count
 
1433
 */
 
1434
static int tsGetOc(void * a)
 
1435
        /*@*/
 
1436
{
 
1437
    struct tsIterator_s * iter = a;
 
1438
    int oc = iter->ocsave;
 
1439
    return oc;
 
1440
}
 
1441
 
 
1442
/**
 
1443
 * Return transaction element available package pointer.
 
1444
 * @param a             transaction element iterator
 
1445
 * @return              available package pointer
 
1446
 */
 
1447
static /*@dependent@*/ struct availablePackage * tsGetAlp(void * a)
 
1448
        /*@*/
 
1449
{
 
1450
    struct tsIterator_s * iter = a;
 
1451
    struct availablePackage * alp = NULL;
 
1452
    int oc = iter->ocsave;
 
1453
 
 
1454
    if (oc != -1) {
 
1455
        rpmTransactionSet ts = iter->ts;
 
1456
        TFI_t fi = ts->flList + oc;
 
1457
        if (ts->addedPackages.list && fi->type == TR_ADDED)
 
1458
            alp = ts->addedPackages.list + ts->order[oc].u.addedIndex;
 
1459
    }
 
1460
    return alp;
 
1461
}
 
1462
 
 
1463
/**
 
1464
 * Destroy transaction element iterator.
 
1465
 * @param a             transaction element iterator
 
1466
 * @return              NULL always
 
1467
 */
 
1468
static /*@null@*/ void * tsFreeIterator(/*@only@*//*@null@*/ const void * a)
 
1469
        /*@modifies a @*/
 
1470
{
 
1471
    return _free(a);
 
1472
}
 
1473
 
 
1474
/**
 
1475
 * Create transaction element iterator.
 
1476
 * @param a             transaction set
 
1477
 * @return              transaction element iterator
 
1478
 */
 
1479
static void * tsInitIterator(/*@kept@*/ const void * a)
 
1480
        /*@*/
 
1481
{
 
1482
    rpmTransactionSet ts = (void *)a;
 
1483
    struct tsIterator_s * iter = NULL;
 
1484
 
 
1485
    iter = xcalloc(1, sizeof(*iter));
 
1486
    iter->ts = ts;
 
1487
    iter->reverse = ((ts->transFlags & RPMTRANS_FLAG_REVERSE) ? 1 : 0);
 
1488
    iter->oc = (iter->reverse ? (ts->orderCount - 1) : 0);
 
1489
    iter->ocsave = iter->oc;
 
1490
    return iter;
 
1491
}
 
1492
 
 
1493
/**
 
1494
 * Return next transaction element's file info.
 
1495
 * @param a             file info iterator
 
1496
 * @return              next index, -1 on termination
 
1497
 */
 
1498
static /*@dependent@*/ TFI_t tsNextIterator(void * a)
 
1499
        /*@*/
 
1500
{
 
1501
    struct tsIterator_s * iter = a;
 
1502
    rpmTransactionSet ts = iter->ts;
 
1503
    TFI_t fi = NULL;
 
1504
    int oc = -1;
 
1505
 
 
1506
    if (iter->reverse) {
 
1507
        if (iter->oc >= 0)              oc = iter->oc--;
 
1508
    } else {
 
1509
        if (iter->oc < ts->orderCount)  oc = iter->oc++;
 
1510
    }
 
1511
    iter->ocsave = oc;
 
1512
    if (oc != -1)
 
1513
        fi = ts->flList + oc;
 
1514
    return fi;
 
1515
}
 
1516
 
 
1517
#define NOTIFY(_ts, _al)        if ((_ts)->notify) (void) (_ts)->notify _al
 
1518
 
 
1519
int rpmRunTransactions( rpmTransactionSet ts,
 
1520
                        rpmCallbackFunction notify, rpmCallbackData notifyData,
 
1521
                        rpmProblemSet okProbs, rpmProblemSet * newProbs,
 
1522
                        rpmtransFlags transFlags, rpmprobFilterFlags ignoreSet)
 
1523
{
 
1524
    int i, j;
 
1525
    int ourrc = 0;
 
1526
    struct availablePackage * alp;
 
1527
#ifdef  DYING
 
1528
    Header * hdrs;
 
1529
#endif
 
1530
    int totalFileCount = 0;
 
1531
    hashTable ht;
 
1532
    TFI_t fi;
 
1533
    struct diskspaceInfo * dip;
 
1534
    struct sharedFileInfo * shared, * sharedList;
 
1535
    int numShared;
 
1536
    int nexti;
 
1537
    int lastFailed;
 
1538
    int oc;
 
1539
    fingerPrintCache fpc;
 
1540
    struct psm_s psmbuf;
 
1541
    PSM_t psm = &psmbuf;
 
1542
    void * tsi;
 
1543
 
 
1544
    /* FIXME: what if the same package is included in ts twice? */
 
1545
 
 
1546
    ts->transFlags = transFlags;
 
1547
    if (ts->transFlags & RPMTRANS_FLAG_NOSCRIPTS)
 
1548
        ts->transFlags |= (_noTransScripts | _noTransTriggers);
 
1549
    if (ts->transFlags & RPMTRANS_FLAG_NOTRIGGERS)
 
1550
        ts->transFlags |= _noTransTriggers;
 
1551
 
 
1552
    /* XXX MULTILIB is broken, as packages can and do execute /sbin/ldconfig. */
 
1553
    if (ts->transFlags & (RPMTRANS_FLAG_JUSTDB | RPMTRANS_FLAG_MULTILIB))
 
1554
        ts->transFlags |= (_noTransScripts | _noTransTriggers);
 
1555
 
 
1556
    ts->notify = notify;
 
1557
    ts->notifyData = notifyData;
 
1558
    /*@-assignexpose@*/
 
1559
    ts->probs = *newProbs = psCreate();
 
1560
    /*@=assignexpose@*/
 
1561
    ts->ignoreSet = ignoreSet;
 
1562
    ts->currDir = _free(ts->currDir);
 
1563
    ts->currDir = currentDirectory();
 
1564
    ts->chrootDone = 0;
 
1565
    if (ts->rpmdb) ts->rpmdb->db_chrootDone = 0;
 
1566
    ts->id = (int_32) time(NULL);
 
1567
 
 
1568
    memset(psm, 0, sizeof(*psm));
 
1569
    /*@-assignexpose@*/
 
1570
    psm->ts = ts;
 
1571
    /*@=assignexpose@*/
 
1572
 
 
1573
    /* Get available space on mounted file systems. */
 
1574
    if (!(ts->ignoreSet & RPMPROB_FILTER_DISKSPACE) &&
 
1575
                !rpmGetFilesystemList(&ts->filesystems, &ts->filesystemCount)) {
 
1576
        struct stat sb;
 
1577
 
 
1578
        ts->di = _free(ts->di);
 
1579
        dip = ts->di = xcalloc(sizeof(*ts->di), ts->filesystemCount + 1);
 
1580
 
 
1581
        for (i = 0; (i < ts->filesystemCount) && dip; i++) {
 
1582
#if STATFS_IN_SYS_STATVFS
 
1583
            struct statvfs sfb;
 
1584
            memset(&sfb, 0, sizeof(sfb));
 
1585
            if (statvfs(ts->filesystems[i], &sfb))
 
1586
#else
 
1587
            struct statfs sfb;
 
1588
#  if STAT_STATFS4
 
1589
/* This platform has the 4-argument version of the statfs call.  The last two
 
1590
 * should be the size of struct statfs and 0, respectively.  The 0 is the
 
1591
 * filesystem type, and is always 0 when statfs is called on a mounted
 
1592
 * filesystem, as we're doing.
 
1593
 */
 
1594
            memset(&sfb, 0, sizeof(sfb));
 
1595
            if (statfs(ts->filesystems[i], &sfb, sizeof(sfb), 0))
 
1596
#  else
 
1597
            memset(&sfb, 0, sizeof(sfb));
 
1598
            if (statfs(ts->filesystems[i], &sfb))
 
1599
#  endif
 
1600
#endif
 
1601
            {
 
1602
                dip = NULL;
 
1603
            } else {
 
1604
                ts->di[i].bsize = sfb.f_bsize;
 
1605
                ts->di[i].bneeded = 0;
 
1606
                ts->di[i].ineeded = 0;
 
1607
#ifdef STATFS_HAS_F_BAVAIL
 
1608
                ts->di[i].bavail = sfb.f_bavail;
 
1609
#else
 
1610
/* FIXME: the statfs struct doesn't have a member to tell how many blocks are
 
1611
 * available for non-superusers.  f_blocks - f_bfree is probably too big, but
 
1612
 * it's about all we can do.
 
1613
 */
 
1614
                ts->di[i].bavail = sfb.f_blocks - sfb.f_bfree;
 
1615
#endif
 
1616
                /* XXX Avoid FAT and other file systems that have not inodes. */
 
1617
                ts->di[i].iavail = !(sfb.f_ffree == 0 && sfb.f_files == 0)
 
1618
                                ? sfb.f_ffree : -1;
 
1619
 
 
1620
                (void) stat(ts->filesystems[i], &sb);
 
1621
                ts->di[i].dev = sb.st_dev;
 
1622
            }
 
1623
        }
 
1624
 
 
1625
        if (dip) ts->di[i].bsize = 0;
 
1626
    }
 
1627
 
 
1628
#ifdef  DYING
 
1629
    hdrs = alloca(sizeof(*hdrs) * ts->addedPackages.size);
 
1630
#endif
 
1631
 
 
1632
    /* ===============================================
 
1633
     * For packages being installed:
 
1634
     * - verify package arch/os.
 
1635
     * - verify package epoch:version-release is newer.
 
1636
     * - count files.
 
1637
     * For packages being removed:
 
1638
     * - count files.
 
1639
     */
 
1640
    /* The ordering doesn't matter here */
 
1641
    if (ts->addedPackages.list != NULL)
 
1642
    for (alp = ts->addedPackages.list;
 
1643
        (alp - ts->addedPackages.list) < ts->addedPackages.size;
 
1644
        alp++)
 
1645
    {
 
1646
        if (!archOkay(alp->h) && !(ts->ignoreSet & RPMPROB_FILTER_IGNOREARCH))
 
1647
            psAppend(ts->probs, RPMPROB_BADARCH, alp, NULL, NULL, NULL, 0);
 
1648
 
 
1649
        if (!osOkay(alp->h) && !(ts->ignoreSet & RPMPROB_FILTER_IGNOREOS))
 
1650
            psAppend(ts->probs, RPMPROB_BADOS, alp, NULL, NULL, NULL, 0);
 
1651
 
 
1652
        if (!(ts->ignoreSet & RPMPROB_FILTER_OLDPACKAGE)) {
 
1653
            rpmdbMatchIterator mi;
 
1654
            Header oldH;
 
1655
            mi = rpmdbInitIterator(ts->rpmdb, RPMTAG_NAME, alp->name, 0);
 
1656
            while ((oldH = rpmdbNextIterator(mi)) != NULL)
 
1657
                (void) ensureOlder(alp, oldH, ts->probs);
 
1658
            mi = rpmdbFreeIterator(mi);
 
1659
        }
 
1660
 
 
1661
        /* XXX multilib should not display "already installed" problems */
 
1662
        if (!(ts->ignoreSet & RPMPROB_FILTER_REPLACEPKG) && !alp->multiLib) {
 
1663
            rpmdbMatchIterator mi;
 
1664
            mi = rpmdbInitIterator(ts->rpmdb, RPMTAG_NAME, alp->name, 0);
 
1665
            (void) rpmdbSetIteratorRE(mi, RPMTAG_VERSION,
 
1666
                        RPMMIRE_DEFAULT, alp->version);
 
1667
            (void) rpmdbSetIteratorRE(mi, RPMTAG_RELEASE,
 
1668
                        RPMMIRE_DEFAULT, alp->release);
 
1669
 
 
1670
            while (rpmdbNextIterator(mi) != NULL) {
 
1671
                psAppend(ts->probs, RPMPROB_PKG_INSTALLED, alp,
 
1672
                        NULL, NULL, NULL, 0);
 
1673
                /*@innerbreak@*/ break;
 
1674
            }
 
1675
            mi = rpmdbFreeIterator(mi);
 
1676
        }
 
1677
 
 
1678
        totalFileCount += alp->filesCount;
 
1679
 
 
1680
    }
 
1681
 
 
1682
    /* FIXME: it seems a bit silly to read in all of these headers twice */
 
1683
    /* The ordering doesn't matter here */
 
1684
    if (ts->numRemovedPackages > 0) {
 
1685
        rpmdbMatchIterator mi;
 
1686
        Header h;
 
1687
        int fileCount;
 
1688
 
 
1689
        mi = rpmdbInitIterator(ts->rpmdb, RPMDBI_PACKAGES, NULL, 0);
 
1690
        (void) rpmdbAppendIterator(mi, ts->removedPackages, ts->numRemovedPackages);
 
1691
        while ((h = rpmdbNextIterator(mi)) != NULL) {
 
1692
            if (headerGetEntry(h, RPMTAG_BASENAMES, NULL, NULL, &fileCount))
 
1693
                totalFileCount += fileCount;
 
1694
        }
 
1695
        mi = rpmdbFreeIterator(mi);
 
1696
    }
 
1697
 
 
1698
    /* ===============================================
 
1699
     * Initialize file list:
 
1700
     */
 
1701
    ts->flEntries = ts->addedPackages.size + ts->numRemovedPackages;
 
1702
    ts->flList = xcalloc(ts->flEntries, sizeof(*ts->flList));
 
1703
 
 
1704
    /*
 
1705
     * FIXME?: we'd be better off assembling one very large file list and
 
1706
     * calling fpLookupList only once. I'm not sure that the speedup is
 
1707
     * worth the trouble though.
 
1708
     */
 
1709
    tsi = tsInitIterator(ts);
 
1710
    while ((fi = tsNextIterator(tsi)) != NULL) {
 
1711
        oc = tsGetOc(tsi);
 
1712
        fi->magic = TFIMAGIC;
 
1713
 
 
1714
        /* XXX watchout: fi->type must be set for tsGetAlp() to "work" */
 
1715
        fi->type = ts->order[oc].type;
 
1716
        switch (fi->type) {
 
1717
        case TR_ADDED:
 
1718
            i = ts->order[oc].u.addedIndex;
 
1719
            /* XXX watchout: fi->type must be set for tsGetAlp() to "work" */
 
1720
            fi->ap = tsGetAlp(tsi);
 
1721
            fi->record = 0;
 
1722
            loadFi(fi->ap->h, fi);
 
1723
            if (fi->fc == 0) {
 
1724
#ifdef  DYING
 
1725
                hdrs[i] = headerLink(fi->h);
 
1726
#endif
 
1727
                continue;
 
1728
            }
 
1729
 
 
1730
#ifdef  DYING
 
1731
            /* Allocate file actions (and initialize to FA_UNKNOWN) */
 
1732
            fi->actions = xcalloc(fi->fc, sizeof(*fi->actions));
 
1733
            hdrs[i] = relocateFileList(ts, fi, fi->ap, fi->h, fi->actions);
 
1734
#else
 
1735
            {   Header foo = relocateFileList(ts, fi, fi->ap, fi->h, fi->actions);
 
1736
                foo = headerFree(foo);
 
1737
            }
 
1738
#endif
 
1739
 
 
1740
            /* Skip netshared paths, not our i18n files, and excluded docs */
 
1741
            skipFiles(ts, fi);
 
1742
            break;
 
1743
        case TR_REMOVED:
 
1744
            fi->ap = NULL;
 
1745
            fi->record = ts->order[oc].u.removed.dboffset;
 
1746
            {   rpmdbMatchIterator mi;
 
1747
 
 
1748
                mi = rpmdbInitIterator(ts->rpmdb, RPMDBI_PACKAGES,
 
1749
                                &fi->record, sizeof(fi->record));
 
1750
                if ((fi->h = rpmdbNextIterator(mi)) != NULL)
 
1751
                    fi->h = headerLink(fi->h);
 
1752
                mi = rpmdbFreeIterator(mi);
 
1753
            }
 
1754
            if (fi->h == NULL) {
 
1755
                /* ACK! */
 
1756
                continue;
 
1757
            }
 
1758
            /* XXX header arg unused. */
 
1759
            loadFi(fi->h, fi);
 
1760
            break;
 
1761
        }
 
1762
 
 
1763
        if (fi->fc)
 
1764
            fi->fps = xmalloc(fi->fc * sizeof(*fi->fps));
 
1765
    }
 
1766
    tsi = tsFreeIterator(tsi);
 
1767
 
 
1768
#ifdef  DYING
 
1769
    /* Open all database indices before installing. */
 
1770
    (void) rpmdbOpenAll(ts->rpmdb);
 
1771
#endif
 
1772
 
 
1773
    if (!ts->chrootDone) {
 
1774
        (void) chdir("/");
 
1775
        /*@-unrecog -superuser @*/
 
1776
        (void) chroot(ts->rootDir);
 
1777
        /*@=unrecog =superuser @*/
 
1778
        ts->chrootDone = 1;
 
1779
        if (ts->rpmdb) ts->rpmdb->db_chrootDone = 1;
 
1780
        /*@-onlytrans@*/
 
1781
        chroot_prefix = ts->rootDir;
 
1782
        /*@=onlytrans@*/
 
1783
    }
 
1784
 
 
1785
    ht = htCreate(totalFileCount * 2, 0, 0, fpHashFunction, fpEqual);
 
1786
    fpc = fpCacheCreate(totalFileCount);
 
1787
 
 
1788
    /* ===============================================
 
1789
     * Add fingerprint for each file not skipped.
 
1790
     */
 
1791
    tsi = tsInitIterator(ts);
 
1792
    while ((fi = tsNextIterator(tsi)) != NULL) {
 
1793
        fpLookupList(fpc, fi->dnl, fi->bnl, fi->dil, fi->fc, fi->fps);
 
1794
        for (i = 0; i < fi->fc; i++) {
 
1795
            if (XFA_SKIPPING(fi->actions[i]))
 
1796
                continue;
 
1797
            /*@-dependenttrans@*/
 
1798
            htAddEntry(ht, fi->fps + i, fi);
 
1799
            /*@=dependenttrans@*/
 
1800
        }
 
1801
    }
 
1802
    tsi = tsFreeIterator(tsi);
 
1803
 
 
1804
    /*@-moduncon@*/
 
1805
    NOTIFY(ts, (NULL, RPMCALLBACK_TRANS_START, 6, ts->flEntries,
 
1806
        NULL, ts->notifyData));
 
1807
    /*@=moduncon@*/
 
1808
 
 
1809
    /* ===============================================
 
1810
     * Compute file disposition for each package in transaction set.
 
1811
     */
 
1812
    tsi = tsInitIterator(ts);
 
1813
    while ((fi = tsNextIterator(tsi)) != NULL) {
 
1814
        dbiIndexSet * matches;
 
1815
        int knownBad;
 
1816
 
 
1817
        /*@-moduncon@*/
 
1818
        NOTIFY(ts, (NULL, RPMCALLBACK_TRANS_PROGRESS, (fi - ts->flList),
 
1819
                        ts->flEntries, NULL, ts->notifyData));
 
1820
        /*@=moduncon@*/
 
1821
 
 
1822
        if (fi->fc == 0) continue;
 
1823
 
 
1824
        /* Extract file info for all files in this package from the database. */
 
1825
        matches = xcalloc(sizeof(*matches), fi->fc);
 
1826
        if (rpmdbFindFpList(ts->rpmdb, fi->fps, matches, fi->fc))
 
1827
            return 1;   /* XXX WTFO? */
 
1828
 
 
1829
        numShared = 0;
 
1830
        for (i = 0; i < fi->fc; i++)
 
1831
            numShared += dbiIndexSetCount(matches[i]);
 
1832
 
 
1833
        /* Build sorted file info list for this package. */
 
1834
        shared = sharedList = xmalloc((numShared + 1) * sizeof(*sharedList));
 
1835
        for (i = 0; i < fi->fc; i++) {
 
1836
            /*
 
1837
             * Take care not to mark files as replaced in packages that will
 
1838
             * have been removed before we will get here.
 
1839
             */
 
1840
            for (j = 0; j < dbiIndexSetCount(matches[i]); j++) {
 
1841
                int k, ro;
 
1842
                ro = dbiIndexRecordOffset(matches[i], j);
 
1843
                knownBad = 0;
 
1844
                for (k = 0; ro != knownBad && k < ts->orderCount; k++) {
 
1845
                    switch (ts->order[k].type) {
 
1846
                    case TR_REMOVED:
 
1847
                        if (ts->order[k].u.removed.dboffset == ro)
 
1848
                            knownBad = ro;
 
1849
                        break;
 
1850
                    case TR_ADDED:
 
1851
                        break;
 
1852
                    }
 
1853
                }
 
1854
 
 
1855
                shared->pkgFileNum = i;
 
1856
                shared->otherPkg = dbiIndexRecordOffset(matches[i], j);
 
1857
                shared->otherFileNum = dbiIndexRecordFileNumber(matches[i], j);
 
1858
                shared->isRemoved = (knownBad == ro);
 
1859
                shared++;
 
1860
            }
 
1861
            matches[i] = dbiFreeIndexSet(matches[i]);
 
1862
        }
 
1863
        numShared = shared - sharedList;
 
1864
        shared->otherPkg = -1;
 
1865
        matches = _free(matches);
 
1866
 
 
1867
        /* Sort file info by other package index (otherPkg) */
 
1868
        qsort(sharedList, numShared, sizeof(*shared), sharedCmp);
 
1869
 
 
1870
        /* For all files from this package that are in the database ... */
 
1871
        for (i = 0; i < numShared; i = nexti) {
 
1872
            int beingRemoved;
 
1873
 
 
1874
            shared = sharedList + i;
 
1875
 
 
1876
            /* Find the end of the files in the other package. */
 
1877
            for (nexti = i + 1; nexti < numShared; nexti++) {
 
1878
                if (sharedList[nexti].otherPkg != shared->otherPkg)
 
1879
                    /*@innerbreak@*/ break;
 
1880
            }
 
1881
 
 
1882
            /* Is this file from a package being removed? */
 
1883
            beingRemoved = 0;
 
1884
            for (j = 0; j < ts->numRemovedPackages; j++) {
 
1885
                if (ts->removedPackages[j] != shared->otherPkg)
 
1886
                    continue;
 
1887
                beingRemoved = 1;
 
1888
                /*@innerbreak@*/ break;
 
1889
            }
 
1890
 
 
1891
            /* Determine the fate of each file. */
 
1892
            switch (fi->type) {
 
1893
            case TR_ADDED:
 
1894
                (void) handleInstInstalledFiles(fi, ts->rpmdb, shared, nexti - i,
 
1895
                !(beingRemoved || (ts->ignoreSet & RPMPROB_FILTER_REPLACEOLDFILES)),
 
1896
                         ts->probs, ts->transFlags);
 
1897
                break;
 
1898
            case TR_REMOVED:
 
1899
                if (!beingRemoved)
 
1900
                    (void) handleRmvdInstalledFiles(fi, ts->rpmdb, shared, nexti - i);
 
1901
                break;
 
1902
            }
 
1903
        }
 
1904
 
 
1905
        free(sharedList);
 
1906
 
 
1907
        /* Update disk space needs on each partition for this package. */
 
1908
        handleOverlappedFiles(fi, ht,
 
1909
               ((ts->ignoreSet & RPMPROB_FILTER_REPLACENEWFILES)
 
1910
                    ? NULL : ts->probs), ts->di);
 
1911
 
 
1912
        /* Check added package has sufficient space on each partition used. */
 
1913
        switch (fi->type) {
 
1914
        case TR_ADDED:
 
1915
            if (!(ts->di && fi->fc))
 
1916
                break;
 
1917
            for (i = 0; i < ts->filesystemCount; i++) {
 
1918
 
 
1919
                dip = ts->di + i;
 
1920
 
 
1921
                /* XXX Avoid FAT and other file systems that have not inodes. */
 
1922
                if (dip->iavail <= 0)
 
1923
                    continue;
 
1924
 
 
1925
                if (adj_fs_blocks(dip->bneeded) > dip->bavail)
 
1926
                    psAppend(ts->probs, RPMPROB_DISKSPACE, fi->ap,
 
1927
                                ts->filesystems[i], NULL, NULL,
 
1928
                   (adj_fs_blocks(dip->bneeded) - dip->bavail) * dip->bsize);
 
1929
 
 
1930
                if (adj_fs_blocks(dip->ineeded) > dip->iavail)
 
1931
                    psAppend(ts->probs, RPMPROB_DISKNODES, fi->ap,
 
1932
                                ts->filesystems[i], NULL, NULL,
 
1933
                    (adj_fs_blocks(dip->ineeded) - dip->iavail));
 
1934
            }
 
1935
            break;
 
1936
        case TR_REMOVED:
 
1937
            break;
 
1938
        }
 
1939
    }
 
1940
    tsi = tsFreeIterator(tsi);
 
1941
 
 
1942
    if (ts->chrootDone) {
 
1943
        /*@-unrecog -superuser @*/
 
1944
        (void) chroot(".");
 
1945
        /*@=unrecog =superuser @*/
 
1946
        ts->chrootDone = 0;
 
1947
        if (ts->rpmdb) ts->rpmdb->db_chrootDone = 0;
 
1948
        chroot_prefix = NULL;
 
1949
        (void) chdir(ts->currDir);
 
1950
    }
 
1951
 
 
1952
    /*@-moduncon@*/
 
1953
    NOTIFY(ts, (NULL, RPMCALLBACK_TRANS_STOP, 6, ts->flEntries,
 
1954
        NULL, ts->notifyData));
 
1955
    /*@=moduncon@*/
 
1956
 
 
1957
    /* ===============================================
 
1958
     * Free unused memory as soon as possible.
 
1959
     */
 
1960
 
 
1961
    tsi = tsInitIterator(ts);
 
1962
    while ((fi = tsNextIterator(tsi)) != NULL) {
 
1963
        psm->fi = fi;
 
1964
        if (fi->fc == 0)
 
1965
            continue;
 
1966
        fi->fps = _free(fi->fps);
 
1967
    }
 
1968
    tsi = tsFreeIterator(tsi);
 
1969
 
 
1970
    fpCacheFree(fpc);
 
1971
    htFree(ht);
 
1972
 
 
1973
    /* ===============================================
 
1974
     * If unfiltered problems exist, free memory and return.
 
1975
     */
 
1976
    if ((ts->transFlags & RPMTRANS_FLAG_BUILD_PROBS) ||
 
1977
           (ts->probs->numProblems && (!okProbs || psTrim(okProbs, ts->probs))))
 
1978
    {
 
1979
        *newProbs = ts->probs;
 
1980
 
 
1981
#ifdef  DYING
 
1982
        for (alp = ts->addedPackages.list, fi = ts->flList;
 
1983
                (alp - ts->addedPackages.list) < ts->addedPackages.size;
 
1984
                alp++, fi++)
 
1985
        {
 
1986
            hdrs[alp - ts->addedPackages.list] =
 
1987
                headerFree(hdrs[alp - ts->addedPackages.list]);
 
1988
        }
 
1989
#endif
 
1990
 
 
1991
        ts->flList = freeFl(ts, ts->flList);
 
1992
        ts->flEntries = 0;
 
1993
        /*@-nullstate@*/
 
1994
        return ts->orderCount;
 
1995
        /*@=nullstate@*/
 
1996
    }
 
1997
 
 
1998
    /* ===============================================
 
1999
     * Save removed files before erasing.
 
2000
     */
 
2001
    if (ts->transFlags & (RPMTRANS_FLAG_DIRSTASH | RPMTRANS_FLAG_REPACKAGE)) {
 
2002
        tsi = tsInitIterator(ts);
 
2003
        while ((fi = tsNextIterator(tsi)) != NULL) {
 
2004
            psm->fi = fi;
 
2005
            switch (fi->type) {
 
2006
            case TR_ADDED:
 
2007
                break;
 
2008
            case TR_REMOVED:
 
2009
                if (ts->transFlags & RPMTRANS_FLAG_REPACKAGE)
 
2010
                    (void) psmStage(psm, PSM_PKGSAVE);
 
2011
                break;
 
2012
            }
 
2013
        }
 
2014
        tsi = tsFreeIterator(tsi);
 
2015
    }
 
2016
 
 
2017
    /* ===============================================
 
2018
     * Install and remove packages.
 
2019
     */
 
2020
 
 
2021
    lastFailed = -2;    /* erased packages have -1 */
 
2022
    tsi = tsInitIterator(ts);
 
2023
    while ((fi = tsNextIterator(tsi)) != NULL) {
 
2024
        Header h;
 
2025
        int gotfd;
 
2026
 
 
2027
        gotfd = 0;
 
2028
        psm->fi = fi;
 
2029
        switch (fi->type)
 
2030
        {
 
2031
        case TR_ADDED:
 
2032
            alp = tsGetAlp(tsi);
 
2033
assert(alp == fi->ap);
 
2034
            i = alp - ts->addedPackages.list;
 
2035
 
 
2036
            h = headerLink(fi->h);
 
2037
            if (alp->fd == NULL) {
 
2038
                alp->fd = ts->notify(fi->h, RPMCALLBACK_INST_OPEN_FILE, 0, 0,
 
2039
                            alp->key, ts->notifyData);
 
2040
                if (alp->fd) {
 
2041
                    rpmRC rpmrc;
 
2042
 
 
2043
#ifdef  DYING
 
2044
                    hdrs[i] = headerFree(hdrs[i]);
 
2045
#else
 
2046
                    h = headerFree(h);
 
2047
#endif
 
2048
                    /*@-mustmod@*/      /* LCL: segfault */
 
2049
                    rpmrc = rpmReadPackageHeader(alp->fd, &h, NULL, NULL, NULL);
 
2050
                    /*@=mustmod@*/
 
2051
                    if (!(rpmrc == RPMRC_OK || rpmrc == RPMRC_BADSIZE)) {
 
2052
                        (void)ts->notify(fi->h, RPMCALLBACK_INST_CLOSE_FILE,
 
2053
                                        0, 0, alp->key, ts->notifyData);
 
2054
                        alp->fd = NULL;
 
2055
                        ourrc++;
 
2056
                    } else {
 
2057
#ifdef  DYING
 
2058
                        hdrs[i] = relocateFileList(ts, fi, alp, h, NULL);
 
2059
                        h = headerFree(h);
 
2060
#else
 
2061
                        Header foo = relocateFileList(ts, fi, alp, h, NULL);
 
2062
                        h = headerFree(h);
 
2063
                        h = headerLink(foo);
 
2064
                        foo = headerFree(foo);
 
2065
#endif
 
2066
                    }
 
2067
                    if (alp->fd) gotfd = 1;
 
2068
                }
 
2069
            }
 
2070
 
 
2071
            if (alp->fd) {
 
2072
                Header hsave = NULL;
 
2073
 
 
2074
                if (fi->h) {
 
2075
                    hsave = headerLink(fi->h);
 
2076
                    fi->h = headerFree(fi->h);
 
2077
                }
 
2078
#ifdef  DYING
 
2079
                fi->h = headerLink(hdrs[i]);
 
2080
#else
 
2081
                fi->h = headerLink(h);
 
2082
#endif
 
2083
                if (alp->multiLib)
 
2084
                    ts->transFlags |= RPMTRANS_FLAG_MULTILIB;
 
2085
 
 
2086
assert(alp == fi->ap);
 
2087
                if (psmStage(psm, PSM_PKGINSTALL)) {
 
2088
                    ourrc++;
 
2089
                    lastFailed = i;
 
2090
                }
 
2091
                fi->h = headerFree(fi->h);
 
2092
                if (hsave) {
 
2093
                    fi->h = headerLink(hsave);
 
2094
                    hsave = headerFree(hsave);
 
2095
                }
 
2096
            } else {
 
2097
                ourrc++;
 
2098
                lastFailed = i;
 
2099
            }
 
2100
 
 
2101
#ifdef  DYING
 
2102
            hdrs[i] = headerFree(hdrs[i]);
 
2103
#else
 
2104
            h = headerFree(h);
 
2105
#endif
 
2106
 
 
2107
            if (gotfd) {
 
2108
                (void)ts->notify(fi->h, RPMCALLBACK_INST_CLOSE_FILE, 0, 0,
 
2109
                        alp->key, ts->notifyData);
 
2110
                alp->fd = NULL;
 
2111
            }
 
2112
            break;
 
2113
        case TR_REMOVED:
 
2114
            oc = tsGetOc(tsi);
 
2115
            /* If install failed, then we shouldn't erase. */
 
2116
            if (ts->order[oc].u.removed.dependsOnIndex == lastFailed)
 
2117
                break;
 
2118
 
 
2119
            if (psmStage(psm, PSM_PKGERASE))
 
2120
                ourrc++;
 
2121
 
 
2122
            break;
 
2123
        }
 
2124
        (void) rpmdbSync(ts->rpmdb);
 
2125
    }
 
2126
    tsi = tsFreeIterator(tsi);
 
2127
 
 
2128
    ts->flList = freeFl(ts, ts->flList);
 
2129
    ts->flEntries = 0;
 
2130
 
 
2131
    /*@-nullstate@*/
 
2132
    if (ourrc)
 
2133
        return -1;
 
2134
    else
 
2135
        return 0;
 
2136
    /*@=nullstate@*/
 
2137
}