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

build/files.c

Go to the documentation of this file.
00001 
00007 #include "system.h"
00008 
00009 #define MYALLPERMS      07777
00010 
00011 #include <regex.h>
00012 
00013 #include <rpmio_internal.h>
00014 #include <fts.h>
00015 
00016 #include <rpmbuild.h>
00017 
00018 #include "cpio.h"
00019 
00020 #include "argv.h"
00021 #include "rpmfc.h"
00022 
00023 #define _RPMFI_INTERNAL
00024 #include "rpmfi.h"
00025 
00026 #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                 char *compress_doc;
01068 
01069                 compress_doc = rpmExpand("%{__compress_doc}", NULL);
01070                 if (compress_doc && *compress_doc != '%')
01071                     appendLineStringBuf(pkg->specialDoc, compress_doc);
01072                 if (compress_doc)
01073                   free(compress_doc);
01074             }
01075         }
01076     }
01077 
01078     return res;
01079 }
01080 /*@=boundswrite@*/
01081 
01084 static int compareFileListRecs(const void * ap, const void * bp)        /*@*/
01085 {
01086     const char *aurl = ((FileListRec)ap)->fileURL;
01087     const char *a = NULL;
01088     const char *burl = ((FileListRec)bp)->fileURL;
01089     const char *b = NULL;
01090     (void) urlPath(aurl, &a);
01091     (void) urlPath(burl, &b);
01092     return strcmp(a, b);
01093 }
01094 
01102 static int isDoc(FileList fl, const char * fileName)    /*@*/
01103 {
01104     int x = fl->docDirCount;
01105 
01106     while (x--) {
01107         if (strstr(fileName, fl->docDirs[x]) == fileName)
01108             return 1;
01109     }
01110     return 0;
01111 }
01112 
01119 static int checkHardLinks(FileList fl)
01120         /*@*/
01121 {
01122     FileListRec ilp, jlp;
01123     int i, j;
01124 
01125     for (i = 0;  i < fl->fileListRecsUsed; i++) {
01126         ilp = fl->fileList + i;
01127         if (!(S_ISREG(ilp->fl_mode) && ilp->fl_nlink > 1))
01128             continue;
01129 
01130         for (j = i + 1; j < fl->fileListRecsUsed; j++) {
01131             jlp = fl->fileList + j;
01132             if (!S_ISREG(jlp->fl_mode))
01133                 /*@innercontinue@*/ continue;
01134             if (ilp->fl_nlink != jlp->fl_nlink)
01135                 /*@innercontinue@*/ continue;
01136             if (ilp->fl_ino != jlp->fl_ino)
01137                 /*@innercontinue@*/ continue;
01138             if (ilp->fl_dev != jlp->fl_dev)
01139                 /*@innercontinue@*/ continue;
01140             return 1;
01141         }
01142     }
01143     return 0;
01144 }
01145 
01146 /*@-boundsread@*/
01147 static int dncmp(const void * a, const void * b)
01148         /*@*/
01149 {
01150     const char ** aurlp = a;
01151     const char ** burlp = b;
01152     const char * adn;
01153     const char * bdn;
01154     (void) urlPath(*aurlp, &adn);
01155     (void) urlPath(*burlp, &bdn);
01156     return strcmp(adn, bdn);
01157 }
01158 /*@=boundsread@*/
01159 
01160 /*@-bounds@*/
01165 static void compressFilelist(Header h)
01166         /*@modifies h @*/
01167 {
01168     HGE_t hge = (HGE_t)headerGetEntryMinMemory;
01169     HAE_t hae = (HAE_t)headerAddEntry;
01170     HRE_t hre = (HRE_t)headerRemoveEntry;
01171     HFD_t hfd = headerFreeData;
01172     char ** fileNames;
01173     const char * fn;
01174     const char ** dirNames;
01175     const char ** baseNames;
01176     int_32 * dirIndexes;
01177     rpmTagType fnt;
01178     int count;
01179     int i, xx;
01180     int dirIndex = -1;
01181 
01182     /*
01183      * This assumes the file list is already sorted, and begins with a
01184      * single '/'. That assumption isn't critical, but it makes things go
01185      * a bit faster.
01186      */
01187 
01188     if (headerIsEntry(h, RPMTAG_DIRNAMES)) {
01189         xx = hre(h, RPMTAG_OLDFILENAMES);
01190         return;         /* Already converted. */
01191     }
01192 
01193     if (!hge(h, RPMTAG_OLDFILENAMES, &fnt, (void **) &fileNames, &count))
01194         return;         /* no file list */
01195     if (fileNames == NULL || count <= 0)
01196         return;
01197 
01198     dirNames = alloca(sizeof(*dirNames) * count);       /* worst case */
01199     baseNames = alloca(sizeof(*dirNames) * count);
01200     dirIndexes = alloca(sizeof(*dirIndexes) * count);
01201 
01202     (void) urlPath(fileNames[0], &fn);
01203     if (fn[0] != '/') {
01204         /* HACK. Source RPM, so just do things differently */
01205         dirIndex = 0;
01206         dirNames[dirIndex] = "";
01207         for (i = 0; i < count; i++) {
01208             dirIndexes[i] = dirIndex;
01209             baseNames[i] = fileNames[i];
01210         }
01211         goto exit;
01212     }
01213 
01214     /*@-branchstate@*/
01215     for (i = 0; i < count; i++) {
01216         const char ** needle;
01217         char savechar;
01218         char * baseName;
01219         int len;
01220 
01221         if (fileNames[i] == NULL)       /* XXX can't happen */
01222             continue;
01223         baseName = strrchr(fileNames[i], '/') + 1;
01224         len = baseName - fileNames[i];
01225         needle = dirNames;
01226         savechar = *baseName;
01227         *baseName = '\0';
01228 /*@-compdef@*/
01229         if (dirIndex < 0 ||
01230             (needle = bsearch(&fileNames[i], dirNames, dirIndex + 1, sizeof(dirNames[0]), dncmp)) == NULL) {
01231             char *s = alloca(len + 1);
01232             memcpy(s, fileNames[i], len + 1);
01233             s[len] = '\0';
01234             dirIndexes[i] = ++dirIndex;
01235             dirNames[dirIndex] = s;
01236         } else
01237             dirIndexes[i] = needle - dirNames;
01238 /*@=compdef@*/
01239 
01240         *baseName = savechar;
01241         baseNames[i] = baseName;
01242     }
01243     /*@=branchstate@*/
01244 
01245 exit:
01246     if (count > 0) {
01247         xx = hae(h, RPMTAG_DIRINDEXES, RPM_INT32_TYPE, dirIndexes, count);
01248         xx = hae(h, RPMTAG_BASENAMES, RPM_STRING_ARRAY_TYPE,
01249                         baseNames, count);
01250         xx = hae(h, RPMTAG_DIRNAMES, RPM_STRING_ARRAY_TYPE,
01251                         dirNames, dirIndex + 1);
01252     }
01253 
01254     fileNames = hfd(fileNames, fnt);
01255 
01256     xx = hre(h, RPMTAG_OLDFILENAMES);
01257 }
01258 /*@=bounds@*/
01259 
01269 /*@-bounds@*/
01270 static void genCpioListAndHeader(/*@partial@*/ FileList fl,
01271                 rpmfi * fip, Header h, int isSrc)
01272         /*@globals rpmGlobalMacroContext, h_errno, fileSystem, internalState @*/
01273         /*@modifies h, *fip, fl->processingFailed, fl->fileList,
01274                 rpmGlobalMacroContext, fileSystem, internalState @*/
01275 {
01276     const char * apath;
01277     int _addDotSlash = !isSrc;
01278     int apathlen = 0;
01279     int dpathlen = 0;
01280     int skipLen = 0;
01281     rpmsx sx = NULL;
01282     const char * sxfn;
01283     size_t fnlen;
01284     FileListRec flp;
01285     char buf[BUFSIZ];
01286     int i;
01287     
01288     /* Sort the big list */
01289     qsort(fl->fileList, fl->fileListRecsUsed,
01290           sizeof(*(fl->fileList)), compareFileListRecs);
01291     
01292     /* Generate the header. */
01293     if (! isSrc) {
01294         skipLen = 1;
01295         if (fl->prefix)
01296             skipLen += strlen(fl->prefix);
01297     }
01298 
01299     sxfn = rpmGetPath("%{?_build_file_context_path}", NULL);
01300     if (sxfn != NULL && *sxfn != '\0')
01301         sx = rpmsxNew(sxfn);
01302 
01303     for (i = 0, flp = fl->fileList; i < fl->fileListRecsUsed; i++, flp++) {
01304         const char *s;
01305 
01306         /* Merge duplicate entries. */
01307         while (i < (fl->fileListRecsUsed - 1) &&
01308             !strcmp(flp->fileURL, flp[1].fileURL)) {
01309 
01310             /* Two entries for the same file found, merge the entries. */
01311             /* Note that an %exclude is a duplication of a file reference */
01312 
01313             /* file flags */
01314             flp[1].flags |= flp->flags; 
01315 
01316             if (!(flp[1].flags & RPMFILE_EXCLUDE))
01317                 rpmMessage(RPMMESS_WARNING, _("File listed twice: %s\n"),
01318                         flp->fileURL);
01319    
01320             /* file mode */
01321             if (S_ISDIR(flp->fl_mode)) {
01322                 if ((flp[1].specdFlags & (SPECD_DIRMODE | SPECD_DEFDIRMODE)) <
01323                     (flp->specdFlags & (SPECD_DIRMODE | SPECD_DEFDIRMODE)))
01324                         flp[1].fl_mode = flp->fl_mode;
01325             } else {
01326                 if ((flp[1].specdFlags & (SPECD_FILEMODE | SPECD_DEFFILEMODE)) <
01327                     (flp->specdFlags & (SPECD_FILEMODE | SPECD_DEFFILEMODE)))
01328                         flp[1].fl_mode = flp->fl_mode;
01329             }
01330 
01331             /* uid */
01332             if ((flp[1].specdFlags & (SPECD_UID | SPECD_DEFUID)) <
01333                 (flp->specdFlags & (SPECD_UID | SPECD_DEFUID)))
01334             {
01335                 flp[1].fl_uid = flp->fl_uid;
01336                 flp[1].uname = flp->uname;
01337             }
01338 
01339             /* gid */
01340             if ((flp[1].specdFlags & (SPECD_GID | SPECD_DEFGID)) <
01341                 (flp->specdFlags & (SPECD_GID | SPECD_DEFGID)))
01342             {
01343                 flp[1].fl_gid = flp->fl_gid;
01344                 flp[1].gname = flp->gname;
01345             }
01346 
01347             /* verify flags */
01348             if ((flp[1].specdFlags & (SPECD_VERIFY | SPECD_DEFVERIFY)) <
01349                 (flp->specdFlags & (SPECD_VERIFY | SPECD_DEFVERIFY)))
01350                     flp[1].verifyFlags = flp->verifyFlags;
01351 
01352             /* XXX to-do: language */
01353 
01354             flp++; i++;
01355         }
01356 
01357         /* Skip files that were marked with %exclude. */
01358         if (flp->flags & RPMFILE_EXCLUDE) continue;
01359 
01360         /* Omit '/' and/or URL prefix, leave room for "./" prefix */
01361         (void) urlPath(flp->fileURL, &apath);
01362         apathlen += (strlen(apath) - skipLen + (_addDotSlash ? 3 : 1));
01363 
01364         /* Leave room for both dirname and basename NUL's */
01365         dpathlen += (strlen(flp->diskURL) + 2);
01366 
01367         /*
01368          * Make the header, the OLDFILENAMES will get converted to a 
01369          * compressed file list write before we write the actual package to
01370          * disk.
01371          */
01372         (void) headerAddOrAppendEntry(h, RPMTAG_OLDFILENAMES, RPM_STRING_ARRAY_TYPE,
01373                                &(flp->fileURL), 1);
01374 
01375 /*@-sizeoftype@*/
01376       if (sizeof(flp->fl_size) != sizeof(uint_32)) {
01377         uint_32 psize = (uint_32)flp->fl_size;
01378         (void) headerAddOrAppendEntry(h, RPMTAG_FILESIZES, RPM_INT32_TYPE,
01379                                &(psize), 1);
01380       } else {
01381         (void) headerAddOrAppendEntry(h, RPMTAG_FILESIZES, RPM_INT32_TYPE,
01382                                &(flp->fl_size), 1);
01383       }
01384         (void) headerAddOrAppendEntry(h, RPMTAG_FILEUSERNAME, RPM_STRING_ARRAY_TYPE,
01385                                &(flp->uname), 1);
01386         (void) headerAddOrAppendEntry(h, RPMTAG_FILEGROUPNAME, RPM_STRING_ARRAY_TYPE,
01387                                &(flp->gname), 1);
01388       if (sizeof(flp->fl_mtime) != sizeof(uint_32)) {
01389         uint_32 mtime = (uint_32)flp->fl_mtime;
01390         (void) headerAddOrAppendEntry(h, RPMTAG_FILEMTIMES, RPM_INT32_TYPE,
01391                                &(mtime), 1);
01392       } else {
01393         (void) headerAddOrAppendEntry(h, RPMTAG_FILEMTIMES, RPM_INT32_TYPE,
01394                                &(flp->fl_mtime), 1);
01395       }
01396       if (sizeof(flp->fl_mode) != sizeof(uint_16)) {
01397         uint_16 pmode = (uint_16)flp->fl_mode;
01398         (void) headerAddOrAppendEntry(h, RPMTAG_FILEMODES, RPM_INT16_TYPE,
01399                                &(pmode), 1);
01400       } else {
01401         (void) headerAddOrAppendEntry(h, RPMTAG_FILEMODES, RPM_INT16_TYPE,
01402                                &(flp->fl_mode), 1);
01403       }
01404       if (sizeof(flp->fl_rdev) != sizeof(uint_16)) {
01405         uint_16 prdev = (uint_16)flp->fl_rdev;
01406         (void) headerAddOrAppendEntry(h, RPMTAG_FILERDEVS, RPM_INT16_TYPE,
01407                                &(prdev), 1);
01408       } else {
01409         (void) headerAddOrAppendEntry(h, RPMTAG_FILERDEVS, RPM_INT16_TYPE,
01410                                &(flp->fl_rdev), 1);
01411       }
01412       if (sizeof(flp->fl_dev) != sizeof(uint_32)) {
01413         uint_32 pdevice = (uint_32)flp->fl_dev;
01414         (void) headerAddOrAppendEntry(h, RPMTAG_FILEDEVICES, RPM_INT32_TYPE,
01415                                &(pdevice), 1);
01416       } else {
01417         (void) headerAddOrAppendEntry(h, RPMTAG_FILEDEVICES, RPM_INT32_TYPE,
01418                                &(flp->fl_dev), 1);
01419       }
01420       if (sizeof(flp->fl_ino) != sizeof(uint_32)) {
01421         uint_32 ino = (uint_32)flp->fl_ino;
01422         (void) headerAddOrAppendEntry(h, RPMTAG_FILEINODES, RPM_INT32_TYPE,
01423                                 &(ino), 1);
01424       } else {
01425         (void) headerAddOrAppendEntry(h, RPMTAG_FILEINODES, RPM_INT32_TYPE,
01426                                 &(flp->fl_ino), 1);
01427       }
01428 /*@=sizeoftype@*/
01429 
01430         (void) headerAddOrAppendEntry(h, RPMTAG_FILELANGS, RPM_STRING_ARRAY_TYPE,
01431                                &(flp->langs),  1);
01432         
01433       { static uint_32 source_file_dalgo = 0;
01434         static uint_32 binary_file_dalgo = 0;
01435         static int oneshot = 0;
01436         uint_32 dalgo = 0;
01437 
01438         if (!oneshot) {
01439             source_file_dalgo =
01440                 rpmExpandNumeric("%{?_build_source_file_digest_algo}");
01441             binary_file_dalgo =
01442                 rpmExpandNumeric("%{?_build_binary_file_digest_algo}");
01443             oneshot++;
01444         }
01445 
01446         dalgo = (isSrc ? source_file_dalgo : binary_file_dalgo);
01447         switch (dalgo) {
01448         case PGPHASHALGO_SHA1:
01449         case PGPHASHALGO_RIPEMD160:
01450         case PGPHASHALGO_MD2:
01451         case PGPHASHALGO_TIGER192:
01452         case PGPHASHALGO_SHA256:
01453         case PGPHASHALGO_SHA384:
01454         case PGPHASHALGO_SHA512:
01455         case PGPHASHALGO_MD4:
01456         case PGPHASHALGO_RIPEMD128:
01457         case PGPHASHALGO_CRC32:
01458         case PGPHASHALGO_ADLER32:
01459         case PGPHASHALGO_CRC64:
01460             (void) rpmlibNeedsFeature(h, "FileDigestParameterized", "4.4.6-1");
01461             /*@switchbreak@*/ break;
01462         case PGPHASHALGO_MD5:
01463         case PGPHASHALGO_HAVAL_5_160:           /* XXX unimplemented */
01464         default:
01465             dalgo = PGPHASHALGO_MD5;
01466             /*@switchbreak@*/ break;
01467         }
01468             
01469         buf[0] = '\0';
01470         if (S_ISREG(flp->fl_mode))
01471             (void) dodigest(dalgo, flp->diskURL, (unsigned char *)buf, 1, NULL);
01472         s = buf;
01473         (void) headerAddOrAppendEntry(h, RPMTAG_FILEDIGESTS, RPM_STRING_ARRAY_TYPE,
01474                                &s, 1);
01475         (void) headerAddOrAppendEntry(h, RPMTAG_FILEDIGESTALGOS, RPM_INT32_TYPE,
01476                                &dalgo, 1);
01477       }
01478         
01479         buf[0] = '\0';
01480         if (S_ISLNK(flp->fl_mode)) {
01481             int xx = Readlink(flp->diskURL, buf, BUFSIZ);
01482             if (xx >= 0)
01483                 buf[xx] = '\0';
01484             if (fl->buildRootURL) {
01485                 const char * buildRoot;
01486                 (void) urlPath(fl->buildRootURL, &buildRoot);
01487 
01488                 if (buf[0] == '/' && strcmp(buildRoot, "/") &&
01489                     !strncmp(buf, buildRoot, strlen(buildRoot))) {
01490                      rpmError(RPMERR_BADSPEC,
01491                                 _("Symlink points to BuildRoot: %s -> %s\n"),
01492                                 flp->fileURL, buf);
01493                     fl->processingFailed = 1;
01494                 }
01495             }
01496         }
01497         s = buf;
01498         (void) headerAddOrAppendEntry(h, RPMTAG_FILELINKTOS, RPM_STRING_ARRAY_TYPE,
01499                                &s, 1);
01500         
01501         if (flp->flags & RPMFILE_GHOST) {
01502             flp->verifyFlags &= ~(RPMVERIFY_MD5 | RPMVERIFY_FILESIZE |
01503                                 RPMVERIFY_LINKTO | RPMVERIFY_MTIME);
01504         }
01505         (void) headerAddOrAppendEntry(h, RPMTAG_FILEVERIFYFLAGS, RPM_INT32_TYPE,
01506                                &(flp->verifyFlags), 1);
01507         
01508         if (!isSrc && isDoc(fl, flp->fileURL))
01509             flp->flags |= RPMFILE_DOC;
01510         /* XXX Should directories have %doc/%config attributes? (#14531) */
01511         if (S_ISDIR(flp->fl_mode))
01512             flp->flags &= ~(RPMFILE_CONFIG|RPMFILE_DOC);
01513 
01514         (void) headerAddOrAppendEntry(h, RPMTAG_FILEFLAGS, RPM_INT32_TYPE,
01515                                &(flp->flags), 1);
01516 
01517         /* Add file security context to package. */
01518 /*@-branchstate@*/
01519         if (sx != NULL) {
01520             mode_t fmode = (uint_16)flp->fl_mode;
01521             s = rpmsxFContext(sx, flp->fileURL, fmode);
01522             if (s == NULL) s = "";
01523             (void) headerAddOrAppendEntry(h, RPMTAG_FILECONTEXTS, RPM_STRING_ARRAY_TYPE,
01524                                &s, 1);
01525         }
01526 /*@=branchstate@*/
01527 
01528     }
01529     sx = rpmsxFree(sx);
01530     sxfn = _free(sxfn);
01531 
01532     (void) headerAddEntry(h, RPMTAG_SIZE, RPM_INT32_TYPE,
01533                    &(fl->totalFileSize), 1);
01534 
01535     compressFilelist(h);
01536 
01537   { int scareMem = 0;
01538     rpmts ts = NULL;    /* XXX FIXME drill rpmts ts all the way down here */
01539     rpmfi fi = rpmfiNew(ts, h, RPMTAG_BASENAMES, scareMem);
01540     char * a, * d;
01541 
01542     if (fi == NULL) return;             /* XXX can't happen */
01543 
01544 /*@-onlytrans@*/
01545     fi->te = xcalloc(1, sizeof(*fi->te));
01546 /*@=onlytrans@*/
01547     fi->te->type = TR_ADDED;
01548 
01549     fi->dnl = _free(fi->dnl);
01550     fi->bnl = _free(fi->bnl);
01551     if (!scareMem) fi->dil = _free(fi->dil);
01552 
01553     /* XXX Insure at least 1 byte is always allocated. */
01554     fi->dnl = xmalloc(fi->fc * sizeof(*fi->dnl) + dpathlen + 1);
01555     d = (char *)(fi->dnl + fi->fc);
01556     *d = '\0';
01557 
01558     fi->bnl = xmalloc(fi->fc * (sizeof(*fi->bnl) + sizeof(*fi->dil)));
01559 /*@-dependenttrans@*/ /* FIX: artifact of spoofing headerGetEntry */
01560     fi->dil = (!scareMem)
01561         ? xcalloc(sizeof(*fi->dil), fi->fc)
01562         : (int *)(fi->bnl + fi->fc);
01563 /*@=dependenttrans@*/
01564 
01565     /* XXX Insure at least 1 byte is always allocated. */
01566     fi->apath = xmalloc(fi->fc * sizeof(*fi->apath) + apathlen + 1);
01567     a = (char *)(fi->apath + fi->fc);
01568     *a = '\0';
01569 
01570     fi->actions = xcalloc(sizeof(*fi->actions), fi->fc);
01571     fi->fmapflags = xcalloc(sizeof(*fi->fmapflags), fi->fc);
01572     fi->astriplen = 0;
01573     if (fl->buildRootURL)
01574         fi->astriplen = strlen(fl->buildRootURL);
01575     fi->striplen = 0;
01576     fi->fuser = NULL;
01577     fi->fgroup = NULL;
01578 
01579     /* Make the cpio list */
01580     if (fi->dil != NULL)        /* XXX can't happen */
01581     for (i = 0, flp = fl->fileList; i < fi->fc; i++, flp++) {
01582         char * b;
01583 
01584         /* Skip (possible) duplicate file entries, use last entry info. */
01585         while (((flp - fl->fileList) < (fl->fileListRecsUsed - 1)) &&
01586                 !strcmp(flp->fileURL, flp[1].fileURL))
01587             flp++;
01588 
01589         if (flp->flags & RPMFILE_EXCLUDE) {
01590             i--;
01591             continue;
01592         }
01593 
01594         if ((fnlen = strlen(flp->diskURL) + 1) > fi->fnlen)
01595             fi->fnlen = fnlen;
01596 
01597         /* Create disk directory and base name. */
01598         fi->dil[i] = i;
01599 /*@-dependenttrans@*/ /* FIX: artifact of spoofing headerGetEntry */
01600         fi->dnl[fi->dil[i]] = d;
01601 /*@=dependenttrans@*/
01602         d = stpcpy(d, flp->diskURL);
01603 
01604         /* Make room for the dirName NUL, find start of baseName. */
01605         for (b = d; b > fi->dnl[fi->dil[i]] && *b != '/'; b--)
01606             b[1] = b[0];
01607         b++;            /* dirname's end in '/' */
01608         *b++ = '\0';    /* terminate dirname, b points to basename */
01609         fi->bnl[i] = b;
01610         d += 2;         /* skip both dirname and basename NUL's */
01611 
01612         /* Create archive path, normally adding "./" */
01613         /*@-dependenttrans@*/   /* FIX: xstrdup? nah ... */
01614         fi->apath[i] = a;
01615         /*@=dependenttrans@*/
01616         if (_addDotSlash)
01617             a = stpcpy(a, "./");
01618         (void) urlPath(flp->fileURL, &apath);
01619         a = stpcpy(a, (apath + skipLen));
01620         a++;            /* skip apath NUL */
01621 
01622         if (flp->flags & RPMFILE_GHOST) {
01623             fi->actions[i] = FA_SKIP;
01624             continue;
01625         }
01626         fi->actions[i] = FA_COPYOUT;
01627         fi->fmapflags[i] = CPIO_MAP_PATH |
01628                 CPIO_MAP_TYPE | CPIO_MAP_MODE | CPIO_MAP_UID | CPIO_MAP_GID;
01629         if (isSrc)
01630             fi->fmapflags[i] |= CPIO_FOLLOW_SYMLINKS;
01631 
01632     }
01633     /*@-branchstate -compdef@*/
01634     if (fip)
01635         *fip = fi;
01636     else
01637         fi = rpmfiFree(fi);
01638     /*@=branchstate =compdef@*/
01639   }
01640 }
01641 /*@=bounds@*/
01642 
01645 /*@-boundswrite@*/
01646 static /*@null@*/ FileListRec freeFileList(/*@only@*/ FileListRec fileList,
01647                         int count)
01648         /*@*/
01649 {
01650     while (count--) {
01651         fileList[count].diskURL = _free(fileList[count].diskURL);
01652         fileList[count].fileURL = _free(fileList[count].fileURL);
01653         fileList[count].langs = _free(fileList[count].langs);
01654     }
01655     fileList = _free(fileList);
01656     return NULL;
01657 }
01658 /*@=boundswrite@*/
01659 
01660 /* forward ref */
01661 static int recurseDir(FileList fl, const char * diskURL)
01662         /*@globals check_fileList, rpmGlobalMacroContext, h_errno,
01663                 fileSystem, internalState @*/
01664         /*@modifies *fl, fl->processingFailed,
01665                 fl->fileList, fl->fileListRecsAlloced, fl->fileListRecsUsed,
01666                 fl->totalFileSize, fl->fileCount, fl->inFtw, fl->isDir,
01667                 check_fileList, rpmGlobalMacroContext,
01668                 fileSystem, internalState @*/;
01669 
01677 /*@-boundswrite@*/
01678 static int addFile(FileList fl, const char * diskURL,
01679                 /*@null@*/ struct stat * statp)
01680         /*@globals check_fileList, rpmGlobalMacroContext, h_errno,
01681                 fileSystem, internalState @*/
01682         /*@modifies *statp, *fl, fl->processingFailed,
01683                 fl->fileList, fl->fileListRecsAlloced, fl->fileListRecsUsed,
01684                 fl->totalFileSize, fl->fileCount,
01685                 check_fileList, rpmGlobalMacroContext,
01686                 fileSystem, internalState @*/
01687 {
01688     const char *fn = xstrdup(diskURL);
01689     const char *fileURL = fn;
01690     struct stat statbuf;
01691     mode_t fileMode;
01692     uid_t fileUid;
01693     gid_t fileGid;
01694     const char *fileUname;
01695     const char *fileGname;
01696     char *lang;
01697     
01698     /* Path may have prepended buildRootURL, so locate the original filename. */
01699     /*
01700      * XXX There are 3 types of entry into addFile:
01701      *
01702      *  From                    diskUrl                 statp
01703      *  =====================================================
01704      *  processBinaryFile       path                    NULL
01705      *  processBinaryFile       glob result path        NULL
01706      *  recurseDir              path                    stat
01707      *
01708      */
01709 /*@-branchstate@*/
01710     {   const char *fileName;
01711         int urltype = urlPath(fileURL, &fileName);
01712         switch (urltype) {
01713         case URL_IS_PATH:
01714             fileURL += (fileName - fileURL);
01715             if (fl->buildRootURL && strcmp(fl->buildRootURL, "/")) {
01716                 size_t nb = strlen(fl->buildRootURL);
01717                 const char * s = fileURL + nb;
01718                 char * t = (char *) fileURL;
01719                 (void) memmove(t, s, nb);
01720             }
01721             fileURL = fn;
01722             break;
01723         default:
01724             if (fl->buildRootURL && strcmp(fl->buildRootURL, "/"))
01725                 fileURL += strlen(fl->buildRootURL);
01726             break;
01727         }
01728     }
01729 /*@=branchstate@*/
01730 
01731     /* XXX make sure '/' can be packaged also */
01732     /*@-branchstate@*/
01733     if (*fileURL == '\0')
01734         fileURL = "/";
01735     /*@=branchstate@*/
01736 
01737     /* If we are using a prefix, validate the file */
01738     if (!fl->inFtw && fl->prefix) {
01739         const char *prefixTest;
01740         const char *prefixPtr = fl->prefix;
01741 
01742         (void) urlPath(fileURL, &prefixTest);
01743         while (*prefixPtr && *prefixTest && (*prefixTest == *prefixPtr)) {
01744             prefixPtr++;
01745             prefixTest++;
01746         }
01747         if (*prefixPtr || (*prefixTest && *prefixTest != '/')) {
01748             rpmError(RPMERR_BADSPEC, _("File doesn't match prefix (%s): %s\n"),
01749                      fl->prefix, fileURL);
01750             fl->processingFailed = 1;
01751             return RPMERR_BADSPEC;
01752         }
01753     }
01754 
01755     if (statp == NULL) {
01756         statp = &statbuf;
01757         memset(statp, 0, sizeof(*statp));
01758         if (fl->devtype) {
01759             time_t now = time(NULL);
01760 
01761             /* XXX hack up a stat structure for a %dev(...) directive. */
01762             statp->st_nlink = 1;
01763             statp->st_rdev =
01764                 ((fl->devmajor & 0xff) << 8) | (fl->devminor & 0xff);
01765             statp->st_dev = statp->st_rdev;
01766             statp->st_mode = (fl->devtype == 'b' ? S_IFBLK : S_IFCHR);
01767             statp->st_mode |= (fl->cur_ar.ar_fmode & 0777);
01768             statp->st_atime = now;
01769             statp->st_mtime = now;
01770             statp->st_ctime = now;
01771         } else if (Lstat(diskURL, statp)) {
01772             rpmError(RPMERR_BADSPEC, _("File not found: %s\n"), diskURL);
01773             fl->processingFailed = 1;
01774             return RPMERR_BADSPEC;
01775         }
01776     }
01777 
01778     if ((! fl->isDir) && S_ISDIR(statp->st_mode)) {
01779 /*@-nullstate@*/ /* FIX: fl->buildRootURL may be NULL */
01780         return recurseDir(fl, diskURL);
01781 /*@=nullstate@*/
01782     }
01783 
01784     fileMode = statp->st_mode;
01785     fileUid = statp->st_uid;
01786     fileGid = statp->st_gid;
01787 
01788     if (S_ISDIR(fileMode) && fl->cur_ar.ar_dmodestr) {
01789         fileMode &= S_IFMT;
01790         fileMode |= fl->cur_ar.ar_dmode;
01791     } else if (fl->cur_ar.ar_fmodestr != NULL) {
01792         fileMode &= S_IFMT;
01793         fileMode |= fl->cur_ar.ar_fmode;
01794     }
01795     if (fl->cur_ar.ar_user) {
01796         fileUname = getUnameS(fl->cur_ar.ar_user);
01797     } else {
01798         fileUname = getUname(fileUid);
01799     }
01800     if (fl->cur_ar.ar_group) {
01801         fileGname = getGnameS(fl->cur_ar.ar_group);
01802     } else {
01803         fileGname = getGname(fileGid);
01804     }
01805         
01806     /* Default user/group to builder's user/group */
01807     if (fileUname == NULL)
01808         fileUname = getUname(getuid());
01809     if (fileGname == NULL)
01810         fileGname = getGname(getgid());
01811     
01812     /* S_XXX macro must be consistent with type in find call at check-files script */
01813     if (check_fileList && (S_ISREG(fileMode) || S_ISLNK(fileMode))) {
01814         const char * diskfn = NULL;
01815         (void) urlPath(diskURL, &diskfn);
01816         appendStringBuf(check_fileList, diskfn);
01817         appendStringBuf(check_fileList, "\n");
01818     }
01819 
01820     /* Add to the file list */
01821     if (fl->fileListRecsUsed == fl->fileListRecsAlloced) {
01822         fl->fileListRecsAlloced += 128;
01823         fl->fileList = xrealloc(fl->fileList,
01824                         fl->fileListRecsAlloced * sizeof(*(fl->fileList)));
01825     }
01826             
01827     {   FileListRec flp = &fl->fileList[fl->fileListRecsUsed];
01828         int i;
01829 
01830         flp->fl_st = *statp;    /* structure assignment */
01831         flp->fl_mode = fileMode;
01832         flp->fl_uid = fileUid;
01833         flp->fl_gid = fileGid;
01834 
01835         flp->fileURL = xstrdup(fileURL);
01836         flp->diskURL = xstrdup(diskURL);
01837         flp->uname = fileUname;
01838         flp->gname = fileGname;
01839 
01840         if (fl->currentLangs && fl->nLangs > 0) {
01841             char * ncl;
01842             size_t nl = 0;
01843             
01844             for (i = 0; i < fl->nLangs; i++)
01845                 nl += strlen(fl->currentLangs[i]) + 1;
01846 
01847             flp->langs = ncl = xmalloc(nl);
01848             for (i = 0; i < fl->nLangs; i++) {
01849                 const char *ocl;
01850                 if (i)  *ncl++ = '|';
01851                 for (ocl = fl->currentLangs[i]; *ocl != '\0'; ocl++)
01852                         *ncl++ = *ocl;
01853                 *ncl = '\0';
01854             }
01855         } else if (! parseForRegexLang(fileURL, &lang)) {
01856             flp->langs = xstrdup(lang);
01857         } else {
01858             flp->langs = xstrdup("");
01859         }
01860 
01861         flp->flags = fl->currentFlags;
01862         flp->specdFlags = fl->currentSpecdFlags;
01863         flp->verifyFlags = fl->currentVerifyFlags;
01864 
01865         /* Hard links need be counted only once. */
01866         if (S_ISREG(flp->fl_mode) && flp->fl_nlink > 1) {
01867             FileListRec ilp;
01868             for (i = 0;  i < fl->fileListRecsUsed; i++) {
01869                 ilp = fl->fileList + i;
01870                 if (!S_ISREG(ilp->fl_mode))
01871                     continue;
01872                 if (flp->fl_nlink != ilp->fl_nlink)
01873                     continue;
01874                 if (flp->fl_ino != ilp->fl_ino)
01875                     continue;
01876                 if (flp->fl_dev != ilp->fl_dev)
01877                     continue;
01878                 break;
01879             }
01880         } else
01881             i = fl->fileListRecsUsed;
01882 
01883         if (!(flp->flags & RPMFILE_EXCLUDE) && S_ISREG(flp->fl_mode) && i >= fl->fileListRecsUsed) 
01884             fl->totalFileSize += flp->fl_size;
01885     }
01886 
01887     fl->fileListRecsUsed++;
01888     fl->fileCount++;
01889 /*@i@*/ fn = _free(fn);
01890 
01891     return 0;
01892 }
01893 /*@=boundswrite@*/
01894 
01901 static int recurseDir(FileList fl, const char * diskURL)
01902 {
01903     char * ftsSet[2];
01904     FTS * ftsp;
01905     FTSENT * fts;
01906     int myFtsOpts = (FTS_COMFOLLOW | FTS_NOCHDIR | FTS_PHYSICAL);
01907     int rc = RPMERR_BADSPEC;
01908 
01909     fl->inFtw = 1;  /* Flag to indicate file has buildRootURL prefixed */
01910     fl->isDir = 1;  /* Keep it from following myftw() again         */
01911 
01912     ftsSet[0] = (char *) diskURL;
01913     ftsSet[1] = NULL;
01914     ftsp = Fts_open(ftsSet, myFtsOpts, NULL);
01915     while ((fts = Fts_read(ftsp)) != NULL) {
01916         switch (fts->fts_info) {
01917         case FTS_D:             /* preorder directory */
01918         case FTS_F:             /* regular file */
01919         case FTS_SL:            /* symbolic link */
01920         case FTS_SLNONE:        /* symbolic link without target */
01921         case FTS_DEFAULT:       /* none of the above */
01922             rc = addFile(fl, fts->fts_accpath, fts->fts_statp);
01923             /*@switchbreak@*/ break;
01924         case FTS_DOT:           /* dot or dot-dot */
01925         case FTS_DP:            /* postorder directory */
01926             rc = 0;
01927             /*@switchbreak@*/ break;
01928         case FTS_NS:            /* stat(2) failed */
01929         case FTS_DNR:           /* unreadable directory */
01930         case FTS_ERR:           /* error; errno is set */
01931         case FTS_DC:            /* directory that causes cycles */
01932         case FTS_NSOK:          /* no stat(2) requested */
01933         case FTS_INIT:          /* initialized only */
01934         case FTS_W:             /* whiteout object */
01935         default:
01936             rc = RPMERR_BADSPEC;
01937             /*@switchbreak@*/ break;
01938         }
01939         if (rc)
01940             break;
01941     }
01942     (void) Fts_close(ftsp);
01943 
01944     fl->isDir = 0;
01945     fl->inFtw = 0;
01946 
01947     return rc;
01948 }
01949 
01958 static int processMetadataFile(Package pkg, FileList fl, const char * fileURL,
01959                 rpmTag tag)
01960         /*@globals check_fileList, rpmGlobalMacroContext, h_errno,
01961                 fileSystem, internalState @*/
01962         /*@modifies pkg->header, *fl, fl->processingFailed,
01963                 fl->fileList, fl->fileListRecsAlloced, fl->fileListRecsUsed,
01964                 fl->totalFileSize, fl->fileCount,
01965                 check_fileList, rpmGlobalMacroContext,
01966                 fileSystem, internalState @*/
01967 {
01968     const char * buildURL = "%{_builddir}/%{?buildsubdir}/";
01969     const char * fn = NULL;
01970     const char * apkt = NULL;
01971     const unsigned char * pkt = NULL;
01972     ssize_t pktlen = 0;
01973     int absolute = 0;
01974     int rc = 1;
01975     int xx;
01976 
01977     (void) urlPath(fileURL, &fn);
01978     if (*fn == '/') {
01979         fn = rpmGenPath(fl->buildRootURL, NULL, fn);
01980         absolute = 1;
01981     } else
01982         fn = rpmGenPath(buildURL, NULL, fn);
01983 
01984 /*@-branchstate@*/
01985     switch (tag) {
01986     default:
01987         rpmError(RPMERR_BADSPEC, _("%s: can't load unknown tag (%d).\n"),
01988                 fn, tag);
01989         goto exit;
01990         /*@notreached@*/ break;
01991     case RPMTAG_PUBKEYS:
01992         if ((rc = pgpReadPkts(fn, &pkt, &pktlen)) <= 0) {
01993             rpmError(RPMERR_BADSPEC, _("%s: public key read failed.\n"), fn);
01994             goto exit;
01995         }
01996         if (rc != PGPARMOR_PUBKEY) {
01997             rpmError(RPMERR_BADSPEC, _("%s: not an armored public key.\n"), fn);
01998             goto exit;
01999         }
02000         apkt = pgpArmorWrap(PGPARMOR_PUBKEY, pkt, pktlen);
02001         break;
02002     case RPMTAG_POLICIES:
02003         if ((rc = rpmioSlurp(fn, &pkt, &pktlen)) != 0) {
02004             rpmError(RPMERR_BADSPEC, _("%s: *.te policy read failed.\n"), fn);
02005             goto exit;
02006         }
02007         apkt = (const char *) pkt;      /* XXX unsigned char */
02008         pkt = NULL;
02009         break;
02010     }
02011 /*@=branchstate@*/
02012 
02013     xx = headerAddOrAppendEntry(pkg->header, tag,
02014                 RPM_STRING_ARRAY_TYPE, &apkt, 1);
02015 
02016     rc = 0;
02017     if (absolute)
02018         rc = addFile(fl, fn, NULL);
02019 
02020 exit:
02021     apkt = _free(apkt);
02022     pkt = _free(pkt);
02023     fn = _free(fn);
02024     if (rc) {
02025         fl->processingFailed = 1;
02026         rc = RPMERR_BADSPEC;
02027     }
02028     return rc;
02029 }
02030 
02038 static int processBinaryFile(/*@unused@*/ Package pkg, FileList fl,
02039                 const char * fileURL)
02040         /*@globals rpmGlobalMacroContext, h_errno, fileSystem, internalState @*/
02041         /*@modifies *fl, fl->processingFailed,
02042                 fl->fileList, fl->fileListRecsAlloced, fl->fileListRecsUsed,
02043                 fl->totalFileSize, fl->fileCount,
02044                 rpmGlobalMacroContext, fileSystem, internalState @*/
02045 {
02046     int quote = 1;      /* XXX permit quoted glob characters. */
02047     int doGlob;
02048     const char *diskURL = NULL;
02049     int rc = 0;
02050     
02051     doGlob = Glob_pattern_p(fileURL, quote);
02052 
02053     /* Check that file starts with leading "/" */
02054     {   const char * fileName;
02055         (void) urlPath(fileURL, &fileName);
02056         if (*fileName != '/') {
02057             rpmError(RPMERR_BADSPEC, _("File needs leading \"/\": %s\n"),
02058                         fileName);
02059             rc = 1;
02060             goto exit;
02061         }
02062     }
02063     
02064     /* Copy file name or glob pattern removing multiple "/" chars. */
02065     /*
02066      * Note: rpmGetPath should guarantee a "canonical" path. That means
02067      * that the following pathologies should be weeded out:
02068      *          //bin//sh
02069      *          //usr//bin/
02070      *          /.././../usr/../bin//./sh
02071      */
02072     diskURL = rpmGenPath(fl->buildRootURL, NULL, fileURL);
02073 
02074     if (doGlob) {
02075         const char ** argv = NULL;
02076         int argc = 0;
02077         int i;
02078 
02079         /* XXX for %dev marker in file manifest only */
02080         if (fl->noGlob) {
02081             rpmError(RPMERR_BADSPEC, _("Glob not permitted: %s\n"),
02082                         diskURL);
02083             rc = 1;
02084             goto exit;
02085         }
02086 
02087         /*@-branchstate@*/
02088         rc = rpmGlob(diskURL, &argc, &argv);
02089         if (rc == 0 && argc >= 1) {
02090             for (i = 0; i < argc; i++) {
02091                 rc = addFile(fl, argv[i], NULL);
02092 /*@-boundswrite@*/
02093                 argv[i] = _free(argv[i]);
02094 /*@=boundswrite@*/
02095             }
02096             argv = _free(argv);
02097         } else {
02098             rpmError(RPMERR_BADSPEC, _("File not found by glob: %s\n"),
02099                         diskURL);
02100             rc = 1;
02101             goto exit;
02102         }
02103         /*@=branchstate@*/
02104     } else {
02105         rc = addFile(fl, diskURL, NULL);
02106     }
02107 
02108 exit:
02109     diskURL = _free(diskURL);
02110     if (rc) {
02111         fl->processingFailed = 1;
02112         rc = RPMERR_BADSPEC;
02113     }
02114     return rc;
02115 }
02116 
02119 /*@-boundswrite@*/
02120 static int processPackageFiles(Spec spec, Package pkg,
02121                                int installSpecialDoc, int test)
02122         /*@globals rpmGlobalMacroContext, h_errno,
02123                 fileSystem, internalState@*/
02124         /*@modifies spec->macros,
02125                 pkg->cpioList, pkg->fileList, pkg->specialDoc, pkg->header,
02126                 rpmGlobalMacroContext, fileSystem, internalState @*/
02127 {
02128     HGE_t hge = (HGE_t)headerGetEntryMinMemory;
02129     struct FileList_s fl;
02130     char *s, **files, **fp;
02131     const char *fileName;
02132     char buf[BUFSIZ];
02133     struct AttrRec_s arbuf;
02134     AttrRec specialDocAttrRec = &arbuf;
02135     char *specialDoc = NULL;
02136 
02137     nullAttrRec(specialDocAttrRec);
02138     pkg->cpioList = NULL;
02139 
02140     if (pkg->fileFile) {
02141         const char *ffn;
02142         FILE * f;
02143         FD_t fd;
02144 
02145         /* XXX W2DO? urlPath might be useful here. */
02146         if (*pkg->fileFile == '/') {
02147             ffn = rpmGetPath(pkg->fileFile, NULL);
02148         } else {
02149             /* XXX FIXME: add %{buildsubdir} */
02150             ffn = rpmGetPath("%{_builddir}/",
02151                 (spec->buildSubdir ? spec->buildSubdir : "") ,
02152                 "/", pkg->fileFile, NULL);
02153         }
02154         fd = Fopen(ffn, "r.fpio");
02155 
02156         if (fd == NULL || Ferror(fd)) {
02157             rpmError(RPMERR_BADFILENAME,
02158                 _("Could not open %%files file %s: %s\n"),
02159                 ffn, Fstrerror(fd));
02160             return RPMERR_BADFILENAME;
02161         }
02162         ffn = _free(ffn);
02163 
02164         /*@+voidabstract@*/ f = fdGetFp(fd); /*@=voidabstract@*/
02165         if (f != NULL)
02166         while (fgets(buf, sizeof(buf), f)) {
02167             handleComments(buf);
02168             if (expandMacros(spec, spec->macros, buf, sizeof(buf))) {
02169                 rpmError(RPMERR_BADSPEC, _("line: %s\n"), buf);
02170                 return RPMERR_BADSPEC;
02171             }
02172             appendStringBuf(pkg->fileList, buf);
02173         }
02174         (void) Fclose(fd);
02175     }
02176     
02177     /* Init the file list structure */
02178     memset(&fl, 0, sizeof(fl));
02179 
02180     fl.buildRootURL = rpmGenPath(spec->rootURL, "%{?buildroot}", NULL);
02181 
02182     if (hge(pkg->header, RPMTAG_DEFAULTPREFIX, NULL, (void **)&fl.prefix, NULL))
02183         fl.prefix = xstrdup(fl.prefix);
02184     else
02185         fl.prefix = NULL;
02186 
02187     fl.fileCount = 0;
02188     fl.totalFileSize = 0;
02189     fl.processingFailed = 0;
02190 
02191     fl.passedSpecialDoc = 0;
02192     fl.isSpecialDoc = 0;
02193 
02194     fl.isDir = 0;
02195     fl.inFtw = 0;
02196     fl.currentFlags = 0;
02197     fl.currentVerifyFlags = 0;
02198     
02199     fl.noGlob = 0;
02200     fl.devtype = 0;
02201     fl.devmajor = 0;
02202     fl.devminor = 0;
02203 
02204     nullAttrRec(&fl.cur_ar);
02205     nullAttrRec(&fl.def_ar);
02206     dupAttrRec(&root_ar, &fl.def_ar);   /* XXX assume %defattr(-,root,root) */
02207 
02208     fl.defVerifyFlags = RPMVERIFY_ALL;
02209     fl.nLangs = 0;
02210     fl.currentLangs = NULL;
02211 
02212     fl.currentSpecdFlags = 0;
02213     fl.defSpecdFlags = 0;
02214 
02215     fl.docDirCount = 0;
02216     fl.docDirs[fl.docDirCount++] = xstrdup("/usr/doc");
02217     fl.docDirs[fl.docDirCount++] = xstrdup("/usr/man");
02218     fl.docDirs[fl.docDirCount++] = xstrdup("/usr/info");
02219     fl.docDirs[fl.docDirCount++] = xstrdup("/usr/X11R6/man");
02220     fl.docDirs[fl.docDirCount++] = xstrdup("/usr/share/doc");
02221     fl.docDirs[fl.docDirCount++] = xstrdup("/usr/share/man");
02222     fl.docDirs[fl.docDirCount++] = xstrdup("/usr/share/info");
02223     fl.docDirs[fl.docDirCount++] = xstrdup("/usr/src/examples");
02224     fl.docDirs[fl.docDirCount++] = rpmGetPath("%{_docdir}", NULL);
02225     fl.docDirs[fl.docDirCount++] = rpmGetPath("%{_mandir}", NULL);
02226     fl.docDirs[fl.docDirCount++] = rpmGetPath("%{_infodir}", NULL);
02227     fl.docDirs[fl.docDirCount++] = rpmGetPath("%{_javadocdir}", NULL);
02228     fl.docDirs[fl.docDirCount++] = rpmGetPath("%{_examplesdir}", NULL);
02229     
02230     fl.fileList = NULL;
02231     fl.fileListRecsAlloced = 0;
02232     fl.fileListRecsUsed = 0;
02233 
02234     s = getStringBuf(pkg->fileList);
02235     files = splitString(s, strlen(s), '\n');
02236 
02237     for (fp = files; *fp != NULL; fp++) {
02238         s = *fp;
02239         SKIPSPACE(s);
02240         if (*s == '\0')
02241             continue;
02242         fileName = NULL;
02243         /*@-nullpass@*/ /* LCL: buf is NULL ?!? */
02244         strcpy(buf, s);
02245         /*@=nullpass@*/
02246         
02247         /* Reset for a new line in %files */
02248         fl.isDir = 0;
02249         fl.inFtw = 0;
02250         fl.currentFlags = 0;
02251         /* turn explicit flags into %def'd ones (gosh this is hacky...) */
02252         fl.currentSpecdFlags = ((unsigned)fl.defSpecdFlags) >> 8;
02253         fl.currentVerifyFlags = fl.defVerifyFlags;
02254         fl.isSpecialDoc = 0;
02255 
02256         fl.noGlob = 0;
02257         fl.devtype = 0;
02258         fl.devmajor = 0;
02259         fl.devminor = 0;
02260 
02261         /* XXX should reset to %deflang value */
02262         if (fl.currentLangs) {
02263             int i;
02264             for (i = 0; i < fl.nLangs; i++)
02265                 /*@-unqualifiedtrans@*/
02266                 fl.currentLangs[i] = _free(fl.currentLangs[i]);
02267                 /*@=unqualifiedtrans@*/
02268             fl.currentLangs = _free(fl.currentLangs);
02269         }
02270         fl.nLangs = 0;
02271 
02272         dupAttrRec(&fl.def_ar, &fl.cur_ar);
02273 
02274         /*@-nullpass@*/ /* LCL: buf is NULL ?!? */
02275         if (parseForVerify(buf, &fl))
02276             continue;
02277         if (parseForAttr(buf, &fl))
02278             continue;
02279         if (parseForDev(buf, &fl))
02280             continue;
02281         if (parseForConfig(buf, &fl))
02282             continue;
02283         if (parseForLang(buf, &fl))
02284             continue;
02285         /*@-nullstate@*/        /* FIX: pkg->fileFile might be NULL */
02286         if (parseForSimple(spec, pkg, buf, &fl, &fileName))
02287         /*@=nullstate@*/
02288             continue;
02289         /*@=nullpass@*/
02290         if (fileName == NULL)
02291             continue;
02292 
02293         /*@-branchstate@*/
02294         if (fl.isSpecialDoc) {
02295             /* Save this stuff for last */
02296             specialDoc = _free(specialDoc);
02297             specialDoc = xstrdup(fileName);
02298             dupAttrRec(&fl.cur_ar, specialDocAttrRec);
02299         } else if (fl.currentFlags & RPMFILE_PUBKEY) {
02300 /*@-nullstate@*/        /* FIX: pkg->fileFile might be NULL */
02301             (void) processMetadataFile(pkg, &fl, fileName, RPMTAG_PUBKEYS);
02302 /*@=nullstate@*/
02303         } else if (fl.currentFlags & RPMFILE_POLICY) {
02304 /*@-nullstate@*/        /* FIX: pkg->fileFile might be NULL */
02305             (void) processMetadataFile(pkg, &fl, fileName, RPMTAG_POLICIES);
02306 /*@=nullstate@*/
02307         } else {
02308 /*@-nullstate@*/        /* FIX: pkg->fileFile might be NULL */
02309             (void) processBinaryFile(pkg, &fl, fileName);
02310 /*@=nullstate@*/
02311         }
02312         /*@=branchstate@*/
02313     }
02314 
02315     /* Now process special doc, if there is one */
02316     if (specialDoc) {
02317         if (installSpecialDoc) {
02318             int _missing_doc_files_terminate_build =
02319                     rpmExpandNumeric("%{?_missing_doc_files_terminate_build}");
02320             int rc;
02321 
02322             rc = doScript(spec, RPMBUILD_STRINGBUF, "%doc", pkg->specialDoc, test);
02323             if (rc && _missing_doc_files_terminate_build)
02324                 fl.processingFailed = rc;
02325         }
02326 
02327         /* Reset for %doc */
02328         fl.isDir = 0;
02329         fl.inFtw = 0;
02330         fl.currentFlags = 0;
02331         fl.currentVerifyFlags = fl.defVerifyFlags;
02332 
02333         fl.noGlob = 0;
02334         fl.devtype = 0;
02335         fl.devmajor = 0;
02336         fl.devminor = 0;
02337 
02338         /* XXX should reset to %deflang value */
02339         if (fl.currentLangs) {
02340             int i;
02341             for (i = 0; i < fl.nLangs; i++)
02342                 /*@-unqualifiedtrans@*/
02343                 fl.currentLangs[i] = _free(fl.currentLangs[i]);
02344                 /*@=unqualifiedtrans@*/
02345             fl.currentLangs = _free(fl.currentLangs);
02346         }
02347         fl.nLangs = 0;
02348 
02349         dupAttrRec(specialDocAttrRec, &fl.cur_ar);
02350         freeAttrRec(specialDocAttrRec);
02351 
02352         /*@-nullstate@*/        /* FIX: pkg->fileFile might be NULL */
02353         (void) processBinaryFile(pkg, &fl, specialDoc);
02354         /*@=nullstate@*/
02355 
02356         specialDoc = _free(specialDoc);
02357     }
02358     
02359     freeSplitString(files);
02360 
02361     if (fl.processingFailed)
02362         goto exit;
02363 
02364     /* Verify that file attributes scope over hardlinks correctly. */
02365     if (checkHardLinks(&fl) && !rpmExpandNumeric("%{_hack_dontneed_PartialHardlinkSets}"))
02366         (void) rpmlibNeedsFeature(pkg->header,
02367                         "PartialHardlinkSets", "4.0.4-1");
02368 
02369     genCpioListAndHeader(&fl, &pkg->cpioList, pkg->header, 0);
02370 
02371     if (spec->timeCheck)
02372         timeCheck(spec->timeCheck, pkg->header);
02373     
02374 exit:
02375     fl.buildRootURL = _free(fl.buildRootURL);
02376     fl.prefix = _free(fl.prefix);
02377 
02378     freeAttrRec(&fl.cur_ar);
02379     freeAttrRec(&fl.def_ar);
02380 
02381     if (fl.currentLangs) {
02382         int i;
02383         for (i = 0; i < fl.nLangs; i++)
02384             /*@-unqualifiedtrans@*/
02385             fl.currentLangs[i] = _free(fl.currentLangs[i]);
02386             /*@=unqualifiedtrans@*/
02387         fl.currentLangs = _free(fl.currentLangs);
02388     }
02389 
02390     fl.fileList = freeFileList(fl.fileList, fl.fileListRecsUsed);
02391     while (fl.docDirCount--)
02392         fl.docDirs[fl.docDirCount] = _free(fl.docDirs[fl.docDirCount]);
02393     return fl.processingFailed;
02394 }
02395 /*@=boundswrite@*/
02396 
02397 int initSourceHeader(Spec spec, StringBuf *sfp)
02398 {
02399     HeaderIterator hi;
02400     int_32 tag, type, count;
02401     const void * ptr;
02402     StringBuf sourceFiles;
02403     struct Source *srcPtr;
02404 
02405     /* Only specific tags are added to the source package header */
02406     /*@-branchstate@*/
02407   if (!spec->sourceHdrInit) {
02408     for (hi = headerInitIterator(spec->packages->header);
02409         headerNextIterator(hi, &tag, &type, &ptr, &count);
02410         ptr = headerFreeData(ptr, type))
02411     {
02412         switch (tag) {
02413         case RPMTAG_NAME:
02414         case RPMTAG_VERSION:
02415         case RPMTAG_RELEASE:
02416         case RPMTAG_EPOCH:
02417         case RPMTAG_SUMMARY:
02418         case RPMTAG_DESCRIPTION:
02419         case RPMTAG_PACKAGER:
02420         case RPMTAG_DISTRIBUTION:
02421         case RPMTAG_DISTURL:
02422         case RPMTAG_VENDOR:
02423         case RPMTAG_LICENSE:
02424         case RPMTAG_GROUP:
02425         case RPMTAG_OS:
02426         case RPMTAG_ARCH:
02427         case RPMTAG_CHANGELOGTIME:
02428         case RPMTAG_CHANGELOGNAME:
02429         case RPMTAG_CHANGELOGTEXT:
02430         case RPMTAG_URL:
02431         case RPMTAG_ICON:
02432         case RPMTAG_GIF:
02433         case RPMTAG_XPM:
02434         case HEADER_I18NTABLE:
02435             if (ptr)
02436                 (void)headerAddEntry(spec->sourceHeader, tag, type, ptr, count);
02437             /*@switchbreak@*/ break;
02438         default:
02439             /* do not copy */
02440             /*@switchbreak@*/ break;
02441         }
02442     }
02443     hi = headerFreeIterator(hi);
02444     /*@=branchstate@*/
02445 
02446     if (spec->BANames && spec->BACount > 0) {
02447         (void) headerAddEntry(spec->sourceHeader, RPMTAG_BUILDARCHS,
02448                        RPM_STRING_ARRAY_TYPE,
02449                        spec->BANames, spec->BACount);
02450     }
02451   }
02452 
02453     if (sfp != NULL && *sfp != NULL)
02454         sourceFiles = *sfp;
02455     else
02456         sourceFiles = newStringBuf();
02457 
02458     /* Construct the source/patch tag entries */
02459     appendLineStringBuf(sourceFiles, spec->specFile);
02460     if (spec->sourceHeader != NULL)
02461     for (srcPtr = spec->sources; srcPtr != NULL; srcPtr = srcPtr->next) {
02462       { const char * sfn;
02463         sfn = rpmGetPath( ((srcPtr->flags & RPMFILE_GHOST) ? "!" : ""),
02464                 "%{_sourcedir}/", srcPtr->source, NULL);
02465         appendLineStringBuf(sourceFiles, sfn);
02466         sfn = _free(sfn);
02467       }
02468 
02469         if (spec->sourceHdrInit)
02470             continue;
02471 
02472         if (srcPtr->flags & RPMFILE_SOURCE) {
02473             (void) headerAddOrAppendEntry(spec->sourceHeader, RPMTAG_SOURCE,
02474                                    RPM_STRING_ARRAY_TYPE, &srcPtr->source, 1);
02475             if (srcPtr->flags & RPMFILE_GHOST) {
02476                 (void) headerAddOrAppendEntry(spec->sourceHeader, RPMTAG_NOSOURCE,
02477                                        RPM_INT32_TYPE, &srcPtr->num, 1);
02478             }
02479         }
02480         if (srcPtr->flags & RPMFILE_PATCH) {
02481             (void) headerAddOrAppendEntry(spec->sourceHeader, RPMTAG_PATCH,
02482                                    RPM_STRING_ARRAY_TYPE, &srcPtr->source, 1);
02483             if (srcPtr->flags & RPMFILE_GHOST) {
02484                 (void) headerAddOrAppendEntry(spec->sourceHeader, RPMTAG_NOPATCH,
02485                                        RPM_INT32_TYPE, &srcPtr->num, 1);
02486             }
02487         }
02488     }
02489 
02490     if (sfp == NULL)
02491         sourceFiles = freeStringBuf(sourceFiles);
02492 
02493     spec->sourceHdrInit = 1;
02494 
02495     return 0;
02496 }
02497 
02498 int processSourceFiles(Spec spec)
02499 {
02500     StringBuf sourceFiles, *sfp = &sourceFiles;
02501     int x, isSpec = 1;
02502     struct FileList_s fl;
02503     char **files, **fp;
02504     int rc;
02505 
02506     *sfp = newStringBuf();
02507     x = initSourceHeader(spec, sfp);
02508 
02509     /* Construct the SRPM file list. */
02510     fl.fileList = xcalloc((spec->numSources + 1), sizeof(*fl.fileList));
02511     rc = fl.processingFailed = 0;
02512     fl.fileListRecsUsed = 0;
02513     fl.totalFileSize = 0;
02514     fl.prefix = NULL;
02515     fl.buildRootURL = NULL;
02516 
02517     {   const char *s = getStringBuf(*sfp);
02518         files = splitString(s, strlen(s), '\n');
02519     }
02520 
02521     /* The first source file is the spec file */
02522     x = 0;
02523     for (fp = files; *fp != NULL; fp++) {
02524         const char * diskURL, *diskPath;
02525         FileListRec flp;
02526 
02527         diskURL = *fp;
02528         SKIPSPACE(diskURL);
02529         if (! *diskURL)
02530             continue;
02531 
02532         flp = &fl.fileList[x];
02533 
02534         flp->flags = isSpec ? RPMFILE_SPECFILE : 0;
02535         /* files with leading ! are no source files */
02536         if (*diskURL == '!') {
02537             flp->flags |= RPMFILE_GHOST;
02538             diskURL++;
02539         }
02540 
02541         (void) urlPath(diskURL, &diskPath);
02542 
02543         flp->diskURL = xstrdup(diskURL);
02544         diskPath = strrchr(diskPath, '/');
02545         if (diskPath)
02546             diskPath++;
02547         else
02548             diskPath = diskURL;
02549 
02550         flp->fileURL = xstrdup(diskPath);
02551         flp->verifyFlags = RPMVERIFY_ALL;
02552 
02553         if (Stat(diskURL, &flp->fl_st)) {
02554             rpmError(RPMERR_BADSPEC, _("Bad file: %s: %s\n"),
02555                 diskURL, strerror(errno));
02556             rc = fl.processingFailed = 1;
02557         }
02558 
02559         flp->uname = getUname(flp->fl_uid);
02560         flp->gname = getGname(flp->fl_gid);
02561         flp->langs = xstrdup("");
02562         
02563         fl.totalFileSize += flp->fl_size;
02564         
02565         if (! (flp->uname && flp->gname)) {
02566             rpmError(RPMERR_BADSPEC, _("Bad owner/group: %s\n"), diskURL);
02567             rc = fl.processingFailed = 1;
02568         }
02569 
02570         isSpec = 0;
02571         x++;
02572     }
02573     fl.fileListRecsUsed = x;
02574     freeSplitString(files);
02575 
02576     if (rc)
02577         goto exit;
02578 
02579     spec->sourceCpioList = NULL;
02580     genCpioListAndHeader(&fl, &spec->sourceCpioList, spec->sourceHeader, 1);
02581 
02582 exit:
02583     *sfp = freeStringBuf(*sfp);
02584     fl.fileList = freeFileList(fl.fileList, fl.fileListRecsUsed);
02585     return rc;
02586 }
02587 
02593 static int checkFiles(StringBuf fileList)
02594         /*@globals rpmGlobalMacroContext, h_errno, fileSystem, internalState @*/
02595         /*@modifies rpmGlobalMacroContext, fileSystem, internalState @*/
02596 {
02597 /*@-readonlytrans@*/
02598     static const char * av_ckfile[] = { "%{?__check_files}", NULL };
02599 /*@=readonlytrans@*/
02600     StringBuf sb_stdout = NULL;
02601     const char * s;
02602     int rc;
02603     
02604     s = rpmExpand(av_ckfile[0], NULL);
02605     if (!(s && *s)) {
02606         rc = -1;
02607         goto exit;
02608     }
02609     rc = 0;
02610 
02611     rpmMessage(RPMMESS_NORMAL, _("Checking for unpackaged file(s): %s\n"), s);
02612 
02613 /*@-boundswrite@*/
02614     rc = rpmfcExec(av_ckfile, fileList, &sb_stdout, 0);
02615 /*@=boundswrite@*/
02616     if (rc < 0)
02617         goto exit;
02618     
02619     if (sb_stdout) {
02620         int _unpackaged_files_terminate_build =
02621                 rpmExpandNumeric("%{?_unpackaged_files_terminate_build}");
02622         const char * t;
02623 
02624         t = getStringBuf(sb_stdout);
02625         if ((*t != '\0') && (*t != '\n')) {
02626             rc = (_unpackaged_files_terminate_build) ? 1 : 0;
02627             rpmMessage((rc ? RPMMESS_ERROR : RPMMESS_WARNING),
02628                 _("Installed (but unpackaged) file(s) found:\n%s"), t);
02629         }
02630     }
02631     
02632 exit:
02633     sb_stdout = freeStringBuf(sb_stdout);
02634     s = _free(s);
02635     return rc;
02636 }
02637 
02638 /*@-incondefs@*/
02639 int processBinaryFiles(Spec spec, int installSpecialDoc, int test)
02640         /*@globals check_fileList @*/
02641         /*@modifies check_fileList @*/
02642 {
02643     Package pkg;
02644     int res = 0;
02645     
02646     check_fileList = newStringBuf();
02647     
02648     for (pkg = spec->packages; pkg != NULL; pkg = pkg->next) {
02649         const char *n, *v, *r;
02650         int rc;
02651 
02652         if (pkg->fileList == NULL)
02653             continue;
02654 
02655         (void) headerMacrosLoad(pkg->header);
02656 
02657         (void) headerNVR(pkg->header, &n, &v, &r);
02658         rpmMessage(RPMMESS_NORMAL, _("Processing files: %s-%s-%s\n"), n, v, r);
02659                    
02660         if ((rc = processPackageFiles(spec, pkg, installSpecialDoc, test)))
02661             res = rc;
02662 
02663         /* Finalize package scriptlets before extracting dependencies. */
02664         if ((rc = processScriptFiles(spec, pkg)))
02665             res = rc;
02666 
02667         if ((rc = rpmfcGenerateDepends(spec, pkg)))
02668             res = rc;
02669 
02670         /* XXX this should be earlier for deps to be entirely sorted. */
02671         providePackageNVR(pkg->header);
02672 
02673         (void) headerMacrosUnload(pkg->header);
02674     }
02675 
02676     /* Now we have in fileList list of files from all packages.
02677      * We pass it to a script which does the work of finding missing
02678      * and duplicated files.
02679      */
02680     
02681     if (res == 0)  {
02682         if (checkFiles(check_fileList) > 0)
02683             res = 1;
02684     }
02685     
02686     check_fileList = freeStringBuf(check_fileList);
02687     
02688     return res;
02689 }
02690 /*@=incondefs@*/

Generated on Mon Aug 3 15:24:57 2009 for rpm by  doxygen 1.4.4