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

« back to all changes in this revision

Viewing changes to lib/fsm.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 payload
 
2
 * \file lib/fsm.c
 
3
 * File state machine to handle a payload from a package.
 
4
 */
 
5
 
 
6
#include "system.h"
 
7
 
 
8
#include "psm.h"
 
9
#include "rpmerr.h"
 
10
#include "debug.h"
 
11
 
 
12
/*@access FD_t @*/
 
13
/*@access rpmTransactionSet @*/
 
14
/*@access TFI_t @*/
 
15
/*@access FSMI_t @*/
 
16
/*@access FSM_t @*/
 
17
 
 
18
#define alloca_strdup(_s)       strcpy(alloca(strlen(_s)+1), (_s))
 
19
 
 
20
int _fsm_debug = 0;
 
21
 
 
22
/* XXX Failure to remove is not (yet) cause for failure. */
 
23
/*@-exportlocal -exportheadervar@*/
 
24
int strict_erasures = 0;
 
25
/*@=exportlocal =exportheadervar@*/
 
26
 
 
27
rpmTransactionSet fsmGetTs(const FSM_t fsm) {
 
28
    const FSMI_t iter = fsm->iter;
 
29
    /*@-retexpose@*/
 
30
    return (iter ? iter->ts : NULL);
 
31
    /*@=retexpose@*/
 
32
}
 
33
 
 
34
TFI_t fsmGetFi(const FSM_t fsm)
 
35
{
 
36
    const FSMI_t iter = fsm->iter;
 
37
    /*@-retexpose@*/
 
38
    return (iter ? iter->fi : NULL);
 
39
    /*@=retexpose@*/
 
40
}
 
41
 
 
42
#define SUFFIX_RPMORIG  ".rpmorig"
 
43
#define SUFFIX_RPMSAVE  ".rpmsave"
 
44
#define SUFFIX_RPMNEW   ".rpmnew"
 
45
 
 
46
/** \ingroup payload
 
47
 * Build path to file from file info, ornamented with subdir and suffix.
 
48
 * @param fsm           file state machine data
 
49
 * @param st            file stat info
 
50
 * @param subdir        subdir to use (NULL disables)
 
51
 * @param suffix        suffix to use (NULL disables)
 
52
 * @retval              path to file
 
53
 */
 
54
static /*@only@*//*@null@*/
 
55
const char * fsmFsPath(/*@special@*/ /*@null@*/ const FSM_t fsm,
 
56
                /*@null@*/ const struct stat * st,
 
57
                /*@null@*/ const char * subdir,
 
58
                /*@null@*/ const char * suffix)
 
59
        /*@uses fsm->dirName, fsm->baseName */
 
60
{
 
61
    const char * s = NULL;
 
62
 
 
63
    if (fsm) {
 
64
        int nb;
 
65
        char * t;
 
66
        /*@-nullpass@*/         /* LCL: subdir/suffix != NULL */
 
67
        nb = strlen(fsm->dirName) +
 
68
            (st && subdir && !S_ISDIR(st->st_mode) ? strlen(subdir) : 0) +
 
69
            (st && suffix && !S_ISDIR(st->st_mode) ? strlen(suffix) : 0) +
 
70
            strlen(fsm->baseName) + 1;
 
71
        s = t = xmalloc(nb);
 
72
        t = stpcpy(t, fsm->dirName);
 
73
        if (st && subdir && !S_ISDIR(st->st_mode))
 
74
            t = stpcpy(t, subdir);
 
75
        t = stpcpy(t, fsm->baseName);
 
76
        if (st && suffix && !S_ISDIR(st->st_mode))
 
77
            t = stpcpy(t, suffix);
 
78
        /*@=nullpass@*/
 
79
    }
 
80
    return s;
 
81
}
 
82
 
 
83
/** \ingroup payload
 
84
 * Destroy file info iterator.
 
85
 * @param p             file info iterator
 
86
 * @retval              NULL always
 
87
 */
 
88
static /*@null@*/ void * mapFreeIterator(/*@only@*//*@null@*/const void * p)
 
89
{
 
90
    return _free((void *)p);
 
91
}
 
92
 
 
93
/** \ingroup payload
 
94
 * Create file info iterator.
 
95
 * @param a             transaction set
 
96
 * @param b             transaction element file info
 
97
 * @return              file info iterator
 
98
 */
 
99
static void *
 
100
mapInitIterator(/*@kept@*/ const void * a, /*@kept@*/ const void * b)
 
101
{
 
102
    rpmTransactionSet ts = (void *)a;
 
103
    TFI_t fi = (void *)b;
 
104
    FSMI_t iter = NULL;
 
105
 
 
106
    iter = xcalloc(1, sizeof(*iter));
 
107
    /*@-assignexpose@*/
 
108
    iter->ts = ts;
 
109
    iter->fi = fi;
 
110
    /*@=assignexpose@*/
 
111
    iter->reverse = (fi->type == TR_REMOVED && fi->action != FA_COPYOUT);
 
112
    iter->i = (iter->reverse ? (fi->fc - 1) : 0);
 
113
    iter->isave = iter->i;
 
114
    return iter;
 
115
}
 
116
 
 
117
/** \ingroup payload
 
118
 * Return next index into file info.
 
119
 * @param a             file info iterator
 
120
 * @return              next index, -1 on termination
 
121
 */
 
122
static int mapNextIterator(void * a) {
 
123
    FSMI_t iter = a;
 
124
    const TFI_t fi = iter->fi;
 
125
    int i = -1;
 
126
 
 
127
    if (iter->reverse) {
 
128
        if (iter->i >= 0)       i = iter->i--;
 
129
    } else {
 
130
        if (iter->i < fi->fc)   i = iter->i++;
 
131
    }
 
132
    iter->isave = i;
 
133
    return i;
 
134
}
 
135
 
 
136
/** \ingroup payload
 
137
 */
 
138
static int cpioStrCmp(const void * a, const void * b)
 
139
        /*@*/
 
140
{
 
141
    const char * afn = *(const char **)a;
 
142
    const char * bfn = *(const char **)b;
 
143
 
 
144
    /* Match rpm-4.0 payloads with ./ prefixes. */
 
145
    if (afn[0] == '.' && afn[1] == '/') afn += 2;
 
146
    if (bfn[0] == '.' && bfn[1] == '/') bfn += 2;
 
147
 
 
148
    /* If either path is absolute, make it relative. */
 
149
    if (afn[0] == '/')  afn += 1;
 
150
    if (bfn[0] == '/')  bfn += 1;
 
151
 
 
152
    return strcmp(afn, bfn);
 
153
}
 
154
 
 
155
/** \ingroup payload
 
156
 * Locate archive path in file info.
 
157
 * @param a             file info iterator
 
158
 * @param fsmPath       archive path
 
159
 * @return              index into file info, -1 if archive path was not found
 
160
 */
 
161
static int mapFind(void * a, const char * fsmPath)
 
162
        /*@*/
 
163
{
 
164
    FSMI_t iter = a;
 
165
    const TFI_t fi = iter->fi;
 
166
    int ix = -1;
 
167
 
 
168
    if (fi && fi->fc > 0 && fi->apath && fsmPath && *fsmPath) {
 
169
        const char ** p = NULL;
 
170
 
 
171
        if (fi->apath != NULL)
 
172
            p = bsearch(&fsmPath, fi->apath, fi->fc, sizeof(fsmPath),
 
173
                        cpioStrCmp);
 
174
        if (p) {
 
175
            iter->i = p - fi->apath;
 
176
            ix = mapNextIterator(iter);
 
177
        }
 
178
    }
 
179
    return ix;
 
180
}
 
181
 
 
182
/** \ingroup payload
 
183
 * Directory name iterator.
 
184
 */
 
185
typedef struct dnli_s {
 
186
/*@dependent@*/ TFI_t fi;
 
187
/*@only@*/ /*@null@*/ char * active;
 
188
    int reverse;
 
189
    int isave;
 
190
    int i;
 
191
} * DNLI_t;
 
192
 
 
193
/** \ingroup payload
 
194
 * Destroy directory name iterator.
 
195
 * @param a             directory name iterator
 
196
 * @retval              NULL always
 
197
 */
 
198
static /*@null@*/ void * dnlFreeIterator(/*@only@*//*@null@*/ const void * a)
 
199
        /*@modifies a @*/
 
200
{
 
201
    if (a) {
 
202
        DNLI_t dnli = (void *)a;
 
203
        if (dnli->active) free(dnli->active);
 
204
    }
 
205
    return _free(a);
 
206
}
 
207
 
 
208
/** \ingroup payload
 
209
 */
 
210
static inline int dnlCount(const DNLI_t dnli)
 
211
        /*@*/
 
212
{
 
213
    return (dnli ? dnli->fi->dc : 0);
 
214
}
 
215
 
 
216
/** \ingroup payload
 
217
 */
 
218
static inline int dnlIndex(const DNLI_t dnli)
 
219
        /*@*/
 
220
{
 
221
    return (dnli ? dnli->isave : -1);
 
222
}
 
223
 
 
224
/** \ingroup payload
 
225
 * Create directory name iterator.
 
226
 * @param fsm           file state machine data
 
227
 * @param reverse       traverse directory names in reverse order?
 
228
 * @return              directory name iterator
 
229
 */
 
230
static /*@only@*/ void * dnlInitIterator(/*@special@*/ const FSM_t fsm,
 
231
                int reverse)
 
232
        /*@uses fsm->iter @*/ 
 
233
        /*@*/
 
234
{
 
235
    TFI_t fi = fsmGetFi(fsm);
 
236
    DNLI_t dnli;
 
237
    int i, j;
 
238
 
 
239
    if (fi == NULL)
 
240
        return NULL;
 
241
    dnli = xcalloc(1, sizeof(*dnli));
 
242
    dnli->fi = fi;
 
243
    dnli->reverse = reverse;
 
244
    dnli->i = (reverse ? fi->dc : 0);
 
245
 
 
246
    if (fi->dc) {
 
247
        dnli->active = xcalloc(fi->dc, sizeof(*dnli->active));
 
248
 
 
249
        /* Identify parent directories not skipped. */
 
250
        for (i = 0; i < fi->fc; i++)
 
251
            if (!XFA_SKIPPING(fi->actions[i])) dnli->active[fi->dil[i]] = 1;
 
252
 
 
253
        /* Exclude parent directories that are explicitly included. */
 
254
        for (i = 0; i < fi->fc; i++) {
 
255
            int dil, dnlen, bnlen;
 
256
 
 
257
            if (!S_ISDIR(fi->fmodes[i]))
 
258
                continue;
 
259
 
 
260
            dil = fi->dil[i];
 
261
            dnlen = strlen(fi->dnl[dil]);
 
262
            bnlen = strlen(fi->bnl[i]);
 
263
 
 
264
            for (j = 0; j < fi->dc; j++) {
 
265
                const char * dnl;
 
266
                int jlen;
 
267
 
 
268
                if (!dnli->active[j] || j == dil) continue;
 
269
                dnl = fi->dnl[j];
 
270
                jlen = strlen(dnl);
 
271
                if (jlen != (dnlen+bnlen+1)) continue;
 
272
                if (strncmp(dnl, fi->dnl[dil], dnlen)) continue;
 
273
                if (strncmp(dnl+dnlen, fi->bnl[i], bnlen)) continue;
 
274
                if (dnl[dnlen+bnlen] != '/' || dnl[dnlen+bnlen+1] != '\0')
 
275
                    continue;
 
276
                /* This directory is included in the package. */
 
277
                dnli->active[j] = 0;
 
278
                /*@innerbreak@*/ break;
 
279
            }
 
280
        }
 
281
 
 
282
        /* Print only once per package. */
 
283
        if (!reverse) {
 
284
            j = 0;
 
285
            for (i = 0; i < fi->dc; i++) {
 
286
                if (!dnli->active[i]) continue;
 
287
                if (j == 0) {
 
288
                    j = 1;
 
289
                    rpmMessage(RPMMESS_DEBUG,
 
290
        _("========= Directories not explictly included in package:\n"));
 
291
                }
 
292
                rpmMessage(RPMMESS_DEBUG, _("%9d %s\n"), i, fi->dnl[i]);
 
293
            }
 
294
            if (j)
 
295
                rpmMessage(RPMMESS_DEBUG, "=========\n");
 
296
        }
 
297
    }
 
298
    return dnli;
 
299
}
 
300
 
 
301
/** \ingroup payload
 
302
 * Return next directory name (from file info).
 
303
 * @param dnli          directory name iterator
 
304
 * @return              next directory name
 
305
 */
 
306
static /*@observer@*/ const char * dnlNextIterator(/*@null@*/ DNLI_t dnli)
 
307
        /*@modifies dnli @*/
 
308
{
 
309
    const char * dn = NULL;
 
310
 
 
311
    if (dnli) {
 
312
        TFI_t fi = dnli->fi;
 
313
        int i = -1;
 
314
 
 
315
        if (dnli->active)
 
316
        do {
 
317
            i = (!dnli->reverse ? dnli->i++ : --dnli->i);
 
318
        } while (i >= 0 && i < fi->dc && !dnli->active[i]);
 
319
 
 
320
        if (i >= 0 && i < fi->dc)
 
321
            dn = fi->dnl[i];
 
322
        else
 
323
            i = -1;
 
324
        dnli->isave = i;
 
325
    }
 
326
    return dn;
 
327
}
 
328
 
 
329
/** \ingroup payload
 
330
 * Save hard link in chain.
 
331
 * @param fsm           file state machine data
 
332
 * @return              Is chain only partially filled?
 
333
 */
 
