rpmgiFree() cleanup to remove an exit point and dead assignment(s)
[platform/upstream/rpm.git] / lib / rpmgi.c
1 /** \ingroup rpmio
2  * \file lib/rpmgi.c
3  */
4 #include "system.h"
5
6 #include <errno.h>
7
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>
14
15 #include "lib/rpmgi.h"
16 #include "lib/manifest.h"
17
18 #include "debug.h"
19
20 RPM_GNUC_INTERNAL
21 rpmgiFlags giFlags = RPMGI_NONE;
22
23 /** \ingroup rpmgi
24  */
25 struct rpmgi_s {
26     rpmts ts;                   /*!< Iterator transaction set. */
27
28     rpmgiFlags flags;           /*!< Iterator control bits. */
29     int i;                      /*!< Element index. */
30     int errors;
31
32     ARGV_t argv;
33     int argc;
34 };
35
36 /**
37  * Open a file after macro expanding path.
38  * @todo There are two error messages printed on header, then manifest failures.
39  * @param path          file path
40  * @param fmode         open mode
41  * @return              file handle
42  */
43 static FD_t rpmgiOpen(const char * path, const char * fmode)
44 {
45     char * fn = rpmExpand(path, NULL);
46     FD_t fd = Fopen(fn, fmode);
47
48     if (fd == NULL || Ferror(fd)) {
49         rpmlog(RPMLOG_ERR, _("open of %s failed: %s\n"), fn, Fstrerror(fd));
50         if (fd != NULL) (void) Fclose(fd);
51         fd = NULL;
52     }
53     free(fn);
54
55     return fd;
56 }
57
58 /**
59  * Load manifest into iterator arg list.
60  * @param gi            generalized iterator
61  * @param path          file path
62  * @return              RPMRC_OK on success
63  */
64 static rpmRC rpmgiLoadManifest(rpmgi gi, const char * path)
65 {
66     FD_t fd = rpmgiOpen(path, "r.ufdio");
67     rpmRC rpmrc = RPMRC_FAIL;
68
69     if (fd != NULL) {
70         rpmrc = rpmReadPackageManifest(fd, &gi->argc, &gi->argv);
71         (void) Fclose(fd);
72     }
73     return rpmrc;
74 }
75
76 /**
77  * Return header from package.
78  * @param gi            generalized iterator
79  * @param path          file path
80  * @retval hdrp         header (NULL on failure)
81  * @return              1 if path could be opened, 0 if not
82  */
83 static int rpmgiReadHeader(rpmgi gi, const char * path, Header * hdrp)
84 {
85     FD_t fd = rpmgiOpen(path, "r.ufdio");
86     Header h = NULL;
87
88     if (fd != NULL) {
89         /* XXX what if path needs expansion? */
90         rpmRC rpmrc = rpmReadPackageFile(gi->ts, fd, path, &h);
91
92         (void) Fclose(fd);
93
94         switch (rpmrc) {
95         case RPMRC_NOTFOUND:
96             /* XXX Read a package manifest. Restart ftswalk on success. */
97         case RPMRC_FAIL:
98         default:
99             h = headerFree(h);
100             break;
101         case RPMRC_NOTTRUSTED:
102         case RPMRC_NOKEY:
103         case RPMRC_OK:
104             break;
105         }
106     }
107
108     *hdrp = h;
109     return (fd != NULL);
110 }
111
112 /**
113  * Read next header from package, lazily expanding manifests as found.
114  * @todo An empty file read as manifest truncates argv returning RPMRC_NOTFOUND.
115  * @todo Chained manifests lose an arg someplace.
116  * @param gi            generalized iterator
117  * @return              header on success
118  */
119 static Header rpmgiLoadReadHeader(rpmgi gi)
120 {
121     Header h = NULL;
122
123     if (gi->argv != NULL && gi->argv[gi->i] != NULL)
124     do {
125         char * fn = gi->argv[gi->i];
126         int rc = rpmgiReadHeader(gi, fn, &h);
127
128         if (h != NULL || (gi->flags & RPMGI_NOMANIFEST) || rc == 0)
129             break;
130
131         /* Not a header, so try for a manifest. */
132         gi->argv[gi->i] = NULL;         /* Mark the insertion point */
133         if (rpmgiLoadManifest(gi, fn) != RPMRC_OK) {
134             gi->argv[gi->i] = fn;       /* Manifest failed, restore fn */
135             rpmlog(RPMLOG_ERR, 
136                    _("%s: not an rpm package (or package manifest)\n"), fn);
137             break;
138         }
139         fn = _free(fn);
140     } while (1);
141
142     return h;
143 }
144
145
146 /**
147  * Append globbed arg list to iterator.
148  * @param gi            generalized iterator
149  * @param argv          arg list to be globbed (or NULL)
150  */
151 static void rpmgiGlobArgv(rpmgi gi, ARGV_const_t argv)
152 {
153     if (argv == NULL) return;
154
155     /* XXX Expand globs only if requested */
156     if ((gi->flags & RPMGI_NOGLOB)) {
157         argvAppend(&gi->argv, argv);
158     } else {
159         const char * arg;
160         while ((arg = *argv++) != NULL) {
161             char * t = rpmEscapeSpaces(arg);
162             char ** av = NULL;
163
164             if (rpmGlob(t, NULL, &av) == 0) {
165                 argvAppend(&gi->argv, av);
166                 argvFree(av);
167             }
168             free(t);
169         }
170     }
171     gi->argc = argvCount(gi->argv);
172
173     return;
174 }
175
176 rpmgi rpmgiFree(rpmgi gi)
177 {
178     if (gi != NULL) {
179         rpmtsFree(gi->ts);
180         argvFree(gi->argv);
181
182         memset(gi, 0, sizeof(*gi)); /* XXX trash and burn */
183         free(gi);
184     }
185     return NULL;
186 }
187
188 rpmgi rpmgiNew(rpmts ts, rpmgiFlags flags, ARGV_const_t argv)
189 {
190     rpmgi gi = xcalloc(1, sizeof(*gi));
191
192     gi->ts = rpmtsLink(ts);
193
194     gi->flags = flags;
195     gi->i = -1;
196     gi->errors = 0;
197
198     gi->flags = flags;
199     gi->argv = argvNew();
200     gi->argc = 0;
201     rpmgiGlobArgv(gi, argv);
202
203     return gi;
204 }
205
206 Header rpmgiNext(rpmgi gi)
207 {
208     Header h = NULL;
209
210     if (gi != NULL && ++gi->i >= 0) {
211         /* 
212          * Read next header, lazily expanding manifests as found,
213          * count + skip errors.
214          */
215         while (gi->i < gi->argc) {
216             if ((h = rpmgiLoadReadHeader(gi)) != NULL) 
217                 break;
218             gi->errors++;
219             gi->i++;
220         }
221
222         /* Out of things to try, end of iteration */
223         if (h == NULL)
224             gi->i = -1;
225     }
226
227     return h;
228 }
229
230 int rpmgiNumErrors(rpmgi gi)
231 {
232     return (gi != NULL ? gi->errors : -1);
233 }