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

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