334
/*@-compmempass@*/
 
335
static int saveHardLink(/*@special@*/ /*@partial@*/ FSM_t fsm)
 
336
        /*@uses fsm->links, fsm->ix, fsm->sb, fsm->goal, fsm->nsuffix @*/
 
337
        /*@defines fsm->li @*/
 
338
        /*@releases fsm->path @*/
 
339
        /*@modifies fsm @*/
 
340
{
 
341
    struct stat * st = &fsm->sb;
 
342
    int rc = 0;
 
343
    int ix = -1;
 
344
    int j;
 
345
 
 
346
    /* Find hard link set. */
 
347
    for (fsm->li = fsm->links; fsm->li; fsm->li = fsm->li->next) {
 
348
        if (fsm->li->sb.st_ino == st->st_ino && fsm->li->sb.st_dev == st->st_dev)
 
349
            break;
 
350
    }
 
351
 
 
352
    /* New hard link encountered, add new link to set. */
 
353
    if (fsm->li == NULL) {
 
354
        fsm->li = xcalloc(1, sizeof(*fsm->li));
 
355
        fsm->li->next = NULL;
 
356
        fsm->li->sb = *st;      /* structure assignment */
 
357
        fsm->li->nlink = st->st_nlink;
 
358
        fsm->li->linkIndex = fsm->ix;
 
359
        fsm->li->createdPath = -1;
 
360
 
 
361
        fsm->li->filex = xcalloc(st->st_nlink, sizeof(fsm->li->filex[0]));
 
362
        memset(fsm->li->filex, -1, (st->st_nlink * sizeof(fsm->li->filex[0])));
 
363
        fsm->li->nsuffix = xcalloc(st->st_nlink, sizeof(*fsm->li->nsuffix));
 
364
 
 
365
        if (fsm->goal == FSM_PKGBUILD)
 
366
            fsm->li->linksLeft = st->st_nlink;
 
367
        if (fsm->goal == FSM_PKGINSTALL)
 
368
            fsm->li->linksLeft = 0;
 
369
 
 
370
        /*@-kepttrans@*/
 
371
        fsm->li->next = fsm->links;
 
372
        /*@=kepttrans@*/
 
373
        fsm->links = fsm->li;
 
374
    }
 
375
 
 
376
    if (fsm->goal == FSM_PKGBUILD) --fsm->li->linksLeft;
 
377
    fsm->li->filex[fsm->li->linksLeft] = fsm->ix;
 
378
    /*@-observertrans -dependenttrans@*/
 
379
    fsm->li->nsuffix[fsm->li->linksLeft] = fsm->nsuffix;
 
380
    /*@=observertrans =dependenttrans@*/
 
381
    if (fsm->goal == FSM_PKGINSTALL) fsm->li->linksLeft++;
 
382
 
 
383
    if (fsm->goal == FSM_PKGBUILD)
 
384
        return (fsm->li->linksLeft > 0);
 
385
 
 
386
    if (fsm->goal != FSM_PKGINSTALL)
 
387
        return 0;
 
388
 
 
389
    if (!(st->st_size || fsm->li->linksLeft == st->st_nlink))
 
390
        return 1;
 
391
 
 
392
    /* Here come the bits, time to choose a non-skipped file name. */
 
393
    {   TFI_t fi = fsmGetFi(fsm);
 
394
 
 
395
        for (j = fsm->li->linksLeft - 1; j >= 0; j--) {
 
396
            ix = fsm->li->filex[j];
 
397
            if (ix < 0 || XFA_SKIPPING(fi->actions[ix]))
 
398
                continue;
 
399
            break;
 
400
        }
 
401
    }
 
402
 
 
403
    /* Are all links skipped or not encountered yet? */
 
404
    if (ix < 0 || j < 0)
 
405
        return 1;       /* XXX W2DO? */
 
406
 
 
407
    /* Save the non-skipped file name and map index. */
 
408
    fsm->li->linkIndex = j;
 
409
    fsm->path = _free(fsm->path);
 
410
    fsm->ix = ix;
 
411
    rc = fsmStage(fsm, FSM_MAP);
 
412
    /*@-nullstate@*/    /* FIX: fsm->path null annotation? */
 
413
    return rc;
 
414
    /*@=nullstate@*/
 
415
}
 
416
/*@=compmempass@*/
 
417
 
 
418
/** \ingroup payload
 
419
 * Destroy set of hard links.
 
420
 * @param li            set of hard links
 
421
 */
 
422
static /*@null@*/ void * freeHardLink(/*@only@*/ /*@null@*/ struct hardLink * li)
 
423
        /*@modifies li @*/
 
424
{
 
425
    if (li) {
 
426
        li->nsuffix = _free(li->nsuffix);       /* XXX elements are shared */
 
427
        li->filex = _free(li->filex);
 
428
    }
 
429
    return _free(li);
 
430
}
 
431
 
 
432
FSM_t newFSM(void)
 
433
{
 
434
    FSM_t fsm = xcalloc(1, sizeof(*fsm));
 
435
    return fsm;
 
436
}
 
437
 
 
438
FSM_t freeFSM(FSM_t fsm)
 
439
{
 
440
    if (fsm) {
 
441
        fsm->path = _free(fsm->path);
 
442
        while ((fsm->li = fsm->links) != NULL) {
 
443
            fsm->links = fsm->li->next;
 
444
            fsm->li->next = NULL;
 
445
            fsm->li = freeHardLink(fsm->li);
 
446
        }
 
447
        fsm->dnlx = _free(fsm->dnlx);
 
448
        fsm->ldn = _free(fsm->ldn);
 
449
        fsm->iter = mapFreeIterator(fsm->iter);
 
450
    }
 
451
    return _free(fsm);
 
452
}
 
453
 
 
454
int fsmSetup(FSM_t fsm, fileStage goal,
 
455
                const rpmTransactionSet ts, const TFI_t fi, FD_t cfd,
 
456
                unsigned int * archiveSize, const char ** failedFile)
 
457
{
 
458
    size_t pos = 0;
 
459
    int rc, ec = 0;
 
460
 
 
461
    fsm->goal = goal;
 
462
    if (cfd) {
 
463
        fsm->cfd = fdLink(cfd, "persist (fsm)");
 
464
        pos = fdGetCpioPos(fsm->cfd);
 
465
        fdSetCpioPos(fsm->cfd, 0);
 
466
    }
 
467
    fsm->iter = mapInitIterator(ts, fi);
 
468
 
 
469
    if (fsm->goal == FSM_PKGINSTALL) {
 
470
        if (ts && ts->notify) {
 
471
            (void)ts->notify(fi->h, RPMCALLBACK_INST_START, 0, fi->archiveSize,
 
472
                (fi->ap ? fi->ap->key : NULL), ts->notifyData);
 
473
        }
 
474
    }
 
475
 
 
476
    /*@-assignexpose@*/
 
477
    fsm->archiveSize = archiveSize;
 
478
    if (fsm->archiveSize)
 
479
        *fsm->archiveSize = 0;
 
480
    fsm->failedFile = failedFile;
 
481
    if (fsm->failedFile)
 
482
        *fsm->failedFile = NULL;
 
483
    /*@=assignexpose@*/
 
484
 
 
485
    memset(fsm->sufbuf, 0, sizeof(fsm->sufbuf));
 
486
    if (fsm->goal == FSM_PKGINSTALL) {
 
487
        if (ts && ts->id > 0)
 
488
            sprintf(fsm->sufbuf, ";%08x", (unsigned)ts->id);
 
489
    }
 
490
 
 
491
    ec = fsm->rc = 0;
 
492
    rc = fsmStage(fsm, FSM_CREATE);
 
493
    if (rc && !ec) ec = rc;
 
494
 
 
495
    rc = fsmStage(fsm, fsm->goal);
 
496
    if (rc && !ec) ec = rc;
 
497
 
 
498
    if (fsm->archiveSize && ec == 0)
 
499
        *fsm->archiveSize = (fdGetCpioPos(fsm->cfd) - pos);
 
500
 
 
501
   return ec;
 
502
}
 
503
 
 
504
int fsmTeardown(FSM_t fsm) {
 
505
    int rc = fsm->rc;
 
506
 
 
507
    if (!rc)
 
508
        rc = fsmStage(fsm, FSM_DESTROY);
 
509
 
 
510
    fsm->iter = mapFreeIterator(fsm->iter);
 
511
    if (fsm->cfd) {
 
512
        fsm->cfd = fdFree(fsm->cfd, "persist (fsm)");
 
513
        fsm->cfd = NULL;
 
514
    }
 
515
    fsm->failedFile = NULL;
 
516
    /*@-nullstate@*/    /* FIX: fsm->iter null annotation? */
 
517
    return rc;
 
518
    /*@=nullstate@*/
 
519
}
 
520
 
 
521
int fsmMapPath(FSM_t fsm)
 
522
{
 
523
    TFI_t fi = fsmGetFi(fsm);   /* XXX const except for fstates */
 
524
    int rc = 0;
 
525
    int i;
 
526
 
 
527
    fsm->osuffix = NULL;
 
528
    fsm->nsuffix = NULL;
 
529
    fsm->astriplen = 0;
 
530
    fsm->action = FA_UNKNOWN;
 
531
    fsm->mapFlags = 0;
 
532
 
 
533
    i = fsm->ix;
 
534
    if (fi && i >= 0 && i < fi->fc) {
 
535
 
 
536
        fsm->astriplen = fi->astriplen;
 
537
        fsm->action = (fi->actions ? fi->actions[i] : fi->action);
 
538
        fsm->fflags = (fi->fflags ? fi->fflags[i] : fi->flags);
 
539
        fsm->mapFlags = (fi->fmapflags ? fi->fmapflags[i] : fi->mapflags);
 
540
 
 
541
        /* src rpms have simple base name in payload. */
 
542
        fsm->dirName = fi->dnl[fi->dil[i]];
 
543
        fsm->baseName = fi->bnl[i];
 
544
 
 
545
        switch (fsm->action) {
 
546
        case FA_SKIP:
 
547
            break;
 
548
        case FA_SKIPMULTILIB:   /* XXX RPMFILE_STATE_MULTILIB? */
 
549
            break;
 
550
        case FA_UNKNOWN:
 
551
            break;
 
552
 
 
553
        case FA_COPYOUT:
 
554
            break;
 
555
        case FA_COPYIN:
 
556
        case FA_CREATE:
 
557
assert(fi->type == TR_ADDED);
 
558
            break;
 
559
 
 
560
        case FA_SKIPNSTATE:
 
561
            if (fi->fstates && fi->type == TR_ADDED)
 
562
                fi->fstates[i] = RPMFILE_STATE_NOTINSTALLED;
 
563
            break;
 
564
 
 
565
        case FA_SKIPNETSHARED:
 
566
            if (fi->fstates && fi->type == TR_ADDED)
 
567
                fi->fstates[i] = RPMFILE_STATE_NETSHARED;
 
568
            break;
 
569
 
 
570
        case FA_BACKUP:
 
571
            if (!(fsm->fflags & RPMFILE_GHOST)) /* XXX Don't if %ghost file. */
 
572
            switch (fi->type) {
 
573
            case TR_ADDED:
 
574
                fsm->osuffix = SUFFIX_RPMORIG;
 
575
                break;
 
576
            case TR_REMOVED:
 
577
                fsm->osuffix = SUFFIX_RPMSAVE;
 
578
                break;
 
579
            }
 
580
            break;
 
581
 
 
582
        case FA_ALTNAME:
 
583
assert(fi->type == TR_ADDED);
 
584
            if (!(fsm->fflags & RPMFILE_GHOST)) /* XXX Don't if %ghost file. */
 
585
                fsm->nsuffix = SUFFIX_RPMNEW;
 
586
            break;
 
587
 
 
588
        case FA_SAVE:
 
589
assert(fi->type == TR_ADDED);
 
590
            if (!(fsm->fflags & RPMFILE_GHOST)) /* XXX Don't if %ghost file. */
 
591
                fsm->osuffix = SUFFIX_RPMSAVE;
 
592
            break;
 
593
        case FA_ERASE:
 
594
            assert(fi->type == TR_REMOVED);
 
595
            /*
 
596
             * XXX TODO: %ghost probably shouldn't be removed, but that changes
 
597
             * legacy rpm behavior.
 
598
             */
 
599
            break;
 
600
        default:
 
601
            break;
 
602
        }
 
603
 
 
604
        if ((fsm->mapFlags & CPIO_MAP_PATH) || fsm->nsuffix) {
 
605
            const struct stat * st = &fsm->sb;
 
606
            fsm->path = _free(fsm->path);
 
607
            /*@-nullstate@*/    /* FIX: fsm->path null annotation? */
 
608
            fsm->path = fsmFsPath(fsm, st, fsm->subdir,
 
609
                (fsm->suffix ? fsm->suffix : fsm->nsuffix));
 
610
            /*@=nullstate@*/
 
611
        }
 
612
    }
 
613
    return rc;
 
614
}
 
615
 
 
616
int fsmMapAttrs(FSM_t fsm)
 
