rpm  5.4.10
rpmrepo.c
Go to the documentation of this file.
1 
5 #include "system.h"
6 
7 #if defined(WITH_DBSQL)
8 #include <dbsql.h>
9 #elif defined(WITH_SQLITE)
10 #include <sqlite3.h>
11 #ifdef __LCLINT__
12 /*@-incondefs -redecl @*/
13 extern const char *sqlite3_errmsg(sqlite3 *db)
14  /*@*/;
15 extern int sqlite3_open(
16  const char *filename, /* Database filename (UTF-8) */
17  /*@out@*/ sqlite3 **ppDb /* OUT: SQLite db handle */
18 )
19  /*@modifies *ppDb @*/;
20 extern int sqlite3_exec(
21  sqlite3 *db, /* An open database */
22  const char *sql, /* SQL to be evaluted */
23  int (*callback)(void*,int,char**,char**), /* Callback function */
24  void *, /* 1st argument to callback */
25  /*@out@*/ char **errmsg /* Error msg written here */
26 )
27  /*@modifies db, *errmsg @*/;
28 extern int sqlite3_prepare(
29  sqlite3 *db, /* Database handle */
30  const char *zSql, /* SQL statement, UTF-8 encoded */
31  int nByte, /* Maximum length of zSql in bytes. */
32  /*@out@*/ sqlite3_stmt **ppStmt, /* OUT: Statement handle */
33  /*@out@*/ const char **pzTail /* OUT: Pointer to unused portion of zSql */
34 )
35  /*@modifies *ppStmt, *pzTail @*/;
36 extern int sqlite3_reset(sqlite3_stmt *pStmt)
37  /*@modifies pStmt @*/;
38 extern int sqlite3_step(sqlite3_stmt *pStmt)
39  /*@modifies pStmt @*/;
40 extern int sqlite3_finalize(/*@only@*/ sqlite3_stmt *pStmt)
41  /*@modifies pStmt @*/;
42 extern int sqlite3_close(sqlite3 * db)
43  /*@modifies db @*/;
44 /*@=incondefs =redecl @*/
45 #endif /* __LCLINT__ */
46 #endif /* WITH_SQLITE */
47 
48 #include <rpmio_internal.h> /* XXX fdInitDigest() et al */
49 #include <rpmiotypes.h>
50 #include <rpmio.h> /* for *Pool methods */
51 #include <rpmlog.h>
52 #include <rpmurl.h>
53 #include <poptIO.h>
54 
55 #define _RPMREPO_INTERNAL
56 #include <rpmrepo.h>
57 
58 #include <rpmtypes.h>
59 #include <rpmtag.h>
60 #include <pkgio.h>
61 #include <rpmts.h>
62 
63 #include "debug.h"
64 
65 /*@unchecked@*/
67 
68 #define REPODBG(_l) if (_rpmrepo_debug) fprintf _l
69 
70 /*==============================================================*/
71 
72 /*@unchecked@*/ /*@observer@*/
73 static const char primary_xml_init[] =
74 "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n"
75 "<metadata xmlns=\"http://linux.duke.edu/metadata/common\" xmlns:rpm=\"http://linux.duke.edu/metadata/rpm\" packages=\"0\">\n";
76 /*@unchecked@*/ /*@observer@*/
77 static const char primary_xml_fini[] = "</metadata>\n";
78 
79 /*@unchecked@*/ /*@observer@*/
80 static const char filelists_xml_init[] =
81 "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n"
82 "<filelists xmlns=\"http://linux.duke.edu/metadata/filelists\" packages=\"0\">\n";
83 /*@unchecked@*/ /*@observer@*/
84 static const char filelists_xml_fini[] = "</filelists>\n";
85 
86 /*@unchecked@*/ /*@observer@*/
87 static const char other_xml_init[] =
88 "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n"
89 "<otherdata xmlns=\"http://linux.duke.edu/metadata/other\" packages=\"0\">\n";
90 /*@unchecked@*/ /*@observer@*/
91 static const char other_xml_fini[] = "</otherdata>\n";
92 
93 /*@unchecked@*/ /*@observer@*/
94 static const char repomd_xml_init[] = "\
95 <?xml version=\"1.0\" encoding=\"UTF-8\"?>\n\
96 <repomd xmlns=\"http://linux.duke.edu/metadata/repo\">\n";
97 /*@unchecked@*/ /*@observer@*/
98 static const char repomd_xml_fini[] = "</repomd>\n";
99 
100 /* XXX todo: wire up popt aliases and bury the --queryformat glop externally. */
101 /*@unchecked@*/ /*@observer@*/
102 static const char primary_xml_qfmt[] =
103 #include "yum_primary_xml"
104 ;
105 
106 /*@unchecked@*/ /*@observer@*/
107 static const char filelists_xml_qfmt[] =
108 #include "yum_filelists_xml"
109 ;
110 
111 /*@unchecked@*/ /*@observer@*/
112 static const char other_xml_qfmt[] =
113 #include "yum_other_xml"
114 ;
115 
116 /*@unchecked@*/ /*@observer@*/
117 static const char primary_yaml_qfmt[] =
118 #include "wnh_primary_yaml"
119 ;
120 
121 /*@unchecked@*/ /*@observer@*/
122 static const char filelists_yaml_qfmt[] =
123 #include "wnh_filelists_yaml"
124 ;
125 
126 /*@unchecked@*/ /*@observer@*/
127 static const char other_yaml_qfmt[] =
128 #include "wnh_other_yaml"
129 ;
130 
131 /*@unchecked@*/ /*@observer@*/
132 static const char Packages_qfmt[] =
133 #include "deb_Packages"
134 ;
135 
136 /*@unchecked@*/ /*@observer@*/
137 static const char Sources_qfmt[] =
138 #include "deb_Sources"
139 ;
140 
141 /*@-nullassign@*/
142 /*@unchecked@*/ /*@observer@*/
143 static const char *primary_sql_init[] = {
144 "PRAGMA synchronous = \"OFF\";",
145 "pragma locking_mode = \"EXCLUSIVE\";",
146 "CREATE TABLE conflicts ( pkgKey INTEGER, name TEXT, flags TEXT, epoch TEXT, version TEXT, release TEXT );",
147 "CREATE TABLE db_info (dbversion INTEGER, checksum TEXT);",
148 "CREATE TABLE files ( pkgKey INTEGER, name TEXT, type TEXT );",
149 "CREATE TABLE obsoletes ( pkgKey INTEGER, name TEXT, flags TEXT, epoch TEXT, version TEXT, release TEXT );",
150 "CREATE TABLE packages ( pkgKey INTEGER PRIMARY KEY, pkgId TEXT, name TEXT, arch TEXT, version TEXT, epoch TEXT, release TEXT, summary TEXT, description TEXT, url TEXT, time_file INTEGER, time_build INTEGER, rpm_license TEXT, rpm_vendor TEXT, rpm_group TEXT, rpm_buildhost TEXT, rpm_sourcerpm TEXT, rpm_header_start INTEGER, rpm_header_end INTEGER, rpm_packager TEXT, size_package INTEGER, size_installed INTEGER, size_archive INTEGER, location_href TEXT, location_base TEXT, checksum_type TEXT);",
151 "CREATE TABLE provides ( pkgKey INTEGER, name TEXT, flags TEXT, epoch TEXT, version TEXT, release TEXT );",
152 "CREATE TABLE requires ( pkgKey INTEGER, name TEXT, flags TEXT, epoch TEXT, version TEXT, release TEXT );",
153 "CREATE INDEX filenames ON files (name);",
154 "CREATE INDEX packageId ON packages (pkgId);",
155 "CREATE INDEX packagename ON packages (name);",
156 "CREATE INDEX pkgconflicts on conflicts (pkgKey);",
157 "CREATE INDEX pkgobsoletes on obsoletes (pkgKey);",
158 "CREATE INDEX pkgprovides on provides (pkgKey);",
159 "CREATE INDEX pkgrequires on requires (pkgKey);",
160 "CREATE INDEX providesname ON provides (name);",
161 "CREATE INDEX requiresname ON requires (name);",
162 "CREATE TRIGGER removals AFTER DELETE ON packages\
163 \n BEGIN\n\
164 \n DELETE FROM files WHERE pkgKey = old.pkgKey;\
165 \n DELETE FROM requires WHERE pkgKey = old.pkgKey;\
166 \n DELETE FROM provides WHERE pkgKey = old.pkgKey;\
167 \n DELETE FROM conflicts WHERE pkgKey = old.pkgKey;\
168 \n DELETE FROM obsoletes WHERE pkgKey = old.pkgKey;\
169 \n END;",
170 "INSERT into db_info values (9, 'direct_create');",
171  NULL
172 };
173 /*XXX todo: DBVERSION needs to be set */
174 
175 /*@unchecked@*/ /*@observer@*/
176 static const char *filelists_sql_init[] = {
177 "PRAGMA synchronous = \"OFF\";",
178 "pragma locking_mode = \"EXCLUSIVE\";",
179 "CREATE TABLE db_info (dbversion INTEGER, checksum TEXT);",
180 "CREATE TABLE filelist ( pkgKey INTEGER, name TEXT, type TEXT );",
181 "CREATE TABLE packages ( pkgKey INTEGER PRIMARY KEY, pkgId TEXT);",
182 "CREATE INDEX filelistnames ON filelist (name);",
183 "CREATE INDEX keyfile ON filelist (pkgKey);",
184 "CREATE INDEX pkgId ON packages (pkgId);",
185 "CREATE TRIGGER remove_filelist AFTER DELETE ON packages\
186 \n BEGIN\
187 \n DELETE FROM filelist WHERE pkgKey = old.pkgKey;\
188 \n END;",
189 "INSERT into db_info values (9, 'direct_create');",
190  NULL
191 };
192 /*XXX todo: DBVERSION needs to be set */
193 
194 /*@unchecked@*/ /*@observer@*/
195 static const char *other_sql_init[] = {
196 "PRAGMA synchronous = \"OFF\";",
197 "pragma locking_mode = \"EXCLUSIVE\";",
198 "CREATE TABLE changelog ( pkgKey INTEGER, author TEXT, date INTEGER, changelog TEXT);",
199 "CREATE TABLE db_info (dbversion INTEGER, checksum TEXT);",
200 "CREATE TABLE packages ( pkgKey INTEGER PRIMARY KEY, pkgId TEXT);",
201 "CREATE INDEX keychange ON changelog (pkgKey);",
202 "CREATE INDEX pkgId ON packages (pkgId);",
203 "CREATE TRIGGER remove_changelogs AFTER DELETE ON packages\
204 \n BEGIN\
205 \n DELETE FROM changelog WHERE pkgKey = old.pkgKey;\
206 \n END;",
207 "INSERT into db_info values (9, 'direct_create');",
208  NULL
209 };
210 /*XXX todo: DBVERSION needs to be set */
211 /*@=nullassign@*/
212 
213 /* packages 1 pkgKey INTEGER PRIMARY KEY */
214 /* packages 2 pkgId TEXT */
215 /* packages 3 name TEXT */
216 /* packages 4 arch TEXT */
217 /* packages 5 version TEXT */
218 /* packages 6 epoch TEXT */
219 /* packages 7 release TEXT */
220 /* packages 8 summary TEXT */
221 /* packages 9 description TEXT */
222 /* packages 10 url TEXT */
223 /* packages 11 time_file INTEGER */
224 /* packages 12 time_build INTEGER */
225 /* packages 13 rpm_license TEXT */
226 /* packages 14 rpm_vendor TEXT */
227 /* packages 15 rpm_group TEXT */
228 /* packages 16 rpm_buildhost TEXT */
229 /* packages 17 rpm_sourcerpm TEXT */
230 /* packages 18 rpm_header_start INTEGER */
231 /* packages 19 rpm_header_end INTEGER */
232 /* packages 20 rpm_packager TEXT */
233 /* packages 21 size_package INTEGER */
234 /* packages 22 size_installed INTEGER */
235 /* packages 23 size_archive INTEGER */
236 /* packages 24 location_href TEXT */
237 /* packages 25 location_base TEXT */
238 /* packages 26 checksum_type TEXT */
239 /* obsoletes 1 pkgKey INTEGER */
240 /* obsoletes 2 name TEXT */
241 /* obsoletes 3 flags TEXT */
242 /* obsoletes 4 epoch TEXT */
243 /* obsoletes 5 version TEXT */
244 /* obsoletes 6 release TEXT */
245 /* provides 1 pkgKey INTEGER */
246 /* provides 2 name TEXT */
247 /* provides 3 flags TEXT */
248 /* provides 4 epoch TEXT */
249 /* provides 5 version TEXT */
250 /* provides 6 release TEXT */
251 /* conflicts 1 pkgKey INTEGER */
252 /* conflicts 2 name TEXT */
253 /* conflicts 3 flags TEXT */
254 /* conflicts 4 epoch TEXT */
255 /* conflicts 5 version TEXT */
256 /* conflicts 6 release TEXT */
257 /* requires 1 pkgKey INTEGER */
258 /* requires 2 name TEXT */
259 /* requires 3 flags TEXT */
260 /* requires 4 epoch TEXT */
261 /* requires 5 version TEXT */
262 /* requires 6 release TEXT */
263 /* files 1 pkgKey INTEGER */
264 /* files 2 name TEXT */
265 /* files 3 type TEXT */
266 
267 /*@unchecked@*/ /*@observer@*/
268 static const char primary_sql_qfmt[] =
269 #include "yum_primary_sqlite"
270 ;
271 
272 /* packages 1 pkgKey INTEGER PRIMARY KEY */
273 /* packages 2 pkgId TEXT */
274 /* filelist 1 pkgKey INTEGER */
275 /* filelist 2 name TEXT */
276 /* filelist 3 type TEXT */
277 
278 /*@unchecked@*/ /*@observer@*/
279 static const char filelists_sql_qfmt[] =
280 #include "yum_filelists_sqlite"
281 ;
282 
283 /* packages 1 pkgKey INTEGER PRIMARY KEY */
284 /* packages 2 pkgId TEXT */
285 /* changelog 1 pkgKey INTEGER */
286 /* changelog 2 author TEXT */
287 /* changelog 3 date INTEGER */
288 /* changelog 4 changelog TEXT */
289 
290 /*@unchecked@*/ /*@observer@*/
291 static const char other_sql_qfmt[] =
292 #include "yum_other_sqlite"
293 ;
294 
295 /* XXX static when ready. */
296 /*@-fullinitblock@*/
297 /*@unchecked@*/
298 static struct rpmrepo_s __repo = {
299  .flags = REPO_FLAGS_PRETTY,
300 
301  .tempdir = ".repodata",
302  .finaldir = "repodata",
303  .olddir = ".olddata",
304  .markup = ".xml",
305  .pkgalgo = PGPHASHALGO_SHA1,
306  .algo = PGPHASHALGO_SHA1,
307  .primary = {
308  .type = "primary",
309  .xml_init= primary_xml_init,
310  .xml_qfmt= primary_xml_qfmt,
311  .xml_fini= primary_xml_fini,
312  .sql_init= primary_sql_init,
313  .sql_qfmt= primary_sql_qfmt,
314 #ifdef NOTYET /* XXX char **?!? */
315  .sql_fini= NULL,
316 #endif
317  .yaml_init= NULL,
318  .yaml_qfmt= primary_yaml_qfmt,
319  .yaml_fini= NULL,
320  .Packages_init= NULL,
321  .Packages_qfmt= NULL,
322  .Packages_fini= NULL,
323  .Sources_init= NULL,
324  .Sources_qfmt= NULL,
325  .Sources_fini= NULL
326  },
327  .filelists = {
328  .type = "filelists",
329  .xml_init= filelists_xml_init,
330  .xml_qfmt= filelists_xml_qfmt,
331  .xml_fini= filelists_xml_fini,
332  .sql_init= filelists_sql_init,
333  .sql_qfmt= filelists_sql_qfmt,
334 #ifdef NOTYET /* XXX char **?!? */
335  .sql_fini= NULL,
336 #endif
337  .yaml_init= NULL,
338  .yaml_qfmt= filelists_yaml_qfmt,
339  .yaml_fini= NULL,
340  .Packages_init= NULL,
341  .Packages_qfmt= NULL,
342  .Packages_fini= NULL,
343  .Sources_init= NULL,
344  .Sources_qfmt= NULL,
345  .Sources_fini= NULL
346  },
347  .other = {
348  .type = "other",
349  .xml_init= other_xml_init,
350  .xml_qfmt= other_xml_qfmt,
351  .xml_fini= other_xml_fini,
352  .sql_init= other_sql_init,
353  .sql_qfmt= other_sql_qfmt,
354 #ifdef NOTYET /* XXX char **?!? */
355  .sql_fini= NULL,
356 #endif
357  .yaml_init= NULL,
358  .yaml_qfmt= other_yaml_qfmt,
359  .yaml_fini= NULL,
360  .Packages_init= NULL,
361  .Packages_qfmt= NULL,
362  .Packages_fini= NULL,
363  .Sources_init= NULL,
364  .Sources_qfmt= NULL,
365  .Sources_fini= NULL
366  },
367  .repomd = {
368  .type = "repomd",
369  .xml_init= repomd_xml_init,
370  .xml_qfmt= NULL,
371  .xml_fini= repomd_xml_fini,
372  .sql_init= NULL,
373  .sql_qfmt= NULL,
374 #ifdef NOTYET /* XXX char **?!? */
375  .sql_fini= NULL,
376 #endif
377  .yaml_init= NULL,
378  .yaml_qfmt= NULL,
379  .yaml_fini= NULL,
380  .Packages_init= NULL,
381  .Packages_qfmt= Packages_qfmt,
382  .Packages_fini= NULL,
383  .Sources_init= NULL,
384  .Sources_qfmt= Sources_qfmt,
385  .Sources_fini= NULL
386  }
387 };
388 /*@=fullinitblock@*/
389 
390 /*@unchecked@*/
391 static rpmrepo _repo = &__repo;
392 
393 /*==============================================================*/
394 
400 static int rpmioExists(const char * fn, /*@out@*/ struct stat * st)
401  /*@globals h_errno, fileSystem, internalState @*/
402  /*@modifies st, fileSystem, internalState @*/
403 {
404  return (Stat(fn, st) == 0);
405 }
406 
412 static time_t rpmioCtime(const char * fn)
413  /*@globals h_errno, fileSystem, internalState @*/
414  /*@modifies fileSystem, internalState @*/
415 {
416  struct stat sb;
417  time_t stctime = 0;
418 
419  if (rpmioExists(fn, &sb))
420  stctime = sb.st_ctime;
421  return stctime;
422 }
423 
424 /*==============================================================*/
425 
426 void
427 rpmrepoError(int lvl, const char *fmt, ...)
428 {
429  va_list ap;
430 
431  va_start(ap, fmt);
432  (void) fflush(NULL);
433  (void) fprintf(stderr, "%s: ", __progname);
434  (void) vfprintf(stderr, fmt, ap);
435  va_end (ap);
436  (void) fprintf(stderr, "\n");
437  if (lvl)
438  exit(EXIT_FAILURE);
439 }
440 
448 static const char * rpmrepoGetPath(rpmrepo repo, const char * dir,
449  const char * type, int compress)
450  /*@globals h_errno, rpmGlobalMacroContext, internalState @*/
451  /*@modifies rpmGlobalMacroContext, internalState @*/
452 {
453  return rpmGetPath(repo->outputdir, "/", dir, "/", type,
454  (repo->markup != NULL ? repo->markup : ""),
455  (repo->suffix != NULL && compress ? repo->suffix : ""), NULL);
456 }
457 
465 static void rpmrepoProgress(/*@unused@*/ rpmrepo repo,
466  /*@null@*/ const char * item, int current, int total)
467  /*@globals fileSystem, internalState @*/
468  /*@modifies fileSystem, internalState @*/
469 {
470  static size_t ncols = 80 - 1; /* XXX TIOCGWINSIZ */
471  const char * bn = (item != NULL ? strrchr(item, '/') : NULL);
472  size_t nb;
473 
474  if (bn != NULL)
475  bn++;
476  else
477  bn = item;
478  nb = fprintf(stdout, "\r%s: %d/%d", __progname, current, total);
479  if (bn != NULL)
480  nb += fprintf(stdout, " - %s", bn);
481  nb--;
482  if (nb < ncols)
483  fprintf(stdout, "%*s", (int)(ncols - nb), "");
484  ncols = nb;
485  (void) fflush(stdout);
486 }
487 
494 static int rpmrepoMkdir(rpmrepo repo, const char * dn)
495  /*@globals rpmGlobalMacroContext, h_errno, fileSystem, internalState @*/
496  /*@modifies rpmGlobalMacroContext, fileSystem, internalState @*/
497 {
498  const char * dnurl = rpmGetPath(repo->outputdir, "/", dn, NULL);
499 /*@-mods@*/
500  int ut = urlPath(dnurl, &dn);
501 /*@=mods@*/
502  int rc = 0;;
503 
504  /* XXX todo: rpmioMkpath doesn't grok URI's */
505  if (ut == URL_IS_UNKNOWN)
506  rc = rpmioMkpath(dn, 0755, (uid_t)-1, (gid_t)-1);
507  else
508  rc = (Mkdir(dnurl, 0755) == 0 || errno == EEXIST ? 0 : -1);
509  if (rc)
510  rpmrepoError(0, _("Cannot create/verify %s: %s"), dnurl, strerror(errno));
511  dnurl = _free(dnurl);
512  return rc;
513 }
514 
515 const char * rpmrepoRealpath(const char * lpath)
516 {
517  /* XXX GLIBC: realpath(path, NULL) return malloc'd */
518  const char *rpath = Realpath(lpath, NULL);
519  if (rpath == NULL) {
520  char fullpath[MAXPATHLEN];
521  rpath = Realpath(lpath, fullpath);
522  if (rpath != NULL)
523  rpath = xstrdup(rpath);
524  }
525  return rpath;
526 }
527 
528 /*==============================================================*/
529 
531 {
532  const char ** directories = repo->directories;
533  struct stat sb, *st = &sb;
534  const char * dn;
535  const char * fn;
536  int rc = 0;
537 
538  /* XXX todo: check repo->pkglist existence? */
539 
540  if (directories != NULL)
541  while ((dn = *directories++) != NULL) {
542  if (!rpmioExists(dn, st) || !S_ISDIR(st->st_mode)) {
543  rpmrepoError(0, _("Directory %s must exist"), dn);
544  rc = 1;
545  }
546  }
547 
548  /* XXX todo create outputdir if it doesn't exist? */
549  if (!rpmioExists(repo->outputdir, st)) {
550  rpmrepoError(0, _("Directory %s does not exist."), repo->outputdir);
551  rc = 1;
552  }
553  if (Access(repo->outputdir, W_OK)) {
554  rpmrepoError(0, _("Directory %s must be writable."), repo->outputdir);
555  rc = 1;
556  }
557 
558  if (rpmrepoMkdir(repo, repo->tempdir)
559  || rpmrepoMkdir(repo, repo->finaldir))
560  rc = 1;
561 
562  dn = rpmGetPath(repo->outputdir, "/", repo->olddir, NULL);
563  if (rpmioExists(dn, st)) {
564  rpmrepoError(0, _("Old data directory exists, please remove: %s"), dn);
565  rc = 1;
566  }
567  dn = _free(dn);
568 
569  { /*@observer@*/
570  static const char * dirs[] = { ".repodata", "repodata", NULL };
571  /*@observer@*/
572  static const char * types[] =
573  { "primary", "filelists", "other", "repomd", NULL };
574  const char ** dirp, ** typep;
575  for (dirp = dirs; *dirp != NULL; dirp++) {
576  for (typep = types; *typep != NULL; typep++) {
577  fn = rpmrepoGetPath(repo, *dirp, *typep, strcmp(*typep, "repomd"));
578  if (rpmioExists(fn, st)) {
579  if (Access(fn, W_OK)) {
580  rpmrepoError(0, _("Path must be writable: %s"), fn);
581  rc = 1;
582  } else
583  if (REPO_ISSET(CHECKTS) && st->st_ctime > repo->mdtimestamp)
584  repo->mdtimestamp = st->st_ctime;
585  }
586  fn = _free(fn);
587  }
588  }
589  }
590 
591 #ifdef NOTYET /* XXX repo->package_dir needs to go away. */
592  if (repo->groupfile != NULL) {
593  if (REPO_ISSET(SPLIT) || repo->groupfile[0] != '/') {
594  fn = rpmGetPath(repo->package_dir, "/", repo->groupfile, NULL);
595  repo->groupfile = _free(repo->groupfile);
596  repo->groupfile = fn;
597  fn = NULL;
598  }
599  if (!rpmioExists(repo->groupfile, st)) {
600  rpmrepoError(0, _("groupfile %s cannot be found."), repo->groupfile);
601  rc = 1;
602  }
603  }
604 #endif
605  return rc;
606 }
607 
614 static int chkSuffix(const char * fn, const char * suffix)
615  /*@*/
616 {
617  size_t flen = strlen(fn);
618  size_t slen = strlen(suffix);
619  return (flen > slen && !strcmp(fn + flen - slen, suffix));
620 }
621 
622 const char ** rpmrepoGetFileList(rpmrepo repo, const char *roots[],
623  const char * ext)
624 {
625  const char ** pkglist = NULL;
626  FTS * t;
627  FTSENT * p;
628  int xx;
629 
630  if ((t = Fts_open((char *const *)roots, repo->ftsoptions, NULL)) == NULL)
631  rpmrepoError(1, _("Fts_open: %s"), strerror(errno));
632 
633  while ((p = Fts_read(t)) != NULL) {
634 #ifdef NOTYET
635  const char * fts_name = p->fts_name;
636  size_t fts_namelen = p->fts_namelen;
637 
638  /* XXX fts(3) (and Fts(3)) have fts_name = "" with pesky trailing '/' */
639  if (p->fts_level == 0 && fts_namelen == 0) {
640  fts_name = ".";
641  fts_namelen = sizeof(".") - 1;
642  }
643 #endif
644 
645  /* Should this element be excluded/included? */
646  /* XXX todo: apply globs to fts_path rather than fts_name? */
647 /*@-onlytrans@*/
648  if (mireApply(repo->excludeMire, repo->nexcludes, p->fts_name, 0, -1) >= 0)
649  continue;
650  if (mireApply(repo->includeMire, repo->nincludes, p->fts_name, 0, +1) < 0)
651  continue;
652 /*@=onlytrans@*/
653 
654  switch (p->fts_info) {
655  case FTS_D:
656  case FTS_DP:
657  default:
658  continue;
659  /*@notreached@*/ /*@switchbreak@*/ break;
660  case FTS_SL:
661  if (REPO_ISSET(NOFOLLOW))
662  continue;
663  /* XXX todo: fuss with symlinks */
664  /*@notreached@*/ /*@switchbreak@*/ break;
665  case FTS_F:
666  /* Is this a *.rpm file? */
667  if (chkSuffix(p->fts_name, ext))
668  xx = argvAdd(&pkglist, p->fts_path);
669  /*@switchbreak@*/ break;
670  }
671  }
672 
673  (void) Fts_close(t);
674 
675 if (_rpmrepo_debug)
676 argvPrint("pkglist", pkglist, NULL);
677 
678  return pkglist;
679 }
680 
682 {
683  int rc = 0;
684 
685  if (REPO_ISSET(CHECKTS)) {
686  const char ** pkg;
687 
688  if (repo->pkglist != NULL)
689  for (pkg = repo->pkglist; *pkg != NULL ; pkg++) {
690  struct stat sb, *st = &sb;
691  if (!rpmioExists(*pkg, st)) {
692  rpmrepoError(0, _("cannot get to file: %s"), *pkg);
693  rc = 1;
694  } else if (st->st_ctime > repo->mdtimestamp)
695  rc = 1;
696  }
697  } else
698  rc = 1;
699 
700  return rc;
701 }
702 
709 static int rpmrfileXMLWrite(rpmrfile rfile, const char * spew)
710  /*@globals fileSystem @*/
711  /*@modifies rfile, fileSystem @*/
712 {
713  size_t nspew = (spew != NULL ? strlen(spew) : 0);
714 /*@-nullpass@*/ /* XXX spew != NULL @*/
715  size_t nb = (nspew > 0 ? Fwrite(spew, 1, nspew, rfile->fd) : 0);
716 /*@=nullpass@*/
717  int rc = 0;
718  if (nspew != nb) {
719  rpmrepoError(0, _("Fwrite failed: expected write %u != %u bytes: %s\n"),
720  (unsigned)nspew, (unsigned)nb, Fstrerror(rfile->fd));
721  rc = 1;
722  }
723  spew = _free(spew);
724  return rc;
725 }
726 
733 static int rpmrepoFclose(rpmrepo repo, FD_t fd)
734  /*@modifies repo, fd @*/
735 {
736  int rc = 0;
737 
738  if (fd != NULL) {
739 #ifdef NOTYET
740  rpmts ts = repo->_ts;
741  if (ts != NULL) {
743  fdstat_op(fd, FDSTAT_READ));
744  (void) rpmswAdd(rpmtsOp(ts, RPMTS_OP_DIGEST),
745  fdstat_op(fd, FDSTAT_DIGEST));
746  }
747 #endif
748  rc = Fclose(fd);
749  }
750  return rc;
751 }
752 
759 static int rpmrepoOpenMDFile(const rpmrepo repo, rpmrfile rfile)
760  /*@globals h_errno, rpmGlobalMacroContext, fileSystem, internalState @*/
761  /*@modifies rfile, rpmGlobalMacroContext, fileSystem, internalState @*/
762 {
763  const char * spew = rfile->xml_init;
764  size_t nspew = strlen(spew);
765  const char * fn = rpmrepoGetPath(repo, repo->tempdir, rfile->type, 1);
766  const char * tail;
767  size_t nb;
768  int rc = 0;
769 
770  rfile->fd = Fopen(fn, repo->wmode);
771 assert(rfile->fd != NULL);
772 
773  if (repo->algo != PGPHASHALGO_NONE)
774  fdInitDigest(rfile->fd, repo->algo, 0);
775 
776  if ((tail = strstr(spew, " packages=\"0\">\n")) != NULL)
777  nspew -= strlen(tail);
778 
779  nb = Fwrite(spew, 1, nspew, rfile->fd);
780 
781  if (tail != NULL) {
782  char buf[64];
783  size_t tnb = snprintf(buf, sizeof(buf), " packages=\"%d\">\n",
784  repo->pkgcount);
785  nspew += tnb;
786  nb += Fwrite(buf, 1, tnb, rfile->fd);
787  }
788  if (nspew != nb) {
789  rpmrepoError(0, _("Fwrite failed: expected write %u != %u bytes: %s\n"),
790  (unsigned)nspew, (unsigned)nb, Fstrerror(rfile->fd));
791  rc = 1;
792  }
793 
794  fn = _free(fn);
795 
796 #if defined(WITH_SQLITE)
797  if (REPO_ISSET(DATABASE)) {
798  const char ** stmt;
799  int xx;
800  fn = rpmGetPath(repo->outputdir, "/", repo->tempdir, "/",
801  rfile->type, ".sqlite", NULL);
802  if ((xx = sqlite3_open(fn, &rfile->sqldb)) != SQLITE_OK)
803  rpmrepoError(1, "sqlite3_open(%s): %s", fn, sqlite3_errmsg(rfile->sqldb));
804  for (stmt = rfile->sql_init; *stmt != NULL; stmt++) {
805  char * msg;
806  xx = sqlite3_exec(rfile->sqldb, *stmt, NULL, NULL, &msg);
807  if (xx != SQLITE_OK)
808  rpmrepoError(1, "sqlite3_exec(%s, \"%s\"): %s\n", fn, *stmt,
809  (msg != NULL ? msg : "failed"));
810  }
811  fn = _free(fn);
812  }
813 #endif
814 
815  return rc;
816 }
817 
818 #if defined(WITH_SQLITE)
819 
824 static int rpmrfileSQL(rpmrfile rfile, const char * msg, int rc)
825  /*@globals fileSystem @*/
826  /*@modifies fileSystem @*/
827 {
828  if (rc != SQLITE_OK || _rpmrepo_debug)
829  rpmrepoError(0, "sqlite3_%s(%s): %s", msg, rfile->type,
830  sqlite3_errmsg(rfile->sqldb));
831  return rc;
832 }
833 
839 static int rpmrfileSQLStep(rpmrfile rfile, sqlite3_stmt * stmt)
840  /*@globals fileSystem @*/
841  /*@modifies fileSystem @*/
842 {
843  int loop = 1;
844  int rc = 0;
845  int xx;
846 
847 /*@-infloops@*/
848  while (loop) {
849  rc = sqlite3_step(stmt);
850  switch (rc) {
851  default:
852  rc = rpmrfileSQL(rfile, "step", rc);
853  /*@fallthrough@*/
854  case SQLITE_DONE:
855  loop = 0;
856  /*@switchbreak@*/ break;
857  }
858  }
859 /*@=infloops@*/
860 
861  xx = rpmrfileSQL(rfile, "reset",
862  sqlite3_reset(stmt));
863 
864  return rc;
865 }
866 
873 static int rpmrfileSQLWrite(rpmrfile rfile, const char * cmd)
874  /*@globals fileSystem @*/
875  /*@modifies fileSystem @*/
876 {
877  sqlite3_stmt * stmt;
878  const char * tail;
879  int xx;
880 
881  xx = rpmrfileSQL(rfile, "prepare",
882  sqlite3_prepare(rfile->sqldb, cmd, (int)strlen(cmd), &stmt, &tail));
883 
884  xx = rpmrfileSQL(rfile, "reset",
885  sqlite3_reset(stmt));
886 
887  xx = rpmrfileSQLStep(rfile, stmt);
888 
889  xx = rpmrfileSQL(rfile, "finalize",
890  sqlite3_finalize(stmt));
891 
892  cmd = _free(cmd);
893 
894  return 0;
895 }
896 #endif /* WITH_SQLITE */
897 
902 static int rpmrepoRfileDigest(const rpmrepo repo, rpmrfile rfile,
903  const char ** digestp)
904  /*@modifies *digestp @*/
905 {
906  static int asAscii = 1;
907  struct stat sb, *st = &sb;
908  const char * fn = rpmrepoGetPath(repo, repo->tempdir, rfile->type, 1);
909  const char * path = NULL;
910  int ut = urlPath(fn, &path);
911  FD_t fd = NULL;
912  int rc = 1;
913  int xx;
914 
915  memset(st, 0, sizeof(*st));
916  if (!rpmioExists(fn, st))
917  goto exit;
918  fd = Fopen(fn, "r.ufdio");
919  if (fd == NULL || Ferror(fd))
920  goto exit;
921 
922  switch (ut) {
923  case URL_IS_PATH:
924  case URL_IS_UNKNOWN:
925 #if defined(HAVE_MMAP)
926  { void * mapped = (void *)-1;
927 
928  if (st->st_size > 0)
929  mapped = mmap(NULL, st->st_size, PROT_READ, MAP_SHARED, Fileno(fd), 0);
930  if (mapped != (void *)-1) {
931 #ifdef NOTYET
932  rpmts ts = repo->_ts;
933  rpmop op = rpmtsOp(ts, RPMTS_OP_DIGEST);
934  rpmtime_t tstamp = rpmswEnter(op, 0);
935 #endif
936  DIGEST_CTX ctx = rpmDigestInit(repo->algo, RPMDIGEST_NONE);
937  xx = rpmDigestUpdate(ctx, mapped, st->st_size);
938  xx = rpmDigestFinal(ctx, digestp, NULL, asAscii);
939 #ifdef NOTYET
940  tstamp = rpmswExit(op, st->st_size);
941 #endif
942  xx = munmap(mapped, st->st_size);
943  break;
944  }
945  } /*@fallthrough@*/
946 #endif
947  default:
948  { char buf[64 * BUFSIZ];
949  size_t nb;
950  size_t fsize = 0;
951 
952  fdInitDigest(fd, repo->algo, 0);
953  while ((nb = Fread(buf, sizeof(buf[0]), sizeof(buf), fd)) > 0)
954  fsize += nb;
955  if (Ferror(fd))
956  goto exit;
957  fdFiniDigest(fd, repo->algo, digestp, NULL, asAscii);
958  } break;
959  }
960 
961  rc = 0;
962 
963 exit:
964  if (fd)
965  xx = rpmrepoFclose(repo, fd);
966  fn = _free(fn);
967  return rc;
968 }
969 
976 static int rpmrepoCloseMDFile(const rpmrepo repo, rpmrfile rfile)
977  /*@globals h_errno, rpmGlobalMacroContext, fileSystem, internalState @*/
978  /*@modifies rfile, rpmGlobalMacroContext, fileSystem, internalState @*/
979 {
980  static int asAscii = 1;
981  char * xmlfn = xstrdup(fdGetOPath(rfile->fd));
982  int rc = 0;
983 
984  if (!repo->quiet)
985  rpmrepoError(0, _("Saving %s metadata"), basename(xmlfn));
986 
987  if (rpmrfileXMLWrite(rfile, xstrdup(rfile->xml_fini)))
988  rc = 1;
989 
990  if (repo->algo > 0)
991  fdFiniDigest(rfile->fd, repo->algo, &rfile->digest, NULL, asAscii);
992  else
993  rfile->digest = xstrdup("");
994 
995  (void) rpmrepoFclose(repo, rfile->fd);
996  rfile->fd = NULL;
997 
998  /* Compute the (usually compressed) ouput file digest too. */
999  rfile->Zdigest = NULL;
1000  (void) rpmrepoRfileDigest(repo, rfile, &rfile->Zdigest);
1001 
1002 #if defined(WITH_SQLITE)
1003  if (REPO_ISSET(DATABASE) && rfile->sqldb != NULL) {
1004  const char *dbfn = rpmGetPath(repo->outputdir, "/", repo->tempdir, "/",
1005  rfile->type, ".sqlite", NULL);
1006  int xx;
1007  if ((xx = sqlite3_close(rfile->sqldb)) != SQLITE_OK)
1008  rpmrepoError(1, "sqlite3_close(%s): %s", dbfn, sqlite3_errmsg(rfile->sqldb));
1009  rfile->sqldb = NULL;
1010  dbfn = _free(dbfn);
1011  }
1012 #endif
1013 
1014  rfile->ctime = rpmioCtime(xmlfn);
1015  xmlfn = _free(xmlfn);
1016 
1017  return rc;
1018 }
1019 
1022 static /*@observer@*/ /*@null@*/ const char *
1023 algo2tagname(uint32_t algo)
1024  /*@*/
1025 {
1026  const char * tagname = NULL;
1027 
1028  switch (algo) {
1029  case PGPHASHALGO_NONE: tagname = "none"; break;
1030  case PGPHASHALGO_MD5: tagname = "md5"; break;
1031  /* XXX todo: should be "sha1" */
1032  case PGPHASHALGO_SHA1: tagname = "sha"; break;
1033  case PGPHASHALGO_RIPEMD160: tagname = "rmd160"; break;
1034  case PGPHASHALGO_MD2: tagname = "md2"; break;
1035  case PGPHASHALGO_TIGER192: tagname = "tiger192"; break;
1036  case PGPHASHALGO_HAVAL_5_160: tagname = "haval160"; break;
1037  case PGPHASHALGO_SHA256: tagname = "sha256"; break;
1038  case PGPHASHALGO_SHA384: tagname = "sha384"; break;
1039  case PGPHASHALGO_SHA512: tagname = "sha512"; break;
1040  case PGPHASHALGO_MD4: tagname = "md4"; break;
1041  case PGPHASHALGO_RIPEMD128: tagname = "rmd128"; break;
1042  case PGPHASHALGO_CRC32: tagname = "crc32"; break;
1043  case PGPHASHALGO_ADLER32: tagname = "adler32"; break;
1044  case PGPHASHALGO_CRC64: tagname = "crc64"; break;
1045  case PGPHASHALGO_JLU32: tagname = "jlu32"; break;
1046  case PGPHASHALGO_SHA224: tagname = "sha224"; break;
1047  case PGPHASHALGO_RIPEMD256: tagname = "rmd256"; break;
1048  case PGPHASHALGO_RIPEMD320: tagname = "rmd320"; break;
1049  case PGPHASHALGO_SALSA10: tagname = "salsa10"; break;
1050  case PGPHASHALGO_SALSA20: tagname = "salsa20"; break;
1051  default: tagname = NULL; break;
1052  }
1053  return tagname;
1054 }
1055 
1061 static const char * rpmrepoMDExpand(rpmrepo repo, rpmrfile rfile)
1062  /*@globals h_errno, rpmGlobalMacroContext, internalState @*/
1063  /*@modifies rpmGlobalMacroContext, internalState @*/
1064 {
1065  const char * spewalgo = algo2tagname(repo->algo);
1066  char spewtime[64];
1067 
1068  (void) snprintf(spewtime, sizeof(spewtime), "%u", (unsigned)rfile->ctime);
1069  return rpmExpand("\
1070  <data type=\"", rfile->type, "\">\n\
1071  <checksum type=\"", spewalgo, "\">", rfile->Zdigest, "</checksum>\n\
1072  <timestamp>", spewtime, "</timestamp>\n\
1073  <open-checksum type=\"",spewalgo,"\">", rfile->digest, "</open-checksum>\n\
1074  <location href=\"", repo->finaldir, "/", rfile->type, (repo->markup != NULL ? repo->markup : ""), (repo->suffix != NULL ? repo->suffix : ""), "\"/>\n\
1075  </data>\n", NULL);
1076 }
1077 
1079 {
1080  rpmrfile rfile = &repo->repomd;
1081  const char * fn = rpmrepoGetPath(repo, repo->tempdir, rfile->type, 0);
1082  int rc = 0;
1083 
1084  if ((rfile->fd = Fopen(fn, "w.ufdio")) != NULL) { /* no compression */
1085  if (rpmrfileXMLWrite(rfile, xstrdup(rfile->xml_init))
1086  || rpmrfileXMLWrite(rfile, rpmrepoMDExpand(repo, &repo->other))
1087  || rpmrfileXMLWrite(rfile, rpmrepoMDExpand(repo, &repo->filelists))
1088  || rpmrfileXMLWrite(rfile, rpmrepoMDExpand(repo, &repo->primary))
1089  || rpmrfileXMLWrite(rfile, xstrdup(rfile->xml_fini)))
1090  rc = 1;
1091  (void) rpmrepoFclose(repo, rfile->fd);
1092  rfile->fd = NULL;
1093  }
1094 
1095  fn = _free(fn);
1096  if (rc) return rc;
1097 
1098 #ifdef NOTYET
1099  def doRepoMetadata(self):
1100  """wrapper to generate the repomd.xml file that stores the info on the other files"""
1101  const char * repopath =
1102  rpmGetPath(repo->outputdir, "/", repo->tempdir, NULL);
1103  repodoc = libxml2.newDoc("1.0")
1104  reporoot = repodoc.newChild(None, "repomd", None)
1105  repons = reporoot.newNs("http://linux.duke.edu/metadata/repo", None)
1106  reporoot.setNs(repons)
1107  repopath = rpmGetPath(repo->outputdir, "/", repo->tempdir, NULL);
1108  fn = rpmrepoGetPath(repo, repo->tempdir, repo->repomd.type, 1);
1109 
1110  repoid = "garbageid";
1111 
1112  if (REPO_ISSET(DATABASE)) {
1113  if (!repo->quiet) rpmrepoError(0, _("Generating sqlite DBs"));
1114  try:
1115  dbversion = str(sqlitecachec.DBVERSION)
1116  except AttributeError:
1117  dbversion = "9"
1118  rp = sqlitecachec.RepodataParserSqlite(repopath, repoid, None)
1119  }
1120 
1121  { static const char * types[] =
1122  { "primary", "filelists", "other", NULL };
1123  const char ** typep;
1124  for (typep = types; *typep != NULL; typep++) {
1125  complete_path = rpmrepoGetPath(repo, repo->tempdir, *typep, 1);
1126 
1127  zfo = _gzipOpen(complete_path)
1128  uncsum = misc.checksum(algo2tagname(repo->algo), zfo)
1129  zfo.close()
1130  csum = misc.checksum(algo2tagname(repo->algo), complete_path)
1131  (void) rpmioExists(complete_path, st)
1132  timestamp = os.stat(complete_path)[8]
1133 
1134  db_csums = {}
1135  db_compressed_sums = {}
1136 
1137  if (REPO_ISSET(repo)) {
1138  if (repo->verbose) {
1139  time_t now = time(NULL);
1140  rpmrepoError(0, _("Starting %s db creation: %s"),
1141  *typep, ctime(&now));
1142  }
1143 
1144  if (!strcmp(*typep, "primary"))
1145  rp.getPrimary(complete_path, csum)
1146  else if (!strcmp(*typep, "filelists"));
1147  rp.getFilelists(complete_path, csum)
1148  else if (!strcmp(*typep, "other"))
1149  rp.getOtherdata(complete_path, csum)
1150 
1151  { const char * tmp_result_path =
1152  rpmGetPath(repo->outputdir, "/", repo->tempdir, "/",
1153  *typep, ".xml.gz.sqlite", NULL);
1154  const char * resultpath =
1155  rpmGetPath(repo->outputdir, "/", repo->tempdir, "/",
1156  *typep, ".sqlite", NULL);
1157 
1158  /* rename from silly name to not silly name */
1159  xx = Rename(tmp_result_path, resultpath);
1160  tmp_result_path = _free(tmp_result_path);
1161  result_compressed =
1162  rpmGetPath(repo->outputdir, "/", repo->tempdir, "/",
1163  *typep, ".sqlite.bz2", NULL);
1164  db_csums[*typep] = misc.checksum(algo2tagname(repo->algo), resultpath)
1165 
1166  /* compress the files */
1167  bzipFile(resultpath, result_compressed)
1168  /* csum the compressed file */
1169  db_compressed_sums[*typep] = misc.checksum(algo2tagname(repo->algo), result_compressed)
1170  /* remove the uncompressed file */
1171  xx = Unlink(resultpath);
1172  resultpath = _free(resultpath);
1173  }
1174 
1175  if (REPO_ISSET(UNIQUEMDFN)) {
1176  const char * csum_result_compressed =
1177  rpmGetPath(repo->outputdir, "/", repo->tempdir, "/",
1178  db_compressed_sums[*typep], "-", *typep, ".sqlite.bz2", NULL);
1179  xx = Rename(result_compressed, csum_result_compressed);
1180  result_compressed = _free(result_compressed);
1181  result_compressed = csum_result_compressed;
1182  }
1183 
1184  /* timestamp the compressed file */
1185  (void) rpmioExists(result_compressed, st)
1186  db_timestamp = os.stat(result_compressed)[8]
1187 
1188  /* add this data as a section to the repomdxml */
1189  db_data_type = rpmExpand(*typep, "_db", NULL);
1190  data = reporoot.newChild(None, 'data', None)
1191  data.newProp('type', db_data_type)
1192  location = data.newChild(None, 'location', None)
1193  if (repo->baseurl != NULL) {
1194  location.newProp('xml:base', repo->baseurl)
1195  }
1196 
1197  location.newProp('href', rpmGetPath(repo->finaldir, "/", *typep, ".sqlite.bz2", NULL));
1198  checksum = data.newChild(None, 'checksum', db_compressed_sums[*typep])
1199  checksum.newProp('type', algo2tagname(repo->algo))
1200  db_tstamp = data.newChild(None, 'timestamp', str(db_timestamp))
1201  unchecksum = data.newChild(None, 'open-checksum', db_csums[*typep])
1202  unchecksum.newProp('type', algo2tagname(repo->algo))
1203  database_version = data.newChild(None, 'database_version', dbversion)
1204  if (repo->verbose) {
1205  time_t now = time(NULL);
1206  rpmrepoError(0, _("Ending %s db creation: %s"),
1207  *typep, ctime(&now));
1208  }
1209  }
1210 
1211  data = reporoot.newChild(None, 'data', None)
1212  data.newProp('type', *typep)
1213 
1214  checksum = data.newChild(None, 'checksum', csum)
1215  checksum.newProp('type', algo2tagname(repo->algo))
1216  timestamp = data.newChild(None, 'timestamp', str(timestamp))
1217  unchecksum = data.newChild(None, 'open-checksum', uncsum)
1218  unchecksum.newProp('type', algo2tagname(repo->algo))
1219  location = data.newChild(None, 'location', None)
1220  if (repo->baseurl != NULL)
1221  location.newProp('xml:base', repo->baseurl)
1222  if (REPO_ISSET(UNIQUEMDFN)) {
1223  orig_file = rpmrepoGetPath(repo, repo->tempdir, *typep, strcmp(*typep, "repomd"));
1224  res_file = rpmExpand(csum, "-", *typep,
1225  (repo->markup ? repo->markup : ""),
1226  (repo->suffix && strcmp(*typep, "repomd") ? repo->suffix : ""), NULL);
1227  dest_file = rpmGetPath(repo->outputdir, "/", repo->tempdir, "/", res_file, NULL);
1228  xx = Rename(orig_file, dest_file);
1229 
1230  } else
1231  res_file = rpmExpand(*typep,
1232  (repo->markup ? repo->markup : ""),
1233  (repo->suffix && strcmp(*typep, "repomd") ? repo->suffix : ""), NULL);
1234 
1235  location.newProp('href', rpmGetPath(repo->finaldir, "/", res_file, NULL));
1236  }
1237  }
1238 
1239  if (!repo->quiet && REPO_ISSET(DATABASE))
1240  rpmrepoError(0, _("Sqlite DBs complete"));
1241 
1242  if (repo->groupfile != NULL) {
1243  self.addArbitraryMetadata(repo->groupfile, 'group_gz', reporoot)
1244  self.addArbitraryMetadata(repo->groupfile, 'group', reporoot, compress=False)
1245  }
1246 
1247  /* save it down */
1248  try:
1249  repodoc.saveFormatFileEnc(fn, 'UTF-8', 1)
1250  except:
1251  rpmrepoError(0, _("Error saving temp file for %s%s%s: %s"),
1252  rfile->type,
1253  (repo->markup ? repo->markup : ""),
1254  (repo->suffix && strcmp(*typep, "repomd") ? repo->suffix : ""),
1255  fn);
1256  rpmrepoError(1, _("Could not save temp file: %s"), fn);
1257 
1258  del repodoc
1259 #endif
1260 
1261  return rc;
1262 }
1263 
1265 {
1266  char * output_final_dir =
1267  rpmGetPath(repo->outputdir, "/", repo->finaldir, NULL);
1268  char * output_old_dir =
1269  rpmGetPath(repo->outputdir, "/", repo->olddir, NULL);
1270  struct stat sb, *st = &sb;
1271  int xx;
1272 
1273  if (rpmioExists(output_final_dir, st)) {
1274  if ((xx = Rename(output_final_dir, output_old_dir)) != 0)
1275  rpmrepoError(1, _("Error moving final %s to old dir %s"),
1276  output_final_dir, output_old_dir);
1277  }
1278 
1279  { const char * output_temp_dir =
1280  rpmGetPath(repo->outputdir, "/", repo->tempdir, NULL);
1281  if ((xx = Rename(output_temp_dir, output_final_dir)) != 0) {
1282  xx = Rename(output_old_dir, output_final_dir);
1283  rpmrepoError(1, _("Error moving final metadata into place"));
1284  }
1285  output_temp_dir = _free(output_temp_dir);
1286  }
1287 
1288  /* Merge old tree into new, unlink/rename as needed. */
1289  {
1290  char *const _av[] = { output_old_dir, NULL };
1291  int _ftsoptions = FTS_NOCHDIR | FTS_PHYSICAL | FTS_XDEV;
1292  int (*_compar)(const FTSENT **, const FTSENT **) = NULL;
1293  FTS * t = Fts_open(_av, _ftsoptions, _compar);
1294  FTSENT * p = NULL;
1295 
1296  if (t != NULL)
1297  while ((p = Fts_read(t)) != NULL) {
1298  const char * opath = p->fts_accpath;
1299  const char * ofn = p->fts_path;
1300  const char * obn = p->fts_name;
1301  const char * nfn = NULL;
1302  switch (p->fts_info) {
1303  default:
1304  break;
1305  case FTS_DP:
1306  /* Remove empty directories on post-traversal visit. */
1307  if ((xx = Rmdir(opath)) != 0)
1308  rpmrepoError(1, _("Could not remove old metadata directory: %s: %s"),
1309  ofn, strerror(errno));
1310  break;
1311  case FTS_F:
1312  /* Remove all non-toplevel files. */
1313  if (p->fts_level > 0) {
1314  if ((xx = Unlink(opath)) != 0)
1315  rpmrepoError(1, _("Could not remove old metadata file: %s: %s"),
1316  ofn, strerror(errno));
1317  break;
1318  }
1319 
1320  /* Remove/rename toplevel files, dependent on target existence. */
1321  nfn = rpmGetPath(output_final_dir, "/", obn, NULL);
1322  if (rpmioExists(nfn, st)) {
1323  if ((xx = Unlink(opath)) != 0)
1324  rpmrepoError(1, _("Could not remove old metadata file: %s: %s"),
1325  ofn, strerror(errno));
1326  } else {
1327  if ((xx = Rename(opath, nfn)) != 0)
1328  rpmrepoError(1, _("Could not restore old non-metadata file: %s -> %s: %s"),
1329  ofn, nfn, strerror(errno));
1330  }
1331  nfn = _free(nfn);
1332  break;
1333  case FTS_SL:
1334  case FTS_SLNONE:
1335  /* Remove all symlinks. */
1336  if ((xx = Unlink(opath)) != 0)
1337  rpmrepoError(1, _("Could not remove old metadata symlink: %s: %s"),
1338  ofn, strerror(errno));
1339  break;
1340  }
1341  }
1342  if (t != NULL)
1343  Fts_close(t);
1344  }
1345 
1346  output_old_dir = _free(output_old_dir);
1347  output_final_dir = _free(output_final_dir);
1348 
1349  return 0;
1350 }
1351 
1352 /*==============================================================*/
1353 
1360 static Header rpmrepoReadHeader(rpmrepo repo, const char * path)
1361  /*@globals rpmGlobalMacroContext, h_errno, fileSystem, internalState @*/
1362  /*@modifies repo, rpmGlobalMacroContext, fileSystem, internalState @*/
1363 {
1364  /* XXX todo: read the payload and collect the blessed file digest. */
1365  FD_t fd = Fopen(path, "r.ufdio");
1366  Header h = NULL;
1367 
1368  if (fd != NULL) {
1369  rpmts ts = repo->_ts;
1370  uint32_t algo = repo->pkgalgo;
1371  rpmRC rpmrc;
1372 
1373  if (algo != PGPHASHALGO_NONE)
1374  fdInitDigest(fd, algo, 0);
1375 
1376  /* XXX what if path needs expansion? */
1377  rpmrc = rpmReadPackageFile(ts, fd, path, &h);
1378  if (algo != PGPHASHALGO_NONE) {
1379  char buffer[32 * BUFSIZ];
1380  size_t nb = sizeof(buffer);
1381  size_t nr;
1382  while ((nr = Fread(buffer, sizeof(buffer[0]), nb, fd)) == nb)
1383  {};
1384  if (Ferror(fd)) {
1385  fprintf(stderr, _("%s: Fread(%s) failed: %s\n"),
1386  __progname, path, Fstrerror(fd));
1387  rpmrc = RPMRC_FAIL;
1388  } else {
1389  static int asAscii = 1;
1390  const char *digest = NULL;
1391  fdFiniDigest(fd, algo, &digest, NULL, asAscii);
1392  (void) headerSetDigest(h, digest);
1393  digest = _free(digest);
1394  }
1395  }
1396 
1397  (void) Fclose(fd);
1398 
1399  switch (rpmrc) {
1400  case RPMRC_NOTFOUND:
1401  case RPMRC_FAIL:
1402  default:
1403  (void) headerFree(h);
1404  h = NULL;
1405  break;
1406  case RPMRC_NOTTRUSTED:
1407  case RPMRC_NOKEY:
1408  case RPMRC_OK:
1409  if (repo->baseurl)
1410  (void) headerSetBaseURL(h, repo->baseurl);
1411  (void) headerSetInstance(h, (uint32_t)repo->current+1);
1412  break;
1413  }
1414  }
1415  return h;
1416 }
1417 
1424 static const char * rfileHeaderSprintf(Header h, const char * qfmt)
1425  /*@globals fileSystem @*/
1426  /*@modifies h, fileSystem @*/
1427 {
1428  const char * msg = NULL;
1429  const char * s = headerSprintf(h, qfmt, NULL, NULL, &msg);
1430  if (s == NULL)
1431  rpmrepoError(1, _("headerSprintf(%s): %s"), qfmt, msg);
1432 assert(s != NULL);
1433  return s;
1434 }
1435 
1436 #if defined(WITH_SQLITE)
1437 
1443 static const char * rfileHeaderSprintfHack(Header h, const char * qfmt)
1444  /*@globals fileSystem @*/
1445  /*@modifies h, fileSystem @*/
1446 {
1447  static const char mark[] = "'XXX'";
1448  static size_t nmark = sizeof("'XXX'") - 1;
1449  const char * msg = NULL;
1450  char * s = (char *) headerSprintf(h, qfmt, NULL, NULL, &msg);
1451  char * f, * fe;
1452  int nsubs = 0;
1453 
1454  if (s == NULL)
1455  rpmrepoError(1, _("headerSprintf(%s): %s"), qfmt, msg);
1456 assert(s != NULL);
1457 
1458  /* XXX Find & replace 'XXX' with '%{DBINSTANCE}' the hard way. */
1459 /*@-nullptrarith@*/
1460  for (f = s; *f != '\0' && (fe = strstr(f, "'XXX'")) != NULL; fe += nmark, f = fe)
1461  nsubs++;
1462 /*@=nullptrarith@*/
1463 
1464  if (nsubs > 0) {
1465  char instance[64];
1466  int xx = snprintf(instance, sizeof(instance), "'%u'",
1467  (uint32_t) headerGetInstance(h));
1468  size_t tlen = strlen(s) + nsubs * ((int)strlen(instance) - (int)nmark);
1469  char * t = xmalloc(tlen + 1);
1470  char * te = t;
1471 
1472  xx = xx;
1473 /*@-nullptrarith@*/
1474  for (f = s; *f != '\0' && (fe = strstr(f, mark)) != NULL; fe += nmark, f = fe) {
1475  *fe = '\0';
1476  te = stpcpy( stpcpy(te, f), instance);
1477  }
1478 /*@=nullptrarith@*/
1479  if (*f != '\0')
1480  te = stpcpy(te, f);
1481  s = _free(s);
1482  s = t;
1483  }
1484 
1485  return s;
1486 }
1487 #endif
1488 
1496 static int rpmrepoWriteMDFile(rpmrepo repo, rpmrfile rfile, Header h)
1497  /*@globals fileSystem @*/
1498  /*@modifies rfile, h, fileSystem @*/
1499 {
1500  int rc = 0;
1501 
1502  if (rfile->xml_qfmt != NULL) {
1503  if (rpmrfileXMLWrite(rfile, rfileHeaderSprintf(h, rfile->xml_qfmt)))
1504  rc = 1;
1505  }
1506 
1507 #if defined(WITH_SQLITE)
1508  if (REPO_ISSET(DATABASE)) {
1509  if (rpmrfileSQLWrite(rfile, rfileHeaderSprintfHack(h, rfile->sql_qfmt)))
1510  rc = 1;
1511  }
1512 #endif
1513 
1514  return rc;
1515 }
1516 
1523  /*@globals h_errno, rpmGlobalMacroContext, fileSystem, internalState @*/
1524  /*@modifies repo, rpmGlobalMacroContext, fileSystem, internalState @*/
1525 {
1526  const char ** pkglist = repo->pkglist;
1527  const char * pkg;
1528  int rc = 0;
1529 
1530  if (pkglist)
1531  while ((pkg = *pkglist++) != NULL) {
1532  Header h = rpmrepoReadHeader(repo, pkg);
1533 
1534  repo->current++;
1535 
1536  /* XXX repoReadHeader() displays error. Continuing is foolish */
1537  if (h == NULL) {
1538  rc = 1;
1539  break;
1540  }
1541 
1542 #ifdef REFERENCE
1543  /* XXX todo: rpmGetPath(mydir, "/", filematrix[mydir], NULL); */
1544  reldir = (pkgpath != NULL ? pkgpath : rpmGetPath(repo->basedir, "/", repo->directories[0], NULL));
1545  self.primaryfile.write(po.do_primary_xml_dump(reldir, baseurl=repo->baseurl))
1546  self.flfile.write(po.do_filelists_xml_dump())
1547  self.otherfile.write(po.do_other_xml_dump())
1548 #endif
1549 
1550  if (rpmrepoWriteMDFile(repo, &repo->primary, h)
1551  || rpmrepoWriteMDFile(repo, &repo->filelists, h)
1552  || rpmrepoWriteMDFile(repo, &repo->other, h))
1553  rc = 1;
1554 
1555  (void) headerFree(h);
1556  h = NULL;
1557  if (rc) break;
1558 
1559  if (!repo->quiet) {
1560  if (repo->verbose)
1561  rpmrepoError(0, "%d/%d - %s", repo->current, repo->pkgcount, pkg);
1562  else
1563  rpmrepoProgress(repo, pkg, repo->current, repo->pkgcount);
1564  }
1565  }
1566  return rc;
1567 }
1568 
1570 {
1571  int rc = 0;
1572 
1573  repo->current = 0;
1574 
1575 #ifdef REFERENCE
1576  def _getFragmentUrl(self, url, fragment):
1577  import urlparse
1578  urlparse.uses_fragment.append('media')
1579  if not url:
1580  return url
1581  (scheme, netloc, path, query, fragid) = urlparse.urlsplit(url)
1582  return urlparse.urlunsplit((scheme, netloc, path, query, str(fragment)))
1583 
1584  def doPkgMetadata(self):
1585  """all the heavy lifting for the package metadata"""
1586  if (argvCount(repo->directories) == 1) {
1587  MetaDataGenerator.doPkgMetadata(self)
1588  return
1589  }
1590 
1591  ARGV_t roots = NULL;
1592  filematrix = {}
1593  for mydir in repo->directories {
1594  if (mydir[0] == '/')
1595  thisdir = xstrdup(mydir);
1596  else if (mydir[0] == '.' && mydir[1] == '.' && mydir[2] == '/')
1597  thisdir = Realpath(mydir, NULL);
1598  else
1599  thisdir = rpmGetPath(repo->basedir, "/", mydir, NULL);
1600 
1601  xx = argvAdd(&roots, thisdir);
1602  thisdir = _free(thisdir);
1603 
1604  filematrix[mydir] = rpmrepoGetFileList(repo, roots, '.rpm')
1605  self.trimRpms(filematrix[mydir])
1606  repo->pkgcount = argvCount(filematrix[mydir]);
1607  roots = argvFree(roots);
1608  }
1609 
1610  mediano = 1;
1611  repo->baseurl = self._getFragmentUrl(repo->baseurl, mediano)
1612 #endif
1613 
1614  if (rpmrepoOpenMDFile(repo, &repo->primary)
1615  || rpmrepoOpenMDFile(repo, &repo->filelists)
1616  || rpmrepoOpenMDFile(repo, &repo->other))
1617  rc = 1;
1618  if (rc) return rc;
1619 
1620 #ifdef REFERENCE
1621  for mydir in repo->directories {
1622  repo->baseurl = self._getFragmentUrl(repo->baseurl, mediano)
1623  /* XXX todo: rpmGetPath(mydir, "/", filematrix[mydir], NULL); */
1624  if (repoWriteMetadataDocs(repo, filematrix[mydir]))
1625  rc = 1;
1626  mediano++;
1627  }
1628  repo->baseurl = self._getFragmentUrl(repo->baseurl, 1)
1629 #endif
1630 
1631  if (repoWriteMetadataDocs(repo))
1632  rc = 1;
1633 
1634  if (!repo->quiet)
1635  fprintf(stderr, "\n");
1636  if (rpmrepoCloseMDFile(repo, &repo->primary)
1637  || rpmrepoCloseMDFile(repo, &repo->filelists)
1638  || rpmrepoCloseMDFile(repo, &repo->other))
1639  rc = 1;
1640 
1641  return rc;
1642 }
1643 
1644 /*==============================================================*/
1645 
1646 /*@unchecked@*/
1647 static int compression = -1;
1648 
1649 /*@unchecked@*/ /*@observer@*/
1650 static struct poptOption repoCompressionPoptTable[] = {
1651  { "uncompressed", '\0', POPT_ARG_VAL, &compression, 0,
1652  N_("don't compress"), NULL },
1653  { "gzip", 'Z', POPT_ARG_VAL, &compression, 1,
1654  N_("use gzip compression"), NULL },
1655  { "bzip2", '\0', POPT_ARG_VAL, &compression, 2,
1656  N_("use bzip2 compression"), NULL },
1657  { "lzma", '\0', POPT_ARG_VAL, &compression, 3,
1658  N_("use lzma compression"), NULL },
1659  { "xz", '\0', POPT_ARG_VAL, &compression, 4,
1660  N_("use xz compression"), NULL },
1661  POPT_TABLEEND
1662 };
1663 
1664 /*@unchecked@*/ /*@observer@*/
1665 static struct poptOption _rpmrepoOptions[] = {
1666 
1667  { "quiet", 'q', POPT_ARG_VAL, &__repo.quiet, 0,
1668  N_("output nothing except for serious errors"), NULL },
1669  { "verbose", 'v', 0, NULL, (int)'v',
1670  N_("output more debugging info."), NULL },
1671  { "dryrun", '\0', POPT_BIT_SET, &__repo.flags, REPO_FLAGS_DRYRUN,
1672  N_("sanity check arguments, don't create metadata"), NULL },
1673  { "excludes", 'x', POPT_ARG_ARGV, &__repo.exclude_patterns, 0,
1674  N_("glob PATTERN(s) to exclude"), N_("PATTERN") },
1675  { "includes", 'i', POPT_ARG_ARGV, &__repo.include_patterns, 0,
1676  N_("glob PATTERN(s) to include"), N_("PATTERN") },
1677  { "basedir", '\0', POPT_ARG_STRING|POPT_ARGFLAG_DOC_HIDDEN, &__repo.basedir, 0,
1678  N_("top level directory"), N_("DIR") },
1679  { "baseurl", 'u', POPT_ARG_STRING|POPT_ARGFLAG_DOC_HIDDEN, &__repo.baseurl, 0,
1680  N_("baseurl to append on all files"), N_("BASEURL") },
1681 #ifdef NOTYET
1682  { "groupfile", 'g', POPT_ARG_STRING|POPT_ARGFLAG_DOC_HIDDEN, &__repo.groupfile, 0,
1683  N_("path to groupfile to include in metadata"), N_("FILE") },
1684 #endif
1685  { "pretty", 'p', POPT_BIT_SET|POPT_ARGFLAG_DOC_HIDDEN, &__repo.flags, REPO_FLAGS_PRETTY,
1686  N_("make sure all xml generated is formatted"), NULL },
1687  { "checkts", 'C', POPT_BIT_SET|POPT_ARGFLAG_DOC_HIDDEN, &__repo.flags, REPO_FLAGS_CHECKTS,
1688  N_("check timestamps on files vs the metadata to see if we need to update"), NULL },
1689  { "database", 'd', POPT_BIT_SET, &__repo.flags, REPO_FLAGS_DATABASE,
1690  N_("create sqlite3 database files"), NULL },
1691  { "split", '\0', POPT_BIT_SET|POPT_ARGFLAG_DOC_HIDDEN, &__repo.flags, REPO_FLAGS_SPLIT,
1692  N_("generate split media"), NULL },
1693  { "pkglist", 'l', POPT_ARG_ARGV|POPT_ARGFLAG_DOC_HIDDEN, &__repo.manifests, 0,
1694  N_("use only the files listed in this file from the directory specified"), N_("FILE") },
1695  { "outputdir", 'o', POPT_ARG_STRING, &__repo.outputdir, 0,
1696  N_("<dir> = optional directory to output to"), N_("DIR") },
1697  { "skip-symlinks", 'S', POPT_BIT_SET, &__repo.flags, REPO_FLAGS_NOFOLLOW,
1698  N_("ignore symlinks of packages"), NULL },
1699  { "unique-md-filenames", '\0', POPT_BIT_SET|POPT_ARGFLAG_DOC_HIDDEN, &__repo.flags, REPO_FLAGS_UNIQUEMDFN,
1700  N_("include the file's checksum in the filename, helps with proxies"), NULL },
1701 
1702  POPT_TABLEEND
1703 
1704 };
1705 
1706 /*@unchecked@*/ /*@observer@*/
1707 static struct poptOption rpmrepoOptionsTable[] = {
1708 
1709  { NULL, '\0', POPT_ARG_INCLUDE_TABLE, _rpmrepoOptions, 0,
1710  N_("Repository options:"), NULL },
1711 
1712  { NULL, '\0', POPT_ARG_INCLUDE_TABLE, rpmioFtsPoptTable, 0,
1713  N_("Fts(3) traversal options:"), NULL },
1714 
1715  { NULL, '\0', POPT_ARG_INCLUDE_TABLE, repoCompressionPoptTable, 0,
1716  N_("Available compressions:"), NULL },
1717 
1718  { NULL, '\0', POPT_ARG_INCLUDE_TABLE, rpmioDigestPoptTable, 0,
1719  N_("Available digests:"), NULL },
1720 
1721  { NULL, '\0', POPT_ARG_INCLUDE_TABLE, rpmioAllPoptTable, 0,
1722  N_("Common options for all rpmio executables:"),
1723  NULL },
1724 
1725  POPT_AUTOALIAS
1726  POPT_AUTOHELP
1727  POPT_TABLEEND
1728 };
1729 
1730 static int rpmrepoInitPopt(rpmrepo repo, char ** av)
1731  /*@modifies repo @*/
1732 {
1733  void *use = repo->_item.use;
1734  void *pool = repo->_item.pool;
1735  int ac = argvCount((ARGV_t)av);
1736  poptContext con = rpmioInit(ac, av, rpmrepoOptionsTable);
1737  int rc = 0; /* XXX assume success */
1738  int xx;
1739  int i;
1740 
1741  *repo = *_repo; /* structure assignment */
1742  repo->_item.use = use;
1743  repo->_item.pool = pool;
1744 
1745  repo->con = con;
1746 
1747  /* XXX Impedanace match against poptIO common code. */
1748  if (rpmIsVerbose())
1749  repo->verbose++;
1750  if (rpmIsDebug())
1751  repo->verbose++;
1752 
1753  repo->ftsoptions = (rpmioFtsOpts ? rpmioFtsOpts : FTS_PHYSICAL);
1754  switch (repo->ftsoptions & (FTS_LOGICAL|FTS_PHYSICAL)) {
1755  case (FTS_LOGICAL|FTS_PHYSICAL):
1756  rpmrepoError(1, "FTS_LOGICAL and FTS_PYSICAL are mutually exclusive");
1757  /*@notreached@*/ break;
1758  case 0:
1759  repo->ftsoptions |= FTS_PHYSICAL;
1760  break;
1761  }
1762 
1763  repo->algo = (rpmioDigestHashAlgo >= 0
1764  ? (rpmioDigestHashAlgo & 0xff) : PGPHASHALGO_SHA1);
1765 
1766  repo->compression = (compression >= 0 ? compression : 1);
1767  switch (repo->compression) {
1768  case 0:
1769  repo->suffix = NULL;
1770  repo->wmode = "w.ufdio";
1771  break;
1772  default:
1773  /*@fallthrough@*/
1774  case 1:
1775  repo->suffix = ".gz";
1776  repo->wmode = "w9.gzdio";
1777  break;
1778  case 2:
1779  repo->suffix = ".bz2";
1780  repo->wmode = "w9.bzdio";
1781  break;
1782  case 3:
1783  repo->suffix = ".lzma";
1784  repo->wmode = "w.lzdio";
1785  break;
1786  case 4:
1787  repo->suffix = ".xz";
1788  repo->wmode = "w.xzdio";
1789  break;
1790  }
1791 
1792  repo->av = poptGetArgs(repo->con);
1793 
1794  if (repo->av == NULL || repo->av[0] == NULL)
1795  rpmrepoError(1, _("Must specify path(s) to index."));
1796 
1797  if (repo->av != NULL)
1798  for (i = 0; repo->av[i] != NULL; i++) {
1799  char fullpath[MAXPATHLEN];
1800  struct stat sb;
1801  const char * rpath;
1802  const char * lpath = NULL;
1803  int ut = urlPath(repo->av[i], &lpath);
1804  size_t nb = (size_t)(lpath - repo->av[i]);
1805  int isdir = (lpath[strlen(lpath)-1] == '/');
1806 
1807  /* Convert to absolute/clean/malloc'd path. */
1808  if (lpath[0] != '/') {
1809  if ((rpath = rpmrepoRealpath(lpath)) == NULL)
1810  rpmrepoError(1, _("Realpath(%s): %s"), lpath, strerror(errno));
1811  lpath = rpmGetPath(rpath, NULL);
1812  rpath = _free(rpath);
1813  } else
1814  lpath = rpmGetPath(lpath, NULL);
1815 
1816  /* Reattach the URI to the absolute/clean path. */
1817  /* XXX todo: rpmGenPath was confused by file:///path/file URI's. */
1818  switch (ut) {
1819  case URL_IS_DASH:
1820  case URL_IS_UNKNOWN:
1821  rpath = lpath;
1822  lpath = NULL;
1823  /*@switchbreak@*/ break;
1824  default:
1825 assert(nb < sizeof(fullpath));
1826  strncpy(fullpath, repo->av[i], nb);
1827  fullpath[nb] = '\0';
1828  rpath = rpmGenPath(fullpath, lpath, NULL);
1829  lpath = _free(lpath);
1830  /*@switchbreak@*/ break;
1831  }
1832 
1833  /* Add a trailing '/' on directories. */
1834  lpath = (isdir || (!Stat(rpath, &sb) && S_ISDIR(sb.st_mode))
1835  ? "/" : NULL);
1836  if (lpath != NULL) {
1837  lpath = rpmExpand(rpath, lpath, NULL);
1838  xx = argvAdd(&repo->directories, lpath);
1839  lpath = _free(lpath);
1840  } else {
1841  xx = argvAdd(&repo->pkglist, rpath);
1842  }
1843  rpath = _free(rpath);
1844  }
1845 
1846  return rc;
1847 }
1848 
1849 static void rpmrepoFini(void * _repo)
1850  /*@globals fileSystem @*/
1851  /*@modifies *_repo, fileSystem @*/
1852 {
1853  rpmrepo repo = _repo;
1854 
1855  repo->primary.digest = _free(repo->primary.digest);
1856  repo->primary.Zdigest = _free(repo->primary.Zdigest);
1857  repo->filelists.digest = _free(repo->filelists.digest);
1858  repo->filelists.Zdigest = _free(repo->filelists.Zdigest);
1859  repo->other.digest = _free(repo->other.digest);
1860  repo->other.Zdigest = _free(repo->other.Zdigest);
1861  repo->repomd.digest = _free(repo->repomd.digest);
1862  repo->repomd.Zdigest = _free(repo->repomd.Zdigest);
1863  repo->outputdir = _free(repo->outputdir);
1864  repo->pkglist = argvFree(repo->pkglist);
1865  repo->directories = argvFree(repo->directories);
1866  repo->manifests = argvFree(repo->manifests);
1867 /*@-onlytrans -refcounttrans @*/
1868  repo->excludeMire = mireFreeAll(repo->excludeMire, repo->nexcludes);
1869  repo->includeMire = mireFreeAll(repo->includeMire, repo->nincludes);
1870 /*@=onlytrans =refcounttrans @*/
1871  repo->exclude_patterns = argvFree(repo->exclude_patterns);
1872  repo->include_patterns = argvFree(repo->include_patterns);
1873 
1874  repo->con = poptFreeContext(repo->con);
1875 
1876 }
1877 
1878 /*@unchecked@*/ /*@only@*/ /*@null@*/
1880 
1881 static rpmrepo rpmrepoGetPool(/*@null@*/ rpmioPool pool)
1882  /*@globals _rpmrepoPool, fileSystem @*/
1883  /*@modifies pool, _rpmrepoPool, fileSystem @*/
1884 {
1885  rpmrepo repo;
1886 
1887  if (_rpmrepoPool == NULL) {
1888  _rpmrepoPool = rpmioNewPool("repo", sizeof(*repo), -1, _rpmrepo_debug,
1889  NULL, NULL, rpmrepoFini);
1890  pool = _rpmrepoPool;
1891  }
1892  repo = (rpmrepo) rpmioGetPool(pool, sizeof(*repo));
1893  memset(((char *)repo)+sizeof(repo->_item), 0, sizeof(*repo)-sizeof(repo->_item));
1894  return repo;
1895 }
1896 
1897 rpmrepo rpmrepoNew(char ** av, int flags)
1898 {
1899  rpmrepo repo = rpmrepoGetPool(_rpmrepoPool);
1900  int xx;
1901 
1902  xx = rpmrepoInitPopt(repo, av);
1903 
1904  return rpmrepoLink(repo);
1905 }
static const char * suffix[]
Definition: rpmgrep.c:188
#define FTS_SLNONE
Definition: fts.h:141
#define FTS_XDEV
Definition: fts.h:93
poptContext rpmioInit(int argc, char *const argv[], struct poptOption *optionsTable)
Definition: poptIO.c:752
int rpmrepoDoFinalMove(rpmrepo repo)
Rename temporary repository to final paths.
Definition: rpmrepo.c:1264
struct poptOption rpmioDigestPoptTable[]
Digest options using popt.
Definition: poptIO.c:151
static const char * primary_sql_init[]
Definition: rpmrepo.c:143
rpmtime_t rpmswExit(rpmop op, ssize_t rc)
Exit timed operation.
Definition: rpmsw.c:264
FTS * Fts_open(char *const *argv, int options, int(*compar)(const FTSENT **, const FTSENT **))
Create a handle for file hierarchy traversal.
Definition: fts.c:207
int mireApply(miRE mire, int nmire, const char *s, size_t slen, int rc)
Apply array of patterns to a string.
Definition: mire.c:553
static struct rpmrepo_s __repo
Definition: rpmrepo.c:298
static const char Packages_qfmt[]
Definition: rpmrepo.c:132
void rpmrepoError(int lvl, const char *fmt,...)
Print an error message and exit (if requested).
Definition: rpmrepo.c:427
void * mireFreeAll(miRE mire, int nmire)
Destroy compiled patterns.
Definition: mire.c:96
struct rpmrfile_s * rpmrfile
Definition: rpmrepo.h:17
static const char filelists_xml_qfmt[]
Definition: rpmrepo.c:107
static const char primary_yaml_qfmt[]
Definition: rpmrepo.c:117
#define EXIT_FAILURE
size_t Fwrite(const void *buf, size_t size, size_t nmemb, FD_t fd)
fwrite(3) clone.
Definition: rpmio.c:2434
char * xstrdup(const char *str)
Definition: rpmmalloc.c:322
FD_t Fopen(const char *path, const char *_fmode)
fopen(3) clone.
Definition: rpmio.c:2833
rpmrepo rpmrepoLink(rpmrepo repo)
Reference a repo wrapper instance.
static int chkSuffix(const char *fn, const char *suffix)
Check file name for a suffix.
Definition: rpmrepo.c:614
DIGEST_CTX rpmDigestInit(pgpHashAlgo hashalgo, rpmDigestFlags flags)
Initialize digest.
Definition: digest.c:244
char * rpmGetPath(const char *path,...)
Return (malloc&#39;ed) expanded, canonicalized, file path.
Definition: macro.c:3310
static const char * fdGetOPath(FD_t fd)
static rpmrepo _repo
Definition: rpmrepo.c:391
#define __progname
Definition: system.h:428
int Access(const char *path, int amode)
access(2) clone.
Definition: rpmrpc.c:2196
static const char * filelists_sql_init[]
Definition: rpmrepo.c:176
static const char * rpmrepoMDExpand(rpmrepo repo, rpmrfile rfile)
Return a repository metadata file item.
Definition: rpmrepo.c:1061
The Header data structure.
int rpmioMkpath(const char *path, mode_t mode, uid_t uid, gid_t gid)
Insure that directories in path exist, creating as needed.
Definition: rpmio.c:3017
struct poptOption rpmioFtsPoptTable[]
Definition: poptIO.c:529
rpmtime_t rpmswAdd(rpmop to, rpmop from)
Sum statistic counters.
Definition: rpmsw.c:280
#define FTS_SL
Definition: fts.h:140
#define MAXPATHLEN
int Stat(const char *path, struct stat *st)
stat(2) clone.
Definition: rpmrpc.c:1361
const char ** rpmrepoGetFileList(rpmrepo repo, const char *roots[], const char *ext)
Walk file/directory trees, looking for files with an extension.
Definition: rpmrepo.c:622
int errno
u_short fts_namelen
Definition: fts.h:119
static int rpmrepoMkdir(rpmrepo repo, const char *dn)
Create directory path.
Definition: rpmrepo.c:494
short fts_level
Definition: fts.h:127
rpmop rpmtsOp(rpmts ts, rpmtsOpX opx)
Retrieve operation timestamp from a transaction set.
Definition: pkgio.c:133
const char * rpmrepoRealpath(const char *lpath)
Return realpath(3) canonicalized absolute path.
Definition: rpmrepo.c:515
pgpHashAlgo rpmioDigestHashAlgo
Definition: poptIO.c:146
static struct poptOption repoCompressionPoptTable[]
Definition: rpmrepo.c:1650
static void fdInitDigest(FD_t fd, pgpHashAlgo hashalgo, int _flags)
Attach digest to fd.
char * headerSprintf(Header h, const char *fmt, headerTagTableEntry tags, headerSprintfExtension exts, errmsg_t *errmsg)
Return formatted output string from header tags.
Definition: hdrfmt.c:6700
static int rpmrepoRfileDigest(const rpmrepo repo, rpmrfile rfile, const char **digestp)
Compute digest of a file.
Definition: rpmrepo.c:902
static rpmop fdstat_op(FD_t fd, fdOpX opx)
static const char * rfileHeaderSprintf(Header h, const char *qfmt)
Return header query.
Definition: rpmrepo.c:1424
static int rpmioExists(const char *fn, struct stat *st)
Return stat(2) for a file.
Definition: rpmrepo.c:400
Yet Another syslog(3) API clone.
u_short fts_info
Definition: fts.h:143
static const char filelists_xml_init[]
Definition: rpmrepo.c:80
#define FTS_D
Definition: fts.h:129
int rpmrepoDoRepoMetadata(rpmrepo repo)
Write repository manifest.
Definition: rpmrepo.c:1078
static const char * algo2tagname(uint32_t algo)
Definition: rpmrepo.c:1023
const char * Fstrerror(FD_t fd)
strerror(3) clone.
Definition: rpmio.c:2401
uint32_t headerSetInstance(Header h, uint32_t instance)
Store header instance (e.g path or URL).
Definition: header.c:1280
int rpmDigestUpdate(DIGEST_CTX ctx, const void *data, size_t len)
Update context with next plain text buffer.
Definition: digest.c:907
static const char primary_sql_qfmt[]
Definition: rpmrepo.c:268
int Rmdir(const char *path)
rmdir(2) clone.
Definition: rpmrpc.c:141
int rpmrepoDoPkgMetadata(rpmrepo repo)
Write repository metadata files.
Definition: rpmrepo.c:1569
rpmioItem rpmioGetPool(rpmioPool pool, size_t size)
Get unused item from pool, or alloc a new item.
Definition: rpmmalloc.c:221
#define N_(Text)
Definition: system.h:490
int Rename(const char *oldpath, const char *newpath)
rename(2) clone.
Definition: rpmrpc.c:286
static const char other_xml_qfmt[]
Definition: rpmrepo.c:112
int argvCount(const ARGV_t argv)
Return no.
Definition: argv.c:71
int Mkdir(const char *path, mode_t mode)
mkdir(2) clone.
Definition: rpmrpc.c:73
ARGV_t argvFree(ARGV_t argv)
Destroy an argv array.
Definition: argv.c:44
static const char other_sql_qfmt[]
Definition: rpmrepo.c:291
static struct poptOption rpmrepoOptionsTable[]
Definition: rpmrepo.c:1707
rpmRC rpmReadPackageFile(rpmts ts, FD_t fd, const char *fn, Header *hdrp)
Return package header from file handle, verifying digests/signatures.
Definition: package.c:428
Digest private data.
Definition: digest.c:127
char * fts_path
Definition: fts.h:115
The FD_t File Handle data structure.
static void fdFiniDigest(FD_t fd, pgpHashAlgo hashalgo, void *datap, size_t *lenp, int asAscii)
const char * rpmGenPath(const char *urlroot, const char *urlmdir, const char *urlfile)
Merge 3 args into path, any or all of which may be a url.
Definition: macro.c:3356
int argvAdd(ARGV_t *argvp, ARGstr_t val)
Add a string to an argv array.
Definition: argv.c:199
static time_t rpmioCtime(const char *fn)
Return stat(2) creation time of a file.
Definition: rpmrepo.c:412
Definition: fts.h:54
Header headerFree(Header h)
Dereference a header instance.
int rpmioFtsOpts
Definition: poptIO.c:526
FTSENT * Fts_read(FTS *sp)
Return next node in the file hierarchy traversal.
Definition: fts.c:467
int rpmswEnter(rpmop op, ssize_t rc)
Enter timed operation.
Definition: rpmsw.c:248
char * rpmExpand(const char *arg,...)
Return (malloc&#39;ed) concatenated macro expansion(s).
Definition: macro.c:3117
size_t Fread(void *buf, size_t size, size_t nmemb, FD_t fd)
fread(3) clone.
Definition: rpmio.c:2412
int headerSetDigest(Header h, const char *digest)
Store digest of origin *.rpm file.
Definition: header.c:1249
int Fclose(FD_t fd)
fclose(3) clone.
Definition: rpmio.c:2534
Cumulative statistics for an operation.
Definition: rpmsw.h:33
void argvPrint(const char *msg, ARGV_t argv, FILE *fp)
Print argv array elements.
Definition: argv.c:19
char * fts_accpath
Definition: fts.h:113
static const char repomd_xml_init[]
Definition: rpmrepo.c:94
char fts_name[1]
Definition: fts.h:157
static const char * other_sql_init[]
Definition: rpmrepo.c:195
static const char primary_xml_init[]
Definition: rpmrepo.c:73
static const char other_yaml_qfmt[]
Definition: rpmrepo.c:127
enum rpmRC_e rpmRC
RPM return codes.
static Header rpmrepoReadHeader(rpmrepo repo, const char *path)
Read a header from a repository package file, computing package file digest.
Definition: rpmrepo.c:1360
int Ferror(FD_t fd)
ferror(3) clone.
Definition: rpmio.c:2944
static int rpmrfileXMLWrite(rpmrfile rfile, const char *spew)
Write to a repository metadata file.
Definition: rpmrepo.c:709
urltype urlPath(const char *url, const char **pathp)
Return path component of URL.
Definition: url.c:429
static int snprintf(char *buf, int nb, const char *fmt,...)
Definition: rpmps.c:220
#define FTS_NOCHDIR
Definition: fts.h:89
Definition: fts.h:102
int rpmrepoCheckTimeStamps(rpmrepo repo)
Check that repository time stamp is newer than any contained package.
Definition: rpmrepo.c:681
static int rpmrepoFclose(rpmrepo repo, FD_t fd)
Close an I/O stream, accumulating uncompress/digest statistics.
Definition: rpmrepo.c:733
Methods to handle package elements.
rpmioPool rpmioNewPool(const char *name, size_t size, int limit, int flags, char *(*dbg)(void *item), void(*init)(void *item), void(*fini)(void *item))
Create a memory pool.
Definition: rpmmalloc.c:110
rpmrepo rpmrepoNew(char **av, int flags)
Create and load a repo wrapper.
Definition: rpmrepo.c:1897
static int compression
Definition: rpmrepo.c:1647
char * stpcpy(char *dest, const char *src)
static int rpmrepoOpenMDFile(const rpmrepo repo, rpmrfile rfile)
Open a repository metadata file.
Definition: rpmrepo.c:759
struct rpmts_s * rpmts
The RPM Transaction Set.
Definition: rpmtypes.h:14
static void * _free(const void *p)
Wrapper to free(3), hides const compilation noise, permit NULL, return NULL.
Definition: rpmiotypes.h:647
Structures and prototypes used for an "rpmts" transaction set.
static const char filelists_yaml_qfmt[]
Definition: rpmrepo.c:122
static const char * rpmrepoGetPath(rpmrepo repo, const char *dir, const char *type, int compress)
Return /repository/directory/component.markup.compression path.
Definition: rpmrepo.c:448
#define FTS_PHYSICAL
Definition: fts.h:91
static const char other_xml_fini[]
Definition: rpmrepo.c:91
#define FTS_LOGICAL
Definition: fts.h:88
#define rpmIsVerbose()
Definition: rpmcb.h:21
int Fts_close(FTS *sp)
Destroy a file hierarchy traversal handle.
Definition: fts.c:380
struct rpmrepo_s * rpmrepo
Definition: rpmrepo.h:16
int Fileno(FD_t fd)
fileno(3) clone.
Definition: rpmio.c:2991
static rpmrepo rpmrepoGetPool(rpmioPool pool)
Definition: rpmrepo.c:1881
int rpmDigestFinal(DIGEST_CTX ctx, void *datap, size_t *lenp, int asAscii)
Return digest and destroy context.
Definition: digest.c:921
static void rpmrepoProgress(rpmrepo repo, const char *item, int current, int total)
Display progress.
Definition: rpmrepo.c:465
#define rpmIsDebug()
Definition: rpmcb.h:23
#define FTS_F
Definition: fts.h:136
static int repoWriteMetadataDocs(rpmrepo repo)
Export all package metadata to repository metadata file(s).
Definition: rpmrepo.c:1522
#define _(Text)
Definition: system.h:30
static const char filelists_sql_qfmt[]
Definition: rpmrepo.c:279
static int rpmrepoCloseMDFile(const rpmrepo repo, rpmrfile rfile)
Close a repository metadata file.
Definition: rpmrepo.c:976
#define xmalloc
Definition: system.h:33
static const char Sources_qfmt[]
Definition: rpmrepo.c:137
#define FTS_DP
Definition: fts.h:134
static void rpmrepoFini(void *_repo)
Definition: rpmrepo.c:1849
ARGstr_t * ARGV_t
Definition: argv.h:9
const char * baseurl
struct poptOption rpmioAllPoptTable[]
Definition: poptIO.c:551
static cptr_t current[2]
Definition: rpmrc.c:128
static const char other_xml_init[]
Definition: rpmrepo.c:87
static int rpmrepoInitPopt(rpmrepo repo, char **av)
Definition: rpmrepo.c:1730
static const char repomd_xml_fini[]
Definition: rpmrepo.c:98
static const char primary_xml_fini[]
Definition: rpmrepo.c:77
int headerSetBaseURL(Header h, const char *baseurl)
Store header base URL (e.g path or URL).
Definition: header.c:1219
uint32_t headerGetInstance(Header h)
Return header instance (if from rpmdb).
Definition: header.c:1275
static const char primary_xml_qfmt[]
Definition: rpmrepo.c:102
char * Realpath(const char *path, char *resolved_path)
realpath(3) clone.
Definition: rpmrpc.c:2330
int rpmrepoTestSetupDirs(rpmrepo repo)
Test for repository sanity.
Definition: rpmrepo.c:530
static const char filelists_xml_fini[]
Definition: rpmrepo.c:84
rpmioPool _rpmrepoPool
Definition: rpmrepo.c:1879
static int rpmrepoWriteMDFile(rpmrepo repo, rpmrfile rfile, Header h)
Export a single package&#39;s metadata to repository metadata file(s).
Definition: rpmrepo.c:1496
static struct poptOption _rpmrepoOptions[]
Definition: rpmrepo.c:1665
int _rpmrepo_debug
Definition: rpmrepo.c:66
#define W_OK
Definition: system.h:218
unsigned long int rpmtime_t
Definition: rpmsw.h:10
int Unlink(const char *path)
unlink(2) clone.
Definition: rpmrpc.c:397