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 
00210 /* strtokWithQuotes() modified from glibc strtok() */
00211 /* Copyright (C) 1991, 1996 Free Software Foundation, Inc.
00212    This file is part of the GNU C Library.
00213 
00214    The GNU C Library is free software; you can redistribute it and/or
00215    modify it under the terms of the GNU Library General Public License as
00216    published by the Free Software Foundation; either version 2 of the
00217    License, or (at your option) any later version.
00218 
00219    The GNU C Library is distributed in the hope that it will be useful,
00220    but WITHOUT ANY WARRANTY; without even the implied warranty of
00221    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00222    Library General Public License for more details.
00223 
00224    You should have received a copy of the GNU Library General Public
00225    License along with the GNU C Library; see the file COPYING.LIB.  If
00226    not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
00227    Boston, MA 02111-1307, USA.  */
00228 
00231 /*@-boundswrite@*/
00232 static char *strtokWithQuotes(char *s, char *delim)
00233         /*@modifies *s @*/
00234 {
00235     static char *olds = NULL;
00236     char *token;
00237 
00238     if (s == NULL) {
00239         s = olds;
00240     }
00241 
00242     /* Skip leading delimiters */
00243     s += strspn(s, delim);
00244     if (*s == '\0') {
00245         return NULL;
00246     }
00247 
00248     /* Find the end of the token.  */
00249     token = s;
00250     if (*token == '"') {
00251         token++;
00252         /* Find next " char */
00253         s = strchr(token, '"');
00254     } else {
00255         s = strpbrk(token, delim);
00256     }
00257 
00258     /* Terminate it */
00259     if (s == NULL) {
00260         /* This token finishes the string */
00261         olds = strchr(token, '\0');
00262     } else {
00263         /* Terminate the token and make olds point past it */
00264         *s = '\0';
00265         olds = s+1;
00266     }
00267 
00268     /*@-retalias -temptrans @*/
00269     return token;
00270     /*@=retalias =temptrans @*/
00271 }
00272 /*@=boundswrite@*/
00273 
00276 static void timeCheck(int tc, Header h)
00277         /*@globals internalState @*/
00278         /*@modifies internalState @*/
00279 {
00280     HGE_t hge = (HGE_t)headerGetEntryMinMemory;
00281     HFD_t hfd = headerFreeData;
00282     int * mtime;
00283     const char ** files;
00284     rpmTagType fnt;
00285     int count, x;
00286     time_t currentTime = time(NULL);
00287 
00288     x = hge(h, RPMTAG_OLDFILENAMES, &fnt, (void **) &files, &count);
00289     x = hge(h, RPMTAG_FILEMTIMES, NULL, (void **) &mtime, NULL);
00290     
00291 /*@-boundsread@*/
00292     for (x = 0; x < count; x++) {
00293         if ((currentTime - mtime[x]) > tc)
00294             rpmMessage(RPMMESS_WARNING, _("TIMECHECK failure: %s\n"), files[x]);
00295     }
00296     files = hfd(files, fnt);
00297 /*@=boundsread@*/
00298 }
00299 
00302 typedef struct VFA {
00303 /*@observer@*/ /*@null@*/ const char * attribute;
00304     int not;
00305     int flag;
00306 } VFA_t;
00307 
00310 /*@-exportlocal -exportheadervar@*/
00311 /*@unchecked@*/
00312 VFA_t verifyAttrs[] = {
00313     { "md5",    0,      RPMVERIFY_MD5 },
00314     { "size",   0,      RPMVERIFY_FILESIZE },
00315     { "link",   0,      RPMVERIFY_LINKTO },
00316     { "user",   0,      RPMVERIFY_USER },
00317     { "group",  0,      RPMVERIFY_GROUP },
00318     { "mtime",  0,      RPMVERIFY_MTIME },
00319     { "mode",   0,      RPMVERIFY_MODE },
00320     { "rdev",   0,      RPMVERIFY_RDEV },
00321     { NULL, 0,  0 }
00322 };
00323 /*@=exportlocal =exportheadervar@*/
00324 
00331 /*@-boundswrite@*/
00332 static int parseForVerify(char * buf, FileList fl)
00333         /*@modifies buf, fl->processingFailed,
00334                 fl->currentVerifyFlags, fl->defVerifyFlags,
00335                 fl->currentSpecdFlags, fl->defSpecdFlags @*/
00336 {
00337     char *p, *pe, *q;
00338     const char *name;
00339     int *resultVerify;
00340     int negated;
00341     int verifyFlags;
00342     specdFlags * specdFlags;
00343 
00344     if ((p = strstr(buf, (name = "%verify"))) != NULL) {
00345         resultVerify = &(fl->currentVerifyFlags);
00346         specdFlags = &fl->currentSpecdFlags;
00347     } else if ((p = strstr(buf, (name = "%defverify"))) != NULL) {
00348         resultVerify = &(fl->defVerifyFlags);
00349         specdFlags = &fl->defSpecdFlags;
00350     } else
00351         return 0;
00352 
00353     for (pe = p; (pe-p) < strlen(name); pe++)
00354         *pe = ' ';
00355 
00356     SKIPSPACE(pe);
00357 
00358     if (*pe != '(') {
00359         rpmError(RPMERR_BADSPEC, _("Missing '(' in %s %s\n"), name, pe);
00360         fl->processingFailed = 1;
00361         return RPMERR_BADSPEC;
00362     }
00363 
00364     /* Bracket %*verify args */
00365     *pe++ = ' ';
00366     for (p = pe; *pe && *pe != ')'; pe++)
00367         {};
00368 
00369     if (*pe == '\0') {
00370         rpmError(RPMERR_BADSPEC, _("Missing ')' in %s(%s\n"), name, p);
00371         fl->processingFailed = 1;
00372         return RPMERR_BADSPEC;
00373     }
00374 
00375     /* Localize. Erase parsed string */
00376     q = alloca((pe-p) + 1);
00377     strncpy(q, p, pe-p);
00378     q[pe-p] = '\0';
00379     while (p <= pe)
00380         *p++ = ' ';
00381 
00382     negated = 0;
00383     verifyFlags = RPMVERIFY_NONE;
00384 
00385     for (p = q; *p != '\0'; p = pe) {
00386         SKIPWHITE(p);
00387         if (*p == '\0')
00388             break;
00389         pe = p;
00390         SKIPNONWHITE(pe);
00391         if (*pe != '\0')
00392             *pe++ = '\0';
00393 
00394         {   VFA_t *vfa;
00395             for (vfa = verifyAttrs; vfa->attribute != NULL; vfa++) {
00396                 if (strcmp(p, vfa->attribute))
00397                     /*@innercontinue@*/ continue;
00398                 verifyFlags |= vfa->flag;
00399                 /*@innerbreak@*/ break;
00400             }
00401             if (vfa->attribute)
00402                 continue;
00403         }
00404 
00405         if (!strcmp(p, "not")) {
00406             negated ^= 1;
00407         } else {
00408             rpmError(RPMERR_BADSPEC, _("Invalid %s token: %s\n"), name, p);
00409             fl->processingFailed = 1;
00410             return RPMERR_BADSPEC;
00411         }
00412     }
00413 
00414     *resultVerify = negated ? ~(verifyFlags) : verifyFlags;
00415     *specdFlags |= SPECD_VERIFY;
00416 
00417     return 0;
00418 }
00419 /*@=boundswrite@*/
00420 
00421 #define isAttrDefault(_ars)     ((_ars)[0] == '-' && (_ars)[1] == '\0')
00422 
00429 /*@-boundswrite@*/
00430 static int parseForDev(char * buf, FileList fl)
00431         /*@modifies buf, fl->processingFailed,
00432                 fl->noGlob, fl->devtype, fl->devmajor, fl->devminor @*/
00433 {
00434     const char * name;
00435     const char * errstr = NULL;
00436     char *p, *pe, *q;
00437     int rc = RPMERR_BADSPEC;    /* assume error */
00438 
00439     if ((p = strstr(buf, (name = "%dev"))) == NULL)
00440         return 0;
00441 
00442     for (pe = p; (pe-p) < strlen(name); pe++)
00443         *pe = ' ';
00444     SKIPSPACE(pe);
00445 
00446     if (*pe != '(') {
00447         errstr = "'('";
00448         goto exit;
00449     }
00450 
00451     /* Bracket %dev args */
00452     *pe++ = ' ';
00453     for (p = pe; *pe && *pe != ')'; pe++)
00454         {};
00455     if (*pe != ')') {
00456         errstr = "')'";
00457         goto exit;
00458     }
00459 
00460     /* Localize. Erase parsed string */
00461     q = alloca((pe-p) + 1);
00462     strncpy(q, p, pe-p);
00463     q[pe-p] = '\0';
00464     while (p <= pe)
00465         *p++ = ' ';
00466 
00467     p = q; SKIPWHITE(p);
00468     pe = p; SKIPNONWHITE(pe); if (*pe != '\0') *pe++ = '\0';
00469     if (*p == 'b')
00470         fl->devtype = 'b';
00471     else if (*p == 'c')
00472         fl->devtype = 'c';
00473     else {
00474         errstr = "devtype";
00475         goto exit;
00476     }
00477 
00478     p = pe; SKIPWHITE(p);
00479     pe = p; SKIPNONWHITE(pe); if (*pe != '\0') *pe++ = '\0';
00480     for (pe = p; *pe && xisdigit(*pe); pe++)
00481         {} ;
00482     if (*pe == '\0') {
00483         fl->devmajor = atoi(p);
00484         /*@-unsignedcompare @*/ /* LCL: ge is ok */
00485         if (!(fl->devmajor >= 0 && fl->devmajor < 256)) {
00486             errstr = "devmajor";
00487             goto exit;
00488         }
00489         /*@=unsignedcompare @*/
00490         pe++;
00491     } else {
00492         errstr = "devmajor";
00493         goto exit;
00494     }
00495 
00496     p = pe; SKIPWHITE(p);
00497     pe = p; SKIPNONWHITE(pe); if (*pe != '\0') *pe++ = '\0';
00498     for (pe = p; *pe && xisdigit(*pe); pe++)
00499         {} ;
00500     if (*pe == '\0') {
00501         fl->devminor = atoi(p);
00502         if (!(fl->devminor >= 0 && fl->devminor < 256)) {
00503             errstr = "devminor";
00504             goto exit;
00505         }
00506         pe++;
00507     } else {
00508         errstr = "devminor";
00509         goto exit;
00510     }
00511 
00512     fl->noGlob = 1;
00513 
00514     rc = 0;
00515 
00516 exit:
00517     if (rc) {
00518         rpmError(RPMERR_BADSPEC, _("Missing %s in %s %s\n"), errstr, name, p);
00519         fl->processingFailed = 1;
00520     }
00521     return rc;
00522 }
00523 /*@=boundswrite@*/
00524 
00531 /*@-boundswrite@*/
00532 static int parseForAttr(char * buf, FileList fl)
00533         /*@modifies buf, fl->processingFailed,
00534                 fl->cur_ar, fl->def_ar,
00535                 fl->currentSpecdFlags, fl->defSpecdFlags @*/
00536 {
00537     const char *name;
00538     char *p, *pe, *q;
00539     int x;
00540     struct AttrRec_s arbuf;
00541     AttrRec ar = &arbuf, ret_ar;
00542     specdFlags * specdFlags;
00543 
00544     if ((p = strstr(buf, (name = "%attr"))) != NULL) {
00545         ret_ar = &(fl->cur_ar);
00546         specdFlags = &fl->currentSpecdFlags;
00547     } else if ((p = strstr(buf, (name = "%defattr"))) != NULL) {
00548         ret_ar = &(fl->def_ar);
00549         specdFlags = &fl->defSpecdFlags;
00550     } else
00551         return 0;
00552 
00553     for (pe = p; (pe-p) < strlen(name); pe++)
00554         *pe = ' ';
00555 
00556     SKIPSPACE(pe);
00557 
00558     if (*pe != '(') {
00559         rpmError(RPMERR_BADSPEC, _("Missing '(' in %s %s\n"), name, pe);
00560         fl->processingFailed = 1;
00561         return RPMERR_BADSPEC;
00562     }
00563 
00564     /* Bracket %*attr args */
00565     *pe++ = ' ';
00566     for (p = pe; *pe && *pe != ')'; pe++)
00567         {};
00568 
00569     if (ret_ar == &(fl->def_ar)) {      /* %defattr */
00570         q = pe;
00571         q++;
00572         SKIPSPACE(q);
00573         if (*q != '\0') {
00574             rpmError(RPMERR_BADSPEC,
00575                      _("Non-white space follows %s(): %s\n"), name, q);
00576             fl->processingFailed = 1;
00577             return RPMERR_BADSPEC;
00578         }
00579     }
00580 
00581     /* Localize. Erase parsed string */
00582     q = alloca((pe-p) + 1);
00583     strncpy(q, p, pe-p);
00584     q[pe-p] = '\0';
00585     while (p <= pe)
00586         *p++ = ' ';
00587 
00588     nullAttrRec(ar);
00589 
00590     p = q; SKIPWHITE(p);
00591     if (*p != '\0') {
00592         pe = p; SKIPNONWHITE(pe); if (*pe != '\0') *pe++ = '\0';
00593         ar->ar_fmodestr = p;
00594         p = pe; SKIPWHITE(p);
00595     }
00596     if (*p != '\0') {
00597         pe = p; SKIPNONWHITE(pe); if (*pe != '\0') *pe++ = '\0';
00598         ar->ar_user = p;
00599         p = pe; SKIPWHITE(p);
00600     }
00601     if (*p != '\0') {
00602         pe = p; SKIPNONWHITE(pe); if (*pe != '\0') *pe++ = '\0';
00603         ar->ar_group = p;
00604         p = pe; SKIPWHITE(p);
00605     }
00606     if (*p != '\0' && ret_ar == &(fl->def_ar)) {        /* %defattr */
00607         pe = p; SKIPNONWHITE(pe); if (*pe != '\0') *pe++ = '\0';
00608         ar->ar_dmodestr = p;
00609         p = pe; SKIPWHITE(p);
00610     }
00611 
00612     if (!(ar->ar_fmodestr && ar->ar_user && ar->ar_group) || *p != '\0') {
00613         rpmError(RPMERR_BADSPEC, _("Bad syntax: %s(%s)\n"), name, q);
00614         fl->processingFailed = 1;
00615         return RPMERR_BADSPEC;
00616     }
00617 
00618     /* Do a quick test on the mode argument and adjust for "-" */
00619     if (ar->ar_fmodestr && !isAttrDefault(ar->ar_fmodestr)) {
00620         unsigned int ui;
00621         x = sscanf(ar->ar_fmodestr, "%o", &ui);
00622         if ((x == 0) || (ar->ar_fmode & ~MYALLPERMS)) {
00623             rpmError(RPMERR_BADSPEC, _("Bad mode spec: %s(%s)\n"), name, q);
00624             fl->processingFailed = 1;
00625             return RPMERR_BADSPEC;
00626         }
00627         ar->ar_fmode = ui;
00628     } else
00629         ar->ar_fmodestr = NULL;
00630 
00631     if (ar->ar_dmodestr && !isAttrDefault(ar->ar_dmodestr)) {
00632         unsigned int ui;
00633         x = sscanf(ar->ar_dmodestr, "%o", &ui);
00634         if ((x == 0) || (ar->ar_dmode & ~MYALLPERMS)) {
00635             rpmError(RPMERR_BADSPEC, _("Bad dirmode spec: %s(%s)\n"), name, q);
00636             fl->processingFailed = 1;
00637             return RPMERR_BADSPEC;
00638         }
00639         ar->ar_dmode = ui;
00640     } else
00641         ar->ar_dmodestr = NULL;
00642 
00643     if (!(ar->ar_user && !isAttrDefault(ar->ar_user)))
00644         ar->ar_user = NULL;
00645 
00646     if (!(ar->ar_group && !isAttrDefault(ar->ar_group)))
00647         ar->ar_group = NULL;
00648 
00649     dupAttrRec(ar, ret_ar);
00650 
00651     /* XXX fix all this */
00652     *specdFlags |= SPECD_UID | SPECD_GID | SPECD_FILEMODE | SPECD_DIRMODE;
00653     
00654     return 0;
00655 }
00656 /*@=boundswrite@*/
00657 
00664 /*@-boundswrite@*/
00665 static int parseForConfig(char * buf, FileList fl)
00666         /*@modifies buf, fl->processingFailed, fl->currentFlags @*/
00667 {
00668     char *p, *pe, *q;
00669     const char *name;
00670 
00671     if ((p = strstr(buf, (name = "%config"))) == NULL)
00672         return 0;
00673 
00674     fl->currentFlags |= RPMFILE_CONFIG;
00675 
00676     /* Erase "%config" token. */
00677     for (pe = p; (pe-p) < strlen(name); pe++)
00678         *pe = ' ';
00679     SKIPSPACE(pe);
00680     if (*pe != '(')
00681         return 0;
00682 
00683     /* Bracket %config args */
00684     *pe++ = ' ';
00685     for (p = pe; *pe && *pe != ')'; pe++)
00686         {};
00687 
00688     if (*pe == '\0') {
00689         rpmError(RPMERR_BADSPEC, _("Missing ')' in %s(%s\n"), name, p);
00690         fl->processingFailed = 1;
00691         return RPMERR_BADSPEC;
00692     }
00693 
00694     /* Localize. Erase parsed string. */
00695     q = alloca((pe-p) + 1);
00696     strncpy(q, p, pe-p);
00697     q[pe-p] = '\0';
00698     while (p <= pe)
00699         *p++ = ' ';
00700 
00701     for (p = q; *p != '\0'; p = pe) {
00702         SKIPWHITE(p);
00703         if (*p == '\0')
00704             break;
00705         pe = p;
00706         SKIPNONWHITE(pe);
00707         if (*pe != '\0')
00708             *pe++ = '\0';
00709         if (!strcmp(p, "missingok")) {
00710             fl->currentFlags |= RPMFILE_MISSINGOK;
00711         } else if (!strcmp(p, "noreplace")) {
00712             fl->currentFlags |= RPMFILE_NOREPLACE;
00713         } else {
00714             rpmError(RPMERR_BADSPEC, _("Invalid %s token: %s\n"), name, p);
00715             fl->processingFailed = 1;
00716             return RPMERR_BADSPEC;
00717         }
00718     }
00719 
00720     return 0;
00721 }
00722 /*@=boundswrite@*/
00723 
00726 static int langCmp(const void * ap, const void * bp)
00727         /*@*/
00728 {
00729 /*@-boundsread@*/
00730     return strcmp(*(const char **)ap, *(const char **)bp);
00731 /*@=boundsread@*/
00732 }
00733 
00740 /*@-bounds@*/
00741 static int parseForLang(char * buf, FileList fl)
00742         /*@modifies buf, fl->processingFailed,
00743                 fl->currentLangs, fl->nLangs @*/
00744 {
00745     char *p, *pe, *q;
00746     const char *name;
00747 
00748   while ((p = strstr(buf, (name = "%lang"))) != NULL) {
00749 
00750     for (pe = p; (pe-p) < strlen(name); pe++)
00751         *pe = ' ';
00752     SKIPSPACE(pe);
00753 
00754     if (*pe != '(') {
00755         rpmError(RPMERR_BADSPEC, _("Missing '(' in %s %s\n"), name, pe);
00756         fl->processingFailed = 1;
00757         return RPMERR_BADSPEC;
00758     }
00759 
00760     /* Bracket %lang args */
00761     *pe++ = ' ';
00762     for (pe = p; *pe && *pe != ')'; pe++)
00763         {};
00764 
00765     if (*pe == '\0') {
00766         rpmError(RPMERR_BADSPEC, _("Missing ')' in %s(%s\n"), name, p);
00767         fl->processingFailed = 1;
00768         return RPMERR_BADSPEC;
00769     }
00770 
00771     /* Localize. Erase parsed string. */
00772     q = alloca((pe-p) + 1);
00773     strncpy(q, p, pe-p);
00774     q[pe-p] = '\0';
00775     while (p <= pe)
00776         *p++ = ' ';
00777 
00778     /* Parse multiple arguments from %lang */
00779     for (p = q; *p != '\0'; p = pe) {
00780         char *newp;
00781         size_t np;
00782         int i;
00783 
00784         SKIPWHITE(p);
00785         pe = p;
00786         SKIPNONWHITE(pe);
00787 
00788         np = pe - p;
00789         
00790         /* Sanity check on locale lengths */
00791         if (np < 1 || (np == 1 && *p != 'C') || np >= 32) {
00792             rpmError(RPMERR_BADSPEC,
00793                 _("Unusual locale length: \"%.*s\" in %%lang(%s)\n"),
00794                 (int)np, p, q);
00795             fl->processingFailed = 1;
00796             return RPMERR_BADSPEC;
00797         }
00798 
00799         /* Check for duplicate locales */
00800         if (fl->currentLangs != NULL)
00801         for (i = 0; i < fl->nLangs; i++) {
00802             if (strncmp(fl->currentLangs[i], p, np))
00803                 /*@innercontinue@*/ continue;
00804             rpmError(RPMERR_BADSPEC, _("Duplicate locale %.*s in %%lang(%s)\n"),
00805                 (int)np, p, q);
00806             fl->processingFailed = 1;
00807             return RPMERR_BADSPEC;
00808         }
00809 
00810         /* Add new locale */
00811         fl->currentLangs = xrealloc(fl->currentLangs,
00812                                 (fl->nLangs + 1) * sizeof(*fl->currentLangs));
00813         newp = xmalloc( np+1 );
00814         strncpy(newp, p, np);
00815         newp[np] = '\0';
00816         fl->currentLangs[fl->nLangs++] = newp;
00817         if (*pe == ',') pe++;   /* skip , if present */
00818     }
00819   }
00820 
00821     /* Insure that locales are sorted. */
00822     if (fl->currentLangs)
00823         qsort(fl->currentLangs, fl->nLangs, sizeof(*fl->currentLangs), langCmp);
00824 
00825     return 0;
00826 }
00827 /*@=bounds@*/
00828 
00831 /*@-boundswrite@*/
00832 static int parseForRegexLang(const char * fileName, /*@out@*/ char ** lang)
00833         /*@globals rpmGlobalMacroContext @*/
00834         /*@modifies *lang, rpmGlobalMacroContext @*/
00835 {
00836     static int initialized = 0;
00837     static int hasRegex = 0;
00838     static regex_t compiledPatt;
00839     static char buf[BUFSIZ];
00840     int x;
00841     regmatch_t matches[2];
00842     const char *s;
00843 
00844     if (! initialized) {
00845         const char *patt = rpmExpand("%{?_langpatt}", NULL);
00846         int rc = 0;
00847         if (!(patt && *patt != '\0'))
00848             rc = 1;
00849         else if (regcomp(&compiledPatt, patt, REG_EXTENDED))
00850             rc = -1;
00851         patt = _free(patt);
00852         if (rc)
00853             return rc;
00854         hasRegex = 1;
00855         initialized = 1;
00856     }
00857     
00858     memset(matches, 0, sizeof(matches));
00859     if (! hasRegex || regexec(&compiledPatt, fileName, 2, matches, REG_NOTEOL))
00860         return 1;
00861 
00862     /* Got match */
00863     s = fileName + matches[1].rm_eo - 1;
00864     x = matches[1].rm_eo - matches[1].rm_so;
00865     buf[x] = '\0';
00866     while (x) {
00867         buf[--x] = *s--;
00868     }
00869     if (lang)
00870         *lang = buf;
00871     return 0;
00872 }
00873 /*@=boundswrite@*/
00874 
00877 /*@-exportlocal -exportheadervar@*/
00878 /*@unchecked@*/
00879 VFA_t virtualFileAttributes[] = {
00880         { "%dir",       0,      0 },    /* XXX why not RPMFILE_DIR? */
00881         { "%doc",       0,      RPMFILE_DOC },
00882         { "%ghost",     0,      RPMFILE_GHOST },
00883         { "%exclude",   0,      RPMFILE_EXCLUDE },
00884         { "%readme",    0,      RPMFILE_README },
00885         { "%license",   0,      RPMFILE_LICENSE },
00886         { "%pubkey",    0,      RPMFILE_PUBKEY },
00887 
00888 #if WHY_NOT
00889         { "%icon",      0,      RPMFILE_ICON },
00890         { "%spec",      0,      RPMFILE_SPEC },
00891         { "%config",    0,      RPMFILE_CONFIG },
00892         { "%missingok", 0,      RPMFILE_CONFIG|RPMFILE_MISSINGOK },
00893         { "%noreplace", 0,      RPMFILE_CONFIG|RPMFILE_NOREPLACE },
00894 #endif
00895 
00896         { NULL, 0, 0 }
00897 };
00898 /*@=exportlocal =exportheadervar@*/
00899 
00909 /*@-boundswrite@*/
00910 static int parseForSimple(/*@unused@*/Spec spec, Package pkg, char * buf,
00911                           FileList fl, /*@out@*/ const char ** fileName)
00912         /*@globals rpmGlobalMacroContext @*/
00913         /*@modifies buf, fl->processingFailed, *fileName,
00914                 fl->currentFlags,
00915                 fl->docDirs, fl->docDirCount, fl->isDir,
00916                 fl->passedSpecialDoc, fl->isSpecialDoc,
00917                 pkg->specialDoc, rpmGlobalMacroContext @*/
00918 {
00919     char *s, *t;
00920     int res, specialDoc = 0;
00921     char specialDocBuf[BUFSIZ];
00922 
00923     specialDocBuf[0] = '\0';
00924     *fileName = NULL;
00925     res = 0;
00926 
00927     t = buf;
00928     while ((s = strtokWithQuotes(t, " \t\n")) != NULL) {
00929         t = NULL;
00930         if (!strcmp(s, "%docdir")) {
00931             s = strtokWithQuotes(NULL, " \t\n");
00932             if (fl->docDirCount == MAXDOCDIR) {
00933                 rpmError(RPMERR_INTERNAL, _("Hit limit for %%docdir\n"));
00934                 fl->processingFailed = 1;
00935                 res = 1;
00936             }
00937             fl->docDirs[fl->docDirCount++] = xstrdup(s);
00938             if (strtokWithQuotes(NULL, " \t\n")) {
00939                 rpmError(RPMERR_INTERNAL, _("Only one arg for %%docdir\n"));
00940                 fl->processingFailed = 1;
00941                 res = 1;
00942             }
00943             break;
00944         }
00945 
00946     /* Set flags for virtual file attributes */
00947     {   VFA_t *vfa;
00948         for (vfa = virtualFileAttributes; vfa->attribute != NULL; vfa++) {
00949             if (strcmp(s, vfa->attribute))
00950                 /*@innercontinue@*/ continue;
00951             if (!vfa->flag) {
00952                 if (!strcmp(s, "%dir"))
00953                     fl->isDir = 1;      /* XXX why not RPMFILE_DIR? */
00954             } else {
00955                 if (vfa->not)
00956                     fl->currentFlags &= ~vfa->flag;
00957                 else
00958                     fl->currentFlags |= vfa->flag;
00959             }
00960 
00961             /*@innerbreak@*/ break;
00962         }
00963         /* if we got an attribute, continue with next token */
00964         if (vfa->attribute != NULL)
00965             continue;
00966     }
00967 
00968         if (*fileName) {
00969             /* We already got a file -- error */
00970             rpmError(RPMERR_BADSPEC, _("Two files on one line: %s\n"),
00971                 *fileName);
00972             fl->processingFailed = 1;
00973             res = 1;
00974         }
00975 
00976         /*@-branchstate@*/
00977         if (*s != '/') {
00978             if (fl->currentFlags & RPMFILE_DOC) {
00979                 specialDoc = 1;
00980                 strcat(specialDocBuf, " ");
00981                 strcat(specialDocBuf, s);
00982             } else if (fl->currentFlags & (RPMFILE_PUBKEY|RPMFILE_ICON)) {
00983                 *fileName = s;
00984             } else {
00985                 /* not in %doc, does not begin with / -- error */
00986                 rpmError(RPMERR_BADSPEC,
00987                     _("File must begin with \"/\": %s\n"), s);
00988                 fl->processingFailed = 1;
00989                 res = 1;
00990             }
00991         } else {
00992             *fileName = s;
00993         }
00994         /*@=branchstate@*/
00995     }
00996 
00997     if (specialDoc) {
00998         if (*fileName || (fl->currentFlags & ~(RPMFILE_DOC))) {
00999             rpmError(RPMERR_BADSPEC,
01000                      _("Can't mix special %%doc with other forms: %s\n"),
01001                      (*fileName ? *fileName : ""));
01002             fl->processingFailed = 1;
01003             res = 1;
01004         } else {
01005         /* XXX WATCHOUT: buf is an arg */
01006             {   const char *ddir, *n, *v;
01007 
01008                 (void) headerNVR(pkg->header, &n, &v, NULL);
01009 
01010                 ddir = rpmGetPath("%{_docdir}/", n, "-", v, NULL);
01011                 strcpy(buf, ddir);
01012                 ddir = _free(ddir);
01013             }
01014 
01015         /* XXX FIXME: this is easy to do as macro expansion */
01016 
01017             if (! fl->passedSpecialDoc) {
01018                 pkg->specialDoc = newStringBuf();
01019                 appendStringBuf(pkg->specialDoc, "DOCDIR=$RPM_BUILD_ROOT");
01020                 appendLineStringBuf(pkg->specialDoc, buf);
01021                 appendLineStringBuf(pkg->specialDoc, "export DOCDIR");
01022                 appendLineStringBuf(pkg->specialDoc, "rm -rf $DOCDIR");
01023                 appendLineStringBuf(pkg->specialDoc, MKDIR_P " $DOCDIR");
01024 
01025                 /*@-temptrans@*/
01026                 *fileName = buf;
01027                 /*@=temptrans@*/
01028                 fl->passedSpecialDoc = 1;
01029                 fl->isSpecialDoc = 1;
01030             }
01031 
01032             appendStringBuf(pkg->specialDoc, "cp -pr ");
01033             appendStringBuf(pkg->specialDoc, specialDocBuf);
01034             appendLineStringBuf(pkg->specialDoc, " $DOCDIR");
01035         }
01036     }
01037 
01038     return res;
01039 }
01040 /*@=boundswrite@*/
01041 
01044 static int compareFileListRecs(const void * ap, const void * bp)        /*@*/
01045 {
01046     const char *a = ((FileListRec)ap)->fileURL;
01047     const char *b = ((FileListRec)bp)->fileURL;
01048     return strcmp(a, b);
01049 }
01050 
01058 static int isDoc(FileList fl, const char * fileName)    /*@*/
01059 {
01060     int x = fl->docDirCount;
01061 
01062     while (x--) {
01063         if (strstr(fileName, fl->docDirs[x]) == fileName)
01064             return 1;
01065     }
01066     return 0;
01067 }
01068 
01075 static int checkHardLinks(FileList fl)
01076         /*@*/
01077 {
01078     FileListRec ilp, jlp;
01079     int i, j;
01080 
01081     for (i = 0;  i < fl->fileListRecsUsed; i++) {
01082         ilp = fl->fileList + i;
01083         if (!(S_ISREG(ilp->fl_mode) && ilp->fl_nlink > 1))
01084             continue;
01085 
01086         for (j = i + 1; j < fl->fileListRecsUsed; j++) {
01087             jlp = fl->fileList + j;
01088             if (!S_ISREG(jlp->fl_mode))
01089                 /*@innercontinue@*/ continue;
01090             if (ilp->fl_nlink != jlp->fl_nlink)
01091                 /*@innercontinue@*/ continue;
01092             if (ilp->fl_ino != jlp->fl_ino)
01093                 /*@innercontinue@*/ continue;
01094             if (ilp->fl_dev != jlp->fl_dev)
01095                 /*@innercontinue@*/ continue;
01096             return 1;
01097         }
01098     }
01099     return 0;
01100 }
01101 
01111 /*@-bounds@*/
01112 static void genCpioListAndHeader(/*@partial@*/ FileList fl,
01113                 rpmfi * fip, Header h, int isSrc)
01114         /*@globals rpmGlobalMacroContext, fileSystem, internalState @*/
01115         /*@modifies h, *fip, fl->processingFailed, fl->fileList,
01116                 rpmGlobalMacroContext, fileSystem, internalState @*/
01117 {
01118     int _addDotSlash = !(isSrc || rpmExpandNumeric("%{_noPayloadPrefix}"));
01119     int apathlen = 0;
01120     int dpathlen = 0;
01121     int skipLen = 0;
01122     size_t fnlen;
01123     FileListRec flp;
01124     char buf[BUFSIZ];
01125     int i;
01126     
01127     /* Sort the big list */
01128     qsort(fl->fileList, fl->fileListRecsUsed,
01129           sizeof(*(fl->fileList)), compareFileListRecs);
01130     
01131     /* Generate the header. */
01132     if (! isSrc) {
01133         skipLen = 1;
01134         if (fl->prefix)
01135             skipLen += strlen(fl->prefix);
01136     }
01137 
01138     for (i = 0, flp = fl->fileList; i < fl->fileListRecsUsed; i++, flp++) {
01139         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     }
01318 
01319     (void) headerAddEntry(h, RPMTAG_SIZE, RPM_INT32_TYPE,
01320                    &(fl->totalFileSize), 1);
01321 
01322     if (_addDotSlash)
01323         (void) rpmlibNeedsFeature(h, "PayloadFilesHavePrefix", "4.0-1");
01324 
01325     /* Choose how filenames are represented. */
01326     if (_noDirTokens)
01327         expandFilelist(h);
01328     else {
01329         compressFilelist(h);
01330         /* Binary packages with dirNames cannot be installed by legacy rpm. */
01331         (void) rpmlibNeedsFeature(h, "CompressedFileNames", "3.0.4-1");
01332     }
01333 
01334   { int scareMem = 0;
01335     rpmts ts = NULL;    /* XXX FIXME drill rpmts ts all the way down here */
01336     rpmfi fi = rpmfiNew(ts, h, RPMTAG_BASENAMES, scareMem);
01337     char * a, * d;
01338 
01339     if (fi == NULL) return;             /* XXX can't happen */
01340 
01341 /*@-onlytrans@*/
01342     fi->te = xcalloc(1, sizeof(*fi->te));
01343 /*@=onlytrans@*/
01344     fi->te->type = TR_ADDED;
01345 
01346     fi->dnl = _free(fi->dnl);
01347     fi->bnl = _free(fi->bnl);
01348     if (!scareMem) fi->dil = _free(fi->dil);
01349 
01350     fi->dnl = xmalloc(fi->fc * sizeof(*fi->dnl) + dpathlen);
01351     d = (char *)(fi->dnl + fi->fc);
01352     *d = '\0';
01353 
01354     fi->bnl = xmalloc(fi->fc * (sizeof(*fi->bnl) + sizeof(*fi->dil)));
01355 /*@-dependenttrans@*/ /* FIX: artifact of spoofing headerGetEntry */
01356     fi->dil = (!scareMem)
01357         ? xcalloc(sizeof(*fi->dil), fi->fc)
01358         : (int *)(fi->bnl + fi->fc);
01359 /*@=dependenttrans@*/
01360 
01361     fi->apath = xmalloc(fi->fc * sizeof(*fi->apath) + apathlen);
01362     a = (char *)(fi->apath + fi->fc);
01363     *a = '\0';
01364 
01365     fi->actions = xcalloc(sizeof(*fi->actions), fi->fc);
01366     fi->fmapflags = xcalloc(sizeof(*fi->fmapflags), fi->fc);
01367     fi->astriplen = 0;
01368     if (fl->buildRootURL)
01369         fi->astriplen = strlen(fl->buildRootURL);
01370     fi->striplen = 0;
01371     fi->fuser = NULL;
01372     fi->fuids = xcalloc(sizeof(*fi->fuids), fi->fc);
01373     fi->fgroup = NULL;
01374     fi->fgids = xcalloc(sizeof(*fi->fgids), fi->fc);
01375 
01376     /* Make the cpio list */
01377     if (fi->dil != NULL)        /* XXX can't happen */
01378     for (i = 0, flp = fl->fileList; i < fi->fc; i++, flp++) {
01379         char * b;
01380 
01381         /* Skip (possible) duplicate file entries, use last entry info. */
01382         while (((flp - fl->fileList) < (fl->fileListRecsUsed - 1)) &&
01383                 !strcmp(flp->fileURL, flp[1].fileURL))
01384             flp++;
01385 
01386         if (flp->flags & RPMFILE_EXCLUDE) {
01387             i--;
01388             continue;
01389         }
01390 
01391         if ((fnlen = strlen(flp->diskURL) + 1) > fi->fnlen)
01392             fi->fnlen = fnlen;
01393 
01394         /* Create disk directory and base name. */
01395         fi->dil[i] = i;
01396 /*@-dependenttrans@*/ /* FIX: artifact of spoofing headerGetEntry */
01397         fi->dnl[fi->dil[i]] = d;
01398 /*@=dependenttrans@*/
01399         d = stpcpy(d, flp->diskURL);
01400 
01401         /* Make room for the dirName NUL, find start of baseName. */
01402         for (b = d; b > fi->dnl[fi->dil[i]] && *b != '/'; b--)
01403             b[1] = b[0];
01404         b++;            /* dirname's end in '/' */
01405         *b++ = '\0';    /* terminate dirname, b points to basename */
01406         fi->bnl[i] = b;
01407         d += 2;         /* skip both dirname and basename NUL's */
01408 
01409         /* Create archive path, normally adding "./" */
01410         /*@-dependenttrans@*/   /* FIX: xstrdup? nah ... */
01411         fi->apath[i] = a;
01412         /*@=dependenttrans@*/
01413         if (_addDotSlash)
01414             a = stpcpy(a, "./");
01415         a = stpcpy(a, (flp->fileURL + skipLen));
01416         a++;            /* skip apath NUL */
01417 
01418         if (flp->flags & RPMFILE_GHOST) {
01419             fi->actions[i] = FA_SKIP;
01420             continue;
01421         }
01422         fi->actions[i] = FA_COPYOUT;
01423         fi->fuids[i] = getUidS(flp->uname);
01424         fi->fgids[i] = getGidS(flp->gname);
01425         if (fi->fuids[i] == (uid_t)-1) fi->fuids[i] = 0;
01426         if (fi->fgids[i] == (gid_t)-1) fi->fgids[i] = 0;
01427         fi->fmapflags[i] = CPIO_MAP_PATH |
01428                 CPIO_MAP_TYPE | CPIO_MAP_MODE | CPIO_MAP_UID | CPIO_MAP_GID;
01429         if (isSrc)
01430             fi->fmapflags[i] |= CPIO_FOLLOW_SYMLINKS;
01431 
01432     }
01433     /*@-branchstate -compdef@*/
01434     if (fip)
01435         *fip = fi;
01436     else
01437         fi = rpmfiFree(fi);
01438     /*@=branchstate =compdef@*/
01439   }
01440 }
01441 /*@=bounds@*/
01442 
01445 /*@-boundswrite@*/
01446 static /*@null@*/ FileListRec freeFileList(/*@only@*/ FileListRec fileList,
01447                         int count)
01448         /*@*/
01449 {
01450     while (count--) {
01451         fileList[count].diskURL = _free(fileList[count].diskURL);
01452         fileList[count].fileURL = _free(fileList[count].fileURL);
01453         fileList[count].langs = _free(fileList[count].langs);
01454     }
01455     fileList = _free(fileList);
01456     return NULL;
01457 }
01458 /*@=boundswrite@*/
01459 
01460 /* forward ref */
01461 static int recurseDir(FileList fl, const char * diskURL)
01462         /*@globals check_fileList, rpmGlobalMacroContext,
01463                 fileSystem, internalState @*/
01464         /*@modifies *fl, fl->processingFailed,
01465                 fl->fileList, fl->fileListRecsAlloced, fl->fileListRecsUsed,
01466                 fl->totalFileSize, fl->fileCount, fl->inFtw, fl->isDir,
01467                 check_fileList, rpmGlobalMacroContext,
01468                 fileSystem, internalState @*/;
01469 
01477 /*@-boundswrite@*/
01478 static int addFile(FileList fl, const char * diskURL,
01479                 /*@null@*/ struct stat * statp)
01480         /*@globals check_fileList, rpmGlobalMacroContext,
01481                 fileSystem, internalState @*/
01482         /*@modifies *statp, *fl, fl->processingFailed,
01483                 fl->fileList, fl->fileListRecsAlloced, fl->fileListRecsUsed,
01484                 fl->totalFileSize, fl->fileCount,
01485                 check_fileList, rpmGlobalMacroContext,
01486                 fileSystem, internalState @*/
01487 {
01488     const char *fileURL = diskURL;
01489     struct stat statbuf;
01490     mode_t fileMode;
01491     uid_t fileUid;
01492     gid_t fileGid;
01493     const char *fileUname;
01494     const char *fileGname;
01495     char *lang;
01496     
01497     /* Path may have prepended buildRootURL, so locate the original filename. */
01498     /*
01499      * XXX There are 3 types of entry into addFile:
01500      *
01501      *  From                    diskUrl                 statp
01502      *  =====================================================
01503      *  processBinaryFile       path                    NULL
01504      *  processBinaryFile       glob result path        NULL
01505      *  myftw                   path                    stat
01506      *
01507      */
01508     {   const char *fileName;
01509         (void) urlPath(fileURL, &fileName);
01510         if (fl->buildRootURL && strcmp(fl->buildRootURL, "/"))
01511             fileURL += strlen(fl->buildRootURL);
01512     }
01513 
01514     /* XXX make sure '/' can be packaged also */
01515     /*@-branchstate@*/
01516     if (*fileURL == '\0')
01517         fileURL = "/";
01518     /*@=branchstate@*/
01519 
01520     /* If we are using a prefix, validate the file */
01521     if (!fl->inFtw && fl->prefix) {
01522         const char *prefixTest;
01523         const char *prefixPtr = fl->prefix;
01524 
01525         (void) urlPath(fileURL, &prefixTest);
01526         while (*prefixPtr && *prefixTest && (*prefixTest == *prefixPtr)) {
01527             prefixPtr++;
01528             prefixTest++;
01529         }
01530         if (*prefixPtr || (*prefixTest && *prefixTest != '/')) {
01531             rpmError(RPMERR_BADSPEC, _("File doesn't match prefix (%s): %s\n"),
01532                      fl->prefix, fileURL);
01533             fl->processingFailed = 1;
01534             return RPMERR_BADSPEC;
01535         }
01536     }
01537 
01538     if (statp == NULL) {
01539         statp = &statbuf;
01540         memset(statp, 0, sizeof(*statp));
01541         if (fl->devtype) {
01542             time_t now = time(NULL);
01543 
01544             /* XXX hack up a stat structure for a %dev(...) directive. */
01545             statp->st_nlink = 1;
01546             statp->st_rdev =
01547                 ((fl->devmajor & 0xff) << 8) | (fl->devminor & 0xff);
01548             statp->st_dev = statp->st_rdev;
01549             statp->st_mode = (fl->devtype == 'b' ? S_IFBLK : S_IFCHR);
01550             statp->st_mode |= (fl->cur_ar.ar_fmode & 0777);
01551             statp->st_atime = now;
01552             statp->st_mtime = now;
01553             statp->st_ctime = now;
01554         } else if (Lstat(diskURL, statp)) {
01555             rpmError(RPMERR_BADSPEC, _("File not found: %s\n"), diskURL);
01556             fl->processingFailed = 1;
01557             return RPMERR_BADSPEC;
01558         }
01559     }
01560 
01561     if ((! fl->isDir) && S_ISDIR(statp->st_mode)) {
01562 /*@-nullstate@*/ /* FIX: fl->buildRootURL may be NULL */
01563         return recurseDir(fl, diskURL);
01564 /*@=nullstate@*/
01565     }
01566 
01567     fileMode = statp->st_mode;
01568     fileUid = statp->st_uid;
01569     fileGid = statp->st_gid;
01570 
01571     if (S_ISDIR(fileMode) && fl->cur_ar.ar_dmodestr) {
01572         fileMode &= S_IFMT;
01573         fileMode |= fl->cur_ar.ar_dmode;
01574     } else if (fl->cur_ar.ar_fmodestr != NULL) {
01575         fileMode &= S_IFMT;
01576         fileMode |= fl->cur_ar.ar_fmode;
01577     }
01578     if (fl->cur_ar.ar_user) {
01579         fileUname = getUnameS(fl->cur_ar.ar_user);
01580     } else {
01581         fileUname = getUname(fileUid);
01582     }
01583     if (fl->cur_ar.ar_group) {
01584         fileGname = getGnameS(fl->cur_ar.ar_group);
01585     } else {
01586         fileGname = getGname(fileGid);
01587     }
01588         
01589     /* Default user/group to builder's user/group */
01590     if (fileUname == NULL)
01591         fileUname = getUname(getuid());
01592     if (fileGname == NULL)
01593         fileGname = getGname(getgid());
01594     
01595     /* S_XXX macro must be consistent with type in find call at check-files script */
01596     if (check_fileList && S_ISREG(fileMode)) {
01597         appendStringBuf(check_fileList, diskURL);
01598         appendStringBuf(check_fileList, "\n");
01599     }
01600 
01601     /* Add to the file list */
01602     if (fl->fileListRecsUsed == fl->fileListRecsAlloced) {
01603         fl->fileListRecsAlloced += 128;
01604         fl->fileList = xrealloc(fl->fileList,
01605                         fl->fileListRecsAlloced * sizeof(*(fl->fileList)));
01606     }
01607             
01608     {   FileListRec flp = &fl->fileList[fl->fileListRecsUsed];
01609         int i;
01610 
01611         flp->fl_st = *statp;    /* structure assignment */
01612         flp->fl_mode = fileMode;
01613         flp->fl_uid = fileUid;
01614         flp->fl_gid = fileGid;
01615 
01616         flp->fileURL = xstrdup(fileURL);
01617         flp->diskURL = xstrdup(diskURL);
01618         flp->uname = fileUname;
01619         flp->gname = fileGname;
01620 
01621         if (fl->currentLangs && fl->nLangs > 0) {
01622             char * ncl;
01623             size_t nl = 0;
01624             
01625             for (i = 0; i < fl->nLangs; i++)
01626                 nl += strlen(fl->currentLangs[i]) + 1;
01627 
01628             flp->langs = ncl = xmalloc(nl);
01629             for (i = 0; i < fl->nLangs; i++) {
01630                 const char *ocl;
01631                 if (i)  *ncl++ = '|';
01632                 for (ocl = fl->currentLangs[i]; *ocl != '\0'; ocl++)
01633                         *ncl++ = *ocl;
01634                 *ncl = '\0';
01635             }
01636         } else if (! parseForRegexLang(fileURL, &lang)) {
01637             flp->langs = xstrdup(lang);
01638         } else {
01639             flp->langs = xstrdup("");
01640         }
01641 
01642         flp->flags = fl->currentFlags;
01643         flp->specdFlags = fl->currentSpecdFlags;
01644         flp->verifyFlags = fl->currentVerifyFlags;
01645 
01646         /* Hard links need be counted only once. */
01647         if (S_ISREG(flp->fl_mode) && flp->fl_nlink > 1) {
01648             FileListRec ilp;
01649             for (i = 0;  i < fl->fileListRecsUsed; i++) {
01650                 ilp = fl->fileList + i;
01651                 if (!S_ISREG(ilp->fl_mode))
01652                     continue;
01653                 if (flp->fl_nlink != ilp->fl_nlink)
01654                     continue;
01655                 if (flp->fl_ino != ilp->fl_ino)
01656                     continue;
01657                 if (flp->fl_dev != ilp->fl_dev)
01658                     continue;
01659                 break;
01660             }
01661         } else
01662             i = fl->fileListRecsUsed;
01663 
01664         if (S_ISREG(flp->fl_mode) && i >= fl->fileListRecsUsed)
01665             fl->totalFileSize += flp->fl_size;
01666     }
01667 
01668     fl->fileListRecsUsed++;
01669     fl->fileCount++;
01670 
01671     return 0;
01672 }
01673 /*@=boundswrite@*/
01674 
01681 static int recurseDir(FileList fl, const char * diskURL)
01682 {
01683     char * ftsSet[2];
01684     FTS * ftsp;
01685     FTSENT * fts;
01686     int ftsOpts = (FTS_COMFOLLOW | FTS_NOCHDIR | FTS_PHYSICAL);
01687     int rc = RPMERR_BADSPEC;
01688 
01689     fl->inFtw = 1;  /* Flag to indicate file has buildRootURL prefixed */
01690     fl->isDir = 1;  /* Keep it from following myftw() again         */
01691 
01692     ftsSet[0] = (char *) diskURL;
01693     ftsSet[1] = NULL;
01694     ftsp = Fts_open(ftsSet, ftsOpts, NULL);
01695     while ((fts = Fts_read(ftsp)) != NULL) {
01696         switch (fts->fts_info) {
01697         case FTS_D:             /* preorder directory */
01698         case FTS_F:             /* regular file */
01699         case FTS_SL:            /* symbolic link */
01700         case FTS_SLNONE:        /* symbolic link without target */
01701         case FTS_DEFAULT:       /* none of the above */
01702             rc = addFile(fl, fts->fts_accpath, fts->fts_statp);
01703             /*@switchbreak@*/ break;
01704         case FTS_DOT:           /* dot or dot-dot */
01705         case FTS_DP:            /* postorder directory */
01706             rc = 0;
01707             /*@switchbreak@*/ break;
01708         case FTS_NS:            /* stat(2) failed */
01709         case FTS_DNR:           /* unreadable directory */
01710         case FTS_ERR:           /* error; errno is set */
01711         case FTS_DC:            /* directory that causes cycles */
01712         case FTS_NSOK:          /* no stat(2) requested */
01713         case FTS_INIT:          /* initialized only */
01714         case FTS_W:             /* whiteout object */
01715         default:
01716             rc = RPMERR_BADSPEC;
01717             /*@switchbreak@*/ break;
01718         }
01719         if (rc)
01720             break;
01721     }
01722     (void) Fts_close(ftsp);
01723 
01724     fl->isDir = 0;
01725     fl->inFtw = 0;
01726 
01727     return rc;
01728 }
01729 
01737 static int processPubkeyFile(Package pkg, FileList fl, const char * fileURL)
01738         /*@globals check_fileList, rpmGlobalMacroContext,
01739                 fileSystem, internalState @*/
01740         /*@modifies pkg->header, *fl, fl->processingFailed,
01741                 fl->fileList, fl->fileListRecsAlloced, fl->fileListRecsUsed,
01742                 fl->totalFileSize, fl->fileCount,
01743                 check_fileList, rpmGlobalMacroContext,
01744                 fileSystem, internalState @*/
01745 {
01746     const char * buildURL = "%{_builddir}/%{?buildsubdir}/";
01747     const char * fn = NULL;
01748     const char * apkt = NULL;
01749     const unsigned char * pkt = NULL;
01750     ssize_t pktlen = 0;
01751     int absolute = 0;
01752     int rc = 1;
01753     int xx;
01754 
01755     (void) urlPath(fileURL, &fn);
01756      if (*fn == '/') {
01757         fn = rpmGenPath(fl->buildRootURL, NULL, fn);
01758         absolute = 1;
01759      } else
01760         fn = rpmGenPath(buildURL, NULL, fn);
01761 
01762     if ((rc = pgpReadPkts(fn, &pkt, &pktlen)) <= 0) {
01763         rpmError(RPMERR_BADSPEC, _("%s: public key read failed.\n"), fn);
01764         goto exit;
01765     }
01766     if (rc != PGPARMOR_PUBKEY) {
01767         rpmError(RPMERR_BADSPEC, _("%s: not an armored public key.\n"), fn);
01768         goto exit;
01769     }
01770 
01771     apkt = pgpArmorWrap(PGPARMOR_PUBKEY, pkt, pktlen);
01772     xx = headerAddOrAppendEntry(pkg->header, RPMTAG_PUBKEYS,
01773                 RPM_STRING_ARRAY_TYPE, &apkt, 1);
01774 
01775     rc = 0;
01776     if (absolute)
01777         rc = addFile(fl, fn, NULL);
01778 
01779 exit:
01780     apkt = _free(apkt);
01781     pkt = _free(pkt);
01782     fn = _free(fn);
01783     if (rc) {
01784         fl->processingFailed = 1;
01785         rc = RPMERR_BADSPEC;
01786     }
01787     return rc;
01788 }
01789 
01797 static int processBinaryFile(/*@unused@*/ Package pkg, FileList fl,
01798                 const char * fileURL)
01799         /*@globals rpmGlobalMacroContext, fileSystem, internalState @*/
01800         /*@modifies *fl, fl->processingFailed,
01801                 fl->fileList, fl->fileListRecsAlloced, fl->fileListRecsUsed,
01802                 fl->totalFileSize, fl->fileCount,
01803                 rpmGlobalMacroContext, fileSystem, internalState @*/
01804 {
01805     int doGlob;
01806     const char *diskURL = NULL;
01807     int rc = 0;
01808     
01809     doGlob = myGlobPatternP(fileURL);
01810 
01811     /* Check that file starts with leading "/" */
01812     {   const char * fileName;
01813         (void) urlPath(fileURL, &fileName);
01814         if (*fileName != '/') {
01815             rpmError(RPMERR_BADSPEC, _("File needs leading \"/\": %s\n"),
01816                         fileName);
01817             rc = 1;
01818             goto exit;
01819         }
01820     }
01821     
01822     /* Copy file name or glob pattern removing multiple "/" chars. */
01823     /*
01824      * Note: rpmGetPath should guarantee a "canonical" path. That means
01825      * that the following pathologies should be weeded out:
01826      *          //bin//sh
01827      *          //usr//bin/
01828      *          /.././../usr/../bin//./sh
01829      */
01830     diskURL = rpmGenPath(fl->buildRootURL, NULL, fileURL);
01831 
01832     if (doGlob) {
01833         const char ** argv = NULL;
01834         int argc = 0;
01835         int i;
01836 
01837         /* XXX for %dev marker in file manifest only */
01838         if (fl->noGlob) {
01839             rpmError(RPMERR_BADSPEC, _("Glob not permitted: %s\n"),
01840                         diskURL);
01841             rc = 1;
01842             goto exit;
01843         }
01844 
01845         /*@-branchstate@*/
01846         rc = rpmGlob(diskURL, &argc, &argv);
01847         if (rc == 0 && argc >= 1 && !myGlobPatternP(argv[0])) {
01848             for (i = 0; i < argc; i++) {
01849                 rc = addFile(fl, argv[i], NULL);
01850 /*@-boundswrite@*/
01851                 argv[i] = _free(argv[i]);
01852 /*@=boundswrite@*/
01853             }
01854             argv = _free(argv);
01855         } else {
01856             rpmError(RPMERR_BADSPEC, _("File not found by glob: %s\n"),
01857                         diskURL);
01858             rc = 1;
01859             goto exit;
01860         }
01861         /*@=branchstate@*/
01862     } else {
01863         rc = addFile(fl, diskURL, NULL);
01864     }
01865 
01866 exit:
01867     diskURL = _free(diskURL);
01868     if (rc) {
01869         fl->processingFailed = 1;
01870         rc = RPMERR_BADSPEC;
01871     }
01872     return rc;
01873 }
01874 
01877 /*@-boundswrite@*/
01878 static int processPackageFiles(Spec spec, Package pkg,
01879                                int installSpecialDoc, int test)
01880         /*@globals rpmGlobalMacroContext,
01881                 fileSystem, internalState@*/
01882         /*@modifies spec->macros,
01883                 pkg->cpioList, pkg->fileList, pkg->specialDoc, pkg->header,
01884                 rpmGlobalMacroContext, fileSystem, internalState @*/
01885 {
01886     HGE_t hge = (HGE_t)headerGetEntryMinMemory;
01887     struct FileList_s fl;
01888     char *s, **files, **fp;
01889     const char *fileName;
01890     char buf[BUFSIZ];
01891     struct AttrRec_s arbuf;
01892     AttrRec specialDocAttrRec = &arbuf;
01893     char *specialDoc = NULL;
01894 
01895     nullAttrRec(specialDocAttrRec);
01896     pkg->cpioList = NULL;
01897 
01898     if (pkg->fileFile) {
01899         const char *ffn;
01900         FILE * f;
01901         FD_t fd;
01902 
01903         /* XXX W2DO? urlPath might be useful here. */
01904         if (*pkg->fileFile == '/') {
01905             ffn = rpmGetPath(pkg->fileFile, NULL);
01906         } else {
01907             /* XXX FIXME: add %{_buildsubdir} */
01908             ffn = rpmGetPath("%{_builddir}/",
01909                 (spec->buildSubdir ? spec->buildSubdir : "") ,
01910                 "/", pkg->fileFile, NULL);
01911         }
01912         fd = Fopen(ffn, "r.fpio");
01913 
01914         if (fd == NULL || Ferror(fd)) {
01915             rpmError(RPMERR_BADFILENAME,
01916                 _("Could not open %%files file %s: %s\n"),
01917                 ffn, Fstrerror(fd));
01918             return RPMERR_BADFILENAME;
01919         }
01920         ffn = _free(ffn);
01921 
01922         /*@+voidabstract@*/ f = fdGetFp(fd); /*@=voidabstract@*/
01923         if (f != NULL)
01924         while (fgets(buf, sizeof(buf), f)) {
01925             handleComments(buf);
01926             if (expandMacros(spec, spec->macros, buf, sizeof(buf))) {
01927                 rpmError(RPMERR_BADSPEC, _("line: %s\n"), buf);
01928                 return RPMERR_BADSPEC;
01929             }
01930             appendStringBuf(pkg->fileList, buf);
01931         }
01932         (void) Fclose(fd);
01933     }
01934     
01935     /* Init the file list structure */
01936     memset(&fl, 0, sizeof(fl));
01937 
01938     /* XXX spec->buildRootURL == NULL, then xstrdup("") is returned */
01939     fl.buildRootURL = rpmGenPath(spec->rootURL, spec->buildRootURL, NULL);
01940 
01941     if (hge(pkg->header, RPMTAG_DEFAULTPREFIX, NULL, (void **)&fl.prefix, NULL))
01942         fl.prefix = xstrdup(fl.prefix);
01943     else
01944         fl.prefix = NULL;
01945 
01946     fl.fileCount = 0;
01947     fl.totalFileSize = 0;
01948     fl.processingFailed = 0;
01949 
01950     fl.passedSpecialDoc = 0;
01951     fl.isSpecialDoc = 0;
01952 
01953     fl.isDir = 0;
01954     fl.inFtw = 0;
01955     fl.currentFlags = 0;
01956     fl.currentVerifyFlags = 0;
01957     
01958     fl.noGlob = 0;
01959     fl.devtype = 0;
01960     fl.devmajor = 0;
01961     fl.devminor = 0;
01962 
01963     nullAttrRec(&fl.cur_ar);
01964     nullAttrRec(&fl.def_ar);
01965 
01966     fl.defVerifyFlags = RPMVERIFY_ALL;
01967     fl.nLangs = 0;
01968     fl.currentLangs = NULL;
01969 
01970     fl.currentSpecdFlags = 0;
01971     fl.defSpecdFlags = 0;
01972 
01973     fl.docDirCount = 0;
01974     fl.docDirs[fl.docDirCount++] = xstrdup("/usr/doc");
01975     fl.docDirs[fl.docDirCount++] = xstrdup("/usr/man");
01976     fl.docDirs[fl.docDirCount++] = xstrdup("/usr/info");
01977     fl.docDirs[fl.docDirCount++] = xstrdup("/usr/X11R6/man");
01978     fl.docDirs[fl.docDirCount++] = xstrdup("/usr/share/doc");
01979     fl.docDirs[fl.docDirCount++] = xstrdup("/usr/share/man");
01980     fl.docDirs[fl.docDirCount++] = xstrdup("/usr/share/info");
01981     fl.docDirs[fl.docDirCount++] = rpmGetPath("%{_docdir}", NULL);
01982     fl.docDirs[fl.docDirCount++] = rpmGetPath("%{_mandir}", NULL);
01983     fl.docDirs[fl.docDirCount++] = rpmGetPath("%{_infodir}", NULL);
01984     
01985     fl.fileList = NULL;
01986     fl.fileListRecsAlloced = 0;
01987     fl.fileListRecsUsed = 0;
01988 
01989     s = getStringBuf(pkg->fileList);
01990     files = splitString(s, strlen(s), '\n');
01991 
01992     for (fp = files; *fp != NULL; fp++) {
01993         s = *fp;
01994         SKIPSPACE(s);
01995         if (*s == '\0')
01996             continue;
01997         fileName = NULL;
01998         /*@-nullpass@*/ /* LCL: buf is NULL ?!? */
01999         strcpy(buf, s);
02000         /*@=nullpass@*/
02001         
02002         /* Reset for a new line in %files */
02003         fl.isDir = 0;
02004         fl.inFtw = 0;
02005         fl.currentFlags = 0;
02006         /* turn explicit flags into %def'd ones (gosh this is hacky...) */
02007         fl.currentSpecdFlags = ((unsigned)fl.defSpecdFlags) >> 8;
02008         fl.currentVerifyFlags = fl.defVerifyFlags;
02009         fl.isSpecialDoc = 0;
02010 
02011         fl.noGlob = 0;
02012         fl.devtype = 0;
02013         fl.devmajor = 0;
02014         fl.devminor = 0;
02015 
02016         /* XXX should reset to %deflang value */
02017         if (fl.currentLangs) {
02018             int i;
02019             for (i = 0; i < fl.nLangs; i++)
02020                 /*@-unqualifiedtrans@*/
02021                 fl.currentLangs[i] = _free(fl.currentLangs[i]);
02022                 /*@=unqualifiedtrans@*/
02023             fl.currentLangs = _free(fl.currentLangs);
02024         }
02025         fl.nLangs = 0;
02026 
02027         dupAttrRec(&fl.def_ar, &fl.cur_ar);
02028 
02029         /*@-nullpass@*/ /* LCL: buf is NULL ?!? */
02030         if (parseForVerify(buf, &fl))
02031             continue;
02032         if (parseForAttr(buf, &fl))
02033             continue;
02034         if (parseForDev(buf, &fl))
02035             continue;
02036         if (parseForConfig(buf, &fl))
02037             continue;
02038         if (parseForLang(buf, &fl))
02039             continue;
02040         /*@-nullstate@*/        /* FIX: pkg->fileFile might be NULL */
02041         if (parseForSimple(spec, pkg, buf, &fl, &fileName))
02042         /*@=nullstate@*/
02043             continue;
02044         /*@=nullpass@*/
02045         if (fileName == NULL)
02046             continue;
02047 
02048         /*@-branchstate@*/
02049         if (fl.isSpecialDoc) {
02050             /* Save this stuff for last */
02051             specialDoc = _free(specialDoc);
02052             specialDoc = xstrdup(fileName);
02053             dupAttrRec(&fl.cur_ar, specialDocAttrRec);
02054         } else if (fl.currentFlags & RPMFILE_PUBKEY) {
02055 /*@-nullstate@*/        /* FIX: pkg->fileFile might be NULL */
02056             (void) processPubkeyFile(pkg, &fl, fileName);
02057 /*@=nullstate@*/
02058         } else {
02059 /*@-nullstate@*/        /* FIX: pkg->fileFile might be NULL */
02060             (void) processBinaryFile(pkg, &fl, fileName);
02061 /*@=nullstate@*/
02062         }
02063         /*@=branchstate@*/
02064     }
02065 
02066     /* Now process special doc, if there is one */
02067     if (specialDoc) {
02068         if (installSpecialDoc) {
02069             static int _missing_doc_files_terminate_build = 0;
02070             static int oneshot = 0;
02071             int rc;
02072 
02073             if (!oneshot) {
02074                 _missing_doc_files_terminate_build =
02075                     rpmExpandNumeric("%{?_missing_doc_files_terminate_build}");
02076                 oneshot = 1;
02077             }
02078             rc = doScript(spec, RPMBUILD_STRINGBUF, "%doc", pkg->specialDoc, test);
02079             if (rc && _missing_doc_files_terminate_build)
02080                 fl.processingFailed = rc;
02081         }
02082 
02083         /* Reset for %doc */
02084         fl.isDir = 0;
02085         fl.inFtw = 0;
02086         fl.currentFlags = 0;
02087         fl.currentVerifyFlags = 0;
02088 
02089         fl.noGlob = 0;
02090         fl.devtype = 0;
02091         fl.devmajor = 0;
02092         fl.devminor = 0;
02093 
02094         /* XXX should reset to %deflang value */
02095         if (fl.currentLangs) {
02096             int i;
02097             for (i = 0; i < fl.nLangs; i++)
02098                 /*@-unqualifiedtrans@*/
02099                 fl.currentLangs[i] = _free(fl.currentLangs[i]);
02100                 /*@=unqualifiedtrans@*/
02101             fl.currentLangs = _free(fl.currentLangs);
02102         }
02103         fl.nLangs = 0;
02104 
02105         dupAttrRec(specialDocAttrRec, &fl.cur_ar);
02106         freeAttrRec(specialDocAttrRec);
02107 
02108         /*@-nullstate@*/        /* FIX: pkg->fileFile might be NULL */
02109         (void) processBinaryFile(pkg, &fl, specialDoc);
02110         /*@=nullstate@*/
02111 
02112         specialDoc = _free(specialDoc);
02113     }
02114     
02115     freeSplitString(files);
02116 
02117     if (fl.processingFailed)
02118         goto exit;
02119 
02120     /* Verify that file attributes scope over hardlinks correctly. */
02121     if (checkHardLinks(&fl))
02122         (void) rpmlibNeedsFeature(pkg->header,
02123                         "PartialHardlinkSets", "4.0.4-1");
02124 
02125     genCpioListAndHeader(&fl, &pkg->cpioList, pkg->header, 0);
02126 
02127     if (spec->timeCheck)
02128         timeCheck(spec->timeCheck, pkg->header);
02129     
02130 exit:
02131     fl.buildRootURL = _free(fl.buildRootURL);
02132     fl.prefix = _free(fl.prefix);
02133 
02134     freeAttrRec(&fl.cur_ar);
02135     freeAttrRec(&fl.def_ar);
02136 
02137     if (fl.currentLangs) {
02138         int i;
02139         for (i = 0; i < fl.nLangs; i++)
02140             /*@-unqualifiedtrans@*/
02141             fl.currentLangs[i] = _free(fl.currentLangs[i]);
02142             /*@=unqualifiedtrans@*/
02143         fl.currentLangs = _free(fl.currentLangs);
02144     }
02145 
02146     fl.fileList = freeFileList(fl.fileList, fl.fileListRecsUsed);
02147     while (fl.docDirCount--)
02148         fl.docDirs[fl.docDirCount] = _free(fl.docDirs[fl.docDirCount]);
02149     return fl.processingFailed;
02150 }
02151 /*@=boundswrite@*/
02152 
02153 void initSourceHeader(Spec spec)
02154 {
02155     HeaderIterator hi;
02156     int_32 tag, type, count;
02157     const void * ptr;
02158 
02159     spec->sourceHeader = headerNew();
02160     /* Only specific tags are added to the source package header */
02161     /*@-branchstate@*/
02162     for (hi = headerInitIterator(spec->packages->header);
02163         headerNextIterator(hi, &tag, &type, &ptr, &count);
02164         ptr = headerFreeData(ptr, type))
02165     {
02166         switch (tag) {
02167         case RPMTAG_NAME:
02168         case RPMTAG_VERSION:
02169         case RPMTAG_RELEASE:
02170         case RPMTAG_EPOCH:
02171         case RPMTAG_SUMMARY:
02172         case RPMTAG_DESCRIPTION:
02173         case RPMTAG_PACKAGER:
02174         case RPMTAG_DISTRIBUTION:
02175         case RPMTAG_DISTURL:
02176         case RPMTAG_VENDOR:
02177         case RPMTAG_LICENSE:
02178         case RPMTAG_GROUP:
02179         case RPMTAG_OS:
02180         case RPMTAG_ARCH:
02181         case RPMTAG_CHANGELOGTIME:
02182         case RPMTAG_CHANGELOGNAME:
02183         case RPMTAG_CHANGELOGTEXT:
02184         case RPMTAG_URL:
02185         case HEADER_I18NTABLE:
02186             if (ptr)
02187                 (void)headerAddEntry(spec->sourceHeader, tag, type, ptr, count);
02188             /*@switchbreak@*/ break;
02189         default:
02190             /* do not copy */
02191             /*@switchbreak@*/ break;
02192         }
02193     }
02194     hi = headerFreeIterator(hi);
02195     /*@=branchstate@*/
02196 
02197     /* Add the build restrictions */
02198     /*@-branchstate@*/
02199     for (hi = headerInitIterator(spec->buildRestrictions);
02200         headerNextIterator(hi, &tag, &type, &ptr, &count);
02201         ptr = headerFreeData(ptr, type))
02202     {
02203         if (ptr)
02204             (void) headerAddEntry(spec->sourceHeader, tag, type, ptr, count);
02205     }
02206     hi = headerFreeIterator(hi);
02207     /*@=branchstate@*/
02208 
02209     if (spec->BANames && spec->BACount > 0) {
02210         (void) headerAddEntry(spec->sourceHeader, RPMTAG_BUILDARCHS,
02211                        RPM_STRING_ARRAY_TYPE,
02212                        spec->BANames, spec->BACount);
02213     }
02214 }
02215 
02216 int processSourceFiles(Spec spec)
02217 {
02218     struct Source *srcPtr;
02219     StringBuf sourceFiles;
02220     int x, isSpec = 1;
02221     struct FileList_s fl;
02222     char *s, **files, **fp;
02223     Package pkg;
02224 
02225     sourceFiles = newStringBuf();
02226 
02227     /* XXX
02228      * XXX This is where the source header for noarch packages needs
02229      * XXX to be initialized.
02230      */
02231     if (spec->sourceHeader == NULL)
02232         initSourceHeader(spec);
02233 
02234     /* Construct the file list and source entries */
02235     appendLineStringBuf(sourceFiles, spec->specFile);
02236     if (spec->sourceHeader != NULL)
02237     for (srcPtr = spec->sources; srcPtr != NULL; srcPtr = srcPtr->next) {
02238         if (srcPtr->flags & RPMBUILD_ISSOURCE) {
02239             (void) headerAddOrAppendEntry(spec->sourceHeader, RPMTAG_SOURCE,
02240                                    RPM_STRING_ARRAY_TYPE, &srcPtr->source, 1);
02241             if (srcPtr->flags & RPMBUILD_ISNO) {
02242                 (void) headerAddOrAppendEntry(spec->sourceHeader, RPMTAG_NOSOURCE,
02243                                        RPM_INT32_TYPE, &srcPtr->num, 1);
02244             }
02245         }
02246         if (srcPtr->flags & RPMBUILD_ISPATCH) {
02247             (void) headerAddOrAppendEntry(spec->sourceHeader, RPMTAG_PATCH,
02248                                    RPM_STRING_ARRAY_TYPE, &srcPtr->source, 1);
02249             if (srcPtr->flags & RPMBUILD_ISNO) {
02250                 (void) headerAddOrAppendEntry(spec->sourceHeader, RPMTAG_NOPATCH,
02251                                        RPM_INT32_TYPE, &srcPtr->num, 1);
02252             }
02253         }
02254 
02255       { const char * sfn;
02256         sfn = rpmGetPath( ((srcPtr->flags & RPMBUILD_ISNO) ? "!" : ""),
02257                 "%{_sourcedir}/", srcPtr->source, NULL);
02258         appendLineStringBuf(sourceFiles, sfn);
02259         sfn = _free(sfn);
02260       }
02261     }
02262 
02263     for (pkg = spec->packages; pkg != NULL; pkg = pkg->next) {
02264         for (srcPtr = pkg->icon; srcPtr != NULL; srcPtr = srcPtr->next) {
02265             const char * sfn;
02266             sfn = rpmGetPath( ((srcPtr->flags & RPMBUILD_ISNO) ? "!" : ""),
02267                 "%{_sourcedir}/", srcPtr->source, NULL);
02268             appendLineStringBuf(sourceFiles, sfn);
02269             sfn = _free(sfn);
02270         }
02271     }
02272 
02273     spec->sourceCpioList = NULL;
02274 
02275     fl.fileList = xcalloc((spec->numSources + 1), sizeof(*fl.fileList));
02276     fl.processingFailed = 0;
02277     fl.fileListRecsUsed = 0;
02278     fl.totalFileSize = 0;
02279     fl.prefix = NULL;
02280     fl.buildRootURL = NULL;
02281 
02282     s = getStringBuf(sourceFiles);
02283     files = splitString(s, strlen(s), '\n');
02284 
02285     /* The first source file is the spec file */
02286     x = 0;
02287     for (fp = files; *fp != NULL; fp++) {
02288         const char * diskURL, *diskPath;
02289         FileListRec flp;
02290 
02291         diskURL = *fp;
02292         SKIPSPACE(diskURL);
02293         if (! *diskURL)
02294             continue;
02295 
02296         flp = &fl.fileList[x];
02297 
02298         flp->flags = isSpec ? RPMFILE_SPECFILE : 0;
02299         /* files with leading ! are no source files */
02300         if (*diskURL == '!') {
02301             flp->flags |= RPMFILE_GHOST;
02302             diskURL++;
02303         }
02304 
02305         (void) urlPath(diskURL, &diskPath);
02306 
02307         flp->diskURL = xstrdup(diskURL);
02308         diskPath = strrchr(diskPath, '/');
02309         if (diskPath)
02310             diskPath++;
02311         else
02312             diskPath = diskURL;
02313 
02314         flp->fileURL = xstrdup(diskPath);
02315         flp->verifyFlags = RPMVERIFY_ALL;
02316 
02317         if (Stat(diskURL, &flp->fl_st)) {
02318             rpmError(RPMERR_BADSPEC, _("Bad file: %s: %s\n"),
02319                 diskURL, strerror(errno));
02320             fl.processingFailed = 1;
02321         }
02322 
02323         flp->uname = getUname(flp->fl_uid);
02324         flp->gname = getGname(flp->fl_gid);
02325         flp->langs = xstrdup("");
02326         
02327         fl.totalFileSize += flp->fl_size;
02328         
02329         if (! (flp->uname && flp->gname)) {
02330             rpmError(RPMERR_BADSPEC, _("Bad owner/group: %s\n"), diskURL);
02331             fl.processingFailed = 1;
02332         }
02333 
02334         isSpec = 0;
02335         x++;
02336     }
02337     fl.fileListRecsUsed = x;
02338     freeSplitString(files);
02339 
02340     if (! fl.processingFailed) {
02341         if (spec->sourceHeader != NULL)
02342             genCpioListAndHeader(&fl, &spec->sourceCpioList,
02343                         spec->sourceHeader, 1);
02344     }
02345 
02346     sourceFiles = freeStringBuf(sourceFiles);
02347     fl.fileList = freeFileList(fl.fileList, fl.fileListRecsUsed);
02348     return fl.processingFailed;
02349 }
02350 
02356 static int checkFiles(StringBuf fileList)
02357         /*@globals rpmGlobalMacroContext, fileSystem, internalState @*/
02358         /*@modifies rpmGlobalMacroContext, fileSystem, internalState @*/
02359 {
02360 /*@-readonlytrans@*/
02361     static const char * av_ckfile[] = { "%{?__check_files}", NULL };
02362 /*@=readonlytrans@*/
02363     StringBuf sb_stdout = NULL;
02364     const char * s;
02365     int rc;
02366     
02367     s = rpmExpand(av_ckfile[0], NULL);
02368     if (!(s && *s)) {
02369         rc = -1;
02370         goto exit;
02371     }
02372     rc = 0;
02373 
02374     rpmMessage(RPMMESS_NORMAL, _("Checking for unpackaged file(s): %s\n"), s);
02375 
02376 /*@-boundswrite@*/
02377     rc = rpmfcExec(av_ckfile, fileList, &sb_stdout, 0);
02378 /*@=boundswrite@*/
02379     if (rc < 0)
02380         goto exit;
02381     
02382     if (sb_stdout) {
02383         static int _unpackaged_files_terminate_build = 0;
02384         static int oneshot = 0;
02385         const char * t;
02386 
02387         if (!oneshot) {
02388             _unpackaged_files_terminate_build =
02389                 rpmExpandNumeric("%{?_unpackaged_files_terminate_build}");
02390             oneshot = 1;
02391         }
02392         
02393         t = getStringBuf(sb_stdout);
02394         if ((*t != '\0') && (*t != '\n')) {
02395             rc = (_unpackaged_files_terminate_build) ? 1 : 0;
02396             rpmMessage((rc ? RPMMESS_ERROR : RPMMESS_WARNING),
02397                 _("Installed (but unpackaged) file(s) found:\n%s"), t);
02398         }
02399     }
02400     
02401 exit:
02402     sb_stdout = freeStringBuf(sb_stdout);
02403     s = _free(s);
02404     return rc;
02405 }
02406 
02407 /*@-incondefs@*/
02408 int processBinaryFiles(Spec spec, int installSpecialDoc, int test)
02409         /*@globals check_fileList @*/
02410         /*@modifies check_fileList @*/
02411 {
02412     Package pkg;
02413     int res = 0;
02414     
02415     check_fileList = newStringBuf();
02416     
02417     for (pkg = spec->packages; pkg != NULL; pkg = pkg->next) {
02418         const char *n, *v, *r;
02419         int rc;
02420 
02421         if (pkg->fileList == NULL)
02422             continue;
02423 
02424         (void) headerNVR(pkg->header, &n, &v, &r);
02425         rpmMessage(RPMMESS_NORMAL, _("Processing files: %s-%s-%s\n"), n, v, r);
02426                    
02427         if ((rc = processPackageFiles(spec, pkg, installSpecialDoc, test)))
02428             res = rc;
02429 
02430         (void) rpmfcGenerateDepends(spec, pkg);
02431 
02432     }
02433 
02434     /* Now we have in fileList list of files from all packages.
02435      * We pass it to a script which does the work of finding missing
02436      * and duplicated files.
02437      */
02438     
02439     if (res == 0)  {
02440         if (checkFiles(check_fileList) > 0)
02441             res = 1;
02442     }
02443     
02444     check_fileList = freeStringBuf(check_fileList);
02445     
02446     return res;
02447 }
02448 /*@=incondefs@*/

Generated on Sun Oct 26 13:01:56 2003 for rpm by doxygen1.2.18