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

Generated on Mon Nov 29 2010 05:18:41 for rpm by  doxygen 1.7.2