617
{
 
618
    struct stat * st = &fsm->sb;
 
619
    TFI_t fi = fsmGetFi(fsm);
 
620
    int i = fsm->ix;
 
621
 
 
622
    if (fi && i >= 0 && i < fi->fc) {
 
623
        mode_t perms =
 
624
                (S_ISDIR(st->st_mode) ? fi->dperms : fi->fperms);
 
625
        mode_t finalMode =
 
626
                (fi->fmodes ? fi->fmodes[i] : perms);
 
627
        uid_t finalUid =
 
628
                (fi->fuids ? fi->fuids[i] : fi->uid); /* XXX chmod u-s */
 
629
        gid_t finalGid =
 
630
                (fi->fgids ? fi->fgids[i] : fi->gid); /* XXX chmod g-s */
 
631
        dev_t finalRdev =
 
632
                (fi->frdevs ? fi->frdevs[i] : 0);
 
633
        int_32 finalMtime =
 
634
                (fi->fmtimes ? fi->fmtimes[i] : 0);
 
635
 
 
636
        if (fsm->mapFlags & CPIO_MAP_MODE)
 
637
            st->st_mode = (st->st_mode & S_IFMT) | (finalMode & ~S_IFMT);
 
638
        if (fsm->mapFlags & CPIO_MAP_TYPE) {
 
639
            st->st_mode = (st->st_mode & ~S_IFMT) | (finalMode & S_IFMT);
 
640
            if ((S_ISCHR(st->st_mode) || S_ISBLK(st->st_mode))
 
641
            && st->st_nlink == 0)
 
642
                st->st_nlink = 1;
 
643
            st->st_rdev = finalRdev;
 
644
            st->st_mtime = finalMtime;
 
645
        }
 
646
        if (fsm->mapFlags & CPIO_MAP_UID)
 
647
            st->st_uid = finalUid;
 
648
        if (fsm->mapFlags & CPIO_MAP_GID)
 
649
            st->st_gid = finalGid;
 
650
 
 
651
        fsm->fmd5sum = (fi->fmd5s ? fi->fmd5s[i] : NULL);
 
652
 
 
653
    }
 
654
    return 0;
 
655
}
 
656
 
 
657
/** \ingroup payload
 
658
 * Create file from payload stream.
 
659
 * @todo Legacy: support brokenEndian MD5 checks?
 
660
 * @param fsm           file state machine data
 
661
 * @return              0 on success
 
662
 */
 
663
static int expandRegular(/*@special@*/ FSM_t fsm)
 
664
        /*@uses fsm->sb @*/
 
665
        /*@modifies fsm, fileSystem @*/
 
666
{
 
667
    const char * fmd5sum;
 
668
    const struct stat * st = &fsm->sb;
 
669
    int left = st->st_size;
 
670
    int rc = 0;
 
671
 
 
672
    rc = fsmStage(fsm, FSM_WOPEN);
 
673
    if (rc)
 
674
        goto exit;
 
675
 
 
676
    /* XXX md5sum's will break on repackaging that includes modified files. */
 
677
    fmd5sum = fsm->fmd5sum;
 
678
 
 
679
    /* XXX This doesn't support brokenEndian checks. */
 
680
    if (st->st_size > 0 && fmd5sum)
 
681
        fdInitMD5(fsm->wfd, 0);
 
682
 
 
683
    while (left) {
 
684
 
 
685
        fsm->wrlen = (left > fsm->wrsize ? fsm->wrsize : left);
 
686
        rc = fsmStage(fsm, FSM_DREAD);
 
687
        if (rc)
 
688
            goto exit;
 
689
 
 
690
        rc = fsmStage(fsm, FSM_WRITE);
 
691
        if (rc)
 
692
            goto exit;
 
693
 
 
694
        left -= fsm->wrnb;
 
695
 
 
696
        /* don't call this with fileSize == fileComplete */
 
697
        if (!rc && left)
 
698
            (void) fsmStage(fsm, FSM_NOTIFY);
 
699
    }
 
700
 
 
701
    if (st->st_size > 0 && fmd5sum) {
 
702
        const char * md5sum = NULL;
 
703
 
 
704
        (void) Fflush(fsm->wfd);
 
705
        fdFiniMD5(fsm->wfd, (void **)&md5sum, NULL, 1);
 
706
 
 
707
        if (md5sum == NULL) {
 
708
            rc = CPIOERR_MD5SUM_MISMATCH;
 
709
        } else {
 
710
            if (strcmp(md5sum, fmd5sum))
 
711
                rc = CPIOERR_MD5SUM_MISMATCH;
 
712
            md5sum = _free(md5sum);
 
713
        }
 
714
    }
 
715
 
 
716
exit:
 
717
    (void) fsmStage(fsm, FSM_WCLOSE);
 
718
    return rc;
 
719
}
 
720
 
 
721
/** \ingroup payload
 
722
 * Write next item to payload stream.
 
723
 * @param fsm           file state machine data
 
724
 * @param writeData     should data be written?
 
725
 * @return              0 on success
 
726
 */
 
727
static int writeFile(/*@special@*/ FSM_t fsm, int writeData)
 
728
        /*@uses fsm->path, fsm->opath, fsm->sb, fsm->osb, fsm->cfd @*/
 
729
        /*@modifies fsm, fileSystem @*/
 
730
{
 
731
    const char * path = fsm->path;
 
732
    const char * opath = fsm->opath;
 
733
    struct stat * st = &fsm->sb;
 
734
    struct stat * ost = &fsm->osb;
 
735
    size_t pos = fdGetCpioPos(fsm->cfd);
 
736
    char * symbuf = NULL;
 
737
    int left;
 
738
    int rc;
 
739
 
 
740
    st->st_size = (writeData ? ost->st_size : 0);
 
741
 
 
742
    if (S_ISDIR(st->st_mode)) {
 
743
        st->st_size = 0;
 
744
    } else if (S_ISLNK(st->st_mode)) {
 
745
        /*
 
746
         * While linux puts the size of a symlink in the st_size field,
 
747
         * I don't think that's a specified standard.
 
748
         */
 
749
        /* XXX NUL terminated result in fsm->rdbuf, len in fsm->rdnb. */
 
750
        rc = fsmStage(fsm, FSM_READLINK);
 
751
        if (rc) goto exit;
 
752
        st->st_size = fsm->rdnb;
 
753
        symbuf = alloca_strdup(fsm->rdbuf);     /* XXX save readlink return. */
 
754
    }
 
755
 
 
756
    if (fsm->mapFlags & CPIO_MAP_ABSOLUTE) {
 
757
        int nb = strlen(fsm->dirName) + strlen(fsm->baseName) + sizeof(".");
 
758
        char * t = alloca(nb);
 
759
        *t = '\0';
 
760
        fsm->path = t;
 
761
        if (fsm->mapFlags & CPIO_MAP_ADDDOT)
 
762
            *t++ = '.';
 
763
        t = stpcpy( stpcpy(t, fsm->dirName), fsm->baseName);
 
764
    } else if (fsm->mapFlags & CPIO_MAP_PATH) {
 
765
        TFI_t fi = fsmGetFi(fsm);
 
766
        fsm->path =
 
767
            (fi->apath ? fi->apath[fsm->ix] + fi->striplen : fi->bnl[fsm->ix]);
 
768
    }
 
769
 
 
770
    rc = fsmStage(fsm, FSM_HWRITE);
 
771
    fsm->path = path;
 
772
    if (rc) goto exit;
 
773
 
 
774
    if (writeData && S_ISREG(st->st_mode)) {
 
775
#if HAVE_MMAP
 
776
        char * rdbuf = NULL;
 
777
        void * mapped = (void *)-1;
 
778
        size_t nmapped;
 
779
#endif
 
780
 
 
781
        rc = fsmStage(fsm, FSM_ROPEN);
 
782
        if (rc) goto exit;
 
783
 
 
784
        /* XXX unbuffered mmap generates *lots* of fdio debugging */
 
785
#if HAVE_MMAP
 
786
        nmapped = 0;
 
787
        mapped = mmap(NULL, st->st_size, PROT_READ, MAP_SHARED, Fileno(fsm->rfd), 0);
 
788
        if (mapped != (void *)-1) {
 
789
            rdbuf = fsm->rdbuf;
 
790
            fsm->rdbuf = (char *) mapped;
 
791
            fsm->rdlen = nmapped = st->st_size;
 
792
        }
 
793
#endif
 
794
 
 
795
        left = st->st_size;
 
796
 
 
797
        while (left) {
 
798
#if HAVE_MMAP
 
799
          if (mapped != (void *)-1) {
 
800
            fsm->rdnb = nmapped;
 
801
          } else
 
802
#endif
 
803
          {
 
804
            fsm->rdlen = (left > fsm->rdsize ? fsm->rdsize : left),
 
805
            rc = fsmStage(fsm, FSM_READ);
 
806
            if (rc) goto exit;
 
807
          }
 
808
 
 
809
            /* XXX DWRITE uses rdnb for I/O length. */
 
810
            rc = fsmStage(fsm, FSM_DWRITE);
 
811
            if (rc) goto exit;
 
812
 
 
813
            left -= fsm->wrnb;
 
814
        }
 
815
 
 
816
#if HAVE_MMAP
 
817
        if (mapped != (void *)-1) {
 
818
            /*@-noeffect@*/ (void) munmap(mapped, nmapped) /*@=noeffect@*/;
 
819
            fsm->rdbuf = rdbuf;
 
820
        }
 
821
#endif
 
822
 
 
823
    } else if (writeData && S_ISLNK(st->st_mode)) {
 
824
        /* XXX DWRITE uses rdnb for I/O length. */
 
825
        strcpy(fsm->rdbuf, symbuf);     /* XXX restore readlink buffer. */
 
826
        fsm->rdnb = strlen(symbuf);
 
827
        rc = fsmStage(fsm, FSM_DWRITE);
 
828
        if (rc) goto exit;
 
829
    }
 
830
 
 
831
    rc = fsmStage(fsm, FSM_PAD);
 
832
    if (rc) goto exit;
 
833
 
 
834
    {   const rpmTransactionSet ts = fsmGetTs(fsm);
 
835
        TFI_t fi = fsmGetFi(fsm);
 
836
        if (ts && fi && ts->notify) {
 
837
            size_t size = (fdGetCpioPos(fsm->cfd) - pos);
 
838
            /*@-modunconnomods@*/
 
839
            (void)ts->notify(fi->h, RPMCALLBACK_INST_PROGRESS, size, size,
 
840
                        (fi->ap ? fi->ap->key : NULL), ts->notifyData);
 
841
            /*@=modunconnomods@*/
 
842
        }
 
843
    }
 
844
 
 
845
    rc = 0;
 
846
 
 
847
exit:
 
848
    if (fsm->rfd)
 
849
        (void) fsmStage(fsm, FSM_RCLOSE);
 
850
    /*@-dependenttrans@*/
 
851
    fsm->opath = opath;
 
852
    fsm->path = path;
 
853
    /*@=dependenttrans@*/
 
854
    return rc;
 
855
}
 
856
 
 
857
/** \ingroup payload
 
858
 * Write set of linked files to payload stream.
 
859
 * @param fsm           file state machine data
 
860
 * @return              0 on success
 
861
 */
 
862
static int writeLinkedFile(/*@special@*/ FSM_t fsm)
 
863
        /*@uses fsm->path, fsm->nsuffix, fsm->ix, fsm->li, fsm->failedFile @*/
 
864
        /*@modifies fsm, fileSystem @*/
 
865
{
 
866
    const char * path = fsm->path;
 
867
    const char * nsuffix = fsm->nsuffix;
 
868
    int iterIndex = fsm->ix;
 
869
    int ec = 0;
 
870
    int rc;
 
871
    int i;
 
872
 
 
873
    fsm->path = NULL;
 
874
    fsm->nsuffix = NULL;
 
875
    fsm->ix = -1;
 
876
 
 
877
    for (i = fsm->li->nlink - 1; i >= 0; i--) {
 
878
 
 
879
        if (fsm->li->filex[i] < 0) continue;
 
880
 
 
881
        fsm->ix = fsm->li->filex[i];
 
882
        rc = fsmStage(fsm, FSM_MAP);
 
883
 
 
884
        /* Write data after last link. */
 
885
        rc = writeFile(fsm, (i == 0));
 
886
        if (fsm->failedFile && rc != 0 && *fsm->failedFile == NULL) {
 
887
            ec = rc;
 
888
            *fsm->failedFile = xstrdup(fsm->path);
 
889
        }
 
890
 
 
891
        fsm->path = _free(fsm->path);
 
892
        fsm->li->filex[i] = -1;
 
893
    }
 
894
 
 
895
    fsm->ix = iterIndex;
 
896
    fsm->nsuffix = nsuffix;
 
897
    fsm->path = path;
 
898
    return ec;
 
899
}
 
900
 
 
901
/** \ingroup payload
 
902
 * Create pending hard links to existing file.
 
903
 * @param fsm           file state machine data
 
904
 * @return              0 on success
 
905
 */
 
906
static int fsmMakeLinks(/*@special@*/ FSM_t fsm)
 
907
        /*@uses fsm->path, fsm->opath, fsm->nsuffix, fsm->ix, fsm->li @*/
 
908
        /*@modifies fsm, fileSystem @*/
 
