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

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

Generated on Thu Sep 23 13:04:05 2004 for rpm by doxygen 1.3.4