8 #include <rpm/rpmtypes.h>
9 #include <rpm/rpmlib.h> /* rpmReadPackageFile */
10 #include <rpm/rpmts.h>
11 #include <rpm/rpmmacro.h> /* XXX rpmExpand */
12 #include <rpm/rpmfileutil.h>
13 #include <rpm/rpmlog.h>
15 #include "lib/rpmgi.h"
16 #include "lib/manifest.h"
20 #define MANIFEST_RECURSIONS 1000 /* Max. number of allowed manifest recursions */
23 rpmgiFlags giFlags = RPMGI_NONE;
28 rpmts ts; /*!< Iterator transaction set. */
30 rpmgiFlags flags; /*!< Iterator control bits. */
31 int i; /*!< Element index. */
37 int curLvl; /*!< Current recursion level */
38 int recLvls[MANIFEST_RECURSIONS]; /*!< Reversed end index for given level */
43 * Open a file after macro expanding path.
44 * @todo There are two error messages printed on header, then manifest failures.
45 * @param path file path
46 * @param fmode open mode
49 static FD_t rpmgiOpen(const char * path, const char * fmode)
51 char * fn = rpmExpand(path, NULL);
52 FD_t fd = Fopen(fn, fmode);
54 if (fd == NULL || Ferror(fd)) {
55 rpmlog(RPMLOG_ERR, _("open of %s failed: %s\n"), fn, Fstrerror(fd));
56 if (fd != NULL) (void) Fclose(fd);
65 * Load manifest into iterator arg list.
66 * @param gi generalized iterator
67 * @param path file path
68 * @return RPMRC_OK on success
70 static rpmRC rpmgiLoadManifest(rpmgi gi, const char * path)
72 FD_t fd = rpmgiOpen(path, "r.ufdio");
73 rpmRC rpmrc = RPMRC_FAIL;
76 rpmrc = rpmReadPackageManifest(fd, &gi->argc, &gi->argv);
83 * Return header from package.
84 * @param gi generalized iterator
85 * @param path file path
86 * @retval hdrp header (NULL on failure)
87 * @return 1 if path could be opened, 0 if not
89 static int rpmgiReadHeader(rpmgi gi, const char * path, Header * hdrp)
91 FD_t fd = rpmgiOpen(path, "r.ufdio");
95 /* XXX what if path needs expansion? */
96 rpmRC rpmrc = rpmReadPackageFile(gi->ts, fd, path, &h);
102 /* XXX Read a package manifest. Restart ftswalk on success. */
107 case RPMRC_NOTTRUSTED:
119 * Read next header from package, lazily expanding manifests as found.
120 * @todo An empty file read as manifest truncates argv returning RPMRC_NOTFOUND.
121 * @todo Chained manifests lose an arg someplace.
122 * @param gi generalized iterator
123 * @return header on success
125 static Header rpmgiLoadReadHeader(rpmgi gi)
129 if (gi->argv != NULL && gi->argv[gi->i] != NULL)
131 char * fn = gi->argv[gi->i];
134 while (gi->recLvls[gi->curLvl] > gi->argc - gi->i)
137 rc = rpmgiReadHeader(gi, fn, &h);
139 if (h != NULL || (gi->flags & RPMGI_NOMANIFEST) || rc == 0)
142 if (gi->curLvl == MANIFEST_RECURSIONS - 1) {
144 _("Max level of manifest recursion exceeded: %s\n"), fn);
148 gi->recLvls[gi->curLvl] = gi->argc - gi->i;
150 /* Not a header, so try for a manifest. */
151 gi->argv[gi->i] = NULL; /* Mark the insertion point */
152 if (rpmgiLoadManifest(gi, fn) != RPMRC_OK) {
153 gi->argv[gi->i] = fn; /* Manifest failed, restore fn */
155 _("%s: not an rpm package (or package manifest)\n"), fn);
166 * Append globbed arg list to iterator.
167 * @param gi generalized iterator
168 * @param argv arg list to be globbed (or NULL)
170 static void rpmgiGlobArgv(rpmgi gi, ARGV_const_t argv)
172 if (argv == NULL) return;
174 /* XXX Expand globs only if requested */
175 if ((gi->flags & RPMGI_NOGLOB)) {
176 argvAppend(&gi->argv, argv);
179 while ((arg = *argv++) != NULL) {
180 char * t = rpmEscapeSpaces(arg);
183 if (rpmGlob(t, NULL, &av) == 0) {
184 argvAppend(&gi->argv, av);
190 gi->argc = argvCount(gi->argv);
195 rpmgi rpmgiFree(rpmgi gi)
201 memset(gi, 0, sizeof(*gi)); /* XXX trash and burn */
207 rpmgi rpmgiNew(rpmts ts, rpmgiFlags flags, ARGV_const_t argv)
209 rpmgi gi = xcalloc(1, sizeof(*gi));
211 gi->ts = rpmtsLink(ts);
217 gi->argv = argvNew();
219 rpmgiGlobArgv(gi, argv);
222 gi->recLvls[gi->curLvl] = 1;
227 Header rpmgiNext(rpmgi gi)
231 if (gi != NULL && ++gi->i >= 0) {
233 * Read next header, lazily expanding manifests as found,
234 * count + skip errors.
236 while (gi->i < gi->argc) {
237 if ((h = rpmgiLoadReadHeader(gi)) != NULL)
243 /* Out of things to try, end of iteration */
251 int rpmgiNumErrors(rpmgi gi)
253 return (gi != NULL ? gi->errors : -1);