build/files.c

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

Generated on Fri May 25 21:18:11 2007 for rpm by  doxygen 1.5.2