Main Page | Modules | Data Structures | Directories | File List | Data Fields | Globals | Related Pages

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

Generated on Wed Jun 15 10:22:52 2005 for rpm by  doxygen 1.3.9.1