909
{
 
910
    const char * path = fsm->path;
 
911
    const char * opath = fsm->opath;
 
912
    const char * nsuffix = fsm->nsuffix;
 
913
    int iterIndex = fsm->ix;
 
914
    int ec = 0;
 
915
    int rc;
 
916
    int i;
 
917
 
 
918
    fsm->path = NULL;
 
919
    fsm->opath = NULL;
 
920
    fsm->nsuffix = NULL;
 
921
    fsm->ix = -1;
 
922
 
 
923
    fsm->ix = fsm->li->filex[fsm->li->createdPath];
 
924
    rc = fsmStage(fsm, FSM_MAP);
 
925
    fsm->opath = fsm->path;
 
926
    fsm->path = NULL;
 
927
    for (i = 0; i < fsm->li->nlink; i++) {
 
928
        if (fsm->li->filex[i] < 0) continue;
 
929
        if (i == fsm->li->createdPath) continue;
 
930
 
 
931
        fsm->ix = fsm->li->filex[i];
 
932
        fsm->path = _free(fsm->path);
 
933
        rc = fsmStage(fsm, FSM_MAP);
 
934
        rc = fsmStage(fsm, FSM_VERIFY);
 
935
        if (!rc) continue;
 
936
        if (rc != CPIOERR_LSTAT_FAILED) break;
 
937
 
 
938
        /* XXX link(fsm->opath, fsm->path) */
 
939
        rc = fsmStage(fsm, FSM_LINK);
 
940
        if (fsm->failedFile && rc != 0 && *fsm->failedFile == NULL) {
 
941
            ec = rc;
 
942
            *fsm->failedFile = xstrdup(fsm->path);
 
943
        }
 
944
 
 
945
        fsm->li->linksLeft--;
 
946
    }
 
947
    fsm->path = _free(fsm->path);
 
948
    fsm->opath = _free(fsm->opath);
 
949
 
 
950
    fsm->ix = iterIndex;
 
951
    fsm->nsuffix = nsuffix;
 
952
    fsm->path = path;
 
953
    fsm->opath = opath;
 
954
    return ec;
 
955
}
 
956
 
 
957
/** \ingroup payload
 
958
 * Commit hard linked file set atomically.
 
959
 * @param fsm           file state machine data
 
960
 * @return              0 on success
 
961
 */
 
962
static int fsmCommitLinks(/*@special@*/ FSM_t fsm)
 
963
        /*@uses fsm->path, fsm->nsuffix, fsm->ix, fsm->sb,
 
964
                fsm->li, fsm->links @*/
 
965
        /*@modifies fsm, fileSystem @*/
 
966
{
 
967
    const char * path = fsm->path;
 
968
    const char * nsuffix = fsm->nsuffix;
 
969
    int iterIndex = fsm->ix;
 
970
    struct stat * st = &fsm->sb;
 
971
    int rc = 0;
 
972
    int i;
 
973
 
 
974
    fsm->path = NULL;
 
975
    fsm->nsuffix = NULL;
 
976
    fsm->ix = -1;
 
977
 
 
978
    for (fsm->li = fsm->links; fsm->li; fsm->li = fsm->li->next) {
 
979
        if (fsm->li->sb.st_ino == st->st_ino && fsm->li->sb.st_dev == st->st_dev)
 
980
            break;
 
981
    }
 
982
 
 
983
    for (i = 0; i < fsm->li->nlink; i++) {
 
984
        if (fsm->li->filex[i] < 0) continue;
 
985
        fsm->ix = fsm->li->filex[i];
 
986
        rc = fsmStage(fsm, FSM_MAP);
 
987
        rc = fsmStage(fsm, FSM_COMMIT);
 
988
        fsm->path = _free(fsm->path);
 
989
        fsm->li->filex[i] = -1;
 
990
    }
 
991
 
 
992
    fsm->ix = iterIndex;
 
993
    fsm->nsuffix = nsuffix;
 
994
    fsm->path = path;
 
995
    return rc;
 
996
}
 
997
 
 
998
/**
 
999
 * Remove (if created) directories not explicitly included in package.
 
1000
 * @param fsm           file state machine data
 
1001
 * @return              0 on success
 
1002
 */
 
1003
/*@-compdef@*/
 
1004
static int fsmRmdirs(/*@special@*/ FSM_t fsm)
 
1005
        /*@uses fsm->path, fsm->dnlx, fsm->ldn, fsm->rdbuf, fsm->iter @*/
 
1006
        /*@modifies fsm, fileSystem @*/
 
1007
{
 
1008
    const char * path = fsm->path;
 
1009
    void * dnli = dnlInitIterator(fsm, 1);
 
1010
    char * dn = fsm->rdbuf;
 
1011
    int dc = dnlCount(dnli);
 
1012
    int rc = 0;
 
1013
 
 
1014
    fsm->path = NULL;
 
1015
    dn[0] = '\0';
 
1016
    /*@-observertrans -dependenttrans@*/
 
1017
    if (fsm->ldn != NULL && fsm->dnlx != NULL)
 
1018
    while ((fsm->path = dnlNextIterator(dnli)) != NULL) {
 
1019
        int dnlen = strlen(fsm->path);
 
1020
        char * te;
 
1021
 
 
1022
        dc = dnlIndex(dnli);
 
1023
        if (fsm->dnlx[dc] < 1 || fsm->dnlx[dc] >= dnlen)
 
1024
            continue;
 
1025
 
 
1026
        /* Copy to avoid const on fsm->path. */
 
1027
        te = stpcpy(dn, fsm->path) - 1;
 
1028
        fsm->path = dn;
 
1029
 
 
1030
        /* Remove generated directories. */
 
1031
        do {
 
1032
            if (*te == '/') {
 
1033
                *te = '\0';
 
1034
                rc = fsmStage(fsm, FSM_RMDIR);
 
1035
                *te = '/';
 
1036
            }
 
1037
            if (rc)
 
1038
                /*@innerbreak@*/ break;
 
1039
            te--;
 
1040
        } while ((te - dn) > fsm->dnlx[dc]);
 
1041
    }
 
1042
    dnli = dnlFreeIterator(dnli);
 
1043
    /*@=observertrans =dependenttrans@*/
 
1044
 
 
1045
    fsm->path = path;
 
1046
    return rc;
 
1047
}
 
1048
/*@=compdef@*/
 
1049
 
 
1050
/**
 
1051
 * Create (if necessary) directories not explicitly included in package.
 
1052
 * @param fsm           file state machine data
 
1053
 * @return              0 on success
 
1054
 */
 
1055
static int fsmMkdirs(/*@special@*/ FSM_t fsm)
 
1056
        /*@uses fsm->path, fsm->sb, fsm->osb, fsm->rdbuf, fsm->iter,
 
1057
                fsm->ldn, fsm->ldnlen, fsm->ldnalloc @*/
 
1058
        /*@defines fsm->dnlx, fsm->ldn @*/
 
1059
        /*@modifies fsm, fileSystem @*/
 
1060
{
 
1061
    struct stat * st = &fsm->sb;
 
1062
    struct stat * ost = &fsm->osb;
 
1063
    const char * path = fsm->path;
 
1064
    mode_t st_mode = st->st_mode;
 
1065
    void * dnli = dnlInitIterator(fsm, 0);
 
1066
    char * dn = fsm->rdbuf;
 
1067
    int dc = dnlCount(dnli);
 
1068
    int rc = 0;
 
1069
    int i;
 
1070
 
 
1071
    fsm->path = NULL;
 
1072
 
 
1073
    dn[0] = '\0';
 
1074
    fsm->dnlx = (dc ? xcalloc(dc, sizeof(*fsm->dnlx)) : NULL);
 
1075
    /*@-observertrans -dependenttrans@*/
 
1076
    if (fsm->dnlx != NULL)
 
1077
    while ((fsm->path = dnlNextIterator(dnli)) != NULL) {
 
1078
        int dnlen = strlen(fsm->path);
 
1079
        char * te;
 
1080
 
 
1081
        dc = dnlIndex(dnli);
 
1082
        if (dc < 0) continue;
 
1083
        fsm->dnlx[dc] = dnlen;
 
1084
        if (dnlen <= 1)
 
1085
            continue;
 
1086
 
 
1087
        /*@-compdef -nullpass@*/        /* FIX: fsm->ldn not defined ??? */
 
1088
        if (dnlen <= fsm->ldnlen && !strcmp(fsm->path, fsm->ldn))
 
1089
            continue;
 
1090
        /*@=compdef =nullpass@*/
 
1091
 
 
1092
        /* Copy to avoid const on fsm->path. */
 
1093
        (void) stpcpy(dn, fsm->path);
 
1094
        fsm->path = dn;
 
1095
 
 
1096
        /* Assume '/' directory exists, "mkdir -p" for others if non-existent */
 
1097
        for (i = 1, te = dn + 1; *te != '\0'; te++, i++) {
 
1098
            if (*te != '/') continue;
 
1099
 
 
1100
            *te = '\0';
 
1101
 
 
1102
            /* Already validated? */
 
1103
            /*@-usedef -compdef -nullpass -nullderef@*/
 
1104
            if (i < fsm->ldnlen &&
 
1105
                (fsm->ldn[i] == '/' || fsm->ldn[i] == '\0') &&
 
1106
                !strncmp(fsm->path, fsm->ldn, i))
 
1107
            {
 
1108
                *te = '/';
 
1109
                /* Move pre-existing path marker forward. */
 
1110
                fsm->dnlx[dc] = (te - dn);
 
1111
                continue;
 
1112
            }
 
1113
            /*@=usedef =compdef =nullpass =nullderef@*/
 
1114
 
 
1115
            /* Validate next component of path. */
 
1116
            rc = fsmStage(fsm, FSM_LSTAT);
 
1117
            *te = '/';
 
1118
 
 
1119
            /* Directory already exists? */
 
1120
            if (rc == 0 && S_ISDIR(ost->st_mode)) {
 
1121
                /* Move pre-existing path marker forward. */
 
1122
                fsm->dnlx[dc] = (te - dn);
 
1123
            } else if (rc == CPIOERR_LSTAT_FAILED) {
 
1124
                TFI_t fi = fsmGetFi(fsm);
 
1125
                *te = '\0';
 
1126
                st->st_mode = S_IFDIR | (fi->dperms & 07777);
 
1127
                rc = fsmStage(fsm, FSM_MKDIR);
 
1128
                if (!rc)
 
1129
                    rpmMessage(RPMMESS_DEBUG,
 
1130
                        _("%s directory created with perms %04o.\n"),
 
1131
                        fsm->path, (unsigned)(st->st_mode & 07777));
 
1132
                *te = '/';
 
1133
            }
 
1134
            if (rc)
 
1135
                /*@innerbreak@*/ break;
 
1136
        }
 
1137
        if (rc) break;
 
1138
 
 
1139
        /* Save last validated path. */
 
1140
        if (fsm->ldnalloc < (dnlen + 1)) {
 
1141
            fsm->ldnalloc = dnlen + 100;
 
1142
            fsm->ldn = xrealloc(fsm->ldn, fsm->ldnalloc);
 
1143
        }
 
1144
        if (fsm->ldn != NULL) { /* XXX can't happen */
 
1145
            strcpy(fsm->ldn, fsm->path);
 
1146
            fsm->ldnlen = dnlen;
 
1147
        }
 
1148
    }
 
1149
    dnli = dnlFreeIterator(dnli);
 
1150
    /*@=observertrans =dependenttrans@*/
 
1151
 
 
1152
    fsm->path = path;
 
1153
    st->st_mode = st_mode;              /* XXX restore st->st_mode */
 
1154
    return rc;
 
1155
}
 
1156
 
 
1157
#ifdef  NOTYET
 
1158
/**
 
1159
 * Check for file on disk.
 
1160
 * @param fsm           file state machine data
 
1161
 * @return              0 on success
 
1162
 */
 
1163
static int fsmStat(FSM_t fsm)
 
1164
{
 
1165
    int saveerrno = errno;
 
1166
    int rc = 0;
 
1167
 
 
1168
    if (fsm->path != NULL) {
 
1169
        int saveernno = errno;
 
1170
        rc = fsmStage(fsm, (!(fsm->mapFlags & CPIO_FOLLOW_SYMLINKS)
 
1171
                        ? FSM_LSTAT : FSM_STAT));
 
1172
        if (rc == CPIOERR_LSTAT_FAILED && errno == ENOENT) {
 
1173
            errno = saveerrno;
 
1174
            rc = 0;
 
1175
            fsm->exists = 0;
 
1176
        } else if (rc == 0) {
 
1177
            fsm->exists = 1;
 
1178
        }
 
1179
    } else {
 
1180
        /* Skip %ghost files on build. */
 
1181
        fsm->exists = 0;
 
1182
    }
 
1183
    return rc;
 
1184
}
 
1185
#endif
 
1186
 
 
1187
/*@-compmempass@*/
 
1188
int fsmStage(FSM_t fsm, fileStage stage)
 
