rpm 5.2.1

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