rpm 5.3.12
build/files.c
Go to the documentation of this file.
00001 
00007 #include "system.h"
00008 
00009 #define MYALLPERMS      07777
00010 
00011 #if defined(WITH_PCRE) && defined(WITH_PCRE_POSIX)
00012 #include <pcreposix.h>
00013 #else
00014 #include <regex.h>
00015 #endif
00016 
00017 #define _RPMIOB_INTERNAL
00018 #include <rpmiotypes.h>
00019 #include <rpmio_internal.h>     /* XXX fdGetFp */
00020 #include <rpmbf.h>
00021 #include <rpmcb.h>
00022 #define _RPMSX_INTERNAL         /* XXX permit disabling. */
00023 #include <rpmsx.h>
00024 #include <fts.h>
00025 #include <argv.h>
00026 
00027 #include "iosm.h"
00028 #define _RPMTAG_INTERNAL        /* XXX rpmTags->aTags */
00029 #define _RPMFI_INTERNAL
00030 #include <rpmbuild.h>
00031 
00032 #define _RPMTE_INTERNAL
00033 #include <rpmte.h>
00034 
00035 #include "rpmfc.h"
00036 
00037 #include "buildio.h"
00038 
00039 #include "legacy.h"     /* XXX dodigest */
00040 #include "debug.h"
00041 
00042 /*@access Header @*/
00043 /*@access rpmfi @*/
00044 /*@access rpmte @*/
00045 /*@access FD_t @*/
00046 
00047 #define SKIPWHITE(_x)   {while(*(_x) && (xisspace(*_x) || *(_x) == ',')) (_x)++;}
00048 #define SKIPNONWHITE(_x){while(*(_x) &&!(xisspace(*_x) || *(_x) == ',')) (_x)++;}
00049 
00050 #define MAXDOCDIR 1024
00051 
00054 typedef enum specdFlags_e {
00055     SPECD_DEFFILEMODE   = (1 << 0),
00056     SPECD_DEFDIRMODE    = (1 << 1),
00057     SPECD_DEFUID        = (1 << 2),
00058     SPECD_DEFGID        = (1 << 3),
00059     SPECD_DEFVERIFY     = (1 << 4),
00060 
00061     SPECD_FILEMODE      = (1 << 8),
00062     SPECD_DIRMODE       = (1 << 9),
00063     SPECD_UID           = (1 << 10),
00064     SPECD_GID           = (1 << 11),
00065     SPECD_VERIFY        = (1 << 12)
00066 } specdFlags;
00067 
00070 typedef struct FileListRec_s {
00071     struct stat fl_st;
00072 #define fl_dev  fl_st.st_dev
00073 #define fl_ino  fl_st.st_ino
00074 #define fl_mode fl_st.st_mode
00075 #define fl_nlink fl_st.st_nlink
00076 #define fl_uid  fl_st.st_uid
00077 #define fl_gid  fl_st.st_gid
00078 #define fl_rdev fl_st.st_rdev
00079 #define fl_size fl_st.st_size
00080 #define fl_mtime fl_st.st_mtime
00081 
00082 /*@only@*/
00083     const char *diskURL;        /* get file from here       */
00084 /*@only@*/
00085     const char *fileURL;        /* filename in cpio archive */
00086 /*@observer@*/
00087     const char *uname;
00088 /*@observer@*/
00089     const char *gname;
00090     unsigned    flags;
00091     specdFlags  specdFlags;     /* which attributes have been explicitly specified. */
00092     unsigned    verifyFlags;
00093 /*@only@*/
00094     const char *langs;          /* XXX locales separated with | */
00095 } * FileListRec;
00096 
00099 typedef struct AttrRec_s {
00100 /*@null@*/
00101     const char *ar_fmodestr;
00102 /*@null@*/
00103     const char *ar_dmodestr;
00104 /*@null@*/
00105     const char *ar_user;
00106 /*@null@*/
00107     const char *ar_group;
00108     mode_t      ar_fmode;
00109     mode_t      ar_dmode;
00110 } * AttrRec;
00111 
00112 /*@-readonlytrans@*/
00113 /*@unchecked@*/ /*@observer@*/
00114 static struct AttrRec_s root_ar = { NULL, NULL, "root", "root", 0, 0 };
00115 /*@=readonlytrans@*/
00116 
00120 typedef struct FileList_s {
00121 /*@only@*/
00122     const char * buildRootURL;
00123 /*@only@*/
00124     const char * prefix;
00125 
00126     int fileCount;
00127     int totalFileSize;
00128     int processingFailed;
00129 
00130     int passedSpecialDoc;
00131     int isSpecialDoc;
00132 
00133     int noGlob;
00134     unsigned devtype;
00135     unsigned devmajor;
00136     int devminor;
00137     
00138     int isDir;
00139     int inFtw;
00140     int currentFlags;
00141     specdFlags currentSpecdFlags;
00142     unsigned currentVerifyFlags;
00143     struct AttrRec_s cur_ar;
00144     struct AttrRec_s def_ar;
00145     specdFlags defSpecdFlags;
00146     unsigned defVerifyFlags;
00147     int nLangs;
00148 /*@only@*/ /*@null@*/
00149     const char ** currentLangs;
00150 
00151     /* Hard coded limit of MAXDOCDIR docdirs.         */
00152     /* If you break it you are doing something wrong. */
00153     const char * docDirs[MAXDOCDIR];
00154     int docDirCount;
00155     
00156 /*@only@*/
00157     FileListRec fileList;
00158     int fileListRecsAlloced;
00159     int fileListRecsUsed;
00160 } * FileList;
00161 
00164 static void nullAttrRec(/*@out@*/ AttrRec ar)   /*@modifies ar @*/
00165 {
00166     ar->ar_fmodestr = NULL;
00167     ar->ar_dmodestr = NULL;
00168     ar->ar_user = NULL;
00169     ar->ar_group = NULL;
00170     ar->ar_fmode = 0;
00171     ar->ar_dmode = 0;
00172 }
00173 
00176 static void freeAttrRec(AttrRec ar)     /*@modifies ar @*/
00177 {
00178     ar->ar_fmodestr = _free(ar->ar_fmodestr);
00179     ar->ar_dmodestr = _free(ar->ar_dmodestr);
00180     ar->ar_user = _free(ar->ar_user);
00181     ar->ar_group = _free(ar->ar_group);
00182     /* XXX doesn't free ar (yet) */
00183     /*@-nullstate@*/
00184     return;
00185     /*@=nullstate@*/
00186 }
00187 
00190 static void dupAttrRec(const AttrRec oar, /*@in@*/ /*@out@*/ AttrRec nar)
00191         /*@modifies nar @*/
00192 {
00193     if (oar == nar)
00194         return;
00195     freeAttrRec(nar);
00196     nar->ar_fmodestr = (oar->ar_fmodestr ? xstrdup(oar->ar_fmodestr) : NULL);
00197     nar->ar_dmodestr = (oar->ar_dmodestr ? xstrdup(oar->ar_dmodestr) : NULL);
00198     nar->ar_user = (oar->ar_user ? xstrdup(oar->ar_user) : NULL);
00199     nar->ar_group = (oar->ar_group ? xstrdup(oar->ar_group) : NULL);
00200     nar->ar_fmode = oar->ar_fmode;
00201     nar->ar_dmode = oar->ar_dmode;
00202 }
00203 
00204 #if 0
00205 
00207 static void dumpAttrRec(const char * msg, AttrRec ar)
00208         /*@globals fileSystem@*/
00209         /*@modifies fileSystem @*/
00210 {
00211     if (msg)
00212         fprintf(stderr, "%s:\t", msg);
00213     fprintf(stderr, "(%s, %s, %s, %s)\n",
00214         ar->ar_fmodestr,
00215         ar->ar_user,
00216         ar->ar_group,
00217         ar->ar_dmodestr);
00218 }
00219 #endif
00220 
00226 /*@null@*/
00227 static char *strtokWithQuotes(/*@null@*/ char *s, const char *delim)
00228         /*@modifies *s @*/
00229 {
00230     static char *olds = NULL;
00231     char *token;
00232 
00233     if (s == NULL)
00234         s = olds;
00235     if (s == NULL)
00236         return NULL;
00237 
00238     /* Skip leading delimiters */
00239     s += strspn(s, delim);
00240     if (*s == '\0')
00241         return NULL;
00242 
00243     /* Find the end of the token.  */
00244     token = s;
00245     if (*token == '"') {
00246         token++;
00247         /* Find next " char */
00248         s = strchr(token, '"');
00249     } else {
00250         s = strpbrk(token, delim);
00251     }
00252 
00253     /* Terminate it */
00254     if (s == NULL) {
00255         /* This token finishes the string */
00256         olds = strchr(token, '\0');
00257     } else {
00258         /* Terminate the token and make olds point past it */
00259         *s = '\0';
00260         olds = s+1;
00261     }
00262 
00263     /*@-retalias -temptrans @*/
00264     return token;
00265     /*@=retalias =temptrans @*/
00266 }
00267 
00270 static void timeCheck(int tc, Header h)
00271         /*@globals internalState @*/
00272         /*@modifies internalState @*/
00273 {
00274     HE_t he = memset(alloca(sizeof(*he)), 0, sizeof(*he));
00275     rpmuint32_t currentTime = (rpmuint32_t) time(NULL);
00276     rpmuint32_t * mtime;
00277     int xx;
00278     size_t i;
00279 
00280     he->tag = RPMTAG_FILEMTIMES;
00281     xx = headerGet(h, he, 0);
00282     mtime = he->p.ui32p;
00283     he->tag = RPMTAG_OLDFILENAMES;
00284     xx = headerGet(h, he, 0);
00285     
00286     for (i = 0; i < he->c; i++) {
00287         xx = currentTime - mtime[i];
00288         if (xx < 0) xx = -xx;
00289         if (xx > tc)
00290             rpmlog(RPMLOG_WARNING, _("TIMECHECK failure: %s\n"), he->p.argv[i]);
00291     }
00292     he->p.ptr = _free(he->p.ptr);
00293     mtime = _free(mtime);
00294 }
00295 
00298 typedef struct VFA {
00299 /*@observer@*/ /*@null@*/ const char * attribute;
00300     int not;
00301     int flag;
00302 } VFA_t;
00303 
00306 /*@-exportlocal -exportheadervar@*/
00307 /*@unchecked@*/
00308 static VFA_t verifyAttrs[] = {
00309     { "md5",    0,      RPMVERIFY_FDIGEST },    /* XXX legacy syntax */
00310     { "size",   0,      RPMVERIFY_FILESIZE },
00311     { "link",   0,      RPMVERIFY_LINKTO },
00312     { "user",   0,      RPMVERIFY_USER },
00313     { "group",  0,      RPMVERIFY_GROUP },
00314     { "mtime",  0,      RPMVERIFY_MTIME },
00315     { "mode",   0,      RPMVERIFY_MODE },
00316     { "rdev",   0,      RPMVERIFY_RDEV },
00317     { "digest", 0,      RPMVERIFY_FDIGEST },
00318     { "hmac",   0,      RPMVERIFY_HMAC },
00319     { NULL, 0,  0 }
00320 };
00321 /*@=exportlocal =exportheadervar@*/
00322 
00329 static rpmRC parseForVerify(char * buf, FileList fl)
00330         /*@modifies buf, fl->processingFailed,
00331                 fl->currentVerifyFlags, fl->defVerifyFlags,
00332                 fl->currentSpecdFlags, fl->defSpecdFlags @*/
00333 {
00334     char *p, *pe, *q;
00335     const char *name;
00336     unsigned *resultVerify;
00337     int negated;
00338     unsigned verifyFlags;
00339     specdFlags * specdFlags;
00340 
00341     if ((p = strstr(buf, (name = "%verify"))) != NULL) {
00342         resultVerify = &(fl->currentVerifyFlags);
00343         specdFlags = &fl->currentSpecdFlags;
00344     } else if ((p = strstr(buf, (name = "%defverify"))) != NULL) {
00345         resultVerify = &(fl->defVerifyFlags);
00346         specdFlags = &fl->defSpecdFlags;
00347     } else
00348         return RPMRC_OK;
00349 
00350     for (pe = p; (size_t)(pe-p) < strlen(name); pe++)
00351         *pe = ' ';
00352 
00353     SKIPSPACE(pe);
00354 
00355     if (*pe != '(') {
00356         rpmlog(RPMLOG_ERR, _("Missing '(' in %s %s\n"), name, pe);
00357         fl->processingFailed = 1;
00358         return RPMRC_FAIL;
00359     }
00360 
00361     /* Bracket %*verify args */
00362     *pe++ = ' ';
00363     for (p = pe; *pe && *pe != ')'; pe++)
00364         {};
00365 
00366     if (*pe == '\0') {
00367         rpmlog(RPMLOG_ERR, _("Missing ')' in %s(%s\n"), name, p);
00368         fl->processingFailed = 1;
00369         return RPMRC_FAIL;
00370     }
00371 
00372     /* Localize. Erase parsed string */
00373     q = alloca((pe-p) + 1);
00374     strncpy(q, p, pe-p);
00375     q[pe-p] = '\0';
00376     while (p <= pe)
00377         *p++ = ' ';
00378 
00379     negated = 0;
00380     verifyFlags = RPMVERIFY_NONE;
00381 
00382     for (p = q; *p != '\0'; p = pe) {
00383         SKIPWHITE(p);
00384         if (*p == '\0')
00385             break;
00386         pe = p;
00387         SKIPNONWHITE(pe);
00388         if (*pe != '\0')
00389             *pe++ = '\0';
00390 
00391         {   VFA_t *vfa;
00392             for (vfa = verifyAttrs; vfa->attribute != NULL; vfa++) {
00393                 if (strcmp(p, vfa->attribute))
00394                     /*@innercontinue@*/ continue;
00395                 verifyFlags |= vfa->flag;
00396                     verifyFlags &= ~RPMVERIFY_FDIGEST;
00397                 /*@innerbreak@*/ break;
00398             }
00399             if (vfa->attribute)
00400                 continue;
00401         }
00402 
00403         if (!strcmp(p, "not")) {
00404             negated ^= 1;
00405         } else {
00406             rpmlog(RPMLOG_ERR, _("Invalid %s token: %s\n"), name, p);
00407             fl->processingFailed = 1;
00408             return RPMRC_FAIL;
00409         }
00410     }
00411 
00412     *resultVerify = negated ? ~(verifyFlags) : verifyFlags;
00413     if (negated) {
00414         /* Make sure "no digest" implies "no hmac" */
00415         if (!(*resultVerify & RPMVERIFY_FDIGEST))
00416             *resultVerify &= ~RPMVERIFY_HMAC;
00417     } else {
00418         /* Make sure "hmac" implies "no digest" */
00419         if (*resultVerify & RPMVERIFY_HMAC)
00420             *resultVerify &= ~RPMVERIFY_FDIGEST;
00421     }
00422     *specdFlags |= SPECD_VERIFY;
00423 
00424     return RPMRC_OK;
00425 }
00426 
00427 #define isAttrDefault(_ars)     ((_ars)[0] == '-' && (_ars)[1] == '\0')
00428 
00435 static rpmRC parseForDev(char * buf, FileList fl)
00436         /*@modifies buf, fl->processingFailed,
00437                 fl->noGlob, fl->devtype, fl->devmajor, fl->devminor @*/
00438 {
00439     const char * name;
00440     const char * errstr = NULL;
00441     char *p, *pe, *q;
00442     rpmRC rc = RPMRC_FAIL;      /* assume error */
00443 
00444     if ((p = strstr(buf, (name = "%dev"))) == NULL)
00445         return RPMRC_OK;
00446 
00447     for (pe = p; (size_t)(pe-p) < strlen(name); pe++)
00448         *pe = ' ';
00449     SKIPSPACE(pe);
00450 
00451     if (*pe != '(') {
00452         errstr = "'('";
00453         goto exit;
00454     }
00455 
00456     /* Bracket %dev args */
00457     *pe++ = ' ';
00458     for (p = pe; *pe && *pe != ')'; pe++)
00459         {};
00460     if (*pe != ')') {
00461         errstr = "')'";
00462         goto exit;
00463     }
00464 
00465     /* Localize. Erase parsed string */
00466     q = alloca((pe-p) + 1);
00467     strncpy(q, p, pe-p);
00468     q[pe-p] = '\0';
00469     while (p <= pe)
00470         *p++ = ' ';
00471 
00472     p = q; SKIPWHITE(p);
00473     pe = p; SKIPNONWHITE(pe); if (*pe != '\0') *pe++ = '\0';
00474     if (*p == 'b')
00475         fl->devtype = 'b';
00476     else if (*p == 'c')
00477         fl->devtype = 'c';
00478     else {
00479         errstr = "devtype";
00480         goto exit;
00481     }
00482 
00483     p = pe; SKIPWHITE(p);
00484     pe = p; SKIPNONWHITE(pe); if (*pe != '\0') *pe++ = '\0';
00485     for (pe = p; *pe && xisdigit(*pe); pe++)
00486         {} ;
00487     if (*pe == '\0') {
00488         fl->devmajor = atoi(p);
00489         /*@-unsignedcompare @*/ /* LCL: ge is ok */
00490         if (!((int)fl->devmajor >= 0 && (int)fl->devmajor < 256)) {
00491             errstr = "devmajor";
00492             goto exit;
00493         }
00494         /*@=unsignedcompare @*/
00495         pe++;
00496     } else {
00497         errstr = "devmajor";
00498         goto exit;
00499     }
00500 
00501     p = pe; SKIPWHITE(p);
00502     pe = p; SKIPNONWHITE(pe); if (*pe != '\0') *pe++ = '\0';
00503     for (pe = p; *pe && xisdigit(*pe); pe++)
00504         {} ;
00505     if (*pe == '\0') {
00506         fl->devminor = atoi(p);
00507         if (!(fl->devminor >= 0 && fl->devminor < 256)) {
00508             errstr = "devminor";
00509             goto exit;
00510         }
00511         pe++;
00512     } else {
00513         errstr = "devminor";
00514         goto exit;
00515     }
00516 
00517     fl->noGlob = 1;
00518 
00519     rc = 0;
00520 
00521 exit:
00522     if (rc) {
00523         rpmlog(RPMLOG_ERR, _("Missing %s in %s %s\n"), errstr, name, p);
00524         fl->processingFailed = 1;
00525     }
00526     return rc;
00527 }
00528 
00535 static rpmRC parseForAttr(char * buf, FileList fl)
00536         /*@modifies buf, fl->processingFailed,
00537                 fl->cur_ar, fl->def_ar,
00538                 fl->currentSpecdFlags, fl->defSpecdFlags @*/
00539 {
00540     const char *name;
00541     char *p, *pe, *q;
00542     int x;
00543     struct AttrRec_s arbuf;
00544     AttrRec ar = &arbuf, ret_ar;
00545     specdFlags * specdFlags;
00546 
00547     if ((p = strstr(buf, (name = "%attr"))) != NULL) {
00548         ret_ar = &(fl->cur_ar);
00549         specdFlags = &fl->currentSpecdFlags;
00550     } else if ((p = strstr(buf, (name = "%defattr"))) != NULL) {
00551         ret_ar = &(fl->def_ar);
00552         specdFlags = &fl->defSpecdFlags;
00553     } else
00554         return RPMRC_OK;
00555 
00556     for (pe = p; (size_t)(pe-p) < strlen(name); pe++)
00557         *pe = ' ';
00558 
00559     SKIPSPACE(pe);
00560 
00561     if (*pe != '(') {
00562         rpmlog(RPMLOG_ERR, _("Missing '(' in %s %s\n"), name, pe);
00563         fl->processingFailed = 1;
00564         return RPMRC_FAIL;
00565     }
00566 
00567     /* Bracket %*attr args */
00568     *pe++ = ' ';
00569     for (p = pe; *pe && *pe != ')'; pe++)
00570         {};
00571 
00572     if (ret_ar == &(fl->def_ar)) {      /* %defattr */
00573         q = pe;
00574         q++;
00575         SKIPSPACE(q);
00576         if (*q != '\0') {
00577             rpmlog(RPMLOG_ERR,
00578                      _("Non-white space follows %s(): %s\n"), name, q);
00579             fl->processingFailed = 1;
00580             return RPMRC_FAIL;
00581         }
00582     }
00583 
00584     /* Localize. Erase parsed string */
00585     q = alloca((pe-p) + 1);
00586     strncpy(q, p, pe-p);
00587     q[pe-p] = '\0';
00588     while (p <= pe)
00589         *p++ = ' ';
00590 
00591     nullAttrRec(ar);
00592 
00593     p = q; SKIPWHITE(p);
00594     if (*p != '\0') {
00595         pe = p; SKIPNONWHITE(pe); if (*pe != '\0') *pe++ = '\0';
00596         ar->ar_fmodestr = p;
00597         p = pe; SKIPWHITE(p);
00598     }
00599     if (*p != '\0') {
00600         pe = p; SKIPNONWHITE(pe); if (*pe != '\0') *pe++ = '\0';
00601         ar->ar_user = p;
00602         p = pe; SKIPWHITE(p);
00603     }
00604     if (*p != '\0') {
00605         pe = p; SKIPNONWHITE(pe); if (*pe != '\0') *pe++ = '\0';
00606         ar->ar_group = p;
00607         p = pe; SKIPWHITE(p);
00608     }
00609     if (*p != '\0' && ret_ar == &(fl->def_ar)) {        /* %defattr */
00610         pe = p; SKIPNONWHITE(pe); if (*pe != '\0') *pe++ = '\0';
00611         ar->ar_dmodestr = p;
00612         p = pe; SKIPWHITE(p);
00613     }
00614 
00615     if (!(ar->ar_fmodestr && ar->ar_user && ar->ar_group) || *p != '\0') {
00616         rpmlog(RPMLOG_ERR, _("Bad syntax: %s(%s)\n"), name, q);
00617         fl->processingFailed = 1;
00618         return RPMRC_FAIL;
00619     }
00620 
00621     /* Do a quick test on the mode argument and adjust for "-" */
00622     if (ar->ar_fmodestr && !isAttrDefault(ar->ar_fmodestr)) {
00623         unsigned int ui;
00624         x = sscanf(ar->ar_fmodestr, "%o", &ui);
00625         if ((x == 0) || (ar->ar_fmode & ~MYALLPERMS)) {
00626             rpmlog(RPMLOG_ERR, _("Bad mode spec: %s(%s)\n"), name, q);
00627             fl->processingFailed = 1;
00628             return RPMRC_FAIL;
00629         }
00630         ar->ar_fmode = ui;
00631     } else
00632         ar->ar_fmodestr = NULL;
00633 
00634     if (ar->ar_dmodestr && !isAttrDefault(ar->ar_dmodestr)) {
00635         unsigned int ui;
00636         x = sscanf(ar->ar_dmodestr, "%o", &ui);
00637         if ((x == 0) || (ar->ar_dmode & ~MYALLPERMS)) {
00638             rpmlog(RPMLOG_ERR, _("Bad dirmode spec: %s(%s)\n"), name, q);
00639             fl->processingFailed = 1;
00640             return RPMRC_FAIL;
00641         }
00642         ar->ar_dmode = ui;
00643     } else
00644         ar->ar_dmodestr = NULL;
00645 
00646     if (!(ar->ar_user && !isAttrDefault(ar->ar_user)))
00647         ar->ar_user = NULL;
00648 
00649     if (!(ar->ar_group && !isAttrDefault(ar->ar_group)))
00650         ar->ar_group = NULL;
00651 
00652     dupAttrRec(ar, ret_ar);
00653 
00654     /* XXX fix all this */
00655     *specdFlags |= SPECD_UID | SPECD_GID | SPECD_FILEMODE | SPECD_DIRMODE;
00656     
00657     return RPMRC_OK;
00658 }
00659 
00666 static rpmRC parseForConfig(char * buf, FileList fl)
00667         /*@modifies buf, fl->processingFailed, fl->currentFlags @*/
00668 {
00669     char *p, *pe, *q;
00670     const char *name;
00671 
00672     if ((p = strstr(buf, (name = "%config"))) == NULL)
00673         return RPMRC_OK;
00674 
00675     fl->currentFlags |= RPMFILE_CONFIG;
00676 
00677     /* Erase "%config" token. */
00678     for (pe = p; (size_t)(pe-p) < strlen(name); pe++)
00679         *pe = ' ';
00680     SKIPSPACE(pe);
00681     if (*pe != '(')
00682         return RPMRC_OK;
00683 
00684     /* Bracket %config args */
00685     *pe++ = ' ';
00686     for (p = pe; *pe && *pe != ')'; pe++)
00687         {};
00688 
00689     if (*pe == '\0') {
00690         rpmlog(RPMLOG_ERR, _("Missing ')' in %s(%s\n"), name, p);
00691         fl->processingFailed = 1;
00692         return RPMRC_FAIL;
00693     }
00694 
00695     /* Localize. Erase parsed string. */
00696     q = alloca((pe-p) + 1);
00697     strncpy(q, p, pe-p);
00698     q[pe-p] = '\0';
00699     while (p <= pe)
00700         *p++ = ' ';
00701 
00702     for (p = q; *p != '\0'; p = pe) {
00703         SKIPWHITE(p);
00704         if (*p == '\0')
00705             break;
00706         pe = p;
00707         SKIPNONWHITE(pe);
00708         if (*pe != '\0')
00709             *pe++ = '\0';
00710         if (!strcmp(p, "missingok")) {
00711             fl->currentFlags |= RPMFILE_MISSINGOK;
00712         } else if (!strcmp(p, "noreplace")) {
00713             fl->currentFlags |= RPMFILE_NOREPLACE;
00714         } else {
00715             rpmlog(RPMLOG_ERR, _("Invalid %s token: %s\n"), name, p);
00716             fl->processingFailed = 1;
00717             return RPMRC_FAIL;
00718         }
00719     }
00720 
00721     return RPMRC_OK;
00722 }
00723 
00726 static int langCmp(const void * ap, const void * bp)
00727         /*@*/
00728 {
00729     return strcmp(*(const char **)ap, *(const char **)bp);
00730 }
00731 
00738 static rpmRC parseForLang(char * buf, FileList fl)
00739         /*@modifies buf, fl->processingFailed,
00740                 fl->currentLangs, fl->nLangs @*/
00741 {
00742     char *p, *pe, *q;
00743     const char *name;
00744 
00745   while ((p = strstr(buf, (name = "%lang"))) != NULL) {
00746 
00747     for (pe = p; (size_t)(pe-p) < strlen(name); pe++)
00748         *pe = ' ';
00749     SKIPSPACE(pe);
00750 
00751     if (*pe != '(') {
00752         rpmlog(RPMLOG_ERR, _("Missing '(' in %s %s\n"), name, pe);
00753         fl->processingFailed = 1;
00754         return RPMRC_FAIL;
00755     }
00756 
00757     /* Bracket %lang args */
00758     *pe++ = ' ';
00759     for (pe = p; *pe && *pe != ')'; pe++)
00760         {};
00761 
00762     if (*pe == '\0') {
00763         rpmlog(RPMLOG_ERR, _("Missing ')' in %s(%s\n"), name, p);
00764         fl->processingFailed = 1;
00765         return RPMRC_FAIL;
00766     }
00767 
00768     /* Localize. Erase parsed string. */
00769     q = alloca((pe-p) + 1);
00770     strncpy(q, p, pe-p);
00771     q[pe-p] = '\0';
00772     while (p <= pe)
00773         *p++ = ' ';
00774 
00775     /* Parse multiple arguments from %lang */
00776     for (p = q; *p != '\0'; p = pe) {
00777         char *newp;
00778         size_t np;
00779         int i;
00780 
00781         SKIPWHITE(p);
00782         pe = p;
00783         SKIPNONWHITE(pe);
00784 
00785         np = pe - p;
00786         
00787         /* Sanity check on locale lengths */
00788         if (np < 1 || (np == 1 && *p != 'C') || np >= 32) {
00789             rpmlog(RPMLOG_ERR,
00790                 _("Unusual locale length: \"%.*s\" in %%lang(%s)\n"),
00791                 (int)np, p, q);
00792             fl->processingFailed = 1;
00793             return RPMRC_FAIL;
00794         }
00795 
00796         /* Check for duplicate locales */
00797         if (fl->currentLangs != NULL)
00798         for (i = 0; i < fl->nLangs; i++) {
00799             if (strncmp(fl->currentLangs[i], p, np))
00800                 /*@innercontinue@*/ continue;
00801             rpmlog(RPMLOG_ERR, _("Duplicate locale %.*s in %%lang(%s)\n"),
00802                 (int)np, p, q);
00803             fl->processingFailed = 1;
00804             return RPMRC_FAIL;
00805         }
00806 
00807         /* Add new locale */
00808         fl->currentLangs = xrealloc(fl->currentLangs,
00809                                 (fl->nLangs + 1) * sizeof(*fl->currentLangs));
00810         newp = xmalloc( np+1 );
00811         strncpy(newp, p, np);
00812         newp[np] = '\0';
00813         fl->currentLangs[fl->nLangs++] = newp;
00814         if (*pe == ',') pe++;   /* skip , if present */
00815     }
00816   }
00817 
00818     /* Insure that locales are sorted. */
00819     if (fl->currentLangs)
00820         qsort(fl->currentLangs, fl->nLangs, sizeof(*fl->currentLangs), langCmp);
00821 
00822     return RPMRC_OK;
00823 }
00824 
00827 static int parseForRegexLang(const char * fileName, /*@out@*/ char ** lang)
00828         /*@globals rpmGlobalMacroContext, h_errno, internalState @*/
00829         /*@modifies *lang, rpmGlobalMacroContext, internalState @*/
00830 {
00831     static int initialized = 0;
00832     static int hasRegex = 0;
00833     static regex_t compiledPatt;
00834     static char buf[BUFSIZ];
00835     int x;
00836     regmatch_t matches[2];
00837     const char *s;
00838 
00839     if (! initialized) {
00840         const char *patt = rpmExpand("%{?_langpatt}", NULL);
00841         int rc = 0;
00842         if (!(patt && *patt != '\0'))
00843             rc = 1;
00844         else if (regcomp(&compiledPatt, patt, REG_EXTENDED))
00845             rc = -1;
00846         patt = _free(patt);
00847         if (rc)
00848             return rc;
00849         hasRegex = 1;
00850         initialized = 1;
00851     }
00852     
00853     memset(matches, 0, sizeof(matches));
00854     if (! hasRegex || regexec(&compiledPatt, fileName, 2, matches, REG_NOTEOL))
00855         return 1;
00856 
00857     /* Got match */
00858     s = fileName + matches[1].rm_eo - 1;
00859     x = (int)matches[1].rm_eo - (int)matches[1].rm_so;
00860     buf[x] = '\0';
00861     while (x) {
00862         buf[--x] = *s--;
00863     }
00864     if (lang)
00865         *lang = buf;
00866     return 0;
00867 }
00868 
00871 /*@-exportlocal -exportheadervar@*/
00872 /*@unchecked@*/
00873 static VFA_t virtualFileAttributes[] = {
00874         { "%dir",       0,      0 },    /* XXX why not RPMFILE_DIR? */
00875         { "%doc",       0,      RPMFILE_DOC },
00876         { "%ghost",     0,      RPMFILE_GHOST },
00877         { "%exclude",   0,      RPMFILE_EXCLUDE },
00878         { "%readme",    0,      RPMFILE_README },
00879         { "%license",   0,      RPMFILE_LICENSE },
00880         { "%pubkey",    0,      RPMFILE_PUBKEY },
00881         { "%policy",    0,      RPMFILE_POLICY },
00882         { "%optional",  0,      RPMFILE_OPTIONAL },
00883         { "%remove",    0,      RPMFILE_REMOVE },
00884 
00885 #if WHY_NOT
00886         { "%icon",      0,      RPMFILE_ICON },
00887         { "%spec",      0,      RPMFILE_SPEC },
00888         { "%config",    0,      RPMFILE_CONFIG },
00889         { "%missingok", 0,      RPMFILE_CONFIG|RPMFILE_MISSINGOK },
00890         { "%noreplace", 0,      RPMFILE_CONFIG|RPMFILE_NOREPLACE },
00891 #endif
00892 
00893         { NULL, 0, 0 }
00894 };
00895 /*@=exportlocal =exportheadervar@*/
00896 
00906 static rpmRC parseForSimple(/*@unused@*/ Spec spec, Package pkg,
00907                 char * buf, FileList fl, /*@out@*/ const char ** fileName)
00908         /*@globals rpmGlobalMacroContext, h_errno, internalState @*/
00909         /*@modifies buf, fl->processingFailed, *fileName,
00910                 fl->currentFlags,
00911                 fl->docDirs, fl->docDirCount, fl->isDir,
00912                 fl->passedSpecialDoc, fl->isSpecialDoc,
00913                 pkg->header, pkg->specialDoc,
00914                 rpmGlobalMacroContext, internalState @*/
00915 {
00916     char *s, *t;
00917     int specialDoc = 0;
00918     char specialDocBuf[BUFSIZ];
00919     rpmRC res = RPMRC_OK;       /* assume success */
00920 
00921     specialDocBuf[0] = '\0';
00922     *fileName = NULL;
00923 
00924     t = buf;
00925     while ((s = strtokWithQuotes(t, " \t\n")) != NULL) {
00926         t = NULL;
00927         if (!strcmp(s, "%docdir")) {
00928             s = strtokWithQuotes(NULL, " \t\n");
00929             if (fl->docDirCount == MAXDOCDIR) {
00930                 rpmlog(RPMLOG_CRIT, _("Hit limit for %%docdir\n"));
00931                 fl->processingFailed = 1;
00932                 res = RPMRC_FAIL;
00933             }
00934         
00935             if (s != NULL)
00936                 fl->docDirs[fl->docDirCount++] = xstrdup(s);
00937             if (s == NULL || strtokWithQuotes(NULL, " \t\n")) {
00938                 rpmlog(RPMLOG_CRIT, _("Only one arg for %%docdir\n"));
00939                 fl->processingFailed = 1;
00940                 res = RPMRC_FAIL;
00941             }
00942             break;
00943         }
00944 #if defined(__LCLINT__)
00945         assert(s != NULL);
00946 #endif
00947 
00948     /* Set flags for virtual file attributes */
00949     {   VFA_t *vfa;
00950         for (vfa = virtualFileAttributes; vfa->attribute != NULL; vfa++) {
00951             if (strcmp(s, vfa->attribute))
00952                 /*@innercontinue@*/ continue;
00953             if (!vfa->flag) {
00954                 if (!strcmp(s, "%dir"))
00955                     fl->isDir = 1;      /* XXX why not RPMFILE_DIR? */
00956             } else {
00957                 if (vfa->not)
00958                     fl->currentFlags &= ~vfa->flag;
00959                 else
00960                     fl->currentFlags |= vfa->flag;
00961             }
00962 
00963             /*@innerbreak@*/ break;
00964         }
00965         /* if we got an attribute, continue with next token */
00966         if (vfa->attribute != NULL)
00967             continue;
00968     }
00969 
00970         if (*fileName) {
00971             /* We already got a file -- error */
00972             rpmlog(RPMLOG_ERR, _("Two files on one line: %s\n"),
00973                 *fileName);
00974             fl->processingFailed = 1;
00975             res = RPMRC_FAIL;
00976         }
00977 
00978         if (*s != '/') {
00979             if (fl->currentFlags & RPMFILE_DOC) {
00980                 specialDoc = 1;
00981                 strcat(specialDocBuf, " ");
00982                 strcat(specialDocBuf, s);
00983             } else
00984             if (fl->currentFlags & (RPMFILE_POLICY|RPMFILE_PUBKEY|RPMFILE_ICON))
00985             {
00986                 *fileName = s;
00987             } else {
00988                 const char * sfn = NULL;
00989                 int urltype = urlPath(s, &sfn);
00990                 switch (urltype) {
00991                 default: /* relative path, not in %doc and not a URL */
00992                     rpmlog(RPMLOG_ERR,
00993                         _("File must begin with \"/\": %s\n"), s);
00994                     fl->processingFailed = 1;
00995                     res = RPMRC_FAIL;
00996                     /*@switchbreak@*/ break;
00997                 case URL_IS_PATH:
00998                     *fileName = s;
00999                     /*@switchbreak@*/ break;
01000                 }
01001             }
01002         } else {
01003             *fileName = s;
01004         }
01005     }
01006 
01007     if (specialDoc) {
01008         if (*fileName || (fl->currentFlags & ~(RPMFILE_DOC))) {
01009             rpmlog(RPMLOG_ERR,
01010                      _("Can't mix special %%doc with other forms: %s\n"),
01011                      (*fileName ? *fileName : ""));
01012             fl->processingFailed = 1;
01013             res = RPMRC_FAIL;
01014         } else {
01015         /* XXX WATCHOUT: buf is an arg */
01016            {    
01017                 /*@only@*/
01018                 static char *_docdir_fmt = NULL;        /* XXX memleak */
01019                 static int oneshot = 0;
01020                 const char *ddir, *fmt, *errstr;
01021                 if (!oneshot) {
01022                     _docdir_fmt = rpmExpand("%{?_docdir_fmt}", NULL);
01023                     if (!(_docdir_fmt && *_docdir_fmt))
01024                         _docdir_fmt = _free(_docdir_fmt);
01025                     oneshot = 1;
01026                 }
01027                 if (_docdir_fmt == NULL)
01028                     _docdir_fmt = xstrdup("%{NAME}-%{VERSION}");
01029                 fmt = headerSprintf(pkg->header, _docdir_fmt, NULL, rpmHeaderFormats, &errstr);
01030                 if (fmt == NULL) {
01031                     rpmlog(RPMLOG_ERR, _("illegal _docdir_fmt: %s\n"), errstr);
01032                     fl->processingFailed = 1;
01033                     res = RPMRC_FAIL;
01034                 } else {
01035                     ddir = rpmGetPath("%{_docdir}/", fmt, NULL);
01036                     strcpy(buf, ddir);
01037                     ddir = _free(ddir);
01038                     fmt = _free(fmt);
01039                 }
01040             }
01041 
01042         /* XXX FIXME: this is easy to do as macro expansion */
01043 
01044             if (! fl->passedSpecialDoc) {
01045                 char *compress_doc;
01046                 char *mkdir_p;
01047 
01048                 pkg->specialDoc = rpmiobNew(0);
01049                 pkg->specialDoc = rpmiobAppend(pkg->specialDoc, "DOCDIR=\"$RPM_BUILD_ROOT\"", 0);
01050                 pkg->specialDoc = rpmiobAppend(pkg->specialDoc, buf, 1);
01051                 pkg->specialDoc = rpmiobAppend(pkg->specialDoc, "export DOCDIR", 1);
01052                 mkdir_p = rpmExpand("%{?__mkdir_p}%{!?__mkdir_p:mkdir -p}", NULL);
01053                 if (!mkdir_p)
01054                     mkdir_p = xstrdup("mkdir -p");
01055                 pkg->specialDoc = rpmiobAppend(pkg->specialDoc, mkdir_p, 0);
01056                 mkdir_p = _free(mkdir_p);
01057                 pkg->specialDoc = rpmiobAppend(pkg->specialDoc, " \"$DOCDIR\"", 1);
01058 
01059                 compress_doc = rpmExpand("%{__compress_doc}", NULL);
01060                 if (compress_doc && *compress_doc != '%')
01061                     pkg->specialDoc = rpmiobAppend(pkg->specialDoc, compress_doc, 1);
01062                 compress_doc = _free(compress_doc);
01063 
01064                 /*@-temptrans@*/
01065                 *fileName = buf;
01066                 /*@=temptrans@*/
01067                 fl->passedSpecialDoc = 1;
01068                 fl->isSpecialDoc = 1;
01069             }
01070 
01071             pkg->specialDoc = rpmiobAppend(pkg->specialDoc, "cp -pr ", 0);
01072             pkg->specialDoc = rpmiobAppend(pkg->specialDoc, specialDocBuf, 0);
01073             pkg->specialDoc = rpmiobAppend(pkg->specialDoc, " \"$DOCDIR\"", 1);
01074         }
01075     }
01076 
01077     return res;
01078 }
01079 
01082 static int compareFileListRecs(const void * ap, const void * bp)        /*@*/
01083 {
01084     const char *aurl = ((FileListRec)ap)->fileURL;
01085     const char *a = NULL;
01086     const char *burl = ((FileListRec)bp)->fileURL;
01087     const char *b = NULL;
01088     (void) urlPath(aurl, &a);
01089     (void) urlPath(burl, &b);
01090     return strcmp(a, b);
01091 }
01092 
01099 static int isDoc(FileList fl, const char * fileName)    /*@*/
01100 {
01101     int x = fl->docDirCount;
01102     size_t k, l;
01103 
01104     k = strlen(fileName);
01105     while (x--) {
01106         l = strlen(fl->docDirs[x]);
01107         if (l < k && strncmp(fileName, fl->docDirs[x], l) == 0 && fileName[l] == '/')
01108             return 1;
01109     }
01110     return 0;
01111 }
01112 
01119 static int checkHardLinks(FileList fl)
01120         /*@*/
01121 {
01122     FileListRec ilp, jlp;
01123     int i, j;
01124 
01125     for (i = 0;  i < fl->fileListRecsUsed; i++) {
01126         ilp = fl->fileList + i;
01127         if (!(S_ISREG(ilp->fl_mode) && ilp->fl_nlink > 1))
01128             continue;
01129         if (ilp->flags & (RPMFILE_EXCLUDE | RPMFILE_GHOST))
01130             continue;
01131 
01132         for (j = i + 1; j < fl->fileListRecsUsed; j++) {
01133             jlp = fl->fileList + j;
01134             if (!S_ISREG(jlp->fl_mode))
01135                 /*@innercontinue@*/ continue;
01136             if (ilp->fl_nlink != jlp->fl_nlink)
01137                 /*@innercontinue@*/ continue;
01138             if (ilp->fl_ino != jlp->fl_ino)
01139                 /*@innercontinue@*/ continue;
01140             if (ilp->fl_dev != jlp->fl_dev)
01141                 /*@innercontinue@*/ continue;
01142             if (jlp->flags & (RPMFILE_EXCLUDE | RPMFILE_GHOST))
01143                 /*@innercontinue@*/ continue;
01144             return 1;
01145         }
01146     }
01147     return 0;
01148 }
01149 
01150 static int dncmp(const void * a, const void * b)
01151         /*@*/
01152 {
01153     const char ** aurlp = (const char **)a;
01154     const char ** burlp = (const char **)b;
01155     const char * adn;
01156     const char * bdn;
01157     (void) urlPath(*aurlp, &adn);
01158     (void) urlPath(*burlp, &bdn);
01159     return strcmp(adn, bdn);
01160 }
01161 
01166 static void compressFilelist(Header h)
01167         /*@globals internalState @*/
01168         /*@modifies h, internalState @*/
01169 {
01170     HE_t he = memset(alloca(sizeof(*he)), 0, sizeof(*he));
01171     const char ** fileNames;
01172     const char * fn;
01173     const char ** dirNames;
01174     const char ** baseNames;
01175     rpmuint32_t * dirIndexes;
01176     int count;
01177     int dirIndex = -1;
01178     int xx;
01179     int i;
01180 
01181     /*
01182      * This assumes the file list is already sorted, and begins with a
01183      * single '/'. That assumption isn't critical, but it makes things go
01184      * a bit faster.
01185      */
01186 
01187     if (headerIsEntry(h, RPMTAG_DIRNAMES)) {
01188         he->tag = RPMTAG_OLDFILENAMES;
01189         xx = headerDel(h, he, 0);
01190         return;         /* Already converted. */
01191     }
01192 
01193     he->tag = RPMTAG_OLDFILENAMES;
01194     xx = headerGet(h, he, 0);
01195     fileNames = he->p.argv;
01196     count = he->c;
01197     if (!xx || fileNames == NULL || count <= 0)
01198         return;         /* no file list */
01199 
01200     dirNames = alloca(sizeof(*dirNames) * count);       /* worst case */
01201     baseNames = alloca(sizeof(*dirNames) * count);
01202     dirIndexes = alloca(sizeof(*dirIndexes) * count);
01203 
01204     (void) urlPath(fileNames[0], &fn);
01205     if (fn[0] != '/') {
01206         /* HACK. Source RPM, so just do things differently */
01207         dirIndex = 0;
01208         dirNames[dirIndex] = "";
01209         for (i = 0; i < count; i++) {
01210             dirIndexes[i] = dirIndex;
01211             baseNames[i] = fileNames[i];
01212         }
01213         goto exit;
01214     }
01215 
01216     for (i = 0; i < count; i++) {
01217         const char ** needle;
01218         char savechar;
01219         char * baseName;
01220         size_t len;
01221 
01222         if (fileNames[i] == NULL)       /* XXX can't happen */
01223             continue;
01224         baseName = strrchr(fileNames[i], '/') + 1;
01225         len = baseName - fileNames[i];
01226         needle = dirNames;
01227         savechar = *baseName;
01228         *baseName = '\0';
01229 /*@-compdef@*/
01230         if (dirIndex < 0 ||
01231             (needle = bsearch(&fileNames[i], dirNames, dirIndex + 1, sizeof(dirNames[0]), dncmp)) == NULL) {
01232             char *s = alloca(len + 1);
01233             memcpy(s, fileNames[i], len + 1);
01234             s[len] = '\0';
01235             dirIndexes[i] = ++dirIndex;
01236             dirNames[dirIndex] = s;
01237         } else
01238             dirIndexes[i] = needle - dirNames;
01239 /*@=compdef@*/
01240 
01241         *baseName = savechar;
01242         baseNames[i] = baseName;
01243     }
01244 
01245 exit:
01246     if (count > 0) {
01247         he->tag = RPMTAG_DIRINDEXES;
01248         he->t = RPM_UINT32_TYPE;
01249         he->p.ui32p = dirIndexes;
01250         he->c = count;
01251         xx = headerPut(h, he, 0);
01252 
01253         he->tag = RPMTAG_BASENAMES;
01254         he->t = RPM_STRING_ARRAY_TYPE;
01255         he->p.argv = baseNames;
01256         he->c = count;
01257         xx = headerPut(h, he, 0);
01258 
01259         he->tag = RPMTAG_DIRNAMES;
01260         he->t = RPM_STRING_ARRAY_TYPE;
01261         he->p.argv = dirNames;
01262         he->c = dirIndex + 1;
01263         xx = headerPut(h, he, 0);
01264     }
01265 
01266     fileNames = _free(fileNames);
01267 
01268     he->tag = RPMTAG_OLDFILENAMES;
01269     xx = headerDel(h, he, 0);
01270 }
01271 
01272 static rpmuint32_t getDigestAlgo(Header h, int isSrc)
01273         /*@modifies h @*/
01274 {
01275     HE_t he = memset(alloca(sizeof(*he)), 0, sizeof(*he));
01276     static rpmuint32_t source_file_dalgo = 0;
01277     static rpmuint32_t binary_file_dalgo = 0;
01278     static int oneshot = 0;
01279     rpmuint32_t dalgo = 0;
01280     int xx;
01281 
01282     if (!oneshot) {
01283         source_file_dalgo =
01284                 rpmExpandNumeric("%{?_build_source_file_digest_algo}");
01285         binary_file_dalgo =
01286                 rpmExpandNumeric("%{?_build_binary_file_digest_algo}");
01287         oneshot++;
01288     }
01289 
01290     dalgo = (isSrc ? source_file_dalgo : binary_file_dalgo);
01291     switch (dalgo) {
01292     case PGPHASHALGO_SHA1:
01293     case PGPHASHALGO_MD2:
01294     case PGPHASHALGO_SHA256:
01295     case PGPHASHALGO_SHA384:
01296     case PGPHASHALGO_SHA512:
01297         (void) rpmlibNeedsFeature(h, "FileDigests", "4.6.0-1");
01298         he->tag = RPMTAG_FILEDIGESTALGO;
01299         he->t = RPM_UINT32_TYPE;
01300         he->p.ui32p = &dalgo;
01301         he->c = 1;
01302         xx = headerPut(h, he, 0);
01303         /*@fallthgrough@*/
01304     case PGPHASHALGO_RIPEMD160:
01305     case PGPHASHALGO_TIGER192:
01306     case PGPHASHALGO_MD4:
01307     case PGPHASHALGO_RIPEMD128:
01308     case PGPHASHALGO_CRC32:
01309     case PGPHASHALGO_ADLER32:
01310     case PGPHASHALGO_CRC64:
01311         (void) rpmlibNeedsFeature(h, "FileDigestParameterized", "4.4.6-1");
01312             /*@switchbreak@*/ break;
01313     case PGPHASHALGO_MD5:
01314     case PGPHASHALGO_HAVAL_5_160:               /* XXX unimplemented */
01315     default:
01316         dalgo = PGPHASHALGO_MD5;
01317         /*@switchbreak@*/ break;
01318     }
01319 
01320     return dalgo;
01321 }
01322 
01332 static void genCpioListAndHeader(/*@partial@*/ FileList fl,
01333                 rpmfi * fip, Header h, int isSrc)
01334         /*@globals rpmGlobalMacroContext, h_errno, fileSystem, internalState @*/
01335         /*@modifies h, *fip, fl->processingFailed, fl->fileList,
01336                 fl->totalFileSize,
01337                 rpmGlobalMacroContext, fileSystem, internalState @*/
01338 {
01339     HE_t he = memset(alloca(sizeof(*he)), 0, sizeof(*he));
01340     const char * apath;
01341     rpmuint16_t ui16;
01342     rpmuint32_t ui32;
01343     int _addDotSlash = !isSrc;
01344     int apathlen = 0;
01345     int dpathlen = 0;
01346     int skipLen = 0;
01347     rpmsx sx = rpmsxNew("%{?_build_file_context_path}", 0);
01348     FileListRec flp;
01349     rpmuint32_t dalgo = getDigestAlgo(h, isSrc);
01350     char buf[BUFSIZ];
01351     int i, xx;
01352 
01353 memset(buf, 0, sizeof(buf));    /* XXX valgrind on rhel6 beta pickier */
01354 
01355     /* Sort the big list */
01356     if (fl->fileListRecsUsed > 1)
01357         qsort(fl->fileList, fl->fileListRecsUsed,
01358                 sizeof(*(fl->fileList)), compareFileListRecs);
01359     
01360     /* Generate the header. */
01361     if (! isSrc) {
01362         skipLen = 1;
01363         if (fl->prefix)
01364             skipLen += strlen(fl->prefix);
01365     }
01366 
01367     for (i = 0, flp = fl->fileList; i < fl->fileListRecsUsed; i++, flp++) {
01368         const char *s;
01369 
01370         /* Merge duplicate entries. */
01371         while (i < (fl->fileListRecsUsed - 1) &&
01372             !strcmp(flp->fileURL, flp[1].fileURL)) {
01373 
01374             /* Two entries for the same file found, merge the entries. */
01375             /* Note that an %exclude is a duplication of a file reference */
01376 
01377             /* file flags */
01378             flp[1].flags |= flp->flags; 
01379 
01380             if (!(flp[1].flags & RPMFILE_EXCLUDE))
01381                 rpmlog(RPMLOG_WARNING, _("File listed twice: %s\n"),
01382                         flp->fileURL);
01383    
01384             /* file mode */
01385             if (S_ISDIR(flp->fl_mode)) {
01386                 if ((flp[1].specdFlags & (SPECD_DIRMODE | SPECD_DEFDIRMODE)) <
01387                     (flp->specdFlags & (SPECD_DIRMODE | SPECD_DEFDIRMODE)))
01388                         flp[1].fl_mode = flp->fl_mode;
01389             } else {
01390                 if ((flp[1].specdFlags & (SPECD_FILEMODE | SPECD_DEFFILEMODE)) <
01391                     (flp->specdFlags & (SPECD_FILEMODE | SPECD_DEFFILEMODE)))
01392                         flp[1].fl_mode = flp->fl_mode;
01393             }
01394 
01395             /* uid */
01396             if ((flp[1].specdFlags & (SPECD_UID | SPECD_DEFUID)) <
01397                 (flp->specdFlags & (SPECD_UID | SPECD_DEFUID)))
01398             {
01399                 flp[1].fl_uid = flp->fl_uid;
01400                 flp[1].uname = flp->uname;
01401             }
01402 
01403             /* gid */
01404             if ((flp[1].specdFlags & (SPECD_GID | SPECD_DEFGID)) <
01405                 (flp->specdFlags & (SPECD_GID | SPECD_DEFGID)))
01406             {
01407                 flp[1].fl_gid = flp->fl_gid;
01408                 flp[1].gname = flp->gname;
01409             }
01410 
01411             /* verify flags */
01412             if ((flp[1].specdFlags & (SPECD_VERIFY | SPECD_DEFVERIFY)) <
01413                 (flp->specdFlags & (SPECD_VERIFY | SPECD_DEFVERIFY)))
01414                     flp[1].verifyFlags = flp->verifyFlags;
01415 
01416             /* XXX to-do: language */
01417 
01418             flp++; i++;
01419         }
01420 
01421         /* Skip files that were marked with %exclude. */
01422         if (flp->flags & RPMFILE_EXCLUDE) continue;
01423 
01424         /* Omit '/' and/or URL prefix, leave room for "./" prefix */
01425         (void) urlPath(flp->fileURL, &apath);
01426         apathlen += (strlen(apath) - skipLen + (_addDotSlash ? 3 : 1));
01427 
01428         /* Leave room for both dirname and basename NUL's */
01429         dpathlen += (strlen(flp->diskURL) + 2);
01430 
01431         /*
01432          * Make the header, the OLDFILENAMES will get converted to a 
01433          * compressed file list write before we write the actual package to
01434          * disk.
01435          */
01436         he->tag = RPMTAG_OLDFILENAMES;
01437         he->t = RPM_STRING_ARRAY_TYPE;
01438         he->p.argv = &flp->fileURL;
01439         he->c = 1;
01440         he->append = 1;
01441         xx = headerPut(h, he, 0);
01442         he->append = 0;
01443 
01444 /*@-sizeoftype@*/
01445         ui32 = (rpmuint32_t) flp->fl_size;
01446         he->tag = RPMTAG_FILESIZES;
01447         he->t = RPM_UINT32_TYPE;
01448         he->p.ui32p = &ui32;
01449         he->c = 1;
01450         he->append = 1;
01451         xx = headerPut(h, he, 0);
01452         he->append = 0;
01453 
01454         he->tag = RPMTAG_FILEUSERNAME;
01455         he->t = RPM_STRING_ARRAY_TYPE;
01456         he->p.argv = &flp->uname;
01457         he->c = 1;
01458         he->append = 1;
01459         xx = headerPut(h, he, 0);
01460         he->append = 0;
01461 
01462         he->tag = RPMTAG_FILEGROUPNAME;
01463         he->t = RPM_STRING_ARRAY_TYPE;
01464         he->p.argv = &flp->gname;
01465         he->c = 1;
01466         he->append = 1;
01467         xx = headerPut(h, he, 0);
01468         he->append = 0;
01469 
01470         ui32 = (rpmuint32_t) flp->fl_mtime;
01471         he->tag = RPMTAG_FILEMTIMES;
01472         he->t = RPM_UINT32_TYPE;
01473         he->p.ui32p = &ui32;
01474         he->c = 1;
01475         he->append = 1;
01476         xx = headerPut(h, he, 0);
01477         he->append = 0;
01478 
01479         ui16 = (rpmuint16_t)flp->fl_mode;
01480         he->tag = RPMTAG_FILEMODES;
01481         he->t = RPM_UINT16_TYPE;
01482         he->p.ui16p = &ui16;
01483         he->c = 1;
01484         he->append = 1;
01485         xx = headerPut(h, he, 0);
01486         he->append = 0;
01487 
01488         ui16 = (rpmuint16_t) flp->fl_rdev;
01489         he->tag = RPMTAG_FILERDEVS;
01490         he->t = RPM_UINT16_TYPE;
01491         he->p.ui16p = &ui16;
01492         he->c = 1;
01493         he->append = 1;
01494         xx = headerPut(h, he, 0);
01495         he->append = 0;
01496 
01497         ui32 = (rpmuint32_t) flp->fl_dev;
01498         he->tag = RPMTAG_FILEDEVICES;
01499         he->t = RPM_UINT32_TYPE;
01500         he->p.ui32p = &ui32;
01501         he->c = 1;
01502         he->append = 1;
01503         xx = headerPut(h, he, 0);
01504         he->append = 0;
01505 
01506         ui32 = (rpmuint32_t) flp->fl_ino;
01507         he->tag = RPMTAG_FILEINODES;
01508         he->t = RPM_UINT32_TYPE;
01509         he->p.ui32p = &ui32;
01510         he->c = 1;
01511         he->append = 1;
01512         xx = headerPut(h, he, 0);
01513         he->append = 0;
01514 
01515 /*@=sizeoftype@*/
01516 
01517         he->tag = RPMTAG_FILELANGS;
01518         he->t = RPM_STRING_ARRAY_TYPE;
01519         he->p.argv = &flp->langs;
01520         he->c = 1;
01521         he->append = 1;
01522         xx = headerPut(h, he, 0);
01523         he->append = 0;
01524 
01525         buf[0] = '\0';
01526         if (S_ISREG(flp->fl_mode)) {
01527             unsigned dflags = 0x01;     /* asAscii */
01528 #define _mask   (RPMVERIFY_FDIGEST|RPMVERIFY_HMAC)
01529             if ((flp->verifyFlags & _mask) == RPMVERIFY_HMAC)
01530                 dflags |= 0x02;         /* doHmac */
01531 #undef  _mask
01532             (void) dodigest(dalgo, flp->diskURL, (unsigned char *)buf,
01533                         dflags, NULL);
01534         }
01535         s = buf;
01536 
01537         he->tag = RPMTAG_FILEDIGESTS;
01538         he->t = RPM_STRING_ARRAY_TYPE;
01539         he->p.argv = &s;
01540         he->c = 1;
01541         he->append = 1;
01542         xx = headerPut(h, he, 0);
01543         he->append = 0;
01544 
01545 if (!(_rpmbuildFlags & 4)) {
01546         ui32 = dalgo;
01547         he->tag = RPMTAG_FILEDIGESTALGOS;
01548         he->t = RPM_UINT32_TYPE;
01549         he->p.ui32p = &ui32;
01550         he->c = 1;
01551         he->append = 1;
01552         xx = headerPut(h, he, 0);
01553         he->append = 0;
01554 }
01555         
01556         buf[0] = '\0';
01557         if (S_ISLNK(flp->fl_mode)) {
01558             xx = Readlink(flp->diskURL, buf, BUFSIZ);
01559             if (xx >= 0)
01560                 buf[xx] = '\0';
01561             if (fl->buildRootURL) {
01562                 const char * buildRoot;
01563                 (void) urlPath(fl->buildRootURL, &buildRoot);
01564 
01565                 if (buf[0] == '/' && strcmp(buildRoot, "/") &&
01566                     !strncmp(buf, buildRoot, strlen(buildRoot))) {
01567                      rpmlog(RPMLOG_ERR,
01568                                 _("Symlink points to BuildRoot: %s -> %s\n"),
01569                                 flp->fileURL, buf);
01570                     fl->processingFailed = 1;
01571                 }
01572             }
01573         }
01574         s = buf;
01575         he->tag = RPMTAG_FILELINKTOS;
01576         he->t = RPM_STRING_ARRAY_TYPE;
01577         he->p.argv = &s;
01578         he->c = 1;
01579         he->append = 1;
01580         xx = headerPut(h, he, 0);
01581         he->append = 0;
01582 
01583         if (flp->flags & RPMFILE_GHOST) {
01584             flp->verifyFlags &= ~(RPMVERIFY_FDIGEST | RPMVERIFY_FILESIZE |
01585                                 RPMVERIFY_LINKTO | RPMVERIFY_MTIME);
01586         }
01587         ui32 = flp->verifyFlags;
01588         he->tag = RPMTAG_FILEVERIFYFLAGS;
01589         he->t = RPM_UINT32_TYPE;
01590         he->p.ui32p = &ui32;
01591         he->c = 1;
01592         he->append = 1;
01593         xx = headerPut(h, he, 0);
01594         he->append = 0;
01595         
01596         if (!isSrc && isDoc(fl, flp->fileURL))
01597             flp->flags |= RPMFILE_DOC;
01598         /* XXX Should directories have %doc/%config attributes? (#14531) */
01599         if (S_ISDIR(flp->fl_mode))
01600             flp->flags &= ~(RPMFILE_CONFIG|RPMFILE_DOC);
01601 
01602         ui32 = flp->flags;
01603         he->tag = RPMTAG_FILEFLAGS;
01604         he->t = RPM_UINT32_TYPE;
01605         he->p.ui32p = &ui32;
01606         he->c = 1;
01607         he->append = 1;
01608         xx = headerPut(h, he, 0);
01609         he->append = 0;
01610         
01611         /* Add file security context to package. */
01612         if (sx && sx->fn  && *sx->fn && !(_rpmbuildFlags & 4)) {
01613             const char * scon = rpmsxMatch(sx, flp->fileURL, flp->fl_mode);
01614             if (scon) {
01615                 he->tag = RPMTAG_FILECONTEXTS;
01616                 he->t = RPM_STRING_ARRAY_TYPE;
01617                 he->p.argv = &scon;
01618                 he->c = 1;
01619                 he->append = 1;
01620                 xx = headerPut(h, he, 0);
01621                 he->append = 0;
01622             }
01623             scon = _free(scon);         /* XXX freecon(scon) instead()? */
01624         }
01625     }
01626 
01627     sx = rpmsxFree(sx);
01628 
01629 if (_rpmbuildFlags & 4) {
01630 (void) rpmlibNeedsFeature(h, "PayloadFilesHavePrefix", "4.0-1");
01631 (void) rpmlibNeedsFeature(h, "CompressedFileNames", "3.0.4-1");
01632 }
01633         
01634     compressFilelist(h);
01635 
01636   { static int scareMem = 0;
01637     void * ts = NULL;   /* XXX FIXME drill rpmts ts all the way down here */
01638     rpmfi fi = rpmfiNew(ts, h, RPMTAG_BASENAMES, scareMem);
01639     char * a, * d;
01640 
01641     if (fi == NULL) return;             /* XXX can't happen */
01642 
01643 /*@-onlytrans@*/
01644     fi->te = xcalloc(1, sizeof(*((rpmte)fi->te)));
01645 /*@=onlytrans@*/
01646     ((rpmte)fi->te)->type = TR_ADDED;
01647 
01648     fi->dnl = _free(fi->dnl);
01649     fi->bnl = _free(fi->bnl);
01650     if (!scareMem) fi->dil = _free(fi->dil);
01651 
01652     /* XXX Insure at least 1 byte is always allocated. */
01653     fi->dnl = xmalloc(fi->fc * sizeof(*fi->dnl) + dpathlen + 1);
01654     d = (char *)(fi->dnl + fi->fc);
01655     *d = '\0';
01656 
01657     fi->bnl = xmalloc(fi->fc * (sizeof(*fi->bnl) + sizeof(*fi->dil)));
01658 /*@-dependenttrans@*/ /* FIX: artifact of spoofing header tag store */
01659     fi->dil = (!scareMem)
01660         ? xcalloc(sizeof(*fi->dil), fi->fc)
01661         : (rpmuint32_t *)(fi->bnl + fi->fc);
01662 /*@=dependenttrans@*/
01663 
01664     /* XXX Insure at least 1 byte is always allocated. */
01665     fi->apath = xmalloc(fi->fc * sizeof(*fi->apath) + apathlen + 1);
01666     a = (char *)(fi->apath + fi->fc);
01667     *a = '\0';
01668 
01669     fi->actions = _free(fi->actions);                   /* XXX memory leak */
01670     fi->actions = xcalloc(sizeof(*fi->actions), fi->fc);
01671     fi->fmapflags = xcalloc(sizeof(*fi->fmapflags), fi->fc);
01672     fi->astriplen = 0;
01673     if (fl->buildRootURL)
01674         fi->astriplen = strlen(fl->buildRootURL);
01675     fi->striplen = 0;
01676     fi->fuser = _free(fi->fuser);
01677     fi->fgroup = _free(fi->fgroup);
01678 
01679     /* Make the cpio list */
01680     if (fi->dil != NULL)        /* XXX can't happen */
01681     for (i = 0, flp = fl->fileList; (unsigned)i < fi->fc; i++, flp++) {
01682         char * b;
01683 
01684         /* Skip (possible) duplicate file entries, use last entry info. */
01685         while (((flp - fl->fileList) < (fl->fileListRecsUsed - 1)) &&
01686                 !strcmp(flp->fileURL, flp[1].fileURL))
01687             flp++;
01688 
01689         if (flp->flags & RPMFILE_EXCLUDE) {
01690             i--;
01691             continue;
01692         }
01693 
01694         {
01695             /* this fi uses diskURL (with buildroot), not fileURL */
01696             size_t fnlen = strlen(flp->diskURL);
01697             if (fnlen > fi->fnlen) {
01698                 /* fnlen-sized buffer must not be allocated yet */
01699                 assert(fi->fn == NULL);
01700                 fi->fnlen = fnlen;
01701             }
01702         }
01703 
01704         /* Create disk directory and base name. */
01705         fi->dil[i] = i;
01706 /*@-dependenttrans@*/ /* FIX: artifact of spoofing header tag store */
01707         fi->dnl[fi->dil[i]] = d;
01708 /*@=dependenttrans@*/
01709         d = stpcpy(d, flp->diskURL);
01710 
01711         /* Make room for the dirName NUL, find start of baseName. */
01712         for (b = d; b > fi->dnl[fi->dil[i]] && *b != '/'; b--)
01713             b[1] = b[0];
01714         b++;            /* dirname's end in '/' */
01715         *b++ = '\0';    /* terminate dirname, b points to basename */
01716         fi->bnl[i] = b;
01717         d += 2;         /* skip both dirname and basename NUL's */
01718 
01719         /* Create archive path, normally adding "./" */
01720         /*@-dependenttrans@*/   /* FIX: xstrdup? nah ... */
01721         fi->apath[i] = a;
01722         /*@=dependenttrans@*/
01723         if (_addDotSlash)
01724             a = stpcpy(a, "./");
01725         (void) urlPath(flp->fileURL, &apath);
01726         a = stpcpy(a, (apath + skipLen));
01727         a++;            /* skip apath NUL */
01728 
01729         if (flp->flags & RPMFILE_GHOST) {
01730             fi->actions[i] = FA_SKIP;
01731             continue;
01732         }
01733         fi->actions[i] = FA_COPYOUT;
01734         fi->fmapflags[i] = IOSM_MAP_PATH |
01735                 IOSM_MAP_TYPE | IOSM_MAP_MODE | IOSM_MAP_UID | IOSM_MAP_GID;
01736         if (isSrc)
01737             fi->fmapflags[i] |= IOSM_FOLLOW_SYMLINKS;
01738 
01739         if (S_ISREG(flp->fl_mode)) {
01740             int bingo = 1;
01741             /* Hard links need be tallied only once. */
01742             if (flp->fl_nlink > 1) {
01743                 FileListRec jlp = flp + 1;
01744                 int j = i + 1;
01745                 for (; (unsigned)j < fi->fc; j++, jlp++) {
01746                     /* follow outer loop logic */
01747                     while (((jlp - fl->fileList) < (fl->fileListRecsUsed - 1)) &&
01748                             !strcmp(jlp->fileURL, jlp[1].fileURL))
01749                         jlp++;
01750                     if (jlp->flags & RPMFILE_EXCLUDE) {
01751                         j--;
01752                         /*@innercontinue@*/ continue;
01753                     }
01754                     if (jlp->flags & RPMFILE_GHOST)
01755                         /*@innercontinue@*/ continue;
01756                     if (!S_ISREG(jlp->fl_mode))
01757                         /*@innercontinue@*/ continue;
01758                     if (flp->fl_nlink != jlp->fl_nlink)
01759                         /*@innercontinue@*/ continue;
01760                     if (flp->fl_ino != jlp->fl_ino)
01761                         /*@innercontinue@*/ continue;
01762                     if (flp->fl_dev != jlp->fl_dev)
01763                         /*@innercontinue@*/ continue;
01764                     bingo = 0;  /* don't tally hardlink yet. */
01765                     /*@innerbreak@*/ break;
01766                 }
01767             }
01768             if (bingo)
01769                 fl->totalFileSize += flp->fl_size;
01770         }
01771     }
01772 
01773     ui32 = fl->totalFileSize;
01774     he->tag = RPMTAG_SIZE;
01775     he->t = RPM_UINT32_TYPE;
01776     he->p.ui32p = &ui32;
01777     he->c = 1;
01778     xx = headerPut(h, he, 0);
01779 
01780     /*@-compdef@*/
01781     if (fip)
01782         *fip = fi;
01783     else
01784         fi = rpmfiFree(fi);
01785     /*@=compdef@*/
01786   }
01787 }
01788 
01791 static /*@null@*/ FileListRec freeFileList(/*@only@*/ FileListRec fileList,
01792                         int count)
01793         /*@*/
01794 {
01795     while (count--) {
01796         fileList[count].diskURL = _free(fileList[count].diskURL);
01797         fileList[count].fileURL = _free(fileList[count].fileURL);
01798         fileList[count].langs = _free(fileList[count].langs);
01799     }
01800     fileList = _free(fileList);
01801     return NULL;
01802 }
01803 
01804 /* forward ref */
01805 static rpmRC recurseDir(FileList fl, const char * diskURL)
01806         /*@globals rpmGlobalMacroContext, h_errno,
01807                 fileSystem, internalState @*/
01808         /*@modifies *fl, fl->processingFailed,
01809                 fl->fileList, fl->fileListRecsAlloced, fl->fileListRecsUsed,
01810                 fl->totalFileSize, fl->fileCount, fl->inFtw, fl->isDir,
01811                 rpmGlobalMacroContext,
01812                 fileSystem, internalState @*/;
01813 
01821 static int addFile(FileList fl, const char * diskURL,
01822                 /*@null@*/ struct stat * statp)
01823         /*@globals rpmGlobalMacroContext, h_errno,
01824                 fileSystem, internalState @*/
01825         /*@modifies *statp, *fl, fl->processingFailed,
01826                 fl->fileList, fl->fileListRecsAlloced, fl->fileListRecsUsed,
01827                 fl->totalFileSize, fl->fileCount,
01828                 rpmGlobalMacroContext,
01829                 fileSystem, internalState @*/
01830 {
01831     const char *fn = xstrdup(diskURL);
01832     const char *fileURL = fn;
01833     struct stat statbuf;
01834     mode_t fileMode;
01835     uid_t fileUid;
01836     gid_t fileGid;
01837     const char *fileUname;
01838     const char *fileGname;
01839     char *lang;
01840     rpmRC rc = RPMRC_OK;
01841     
01842     /* Path may have prepended buildRootURL, so locate the original filename. */
01843     /*
01844      * XXX There are 3 types of entry into addFile:
01845      *
01846      *  From                    diskUrl                 statp
01847      *  =====================================================
01848      *  processBinaryFile       path                    NULL
01849      *  processBinaryFile       glob result path        NULL
01850      *  recurseDir              path                    stat
01851      *
01852      */
01853     {   const char *fileName;
01854         int urltype = urlPath(fileURL, &fileName);
01855         switch (urltype) {
01856         case URL_IS_PATH:
01857             fileURL += (fileName - fileURL);
01858             if (fl->buildRootURL && strcmp(fl->buildRootURL, "/")) {
01859                 size_t nb = strlen(fl->buildRootURL);
01860                 const char * s = fileURL + nb;
01861                 char * t = (char *) fileURL;
01862                 (void) memmove(t, s, nb);
01863             }
01864             fileURL = fn;
01865             break;
01866         default:
01867             if (fl->buildRootURL && strcmp(fl->buildRootURL, "/"))
01868                 fileURL += strlen(fl->buildRootURL);
01869             break;
01870         }
01871     }
01872 
01873     /* XXX make sure '/' can be packaged also */
01874     if (*fileURL == '\0')
01875         fileURL = "/";
01876 
01877     /* If we are using a prefix, validate the file */
01878     if (!fl->inFtw && fl->prefix) {
01879         const char *prefixTest;
01880         const char *prefixPtr = fl->prefix;
01881 
01882         (void) urlPath(fileURL, &prefixTest);
01883         while (*prefixPtr && *prefixTest && (*prefixTest == *prefixPtr)) {
01884             prefixPtr++;
01885             prefixTest++;
01886         }
01887         if (*prefixPtr || (*prefixTest && *prefixTest != '/')) {
01888             rpmlog(RPMLOG_ERR, _("File doesn't match prefix (%s): %s\n"),
01889                      fl->prefix, fileURL);
01890             fl->processingFailed = 1;
01891             rc = RPMRC_FAIL;
01892             goto exit;
01893         }
01894     }
01895 
01896     if (statp == NULL) {
01897         statp = &statbuf;
01898         memset(statp, 0, sizeof(*statp));
01899         if (fl->devtype) {
01900             time_t now = time(NULL);
01901 
01902             /* XXX hack up a stat structure for a %dev(...) directive. */
01903             statp->st_nlink = 1;
01904             statp->st_rdev =
01905                 ((fl->devmajor & 0xff) << 8) | (fl->devminor & 0xff);
01906             statp->st_dev = statp->st_rdev;
01907             statp->st_mode = (fl->devtype == 'b' ? S_IFBLK : S_IFCHR);
01908             statp->st_mode |= (fl->cur_ar.ar_fmode & 0777);
01909             statp->st_atime = now;
01910             statp->st_mtime = now;
01911             statp->st_ctime = now;
01912         } else if (Lstat(diskURL, statp)) {
01913             if (fl->currentFlags & RPMFILE_OPTIONAL) {
01914                 rpmlog(RPMLOG_WARNING, _("Optional file not found: %s\n"), diskURL);
01915                 rc = RPMRC_OK;
01916             } else {
01917                 rpmlog(RPMLOG_ERR, _("File not found: %s\n"), diskURL);
01918                 fl->processingFailed = 1;
01919                 rc = RPMRC_FAIL;
01920             }
01921             goto exit;
01922         }
01923     }
01924 
01925     if ((! fl->isDir) && S_ISDIR(statp->st_mode)) {
01926 /*@-nullstate@*/ /* FIX: fl->buildRootURL may be NULL */
01927         rc = recurseDir(fl, diskURL);
01928         goto exit;
01929 /*@=nullstate@*/
01930     }
01931 
01932     fileMode = statp->st_mode;
01933     fileUid = statp->st_uid;
01934     fileGid = statp->st_gid;
01935 
01936     if (S_ISDIR(fileMode) && fl->cur_ar.ar_dmodestr) {
01937         fileMode &= S_IFMT;
01938         fileMode |= fl->cur_ar.ar_dmode;
01939     } else if (fl->cur_ar.ar_fmodestr != NULL) {
01940         fileMode &= S_IFMT;
01941         fileMode |= fl->cur_ar.ar_fmode;
01942     }
01943     if (fl->cur_ar.ar_user) {
01944         fileUname = getUnameS(fl->cur_ar.ar_user);
01945     } else {
01946         fileUname = getUname(fileUid);
01947     }
01948     if (fl->cur_ar.ar_group) {
01949         fileGname = getGnameS(fl->cur_ar.ar_group);
01950     } else {
01951         fileGname = getGname(fileGid);
01952     }
01953         
01954     /* Default user/group to builder's user/group */
01955     if (fileUname == NULL)
01956         fileUname = getUname(getuid());
01957     if (fileGname == NULL)
01958         fileGname = getGname(getgid());
01959     
01960     /* Add to the file list */
01961     if (fl->fileListRecsUsed == fl->fileListRecsAlloced) {
01962         fl->fileListRecsAlloced += 128;
01963         fl->fileList = xrealloc(fl->fileList,
01964                         fl->fileListRecsAlloced * sizeof(*(fl->fileList)));
01965     }
01966             
01967     {   FileListRec flp = &fl->fileList[fl->fileListRecsUsed];
01968         int i;
01969 
01970         flp->fl_st = *statp;    /* structure assignment */
01971         flp->fl_mode = fileMode;
01972         flp->fl_uid = fileUid;
01973         flp->fl_gid = fileGid;
01974 
01975         flp->fileURL = xstrdup(fileURL);
01976         flp->diskURL = xstrdup(diskURL);
01977         flp->uname = fileUname;
01978         flp->gname = fileGname;
01979 
01980         if (fl->currentLangs && fl->nLangs > 0) {
01981             char * ncl;
01982             size_t nl = 0;
01983             
01984             for (i = 0; i < fl->nLangs; i++)
01985                 nl += strlen(fl->currentLangs[i]) + 1;
01986 
01987             flp->langs = ncl = xmalloc(nl);
01988             for (i = 0; i < fl->nLangs; i++) {
01989                 const char *ocl;
01990                 if (i)  *ncl++ = '|';
01991                 for (ocl = fl->currentLangs[i]; *ocl != '\0'; ocl++)
01992                         *ncl++ = *ocl;
01993                 *ncl = '\0';
01994             }
01995         } else if (! parseForRegexLang(fileURL, &lang)) {
01996             flp->langs = xstrdup(lang);
01997         } else {
01998             flp->langs = xstrdup("");
01999         }
02000 
02001         flp->flags = fl->currentFlags;
02002         flp->specdFlags = fl->currentSpecdFlags;
02003         flp->verifyFlags = fl->currentVerifyFlags;
02004     }
02005 
02006     fl->fileListRecsUsed++;
02007     fl->fileCount++;
02008 
02009 exit:
02010 /*@i@*/ fn = _free(fn);
02011     return rc;
02012 }
02013 
02020 static rpmRC recurseDir(FileList fl, const char * diskURL)
02021 {
02022     char * ftsSet[2];
02023     FTS * ftsp;
02024     FTSENT * fts;
02025     int myFtsOpts = (FTS_COMFOLLOW | FTS_NOCHDIR | FTS_PHYSICAL);
02026     rpmRC rc = RPMRC_FAIL;
02027 
02028     fl->inFtw = 1;  /* Flag to indicate file has buildRootURL prefixed */
02029     fl->isDir = 1;  /* Keep it from following myftw() again         */
02030 
02031     ftsSet[0] = (char *) diskURL;
02032     ftsSet[1] = NULL;
02033     ftsp = Fts_open(ftsSet, myFtsOpts, NULL);
02034     while ((fts = Fts_read(ftsp)) != NULL) {
02035         switch (fts->fts_info) {
02036         case FTS_D:             /* preorder directory */
02037         case FTS_F:             /* regular file */
02038         case FTS_SL:            /* symbolic link */
02039         case FTS_SLNONE:        /* symbolic link without target */
02040         case FTS_DEFAULT:       /* none of the above */
02041             rc = addFile(fl, fts->fts_accpath, fts->fts_statp);
02042             /*@switchbreak@*/ break;
02043         case FTS_DOT:           /* dot or dot-dot */
02044         case FTS_DP:            /* postorder directory */
02045             rc = RPMRC_OK;
02046             /*@switchbreak@*/ break;
02047         case FTS_NS:            /* stat(2) failed */
02048         case FTS_DNR:           /* unreadable directory */
02049         case FTS_ERR:           /* error; errno is set */
02050         case FTS_DC:            /* directory that causes cycles */
02051         case FTS_NSOK:          /* no stat(2) requested */
02052         case FTS_INIT:          /* initialized only */
02053         case FTS_W:             /* whiteout object */
02054         default:
02055             rc = RPMRC_FAIL;
02056             /*@switchbreak@*/ break;
02057         }
02058         if (rc != RPMRC_OK)
02059             break;
02060     }
02061     (void) Fts_close(ftsp);
02062 
02063     fl->isDir = 0;
02064     fl->inFtw = 0;
02065 
02066     return rc;
02067 }
02068 
02077 static rpmRC processMetadataFile(Package pkg, FileList fl, const char * fileURL,
02078                 rpmTag tag)
02079         /*@globals rpmGlobalMacroContext, h_errno,
02080                 fileSystem, internalState @*/
02081         /*@modifies pkg->header, *fl, fl->processingFailed,
02082                 fl->fileList, fl->fileListRecsAlloced, fl->fileListRecsUsed,
02083                 fl->totalFileSize, fl->fileCount,
02084                 rpmGlobalMacroContext,
02085                 fileSystem, internalState @*/
02086 {
02087     HE_t he = memset(alloca(sizeof(*he)), 0, sizeof(*he));
02088     const char * buildURL = "%{_builddir}/%{?buildsubdir}/";
02089     const char * fn = NULL;
02090     const char * apkt = NULL;
02091     rpmiob iob = NULL;
02092     rpmuint8_t * pkt = NULL;
02093     ssize_t pktlen = 0;
02094     int absolute = 0;
02095     rpmRC rc = RPMRC_FAIL;
02096     int xx;
02097 
02098     (void) urlPath(fileURL, &fn);
02099     if (*fn == '/') {
02100         fn = rpmGenPath(fl->buildRootURL, NULL, fn);
02101         absolute = 1;
02102     } else
02103         fn = rpmGenPath(buildURL, NULL, fn);
02104 
02105     switch (tag) {
02106     default:
02107         rpmlog(RPMLOG_ERR, _("%s: can't load unknown tag (%d).\n"),
02108                 fn, tag);
02109         goto exit;
02110         /*@notreached@*/ break;
02111     case RPMTAG_PUBKEYS:
02112         if ((xx = pgpReadPkts(fn, &pkt, (size_t *)&pktlen)) <= 0) {
02113             rpmlog(RPMLOG_ERR, _("%s: public key read failed.\n"), fn);
02114             goto exit;
02115         }
02116         if (xx != PGPARMOR_PUBKEY) {
02117             rpmlog(RPMLOG_ERR, _("%s: not an armored public key.\n"), fn);
02118             goto exit;
02119         }
02120         apkt = pgpArmorWrap(PGPARMOR_PUBKEY, pkt, pktlen);
02121         break;
02122     case RPMTAG_POLICIES:
02123         xx = rpmiobSlurp(fn, &iob);
02124         if (!(xx == 0 && iob != NULL)) {
02125             rpmlog(RPMLOG_ERR, _("%s: *.te policy read failed.\n"), fn);
02126             goto exit;
02127         }
02128         apkt = (const char *) iob->b;   /* XXX unsigned char */
02129         /* XXX steal the I/O buffer */
02130         iob->b = (rpmuint8_t *)xcalloc(1, sizeof(*iob->b));
02131         iob->blen = 0;
02132         break;
02133     }
02134 
02135     he->tag = tag;
02136     he->t = RPM_STRING_ARRAY_TYPE;
02137     he->p.argv = &apkt;
02138     he->c = 1;
02139     he->append = 1;
02140     xx = headerPut(pkg->header, he, 0);
02141     he->append = 0;
02142 
02143     rc = RPMRC_OK;
02144     if (absolute)
02145         rc = addFile(fl, fn, NULL);
02146 
02147 exit:
02148     apkt = _free(apkt);
02149     pkt = _free(pkt);
02150     iob = rpmiobFree(iob);
02151     fn = _free(fn);
02152     if (rc != RPMRC_OK)
02153         fl->processingFailed = 1;
02154     return rc;
02155 }
02156 
02164 static rpmRC processBinaryFile(/*@unused@*/ Package pkg, FileList fl,
02165                 const char * fileURL)
02166         /*@globals rpmGlobalMacroContext, h_errno, fileSystem, internalState @*/
02167         /*@modifies *fl, fl->processingFailed,
02168                 fl->fileList, fl->fileListRecsAlloced, fl->fileListRecsUsed,
02169                 fl->totalFileSize, fl->fileCount,
02170                 rpmGlobalMacroContext, fileSystem, internalState @*/
02171 {
02172     int quote = 1;      /* XXX permit quoted glob characters. */
02173     int doGlob;
02174     const char *diskURL = NULL;
02175     rpmRC rc = RPMRC_OK;
02176     int xx;
02177     
02178     doGlob = Glob_pattern_p(fileURL, quote);
02179 
02180     /* Check that file starts with leading "/" */
02181     {   const char * fileName;
02182         (void) urlPath(fileURL, &fileName);
02183         if (*fileName != '/') {
02184             rpmlog(RPMLOG_ERR, _("File needs leading \"/\": %s\n"),
02185                         fileName);
02186             rc = RPMRC_FAIL;
02187             goto exit;
02188         }
02189     }
02190     
02191     /* Copy file name or glob pattern removing multiple "/" chars. */
02192     /*
02193      * Note: rpmGetPath should guarantee a "canonical" path. That means
02194      * that the following pathologies should be weeded out:
02195      *          //bin//sh
02196      *          //usr//bin/
02197      *          /.././../usr/../bin//./sh
02198      */
02199     diskURL = rpmGenPath(fl->buildRootURL, NULL, fileURL);
02200 
02201     if (doGlob) {
02202         const char ** argv = NULL;
02203         int argc = 0;
02204         int i;
02205 
02206         /* XXX for %dev marker in file manifest only */
02207         if (fl->noGlob) {
02208             rpmlog(RPMLOG_ERR, _("Glob not permitted: %s\n"),
02209                         diskURL);
02210             rc = RPMRC_FAIL;
02211             goto exit;
02212         }
02213 
02214         xx = rpmGlob(diskURL, &argc, &argv);
02215         if (xx == 0 && argc >= 1) {
02216             for (i = 0; i < argc; i++) {
02217                 rc = addFile(fl, argv[i], NULL);
02218                 argv[i] = _free(argv[i]);
02219             }
02220             argv = _free(argv);
02221         } else {
02222             if (fl->currentFlags & RPMFILE_OPTIONAL) {
02223                 rpmlog(RPMLOG_WARNING, _("Optional file not found by glob: %s\n"),
02224                             diskURL);
02225                 rc = RPMRC_OK;
02226             } else {
02227                 rpmlog(RPMLOG_ERR, _("File not found by glob: %s\n"),
02228                             diskURL);
02229                 rc = RPMRC_FAIL;
02230             }
02231             goto exit;
02232         }
02233     } else
02234         rc = addFile(fl, diskURL, NULL);
02235 
02236 exit:
02237     diskURL = _free(diskURL);
02238     if (rc != RPMRC_OK)
02239         fl->processingFailed = 1;
02240     return rc;
02241 }
02242 
02245 static rpmRC processPackageFiles(Spec spec, Package pkg,
02246                                int installSpecialDoc, int test)
02247         /*@globals rpmGlobalMacroContext, h_errno,
02248                 fileSystem, internalState@*/
02249         /*@modifies spec->macros,
02250                 pkg->fi, pkg->fileList, pkg->specialDoc, pkg->header,
02251                 rpmGlobalMacroContext, fileSystem, internalState @*/
02252 {
02253     HE_t he = memset(alloca(sizeof(*he)), 0, sizeof(*he));
02254     struct FileList_s fl;
02255     ARGV_t files = NULL;
02256     ARGV_t fp;
02257     const char *fileName;
02258     char buf[BUFSIZ];
02259     struct AttrRec_s arbuf;
02260     AttrRec specialDocAttrRec = &arbuf;
02261     char *specialDoc = NULL;
02262     int xx;
02263 
02264     nullAttrRec(specialDocAttrRec);
02265     pkg->fi = NULL;
02266 
02267     if (pkg->fileFile) {
02268         char *saveptr = NULL;
02269         char *filesFiles = xstrdup(pkg->fileFile);
02270 /*@-unrecog@*/
02271         char *token = strtok_r(filesFiles, ",", &saveptr);
02272 /*@=unrecog@*/
02273         do {
02274             const char *ffn;
02275             FILE * f;
02276             FD_t fd;
02277 
02278             /* XXX W2DO? urlPath might be useful here. */
02279             if (*token == '/') {
02280                 ffn = rpmGetPath(token, NULL);
02281             } else {
02282                 /* XXX FIXME: add %{buildsubdir} */
02283                 ffn = rpmGetPath("%{_builddir}/",
02284                     (spec->buildSubdir ? spec->buildSubdir : "") ,
02285                     "/", token, NULL);
02286             }
02287 
02288             fd = Fopen(ffn, "r.fpio");
02289 
02290             if (fd == NULL || Ferror(fd)) {
02291                 rpmlog(RPMLOG_ERR,
02292                     _("Could not open %%files file %s: %s\n"),
02293                     ffn, Fstrerror(fd));
02294                 return RPMRC_FAIL;
02295             }
02296             ffn = _free(ffn);
02297 
02298             /*@+voidabstract@*/ f = fdGetFp(fd); /*@=voidabstract@*/
02299             if (f != NULL) {
02300                 while (fgets(buf, (int)sizeof(buf), f)) {
02301                     handleComments(buf);
02302                     if (expandMacros(spec, spec->macros, buf, sizeof(buf))) {
02303                         rpmlog(RPMLOG_ERR, _("line: %s\n"), buf);
02304                         return RPMRC_FAIL;
02305                     }
02306                     pkg->fileList = rpmiobAppend(pkg->fileList, buf, 0);
02307                 }
02308             }
02309             (void) Fclose(fd);
02310         } while((token = strtok_r(NULL, ",", &saveptr)) != NULL);
02311         filesFiles = _free(filesFiles);
02312     }
02313     
02314     /* Init the file list structure */
02315     memset(&fl, 0, sizeof(fl));
02316 
02317     fl.buildRootURL = rpmGenPath(spec->rootURL, "%{?buildroot}", NULL);
02318 
02319     he->tag = RPMTAG_DEFAULTPREFIX;
02320     xx = headerGet(pkg->header, he, 0);
02321     fl.prefix = he->p.str;
02322 
02323     fl.fileCount = 0;
02324     fl.totalFileSize = 0;
02325     fl.processingFailed = 0;
02326 
02327     fl.passedSpecialDoc = 0;
02328     fl.isSpecialDoc = 0;
02329 
02330     fl.isDir = 0;
02331     fl.inFtw = 0;
02332     fl.currentFlags = 0;
02333     fl.currentVerifyFlags = 0;
02334     
02335     fl.noGlob = 0;
02336     fl.devtype = 0;
02337     fl.devmajor = 0;
02338     fl.devminor = 0;
02339 
02340     nullAttrRec(&fl.cur_ar);
02341     nullAttrRec(&fl.def_ar);
02342     dupAttrRec(&root_ar, &fl.def_ar);   /* XXX assume %defattr(-,root,root) */
02343 
02344     fl.defVerifyFlags = RPMVERIFY_ALL;
02345     fl.nLangs = 0;
02346     fl.currentLangs = NULL;
02347 
02348     fl.currentSpecdFlags = 0;
02349     fl.defSpecdFlags = 0;
02350 
02351     fl.docDirCount = 0;
02352 #if defined(RPM_VENDOR_OPENPKG) /* no-default-doc-files */
02353     /* do not declare any files as %doc files by default. */
02354 #else
02355     fl.docDirs[fl.docDirCount++] = xstrdup("/usr/doc");
02356     fl.docDirs[fl.docDirCount++] = xstrdup("/usr/man");
02357     fl.docDirs[fl.docDirCount++] = xstrdup("/usr/info");
02358     fl.docDirs[fl.docDirCount++] = xstrdup("/usr/X11R6/man");
02359     fl.docDirs[fl.docDirCount++] = xstrdup("/usr/share/doc");
02360     fl.docDirs[fl.docDirCount++] = xstrdup("/usr/share/man");
02361     fl.docDirs[fl.docDirCount++] = xstrdup("/usr/share/info");
02362     fl.docDirs[fl.docDirCount++] = xstrdup("/usr/src/examples");
02363     fl.docDirs[fl.docDirCount++] = rpmGetPath("%{_docdir}", NULL);
02364     fl.docDirs[fl.docDirCount++] = rpmGetPath("%{_mandir}", NULL);
02365     fl.docDirs[fl.docDirCount++] = rpmGetPath("%{_infodir}", NULL);
02366     fl.docDirs[fl.docDirCount++] = rpmGetPath("%{_javadocdir}", NULL);
02367     fl.docDirs[fl.docDirCount++] = rpmGetPath("%{_examplesdir}", NULL);
02368 #endif
02369     
02370     fl.fileList = NULL;
02371     fl.fileListRecsAlloced = 0;
02372     fl.fileListRecsUsed = 0;
02373 
02374     xx = argvSplit(&files, rpmiobStr(pkg->fileList), "\n");
02375 
02376     for (fp = files; *fp != NULL; fp++) {
02377         const char * s;
02378         s = *fp;
02379         SKIPSPACE(s);
02380         if (*s == '\0')
02381             continue;
02382         fileName = NULL;
02383         /*@-nullpass@*/ /* LCL: buf is NULL ?!? */
02384         strncpy(buf, s, sizeof(buf)-1);
02385         buf[sizeof(buf)-1] = '\0';
02386         /*@=nullpass@*/
02387         
02388         /* Reset for a new line in %files */
02389         fl.isDir = 0;
02390         fl.inFtw = 0;
02391         fl.currentFlags = 0;
02392         /* turn explicit flags into %def'd ones (gosh this is hacky...) */
02393         fl.currentSpecdFlags = ((unsigned)fl.defSpecdFlags) >> 8;
02394         fl.currentVerifyFlags = fl.defVerifyFlags;
02395         fl.isSpecialDoc = 0;
02396 
02397         fl.noGlob = 0;
02398         fl.devtype = 0;
02399         fl.devmajor = 0;
02400         fl.devminor = 0;
02401 
02402         /* XXX should reset to %deflang value */
02403         if (fl.currentLangs) {
02404             int i;
02405             for (i = 0; i < fl.nLangs; i++)
02406                 /*@-unqualifiedtrans@*/
02407                 fl.currentLangs[i] = _free(fl.currentLangs[i]);
02408                 /*@=unqualifiedtrans@*/
02409             fl.currentLangs = _free(fl.currentLangs);
02410         }
02411         fl.nLangs = 0;
02412 
02413         dupAttrRec(&fl.def_ar, &fl.cur_ar);
02414 
02415         /*@-nullpass@*/ /* LCL: buf is NULL ?!? */
02416         if (parseForVerify(buf, &fl) != RPMRC_OK)
02417             continue;
02418         if (parseForAttr(buf, &fl) != RPMRC_OK)
02419             continue;
02420         if (parseForDev(buf, &fl) != RPMRC_OK)
02421             continue;
02422         if (parseForConfig(buf, &fl) != RPMRC_OK)
02423             continue;
02424         if (parseForLang(buf, &fl) != RPMRC_OK)
02425             continue;
02426         /*@-nullstate@*/        /* FIX: pkg->fileFile might be NULL */
02427         if (parseForSimple(spec, pkg, buf, &fl, &fileName) != RPMRC_OK)
02428         /*@=nullstate@*/
02429             continue;
02430         /*@=nullpass@*/
02431         if (fileName == NULL)
02432             continue;
02433 
02434         if (fl.isSpecialDoc) {
02435             /* Save this stuff for last */
02436             specialDoc = _free(specialDoc);
02437             specialDoc = xstrdup(fileName);
02438             dupAttrRec(&fl.cur_ar, specialDocAttrRec);
02439         } else if (fl.currentFlags & RPMFILE_PUBKEY) {
02440 /*@-nullstate@*/        /* FIX: pkg->fileFile might be NULL */
02441             (void) processMetadataFile(pkg, &fl, fileName, RPMTAG_PUBKEYS);
02442 /*@=nullstate@*/
02443         } else if (fl.currentFlags & RPMFILE_POLICY) {
02444 /*@-nullstate@*/        /* FIX: pkg->fileFile might be NULL */
02445             (void) processMetadataFile(pkg, &fl, fileName, RPMTAG_POLICIES);
02446 /*@=nullstate@*/
02447         } else {
02448 /*@-nullstate@*/        /* FIX: pkg->fileFile might be NULL */
02449             (void) processBinaryFile(pkg, &fl, fileName);
02450 /*@=nullstate@*/
02451         }
02452     }
02453 
02454     /* Now process special doc, if there is one */
02455     if (specialDoc) {
02456         if (installSpecialDoc) {
02457             int _missing_doc_files_terminate_build =
02458                     rpmExpandNumeric("%{?_missing_doc_files_terminate_build}");
02459             rpmRC rc;
02460 
02461             rc = doScript(spec, RPMBUILD_STRINGBUF, "%doc", pkg->specialDoc, test);
02462             if (rc != RPMRC_OK && _missing_doc_files_terminate_build)
02463                 fl.processingFailed = 1;
02464         }
02465 
02466         /* Reset for %doc */
02467         fl.isDir = 0;
02468         fl.inFtw = 0;
02469         fl.currentFlags = 0;
02470         fl.currentVerifyFlags = fl.defVerifyFlags;
02471 
02472         fl.noGlob = 0;
02473         fl.devtype = 0;
02474         fl.devmajor = 0;
02475         fl.devminor = 0;
02476 
02477         /* XXX should reset to %deflang value */
02478         if (fl.currentLangs) {
02479             int i;
02480             for (i = 0; i < fl.nLangs; i++)
02481                 /*@-unqualifiedtrans@*/
02482                 fl.currentLangs[i] = _free(fl.currentLangs[i]);
02483                 /*@=unqualifiedtrans@*/
02484             fl.currentLangs = _free(fl.currentLangs);
02485         }
02486         fl.nLangs = 0;
02487 
02488         dupAttrRec(specialDocAttrRec, &fl.cur_ar);
02489         freeAttrRec(specialDocAttrRec);
02490 
02491         /*@-nullstate@*/        /* FIX: pkg->fileFile might be NULL */
02492         (void) processBinaryFile(pkg, &fl, specialDoc);
02493         /*@=nullstate@*/
02494 
02495         specialDoc = _free(specialDoc);
02496     }
02497     
02498     files = argvFree(files);
02499 
02500     if (fl.processingFailed)
02501         goto exit;
02502 
02503     /* Verify that file attributes scope over hardlinks correctly. */
02504     if (checkHardLinks(&fl))
02505         (void) rpmlibNeedsFeature(pkg->header,
02506                         "PartialHardlinkSets", "4.0.4-1");
02507 
02508     /* XXX should tags be added if filelist is empty? */
02509     genCpioListAndHeader(&fl, &pkg->fi, pkg->header, 0);
02510 
02511     if (spec->timeCheck)
02512         timeCheck(spec->timeCheck, pkg->header);
02513     
02514 exit:
02515     fl.buildRootURL = _free(fl.buildRootURL);
02516     fl.prefix = _free(fl.prefix);
02517 
02518     freeAttrRec(&fl.cur_ar);
02519     freeAttrRec(&fl.def_ar);
02520 
02521     if (fl.currentLangs) {
02522         int i;
02523         for (i = 0; i < fl.nLangs; i++)
02524             /*@-unqualifiedtrans@*/
02525             fl.currentLangs[i] = _free(fl.currentLangs[i]);
02526             /*@=unqualifiedtrans@*/
02527         fl.currentLangs = _free(fl.currentLangs);
02528     }
02529 
02530     fl.fileList = freeFileList(fl.fileList, fl.fileListRecsUsed);
02531     while (fl.docDirCount--)
02532         fl.docDirs[fl.docDirCount] = _free(fl.docDirs[fl.docDirCount]);
02533     return (fl.processingFailed ? RPMRC_FAIL : RPMRC_OK);
02534 }
02535 
02536 int initSourceHeader(Spec spec, rpmiob *sfp)
02537 {
02538     HE_t he = memset(alloca(sizeof(*he)), 0, sizeof(*he));
02539     HeaderIterator hi;
02540     rpmiob sourceFiles;
02541     struct Source *srcPtr;
02542     static rpmTag classTag = 0xffffffff;
02543     int xx;
02544     size_t i;
02545 
02546     if (classTag == 0xffffffff)
02547         classTag = tagValue("Class");
02548 
02549     /* Only specific tags are added to the source package header */
02550   if (spec->packages && !spec->sourceHdrInit) {
02551     for (hi = headerInit(spec->packages->header);
02552         headerNext(hi, he, 0);
02553         he->p.ptr = _free(he->p.ptr))
02554     {
02555         switch (he->tag) {
02556         case RPMTAG_NAME:
02557         case RPMTAG_VERSION:
02558         case RPMTAG_RELEASE:
02559         case RPMTAG_DISTEPOCH:
02560         case RPMTAG_EPOCH:
02561         case RPMTAG_SUMMARY:
02562         case RPMTAG_DESCRIPTION:
02563         case RPMTAG_PACKAGER:
02564         case RPMTAG_DISTRIBUTION:
02565         case RPMTAG_DISTURL:
02566         case RPMTAG_VENDOR:
02567         case RPMTAG_LICENSE:
02568         case RPMTAG_GROUP:
02569         case RPMTAG_OS:
02570         case RPMTAG_ARCH:
02571         case RPMTAG_CHANGELOGTIME:
02572         case RPMTAG_CHANGELOGNAME:
02573         case RPMTAG_CHANGELOGTEXT:
02574         case RPMTAG_URL:
02575         case RPMTAG_BUGURL:
02576         case RPMTAG_ICON:
02577         case RPMTAG_GIF:
02578         case RPMTAG_XPM:
02579         case HEADER_I18NTABLE:
02580 #if defined(RPM_VENDOR_OPENPKG) /* propagate-provides-to-srpms */
02581         /* make sure the "Provides" headers are available for querying from the .src.rpm files. */
02582         case RPMTAG_PROVIDENAME:
02583         case RPMTAG_PROVIDEVERSION:
02584         case RPMTAG_PROVIDEFLAGS:
02585 #endif
02586             if (he->p.ptr)
02587                 xx = headerPut(spec->sourceHeader, he, 0);
02588             /*@switchbreak@*/ break;
02589         default:
02590             if (classTag == he->tag && he->p.ptr != NULL)
02591                 xx = headerPut(spec->sourceHeader, he, 0);
02592             /*@switchbreak@*/ break;
02593         }
02594     }
02595     hi = headerFini(hi);
02596 
02597     if (spec->BANames && spec->BACount > 0) {
02598         he->tag = RPMTAG_BUILDARCHS;
02599         he->t = RPM_STRING_ARRAY_TYPE;
02600         he->p.argv = spec->BANames;
02601         he->c = spec->BACount;
02602         xx = headerPut(spec->sourceHeader, he, 0);
02603     }
02604 
02605     /* Load arbitrary tags into srpm header. */
02606     if (spec->foo)
02607     for (i = 0; i < spec->nfoo; i++) {
02608         const char * str = spec->foo[i].str;
02609         rpmTag tag = spec->foo[i].tag;
02610         rpmiob iob = spec->foo[i].iob;
02611         char * s;
02612 
02613         if (str == NULL || iob == NULL)
02614             continue;
02615 
02616         /* XXX Special case %track interpreter for now. */
02617         if (!xstrcasecmp(str, "track")) {
02618             he->p.str = rpmExpand("%{?__vcheck}", NULL);
02619             if (!(he->p.str != NULL && he->p.str[0] != '\0')) {
02620                 he->p.str = _free(he->p.str);
02621                 continue;
02622             }
02623             he->tag = tagValue("Trackprog");
02624             he->t = RPM_STRING_TYPE;
02625             he->c = 1;
02626             xx = headerPut(spec->sourceHeader, he, 0);
02627             he->p.str = _free(he->p.str);
02628         }
02629 
02630         s = rpmiobStr(iob);
02631         he->tag = tag;
02632         he->append = headerIsEntry(spec->sourceHeader, tag);
02633         if (he->append) {
02634             he->t = RPM_STRING_ARRAY_TYPE;
02635             he->p.argv = (const char **) &s;
02636             he->c = 1;
02637         } else {
02638             he->t = RPM_STRING_TYPE;
02639             he->p.str = s;
02640             he->c = 1;
02641         }
02642         xx = headerPut(spec->sourceHeader, he, 0);
02643         he->append = 0;
02644     }
02645   }
02646 
02647     if (sfp != NULL && *sfp != NULL)
02648         sourceFiles = *sfp;
02649     else
02650         sourceFiles = rpmiobNew(0);
02651 
02652     /* Construct the source/patch tag entries */
02653     if (spec->specFile != NULL) /* XXX segfault avoidance */
02654         sourceFiles = rpmiobAppend(sourceFiles, spec->specFile, 1);
02655     if (spec->sourceHeader != NULL)
02656     for (srcPtr = spec->sources; srcPtr != NULL; srcPtr = srcPtr->next) {
02657       { const char * sfn;
02658 /*@-nullpass@*/         /* XXX getSourceDir returns NULL with bad flags. */
02659         sfn = rpmGetPath( ((srcPtr->flags & RPMFILE_GHOST) ? "!" : ""),
02660 #if defined(RPM_VENDOR_OPENPKG) /* splitted-source-directory */
02661                 getSourceDir(srcPtr->flags, srcPtr->source), srcPtr->source, NULL);
02662 #else
02663                 getSourceDir(srcPtr->flags), srcPtr->source, NULL);
02664 #endif
02665 /*@=nullpass@*/
02666         sourceFiles = rpmiobAppend(sourceFiles, sfn, 1);
02667         sfn = _free(sfn);
02668       }
02669 
02670         if (spec->sourceHdrInit)
02671             continue;
02672 
02673         if (srcPtr->flags & RPMFILE_SOURCE) {
02674             he->tag = RPMTAG_SOURCE;
02675             he->t = RPM_STRING_ARRAY_TYPE;
02676             he->p.argv = &srcPtr->source;
02677             he->c = 1;
02678             he->append = 1;
02679             xx = headerPut(spec->sourceHeader, he, 0);
02680             he->append = 0;
02681             if (srcPtr->flags & RPMFILE_GHOST) {
02682                 he->tag = RPMTAG_NOSOURCE;
02683                 he->t = RPM_UINT32_TYPE;
02684                 he->p.ui32p = &srcPtr->num;
02685                 he->c = 1;
02686                 he->append = 1;
02687                 xx = headerPut(spec->sourceHeader, he, 0);
02688                 he->append = 0;
02689             }
02690         }
02691         if (srcPtr->flags & RPMFILE_PATCH) {
02692             he->tag = RPMTAG_PATCH;
02693             he->t = RPM_STRING_ARRAY_TYPE;
02694             he->p.argv = &srcPtr->source;
02695             he->c = 1;
02696             he->append = 1;
02697             xx = headerPut(spec->sourceHeader, he, 0);
02698             he->append = 0;
02699             if (srcPtr->flags & RPMFILE_GHOST) {
02700                 he->tag = RPMTAG_NOPATCH;
02701                 he->t = RPM_UINT32_TYPE;
02702                 he->p.ui32p = &srcPtr->num;
02703                 he->c = 1;
02704                 he->append = 1;
02705                 xx = headerPut(spec->sourceHeader, he, 0);
02706                 he->append = 0;
02707             }
02708         }
02709     }
02710 
02711     if (sfp == NULL)
02712         sourceFiles = rpmiobFree(sourceFiles);
02713 
02714     spec->sourceHdrInit = 1;
02715 
02716 /*@-usereleased@*/
02717     return 0;
02718 /*@=usereleased@*/
02719 }
02720 
02721 int processSourceFiles(Spec spec)
02722 {
02723     rpmiob sourceFiles, *sfp = &sourceFiles;
02724     int x, isSpec = 1;
02725     struct FileList_s fl;
02726     ARGV_t files = NULL;
02727     ARGV_t fp;
02728     int rc;
02729     /* srcdefattr: needed variables */
02730     char _srcdefattr_buf[BUFSIZ];
02731     char * _srcdefattr = rpmExpand("%{?_srcdefattr}", NULL);
02732     int xx;
02733 
02734     *sfp = rpmiobNew(0);
02735     x = initSourceHeader(spec, sfp);
02736 
02737     /* srcdefattr: initialize file list structure */
02738     memset(&fl, 0, sizeof(fl));
02739     if (_srcdefattr && *_srcdefattr) {
02740         xx = snprintf(_srcdefattr_buf, sizeof(_srcdefattr_buf), "%%defattr %s", _srcdefattr);
02741         _srcdefattr_buf[sizeof(_srcdefattr_buf)-1] = '\0';
02742         xx = parseForAttr(_srcdefattr_buf, &fl);
02743     }
02744 
02745     /* Construct the SRPM file list. */
02746     fl.fileList = xcalloc((spec->numSources + 1), sizeof(*fl.fileList));
02747     rc = fl.processingFailed = 0;
02748     fl.fileListRecsUsed = 0;
02749     fl.totalFileSize = 0;
02750     fl.prefix = NULL;
02751     fl.buildRootURL = NULL;
02752 
02753     xx = argvSplit(&files, rpmiobStr(*sfp), "\n");
02754 
02755     /* The first source file is the spec file */
02756     x = 0;
02757     for (fp = files; *fp != NULL; fp++) {
02758         const char * diskURL, *diskPath;
02759         FileListRec flp;
02760 
02761         diskURL = *fp;
02762         SKIPSPACE(diskURL);
02763         if (! *diskURL)
02764             continue;
02765 
02766         flp = &fl.fileList[x];
02767 
02768         flp->flags = isSpec ? RPMFILE_SPECFILE : 0;
02769         /* files with leading ! are no source files */
02770         if (*diskURL == '!') {
02771             flp->flags |= RPMFILE_GHOST;
02772             diskURL++;
02773         }
02774 
02775         (void) urlPath(diskURL, &diskPath);
02776 
02777         flp->diskURL = xstrdup(diskURL);
02778         diskPath = strrchr(diskPath, '/');
02779         if (diskPath)
02780             diskPath++;
02781         else
02782             diskPath = diskURL;
02783 
02784         flp->fileURL = xstrdup(diskPath);
02785         flp->verifyFlags = RPMVERIFY_ALL;
02786 
02787         if (Stat(diskURL, &flp->fl_st)) {
02788             rpmlog(RPMLOG_ERR, _("Bad file: %s: %s\n"),
02789                 diskURL, strerror(errno));
02790             rc = fl.processingFailed = 1;
02791         }
02792 
02793 #if defined(RPM_VENDOR_OPENPKG) /* support-srcdefattr */
02794         /* srcdefattr: allow to set SRPM file attributes via %{_srcdefattr} macro */
02795         if (fl.def_ar.ar_fmodestr) {
02796             flp->fl_mode &= S_IFMT;
02797             flp->fl_mode |= fl.def_ar.ar_fmode;
02798         }
02799         flp->uname = fl.def_ar.ar_user  ? getUnameS(fl.def_ar.ar_user)  : getUname(flp->fl_uid);
02800         flp->gname = fl.def_ar.ar_group ? getGnameS(fl.def_ar.ar_group) : getGname(flp->fl_gid);
02801 #else
02802         flp->uname = getUname(flp->fl_uid);
02803         flp->gname = getGname(flp->fl_gid);
02804 #endif
02805         flp->langs = xstrdup("");
02806         
02807         if (! (flp->uname && flp->gname)) {
02808             rpmlog(RPMLOG_ERR, _("Bad owner/group: %s\n"), diskURL);
02809             rc = fl.processingFailed = 1;
02810         }
02811 
02812         isSpec = 0;
02813         x++;
02814     }
02815     fl.fileListRecsUsed = x;
02816     files = argvFree(files);
02817 
02818     if (rc)
02819         goto exit;
02820 
02821     /* XXX should tags be added if filelist is empty? */
02822     spec->fi = NULL;
02823     genCpioListAndHeader(&fl, &spec->fi, spec->sourceHeader, 1);
02824 
02825 exit:
02826     *sfp = rpmiobFree(*sfp);
02827     fl.fileList = freeFileList(fl.fileList, fl.fileListRecsUsed);
02828     _srcdefattr = _free(_srcdefattr);
02829     return rc;
02830 }
02831 
02837 static int checkUnpackagedFiles(Spec spec)
02838         /*@globals rpmGlobalMacroContext, h_errno, fileSystem, internalState @*/
02839         /*@modifies *spec->packages,
02840                 rpmGlobalMacroContext, fileSystem, internalState @*/
02841 {
02842 /*@-readonlytrans@*/
02843     static const char * av_ckfile[] = { "%{?__check_files}", NULL };
02844 /*@=readonlytrans@*/
02845     rpmiob iob_stdout = NULL;
02846     const char * s;
02847     int rc;
02848     rpmiob fileList = NULL;
02849     Package pkg;
02850     int n = 0;
02851     
02852     s = rpmExpand(av_ckfile[0], NULL);
02853     if (!(s && *s)) {
02854         rc = -1;
02855         goto exit;
02856     }
02857     rc = 0;
02858 
02859     /* initialize fileList */
02860     fileList = rpmiobNew(0);
02861     for (pkg = spec->packages; pkg != NULL; pkg = pkg->next) {
02862         int i;
02863 #ifndef DYING   /* XXX rpmfiNew is necessary here. why?!? */
02864         rpmfi fi = rpmfiNew(NULL, pkg->header, RPMTAG_BASENAMES, 0);
02865 #else
02866         rpmfi fi = rpmfiLink(pkg->fi, __FUNCTION__);
02867 #endif
02868         fi = rpmfiInit(fi, 0);
02869         while ((i = rpmfiNext(fi)) >= 0) {
02870             const char *fn = rpmfiFN(fi);
02871             fileList = rpmiobAppend(fileList, fn, 1);
02872             n++;
02873         }
02874         fi = rpmfiFree(fi);
02875     }
02876 
02877     if (n == 0) {
02878         /* no packaged files, and buildroot may not exist -
02879          * no need to run check */
02880         rc = -1;
02881         goto exit;
02882     }
02883 
02884     rpmlog(RPMLOG_NOTICE, _("Checking for unpackaged file(s): %s\n"), s);
02885 
02886     rc = rpmfcExec(av_ckfile, fileList, &iob_stdout, 0);
02887     if (rc < 0)
02888         goto exit;
02889     
02890     if (iob_stdout) {
02891         int _unpackaged_files_terminate_build =
02892                 rpmExpandNumeric("%{?_unpackaged_files_terminate_build}");
02893         const char * t;
02894 
02895         t = rpmiobStr(iob_stdout);
02896         if ((*t != '\0') && (*t != '\n')) {
02897             rc = (_unpackaged_files_terminate_build) ? 1 : 0;
02898             rpmlog((rc ? RPMLOG_ERR : RPMLOG_WARNING),
02899                 _("Installed (but unpackaged) file(s) found:\n%s"), t);
02900         }
02901     }
02902     
02903 exit:
02904     fileList = rpmiobFree(fileList);
02905     iob_stdout = rpmiobFree(iob_stdout);
02906     s = _free(s);
02907     return rc;
02908 }
02909 
02910 /* auxiliary function for checkDuplicateFiles() */
02911 /* XXX need to pass Header because fi->h is NULL */
02912 static int fiIntersect(/*@null@*/ rpmfi fi1, /*@null@*/ rpmfi fi2)
02913         /*@globals internalState @*/
02914         /*@modifies fi1, fi2, internalState @*/
02915 {
02916     int n = 0;
02917     int i1, i2;
02918     const char *fn1, *fn2;
02919     rpmiob dups = NULL;
02920 
02921     if ((fi1 = rpmfiInit(fi1, 0)) != NULL)
02922     while ((i1 = rpmfiNext(fi1)) >= 0) {
02923         if (S_ISDIR(rpmfiFMode(fi1)))
02924             continue;
02925         fn1 = rpmfiFN(fi1);
02926         if ((fi2 = rpmfiInit(fi2, 0)) != NULL)
02927         while ((i2 = rpmfiNext(fi2)) >= 0) {
02928             if (S_ISDIR(rpmfiFMode(fi2)))
02929                 /*@innercontinue@*/ continue;
02930             fn2 = rpmfiFN(fi2);
02931             if (strcmp(fn1, fn2))
02932                 /*@innercontinue@*/ continue;
02933             if (!dups)
02934                 dups = rpmiobNew(0);
02935             dups = rpmiobAppend(dups, "\t", 0);
02936             dups = rpmiobAppend(dups, fn1, 1);
02937             n++;
02938         }
02939     }
02940 
02941     if (n > 0) {
02942         const char *N1, *N2;
02943         HE_t he = memset(alloca(sizeof(*he)), 0, sizeof(*he));
02944 
02945         he->tag = RPMTAG_NVRA;
02946         N1 = (headerGet(fi1->h, he, 0) ? he->p.str : NULL);
02947         he->tag = RPMTAG_NVRA;
02948         N2 = (headerGet(fi2->h, he, 0) ? he->p.str : NULL);
02949 
02950         rpmlog(RPMLOG_WARNING,
02951                _("File(s) packaged into both %s and %s:\n%s"),
02952                N1, N2, rpmiobStr(dups));
02953 
02954         N1 = _free(N1);
02955         N2 = _free(N2);
02956         dups = rpmiobFree(dups);
02957     }
02958 
02959     return n;
02960 }
02961 
02967 static int checkDuplicateFiles(Spec spec)
02968         /*@globals rpmGlobalMacroContext, h_errno, fileSystem, internalState @*/
02969         /*@modifies *spec->packages,
02970                 rpmGlobalMacroContext, fileSystem, internalState @*/
02971 {
02972     int n = 0;
02973     Package pkg1, pkg2;
02974 
02975     if (spec->packages) /* XXX segfault avoidance */
02976     for (pkg1 = spec->packages; pkg1->next; pkg1 = pkg1->next) {
02977 #ifdef  DYING
02978         rpmfi fi1 = rpmfiNew(NULL, pkg1->header, RPMTAG_BASENAMES, 0);
02979 #else
02980         rpmfi fi1 = rpmfiLink(pkg1->fi, __FUNCTION__);
02981 #endif
02982         if (fi1 == NULL) continue;
02983         (void) rpmfiSetHeader(fi1, pkg1->header);
02984         for (pkg2 = pkg1->next; pkg2; pkg2 = pkg2->next) {
02985 #ifdef  DYING
02986             rpmfi fi2 = rpmfiNew(NULL, pkg2->header, RPMTAG_BASENAMES, 0);
02987 #else
02988             rpmfi fi2 = rpmfiLink(pkg2->fi, __FUNCTION__);
02989 #endif
02990             if (fi2 == NULL) continue;
02991             (void) rpmfiSetHeader(fi2, pkg2->header);
02992             n += fiIntersect(fi1, fi2);
02993             (void) rpmfiSetHeader(fi2, NULL);
02994             fi2 = rpmfiFree(fi2);
02995         }
02996         (void) rpmfiSetHeader(fi1, NULL);
02997         fi1 = rpmfiFree(fi1);
02998     }
02999     return n;
03000 }
03001 
03002 /* auxiliary function: check if directory d is packaged */
03003 static inline int packagedDir(Package pkg, const char *d)
03004         /*@globals rpmGlobalMacroContext, h_errno, fileSystem, internalState @*/
03005         /*@modifies pkg->header,
03006                 rpmGlobalMacroContext, fileSystem, internalState @*/
03007 {
03008     return rpmbfChk(rpmfiFNBF(pkg->fi), d, strlen(d));
03009 }
03010 
03011 /* auxiliary function: find unpackaged subdirectories
03012  *
03013  * E.g. consider this %files section:
03014  *       %dir /A
03015  *       /A/B/C/D
03016  * Now directories "/A/B" and "/A/B/C" should also be packaged.
03017  */
03018 static int pkgUnpackagedSubdirs(Package pkg)
03019         /*@globals rpmGlobalMacroContext, h_errno, fileSystem, internalState @*/
03020         /*@modifies pkg->header,
03021                 rpmGlobalMacroContext, fileSystem, internalState @*/
03022 {
03023     int n = 0;
03024     int i, j;
03025     char **unpackaged = NULL;
03026     char *fn;
03027 #ifdef  DYING
03028     rpmfi fi = rpmfiNew(NULL, pkg->header, RPMTAG_BASENAMES, 0);
03029 #else
03030     rpmfi fi = rpmfiLink(pkg->fi, __FUNCTION__);
03031 #endif
03032 
03033     if (rpmfiFC(fi) <= 1) {
03034         fi = rpmfiFree(fi);
03035         return 0;
03036     }
03037     fn = alloca(rpmfiFNMaxLen(fi) + 1);
03038 
03039     fi = rpmfiInit(fi, 0);
03040     while ((i = rpmfiNext(fi)) >= 0) {
03041         int found = 0;
03042         /* make local copy of file name */
03043         char *p = fn;
03044         strcpy(fn, rpmfiFN(fi));
03045         /* find the first path component that is packaged */
03046         while ((p = strchr(p + 1, '/'))) {
03047             *p = '\0';
03048             found = packagedDir(pkg, fn);
03049             *p = '/';
03050             if (found)
03051                 /*@innerbreak@*/ break;
03052         }
03053         if (!found)
03054             continue;
03055         /* other path components should be packaged, too */
03056         if (p != NULL)
03057         while ((p = strchr(p + 1, '/'))) {
03058             *p = '\0';
03059             if (packagedDir(pkg, fn)) {
03060                 *p = '/';
03061                 /*@innercontinue@*/ continue;
03062             }
03063             /* might be already added */
03064             found = 0;
03065             for (j = 0; j < n; j++)
03066                 if (strcmp(fn, unpackaged[j]) == 0) {
03067                     found = 1;
03068                     /*@innerbreak@*/ break;
03069                 }
03070             if (found) {
03071                 *p = '/';
03072                 /*@innercontinue@*/ continue;
03073             }
03074             unpackaged = xrealloc(unpackaged, sizeof(*unpackaged) * (n + 1));
03075             unpackaged[n++] = xstrdup(fn);
03076             *p = '/';
03077         }
03078     }
03079     fi = rpmfiFree(fi);
03080 
03081     if (n > 0) {
03082         const char *N;
03083         HE_t he = memset(alloca(sizeof(*he)), 0, sizeof(*he));
03084         rpmiob list = rpmiobNew(0);
03085 
03086         he->tag = RPMTAG_NVRA;
03087         N = (headerGet(pkg->header, he, 0) ? he->p.str : NULL);
03088 
03089         for (i = 0; i < n; i++) {
03090             list = rpmiobAppend(list, "\t", 0);
03091             list = rpmiobAppend(list, unpackaged[i], 1);
03092             unpackaged[i] = _free(unpackaged[i]);
03093         }
03094         unpackaged = _free(unpackaged);
03095 
03096         rpmlog(RPMLOG_WARNING,
03097                _("Unpackaged subdir(s) in %s:\n%s"),
03098                N, rpmiobStr(list));
03099 
03100         N = _free(N);
03101         list = rpmiobFree(list);
03102     }   
03103 
03104     return n;
03105 }
03106 
03112 static int checkUnpackagedSubdirs(Spec spec)
03113         /*@globals rpmGlobalMacroContext, h_errno, fileSystem, internalState @*/
03114         /*@modifies *spec->packages,
03115                 rpmGlobalMacroContext, fileSystem, internalState @*/
03116 {
03117     int n = 0;
03118     Package pkg;
03119 
03120     for (pkg = spec->packages; pkg; pkg = pkg->next)
03121         n += pkgUnpackagedSubdirs(pkg);
03122     return n;
03123 }
03124 
03125 /*@-incondefs@*/
03126 rpmRC processBinaryFiles(Spec spec, int installSpecialDoc, int test)
03127 {
03128     HE_t he = memset(alloca(sizeof(*he)), 0, sizeof(*he));
03129     Package pkg;
03130     rpmRC res = RPMRC_OK;
03131     
03132     for (pkg = spec->packages; pkg != NULL; pkg = pkg->next) {
03133         int rc;
03134 
03135         if (pkg->fileList == NULL)
03136             continue;
03137 
03138         (void) headerMacrosLoad(pkg->header);
03139 
03140         he->tag = RPMTAG_NVRA;
03141         rc = headerGet(pkg->header, he, 0);
03142         rpmlog(RPMLOG_NOTICE, _("Processing files: %s\n"), he->p.str);
03143         he->p.ptr = _free(he->p.ptr);
03144                    
03145         if ((rc = processPackageFiles(spec, pkg, installSpecialDoc, test))) {
03146             res = RPMRC_FAIL;
03147             (void) headerMacrosUnload(pkg->header);
03148             break;
03149         }
03150 
03151         /* Finalize package scriptlets before extracting dependencies. */
03152         if ((rc = processScriptFiles(spec, pkg))) {
03153             res = rc;
03154             (void) headerMacrosUnload(pkg->header);
03155             break;
03156         }
03157 
03158         if ((rc = rpmfcGenerateDepends(spec, pkg))) {
03159             res = RPMRC_FAIL;
03160             (void) headerMacrosUnload(pkg->header);
03161             break;
03162         }
03163 
03164         /* XXX this should be earlier for deps to be entirely sorted. */
03165         providePackageNVR(pkg->header);
03166 
03167         (void) headerMacrosUnload(pkg->header);
03168     }
03169 
03170     if (res == RPMRC_OK) {
03171         if (checkUnpackagedFiles(spec) > 0)
03172             res = RPMRC_FAIL;
03173         (void) checkDuplicateFiles(spec);
03174         (void) checkUnpackagedSubdirs(spec);
03175     }
03176     
03177     return res;
03178 }
03179 /*@=incondefs@*/