1189
{
 
1190
#ifdef  UNUSED
 
1191
    fileStage prevStage = fsm->stage;
 
1192
    const char * const prev = fileStageString(prevStage);
 
1193
#endif
 
1194
    static int modulo = 4;
 
1195
    const char * const cur = fileStageString(stage);
 
1196
    struct stat * st = &fsm->sb;
 
1197
    struct stat * ost = &fsm->osb;
 
1198
    int saveerrno = errno;
 
1199
    int rc = fsm->rc;
 
1200
    size_t left;
 
1201
    int i;
 
1202
 
 
1203
#define _fafilter(_a)   \
 
1204
    (!((_a) == FA_CREATE || (_a) == FA_ERASE || (_a) == FA_COPYIN || (_a) == FA_COPYOUT) \
 
1205
        ? fileActionString(_a) : "")
 
1206
 
 
1207
    if (stage & FSM_DEAD) {
 
1208
        /* do nothing */
 
1209
    } else if (stage & FSM_INTERNAL) {
 
1210
        if (_fsm_debug && !(stage & FSM_SYSCALL))
 
1211
            rpmMessage(RPMMESS_DEBUG, " %8s %06o%3d (%4d,%4d)%10d %s %s\n",
 
1212
                cur,
 
1213
                (unsigned)st->st_mode, (int)st->st_nlink,
 
1214
                (int)st->st_uid, (int)st->st_gid, (int)st->st_size,
 
1215
                (fsm->path ? fsm->path : ""),
 
1216
                _fafilter(fsm->action));
 
1217
    } else {
 
1218
        fsm->stage = stage;
 
1219
        if (_fsm_debug || !(stage & FSM_VERBOSE))
 
1220
            rpmMessage(RPMMESS_DEBUG, "%-8s  %06o%3d (%4d,%4d)%10d %s %s\n",
 
1221
                cur,
 
1222
                (unsigned)st->st_mode, (int)st->st_nlink,
 
1223
                (int)st->st_uid, (int)st->st_gid, (int)st->st_size,
 
1224
                (fsm->path ? fsm->path + fsm->astriplen : ""),
 
1225
                _fafilter(fsm->action));
 
1226
    }
 
1227
#undef  _fafilter
 
1228
 
 
1229
    switch (stage) {
 
1230
    case FSM_UNKNOWN:
 
1231
        break;
 
1232
    case FSM_PKGINSTALL:
 
1233
        while (1) {
 
1234
            /* Clean fsm, free'ing memory. Read next archive header. */
 
1235
            rc = fsmStage(fsm, FSM_INIT);
 
1236
 
 
1237
            /* Exit on end-of-payload. */
 
1238
            if (rc == CPIOERR_HDR_TRAILER) {
 
1239
                rc = 0;
 
1240
                /*@loopbreak@*/ break;
 
1241
            }
 
1242
 
 
1243
            /* Exit on error. */
 
1244
            if (rc) {
 
1245
                fsm->postpone = 1;
 
1246
                (void) fsmStage(fsm, FSM_UNDO);
 
1247
                /*@loopbreak@*/ break;
 
1248
            }
 
1249
 
 
1250
            /* Extract file from archive. */
 
1251
            rc = fsmStage(fsm, FSM_PROCESS);
 
1252
            if (rc) {
 
1253
                (void) fsmStage(fsm, FSM_UNDO);
 
1254
                /*@loopbreak@*/ break;
 
1255
            }
 
1256
 
 
1257
            /* Notify on success. */
 
1258
            (void) fsmStage(fsm, FSM_NOTIFY);
 
1259
 
 
1260
            rc = fsmStage(fsm, FSM_FINI);
 
1261
            if (rc) {
 
1262
                /*@loopbreak@*/ break;
 
1263
            }
 
1264
        }
 
1265
        break;
 
1266
    case FSM_PKGERASE:
 
1267
    case FSM_PKGCOMMIT:
 
1268
        while (1) {
 
1269
            /* Clean fsm, free'ing memory. */
 
1270
            rc = fsmStage(fsm, FSM_INIT);
 
1271
 
 
1272
            /* Exit on end-of-payload. */
 
1273
            if (rc == CPIOERR_HDR_TRAILER) {
 
1274
                rc = 0;
 
1275
                /*@loopbreak@*/ break;
 
1276
            }
 
1277
 
 
1278
            /* Rename/erase next item. */
 
1279
            if (fsmStage(fsm, FSM_FINI))
 
1280
                /*@loopbreak@*/ break;
 
1281
        }
 
1282
        break;
 
1283
    case FSM_PKGBUILD:
 
1284
        while (1) {
 
1285
 
 
1286
            rc = fsmStage(fsm, FSM_INIT);
 
1287
 
 
1288
            /* Exit on end-of-payload. */
 
1289
            if (rc == CPIOERR_HDR_TRAILER) {
 
1290
                rc = 0;
 
1291
                /*@loopbreak@*/ break;
 
1292
            }
 
1293
 
 
1294
            /* Exit on error. */
 
1295
            if (rc) {
 
1296
                fsm->postpone = 1;
 
1297
                (void) fsmStage(fsm, FSM_UNDO);
 
1298
                /*@loopbreak@*/ break;
 
1299
            }
 
1300
 
 
1301
            /* Copy file into archive. */
 
1302
            rc = fsmStage(fsm, FSM_PROCESS);
 
1303
            if (rc) {
 
1304
                (void) fsmStage(fsm, FSM_UNDO);
 
1305
                /*@loopbreak@*/ break;
 
1306
            }
 
1307
 
 
1308
            if (fsmStage(fsm, FSM_FINI))
 
1309
                /*@loopbreak@*/ break;
 
1310
        }
 
1311
 
 
1312
        /* Flush partial sets of hard linked files. */
 
1313
        if (!(fsm->mapFlags & CPIO_ALL_HARDLINKS)) {
 
1314
            int nlink, j;
 
1315
            while ((fsm->li = fsm->links) != NULL) {
 
1316
                fsm->links = fsm->li->next;
 
1317
                fsm->li->next = NULL;
 
1318
 
 
1319
                /* Re-calculate link count for archive header. */
 
1320
                for (j = -1, nlink = 0, i = 0; i < fsm->li->nlink; i++) {
 
1321
                    if (fsm->li->filex[i] < 0) continue;
 
1322
                    nlink++;
 
1323
                    if (j == -1) j = i;
 
1324
                }
 
1325
                /* XXX force the contents out as well. */
 
1326
                if (j != 0) {
 
1327
                    fsm->li->filex[0] = fsm->li->filex[j];
 
1328
                    fsm->li->filex[j] = -1;
 
1329
                }
 
1330
                fsm->li->sb.st_nlink = nlink;
 
1331
 
 
1332
                fsm->sb = fsm->li->sb;  /* structure assignment */
 
1333
                fsm->osb = fsm->sb;     /* structure assignment */
 
1334
 
 
1335
                if (!rc) rc = writeLinkedFile(fsm);
 
1336
 
 
1337
                fsm->li = freeHardLink(fsm->li);
 
1338
            }
 
1339
        }
 
1340
 
 
1341
        if (!rc)
 
1342
            rc = fsmStage(fsm, FSM_TRAILER);
 
1343
 
 
1344
        break;
 
1345
    case FSM_CREATE:
 
1346
        {   rpmTransactionSet ts = fsmGetTs(fsm);
 
1347
#define _tsmask (RPMTRANS_FLAG_PKGCOMMIT | RPMTRANS_FLAG_COMMIT)
 
1348
            fsm->commit = ((ts && (ts->transFlags & _tsmask) &&
 
1349
                        fsm->goal != FSM_PKGCOMMIT) ? 0 : 1);
 
1350
#undef _tsmask
 
1351
        }
 
1352
        fsm->path = _free(fsm->path);
 
1353
        fsm->opath = _free(fsm->opath);
 
1354
        fsm->dnlx = _free(fsm->dnlx);
 
1355
 
 
1356
        fsm->ldn = _free(fsm->ldn);
 
1357
        fsm->ldnalloc = fsm->ldnlen = 0;
 
1358
 
 
1359
        fsm->rdsize = fsm->wrsize = 0;
 
1360
        fsm->rdbuf = fsm->rdb = _free(fsm->rdb);
 
1361
        fsm->wrbuf = fsm->wrb = _free(fsm->wrb);
 
1362
        if (fsm->goal == FSM_PKGINSTALL || fsm->goal == FSM_PKGBUILD) {
 
1363
            fsm->rdsize = 8 * BUFSIZ;
 
1364
            fsm->rdbuf = fsm->rdb = xmalloc(fsm->rdsize);
 
1365
            fsm->wrsize = 8 * BUFSIZ;
 
1366
            fsm->wrbuf = fsm->wrb = xmalloc(fsm->wrsize);
 
1367
        }
 
1368
 
 
1369
        fsm->mkdirsdone = 0;
 
1370
        fsm->ix = -1;
 
1371
        fsm->links = NULL;
 
1372
        fsm->li = NULL;
 
1373
        errno = 0;      /* XXX get rid of EBADF */
 
1374
 
 
1375
        /* Detect and create directories not explicitly in package. */
 
1376
        if (fsm->goal == FSM_PKGINSTALL) {
 
1377
            rc = fsmStage(fsm, FSM_MKDIRS);
 
1378
            if (!rc) fsm->mkdirsdone = 1;
 
1379
        }
 
1380
 
 
1381
        break;
 
1382
    case FSM_INIT:
 
1383
        fsm->path = _free(fsm->path);
 
1384
        fsm->postpone = 0;
 
1385
        fsm->diskchecked = fsm->exists = 0;
 
1386
        fsm->subdir = NULL;
 
1387
        fsm->suffix = (fsm->sufbuf[0] != '\0' ? fsm->sufbuf : NULL);
 
1388
        fsm->action = FA_UNKNOWN;
 
1389
        fsm->osuffix = NULL;
 
1390
        fsm->nsuffix = NULL;
 
1391
 
 
1392
        if (fsm->goal == FSM_PKGINSTALL) {
 
1393
            /* Read next header from payload, checking for end-of-payload. */
 
1394
            rc = fsmStage(fsm, FSM_NEXT);
 
1395
        }
 
1396
        if (rc) break;
 
1397
 
 
1398
        /* Identify mapping index. */
 
1399
        fsm->ix = ((fsm->goal == FSM_PKGINSTALL)
 
1400
                ? mapFind(fsm->iter, fsm->path) : mapNextIterator(fsm->iter));
 
1401
 
 
1402
        /* Detect end-of-loop and/or mapping error. */
 
1403
        if (fsm->ix < 0) {
 
1404
            if (fsm->goal == FSM_PKGINSTALL) {
 
1405
#if 0
 
1406
                rpmMessage(RPMMESS_WARNING,
 
1407
                    _("archive file %s was not found in header file list\n"),
 
1408
                        fsm->path);
 
1409
#endif
 
1410
                if (fsm->failedFile && *fsm->failedFile == NULL)
 
1411
                    *fsm->failedFile = xstrdup(fsm->path);
 
1412
                rc = CPIOERR_UNMAPPED_FILE;
 
1413
            } else {
 
1414
                rc = CPIOERR_HDR_TRAILER;
 
1415
            }
 
1416
            break;
 
1417
        }
 
1418
 
 
1419
        /* On non-install, mode must be known so that dirs don't get suffix. */
 
1420
        if (fsm->goal != FSM_PKGINSTALL) {
 
1421
            TFI_t fi = fsmGetFi(fsm);
 
1422
            st->st_mode = fi->fmodes[fsm->ix];
 
1423
        }
 
1424
 
 
1425
        /* Generate file path. */
 
1426
        rc = fsmStage(fsm, FSM_MAP);
 
1427
        if (rc) break;
 
1428
 
 
1429
        /* Perform lstat/stat for disk file. */
 
1430
#ifdef  NOTYET
 
1431
        rc = fsmStat(fsm);
 
1432
#else
 
1433
        if (fsm->path != NULL) {
 
1434
            rc = fsmStage(fsm, (!(fsm->mapFlags & CPIO_FOLLOW_SYMLINKS)
 
1435
                        ? FSM_LSTAT : FSM_STAT));
 
1436
            if (rc == CPIOERR_LSTAT_FAILED && errno == ENOENT) {
 
1437
                errno = saveerrno;
 
1438
                rc = 0;
 
1439
                fsm->exists = 0;
 
1440
            } else if (rc == 0) {
 
1441
                fsm->exists = 1;
 
1442
            }
 
1443
        } else {
 
1444
            /* Skip %ghost files on build. */
 
1445
            fsm->exists = 0;
 
1446
        }
 
1447
#endif
 
1448
        fsm->diskchecked = 1;
 
1449
        if (rc) break;
 
1450
 
 
1451
        /* On non-install, the disk file stat is what's remapped. */
 
1452
        if (fsm->goal != FSM_PKGINSTALL)
 
1453
            *st = *ost;                 /* structure assignment */
 
1454
 
 
1455
        /* Remap file perms, owner, and group. */
 
1456
        rc = fsmMapAttrs(fsm);
 
1457
        if (rc) break;
 
1458
 
 
1459
        fsm->postpone = XFA_SKIPPING(fsm->action);
 
1460
        if (fsm->goal == FSM_PKGINSTALL || fsm->goal == FSM_PKGBUILD) {
 
1461
            /*@-evalorder@*/
 
1462
            if (!S_ISDIR(st->st_mode) && st->st_nlink > 1)
 
1463
                fsm->postpone = saveHardLink(fsm);
 
1464
            /*@=evalorder@*/
 
1465
        }
 
1466
        break;
 
1467
    case FSM_PRE:
 
1468
        break;
 
1469
    case FSM_MAP:
 
1470
        rc = fsmMapPath(fsm);
 
1471
        break;
 
1472
    case FSM_MKDIRS:
 
1473
        rc = fsmMkdirs(fsm);
 
1474
        break;
 
1475
    case FSM_RMDIRS:
 
1476
        if (fsm->dnlx)
 
1477
            rc = fsmRmdirs(fsm);
 
1478
        break;
 
1479
    case FSM_PROCESS:
 
1480
        if (fsm->postpone) {
 
1481
            if (fsm->goal == FSM_PKGINSTALL)
 
1482
                rc = fsmStage(fsm, FSM_EAT);
 
1483
            break;
 
1484
        }
 
1485
 
 
1486
        if (fsm->goal == FSM_PKGBUILD) {
 
1487
            if (!S_ISDIR(st->st_mode) && st->st_nlink > 1) {
 
1488
                struct hardLink * li, * prev;
 
1489
 
 
1490
if (!(fsm->mapFlags & CPIO_ALL_HARDLINKS)) break;
 
1491
                rc = writeLinkedFile(fsm);
 
1492
                if (rc) break;  /* W2DO? */
 
1493
 
 
1494
                for (li = fsm->links, prev = NULL; li; prev = li, li = li->next)
 
1495
                     if (li == fsm->li)
 
1496
                        /*@loopbreak@*/ break;
 
1497
 
 
1498
                if (prev == NULL)
 
1499
                    fsm->links = fsm->li->next;
 
1500
                else
 
1501
                    prev->next = fsm->li->next;
 
1502
                fsm->li->next = NULL;
 
1503
                fsm->li = freeHardLink(fsm->li);
 
1504
            } else {
 
1505
                rc = writeFile(fsm, 1);
 
1506
            }
 
1507
            break;
 
1508
        }
 
1509
 
 
1510
        if (fsm->goal != FSM_PKGINSTALL)
 
1511
            break;
 
1512
 
 
1513
        if (S_ISREG(st->st_mode)) {
 
1514
            const char * path = fsm->path;
 
1515
            if (fsm->osuffix)
 
1516
                fsm->path = fsmFsPath(fsm, st, NULL, NULL);
 
1517
            rc = fsmStage(fsm, FSM_VERIFY);
 
1518
 
 
1519
            if (rc == 0 && fsm->osuffix) {
 
1520
                const char * opath = fsm->opath;
 
1521
                fsm->opath = fsm->path;
 
1522
                fsm->path = fsmFsPath(fsm, st, NULL, fsm->osuffix);
 
1523
                rc = fsmStage(fsm, FSM_RENAME);
 
1524
                if (!rc)
 
1525
                    rpmMessage(RPMMESS_WARNING,
 
1526
                        _("%s saved as %s\n"), fsm->opath, fsm->path);
 
1527
                fsm->path = _free(fsm->path);
 
1528
                fsm->opath = opath;
 
1529
            }
 
1530
 
 
1531
            /*@-dependenttrans@*/
 
1532
            fsm->path = path;
 
1533
            /*@=dependenttrans@*/
 
1534
            if (rc != CPIOERR_LSTAT_FAILED) return rc;
 
1535
            rc = expandRegular(fsm);
 
1536
        } else if (S_ISDIR(st->st_mode)) {
 
1537
            mode_t st_mode = st->st_mode;
 
1538
            rc = fsmStage(fsm, FSM_VERIFY);
 
1539
            if (rc == CPIOERR_LSTAT_FAILED) {
 
1540
                st->st_mode &= ~07777;          /* XXX abuse st->st_mode */
 
1541
                st->st_mode |=  00700;
 
1542
                rc = fsmStage(fsm, FSM_MKDIR);
 
1543
                st->st_mode = st_mode;          /* XXX restore st->st_mode */
 
1544
            }
 
1545
        } else if (S_ISLNK(st->st_mode)) {
 
1546
            const char * opath = fsm->opath;
 
1547
 
 
1548
            if ((st->st_size + 1) > fsm->rdsize) {
 
1549
                rc = CPIOERR_HDR_SIZE;
 
1550
                break;
 
1551
            }
 
1552
 
 
1553
            fsm->wrlen = st->st_size;
 
1554
            rc = fsmStage(fsm, FSM_DREAD);
 
1555
            if (!rc && fsm->rdnb != fsm->wrlen)
 
1556
                rc = CPIOERR_READ_FAILED;
 
1557
            if (rc) break;
 
1558
 
 
1559
            fsm->wrbuf[st->st_size] = '\0';
 
1560
            /* XXX symlink(fsm->opath, fsm->path) */
 
1561
            /*@-dependenttrans@*/
 
1562
            fsm->opath = fsm->wrbuf;
 
1563
            /*@=dependenttrans@*/
 
1564
            rc = fsmStage(fsm, FSM_VERIFY);
 
1565
            if (rc == CPIOERR_LSTAT_FAILED)
 
1566
                rc = fsmStage(fsm, FSM_SYMLINK);
 
1567
            fsm->opath = opath;         /* XXX restore fsm->path */
 
1568
        } else if (S_ISFIFO(st->st_mode)) {
 
1569
            mode_t st_mode = st->st_mode;
 
1570
            /* This mimics cpio S_ISSOCK() behavior but probably isnt' right */
 
1571
            rc = fsmStage(fsm, FSM_VERIFY);
 
1572
            if (rc == CPIOERR_LSTAT_FAILED) {
 
1573
                st->st_mode = 0000;             /* XXX abuse st->st_mode */
 
1574
                rc = fsmStage(fsm, FSM_MKFIFO);
 
1575
                st->st_mode = st_mode;  /* XXX restore st->st_mode */
 
1576
            }
 
1577
        } else if (S_ISCHR(st->st_mode) ||
 
1578
                   S_ISBLK(st->st_mode) ||
 
1579
    /*@-unrecog@*/ S_ISSOCK(st->st_mode) /*@=unrecog@*/)
 
1580
        {
 
1581
            rc = fsmStage(fsm, FSM_VERIFY);
 
1582
            if (rc == CPIOERR_LSTAT_FAILED)
 
1583
                rc = fsmStage(fsm, FSM_MKNOD);
 
1584
        } else {
 
1585
            rc = CPIOERR_UNKNOWN_FILETYPE;
 
1586
        }
 
1587
        if (!S_ISDIR(st->st_mode) && st->st_nlink > 1) {
 
1588
            fsm->li->createdPath = fsm->li->linkIndex;
 
1589
            rc = fsmMakeLinks(fsm);
 
1590
        }
 
1591
        break;
 
1592
    case FSM_POST:
 
1593
        break;
 
1594
    case FSM_MKLINKS:
 
1595
        rc = fsmMakeLinks(fsm);
 
1596
        break;
 
1597
    case FSM_NOTIFY:            /* XXX move from fsm to psm -> tsm */
 
1598
        if (fsm->goal == FSM_PKGINSTALL || fsm->goal == FSM_PKGBUILD) {
 
1599
            rpmTransactionSet ts = fsmGetTs(fsm);
 
1600
            TFI_t fi = fsmGetFi(fsm);
 
1601
            if (ts && ts->notify && fi)
 
1602
                (void)ts->notify(fi->h, RPMCALLBACK_INST_PROGRESS,
 
1603
                        fdGetCpioPos(fsm->cfd), fi->archiveSize,
 
1604
                        (fi->ap ? fi->ap->key : NULL), ts->notifyData);
 
1605
        }
 
1606
        break;
 
1607
    case FSM_UNDO:
 
1608
        if (fsm->postpone)
 
1609
            break;
 
1610
        if (fsm->goal == FSM_PKGINSTALL) {
 
1611
            (void) fsmStage(fsm,
 
1612
                (S_ISDIR(st->st_mode) ? FSM_RMDIR : FSM_UNLINK));
 
1613
 
 
1614
#ifdef  NOTYET  /* XXX remove only dirs just created, not all. */
 
1615
            if (fsm->dnlx)
 
1616
                (void) fsmStage(fsm, FSM_RMDIRS);
 
1617
#endif
 
1618
            errno = saveerrno;
 
1619
        }
 
1620
        if (fsm->failedFile && *fsm->failedFile == NULL)
 
1621
            *fsm->failedFile = xstrdup(fsm->path);
 
1622
        break;
 
1623
    case FSM_FINI:
 
1624
        if (!fsm->postpone && fsm->commit) {
 
1625
            if (fsm->goal == FSM_PKGINSTALL)
 
1626
                rc = ((!S_ISDIR(st->st_mode) && st->st_nlink > 1)
 
1627
                        ? fsmCommitLinks(fsm) : fsmStage(fsm, FSM_COMMIT));
 
1628
            if (fsm->goal == FSM_PKGCOMMIT)
 
1629
                rc = fsmStage(fsm, FSM_COMMIT);
 
1630
            if (fsm->goal == FSM_PKGERASE)
 
1631
                rc = fsmStage(fsm, FSM_COMMIT);
 
1632
        }
 
1633
        fsm->path = _free(fsm->path);
 
1634
        fsm->opath = _free(fsm->opath);
 
1635
        memset(st, 0, sizeof(*st));
 
1636
        memset(ost, 0, sizeof(*ost));
 
1637
        break;
 
1638
    case FSM_COMMIT:
 
1639
        /* Rename pre-existing modified or unmanaged file. */
 
1640
        if (fsm->diskchecked && fsm->exists && fsm->osuffix) {
 
1641
            const char * opath = fsm->opath;
 
1642
            const char * path = fsm->path;
 
1643
            /*@-nullstate@*/    /* FIX: fsm->opath null annotation? */
 
1644
            fsm->opath = fsmFsPath(fsm, st, NULL, NULL);
 
1645
            /*@=nullstate@*/
 
1646
            /*@-nullstate@*/    /* FIX: fsm->path null annotation? */
 
1647
            fsm->path = fsmFsPath(fsm, st, NULL, fsm->osuffix);
 
1648
            /*@=nullstate@*/
 
1649
            rc = fsmStage(fsm, FSM_RENAME);
 
1650
            if (!rc) {
 
1651
                rpmMessage(RPMMESS_WARNING, _("%s saved as %s\n"),
 
1652
                                fsm->opath, fsm->path);
 
1653
            }
 
1654
            fsm->path = _free(fsm->path);
 
1655
            fsm->path = path;
 
1656
            fsm->opath = _free(fsm->opath);
 
1657
            fsm->opath = opath;
 
1658
        }
 
1659
 
 
1660
        /* Remove erased files. */
 
1661
        if (fsm->goal == FSM_PKGERASE) {
 
1662
            if (fsm->action == FA_ERASE) {
 
1663
                TFI_t fi = fsmGetFi(fsm);
 
1664
                if (S_ISDIR(st->st_mode)) {
 
1665
                    rc = fsmStage(fsm, FSM_RMDIR);
 
1666
                    if (!rc) break;
 
1667
                    switch (errno) {
 
1668
                    case ENOENT: /* XXX rmdir("/") linux 2.2.x kernel hack */
 
1669
                    case ENOTEMPTY:
 
1670
        /* XXX make sure that build side permits %missingok on directories. */
 
1671
                        if (fsm->fflags & RPMFILE_MISSINGOK)
 
1672
                            break;
 
1673
 
 
1674
                        /* XXX common error message. */
 
1675
                        rpmError(
 
1676
                            (strict_erasures ? RPMERR_RMDIR : RPMDEBUG_RMDIR),
 
1677
                            _("%s rmdir of %s failed: Directory not empty\n"), 
 
1678
                                fiTypeString(fi), fsm->path);
 
1679
                        break;
 
1680
                    default:
 
1681
                        rpmError(
 
1682
                            (strict_erasures ? RPMERR_RMDIR : RPMDEBUG_RMDIR),
 
1683
                                _("%s rmdir of %s failed: %s\n"),
 
1684
                                fiTypeString(fi), fsm->path, strerror(errno));
 
1685
                        break;
 
1686
                    }
 
1687
                } else {
 
1688
                    rc = fsmStage(fsm, FSM_UNLINK);
 
1689
                    if (!rc) break;
 
1690
                    if (!(errno == ENOENT && (fsm->fflags & RPMFILE_MISSINGOK)))
 
1691
                        rpmError(
 
1692
                            (strict_erasures ? RPMERR_UNLINK : RPMDEBUG_UNLINK),
 
1693
                                _("%s unlink of %s failed: %s\n"),
 
1694
                                fiTypeString(fi), fsm->path, strerror(errno));
 
1695
                }
 
1696
            }
 
1697
            /* XXX Failure to remove is not (yet) cause for failure. */
 
1698
            if (!strict_erasures) rc = 0;
 
1699
            break;
 
1700
        }
 
1701
 
 
1702
        if (!S_ISSOCK(st->st_mode)) {   /* XXX /dev/log et al are skipped */
 
1703
            /* Rename temporary to final file name. */
 
1704
            if (!S_ISDIR(st->st_mode) &&
 
1705
                (fsm->subdir || fsm->suffix || fsm->nsuffix))
 
1706
            {
 
1707
                fsm->opath = fsm->path;
 
1708
                fsm->path = fsmFsPath(fsm, st, NULL, fsm->nsuffix);
 
1709
                rc = fsmStage(fsm, FSM_RENAME);
 
1710
                if (!rc && fsm->nsuffix) {
 
1711
                    const char * opath = fsmFsPath(fsm, st, NULL, NULL);
 
1712
                    rpmMessage(RPMMESS_WARNING, _("%s created as %s\n"),
 
1713
                                (opath ? opath : ""), fsm->path);
 
1714
                    opath = _free(opath);
 
1715
                }
 
1716
                fsm->opath = _free(fsm->opath);
 
1717
            }
 
1718
            if (S_ISLNK(st->st_mode)) {
 
1719
                if (!rc && !getuid())
 
1720
                    rc = fsmStage(fsm, FSM_LCHOWN);
 
1721
            } else {
 
1722
                if (!rc && !getuid())
 
1723
                    rc = fsmStage(fsm, FSM_CHOWN);
 
1724
                if (!rc)
 
1725
                    rc = fsmStage(fsm, FSM_CHMOD);
 
1726
                if (!rc) {
 
1727
                    time_t mtime = st->st_mtime;
 
1728
                    TFI_t fi = fsmGetFi(fsm);
 
1729
                    if (fi->fmtimes)
 
1730
                        st->st_mtime = fi->fmtimes[fsm->ix];
 
1731
                    rc = fsmStage(fsm, FSM_UTIME);
 
1732
                    st->st_mtime = mtime;
 
1733
                }
 
1734
            }
 
1735
        }
 
1736
 
 
1737
        /* Notify on success. */
 
1738
        if (!rc)                rc = fsmStage(fsm, FSM_NOTIFY);
 
1739
        else if (fsm->failedFile && *fsm->failedFile == NULL) {
 
1740
            *fsm->failedFile = fsm->path;
 
1741
            fsm->path = NULL;
 
1742
        }
 
1743
        break;
 
1744
    case FSM_DESTROY:
 
1745
        fsm->path = _free(fsm->path);
 
1746
 
 
1747
        /* Check for hard links missing from payload. */
 
1748
        while ((fsm->li = fsm->links) != NULL) {
 
1749
            fsm->links = fsm->li->next;
 
1750
            fsm->li->next = NULL;
 
1751
            if (fsm->goal == FSM_PKGINSTALL &&
 
1752
                        fsm->commit && fsm->li->linksLeft)
 
1753
            {
 
1754
                for (i = 0 ; i < fsm->li->linksLeft; i++) {
 
1755
                    if (fsm->li->filex[i] < 0) continue;
 
1756
                    rc = CPIOERR_MISSING_HARDLINK;
 
1757
                    if (fsm->failedFile && *fsm->failedFile == NULL) {
 
1758
                        fsm->ix = fsm->li->filex[i];
 
1759
                        if (!fsmStage(fsm, FSM_MAP)) {
 
1760
                            *fsm->failedFile = fsm->path;
 
1761
                            fsm->path = NULL;
 
1762
                        }
 
1763
                    }
 
1764
                    /*@loopbreak@*/ break;
 
1765
                }
 
1766
            }
 
1767
            if (fsm->goal == FSM_PKGBUILD &&
 
1768
                (fsm->mapFlags & CPIO_ALL_HARDLINKS))
 
1769
            {
 
1770
                rc = CPIOERR_MISSING_HARDLINK;
 
1771
            }
 
1772
            fsm->li = freeHardLink(fsm->li);
 
1773
        }
 
1774
        fsm->ldn = _free(fsm->ldn);
 
1775
        fsm->ldnalloc = fsm->ldnlen = 0;
 
1776
        fsm->rdbuf = fsm->rdb = _free(fsm->rdb);
 
1777
        fsm->wrbuf = fsm->wrb = _free(fsm->wrb);
 
1778
        break;
 
1779
    case FSM_VERIFY:
 
1780
        if (fsm->diskchecked && !fsm->exists) {
 
1781
            rc = CPIOERR_LSTAT_FAILED;
 
1782
            break;
 
1783
        }
 
1784
        if (S_ISREG(st->st_mode)) {
 
1785
            char * path = alloca(strlen(fsm->path) + sizeof("-RPMDELETE"));
 
1786
            (void) stpcpy( stpcpy(path, fsm->path), "-RPMDELETE");
 
1787
            /*
 
1788
             * XXX HP-UX (and other os'es) don't permit unlink on busy
 
1789
             * XXX files.
 
1790
             */
 
1791
            fsm->opath = fsm->path;
 
1792
            fsm->path = path;
 
1793
            rc = fsmStage(fsm, FSM_RENAME);
 
1794
            if (!rc)
 
1795
                    (void) fsmStage(fsm, FSM_UNLINK);
 
1796
            else
 
1797
                    rc = CPIOERR_UNLINK_FAILED;
 
1798
            fsm->path = fsm->opath;
 
1799
            fsm->opath = NULL;
 
1800
            return (rc ? rc : CPIOERR_LSTAT_FAILED);    /* XXX HACK */
 
1801
            /*@notreached@*/ break;
 
1802
        } else if (S_ISDIR(st->st_mode)) {
 
1803
            if (S_ISDIR(ost->st_mode))          return 0;
 
1804
            if (S_ISLNK(ost->st_mode)) {
 
1805
                rc = fsmStage(fsm, FSM_STAT);
 
1806
                if (rc == CPIOERR_STAT_FAILED && errno == ENOENT) rc = 0;
 
1807
                if (rc) break;
 
1808
                errno = saveerrno;
 
1809
                if (S_ISDIR(ost->st_mode))      return 0;
 
1810
            }
 
1811
        } else if (S_ISLNK(st->st_mode)) {
 
1812
            if (S_ISLNK(ost->st_mode)) {
 
1813
        /* XXX NUL terminated result in fsm->rdbuf, len in fsm->rdnb. */
 
1814
                rc = fsmStage(fsm, FSM_READLINK);
 
1815
                errno = saveerrno;
 
1816
                if (rc) break;
 
1817
                if (!strcmp(fsm->opath, fsm->rdbuf))    return 0;
 
1818
            }
 
1819
        } else if (S_ISFIFO(st->st_mode)) {
 
1820
            if (S_ISFIFO(ost->st_mode))         return 0;
 
1821
        } else if (S_ISCHR(st->st_mode) || S_ISBLK(st->st_mode)) {
 
1822
            if ((S_ISCHR(ost->st_mode) || S_ISBLK(ost->st_mode)) &&
 
1823
                (ost->st_rdev == st->st_rdev))  return 0;
 
1824
        } else if (S_ISSOCK(st->st_mode)) {
 
1825
            if (S_ISSOCK(ost->st_mode))         return 0;
 
1826
        }
 
1827
            /* XXX shouldn't do this with commit/undo. */
 
1828
        rc = 0;
 
1829
        if (fsm->stage == FSM_PROCESS) rc = fsmStage(fsm, FSM_UNLINK);
 
1830
        if (rc == 0)    rc = CPIOERR_LSTAT_FAILED;
 
1831
        return (rc ? rc : CPIOERR_LSTAT_FAILED);        /* XXX HACK */
 
1832
        /*@notreached@*/ break;
 
1833
 
 
1834
    case FSM_UNLINK:
 
1835
        rc = Unlink(fsm->path);
 
1836
        if (_fsm_debug && (stage & FSM_SYSCALL))
 
1837
            rpmMessage(RPMMESS_DEBUG, " %8s (%s) %s\n", cur,
 
1838
                fsm->path, (rc < 0 ? strerror(errno) : ""));
 
1839
        if (rc < 0)     rc = CPIOERR_UNLINK_FAILED;
 
1840
        break;
 
1841
    case FSM_RENAME:
 
1842
        rc = Rename(fsm->opath, fsm->path);
 
1843
        if (_fsm_debug && (stage & FSM_SYSCALL))
 
1844
            rpmMessage(RPMMESS_DEBUG, " %8s (%s, %s) %s\n", cur,
 
1845
                fsm->opath, fsm->path, (rc < 0 ? strerror(errno) : ""));
 
1846
        if (rc < 0)     rc = CPIOERR_RENAME_FAILED;
 
1847
        break;
 
1848
    case FSM_MKDIR:
 
1849
        rc = Mkdir(fsm->path, (st->st_mode & 07777));
 
1850
        if (_fsm_debug && (stage & FSM_SYSCALL))
 
1851
            rpmMessage(RPMMESS_DEBUG, " %8s (%s, 0%04o) %s\n", cur,
 
1852
                fsm->path, (unsigned)(st->st_mode & 07777),
 
1853
                (rc < 0 ? strerror(errno) : ""));
 
1854
        if (rc < 0)     rc = CPIOERR_MKDIR_FAILED;
 
1855
        break;
 
1856
    case FSM_RMDIR:
 
1857
        rc = Rmdir(fsm->path);
 
1858
        if (_fsm_debug && (stage & FSM_SYSCALL))
 
1859
            rpmMessage(RPMMESS_DEBUG, " %8s (%s) %s\n", cur,
 
1860
                fsm->path, (rc < 0 ? strerror(errno) : ""));
 
1861
        if (rc < 0)     rc = CPIOERR_RMDIR_FAILED;
 
1862
        break;
 
1863
    case FSM_CHOWN:
 
1864
        rc = chown(fsm->path, st->st_uid, st->st_gid);
 
1865
        if (_fsm_debug && (stage & FSM_SYSCALL))
 
1866
            rpmMessage(RPMMESS_DEBUG, " %8s (%s, %d, %d) %s\n", cur,
 
1867
                fsm->path, (int)st->st_uid, (int)st->st_gid,
 
1868
                (rc < 0 ? strerror(errno) : ""));
 
1869
        if (rc < 0)     rc = CPIOERR_CHOWN_FAILED;
 
1870
        break;
 
1871
    case FSM_LCHOWN:
 
1872
#if ! CHOWN_FOLLOWS_SYMLINK
 
1873
        rc = lchown(fsm->path, st->st_uid, st->st_gid);
 
1874
        if (_fsm_debug && (stage & FSM_SYSCALL))
 
1875
            rpmMessage(RPMMESS_DEBUG, " %8s (%s, %d, %d) %s\n", cur,
 
1876
                fsm->path, (int)st->st_uid, (int)st->st_gid,
 
1877
                (rc < 0 ? strerror(errno) : ""));
 
1878
        if (rc < 0)     rc = CPIOERR_CHOWN_FAILED;
 
1879
#endif
 
1880
        break;
 
1881
    case FSM_CHMOD:
 
1882
        rc = chmod(fsm->path, (st->st_mode & 07777));
 
1883
        if (_fsm_debug && (stage & FSM_SYSCALL))
 
1884
            rpmMessage(RPMMESS_DEBUG, " %8s (%s, 0%04o) %s\n", cur,
 
1885
                fsm->path, (unsigned)(st->st_mode & 07777),
 
1886
                (rc < 0 ? strerror(errno) : ""));
 
1887
        if (rc < 0)     rc = CPIOERR_CHMOD_FAILED;
 
1888
        break;
 
1889
    case FSM_UTIME:
 
1890
        {   struct utimbuf stamp;
 
1891
            stamp.actime = st->st_mtime;
 
1892
            stamp.modtime = st->st_mtime;
 
1893
            rc = utime(fsm->path, &stamp);
 
1894
            if (_fsm_debug && (stage & FSM_SYSCALL))
 
1895
                rpmMessage(RPMMESS_DEBUG, " %8s (%s, 0x%x) %s\n", cur,
 
1896
                        fsm->path, (unsigned)st->st_mtime,
 
1897
                        (rc < 0 ? strerror(errno) : ""));
 
1898
            if (rc < 0) rc = CPIOERR_UTIME_FAILED;
 
1899
        }
 
1900
        break;
 
1901
    case FSM_SYMLINK:
 
1902
        rc = symlink(fsm->opath, fsm->path);
 
1903
        if (_fsm_debug && (stage & FSM_SYSCALL))
 
1904
            rpmMessage(RPMMESS_DEBUG, " %8s (%s, %s) %s\n", cur,
 
1905
                fsm->opath, fsm->path, (rc < 0 ? strerror(errno) : ""));
 
1906
        if (rc < 0)     rc = CPIOERR_SYMLINK_FAILED;
 
1907
        break;
 
1908
    case FSM_LINK:
 
1909
        rc = Link(fsm->opath, fsm->path);
 
1910
        if (_fsm_debug && (stage & FSM_SYSCALL))
 
1911
            rpmMessage(RPMMESS_DEBUG, " %8s (%s, %s) %s\n", cur,
 
1912
                fsm->opath, fsm->path, (rc < 0 ? strerror(errno) : ""));
 
1913
        if (rc < 0)     rc = CPIOERR_LINK_FAILED;
 
1914
        break;
 
1915
    case FSM_MKFIFO:
 
1916
        rc = mkfifo(fsm->path, (st->st_mode & 07777));
 
1917
        if (_fsm_debug && (stage & FSM_SYSCALL))
 
1918
            rpmMessage(RPMMESS_DEBUG, " %8s (%s, 0%04o) %s\n", cur,
 
1919
                fsm->path, (unsigned)(st->st_mode & 07777),
 
1920
                (rc < 0 ? strerror(errno) : ""));
 
1921
        if (rc < 0)     rc = CPIOERR_MKFIFO_FAILED;
 
1922
        break;
 
1923
    case FSM_MKNOD:
 
1924
        /*@-unrecog -portability @*/ /* FIX: check S_IFIFO or dev != 0 */
 
1925
        rc = mknod(fsm->path, (st->st_mode & ~07777), st->st_rdev);
 
1926
        /*@=unrecog =portability @*/
 
1927
        if (_fsm_debug && (stage & FSM_SYSCALL))
 
1928
            rpmMessage(RPMMESS_DEBUG, " %8s (%s, 0%o, 0x%x) %s\n", cur,
 
1929
                fsm->path, (unsigned)(st->st_mode & ~07777),
 
1930
                (unsigned)st->st_rdev,
 
1931
                (rc < 0 ? strerror(errno) : ""));
 
1932
        if (rc < 0)     rc = CPIOERR_MKNOD_FAILED;
 
1933
        break;
 
1934
    case FSM_LSTAT:
 
1935
        rc = Lstat(fsm->path, ost);
 
1936
        if (_fsm_debug && (stage & FSM_SYSCALL) && rc && errno != ENOENT)
 
1937
            rpmMessage(RPMMESS_DEBUG, " %8s (%s, ost) %s\n", cur,
 
1938
                fsm->path, (rc < 0 ? strerror(errno) : ""));
 
1939
        if (rc < 0)     rc = CPIOERR_LSTAT_FAILED;
 
1940
        break;
 
1941
    case FSM_STAT:
 
1942
        rc = Stat(fsm->path, ost);
 
1943
        if (_fsm_debug && (stage & FSM_SYSCALL) && rc && errno != ENOENT)
 
1944
            rpmMessage(RPMMESS_DEBUG, " %8s (%s, ost) %s\n", cur,
 
1945
                fsm->path, (rc < 0 ? strerror(errno) : ""));
 
1946
        if (rc < 0)     rc = CPIOERR_STAT_FAILED;
 
1947
        break;
 
1948
    case FSM_READLINK:
 
1949
        /* XXX NUL terminated result in fsm->rdbuf, len in fsm->rdnb. */
 
1950
        rc = Readlink(fsm->path, fsm->rdbuf, fsm->rdsize - 1);
 
1951
        if (_fsm_debug && (stage & FSM_SYSCALL))
 
1952
            rpmMessage(RPMMESS_DEBUG, " %8s (%s, rdbuf, %d) %s\n", cur,
 
1953
                fsm->path, (int)(fsm->rdsize -1), (rc < 0 ? strerror(errno) : ""));
 
1954
        if (rc < 0)     rc = CPIOERR_READLINK_FAILED;
 
1955
        else {
 
1956
            fsm->rdnb = rc;
 
1957
            fsm->rdbuf[fsm->rdnb] = '\0';
 
1958
            rc = 0;
 
1959
        }
 
1960
        break;
 
1961
    case FSM_CHROOT:
 
1962
        break;
 
1963
 
 
1964
    case FSM_NEXT:
 
1965
        rc = fsmStage(fsm, FSM_HREAD);
 
1966
        if (rc) break;
 
1967
        if (!strcmp(fsm->path, CPIO_TRAILER)) { /* Detect end-of-payload. */
 
1968
            fsm->path = _free(fsm->path);
 
1969
            rc = CPIOERR_HDR_TRAILER;
 
1970
        }
 
1971
        if (!rc)
 
1972
            rc = fsmStage(fsm, FSM_POS);
 
1973
        break;
 
1974
    case FSM_EAT:
 
1975
        for (left = st->st_size; left > 0; left -= fsm->rdnb) {
 
1976
            fsm->wrlen = (left > fsm->wrsize ? fsm->wrsize : left);
 
1977
            rc = fsmStage(fsm, FSM_DREAD);
 
1978
            if (rc)
 
1979
                /*@loopbreak@*/ break;
 
1980
        }
 
1981
        break;
 
1982
    case FSM_POS:
 
1983
        left = (modulo - (fdGetCpioPos(fsm->cfd) % modulo)) % modulo;
 
1984
        if (left) {
 
1985
            fsm->wrlen = left;
 
1986
            (void) fsmStage(fsm, FSM_DREAD);
 
1987
        }
 
1988
        break;
 
1989
    case FSM_PAD:
 
1990
        left = (modulo - (fdGetCpioPos(fsm->cfd) % modulo)) % modulo;
 
1991
        if (left) {
 
1992
            memset(fsm->rdbuf, 0, left);
 
1993
            /* XXX DWRITE uses rdnb for I/O length. */
 
1994
            fsm->rdnb = left;
 
1995
            (void) fsmStage(fsm, FSM_DWRITE);
 
1996
        }
 
1997
        break;
 
1998
    case FSM_TRAILER:
 
1999
        rc = cpioTrailerWrite(fsm);
 
2000
        break;
 
2001
    case FSM_HREAD:
 
2002
        rc = fsmStage(fsm, FSM_POS);
 
2003
        if (!rc)
 
2004
            rc = cpioHeaderRead(fsm, st);       /* Read next payload header. */
 
2005
        break;
 
2006
    case FSM_HWRITE:
 
2007
        rc = cpioHeaderWrite(fsm, st);          /* Write next payload header. */
 
2008
        break;
 
2009
    case FSM_DREAD:
 
2010
        fsm->rdnb = Fread(fsm->wrbuf, sizeof(*fsm->wrbuf), fsm->wrlen, fsm->cfd);
 
2011
        if (_fsm_debug && (stage & FSM_SYSCALL))
 
2012
            rpmMessage(RPMMESS_DEBUG, " %8s (%s, %d, cfd)\trdnb %d\n",
 
2013
                cur, (fsm->wrbuf == fsm->wrb ? "wrbuf" : "mmap"),
 
2014
                (int)fsm->wrlen, (int)fsm->rdnb);
 
2015
        if (fsm->rdnb != fsm->wrlen || Ferror(fsm->cfd))
 
2016
            rc = CPIOERR_READ_FAILED;
 
2017
        if (fsm->rdnb > 0)
 
2018
            fdSetCpioPos(fsm->cfd, fdGetCpioPos(fsm->cfd) + fsm->rdnb);
 
2019
        break;
 
2020
    case FSM_DWRITE:
 
2021
        fsm->wrnb = Fwrite(fsm->rdbuf, sizeof(*fsm->rdbuf), fsm->rdnb, fsm->cfd);
 
2022
        if (_fsm_debug && (stage & FSM_SYSCALL))
 
2023
            rpmMessage(RPMMESS_DEBUG, " %8s (%s, %d, cfd)\twrnb %d\n",
 
2024
                cur, (fsm->rdbuf == fsm->rdb ? "rdbuf" : "mmap"),
 
2025
                (int)fsm->rdnb, (int)fsm->wrnb);
 
2026
        if (fsm->rdnb != fsm->wrnb || Ferror(fsm->cfd))
 
2027
            rc = CPIOERR_WRITE_FAILED;
 
2028
        if (fsm->wrnb > 0)
 
2029
            fdSetCpioPos(fsm->cfd, fdGetCpioPos(fsm->cfd) + fsm->wrnb);
 
2030
        break;
 
2031
 
 
2032
    case FSM_ROPEN:
 
2033
        fsm->rfd = Fopen(fsm->path, "r.ufdio");
 
2034
        if (fsm->rfd == NULL || Ferror(fsm->rfd)) {
 
2035
            if (fsm->rfd)       (void) fsmStage(fsm, FSM_RCLOSE);
 
2036
            fsm->rfd = NULL;
 
2037
            rc = CPIOERR_OPEN_FAILED;
 
2038
            break;
 
2039
        }
 
2040
        if (_fsm_debug && (stage & FSM_SYSCALL))
 
2041
            rpmMessage(RPMMESS_DEBUG, " %8s (%s, \"r\") rfd %p rdbuf %p\n", cur,
 
2042
                fsm->path, fsm->rfd, fsm->rdbuf);
 
2043
        break;
 
2044
    case FSM_READ:
 
2045
        fsm->rdnb = Fread(fsm->rdbuf, sizeof(*fsm->rdbuf), fsm->rdlen, fsm->rfd);
 
2046
        if (_fsm_debug && (stage & FSM_SYSCALL))
 
2047
            rpmMessage(RPMMESS_DEBUG, " %8s (rdbuf, %d, rfd)\trdnb %d\n",
 
2048
                cur, (int)fsm->rdlen, (int)fsm->rdnb);
 
2049
        if (fsm->rdnb != fsm->rdlen || Ferror(fsm->rfd))
 
2050
            rc = CPIOERR_READ_FAILED;
 
2051
        break;
 
2052
    case FSM_RCLOSE:
 
2053
        if (fsm->rfd) {
 
2054
            if (_fsm_debug && (stage & FSM_SYSCALL))
 
2055
                rpmMessage(RPMMESS_DEBUG, " %8s (%p)\n", cur, fsm->rfd);
 
2056
            (void) Fclose(fsm->rfd);
 
2057
            errno = saveerrno;
 
2058
        }
 
2059
        fsm->rfd = NULL;
 
2060
        break;
 
2061
    case FSM_WOPEN:
 
2062
        fsm->wfd = Fopen(fsm->path, "w.ufdio");
 
2063
        if (fsm->wfd == NULL || Ferror(fsm->wfd)) {
 
2064
            if (fsm->wfd)       (void) fsmStage(fsm, FSM_WCLOSE);
 
2065
            fsm->wfd = NULL;
 
2066
            rc = CPIOERR_OPEN_FAILED;
 
2067
        }
 
2068
        if (_fsm_debug && (stage & FSM_SYSCALL))
 
2069
            rpmMessage(RPMMESS_DEBUG, " %8s (%s, \"w\") wfd %p wrbuf %p\n", cur,
 
2070
                fsm->path, fsm->wfd, fsm->wrbuf);
 
2071
        break;
 
2072
    case FSM_WRITE:
 
2073
        fsm->wrnb = Fwrite(fsm->wrbuf, sizeof(*fsm->wrbuf), fsm->rdnb, fsm->wfd);
 
2074
        if (_fsm_debug && (stage & FSM_SYSCALL))
 
2075
            rpmMessage(RPMMESS_DEBUG, " %8s (wrbuf, %d, wfd)\twrnb %d\n",
 
2076
                cur, (int)fsm->rdnb, (int)fsm->wrnb);
 
2077
        if (fsm->rdnb != fsm->wrnb || Ferror(fsm->wfd))
 
2078
            rc = CPIOERR_WRITE_FAILED;
 
2079
        break;
 
2080
    case FSM_WCLOSE:
 
2081
        if (fsm->wfd) {
 
2082
            if (_fsm_debug && (stage & FSM_SYSCALL))
 
2083
                rpmMessage(RPMMESS_DEBUG, " %8s (%p)\n", cur, fsm->wfd);
 
2084
            (void) Fclose(fsm->wfd);
 
2085
            errno = saveerrno;
 
2086
        }
 
2087
        fsm->wfd = NULL;
 
2088
        break;
 
2089
 
 
2090
    default:
 
2091
        break;
 
2092
    }
 
2093
 
 
2094
    if (!(stage & FSM_INTERNAL)) {
 
2095
        fsm->rc = (rc == CPIOERR_HDR_TRAILER ? 0 : rc);
 
2096
    }
 
2097
    return rc;
 
2098
}
 
