rpm 5.2.1

- Main Page
- Related Pages
- Modules
- Data Structures
- Files

- File List
- Globals

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@*/