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

build/files.c

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

Generated on Sun Aug 18 18:33:11 2013 for rpm by  doxygen 1.4.4