2099
/*@=compmempass@*/
 
2100
 
 
2101
/*@obserever@*/ const char *const fileActionString(fileAction a)
 
2102
{
 
2103
    switch (a) {
 
2104
    case FA_UNKNOWN:    return "unknown";
 
2105
    case FA_CREATE:     return "create";
 
2106
    case FA_COPYOUT:    return "copyout";
 
2107
    case FA_COPYIN:     return "copyin";
 
2108
    case FA_BACKUP:     return "backup";
 
2109
    case FA_SAVE:       return "save";
 
2110
    case FA_SKIP:       return "skip";
 
2111
    case FA_ALTNAME:    return "altname";
 
2112
    case FA_ERASE:      return "erase";
 
2113
    case FA_SKIPNSTATE: return "skipnstate";
 
2114
    case FA_SKIPNETSHARED: return "skipnetshared";
 
2115
    case FA_SKIPMULTILIB: return "skipmultilib";
 
2116
    default:            return "???";
 
2117
    }
 
2118
    /*@notreached@*/
 
2119
}
 
2120
 
 
2121
/*@observer@*/ const char *const fileStageString(fileStage a) {
 
2122
    switch(a) {
 
2123
    case FSM_UNKNOWN:   return "unknown";
 
2124
 
 
2125
    case FSM_PKGINSTALL:return "pkginstall";
 
2126
    case FSM_PKGERASE:  return "pkgerase";
 
2127
    case FSM_PKGBUILD:  return "pkgbuild";
 
2128
    case FSM_PKGCOMMIT: return "pkgcommit";
 
2129
    case FSM_PKGUNDO:   return "pkgundo";
 
2130
 
 
2131
    case FSM_CREATE:    return "create";
 
2132
    case FSM_INIT:      return "init";
 
2133
    case FSM_MAP:       return "map";
 
2134
    case FSM_MKDIRS:    return "mkdirs";
 
2135
    case FSM_RMDIRS:    return "rmdirs";
 
2136
    case FSM_PRE:       return "pre";
 
2137
    case FSM_PROCESS:   return "process";
 
2138
    case FSM_POST:      return "post";
 
2139
    case FSM_MKLINKS:   return "mklinks";
 
2140
    case FSM_NOTIFY:    return "notify";
 
2141
    case FSM_UNDO:      return "undo";
 
2142
    case FSM_FINI:      return "fini";
 
2143
    case FSM_COMMIT:    return "commit";
 
2144
    case FSM_DESTROY:   return "destroy";
 
2145
    case FSM_VERIFY:    return "verify";
 
2146
 
 
2147
    case FSM_UNLINK:    return "Unlink";
 
2148
    case FSM_RENAME:    return "Rename";
 
2149
    case FSM_MKDIR:     return "Mkdir";
 
2150
    case FSM_RMDIR:     return "rmdir";
 
2151
    case FSM_CHOWN:     return "chown";
 
2152
    case FSM_LCHOWN:    return "lchown";
 
2153
    case FSM_CHMOD:     return "chmod";
 
2154
    case FSM_UTIME:     return "utime";
 
2155
    case FSM_SYMLINK:   return "symlink";
 
2156
    case FSM_LINK:      return "Link";
 
2157
    case FSM_MKFIFO:    return "mkfifo";
 
2158
    case FSM_MKNOD:     return "mknod";
 
2159
    case FSM_LSTAT:     return "Lstat";
 
2160
    case FSM_STAT:      return "Stat";
 
2161
    case FSM_READLINK:  return "Readlink";
 
2162
    case FSM_CHROOT:    return "chroot";
 
2163
 
 
2164
    case FSM_NEXT:      return "next";
 
2165
    case FSM_EAT:       return "eat";
 
2166
    case FSM_POS:       return "pos";
 
2167
    case FSM_PAD:       return "pad";
 
2168
    case FSM_TRAILER:   return "trailer";
 
2169
    case FSM_HREAD:     return "hread";
 
2170
    case FSM_HWRITE:    return "hwrite";
 
2171
    case FSM_DREAD:     return "Fread";
 
2172
    case FSM_DWRITE:    return "Fwrite";
 
2173
 
 
2174
    case FSM_ROPEN:     return "Fopen";
 
2175
    case FSM_READ:      return "Fread";
 
2176
    case FSM_RCLOSE:    return "Fclose";
 
2177
    case FSM_WOPEN:     return "Fopen";
 
2178
    case FSM_WRITE:     return "Fwrite";
 
2179
    case FSM_WCLOSE:    return "Fclose";
 
2180
 
 
2181
    default:            return "???";
 
2182
    }
 
2183
    /*@noteached@*/
 
2184
}