build/files.c

Go to the documentation of this file.
00001 
00007 #include "system.h"
00008 
00009 #define MYALLPERMS      07777
00010 
00011 #include <regex.h>
00012 
00013 #include <rpmio_internal.h>
00014 #include <fts.h>
00015 
00016 #include <rpmbuild.h>
00017 
00018 #include "cpio.h"
00019 
00020 #include "argv.h"
00021 #include "rpmfc.h"
00022 
00023 #define _RPMFI_INTERNAL
00024 #include "rpmfi.h"
00025 
00026 #include "rpmsx.h"
00027 
00028 #define _RPMTE_INTERNAL
00029 #include "rpmte.h"
00030 
00031 #include "buildio.h"
00032 
00033 #include "legacy.h"     /* XXX domd5, expandFileList, compressFileList */
00034 #include "misc.h"
00035 #include "debug.h"
00036 
00037 /*@access Header @*/
00038 /*@access rpmfi @*/
00039 /*@access rpmte @*/
00040 /*@access FD_t @*/
00041 /*@access StringBuf @*/         /* compared with NULL */
00042 
00043 #define SKIPWHITE(_x)   {while(*(_x) && (xisspace(*_x) || *(_x) == ',')) (_x)++;}
00044 #define SKIPNONWHITE(_x){while(*(_x) &&!(xisspace(*_x) || *(_x) == ',')) (_x)++;}
00045 
00046 #define MAXDOCDIR 1024
00047 
00050 typedef enum specdFlags_e {
00051     SPECD_DEFFILEMODE   = (1 << 0),
00052     SPECD_DEFDIRMODE    = (1 << 1),
00053     SPECD_DEFUID        = (1 << 2),
00054     SPECD_DEFGID        = (1 << 3),
00055     SPECD_DEFVERIFY     = (1 << 4),
00056 
00057     SPECD_FILEMODE      = (1 << 8),
00058     SPECD_DIRMODE       = (1 << 9),
00059     SPECD_UID           = (1 << 10),
00060     SPECD_GID           = (1 << 11),
00061     SPECD_VERIFY        = (1 << 12)
00062 } specdFlags;
00063 
00066 typedef struct FileListRec_s {
00067     struct stat fl_st;
00068 #define fl_dev  fl_st.st_dev
00069 #define fl_ino  fl_st.st_ino
00070 #define fl_mode fl_st.st_mode
00071 #define fl_nlink fl_st.st_nlink
00072 #define fl_uid  fl_st.st_uid
00073 #define fl_gid  fl_st.st_gid
00074 #define fl_rdev fl_st.st_rdev
00075 #define fl_size fl_st.st_size
00076 #define fl_mtime fl_st.st_mtime
00077 
00078 /*@only@*/
00079     const char *diskURL;        /* get file from here       */
00080 /*@only@*/
00081     const char *fileURL;        /* filename in cpio archive */
00082 /*@observer@*/
00083     const char *uname;
00084 /*@observer@*/
00085     const char *gname;
00086     unsigned    flags;
00087     specdFlags  specdFlags;     /* which attributes have been explicitly specified. */
00088     unsigned    verifyFlags;
00089 /*@only@*/
00090     const char *langs;          /* XXX locales separated with | */
00091 } * FileListRec;
00092 
00095 typedef struct AttrRec_s {
00096 /*@null@*/
00097     const char *ar_fmodestr;
00098 /*@null@*/
00099     const char *ar_dmodestr;
00100 /*@null@*/
00101     const char *ar_user;
00102 /*@null@*/
00103     const char *ar_group;
00104     mode_t      ar_fmode;
00105     mode_t      ar_dmode;
00106 } * AttrRec;
00107 
00108 /*@-readonlytrans@*/
00109 /*@unchecked@*/ /*@observer@*/
00110 static struct AttrRec_s root_ar = { NULL, NULL, "root", "root", 0, 0 };
00111 /*@=readonlytrans@*/
00112 
00113 /* list of files */
00114 /*@unchecked@*/ /*@only@*/ /*@null@*/
00115 static StringBuf check_fileList = NULL;
00116 
00120 typedef struct FileList_s {
00121 /*@only@*/
00122     const char * buildRootURL;
00123 /*@only@*/
00124     const char * prefix;
00125 
00126     int fileCount;
00127     int totalFileSize;
00128     int processingFailed;
00129 
00130     int passedSpecialDoc;
00131     int isSpecialDoc;
00132 
00133     int noGlob;
00134     unsigned devtype;
00135     unsigned devmajor;
00136     int devminor;
00137     
00138     int isDir;
00139     int inFtw;
00140     int currentFlags;
00141     specdFlags currentSpecdFlags;
00142     int currentVerifyFlags;
00143     struct AttrRec_s cur_ar;
00144     struct AttrRec_s def_ar;
00145     specdFlags defSpecdFlags;
00146     int defVerifyFlags;
00147     int nLangs;
00148 /*@only@*/ /*@null@*/
00149     const char ** currentLangs;
00150 
00151     /* Hard coded limit of MAXDOCDIR docdirs.         */
00152     /* If you break it you are doing something wrong. */
00153     const char * docDirs[MAXDOCDIR];
00154     int docDirCount;
00155     
00156 /*@only@*/
00157     FileListRec fileList;
00158     int fileListRecsAlloced;
00159     int fileListRecsUsed;
00160 } * FileList;
00161 
00164 static void nullAttrRec(/*@out@*/ AttrRec ar)   /*@modifies ar @*/
00165 {
00166     ar->ar_fmodestr = NULL;
00167     ar->ar_dmodestr = NULL;
00168     ar->ar_user = NULL;
00169     ar->ar_group = NULL;
00170     ar->ar_fmode = 0;
00171     ar->ar_dmode = 0;
00172 }
00173 
00176 static void freeAttrRec(AttrRec ar)     /*@modifies ar @*/
00177 {
00178     ar->ar_fmodestr = _free(ar->ar_fmodestr);
00179     ar->ar_dmodestr = _free(ar->ar_dmodestr);
00180     ar->ar_user = _free(ar->ar_user);
00181     ar->ar_group = _free(ar->ar_group);
00182     /* XXX doesn't free ar (yet) */
00183     /*@-nullstate@*/
00184     return;
00185     /*@=nullstate@*/
00186 }
00187 
00190 static void dupAttrRec(const AttrRec oar, /*@in@*/ /*@out@*/ AttrRec nar)
00191         /*@modifies nar @*/
00192 {
00193     if (oar == nar)
00194         return;
00195     freeAttrRec(nar);
00196     nar->ar_fmodestr = (oar->ar_fmodestr ? xstrdup(oar->ar_fmodestr) : NULL);
00197     nar->ar_dmodestr = (oar->ar_dmodestr ? xstrdup(oar->ar_dmodestr) : NULL);
00198     nar->ar_user = (oar->ar_user ? xstrdup(oar->ar_user) : NULL);
00199     nar->ar_group = (oar->ar_group ? xstrdup(oar->ar_group) : NULL);
00200     nar->ar_fmode = oar->ar_fmode;
00201     nar->ar_dmode = oar->ar_dmode;
00202 }
00203 
00204 #if 0
00205 
00207 static void dumpAttrRec(const char * msg, AttrRec ar)
00208         /*@globals fileSystem@*/
00209         /*@modifies fileSystem @*/
00210 {
00211     if (msg)
00212         fprintf(stderr, "%s:\t", msg);
00213     fprintf(stderr, "(%s, %s, %s, %s)\n",
00214         ar->ar_fmodestr,
00215         ar->ar_user,
00216         ar->ar_group,
00217         ar->ar_dmodestr);
00218 }
00219 #endif
00220 
00225 /*@-boundswrite@*/
00226 /*@null@*/
00227 static char *strtokWithQuotes(/*@null@*/ char *s, char *delim)
00228         /*@modifies *s @*/
00229 {
00230     static char *olds = NULL;
00231     char *token;
00232 
00233     if (s == NULL)
00234         s = olds;
00235     if (s == NULL)
00236         return NULL;
00237 
00238     /* Skip leading delimiters */
00239     s += strspn(s, delim);
00240     if (*s == '\0')
00241         return NULL;
00242 
00243     /* Find the end of the token.  */
00244     token = s;
00245     if (*token == '"') {
00246         token++;
00247         /* Find next " char */
00248         s = strchr(token, '"');
00249     } else {
00250         s = strpbrk(token, delim);
00251     }
00252 
00253     /* Terminate it */
00254     if (s == NULL) {
00255         /* This token finishes the string */
00256         olds = strchr(token, '\0');
00257     } else {
00258         /* Terminate the token and make olds point past it */
00259         *s = '\0';
00260         olds = s+1;
00261     }
00262 
00263     /*@-retalias -temptrans @*/
00264     return token;
00265     /*@=retalias =temptrans @*/
00266 }
00267 /*@=boundswrite@*/
00268 
00271 static void timeCheck(int tc, Header h)
00272         /*@globals internalState @*/
00273         /*@modifies internalState @*/
00274 {
00275     HGE_t hge = (HGE_t)headerGetEntryMinMemory;
00276     HFD_t hfd = headerFreeData;
00277     int * mtime;
00278     const char ** files;
00279     rpmTagType fnt;
00280     int count, x;
00281     time_t currentTime = time(NULL);
00282 
00283     x = hge(h, RPMTAG_OLDFILENAMES, &fnt, (void **) &files, &count);
00284     x = hge(h, RPMTAG_FILEMTIMES, NULL, (void **) &mtime, NULL);
00285     
00286 /*@-boundsread@*/
00287     for (x = 0; x < count; x++) {
00288         if ((currentTime - mtime[x]) > tc)
00289             rpmMessage(RPMMESS_WARNING, _("TIMECHECK failure: %s\n"), files[x]);
00290     }
00291     files = hfd(files, fnt);
00292 /*@=boundsread@*/
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 /*@-boundswrite@*/
00327 static int parseForVerify(char * buf, FileList fl)
00328         /*@modifies buf, fl->processingFailed,
00329                 fl->currentVerifyFlags, fl->defVerifyFlags,
00330                 fl->currentSpecdFlags, fl->defSpecdFlags @*/
00331 {
00332     char *p, *pe, *q;
00333     const char *name;
00334     int *resultVerify;
00335     int negated;
00336     int verifyFlags;
00337     specdFlags * specdFlags;
00338 
00339     if ((p = strstr(buf, (name = "%verify"))) != NULL) {
00340         resultVerify = &(fl->currentVerifyFlags);
00341         specdFlags = &fl->currentSpecdFlags;
00342     } else if ((p = strstr(buf, (name = "%defverify"))) != NULL) {
00343         resultVerify = &(fl->defVerifyFlags);
00344         specdFlags = &fl->defSpecdFlags;
00345     } else
00346         return 0;
00347 
00348     for (pe = p; (pe-p) < strlen(name); pe++)
00349         *pe = ' ';
00350 
00351     SKIPSPACE(pe);
00352 
00353     if (*pe != '(') {
00354         rpmError(RPMERR_BADSPEC, _("Missing '(' in %s %s\n"), name, pe);
00355         fl->processingFailed = 1;
00356         return RPMERR_BADSPEC;
00357     }
00358 
00359     /* Bracket %*verify args */
00360     *pe++ = ' ';
00361     for (p = pe; *pe && *pe != ')'; pe++)
00362         {};
00363 
00364     if (*pe == '\0') {
00365         rpmError(RPMERR_BADSPEC, _("Missing ')' in %s(%s\n"), name, p);
00366         fl->processingFailed = 1;
00367         return RPMERR_BADSPEC;
00368     }
00369 
00370     /* Localize. Erase parsed string */
00371     q = alloca((pe-p) + 1);
00372     strncpy(q, p, pe-p);
00373     q[pe-p] = '\0';
00374     while (p <= pe)
00375         *p++ = ' ';
00376 
00377     negated = 0;
00378     verifyFlags = RPMVERIFY_NONE;
00379 
00380     for (p = q; *p != '\0'; p = pe) {
00381         SKIPWHITE(p);
00382         if (*p == '\0')
00383             break;
00384         pe = p;
00385         SKIPNONWHITE(pe);
00386         if (*pe != '\0')
00387             *pe++ = '\0';
00388 
00389         {   VFA_t *vfa;
00390             for (vfa = verifyAttrs; vfa->attribute != NULL; vfa++) {
00391                 if (strcmp(p, vfa->attribute))
00392                     /*@innercontinue@*/ continue;
00393                 verifyFlags |= vfa->flag;
00394                 /*@innerbreak@*/ break;
00395             }
00396             if (vfa->attribute)
00397                 continue;
00398         }
00399 
00400         if (!strcmp(p, "not")) {
00401             negated ^= 1;
00402         } else {
00403             rpmError(RPMERR_BADSPEC, _("Invalid %s token: %s\n"), name, p);
00404             fl->processingFailed = 1;
00405             return RPMERR_BADSPEC;
00406         }
00407     }
00408 
00409     *resultVerify = negated ? ~(verifyFlags) : verifyFlags;
00410     *specdFlags |= SPECD_VERIFY;
00411 
00412     return 0;
00413 }
00414 /*@=boundswrite@*/
00415 
00416 #define isAttrDefault(_ars)     ((_ars)[0] == '-' && (_ars)[1] == '\0')
00417 
00424 /*@-boundswrite@*/
00425 static int parseForDev(char * buf, FileList fl)
00426         /*@modifies buf, fl->processingFailed,
00427                 fl->noGlob, fl->devtype, fl->devmajor, fl->devminor @*/
00428 {
00429     const char * name;
00430     const char * errstr = NULL;
00431     char *p, *pe, *q;
00432     int rc = RPMERR_BADSPEC;    /* assume error */
00433 
00434     if ((p = strstr(buf, (name = "%dev"))) == NULL)
00435         return 0;
00436 
00437     for (pe = p; (pe-p) < strlen(name); pe++)
00438         *pe = ' ';
00439     SKIPSPACE(pe);
00440 
00441     if (*pe != '(') {
00442         errstr = "'('";
00443         goto exit;
00444     }
00445 
00446     /* Bracket %dev args */
00447     *pe++ = ' ';
00448     for (p = pe; *pe && *pe != ')'; pe++)
00449         {};
00450     if (*pe != ')') {
00451         errstr = "')'";
00452         goto exit;
00453     }
00454 
00455     /* Localize. Erase parsed string */
00456     q = alloca((pe-p) + 1);
00457     strncpy(q, p, pe-p);
00458     q[pe-p] = '\0';
00459     while (p <= pe)
00460         *p++ = ' ';
00461 
00462     p = q; SKIPWHITE(p);
00463     pe = p; SKIPNONWHITE(pe); if (*pe != '\0') *pe++ = '\0';
00464     if (*p == 'b')
00465         fl->devtype = 'b';
00466     else if (*p == 'c')
00467         fl->devtype = 'c';
00468     else {
00469         errstr = "devtype";
00470         goto exit;
00471     }
00472 
00473     p = pe; SKIPWHITE(p);
00474     pe = p; SKIPNONWHITE(pe); if (*pe != '\0') *pe++ = '\0';
00475     for (pe = p; *pe && xisdigit(*pe); pe++)
00476         {} ;
00477     if (*pe == '\0') {
00478         fl->devmajor = atoi(p);
00479         /*@-unsignedcompare @*/ /* LCL: ge is ok */
00480         if (!(fl->devmajor >= 0 && fl->devmajor < 256)) {
00481             errstr = "devmajor";
00482             goto exit;
00483         }
00484         /*@=unsignedcompare @*/
00485         pe++;
00486     } else {
00487         errstr = "devmajor";
00488         goto exit;
00489     }
00490 
00491     p = pe; SKIPWHITE(p);
00492     pe = p; SKIPNONWHITE(pe); if (*pe != '\0') *pe++ = '\0';
00493     for (pe = p; *pe && xisdigit(*pe); pe++)
00494         {} ;
00495     if (*pe == '\0') {
00496         fl->devminor = atoi(p);
00497         if (!(fl->devminor >= 0 && fl->devminor < 256)) {
00498             errstr = "devminor";
00499             goto exit;
00500         }
00501         pe++;
00502     } else {
00503         errstr = "devminor";
00504         goto exit;
00505     }
00506 
00507     fl->noGlob = 1;
00508 
00509     rc = 0;
00510 
00511 exit:
00512     if (rc) {
00513         rpmError(RPMERR_BADSPEC, _("Missing %s in %s %s\n"), errstr, name, p);
00514         fl->processingFailed = 1;
00515     }
00516     return rc;
00517 }
00518 /*@=boundswrite@*/
00519 
00526 /*@-boundswrite@*/
00527 static int parseForAttr(char * buf, FileList fl)
00528         /*@modifies buf, fl->processingFailed,
00529                 fl->cur_ar, fl->def_ar,
00530                 fl->currentSpecdFlags, fl->defSpecdFlags @*/
00531 {
00532     const char *name;
00533     char *p, *pe, *q;
00534     int x;
00535     struct AttrRec_s arbuf;
00536     AttrRec ar = &arbuf, ret_ar;
00537     specdFlags * specdFlags;
00538 
00539     if ((p = strstr(buf, (name = "%attr"))) != NULL) {
00540         ret_ar = &(fl->cur_ar);
00541         specdFlags = &fl->currentSpecdFlags;
00542     } else if ((p = strstr(buf, (name = "%defattr"))) != NULL) {
00543         ret_ar = &(fl->def_ar);
00544         specdFlags = &fl->defSpecdFlags;
00545     } else
00546         return 0;
00547 
00548     for (pe = p; (pe-p) < strlen(name); pe++)
00549         *pe = ' ';
00550 
00551     SKIPSPACE(pe);
00552 
00553     if (*pe != '(') {
00554         rpmError(RPMERR_BADSPEC, _("Missing '(' in %s %s\n"), name, pe);
00555         fl->processingFailed = 1;
00556         return RPMERR_BADSPEC;
00557     }
00558 
00559     /* Bracket %*attr args */
00560     *pe++ = ' ';
00561     for (p = pe; *pe && *pe != ')'; pe++)
00562         {};
00563 
00564     if (ret_ar == &(fl->def_ar)) {      /* %defattr */
00565         q = pe;
00566         q++;
00567         SKIPSPACE(q);
00568         if (*q != '\0') {
00569             rpmError(RPMERR_BADSPEC,
00570                      _("Non-white space follows %s(): %s\n"), name, q);
00571             fl->processingFailed = 1;
00572             return RPMERR_BADSPEC;
00573         }
00574     }
00575 
00576     /* Localize. Erase parsed string */
00577     q = alloca((pe-p) + 1);
00578     strncpy(q, p, pe-p);
00579     q[pe-p] = '\0';
00580     while (p <= pe)
00581         *p++ = ' ';
00582 
00583     nullAttrRec(ar);
00584 
00585     p = q; SKIPWHITE(p);
00586     if (*p != '\0') {
00587         pe = p; SKIPNONWHITE(pe); if (*pe != '\0') *pe++ = '\0';
00588         ar->ar_fmodestr = p;
00589         p = pe; SKIPWHITE(p);
00590     }
00591     if (*p != '\0') {
00592         pe = p; SKIPNONWHITE(pe); if (*pe != '\0') *pe++ = '\0';
00593         ar->ar_user = p;
00594         p = pe; SKIPWHITE(p);
00595     }
00596     if (*p != '\0') {
00597         pe = p; SKIPNONWHITE(pe); if (*pe != '\0') *pe++ = '\0';
00598         ar->ar_group = p;
00599         p = pe; SKIPWHITE(p);
00600     }
00601     if (*p != '\0' && ret_ar == &(fl->def_ar)) {        /* %defattr */
00602         pe = p; SKIPNONWHITE(pe); if (*pe != '\0') *pe++ = '\0';
00603         ar->ar_dmodestr = p;
00604         p = pe; SKIPWHITE(p);
00605     }
00606 
00607     if (!(ar->ar_fmodestr && ar->ar_user && ar->ar_group) || *p != '\0') {
00608         rpmError(RPMERR_BADSPEC, _("Bad syntax: %s(%s)\n"), name, q);
00609         fl->processingFailed = 1;
00610         return RPMERR_BADSPEC;
00611     }
00612 
00613     /* Do a quick test on the mode argument and adjust for "-" */
00614     if (ar->ar_fmodestr && !isAttrDefault(ar->ar_fmodestr)) {
00615         unsigned int ui;
00616         x = sscanf(ar->ar_fmodestr, "%o", &ui);
00617         if ((x == 0) || (ar->ar_fmode & ~MYALLPERMS)) {
00618             rpmError(RPMERR_BADSPEC, _("Bad mode spec: %s(%s)\n"), name, q);
00619             fl->processingFailed = 1;
00620             return RPMERR_BADSPEC;
00621         }
00622         ar->ar_fmode = ui;
00623     } else
00624         ar->ar_fmodestr = NULL;
00625 
00626     if (ar->ar_dmodestr && !isAttrDefault(ar->ar_dmodestr)) {
00627         unsigned int ui;
00628         x = sscanf(ar->ar_dmodestr, "%o", &ui);
00629         if ((x == 0) || (ar->ar_dmode & ~MYALLPERMS)) {
00630             rpmError(RPMERR_BADSPEC, _("Bad dirmode spec: %s(%s)\n"), name, q);
00631             fl->processingFailed = 1;
00632             return RPMERR_BADSPEC;
00633         }
00634         ar->ar_dmode = ui;
00635     } else
00636         ar->ar_dmodestr = NULL;
00637 
00638     if (!(ar->ar_user && !isAttrDefault(ar->ar_user)))
00639         ar->ar_user = NULL;
00640 
00641     if (!(ar->ar_group && !isAttrDefault(ar->ar_group)))
00642         ar->ar_group = NULL;
00643 
00644     dupAttrRec(ar, ret_ar);
00645 
00646     /* XXX fix all this */
00647     *specdFlags |= SPECD_UID | SPECD_GID | SPECD_FILEMODE | SPECD_DIRMODE;
00648     
00649     return 0;
00650 }
00651 /*@=boundswrite@*/
00652 
00659 /*@-boundswrite@*/
00660 static int parseForConfig(char * buf, FileList fl)
00661         /*@modifies buf, fl->processingFailed, fl->currentFlags @*/
00662 {
00663     char *p, *pe, *q;
00664     const char *name;
00665 
00666     if ((p = strstr(buf, (name = "%config"))) == NULL)
00667         return 0;
00668 
00669     fl->currentFlags |= RPMFILE_CONFIG;
00670 
00671     /* Erase "%config" token. */
00672     for (pe = p; (pe-p) < strlen(name); pe++)
00673         *pe = ' ';
00674     SKIPSPACE(pe);
00675     if (*pe != '(')
00676         return 0;
00677 
00678     /* Bracket %config args */
00679     *pe++ = ' ';
00680     for (p = pe; *pe && *pe != ')'; pe++)
00681         {};
00682 
00683     if (*pe == '\0') {
00684         rpmError(RPMERR_BADSPEC, _("Missing ')' in %s(%s\n"), name, p);
00685         fl->processingFailed = 1;
00686         return RPMERR_BADSPEC;
00687     }
00688 
00689     /* Localize. Erase parsed string. */
00690     q = alloca((pe-p) + 1);
00691     strncpy(q, p, pe-p);
00692     q[pe-p] = '\0';
00693     while (p <= pe)
00694         *p++ = ' ';
00695 
00696     for (p = q; *p != '\0'; p = pe) {
00697         SKIPWHITE(p);
00698         if (*p == '\0')
00699             break;
00700         pe = p;
00701         SKIPNONWHITE(pe);
00702         if (*pe != '\0')
00703             *pe++ = '\0';
00704         if (!strcmp(p, "missingok")) {
00705             fl->currentFlags |= RPMFILE_MISSINGOK;
00706         } else if (!strcmp(p, "noreplace")) {
00707             fl->currentFlags |= RPMFILE_NOREPLACE;
00708         } else {
00709             rpmError(RPMERR_BADSPEC, _("Invalid %s token: %s\n"), name, p);
00710             fl->processingFailed = 1;
00711             return RPMERR_BADSPEC;
00712         }
00713     }
00714 
00715     return 0;
00716 }
00717 /*@=boundswrite@*/
00718 
00721 static int langCmp(const void * ap, const void * bp)
00722         /*@*/
00723 {
00724 /*@-boundsread@*/
00725     return strcmp(*(const char **)ap, *(const char **)bp);
00726 /*@=boundsread@*/
00727 }
00728 
00735 /*@-bounds@*/
00736 static int parseForLang(char * buf, FileList fl)
00737         /*@modifies buf, fl->processingFailed,
00738                 fl->currentLangs, fl->nLangs @*/
00739 {
00740     char *p, *pe, *q;
00741     const char *name;
00742 
00743   while ((p = strstr(buf, (name = "%lang"))) != NULL) {
00744 
00745     for (pe = p; (pe-p) < strlen(name); pe++)
00746         *pe = ' ';
00747     SKIPSPACE(pe);
00748 
00749     if (*pe != '(') {
00750         rpmError(RPMERR_BADSPEC, _("Missing '(' in %s %s\n"), name, pe);
00751         fl->processingFailed = 1;
00752         return RPMERR_BADSPEC;
00753     }
00754 
00755     /* Bracket %lang args */
00756     *pe++ = ' ';
00757     for (pe = p; *pe && *pe != ')'; pe++)
00758         {};
00759 
00760     if (*pe == '\0') {
00761         rpmError(RPMERR_BADSPEC, _("Missing ')' in %s(%s\n"), name, p);
00762         fl->processingFailed = 1;
00763         return RPMERR_BADSPEC;
00764     }
00765 
00766     /* Localize. Erase parsed string. */
00767     q = alloca((pe-p) + 1);
00768     strncpy(q, p, pe-p);
00769     q[pe-p] = '\0';
00770     while (p <= pe)
00771         *p++ = ' ';
00772 
00773     /* Parse multiple arguments from %lang */
00774     for (p = q; *p != '\0'; p = pe) {
00775         char *newp;
00776         size_t np;
00777         int i;
00778 
00779         SKIPWHITE(p);
00780         pe = p;
00781         SKIPNONWHITE(pe);
00782 
00783         np = pe - p;
00784         
00785         /* Sanity check on locale lengths */
00786         if (np < 1 || (np == 1 && *p != 'C') || np >= 32) {
00787             rpmError(RPMERR_BADSPEC,
00788                 _("Unusual locale length: \"%.*s\" in %%lang(%s)\n"),
00789                 (int)np, p, q);
00790             fl->processingFailed = 1;
00791             return RPMERR_BADSPEC;
00792         }
00793 
00794         /* Check for duplicate locales */
00795         if (fl->currentLangs != NULL)
00796         for (i = 0; i < fl->nLangs; i++) {
00797             if (strncmp(fl->currentLangs[i], p, np))
00798                 /*@innercontinue@*/ continue;
00799             rpmError(RPMERR_BADSPEC, _("Duplicate locale %.*s in %%lang(%s)\n"),
00800                 (int)np, p, q);
00801             fl->processingFailed = 1;
00802             return RPMERR_BADSPEC;
00803         }
00804 
00805         /* Add new locale */
00806         fl->currentLangs = xrealloc(fl->currentLangs,
00807                                 (fl->nLangs + 1) * sizeof(*fl->currentLangs));
00808         newp = xmalloc( np+1 );
00809         strncpy(newp, p, np);
00810         newp[np] = '\0';
00811         fl->currentLangs[fl->nLangs++] = newp;
00812         if (*pe == ',') pe++;   /* skip , if present */
00813     }
00814   }
00815 
00816     /* Insure that locales are sorted. */
00817     if (fl->currentLangs)
00818         qsort(fl->currentLangs, fl->nLangs, sizeof(*fl->currentLangs), langCmp);
00819 
00820     return 0;
00821 }
00822 /*@=bounds@*/
00823 
00826 /*@-boundswrite@*/
00827 static int parseForRegexLang(const char * fileName, /*@out@*/ char ** lang)
00828         /*@globals rpmGlobalMacroContext, h_errno @*/
00829         /*@modifies *lang, rpmGlobalMacroContext @*/
00830 {
00831     static int initialized = 0;
00832     static int hasRegex = 0;
00833     static regex_t compiledPatt;
00834     static char buf[BUFSIZ];
00835     int x;
00836     regmatch_t matches[2];
00837     const char *s;
00838 
00839     if (! initialized) {
00840         const char *patt = rpmExpand("%{?_langpatt}", NULL);
00841         int rc = 0;
00842         if (!(patt && *patt != '\0'))
00843             rc = 1;
00844         else if (regcomp(&compiledPatt, patt, REG_EXTENDED))
00845             rc = -1;
00846         patt = _free(patt);
00847         if (rc)
00848             return rc;
00849         hasRegex = 1;
00850         initialized = 1;
00851     }
00852     
00853     memset(matches, 0, sizeof(matches));
00854     if (! hasRegex || regexec(&compiledPatt, fileName, 2, matches, REG_NOTEOL))
00855         return 1;
00856 
00857     /* Got match */
00858     s = fileName + matches[1].rm_eo - 1;
00859     x = matches[1].rm_eo - matches[1].rm_so;
00860     buf[x] = '\0';
00861     while (x) {
00862         buf[--x] = *s--;
00863     }
00864     if (lang)
00865         *lang = buf;
00866     return 0;
00867 }
00868 /*@=boundswrite@*/
00869 
00872 /*@-exportlocal -exportheadervar@*/
00873 /*@unchecked@*/
00874 VFA_t virtualFileAttributes[] = {
00875         { "%dir",       0,      0 },    /* XXX why not RPMFILE_DIR? */
00876         { "%doc",       0,      RPMFILE_DOC },
00877         { "%ghost",     0,      RPMFILE_GHOST },
00878         { "%exclude",   0,      RPMFILE_EXCLUDE },
00879         { "%readme",    0,      RPMFILE_README },
00880         { "%license",   0,      RPMFILE_LICENSE },
00881         { "%pubkey",    0,      RPMFILE_PUBKEY },
00882         { "%policy",    0,      RPMFILE_POLICY },
00883 
00884 #if WHY_NOT
00885         { "%icon",      0,      RPMFILE_ICON },
00886         { "%spec",      0,      RPMFILE_SPEC },
00887         { "%config",    0,      RPMFILE_CONFIG },
00888         { "%missingok", 0,      RPMFILE_CONFIG|RPMFILE_MISSINGOK },
00889         { "%noreplace", 0,      RPMFILE_CONFIG|RPMFILE_NOREPLACE },
00890 #endif
00891 
00892         { NULL, 0, 0 }
00893 };
00894 /*@=exportlocal =exportheadervar@*/
00895 
00905 /*@-boundswrite@*/
00906 static int parseForSimple(/*@unused@*/Spec spec, Package pkg, char * buf,
00907                           FileList fl, /*@out@*/ const char ** fileName)
00908         /*@globals rpmGlobalMacroContext, h_errno @*/
00909         /*@modifies buf, fl->processingFailed, *fileName,
00910                 fl->currentFlags,
00911                 fl->docDirs, fl->docDirCount, fl->isDir,
00912                 fl->passedSpecialDoc, fl->isSpecialDoc,
00913                 pkg->specialDoc, rpmGlobalMacroContext @*/
00914 {
00915     char *s, *t;
00916     int res, specialDoc = 0;
00917     char specialDocBuf[BUFSIZ];
00918 
00919     specialDocBuf[0] = '\0';
00920     *fileName = NULL;
00921     res = 0;
00922 
00923     t = buf;
00924     while ((s = strtokWithQuotes(t, " \t\n")) != NULL) {
00925         t = NULL;
00926         if (!strcmp(s, "%docdir")) {
00927             s = strtokWithQuotes(NULL, " \t\n");
00928             if (fl->docDirCount == MAXDOCDIR) {
00929                 rpmError(RPMERR_INTERNAL, _("Hit limit for %%docdir\n"));
00930                 fl->processingFailed = 1;
00931                 res = 1;
00932             }
00933         
00934             if (s != NULL)
00935                 fl->docDirs[fl->docDirCount++] = xstrdup(s);
00936             if (s == NULL || strtokWithQuotes(NULL, " \t\n")) {
00937                 rpmError(RPMERR_INTERNAL, _("Only one arg for %%docdir\n"));
00938                 fl->processingFailed = 1;
00939                 res = 1;
00940             }
00941             break;
00942         }
00943 #if defined(__LCLINT__)
00944         assert(s != NULL);
00945 #endif
00946 
00947     /* Set flags for virtual file attributes */
00948     {   VFA_t *vfa;
00949         for (vfa = virtualFileAttributes; vfa->attribute != NULL; vfa++) {
00950             if (strcmp(s, vfa->attribute))
00951                 /*@innercontinue@*/ continue;
00952             if (!vfa->flag) {
00953                 if (!strcmp(s, "%dir"))
00954                     fl->isDir = 1;      /* XXX why not RPMFILE_DIR? */
00955             } else {
00956                 if (vfa->not)
00957                     fl->currentFlags &= ~vfa->flag;
00958                 else
00959                     fl->currentFlags |= vfa->flag;
00960             }
00961 
00962             /*@innerbreak@*/ break;
00963         }
00964         /* if we got an attribute, continue with next token */
00965         if (vfa->attribute != NULL)
00966             continue;
00967     }
00968 
00969         if (*fileName) {
00970             /* We already got a file -- error */
00971             rpmError(RPMERR_BADSPEC, _("Two files on one line: %s\n"),
00972                 *fileName);
00973             fl->processingFailed = 1;
00974             res = 1;
00975         }
00976 
00977         /*@-branchstate@*/
00978         if (*s != '/') {
00979             if (fl->currentFlags & RPMFILE_DOC) {
00980                 specialDoc = 1;
00981                 strcat(specialDocBuf, " ");
00982                 strcat(specialDocBuf, s);
00983             } else
00984             if (fl->currentFlags & (RPMFILE_POLICY|RPMFILE_PUBKEY|RPMFILE_ICON))
00985             {
00986                 *fileName = s;
00987             } else {
00988                 /* not in %doc, does not begin with / -- error */
00989                 rpmError(RPMERR_BADSPEC,
00990                     _("File must begin with \"/\": %s\n"), s);
00991                 fl->processingFailed = 1;
00992                 res = 1;
00993             }
00994         } else {
00995             *fileName = s;
00996         }
00997         /*@=branchstate@*/
00998     }
00999 
01000     if (specialDoc) {
01001         if (*fileName || (fl->currentFlags & ~(RPMFILE_DOC))) {
01002             rpmError(RPMERR_BADSPEC,
01003                      _("Can't mix special %%doc with other forms: %s\n"),
01004                      (*fileName ? *fileName : ""));
01005             fl->processingFailed = 1;
01006             res = 1;
01007         } else {
01008         /* XXX WATCHOUT: buf is an arg */
01009             {   const char *ddir, *n, *v;
01010 
01011                 (void) headerNVR(pkg->header, &n, &v, NULL);
01012 
01013                 ddir = rpmGetPath("%{_docdir}/", n, "-", v, NULL);
01014                 strcpy(buf, ddir);
01015                 ddir = _free(ddir);
01016             }
01017 
01018         /* XXX FIXME: this is easy to do as macro expansion */
01019 
01020             if (! fl->passedSpecialDoc) {
01021                 pkg->specialDoc = newStringBuf();
01022                 appendStringBuf(pkg->specialDoc, "DOCDIR=$RPM_BUILD_ROOT");
01023                 appendLineStringBuf(pkg->specialDoc, buf);
01024                 appendLineStringBuf(pkg->specialDoc, "export DOCDIR");
01025                 appendLineStringBuf(pkg->specialDoc, "rm -rf $DOCDIR");
01026                 appendLineStringBuf(pkg->specialDoc, MKDIR_P " $DOCDIR");
01027 
01028                 /*@-temptrans@*/
01029                 *fileName = buf;
01030                 /*@=temptrans@*/
01031                 fl->passedSpecialDoc = 1;
01032                 fl->isSpecialDoc = 1;
01033             }
01034 
01035             appendStringBuf(pkg->specialDoc, "cp -pr ");
01036             appendStringBuf(pkg->specialDoc, specialDocBuf);
01037             appendLineStringBuf(pkg->specialDoc, " $DOCDIR");
01038 
01039             {
01040                 char *compress_doc;
01041 
01042                 compress_doc = rpmExpand("%{__compress_doc}", NULL);
01043                 if (compress_doc && *compress_doc != '%')
01044                     appendLineStringBuf(pkg->specialDoc, compress_doc);
01045                 if (compress_doc)
01046                   free(compress_doc);
01047             }
01048         }
01049     }
01050 
01051     return res;
01052 }
01053 /*@=boundswrite@*/
01054 
01057 static int compareFileListRecs(const void * ap, const void * bp)        /*@*/
01058 {
01059     const char *a = ((FileListRec)ap)->fileURL;
01060     const char *b = ((FileListRec)bp)->fileURL;
01061     return strcmp(a, b);
01062 }
01063 
01071 static int isDoc(FileList fl, const char * fileName)    /*@*/
01072 {
01073     int x = fl->docDirCount;
01074 
01075     while (x--) {
01076         if (strstr(fileName, fl->docDirs[x]) == fileName)
01077             return 1;
01078     }
01079     return 0;
01080 }
01081 
01088 static int checkHardLinks(FileList fl)
01089         /*@*/
01090 {
01091     FileListRec ilp, jlp;
01092     int i, j;
01093 
01094     for (i = 0;  i < fl->fileListRecsUsed; i++) {
01095         ilp = fl->fileList + i;
01096         if (!(S_ISREG(ilp->fl_mode) && ilp->fl_nlink > 1))
01097             continue;
01098 
01099         for (j = i + 1; j < fl->fileListRecsUsed; j++) {
01100             jlp = fl->fileList + j;
01101             if (!S_ISREG(jlp->fl_mode))
01102                 /*@innercontinue@*/ continue;
01103             if (ilp->fl_nlink != jlp->fl_nlink)
01104                 /*@innercontinue@*/ continue;
01105             if (ilp->fl_ino != jlp->fl_ino)
01106                 /*@innercontinue@*/ continue;
01107             if (ilp->fl_dev != jlp->fl_dev)
01108                 /*@innercontinue@*/ continue;
01109             return 1;
01110         }
01111     }
01112     return 0;
01113 }
01114 
01124 /*@-bounds@*/
01125 static void genCpioListAndHeader(/*@partial@*/ FileList fl,
01126                 rpmfi * fip, Header h, int isSrc)
01127         /*@globals rpmGlobalMacroContext, h_errno, fileSystem, internalState @*/
01128         /*@modifies h, *fip, fl->processingFailed, fl->fileList,
01129                 rpmGlobalMacroContext, fileSystem, internalState @*/
01130 {
01131     int _addDotSlash = !(isSrc || rpmExpandNumeric("%{_noPayloadPrefix}"));
01132     int apathlen = 0;
01133     int dpathlen = 0;
01134     int skipLen = 0;
01135     rpmsx sx = NULL;
01136     const char * sxfn;
01137     size_t fnlen;
01138     FileListRec flp;
01139     char buf[BUFSIZ];
01140     int i;
01141     
01142     /* Sort the big list */
01143     qsort(fl->fileList, fl->fileListRecsUsed,
01144           sizeof(*(fl->fileList)), compareFileListRecs);
01145     
01146     /* Generate the header. */
01147     if (! isSrc) {
01148         skipLen = 1;
01149         if (fl->prefix)
01150             skipLen += strlen(fl->prefix);
01151     }
01152 
01153     sxfn = rpmGetPath("%{?_build_file_context_path}", NULL);
01154     if (sxfn != NULL && *sxfn != '\0')
01155         sx = rpmsxNew(sxfn);
01156 
01157     for (i = 0, flp = fl->fileList; i < fl->fileListRecsUsed; i++, flp++) {
01158         const char *s;
01159 
01160         /* Merge duplicate entries. */
01161         while (i < (fl->fileListRecsUsed - 1) &&
01162             !strcmp(flp->fileURL, flp[1].fileURL)) {
01163 
01164             /* Two entries for the same file found, merge the entries. */
01165             /* Note that an %exclude is a duplication of a file reference */
01166 
01167             /* file flags */
01168             flp[1].flags |= flp->flags; 
01169 
01170             if (!(flp[1].flags & RPMFILE_EXCLUDE))
01171                 rpmMessage(RPMMESS_WARNING, _("File listed twice: %s\n"),
01172                         flp->fileURL);
01173    
01174             /* file mode */
01175             if (S_ISDIR(flp->fl_mode)) {
01176                 if ((flp[1].specdFlags & (SPECD_DIRMODE | SPECD_DEFDIRMODE)) <
01177                     (flp->specdFlags & (SPECD_DIRMODE | SPECD_DEFDIRMODE)))
01178                         flp[1].fl_mode = flp->fl_mode;
01179             } else {
01180                 if ((flp[1].specdFlags & (SPECD_FILEMODE | SPECD_DEFFILEMODE)) <
01181                     (flp->specdFlags & (SPECD_FILEMODE | SPECD_DEFFILEMODE)))
01182                         flp[1].fl_mode = flp->fl_mode;
01183             }
01184 
01185             /* uid */
01186             if ((flp[1].specdFlags & (SPECD_UID | SPECD_DEFUID)) <
01187                 (flp->specdFlags & (SPECD_UID | SPECD_DEFUID)))
01188             {
01189                 flp[1].fl_uid = flp->fl_uid;
01190                 flp[1].uname = flp->uname;
01191             }
01192 
01193             /* gid */
01194             if ((flp[1].specdFlags & (SPECD_GID | SPECD_DEFGID)) <
01195                 (flp->specdFlags & (SPECD_GID | SPECD_DEFGID)))
01196             {
01197                 flp[1].fl_gid = flp->fl_gid;
01198                 flp[1].gname = flp->gname;
01199             }
01200 
01201             /* verify flags */
01202             if ((flp[1].specdFlags & (SPECD_VERIFY | SPECD_DEFVERIFY)) <
01203                 (flp->specdFlags & (SPECD_VERIFY | SPECD_DEFVERIFY)))
01204                     flp[1].verifyFlags = flp->verifyFlags;
01205 
01206             /* XXX to-do: language */
01207 
01208             flp++; i++;
01209         }
01210 
01211         /* Skip files that were marked with %exclude. */
01212         if (flp->flags & RPMFILE_EXCLUDE) continue;
01213 
01214         /* Omit '/' and/or URL prefix, leave room for "./" prefix */
01215         apathlen += (strlen(flp->fileURL) - skipLen + (_addDotSlash ? 3 : 1));
01216 
01217         /* Leave room for both dirname and basename NUL's */
01218         dpathlen += (strlen(flp->diskURL) + 2);
01219 
01220         /*
01221          * Make the header, the OLDFILENAMES will get converted to a 
01222          * compressed file list write before we write the actual package to
01223          * disk.
01224          */
01225         (void) headerAddOrAppendEntry(h, RPMTAG_OLDFILENAMES, RPM_STRING_ARRAY_TYPE,
01226                                &(flp->fileURL), 1);
01227 
01228 /*@-sizeoftype@*/
01229       if (sizeof(flp->fl_size) != sizeof(uint_32)) {
01230         uint_32 psize = (uint_32)flp->fl_size;
01231         (void) headerAddOrAppendEntry(h, RPMTAG_FILESIZES, RPM_INT32_TYPE,
01232                                &(psize), 1);
01233       } else {
01234         (void) headerAddOrAppendEntry(h, RPMTAG_FILESIZES, RPM_INT32_TYPE,
01235                                &(flp->fl_size), 1);
01236       }
01237         (void) headerAddOrAppendEntry(h, RPMTAG_FILEUSERNAME, RPM_STRING_ARRAY_TYPE,
01238                                &(flp->uname), 1);
01239         (void) headerAddOrAppendEntry(h, RPMTAG_FILEGROUPNAME, RPM_STRING_ARRAY_TYPE,
01240                                &(flp->gname), 1);
01241       if (sizeof(flp->fl_mtime) != sizeof(uint_32)) {
01242         uint_32 mtime = (uint_32)flp->fl_mtime;
01243         (void) headerAddOrAppendEntry(h, RPMTAG_FILEMTIMES, RPM_INT32_TYPE,
01244                                &(mtime), 1);
01245       } else {
01246         (void) headerAddOrAppendEntry(h, RPMTAG_FILEMTIMES, RPM_INT32_TYPE,
01247                                &(flp->fl_mtime), 1);
01248       }
01249       if (sizeof(flp->fl_mode) != sizeof(uint_16)) {
01250         uint_16 pmode = (uint_16)flp->fl_mode;
01251         (void) headerAddOrAppendEntry(h, RPMTAG_FILEMODES, RPM_INT16_TYPE,
01252                                &(pmode), 1);
01253       } else {
01254         (void) headerAddOrAppendEntry(h, RPMTAG_FILEMODES, RPM_INT16_TYPE,
01255                                &(flp->fl_mode), 1);
01256       }
01257       if (sizeof(flp->fl_rdev) != sizeof(uint_16)) {
01258         uint_16 prdev = (uint_16)flp->fl_rdev;
01259         (void) headerAddOrAppendEntry(h, RPMTAG_FILERDEVS, RPM_INT16_TYPE,
01260                                &(prdev), 1);
01261       } else {
01262         (void) headerAddOrAppendEntry(h, RPMTAG_FILERDEVS, RPM_INT16_TYPE,
01263                                &(flp->fl_rdev), 1);
01264       }
01265       if (sizeof(flp->fl_dev) != sizeof(uint_32)) {
01266         uint_32 pdevice = (uint_32)flp->fl_dev;
01267         (void) headerAddOrAppendEntry(h, RPMTAG_FILEDEVICES, RPM_INT32_TYPE,
01268                                &(pdevice), 1);
01269       } else {
01270         (void) headerAddOrAppendEntry(h, RPMTAG_FILEDEVICES, RPM_INT32_TYPE,
01271                                &(flp->fl_dev), 1);
01272       }
01273       if (sizeof(flp->fl_ino) != sizeof(uint_32)) {
01274         uint_32 ino = (uint_32)flp->fl_ino;
01275         (void) headerAddOrAppendEntry(h, RPMTAG_FILEINODES, RPM_INT32_TYPE,
01276                                 &(ino), 1);
01277       } else {
01278         (void) headerAddOrAppendEntry(h, RPMTAG_FILEINODES, RPM_INT32_TYPE,
01279                                 &(flp->fl_ino), 1);
01280       }
01281 /*@=sizeoftype@*/
01282 
01283         (void) headerAddOrAppendEntry(h, RPMTAG_FILELANGS, RPM_STRING_ARRAY_TYPE,
01284                                &(flp->langs),  1);
01285         
01286         /* We used to add these, but they should not be needed */
01287         /* (void) headerAddOrAppendEntry(h, RPMTAG_FILEUIDS,
01288          *                 RPM_INT32_TYPE, &(flp->fl_uid), 1);
01289          * (void) headerAddOrAppendEntry(h, RPMTAG_FILEGIDS,
01290          *                 RPM_INT32_TYPE, &(flp->fl_gid), 1);
01291          */
01292         
01293         buf[0] = '\0';
01294         if (S_ISREG(flp->fl_mode))
01295             (void) domd5(flp->diskURL, buf, 1, NULL);
01296         s = buf;
01297         (void) headerAddOrAppendEntry(h, RPMTAG_FILEMD5S, RPM_STRING_ARRAY_TYPE,
01298                                &s, 1);
01299         
01300         buf[0] = '\0';
01301         if (S_ISLNK(flp->fl_mode)) {
01302             buf[Readlink(flp->diskURL, buf, BUFSIZ)] = '\0';
01303             if (fl->buildRootURL) {
01304                 const char * buildRoot;
01305                 (void) urlPath(fl->buildRootURL, &buildRoot);
01306 
01307                 if (buf[0] == '/' && strcmp(buildRoot, "/") &&
01308                     !strncmp(buf, buildRoot, strlen(buildRoot))) {
01309                      rpmError(RPMERR_BADSPEC,
01310                                 _("Symlink points to BuildRoot: %s -> %s\n"),
01311                                 flp->fileURL, buf);
01312                     fl->processingFailed = 1;
01313                 }
01314             }
01315         }
01316         s = buf;
01317         (void) headerAddOrAppendEntry(h, RPMTAG_FILELINKTOS, RPM_STRING_ARRAY_TYPE,
01318                                &s, 1);
01319         
01320         if (flp->flags & RPMFILE_GHOST) {
01321             flp->verifyFlags &= ~(RPMVERIFY_MD5 | RPMVERIFY_FILESIZE |
01322                                 RPMVERIFY_LINKTO | RPMVERIFY_MTIME);
01323         }
01324         (void) headerAddOrAppendEntry(h, RPMTAG_FILEVERIFYFLAGS, RPM_INT32_TYPE,
01325                                &(flp->verifyFlags), 1);
01326         
01327         if (!isSrc && isDoc(fl, flp->fileURL))
01328             flp->flags |= RPMFILE_DOC;
01329         /* XXX Should directories have %doc/%config attributes? (#14531) */
01330         if (S_ISDIR(flp->fl_mode))
01331             flp->flags &= ~(RPMFILE_CONFIG|RPMFILE_DOC);
01332 
01333         (void) headerAddOrAppendEntry(h, RPMTAG_FILEFLAGS, RPM_INT32_TYPE,
01334                                &(flp->flags), 1);
01335 
01336         /* Add file security context to package. */
01337 /*@-branchstate@*/
01338         if (sx != NULL) {
01339             mode_t fmode = (uint_16)flp->fl_mode;
01340             s = rpmsxFContext(sx, flp->fileURL, fmode);
01341             if (s == NULL) s = "";
01342             (void) headerAddOrAppendEntry(h, RPMTAG_FILECONTEXTS, RPM_STRING_ARRAY_TYPE,
01343                                &s, 1);
01344         }
01345 /*@=branchstate@*/
01346 
01347     }
01348     sx = rpmsxFree(sx);
01349     sxfn = _free(sxfn);
01350 
01351     (void) headerAddEntry(h, RPMTAG_SIZE, RPM_INT32_TYPE,
01352                    &(fl->totalFileSize), 1);
01353 
01354     if (_addDotSlash)
01355         (void) rpmlibNeedsFeature(h, "PayloadFilesHavePrefix", "4.0-1");
01356 
01357     /* Choose how filenames are represented. */
01358     if (_noDirTokens)
01359         expandFilelist(h);
01360     else {
01361         compressFilelist(h);
01362         /* Binary packages with dirNames cannot be installed by legacy rpm. */
01363         (void) rpmlibNeedsFeature(h, "CompressedFileNames", "3.0.4-1");
01364     }
01365 
01366   { int scareMem = 0;
01367     rpmts ts = NULL;    /* XXX FIXME drill rpmts ts all the way down here */
01368     rpmfi fi = rpmfiNew(ts, h, RPMTAG_BASENAMES, scareMem);
01369     char * a, * d;
01370 
01371     if (fi == NULL) return;             /* XXX can't happen */
01372 
01373 /*@-onlytrans@*/
01374     fi->te = xcalloc(1, sizeof(*fi->te));
01375 /*@=onlytrans@*/
01376     fi->te->type = TR_ADDED;
01377 
01378     fi->dnl = _free(fi->dnl);
01379     fi->bnl = _free(fi->bnl);
01380     if (!scareMem) fi->dil = _free(fi->dil);
01381 
01382     fi->dnl = xmalloc(fi->fc * sizeof(*fi->dnl) + dpathlen);
01383     d = (char *)(fi->dnl + fi->fc);
01384     *d = '\0';
01385 
01386     fi->bnl = xmalloc(fi->fc * (sizeof(*fi->bnl) + sizeof(*fi->dil)));
01387 /*@-dependenttrans@*/ /* FIX: artifact of spoofing headerGetEntry */
01388     fi->dil = (!scareMem)
01389         ? xcalloc(sizeof(*fi->dil), fi->fc)
01390         : (int *)(fi->bnl + fi->fc);
01391 /*@=dependenttrans@*/
01392 
01393     fi->apath = xmalloc(fi->fc * sizeof(*fi->apath) + apathlen);
01394     a = (char *)(fi->apath + fi->fc);
01395     *a = '\0';
01396 
01397     fi->actions = xcalloc(sizeof(*fi->actions), fi->fc);
01398     fi->fmapflags = xcalloc(sizeof(*fi->fmapflags), fi->fc);
01399     fi->astriplen = 0;
01400     if (fl->buildRootURL)
01401         fi->astriplen = strlen(fl->buildRootURL);
01402     fi->striplen = 0;
01403     fi->fuser = NULL;
01404     fi->fgroup = NULL;
01405 
01406     /* Make the cpio list */
01407     if (fi->dil != NULL)        /* XXX can't happen */
01408     for (i = 0, flp = fl->fileList; i < fi->fc; i++, flp++) {
01409         char * b;
01410 
01411         /* Skip (possible) duplicate file entries, use last entry info. */
01412         while (((flp - fl->fileList) < (fl->fileListRecsUsed - 1)) &&
01413                 !strcmp(flp->fileURL, flp[1].fileURL))
01414             flp++;
01415 
01416         if (flp->flags & RPMFILE_EXCLUDE) {
01417             i--;
01418             continue;
01419         }
01420 
01421         if ((fnlen = strlen(flp->diskURL) + 1) > fi->fnlen)
01422             fi->fnlen = fnlen;
01423 
01424         /* Create disk directory and base name. */
01425         fi->dil[i] = i;
01426 /*@-dependenttrans@*/ /* FIX: artifact of spoofing headerGetEntry */
01427         fi->dnl[fi->dil[i]] = d;
01428 /*@=dependenttrans@*/
01429         d = stpcpy(d, flp->diskURL);
01430 
01431         /* Make room for the dirName NUL, find start of baseName. */
01432         for (b = d; b > fi->dnl[fi->dil[i]] && *b != '/'; b--)
01433             b[1] = b[0];
01434         b++;            /* dirname's end in '/' */
01435         *b++ = '\0';    /* terminate dirname, b points to basename */
01436         fi->bnl[i] = b;
01437         d += 2;         /* skip both dirname and basename NUL's */
01438 
01439         /* Create archive path, normally adding "./" */
01440         /*@-dependenttrans@*/   /* FIX: xstrdup? nah ... */
01441         fi->apath[i] = a;
01442         /*@=dependenttrans@*/
01443         if (_addDotSlash)
01444             a = stpcpy(a, "./");
01445         a = stpcpy(a, (flp->fileURL + skipLen));
01446         a++;            /* skip apath NUL */
01447 
01448         if (flp->flags & RPMFILE_GHOST) {
01449             fi->actions[i] = FA_SKIP;
01450             continue;
01451         }
01452         fi->actions[i] = FA_COPYOUT;
01453         fi->fmapflags[i] = CPIO_MAP_PATH |
01454                 CPIO_MAP_TYPE | CPIO_MAP_MODE | CPIO_MAP_UID | CPIO_MAP_GID;
01455         if (isSrc)
01456             fi->fmapflags[i] |= CPIO_FOLLOW_SYMLINKS;
01457 
01458     }
01459     /*@-branchstate -compdef@*/
01460     if (fip)
01461         *fip = fi;
01462     else
01463         fi = rpmfiFree(fi);
01464     /*@=branchstate =compdef@*/
01465   }
01466 }
01467 /*@=bounds@*/
01468 
01471 /*@-boundswrite@*/
01472 static /*@null@*/ FileListRec freeFileList(/*@only@*/ FileListRec fileList,
01473                         int count)
01474         /*@*/
01475 {
01476     while (count--) {
01477         fileList[count].diskURL = _free(fileList[count].diskURL);
01478         fileList[count].fileURL = _free(fileList[count].fileURL);
01479         fileList[count].langs = _free(fileList[count].langs);
01480     }
01481     fileList = _free(fileList);
01482     return NULL;
01483 }
01484 /*@=boundswrite@*/
01485 
01486 /* forward ref */
01487 static int recurseDir(FileList fl, const char * diskURL)
01488         /*@globals check_fileList, rpmGlobalMacroContext, h_errno,
01489                 fileSystem, internalState @*/
01490         /*@modifies *fl, fl->processingFailed,
01491                 fl->fileList, fl->fileListRecsAlloced, fl->fileListRecsUsed,
01492                 fl->totalFileSize, fl->fileCount, fl->inFtw, fl->isDir,
01493                 check_fileList, rpmGlobalMacroContext,
01494                 fileSystem, internalState @*/;
01495 
01503 /*@-boundswrite@*/
01504 static int addFile(FileList fl, const char * diskURL,
01505                 /*@null@*/ struct stat * statp)
01506         /*@globals check_fileList, rpmGlobalMacroContext, h_errno,
01507                 fileSystem, internalState @*/
01508         /*@modifies *statp, *fl, fl->processingFailed,
01509                 fl->fileList, fl->fileListRecsAlloced, fl->fileListRecsUsed,
01510                 fl->totalFileSize, fl->fileCount,
01511                 check_fileList, rpmGlobalMacroContext,
01512                 fileSystem, internalState @*/
01513 {
01514     const char *fileURL = diskURL;
01515     struct stat statbuf;
01516     mode_t fileMode;
01517     uid_t fileUid;
01518     gid_t fileGid;
01519     const char *fileUname;
01520     const char *fileGname;
01521     char *lang;
01522     
01523     /* Path may have prepended buildRootURL, so locate the original filename. */
01524     /*
01525      * XXX There are 3 types of entry into addFile:
01526      *
01527      *  From                    diskUrl                 statp
01528      *  =====================================================
01529      *  processBinaryFile       path                    NULL
01530      *  processBinaryFile       glob result path        NULL
01531      *  myftw                   path                    stat
01532      *
01533      */
01534     {   const char *fileName;
01535         (void) urlPath(fileURL, &fileName);
01536         if (fl->buildRootURL && strcmp(fl->buildRootURL, "/"))
01537             fileURL += strlen(fl->buildRootURL);
01538     }
01539 
01540     /* XXX make sure '/' can be packaged also */
01541     /*@-branchstate@*/
01542     if (*fileURL == '\0')
01543         fileURL = "/";
01544     /*@=branchstate@*/
01545 
01546     /* If we are using a prefix, validate the file */
01547     if (!fl->inFtw && fl->prefix) {
01548         const char *prefixTest;
01549         const char *prefixPtr = fl->prefix;
01550 
01551         (void) urlPath(fileURL, &prefixTest);
01552         while (*prefixPtr && *prefixTest && (*prefixTest == *prefixPtr)) {
01553             prefixPtr++;
01554             prefixTest++;
01555         }
01556         if (*prefixPtr || (*prefixTest && *prefixTest != '/')) {
01557             rpmError(RPMERR_BADSPEC, _("File doesn't match prefix (%s): %s\n"),
01558                      fl->prefix, fileURL);
01559             fl->processingFailed = 1;
01560             return RPMERR_BADSPEC;
01561         }
01562     }
01563 
01564     if (statp == NULL) {
01565         statp = &statbuf;
01566         memset(statp, 0, sizeof(*statp));
01567         if (fl->devtype) {
01568             time_t now = time(NULL);
01569 
01570             /* XXX hack up a stat structure for a %dev(...) directive. */
01571             statp->st_nlink = 1;
01572             statp->st_rdev =
01573                 ((fl->devmajor & 0xff) << 8) | (fl->devminor & 0xff);
01574             statp->st_dev = statp->st_rdev;
01575             statp->st_mode = (fl->devtype == 'b' ? S_IFBLK : S_IFCHR);
01576             statp->st_mode |= (fl->cur_ar.ar_fmode & 0777);
01577             statp->st_atime = now;
01578             statp->st_mtime = now;
01579             statp->st_ctime = now;
01580         } else if (Lstat(diskURL, statp)) {
01581             rpmError(RPMERR_BADSPEC, _("File not found: %s\n"), diskURL);
01582             fl->processingFailed = 1;
01583             return RPMERR_BADSPEC;
01584         }
01585     }
01586 
01587     if ((! fl->isDir) && S_ISDIR(statp->st_mode)) {
01588 /*@-nullstate@*/ /* FIX: fl->buildRootURL may be NULL */
01589         return recurseDir(fl, diskURL);
01590 /*@=nullstate@*/
01591     }
01592 
01593     fileMode = statp->st_mode;
01594     fileUid = statp->st_uid;
01595     fileGid = statp->st_gid;
01596 
01597     if (S_ISDIR(fileMode) && fl->cur_ar.ar_dmodestr) {
01598         fileMode &= S_IFMT;
01599         fileMode |= fl->cur_ar.ar_dmode;
01600     } else if (fl->cur_ar.ar_fmodestr != NULL) {
01601         fileMode &= S_IFMT;
01602         fileMode |= fl->cur_ar.ar_fmode;
01603     }
01604     if (fl->cur_ar.ar_user) {
01605         fileUname = getUnameS(fl->cur_ar.ar_user);
01606     } else {
01607         fileUname = getUname(fileUid);
01608     }
01609     if (fl->cur_ar.ar_group) {
01610         fileGname = getGnameS(fl->cur_ar.ar_group);
01611     } else {
01612         fileGname = getGname(fileGid);
01613     }
01614         
01615     /* Default user/group to builder's user/group */
01616     if (fileUname == NULL)
01617         fileUname = getUname(getuid());
01618     if (fileGname == NULL)
01619         fileGname = getGname(getgid());
01620     
01621     /* S_XXX macro must be consistent with type in find call at check-files script */
01622     if (check_fileList && (S_ISREG(fileMode) || S_ISLNK(fileMode))) {
01623         appendStringBuf(check_fileList, diskURL);
01624         appendStringBuf(check_fileList, "\n");
01625     }
01626 
01627     /* Add to the file list */
01628     if (fl->fileListRecsUsed == fl->fileListRecsAlloced) {
01629         fl->fileListRecsAlloced += 128;
01630         fl->fileList = xrealloc(fl->fileList,
01631                         fl->fileListRecsAlloced * sizeof(*(fl->fileList)));
01632     }
01633             
01634     {   FileListRec flp = &fl->fileList[fl->fileListRecsUsed];
01635         int i;
01636 
01637         flp->fl_st = *statp;    /* structure assignment */
01638         flp->fl_mode = fileMode;
01639         flp->fl_uid = fileUid;
01640         flp->fl_gid = fileGid;
01641 
01642         flp->fileURL = xstrdup(fileURL);
01643         flp->diskURL = xstrdup(diskURL);
01644         flp->uname = fileUname;
01645         flp->gname = fileGname;
01646 
01647         if (fl->currentLangs && fl->nLangs > 0) {
01648             char * ncl;
01649             size_t nl = 0;
01650             
01651             for (i = 0; i < fl->nLangs; i++)
01652                 nl += strlen(fl->currentLangs[i]) + 1;
01653 
01654             flp->langs = ncl = xmalloc(nl);
01655             for (i = 0; i < fl->nLangs; i++) {
01656                 const char *ocl;
01657                 if (i)  *ncl++ = '|';
01658                 for (ocl = fl->currentLangs[i]; *ocl != '\0'; ocl++)
01659                         *ncl++ = *ocl;
01660                 *ncl = '\0';
01661             }
01662         } else if (! parseForRegexLang(fileURL, &lang)) {
01663             flp->langs = xstrdup(lang);
01664         } else {
01665             flp->langs = xstrdup("");
01666         }
01667 
01668         flp->flags = fl->currentFlags;
01669         flp->specdFlags = fl->currentSpecdFlags;
01670         flp->verifyFlags = fl->currentVerifyFlags;
01671 
01672         /* Hard links need be counted only once. */
01673         if (S_ISREG(flp->fl_mode) && flp->fl_nlink > 1) {
01674             FileListRec ilp;
01675             for (i = 0;  i < fl->fileListRecsUsed; i++) {
01676                 ilp = fl->fileList + i;
01677                 if (!S_ISREG(ilp->fl_mode))
01678                     continue;
01679                 if (flp->fl_nlink != ilp->fl_nlink)
01680                     continue;
01681                 if (flp->fl_ino != ilp->fl_ino)
01682                     continue;
01683                 if (flp->fl_dev != ilp->fl_dev)
01684                     continue;
01685                 break;
01686             }
01687         } else
01688             i = fl->fileListRecsUsed;
01689 
01690         if (S_ISREG(flp->fl_mode) && i >= fl->fileListRecsUsed)
01691             fl->totalFileSize += flp->fl_size;
01692     }
01693 
01694     fl->fileListRecsUsed++;
01695     fl->fileCount++;
01696 
01697     return 0;
01698 }
01699 /*@=boundswrite@*/
01700 
01707 static int recurseDir(FileList fl, const char * diskURL)
01708 {
01709     char * ftsSet[2];
01710     FTS * ftsp;
01711     FTSENT * fts;
01712     int myFtsOpts = (FTS_COMFOLLOW | FTS_NOCHDIR | FTS_PHYSICAL);
01713     int rc = RPMERR_BADSPEC;
01714 
01715     fl->inFtw = 1;  /* Flag to indicate file has buildRootURL prefixed */
01716     fl->isDir = 1;  /* Keep it from following myftw() again         */
01717 
01718     ftsSet[0] = (char *) diskURL;
01719     ftsSet[1] = NULL;
01720     ftsp = Fts_open(ftsSet, myFtsOpts, NULL);
01721     while ((fts = Fts_read(ftsp)) != NULL) {
01722         switch (fts->fts_info) {
01723         case FTS_D:             /* preorder directory */
01724         case FTS_F:             /* regular file */
01725         case FTS_SL:            /* symbolic link */
01726         case FTS_SLNONE:        /* symbolic link without target */
01727         case FTS_DEFAULT:       /* none of the above */
01728             rc = addFile(fl, fts->fts_accpath, fts->fts_statp);
01729             /*@switchbreak@*/ break;
01730         case FTS_DOT:           /* dot or dot-dot */
01731         case FTS_DP:            /* postorder directory */
01732             rc = 0;
01733             /*@switchbreak@*/ break;
01734         case FTS_NS:            /* stat(2) failed */
01735         case FTS_DNR:           /* unreadable directory */
01736         case FTS_ERR:           /* error; errno is set */
01737         case FTS_DC:            /* directory that causes cycles */
01738         case FTS_NSOK:          /* no stat(2) requested */
01739         case FTS_INIT:          /* initialized only */
01740         case FTS_W:             /* whiteout object */
01741         default:
01742             rc = RPMERR_BADSPEC;
01743             /*@switchbreak@*/ break;
01744         }
01745         if (rc)
01746             break;
01747     }
01748     (void) Fts_close(ftsp);
01749 
01750     fl->isDir = 0;
01751     fl->inFtw = 0;
01752 
01753     return rc;
01754 }
01755 
01764 static int processMetadataFile(Package pkg, FileList fl, const char * fileURL,
01765                 rpmTag tag)
01766         /*@globals check_fileList, rpmGlobalMacroContext, h_errno,
01767                 fileSystem, internalState @*/
01768         /*@modifies pkg->header, *fl, fl->processingFailed,
01769                 fl->fileList, fl->fileListRecsAlloced, fl->fileListRecsUsed,
01770                 fl->totalFileSize, fl->fileCount,
01771                 check_fileList, rpmGlobalMacroContext,
01772                 fileSystem, internalState @*/
01773 {
01774     const char * buildURL = "%{_builddir}/%{?buildsubdir}/";
01775     const char * fn = NULL;
01776     const char * apkt = NULL;
01777     const unsigned char * pkt = NULL;
01778     ssize_t pktlen = 0;
01779     int absolute = 0;
01780     int rc = 1;
01781     int xx;
01782 
01783     (void) urlPath(fileURL, &fn);
01784     if (*fn == '/') {
01785         fn = rpmGenPath(fl->buildRootURL, NULL, fn);
01786         absolute = 1;
01787     } else
01788         fn = rpmGenPath(buildURL, NULL, fn);
01789 
01790 /*@-branchstate@*/
01791     switch (tag) {
01792     default:
01793         rpmError(RPMERR_BADSPEC, _("%s: can't load unknown tag (%d).\n"),
01794                 fn, tag);
01795         goto exit;
01796         /*@notreached@*/ break;
01797     case RPMTAG_PUBKEYS:
01798         if ((rc = pgpReadPkts(fn, &pkt, &pktlen)) <= 0) {
01799             rpmError(RPMERR_BADSPEC, _("%s: public key read failed.\n"), fn);
01800             goto exit;
01801         }
01802         if (rc != PGPARMOR_PUBKEY) {
01803             rpmError(RPMERR_BADSPEC, _("%s: not an armored public key.\n"), fn);
01804             goto exit;
01805         }
01806         apkt = pgpArmorWrap(PGPARMOR_PUBKEY, pkt, pktlen);
01807         break;
01808     case RPMTAG_POLICIES:
01809         if ((rc = rpmioSlurp(fn, &pkt, &pktlen)) != 0) {
01810             rpmError(RPMERR_BADSPEC, _("%s: *.te policy read failed.\n"), fn);
01811             goto exit;
01812         }
01813         apkt = (const char *) pkt;      /* XXX unsigned char */
01814         pkt = NULL;
01815         break;
01816     }
01817 /*@=branchstate@*/
01818 
01819     xx = headerAddOrAppendEntry(pkg->header, tag,
01820                 RPM_STRING_ARRAY_TYPE, &apkt, 1);
01821 
01822     rc = 0;
01823     if (absolute)
01824         rc = addFile(fl, fn, NULL);
01825 
01826 exit:
01827     apkt = _free(apkt);
01828     pkt = _free(pkt);
01829     fn = _free(fn);
01830     if (rc) {
01831         fl->processingFailed = 1;
01832         rc = RPMERR_BADSPEC;
01833     }
01834     return rc;
01835 }
01836 
01844 static int processBinaryFile(/*@unused@*/ Package pkg, FileList fl,
01845                 const char * fileURL)
01846         /*@globals rpmGlobalMacroContext, h_errno, fileSystem, internalState @*/
01847         /*@modifies *fl, fl->processingFailed,
01848                 fl->fileList, fl->fileListRecsAlloced, fl->fileListRecsUsed,
01849                 fl->totalFileSize, fl->fileCount,
01850                 rpmGlobalMacroContext, fileSystem, internalState @*/
01851 {
01852     int quote = 1;      /* XXX permit quoted glob characters. */
01853     int doGlob;
01854     const char *diskURL = NULL;
01855     int rc = 0;
01856     
01857     doGlob = Glob_pattern_p(fileURL, quote);
01858 
01859     /* Check that file starts with leading "/" */
01860     {   const char * fileName;
01861         (void) urlPath(fileURL, &fileName);
01862         if (*fileName != '/') {
01863             rpmError(RPMERR_BADSPEC, _("File needs leading \"/\": %s\n"),
01864                         fileName);
01865             rc = 1;
01866             goto exit;
01867         }
01868     }
01869     
01870     /* Copy file name or glob pattern removing multiple "/" chars. */
01871     /*
01872      * Note: rpmGetPath should guarantee a "canonical" path. That means
01873      * that the following pathologies should be weeded out:
01874      *          //bin//sh
01875      *          //usr//bin/
01876      *          /.././../usr/../bin//./sh
01877      */
01878     diskURL = rpmGenPath(fl->buildRootURL, NULL, fileURL);
01879 
01880     if (doGlob) {
01881         const char ** argv = NULL;
01882         int argc = 0;
01883         int i;
01884 
01885         /* XXX for %dev marker in file manifest only */
01886         if (fl->noGlob) {
01887             rpmError(RPMERR_BADSPEC, _("Glob not permitted: %s\n"),
01888                         diskURL);
01889             rc = 1;
01890             goto exit;
01891         }
01892 
01893         /*@-branchstate@*/
01894         rc = rpmGlob(diskURL, &argc, &argv);
01895         if (rc == 0 && argc >= 1 && !Glob_pattern_p(argv[0], quote)) {
01896             for (i = 0; i < argc; i++) {
01897                 rc = addFile(fl, argv[i], NULL);
01898 /*@-boundswrite@*/
01899                 argv[i] = _free(argv[i]);
01900 /*@=boundswrite@*/
01901             }
01902             argv = _free(argv);
01903         } else {
01904             rpmError(RPMERR_BADSPEC, _("File not found by glob: %s\n"),
01905                         diskURL);
01906             rc = 1;
01907             goto exit;
01908         }
01909         /*@=branchstate@*/
01910     } else {
01911         rc = addFile(fl, diskURL, NULL);
01912     }
01913 
01914 exit:
01915     diskURL = _free(diskURL);
01916     if (rc) {
01917         fl->processingFailed = 1;
01918         rc = RPMERR_BADSPEC;
01919     }
01920     return rc;
01921 }
01922 
01925 /*@-boundswrite@*/
01926 static int processPackageFiles(Spec spec, Package pkg,
01927                                int installSpecialDoc, int test)
01928         /*@globals rpmGlobalMacroContext, h_errno,
01929                 fileSystem, internalState@*/
01930         /*@modifies spec->macros,
01931                 pkg->cpioList, pkg->fileList, pkg->specialDoc, pkg->header,
01932                 rpmGlobalMacroContext, fileSystem, internalState @*/
01933 {
01934     HGE_t hge = (HGE_t)headerGetEntryMinMemory;
01935     struct FileList_s fl;
01936     char *s, **files, **fp;
01937     const char *fileName;
01938     char buf[BUFSIZ];
01939     struct AttrRec_s arbuf;
01940     AttrRec specialDocAttrRec = &arbuf;
01941     char *specialDoc = NULL;
01942 
01943     nullAttrRec(specialDocAttrRec);
01944     pkg->cpioList = NULL;
01945 
01946     if (pkg->fileFile) {
01947         const char *ffn;
01948         FILE * f;
01949         FD_t fd;
01950 
01951         /* XXX W2DO? urlPath might be useful here. */
01952         if (*pkg->fileFile == '/') {
01953             ffn = rpmGetPath(pkg->fileFile, NULL);
01954         } else {
01955             /* XXX FIXME: add %{_buildsubdir} */
01956             ffn = rpmGetPath("%{_builddir}/",
01957                 (spec->buildSubdir ? spec->buildSubdir : "") ,
01958                 "/", pkg->fileFile, NULL);
01959         }
01960         fd = Fopen(ffn, "r.fpio");
01961 
01962         if (fd == NULL || Ferror(fd)) {
01963             rpmError(RPMERR_BADFILENAME,
01964                 _("Could not open %%files file %s: %s\n"),
01965                 ffn, Fstrerror(fd));
01966             return RPMERR_BADFILENAME;
01967         }
01968         ffn = _free(ffn);
01969 
01970         /*@+voidabstract@*/ f = fdGetFp(fd); /*@=voidabstract@*/
01971         if (f != NULL)
01972         while (fgets(buf, sizeof(buf), f)) {
01973             handleComments(buf);
01974             if (expandMacros(spec, spec->macros, buf, sizeof(buf))) {
01975                 rpmError(RPMERR_BADSPEC, _("line: %s\n"), buf);
01976                 return RPMERR_BADSPEC;
01977             }
01978             appendStringBuf(pkg->fileList, buf);
01979         }
01980         (void) Fclose(fd);
01981     }
01982     
01983     /* Init the file list structure */
01984     memset(&fl, 0, sizeof(fl));
01985 
01986     /* XXX spec->buildRootURL == NULL, then xstrdup("") is returned */
01987     fl.buildRootURL = rpmGenPath(spec->rootURL, spec->buildRootURL, NULL);
01988 
01989     if (hge(pkg->header, RPMTAG_DEFAULTPREFIX, NULL, (void **)&fl.prefix, NULL))
01990         fl.prefix = xstrdup(fl.prefix);
01991     else
01992         fl.prefix = NULL;
01993 
01994     fl.fileCount = 0;
01995     fl.totalFileSize = 0;
01996     fl.processingFailed = 0;
01997 
01998     fl.passedSpecialDoc = 0;
01999     fl.isSpecialDoc = 0;
02000 
02001     fl.isDir = 0;
02002     fl.inFtw = 0;
02003     fl.currentFlags = 0;
02004     fl.currentVerifyFlags = 0;
02005     
02006     fl.noGlob = 0;
02007     fl.devtype = 0;
02008     fl.devmajor = 0;
02009     fl.devminor = 0;
02010 
02011     nullAttrRec(&fl.cur_ar);
02012     nullAttrRec(&fl.def_ar);
02013     dupAttrRec(&root_ar, &fl.def_ar);   /* XXX assume %defattr(-,root,root) */
02014 
02015     fl.defVerifyFlags = RPMVERIFY_ALL;
02016     fl.nLangs = 0;
02017     fl.currentLangs = NULL;
02018 
02019     fl.currentSpecdFlags = 0;
02020     fl.defSpecdFlags = 0;
02021 
02022     fl.docDirCount = 0;
02023     fl.docDirs[fl.docDirCount++] = xstrdup("/usr/doc");
02024     fl.docDirs[fl.docDirCount++] = xstrdup("/usr/man");
02025     fl.docDirs[fl.docDirCount++] = xstrdup("/usr/info");
02026     fl.docDirs[fl.docDirCount++] = xstrdup("/usr/X11R6/man");
02027     fl.docDirs[fl.docDirCount++] = xstrdup("/usr/share/doc");
02028     fl.docDirs[fl.docDirCount++] = xstrdup("/usr/share/man");
02029     fl.docDirs[fl.docDirCount++] = xstrdup("/usr/share/info");
02030     fl.docDirs[fl.docDirCount++] = xstrdup("/usr/src/examples");
02031     fl.docDirs[fl.docDirCount++] = rpmGetPath("%{_docdir}", NULL);
02032     fl.docDirs[fl.docDirCount++] = rpmGetPath("%{_mandir}", NULL);
02033     fl.docDirs[fl.docDirCount++] = rpmGetPath("%{_infodir}", NULL);
02034     fl.docDirs[fl.docDirCount++] = rpmGetPath("%{_javadocdir}", NULL);
02035     fl.docDirs[fl.docDirCount++] = rpmGetPath("%{_examplesdir}", NULL);
02036     
02037     fl.fileList = NULL;
02038     fl.fileListRecsAlloced = 0;
02039     fl.fileListRecsUsed = 0;
02040 
02041     s = getStringBuf(pkg->fileList);
02042     files = splitString(s, strlen(s), '\n');
02043 
02044     for (fp = files; *fp != NULL; fp++) {
02045         s = *fp;
02046         SKIPSPACE(s);
02047         if (*s == '\0')
02048             continue;
02049         fileName = NULL;
02050         /*@-nullpass@*/ /* LCL: buf is NULL ?!? */
02051         strcpy(buf, s);
02052         /*@=nullpass@*/
02053         
02054         /* Reset for a new line in %files */
02055         fl.isDir = 0;
02056         fl.inFtw = 0;
02057         fl.currentFlags = 0;
02058         /* turn explicit flags into %def'd ones (gosh this is hacky...) */
02059         fl.currentSpecdFlags = ((unsigned)fl.defSpecdFlags) >> 8;
02060         fl.currentVerifyFlags = fl.defVerifyFlags;
02061         fl.isSpecialDoc = 0;
02062 
02063         fl.noGlob = 0;
02064         fl.devtype = 0;
02065         fl.devmajor = 0;
02066         fl.devminor = 0;
02067 
02068         /* XXX should reset to %deflang value */
02069         if (fl.currentLangs) {
02070             int i;
02071             for (i = 0; i < fl.nLangs; i++)
02072                 /*@-unqualifiedtrans@*/
02073                 fl.currentLangs[i] = _free(fl.currentLangs[i]);
02074                 /*@=unqualifiedtrans@*/
02075             fl.currentLangs = _free(fl.currentLangs);
02076         }
02077         fl.nLangs = 0;
02078 
02079         dupAttrRec(&fl.def_ar, &fl.cur_ar);
02080 
02081         /*@-nullpass@*/ /* LCL: buf is NULL ?!? */
02082         if (parseForVerify(buf, &fl))
02083             continue;
02084         if (parseForAttr(buf, &fl))
02085             continue;
02086         if (parseForDev(buf, &fl))
02087             continue;
02088         if (parseForConfig(buf, &fl))
02089             continue;
02090         if (parseForLang(buf, &fl))
02091             continue;
02092         /*@-nullstate@*/        /* FIX: pkg->fileFile might be NULL */
02093         if (parseForSimple(spec, pkg, buf, &fl, &fileName))
02094         /*@=nullstate@*/
02095             continue;
02096         /*@=nullpass@*/
02097         if (fileName == NULL)
02098             continue;
02099 
02100         /*@-branchstate@*/
02101         if (fl.isSpecialDoc) {
02102             /* Save this stuff for last */
02103             specialDoc = _free(specialDoc);
02104             specialDoc = xstrdup(fileName);
02105             dupAttrRec(&fl.cur_ar, specialDocAttrRec);
02106         } else if (fl.currentFlags & RPMFILE_PUBKEY) {
02107 /*@-nullstate@*/        /* FIX: pkg->fileFile might be NULL */
02108             (void) processMetadataFile(pkg, &fl, fileName, RPMTAG_PUBKEYS);
02109 /*@=nullstate@*/
02110         } else if (fl.currentFlags & RPMFILE_POLICY) {
02111 /*@-nullstate@*/        /* FIX: pkg->fileFile might be NULL */
02112             (void) processMetadataFile(pkg, &fl, fileName, RPMTAG_POLICIES);
02113 /*@=nullstate@*/
02114         } else {
02115 /*@-nullstate@*/        /* FIX: pkg->fileFile might be NULL */
02116             (void) processBinaryFile(pkg, &fl, fileName);
02117 /*@=nullstate@*/
02118         }
02119         /*@=branchstate@*/
02120     }
02121 
02122     /* Now process special doc, if there is one */
02123     if (specialDoc) {
02124         if (installSpecialDoc) {
02125             int _missing_doc_files_terminate_build =
02126                     rpmExpandNumeric("%{?_missing_doc_files_terminate_build}");
02127             int rc;
02128 
02129             rc = doScript(spec, RPMBUILD_STRINGBUF, "%doc", pkg->specialDoc, test);
02130             if (rc && _missing_doc_files_terminate_build)
02131                 fl.processingFailed = rc;
02132         }
02133 
02134         /* Reset for %doc */
02135         fl.isDir = 0;
02136         fl.inFtw = 0;
02137         fl.currentFlags = 0;
02138         fl.currentVerifyFlags = 0;
02139 
02140         fl.noGlob = 0;
02141         fl.devtype = 0;
02142         fl.devmajor = 0;
02143         fl.devminor = 0;
02144 
02145         /* XXX should reset to %deflang value */
02146         if (fl.currentLangs) {
02147             int i;
02148             for (i = 0; i < fl.nLangs; i++)
02149                 /*@-unqualifiedtrans@*/
02150                 fl.currentLangs[i] = _free(fl.currentLangs[i]);
02151                 /*@=unqualifiedtrans@*/
02152             fl.currentLangs = _free(fl.currentLangs);
02153         }
02154         fl.nLangs = 0;
02155 
02156         dupAttrRec(specialDocAttrRec, &fl.cur_ar);
02157         freeAttrRec(specialDocAttrRec);
02158 
02159         /*@-nullstate@*/        /* FIX: pkg->fileFile might be NULL */
02160         (void) processBinaryFile(pkg, &fl, specialDoc);
02161         /*@=nullstate@*/
02162 
02163         specialDoc = _free(specialDoc);
02164     }
02165     
02166     freeSplitString(files);
02167 
02168     if (fl.processingFailed)
02169         goto exit;
02170 
02171     /* Verify that file attributes scope over hardlinks correctly. */
02172     if (checkHardLinks(&fl) && !rpmExpandNumeric("%{_hack_dontneed_PartialHardlinkSets}"))
02173         (void) rpmlibNeedsFeature(pkg->header,
02174                         "PartialHardlinkSets", "4.0.4-1");
02175 
02176     genCpioListAndHeader(&fl, &pkg->cpioList, pkg->header, 0);
02177 
02178     if (spec->timeCheck)
02179         timeCheck(spec->timeCheck, pkg->header);
02180     
02181 exit:
02182     fl.buildRootURL = _free(fl.buildRootURL);
02183     fl.prefix = _free(fl.prefix);
02184 
02185     freeAttrRec(&fl.cur_ar);
02186     freeAttrRec(&fl.def_ar);
02187 
02188     if (fl.currentLangs) {
02189         int i;
02190         for (i = 0; i < fl.nLangs; i++)
02191             /*@-unqualifiedtrans@*/
02192             fl.currentLangs[i] = _free(fl.currentLangs[i]);
02193             /*@=unqualifiedtrans@*/
02194         fl.currentLangs = _free(fl.currentLangs);
02195     }
02196 
02197     fl.fileList = freeFileList(fl.fileList, fl.fileListRecsUsed);
02198     while (fl.docDirCount--)
02199         fl.docDirs[fl.docDirCount] = _free(fl.docDirs[fl.docDirCount]);
02200     return fl.processingFailed;
02201 }
02202 /*@=boundswrite@*/
02203 
02204 void initSourceHeader(Spec spec)
02205 {
02206     HeaderIterator hi;
02207     int_32 tag, type, count;
02208     const void * ptr;
02209 
02210     spec->sourceHeader = headerNew();
02211     /* Only specific tags are added to the source package header */
02212     /*@-branchstate@*/
02213     for (hi = headerInitIterator(spec->packages->header);
02214         headerNextIterator(hi, &tag, &type, &ptr, &count);
02215         ptr = headerFreeData(ptr, type))
02216     {
02217         switch (tag) {
02218         case RPMTAG_NAME:
02219         case RPMTAG_VERSION:
02220         case RPMTAG_RELEASE:
02221         case RPMTAG_EPOCH:
02222         case RPMTAG_SUMMARY:
02223         case RPMTAG_DESCRIPTION:
02224         case RPMTAG_PACKAGER:
02225         case RPMTAG_DISTRIBUTION:
02226         case RPMTAG_DISTURL:
02227         case RPMTAG_VENDOR:
02228         case RPMTAG_LICENSE:
02229         case RPMTAG_GROUP:
02230         case RPMTAG_OS:
02231         case RPMTAG_ARCH:
02232         case RPMTAG_CHANGELOGTIME:
02233         case RPMTAG_CHANGELOGNAME:
02234         case RPMTAG_CHANGELOGTEXT:
02235         case RPMTAG_URL:
02236         case HEADER_I18NTABLE:
02237             if (ptr)
02238                 (void)headerAddEntry(spec->sourceHeader, tag, type, ptr, count);
02239             /*@switchbreak@*/ break;
02240         default:
02241             /* do not copy */
02242             /*@switchbreak@*/ break;
02243         }
02244     }
02245     hi = headerFreeIterator(hi);
02246     /*@=branchstate@*/
02247 
02248     /* Add the build restrictions */
02249     /*@-branchstate@*/
02250     for (hi = headerInitIterator(spec->buildRestrictions);
02251         headerNextIterator(hi, &tag, &type, &ptr, &count);
02252         ptr = headerFreeData(ptr, type))
02253     {
02254         if (ptr)
02255             (void) headerAddEntry(spec->sourceHeader, tag, type, ptr, count);
02256     }
02257     hi = headerFreeIterator(hi);
02258     /*@=branchstate@*/
02259 
02260     if (spec->BANames && spec->BACount > 0) {
02261         (void) headerAddEntry(spec->sourceHeader, RPMTAG_BUILDARCHS,
02262                        RPM_STRING_ARRAY_TYPE,
02263                        spec->BANames, spec->BACount);
02264     }
02265 }
02266 
02267 int processSourceFiles(Spec spec)
02268 {
02269     struct Source *srcPtr;
02270     StringBuf sourceFiles;
02271     int x, isSpec = 1;
02272     struct FileList_s fl;
02273     char *s, **files, **fp;
02274     Package pkg;
02275 
02276     sourceFiles = newStringBuf();
02277 
02278     /* XXX
02279      * XXX This is where the source header for noarch packages needs
02280      * XXX to be initialized.
02281      */
02282     if (spec->sourceHeader == NULL)
02283         initSourceHeader(spec);
02284 
02285     /* Construct the file list and source entries */
02286     appendLineStringBuf(sourceFiles, spec->specFile);
02287     if (spec->sourceHeader != NULL)
02288     for (srcPtr = spec->sources; srcPtr != NULL; srcPtr = srcPtr->next) {
02289         if (srcPtr->flags & RPMBUILD_ISSOURCE) {
02290             (void) headerAddOrAppendEntry(spec->sourceHeader, RPMTAG_SOURCE,
02291                                    RPM_STRING_ARRAY_TYPE, &srcPtr->source, 1);
02292             if (srcPtr->flags & RPMBUILD_ISNO) {
02293                 (void) headerAddOrAppendEntry(spec->sourceHeader, RPMTAG_NOSOURCE,
02294                                        RPM_INT32_TYPE, &srcPtr->num, 1);
02295             }
02296         }
02297         if (srcPtr->flags & RPMBUILD_ISPATCH) {
02298             (void) headerAddOrAppendEntry(spec->sourceHeader, RPMTAG_PATCH,
02299                                    RPM_STRING_ARRAY_TYPE, &srcPtr->source, 1);
02300             if (srcPtr->flags & RPMBUILD_ISNO) {
02301                 (void) headerAddOrAppendEntry(spec->sourceHeader, RPMTAG_NOPATCH,
02302                                        RPM_INT32_TYPE, &srcPtr->num, 1);
02303             }
02304         }
02305 
02306       { const char * sfn;
02307         sfn = rpmGetPath( ((srcPtr->flags & RPMBUILD_ISNO) ? "!" : ""),
02308                 "%{_sourcedir}/", srcPtr->source, NULL);
02309         appendLineStringBuf(sourceFiles, sfn);
02310         sfn = _free(sfn);
02311       }
02312     }
02313 
02314     for (pkg = spec->packages; pkg != NULL; pkg = pkg->next) {
02315         for (srcPtr = pkg->icon; srcPtr != NULL; srcPtr = srcPtr->next) {
02316             const char * sfn;
02317             sfn = rpmGetPath( ((srcPtr->flags & RPMBUILD_ISNO) ? "!" : ""),
02318                 "%{_sourcedir}/", srcPtr->source, NULL);
02319             appendLineStringBuf(sourceFiles, sfn);
02320             sfn = _free(sfn);
02321         }
02322     }
02323 
02324     spec->sourceCpioList = NULL;
02325 
02326     fl.fileList = xcalloc((spec->numSources + 1), sizeof(*fl.fileList));
02327     fl.processingFailed = 0;
02328     fl.fileListRecsUsed = 0;
02329     fl.totalFileSize = 0;
02330     fl.prefix = NULL;
02331     fl.buildRootURL = NULL;
02332 
02333     s = getStringBuf(sourceFiles);
02334     files = splitString(s, strlen(s), '\n');
02335 
02336     /* The first source file is the spec file */
02337     x = 0;
02338     for (fp = files; *fp != NULL; fp++) {
02339         const char * diskURL, *diskPath;
02340         FileListRec flp;
02341 
02342         diskURL = *fp;
02343         SKIPSPACE(diskURL);
02344         if (! *diskURL)
02345             continue;
02346 
02347         flp = &fl.fileList[x];
02348 
02349         flp->flags = isSpec ? RPMFILE_SPECFILE : 0;
02350         /* files with leading ! are no source files */
02351         if (*diskURL == '!') {
02352             flp->flags |= RPMFILE_GHOST;
02353             diskURL++;
02354         }
02355 
02356         (void) urlPath(diskURL, &diskPath);
02357 
02358         flp->diskURL = xstrdup(diskURL);
02359         diskPath = strrchr(diskPath, '/');
02360         if (diskPath)
02361             diskPath++;
02362         else
02363             diskPath = diskURL;
02364 
02365         flp->fileURL = xstrdup(diskPath);
02366         flp->verifyFlags = RPMVERIFY_ALL;
02367 
02368         if (Stat(diskURL, &flp->fl_st)) {
02369             rpmError(RPMERR_BADSPEC, _("Bad file: %s: %s\n"),
02370                 diskURL, strerror(errno));
02371             fl.processingFailed = 1;
02372         }
02373 
02374         flp->uname = getUname(flp->fl_uid);
02375         flp->gname = getGname(flp->fl_gid);
02376         flp->langs = xstrdup("");
02377         
02378         fl.totalFileSize += flp->fl_size;
02379         
02380         if (! (flp->uname && flp->gname)) {
02381             rpmError(RPMERR_BADSPEC, _("Bad owner/group: %s\n"), diskURL);
02382             fl.processingFailed = 1;
02383         }
02384 
02385         isSpec = 0;
02386         x++;
02387     }
02388     fl.fileListRecsUsed = x;
02389     freeSplitString(files);
02390 
02391     if (! fl.processingFailed) {
02392         if (spec->sourceHeader != NULL)
02393             genCpioListAndHeader(&fl, &spec->sourceCpioList,
02394                         spec->sourceHeader, 1);
02395     }
02396 
02397     sourceFiles = freeStringBuf(sourceFiles);
02398     fl.fileList = freeFileList(fl.fileList, fl.fileListRecsUsed);
02399     return fl.processingFailed;
02400 }
02401 
02407 static int checkFiles(StringBuf fileList)
02408         /*@globals rpmGlobalMacroContext, h_errno, fileSystem, internalState @*/
02409         /*@modifies rpmGlobalMacroContext, fileSystem, internalState @*/
02410 {
02411 /*@-readonlytrans@*/
02412     static const char * av_ckfile[] = { "%{?__check_files}", NULL };
02413 /*@=readonlytrans@*/
02414     StringBuf sb_stdout = NULL;
02415     const char * s;
02416     int rc;
02417     
02418     s = rpmExpand(av_ckfile[0], NULL);
02419     if (!(s && *s)) {
02420         rc = -1;
02421         goto exit;
02422     }
02423     rc = 0;
02424 
02425     rpmMessage(RPMMESS_NORMAL, _("Checking for unpackaged file(s): %s\n"), s);
02426 
02427 /*@-boundswrite@*/
02428     rc = rpmfcExec(av_ckfile, fileList, &sb_stdout, 0);
02429 /*@=boundswrite@*/
02430     if (rc < 0)
02431         goto exit;
02432     
02433     if (sb_stdout) {
02434         int _unpackaged_files_terminate_build =
02435                 rpmExpandNumeric("%{?_unpackaged_files_terminate_build}");
02436         const char * t;
02437 
02438         t = getStringBuf(sb_stdout);
02439         if ((*t != '\0') && (*t != '\n')) {
02440             rc = (_unpackaged_files_terminate_build) ? 1 : 0;
02441             rpmMessage((rc ? RPMMESS_ERROR : RPMMESS_WARNING),
02442                 _("Installed (but unpackaged) file(s) found:\n%s"), t);
02443         }
02444     }
02445     
02446 exit:
02447     sb_stdout = freeStringBuf(sb_stdout);
02448     s = _free(s);
02449     return rc;
02450 }
02451 
02452 /*@-incondefs@*/
02453 int processBinaryFiles(Spec spec, int installSpecialDoc, int test)
02454         /*@globals check_fileList @*/
02455         /*@modifies check_fileList @*/
02456 {
02457     Package pkg;
02458     int res = 0;
02459     
02460     check_fileList = newStringBuf();
02461     
02462     for (pkg = spec->packages; pkg != NULL; pkg = pkg->next) {
02463         const char *n, *v, *r;
02464         int rc;
02465 
02466         if (pkg->fileList == NULL)
02467             continue;
02468 
02469         (void) headerNVR(pkg->header, &n, &v, &r);
02470         rpmMessage(RPMMESS_NORMAL, _("Processing files: %s-%s-%s\n"), n, v, r);
02471                    
02472         if ((rc = processPackageFiles(spec, pkg, installSpecialDoc, test)))
02473             res = rc;
02474 
02475         (void) rpmfcGenerateDepends(spec, pkg);
02476 
02477     }
02478 
02479     /* Now we have in fileList list of files from all packages.
02480      * We pass it to a script which does the work of finding missing
02481      * and duplicated files.
02482      */
02483     
02484     if (res == 0)  {
02485         if (checkFiles(check_fileList) > 0)
02486             res = 1;
02487     }
02488     
02489     check_fileList = freeStringBuf(check_fileList);
02490     
02491     return res;
02492 }
02493 /*@=incondefs@*/

Generated on Mon Mar 5 13:43:50 2007 for rpm by  doxygen 1.5.1