rpm  5.4.15
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 
449 static const char * rpmrepoGetPath(rpmrepo repo, const char * dir,
450  const char * type, int compress)
451  /*@globals h_errno, rpmGlobalMacroContext, internalState @*/
452  /*@modifies rpmGlobalMacroContext, internalState @*/
453 {
454  return rpmGetPath(repo->outputdir, "/", dir, "/", type,
455  (repo->markup != NULL ? repo->markup : ""),
456  (repo->suffix != NULL && compress ? repo->suffix : ""), NULL);
457 }
458 
466 static void rpmrepoProgress(/*@unused@*/ rpmrepo repo,
467  /*@null@*/ const char * item, int current, int total)
468  /*@globals fileSystem, internalState @*/
469  /*@modifies fileSystem, internalState @*/
470 {
471  static size_t ncols = 80 - 1; /* XXX TIOCGWINSIZ */
472  const char * bn = (item != NULL ? strrchr(item, '/') : NULL);
473  size_t nb;
474 
475  if (bn != NULL)
476  bn++;
477  else
478  bn = item;
479  nb = fprintf(stdout, "\r%s: %d/%d", __progname, current, total);
480  if (bn != NULL)
481  nb += fprintf(stdout, " - %s", bn);
482  nb--;
483  if (nb < ncols)
484  fprintf(stdout, "%*s", (int)(ncols - nb), "");
485  ncols = nb;
486  (void) fflush(stdout);
487 }
488 
495 static int rpmrepoMkdir(rpmrepo repo, const char * dn)
496  /*@globals rpmGlobalMacroContext, h_errno, fileSystem, internalState @*/
497  /*@modifies rpmGlobalMacroContext, fileSystem, internalState @*/
498 {
499  const char * dnurl = rpmGetPath(repo->outputdir, "/", dn, NULL);
500 /*@-mods@*/
501  int ut = urlPath(dnurl, &dn);
502 /*@=mods@*/
503  int rc = 0;;
504 
505  /* XXX todo: rpmioMkpath doesn't grok URI's */
506  if (ut == URL_IS_UNKNOWN)
507  rc = rpmioMkpath(dn, 0755, (uid_t)-1, (gid_t)-1);
508  else
509  rc = (Mkdir(dnurl, 0755) == 0 || errno == EEXIST ? 0 : -1);
510  if (rc)
511  rpmrepoError(0, _("Cannot create/verify %s: %s"), dnurl, strerror(errno));
512  dnurl = _free(dnurl);
513  return rc;
514 }
515 
516 const char * rpmrepoRealpath(const char * lpath)
517 {
518  /* XXX GLIBC: realpath(path, NULL) return malloc'd */
519  const char *rpath = Realpath(lpath, NULL);
520  if (rpath == NULL) {
521  char fullpath[MAXPATHLEN];
522  rpath = Realpath(lpath, fullpath);
523  if (rpath != NULL)
524  rpath = xstrdup(rpath);
525  }
526  return rpath;
527 }
528 
529 /*==============================================================*/
530 
532 {
533  const char ** directories = repo->directories;
534  struct stat sb, *st = &sb;
535  const char * dn;
536  const char * fn;
537  int rc = 0;
538 
539  /* XXX todo: check repo->pkglist existence? */
540 
541  if (directories != NULL)
542  while ((dn = *directories++) != NULL) {
543  if (!rpmioExists(dn, st) || !S_ISDIR(st->st_mode)) {
544  rpmrepoError(0, _("Directory %s must exist"), dn);
545  rc = 1;
546  }
547  }
548 
549  /* XXX todo create outputdir if it doesn't exist? */
550  if (!rpmioExists(repo->outputdir, st)) {
551  rpmrepoError(0, _("Directory %s does not exist."), repo->outputdir);
552  rc = 1;
553  }
554  if (Access(repo->outputdir, W_OK)) {
555  rpmrepoError(0, _("Directory %s must be writable."), repo->outputdir);
556  rc = 1;
557  }
558 
559  if (rpmrepoMkdir(repo, repo->tempdir)
560  || rpmrepoMkdir(repo, repo->finaldir))
561  rc = 1;
562 
563  dn = rpmGetPath(repo->outputdir, "/", repo->olddir, NULL);
564  if (rpmioExists(dn, st)) {
565  rpmrepoError(0, _("Old data directory exists, please remove: %s"), dn);
566  rc = 1;
567  }
568  dn = _free(dn);
569 
570  { /*@observer@*/
571  static const char * dirs[] = { ".repodata", "repodata", NULL };
572  /*@observer@*/
573  static const char * types[] =
574  { "primary", "filelists", "other", "repomd", NULL };
575  const char ** dirp, ** typep;
576  for (dirp = dirs; *dirp != NULL; dirp++) {
577  for (typep = types; *typep != NULL; typep++) {
578  fn = rpmrepoGetPath(repo, *dirp, *typep, strcmp(*typep, "repomd"));
579  if (rpmioExists(fn, st)) {
580  if (Access(fn, W_OK)) {
581  rpmrepoError(0, _("Path must be writable: %s"), fn);
582  rc = 1;
583  } else
584  if (REPO_ISSET(CHECKTS) && st->st_ctime > repo->mdtimestamp)
585  repo->mdtimestamp = st->st_ctime;
586  }
587  fn = _free(fn);
588  }
589  }
590  }
591 
592 #ifdef NOTYET /* XXX repo->package_dir needs to go away. */
593  if (repo->groupfile != NULL) {
594  if (REPO_ISSET(SPLIT) || repo->groupfile[0] != '/') {
595  fn = rpmGetPath(repo->package_dir, "/", repo->groupfile, NULL);
596  repo->groupfile = _free(repo->groupfile);
597  repo->groupfile = fn;
598  fn = NULL;
599  }
600  if (!rpmioExists(repo->groupfile, st)) {
601  rpmrepoError(0, _("groupfile %s cannot be found."), repo->groupfile);
602  rc = 1;
603  }
604  }
605 #endif
606  return rc;
607 }
608 
615 static int chkSuffix(const char * fn, const char * suffix)
616  /*@*/
617 {
618  size_t flen = strlen(fn);
619  size_t slen = strlen(suffix);
620  return (flen > slen && !strcmp(fn + flen - slen, suffix));
621 }
622 
623 const char ** rpmrepoGetFileList(rpmrepo repo, const char *roots[],
624  const char * ext)
625 {
626  const char ** pkglist = NULL;
627  FTS * t;
628  FTSENT * p;
629  int xx;
630 
631  if ((t = Fts_open((char *const *)roots, repo->ftsoptions, NULL)) == NULL)
632  rpmrepoError(1, _("Fts_open: %s"), strerror(errno));
633 
634  while ((p = Fts_read(t)) != NULL) {
635 #ifdef NOTYET
636  const char * fts_name = p->fts_name;
637  size_t fts_namelen = p->fts_namelen;
638 
639  /* XXX fts(3) (and Fts(3)) have fts_name = "" with pesky trailing '/' */
640  if (p->fts_level == 0 && fts_namelen == 0) {
641  fts_name = ".";
642  fts_namelen = sizeof(".") - 1;
643  }
644 #endif
645 
646  /* Should this element be excluded/included? */
647  /* XXX todo: apply globs to fts_path rather than fts_name? */
648 /*@-onlytrans@*/
649  if (mireApply(repo->excludeMire, repo->nexcludes, p->fts_name, 0, -1) >= 0)
650  continue;
651  if (mireApply(repo->includeMire, repo->nincludes, p->fts_name, 0, +1) < 0)
652  continue;
653 /*@=onlytrans@*/
654 
655  switch (p->fts_info) {
656  case FTS_D:
657  case FTS_DP:
658  default:
659  continue;
660  /*@notreached@*/ /*@switchbreak@*/ break;
661  case FTS_SL:
662  if (REPO_ISSET(NOFOLLOW))
663  continue;
664  /* XXX todo: fuss with symlinks */
665  /*@notreached@*/ /*@switchbreak@*/ break;
666  case FTS_F:
667  /* Is this a *.rpm file? */
668  if (chkSuffix(p->fts_name, ext))
669  xx = argvAdd(&pkglist, p->fts_path);
670  /*@switchbreak@*/ break;
671  }
672  }
673 
674  (void) Fts_close(t);
675 
676 if (_rpmrepo_debug)
677 argvPrint("pkglist", pkglist, NULL);
678 
679  return pkglist;
680 }
681 
683 {
684  int rc = 0;
685 
686  if (REPO_ISSET(CHECKTS)) {
687  const char ** pkg;
688 
689  if (repo->pkglist != NULL)
690  for (pkg = repo->pkglist; *pkg != NULL ; pkg++) {
691  struct stat sb, *st = &sb;
692  if (!rpmioExists(*pkg, st)) {
693  rpmrepoError(0, _("cannot get to file: %s"), *pkg);
694  rc = 1;
695  } else if (st->st_ctime > repo->mdtimestamp)
696  rc = 1;
697  }
698  } else
699  rc = 1;
700 
701  return rc;
702 }
703 
710 static int rpmrfileXMLWrite(rpmrfile rfile, const char * spew)
711  /*@globals fileSystem @*/
712  /*@modifies rfile, fileSystem @*/
713 {
714  size_t nspew = (spew != NULL ? strlen(spew) : 0);
715 /*@-nullpass@*/ /* XXX spew != NULL @*/
716  size_t nb = (nspew > 0 ? Fwrite(spew, 1, nspew, rfile->fd) : 0);
717 /*@=nullpass@*/
718  int rc = 0;
719  if (nspew != nb) {
720  rpmrepoError(0, _("Fwrite failed: expected write %u != %u bytes: %s\n"),
721  (unsigned)nspew, (unsigned)nb, Fstrerror(rfile->fd));
722  rc = 1;
723  }
724  spew = _free(spew);
725  return rc;
726 }
727 
734 static int rpmrepoFclose(rpmrepo repo, FD_t fd)
735  /*@modifies repo, fd @*/
736 {
737  int rc = 0;
738 
739  if (fd != NULL) {
740 #ifdef NOTYET
741  rpmts ts = repo->_ts;
742  if (ts != NULL) {
744  fdstat_op(fd, FDSTAT_READ));
745  (void) rpmswAdd(rpmtsOp(ts, RPMTS_OP_DIGEST),
746  fdstat_op(fd, FDSTAT_DIGEST));
747  }
748 #endif
749  rc = Fclose(fd);
750  }
751  return rc;
752 }
753 
760 static int rpmrepoOpenMDFile(const rpmrepo repo, rpmrfile rfile)
761  /*@globals h_errno, rpmGlobalMacroContext, fileSystem, internalState @*/
762  /*@modifies rfile, rpmGlobalMacroContext, fileSystem, internalState @*/
763 {
764  const char * spew = rfile->xml_init;
765  size_t nspew = strlen(spew);
766  const char * fn = rpmrepoGetPath(repo, repo->tempdir, rfile->type, 1);
767  const char * tail;
768  size_t nb;
769  int rc = 0;
770 
771  rfile->fd = Fopen(fn, repo->wmode);
772 assert(rfile->fd != NULL);
773 
774  if (repo->algo != PGPHASHALGO_NONE)
775  fdInitDigest(rfile->fd, repo->algo, 0);
776 
777  if ((tail = strstr(spew, " packages=\"0\">\n")) != NULL)
778  nspew -= strlen(tail);
779 
780  nb = Fwrite(spew, 1, nspew, rfile->fd);
781 
782  if (tail != NULL) {
783  char buf[64];
784  size_t tnb = snprintf(buf, sizeof(buf), " packages=\"%d\">\n",
785  repo->pkgcount);
786  nspew += tnb;
787  nb += Fwrite(buf, 1, tnb, rfile->fd);
788  }
789  if (nspew != nb) {
790  rpmrepoError(0, _("Fwrite failed: expected write %u != %u bytes: %s\n"),
791  (unsigned)nspew, (unsigned)nb, Fstrerror(rfile->fd));
792  rc = 1;
793  }
794 
795  fn = _free(fn);
796 
797 #if defined(WITH_SQLITE)
798  if (REPO_ISSET(DATABASE)) {
799  const char ** stmt;
800  int xx;
801  fn = rpmGetPath(repo->outputdir, "/", repo->tempdir, "/",
802  rfile->type, ".sqlite", NULL);
803  if ((xx = sqlite3_open(fn, &rfile->sqldb)) != SQLITE_OK)
804  rpmrepoError(1, "sqlite3_open(%s): %s", fn, sqlite3_errmsg(rfile->sqldb));
805  for (stmt = rfile->sql_init; *stmt != NULL; stmt++) {
806  char * msg;
807  xx = sqlite3_exec(rfile->sqldb, *stmt, NULL, NULL, &msg);
808  if (xx != SQLITE_OK)
809  rpmrepoError(1, "sqlite3_exec(%s, \"%s\"): %s\n", fn, *stmt,
810  (msg != NULL ? msg : "failed"));
811  }
812  fn = _free(fn);
813  }
814 #endif
815 
816  return rc;
817 }
818 
819 #if defined(WITH_SQLITE)
820 
827 static int rpmrfileSQL(rpmrfile rfile, const char * msg, int rc)
828  /*@globals fileSystem @*/
829  /*@modifies fileSystem @*/
830 {
831  if (rc != SQLITE_OK || _rpmrepo_debug)
832  rpmrepoError(0, "sqlite3_%s(%s): %s", msg, rfile->type,
833  sqlite3_errmsg(rfile->sqldb));
834  return rc;
835 }
836 
843 static int rpmrfileSQLStep(rpmrfile rfile, sqlite3_stmt * stmt)
844  /*@globals fileSystem @*/
845  /*@modifies fileSystem @*/
846 {
847  int loop = 1;
848  int rc = 0;
849  int xx;
850 
851 /*@-infloops@*/
852  while (loop) {
853  rc = sqlite3_step(stmt);
854  switch (rc) {
855  default:
856  rc = rpmrfileSQL(rfile, "step", rc);
857  /*@fallthrough@*/
858  case SQLITE_DONE:
859  loop = 0;
860  /*@switchbreak@*/ break;
861  }
862  }
863 /*@=infloops@*/
864 
865  xx = rpmrfileSQL(rfile, "reset",
866  sqlite3_reset(stmt));
867 
868  return rc;
869 }
870 
877 static int rpmrfileSQLWrite(rpmrfile rfile, const char * cmd)
878  /*@globals fileSystem @*/
879  /*@modifies fileSystem @*/
880 {
881  sqlite3_stmt * stmt;
882  const char * tail;
883  int xx;
884 
885  xx = rpmrfileSQL(rfile, "prepare",
886  sqlite3_prepare(rfile->sqldb, cmd, (int)strlen(cmd), &stmt, &tail));
887 
888  xx = rpmrfileSQL(rfile, "reset",
889  sqlite3_reset(stmt));
890 
891  xx = rpmrfileSQLStep(rfile, stmt);
892 
893  xx = rpmrfileSQL(rfile, "finalize",
894  sqlite3_finalize(stmt));
895 
896  cmd = _free(cmd);
897 
898  return 0;
899 }
900 #endif /* WITH_SQLITE */
901 
906 static int rpmrepoRfileDigest(const rpmrepo repo, rpmrfile rfile,
907  const char ** digestp)
908  /*@modifies *digestp @*/
909 {
910  static int asAscii = 1;
911  struct stat sb, *st = &sb;
912  const char * fn = rpmrepoGetPath(repo, repo->tempdir, rfile->type, 1);
913  const char * path = NULL;
914  int ut = urlPath(fn, &path);
915  FD_t fd = NULL;
916  int rc = 1;
917  int xx;
918 
919  memset(st, 0, sizeof(*st));
920  if (!rpmioExists(fn, st))
921  goto exit;
922  fd = Fopen(fn, "r.ufdio");
923  if (fd == NULL || Ferror(fd))
924  goto exit;
925 
926  switch (ut) {
927  case URL_IS_PATH:
928  case URL_IS_UNKNOWN:
929 #if defined(HAVE_MMAP)
930  { void * mapped = (void *)-1;
931 
932  if (st->st_size > 0)
933  mapped = mmap(NULL, st->st_size, PROT_READ, MAP_SHARED, Fileno(fd), 0);
934  if (mapped != (void *)-1) {
935 #ifdef NOTYET
936  rpmts ts = repo->_ts;
938  rpmtime_t tstamp = rpmswEnter(op, 0);
939 #endif
940  DIGEST_CTX ctx = rpmDigestInit(repo->algo, RPMDIGEST_NONE);
941  xx = rpmDigestUpdate(ctx, mapped, st->st_size);
942  xx = rpmDigestFinal(ctx, digestp, NULL, asAscii);
943 #ifdef NOTYET
944  tstamp = rpmswExit(op, st->st_size);
945 #endif
946  xx = munmap(mapped, st->st_size);
947  break;
948  }
949  } /*@fallthrough@*/
950 #endif
951  default:
952  { char buf[64 * BUFSIZ];
953  size_t nb;
954  size_t fsize = 0;
955 
956  fdInitDigest(fd, repo->algo, 0);
957  while ((nb = Fread(buf, sizeof(buf[0]), sizeof(buf), fd)) > 0)
958  fsize += nb;
959  if (Ferror(fd))
960  goto exit;
961  fdFiniDigest(fd, repo->algo, digestp, NULL, asAscii);
962  } break;
963  }
964 
965  rc = 0;
966 
967 exit:
968  if (fd)
969  xx = rpmrepoFclose(repo, fd);
970  fn = _free(fn);
971  return rc;
972 }
973 
980 static int rpmrepoCloseMDFile(const rpmrepo repo, rpmrfile rfile)
981  /*@globals h_errno, rpmGlobalMacroContext, fileSystem, internalState @*/
982  /*@modifies rfile, rpmGlobalMacroContext, fileSystem, internalState @*/
983 {
984  static int asAscii = 1;
985  char * xmlfn = xstrdup(fdGetOPath(rfile->fd));
986  int rc = 0;
987 
988  if (!repo->quiet)
989  rpmrepoError(0, _("Saving %s metadata"), basename(xmlfn));
990 
991  if (rpmrfileXMLWrite(rfile, xstrdup(rfile->xml_fini)))
992  rc = 1;
993 
994  if (repo->algo > 0)
995  fdFiniDigest(rfile->fd, repo->algo, &rfile->digest, NULL, asAscii);
996  else
997  rfile->digest = xstrdup("");
998 
999  (void) rpmrepoFclose(repo, rfile->fd);
1000  rfile->fd = NULL;
1001 
1002  /* Compute the (usually compressed) ouput file digest too. */
1003  rfile->Zdigest = NULL;
1004  (void) rpmrepoRfileDigest(repo, rfile, &rfile->Zdigest);
1005 
1006 #if defined(WITH_SQLITE)
1007  if (REPO_ISSET(DATABASE) && rfile->sqldb != NULL) {
1008  const char *dbfn = rpmGetPath(repo->outputdir, "/", repo->tempdir, "/",
1009  rfile->type, ".sqlite", NULL);
1010  int xx;
1011  if ((xx = sqlite3_close(rfile->sqldb)) != SQLITE_OK)
1012  rpmrepoError(1, "sqlite3_close(%s): %s", dbfn, sqlite3_errmsg(rfile->sqldb));
1013  rfile->sqldb = NULL;
1014  dbfn = _free(dbfn);
1015  }
1016 #endif
1017 
1018  rfile->ctime = rpmioCtime(xmlfn);
1019  xmlfn = _free(xmlfn);
1020 
1021  return rc;
1022 }
1023 
1026 static /*@observer@*/ /*@null@*/ const char *
1027 algo2tagname(uint32_t algo)
1028  /*@*/
1029 {
1030  const char * tagname = NULL;
1031 
1032  switch (algo) {
1033  case PGPHASHALGO_NONE: tagname = "none"; break;
1034  case PGPHASHALGO_MD5: tagname = "md5"; break;
1035  /* XXX todo: should be "sha1" */
1036  case PGPHASHALGO_SHA1: tagname = "sha"; break;
1037  case PGPHASHALGO_RIPEMD160: tagname = "rmd160"; break;
1038  case PGPHASHALGO_MD2: tagname = "md2"; break;
1039  case PGPHASHALGO_TIGER192: tagname = "tiger192"; break;
1040  case PGPHASHALGO_HAVAL_5_160: tagname = "haval160"; break;
1041  case PGPHASHALGO_SHA256: tagname = "sha256"; break;
1042  case PGPHASHALGO_SHA384: tagname = "sha384"; break;
1043  case PGPHASHALGO_SHA512: tagname = "sha512"; break;
1044  case PGPHASHALGO_MD4: tagname = "md4"; break;
1045  case PGPHASHALGO_RIPEMD128: tagname = "rmd128"; break;
1046  case PGPHASHALGO_CRC32: tagname = "crc32"; break;
1047  case PGPHASHALGO_ADLER32: tagname = "adler32"; break;
1048  case PGPHASHALGO_CRC64: tagname = "crc64"; break;
1049  case PGPHASHALGO_JLU32: tagname = "jlu32"; break;
1050  case PGPHASHALGO_SHA224: tagname = "sha224"; break;
1051  case PGPHASHALGO_RIPEMD256: tagname = "rmd256"; break;
1052  case PGPHASHALGO_RIPEMD320: tagname = "rmd320"; break;
1053  case PGPHASHALGO_SALSA10: tagname = "salsa10"; break;
1054  case PGPHASHALGO_SALSA20: tagname = "salsa20"; break;
1055  default: tagname = NULL; break;
1056  }
1057  return tagname;
1058 }
1059 
1066 static const char * rpmrepoMDExpand(rpmrepo repo, rpmrfile rfile)
1067  /*@globals h_errno, rpmGlobalMacroContext, internalState @*/
1068  /*@modifies rpmGlobalMacroContext, internalState @*/
1069 {
1070  const char * spewalgo = algo2tagname(repo->algo);
1071  char spewtime[64];
1072 
1073  (void) snprintf(spewtime, sizeof(spewtime), "%u", (unsigned)rfile->ctime);
1074  return rpmExpand("\
1075  <data type=\"", rfile->type, "\">\n\
1076  <checksum type=\"", spewalgo, "\">", rfile->Zdigest, "</checksum>\n\
1077  <timestamp>", spewtime, "</timestamp>\n\
1078  <open-checksum type=\"",spewalgo,"\">", rfile->digest, "</open-checksum>\n\
1079  <location href=\"", repo->finaldir, "/", rfile->type, (repo->markup != NULL ? repo->markup : ""), (repo->suffix != NULL ? repo->suffix : ""), "\"/>\n\
1080  </data>\n", NULL);
1081 }
1082 
1084 {
1085  rpmrfile rfile = &repo->repomd;
1086  const char * fn = rpmrepoGetPath(repo, repo->tempdir, rfile->type, 0);
1087  int rc = 0;
1088 
1089  if ((rfile->fd = Fopen(fn, "w.ufdio")) != NULL) { /* no compression */
1090  if (rpmrfileXMLWrite(rfile, xstrdup(rfile->xml_init))
1091  || rpmrfileXMLWrite(rfile, rpmrepoMDExpand(repo, &repo->other))
1092  || rpmrfileXMLWrite(rfile, rpmrepoMDExpand(repo, &repo->filelists))
1093  || rpmrfileXMLWrite(rfile, rpmrepoMDExpand(repo, &repo->primary))
1094  || rpmrfileXMLWrite(rfile, xstrdup(rfile->xml_fini)))
1095  rc = 1;
1096  (void) rpmrepoFclose(repo, rfile->fd);
1097  rfile->fd = NULL;
1098  }
1099 
1100  fn = _free(fn);
1101  if (rc) return rc;
1102 
1103 #ifdef NOTYET
1104  def doRepoMetadata(self):
1105  """wrapper to generate the repomd.xml file that stores the info on the other files"""
1106  const char * repopath =
1107  rpmGetPath(repo->outputdir, "/", repo->tempdir, NULL);
1108  repodoc = libxml2.newDoc("1.0")
1109  reporoot = repodoc.newChild(None, "repomd", None)
1110  repons = reporoot.newNs("http://linux.duke.edu/metadata/repo", None)
1111  reporoot.setNs(repons)
1112  repopath = rpmGetPath(repo->outputdir, "/", repo->tempdir, NULL);
1113  fn = rpmrepoGetPath(repo, repo->tempdir, repo->repomd.type, 1);
1114 
1115  repoid = "garbageid";
1116 
1117  if (REPO_ISSET(DATABASE)) {
1118  if (!repo->quiet) rpmrepoError(0, _("Generating sqlite DBs"));
1119  try:
1120  dbversion = str(sqlitecachec.DBVERSION)
1121  except AttributeError:
1122  dbversion = "9"
1123  rp = sqlitecachec.RepodataParserSqlite(repopath, repoid, None)
1124  }
1125 
1126  { static const char * types[] =
1127  { "primary", "filelists", "other", NULL };
1128  const char ** typep;
1129  for (typep = types; *typep != NULL; typep++) {
1130  complete_path = rpmrepoGetPath(repo, repo->tempdir, *typep, 1);
1131 
1132  zfo = _gzipOpen(complete_path)
1133  uncsum = misc.checksum(algo2tagname(repo->algo), zfo)
1134  zfo.close()
1135  csum = misc.checksum(algo2tagname(repo->algo), complete_path)
1136  (void) rpmioExists(complete_path, st)
1137  timestamp = os.stat(complete_path)[8]
1138 
1139  db_csums = {}
1140  db_compressed_sums = {}
1141 
1142  if (REPO_ISSET(repo)) {
1143  if (repo->verbose) {
1144  time_t now = time(NULL);
1145  rpmrepoError(0, _("Starting %s db creation: %s"),
1146  *typep, ctime(&now));
1147  }
1148 
1149  if (!strcmp(*typep, "primary"))
1150  rp.getPrimary(complete_path, csum)
1151  else if (!strcmp(*typep, "filelists"));
1152  rp.getFilelists(complete_path, csum)
1153  else if (!strcmp(*typep, "other"))
1154  rp.getOtherdata(complete_path, csum)
1155 
1156  { const char * tmp_result_path =
1157  rpmGetPath(repo->outputdir, "/", repo->tempdir, "/",
1158  *typep, ".xml.gz.sqlite", NULL);
1159  const char * resultpath =
1160  rpmGetPath(repo->outputdir, "/", repo->tempdir, "/",
1161  *typep, ".sqlite", NULL);
1162 
1163  /* rename from silly name to not silly name */
1164  xx = Rename(tmp_result_path, resultpath);
1165  tmp_result_path = _free(tmp_result_path);
1166  result_compressed =
1167  rpmGetPath(repo->outputdir, "/", repo->tempdir, "/",
1168  *typep, ".sqlite.bz2", NULL);
1169  db_csums[*typep] = misc.checksum(algo2tagname(repo->algo), resultpath)
1170 
1171  /* compress the files */
1172  bzipFile(resultpath, result_compressed)
1173  /* csum the compressed file */
1174  db_compressed_sums[*typep] = misc.checksum(algo2tagname(repo->algo), result_compressed)
1175  /* remove the uncompressed file */
1176  xx = Unlink(resultpath);
1177  resultpath = _free(resultpath);
1178  }
1179 
1180  if (REPO_ISSET(UNIQUEMDFN)) {
1181  const char * csum_result_compressed =
1182  rpmGetPath(repo->outputdir, "/", repo->tempdir, "/",
1183  db_compressed_sums[*typep], "-", *typep, ".sqlite.bz2", NULL);
1184  xx = Rename(result_compressed, csum_result_compressed);
1185  result_compressed = _free(result_compressed);
1186  result_compressed = csum_result_compressed;
1187  }
1188 
1189  /* timestamp the compressed file */
1190  (void) rpmioExists(result_compressed, st)
1191  db_timestamp = os.stat(result_compressed)[8]
1192 
1193  /* add this data as a section to the repomdxml */
1194  db_data_type = rpmExpand(*typep, "_db", NULL);
1195  data = reporoot.newChild(None, 'data', None)
1196  data.newProp('type', db_data_type)
1197  location = data.newChild(None, 'location', None)
1198  if (repo->baseurl != NULL) {
1199  location.newProp('xml:base', repo->baseurl)
1200  }
1201 
1202  location.newProp('href', rpmGetPath(repo->finaldir, "/", *typep, ".sqlite.bz2", NULL));
1203  checksum = data.newChild(None, 'checksum', db_compressed_sums[*typep])
1204  checksum.newProp('type', algo2tagname(repo->algo))
1205  db_tstamp = data.newChild(None, 'timestamp', str(db_timestamp))
1206  unchecksum = data.newChild(None, 'open-checksum', db_csums[*typep])
1207  unchecksum.newProp('type', algo2tagname(repo->algo))
1208  database_version = data.newChild(None, 'database_version', dbversion)
1209  if (repo->verbose) {
1210  time_t now = time(NULL);
1211  rpmrepoError(0, _("Ending %s db creation: %s"),
1212  *typep, ctime(&now));
1213  }
1214  }
1215 
1216  data = reporoot.newChild(None, 'data', None)
1217  data.newProp('type', *typep)
1218 
1219  checksum = data.newChild(None, 'checksum', csum)
1220  checksum.newProp('type', algo2tagname(repo->algo))
1221  timestamp = data.newChild(None, 'timestamp', str(timestamp))
1222  unchecksum = data.newChild(None, 'open-checksum', uncsum)
1223  unchecksum.newProp('type', algo2tagname(repo->algo))
1224  location = data.newChild(None, 'location', None)
1225  if (repo->baseurl != NULL)
1226  location.newProp('xml:base', repo->baseurl)
1227  if (REPO_ISSET(UNIQUEMDFN)) {
1228  orig_file = rpmrepoGetPath(repo, repo->tempdir, *typep, strcmp(*typep, "repomd"));
1229  res_file = rpmExpand(csum, "-", *typep,
1230  (repo->markup ? repo->markup : ""),
1231  (repo->suffix && strcmp(*typep, "repomd") ? repo->suffix : ""), NULL);
1232  dest_file = rpmGetPath(repo->outputdir, "/", repo->tempdir, "/", res_file, NULL);
1233  xx = Rename(orig_file, dest_file);
1234 
1235  } else
1236  res_file = rpmExpand(*typep,
1237  (repo->markup ? repo->markup : ""),
1238  (repo->suffix && strcmp(*typep, "repomd") ? repo->suffix : ""), NULL);
1239 
1240  location.newProp('href', rpmGetPath(repo->finaldir, "/", res_file, NULL));
1241  }
1242  }
1243 
1244  if (!repo->quiet && REPO_ISSET(DATABASE))
1245  rpmrepoError(0, _("Sqlite DBs complete"));
1246 
1247  if (repo->groupfile != NULL) {
1248  self.addArbitraryMetadata(repo->groupfile, 'group_gz', reporoot)
1249  self.addArbitraryMetadata(repo->groupfile, 'group', reporoot, compress=False)
1250  }
1251 
1252  /* save it down */
1253  try:
1254  repodoc.saveFormatFileEnc(fn, 'UTF-8', 1)
1255  except:
1256  rpmrepoError(0, _("Error saving temp file for %s%s%s: %s"),
1257  rfile->type,
1258  (repo->markup ? repo->markup : ""),
1259  (repo->suffix && strcmp(*typep, "repomd") ? repo->suffix : ""),
1260  fn);
1261  rpmrepoError(1, _("Could not save temp file: %s"), fn);
1262 
1263  del repodoc
1264 #endif
1265 
1266  return rc;
1267 }
1268 
1270 {
1271  char * output_final_dir =
1272  rpmGetPath(repo->outputdir, "/", repo->finaldir, NULL);
1273  char * output_old_dir =
1274  rpmGetPath(repo->outputdir, "/", repo->olddir, NULL);
1275  struct stat sb, *st = &sb;
1276  int xx;
1277 
1278  if (rpmioExists(output_final_dir, st)) {
1279  if ((xx = Rename(output_final_dir, output_old_dir)) != 0)
1280  rpmrepoError(1, _("Error moving final %s to old dir %s"),
1281  output_final_dir, output_old_dir);
1282  }
1283 
1284  { const char * output_temp_dir =
1285  rpmGetPath(repo->outputdir, "/", repo->tempdir, NULL);
1286  if ((xx = Rename(output_temp_dir, output_final_dir)) != 0) {
1287  xx = Rename(output_old_dir, output_final_dir);
1288  rpmrepoError(1, _("Error moving final metadata into place"));
1289  }
1290  output_temp_dir = _free(output_temp_dir);
1291  }
1292 
1293  /* Merge old tree into new, unlink/rename as needed. */
1294  {
1295  char *const _av[] = { output_old_dir, NULL };
1296  int _ftsoptions = FTS_NOCHDIR | FTS_PHYSICAL | FTS_XDEV;
1297  int (*_compar)(const FTSENT **, const FTSENT **) = NULL;
1298  FTS * t = Fts_open(_av, _ftsoptions, _compar);
1299  FTSENT * p = NULL;
1300 
1301  if (t != NULL)
1302  while ((p = Fts_read(t)) != NULL) {
1303  const char * opath = p->fts_accpath;
1304  const char * ofn = p->fts_path;
1305  const char * obn = p->fts_name;
1306  const char * nfn = NULL;
1307  switch (p->fts_info) {
1308  default:
1309  break;
1310  case FTS_DP:
1311  /* Remove empty directories on post-traversal visit. */
1312  if ((xx = Rmdir(opath)) != 0)
1313  rpmrepoError(1, _("Could not remove old metadata directory: %s: %s"),
1314  ofn, strerror(errno));
1315  break;
1316  case FTS_F:
1317  /* Remove all non-toplevel files. */
1318  if (p->fts_level > 0) {
1319  if ((xx = Unlink(opath)) != 0)
1320  rpmrepoError(1, _("Could not remove old metadata file: %s: %s"),
1321  ofn, strerror(errno));
1322  break;
1323  }
1324 
1325  /* Remove/rename toplevel files, dependent on target existence. */
1326  nfn = rpmGetPath(output_final_dir, "/", obn, NULL);
1327  if (rpmioExists(nfn, st)) {
1328  if ((xx = Unlink(opath)) != 0)
1329  rpmrepoError(1, _("Could not remove old metadata file: %s: %s"),
1330  ofn, strerror(errno));
1331  } else {
1332  if ((xx = Rename(opath, nfn)) != 0)
1333  rpmrepoError(1, _("Could not restore old non-metadata file: %s -> %s: %s"),
1334  ofn, nfn, strerror(errno));
1335  }
1336  nfn = _free(nfn);
1337  break;
1338  case FTS_SL:
1339  case FTS_SLNONE:
1340  /* Remove all symlinks. */
1341  if ((xx = Unlink(opath)) != 0)
1342  rpmrepoError(1, _("Could not remove old metadata symlink: %s: %s"),
1343  ofn, strerror(errno));
1344  break;
1345  }
1346  }
1347  if (t != NULL)
1348  Fts_close(t);
1349  }
1350 
1351  output_old_dir = _free(output_old_dir);
1352  output_final_dir = _free(output_final_dir);
1353 
1354  return 0;
1355 }
1356 
1357 /*==============================================================*/
1358 
1365 static Header rpmrepoReadHeader(rpmrepo repo, const char * path)
1366  /*@globals rpmGlobalMacroContext, h_errno, fileSystem, internalState @*/
1367  /*@modifies repo, rpmGlobalMacroContext, fileSystem, internalState @*/
1368 {
1369  /* XXX todo: read the payload and collect the blessed file digest. */
1370  FD_t fd = Fopen(path, "r.ufdio");
1371  Header h = NULL;
1372 
1373  if (fd != NULL) {
1374  rpmts ts = repo->_ts;
1375  uint32_t algo = repo->pkgalgo;
1376  rpmRC rpmrc;
1377 
1378  if (algo != PGPHASHALGO_NONE)
1379  fdInitDigest(fd, algo, 0);
1380 
1381  /* XXX what if path needs expansion? */
1382  rpmrc = rpmReadPackageFile(ts, fd, path, &h);
1383  if (algo != PGPHASHALGO_NONE) {
1384  char buffer[32 * BUFSIZ];
1385  size_t nb = sizeof(buffer);
1386  size_t nr;
1387  while ((nr = Fread(buffer, sizeof(buffer[0]), nb, fd)) == nb)
1388  {};
1389  if (Ferror(fd)) {
1390  fprintf(stderr, _("%s: Fread(%s) failed: %s\n"),
1391  __progname, path, Fstrerror(fd));
1392  rpmrc = RPMRC_FAIL;
1393  } else {
1394  static int asAscii = 1;
1395  const char *digest = NULL;
1396  fdFiniDigest(fd, algo, &digest, NULL, asAscii);
1397  (void) headerSetDigest(h, digest);
1398  digest = _free(digest);
1399  }
1400  }
1401 
1402  (void) Fclose(fd);
1403 
1404  switch (rpmrc) {
1405  case RPMRC_NOTFOUND:
1406  case RPMRC_FAIL:
1407  default:
1408  (void) headerFree(h);
1409  h = NULL;
1410  break;
1411  case RPMRC_NOTTRUSTED:
1412  case RPMRC_NOKEY:
1413  case RPMRC_OK:
1414  if (repo->baseurl)
1415  (void) headerSetBaseURL(h, repo->baseurl);
1416  (void) headerSetInstance(h, (uint32_t)repo->current+1);
1417  break;
1418  }
1419  }
1420  return h;
1421 }
1422 
1429 static const char * rfileHeaderSprintf(Header h, const char * qfmt)
1430  /*@globals fileSystem @*/
1431  /*@modifies h, fileSystem @*/
1432 {
1433  const char * msg = NULL;
1434  const char * s = headerSprintf(h, qfmt, NULL, NULL, &msg);
1435  if (s == NULL)
1436  rpmrepoError(1, _("headerSprintf(%s): %s"), qfmt, msg);
1437 assert(s != NULL);
1438  return s;
1439 }
1440 
1441 #if defined(WITH_SQLITE)
1442 
1448 static const char * rfileHeaderSprintfHack(Header h, const char * qfmt)
1449  /*@globals fileSystem @*/
1450  /*@modifies h, fileSystem @*/
1451 {
1452  static const char mark[] = "'XXX'";
1453  static size_t nmark = sizeof("'XXX'") - 1;
1454  const char * msg = NULL;
1455  char * s = (char *) headerSprintf(h, qfmt, NULL, NULL, &msg);
1456  char * f, * fe;
1457  int nsubs = 0;
1458 
1459  if (s == NULL)
1460  rpmrepoError(1, _("headerSprintf(%s): %s"), qfmt, msg);
1461 assert(s != NULL);
1462 
1463  /* XXX Find & replace 'XXX' with '%{DBINSTANCE}' the hard way. */
1464 /*@-nullptrarith@*/
1465  for (f = s; *f != '\0' && (fe = strstr(f, "'XXX'")) != NULL; fe += nmark, f = fe)
1466  nsubs++;
1467 /*@=nullptrarith@*/
1468 
1469  if (nsubs > 0) {
1470  char instance[64];
1471  int xx = snprintf(instance, sizeof(instance), "'%u'",
1472  (uint32_t) headerGetInstance(h));
1473  size_t tlen = strlen(s) + nsubs * ((int)strlen(instance) - (int)nmark);
1474  char * t = xmalloc(tlen + 1);
1475  char * te = t;
1476 
1477  xx = xx;
1478 /*@-nullptrarith@*/
1479  for (f = s; *f != '\0' && (fe = strstr(f, mark)) != NULL; fe += nmark, f = fe) {
1480  *fe = '\0';
1481  te = stpcpy( stpcpy(te, f), instance);
1482  }
1483 /*@=nullptrarith@*/
1484  if (*f != '\0')
1485  te = stpcpy(te, f);
1486  s = _free(s);
1487  s = t;
1488  }
1489 
1490  return s;
1491 }
1492 #endif
1493 
1501 static int rpmrepoWriteMDFile(rpmrepo repo, rpmrfile rfile, Header h)
1502  /*@globals fileSystem @*/
1503  /*@modifies rfile, h, fileSystem @*/
1504 {
1505  int rc = 0;
1506 
1507  if (rfile->xml_qfmt != NULL) {
1508  if (rpmrfileXMLWrite(rfile, rfileHeaderSprintf(h, rfile->xml_qfmt)))
1509  rc = 1;
1510  }
1511 
1512 #if defined(WITH_SQLITE)
1513  if (REPO_ISSET(DATABASE)) {
1514  if (rpmrfileSQLWrite(rfile, rfileHeaderSprintfHack(h, rfile->sql_qfmt)))
1515  rc = 1;
1516  }
1517 #endif
1518 
1519  return rc;
1520 }
1521 
1528  /*@globals h_errno, rpmGlobalMacroContext, fileSystem, internalState @*/
1529  /*@modifies repo, rpmGlobalMacroContext, fileSystem, internalState @*/
1530 {
1531  const char ** pkglist = repo->pkglist;
1532  const char * pkg;
1533  int rc = 0;
1534 
1535  if (pkglist)
1536  while ((pkg = *pkglist++) != NULL) {
1537  Header h = rpmrepoReadHeader(repo, pkg);
1538 
1539  repo->current++;
1540 
1541  /* XXX repoReadHeader() displays error. Continuing is foolish */
1542  if (h == NULL) {
1543  rc = 1;
1544  break;
1545  }
1546 
1547 #ifdef REFERENCE
1548  /* XXX todo: rpmGetPath(mydir, "/", filematrix[mydir], NULL); */
1549  reldir = (pkgpath != NULL ? pkgpath : rpmGetPath(repo->basedir, "/", repo->directories[0], NULL));
1550  self.primaryfile.write(po.do_primary_xml_dump(reldir, baseurl=repo->baseurl))
1551  self.flfile.write(po.do_filelists_xml_dump())
1552  self.otherfile.write(po.do_other_xml_dump())
1553 #endif
1554 
1555  if (rpmrepoWriteMDFile(repo, &repo->primary, h)
1556  || rpmrepoWriteMDFile(repo, &repo->filelists, h)
1557  || rpmrepoWriteMDFile(repo, &repo->other, h))
1558  rc = 1;
1559 
1560  (void) headerFree(h);
1561  h = NULL;
1562  if (rc) break;
1563 
1564  if (!repo->quiet) {
1565  if (repo->verbose)
1566  rpmrepoError(0, "%d/%d - %s", repo->current, repo->pkgcount, pkg);
1567  else
1568  rpmrepoProgress(repo, pkg, repo->current, repo->pkgcount);
1569  }
1570  }
1571  return rc;
1572 }
1573 
1575 {
1576  int rc = 0;
1577 
1578  repo->current = 0;
1579 
1580 #ifdef REFERENCE
1581  def _getFragmentUrl(self, url, fragment):
1582  import urlparse
1583  urlparse.uses_fragment.append('media')
1584  if not url:
1585  return url
1586  (scheme, netloc, path, query, fragid) = urlparse.urlsplit(url)
1587  return urlparse.urlunsplit((scheme, netloc, path, query, str(fragment)))
1588 
1589  def doPkgMetadata(self):
1590  """all the heavy lifting for the package metadata"""
1591  if (argvCount(repo->directories) == 1) {
1592  MetaDataGenerator.doPkgMetadata(self)
1593  return
1594  }
1595 
1596  ARGV_t roots = NULL;
1597  filematrix = {}
1598  for mydir in repo->directories {
1599  if (mydir[0] == '/')
1600  thisdir = xstrdup(mydir);
1601  else if (mydir[0] == '.' && mydir[1] == '.' && mydir[2] == '/')
1602  thisdir = Realpath(mydir, NULL);
1603  else
1604  thisdir = rpmGetPath(repo->basedir, "/", mydir, NULL);
1605 
1606  xx = argvAdd(&roots, thisdir);
1607  thisdir = _free(thisdir);
1608 
1609  filematrix[mydir] = rpmrepoGetFileList(repo, roots, '.rpm')
1610  self.trimRpms(filematrix[mydir])
1611  repo->pkgcount = argvCount(filematrix[mydir]);
1612  roots = argvFree(roots);
1613  }
1614 
1615  mediano = 1;
1616  repo->baseurl = self._getFragmentUrl(repo->baseurl, mediano)
1617 #endif
1618 
1619  if (rpmrepoOpenMDFile(repo, &repo->primary)
1620  || rpmrepoOpenMDFile(repo, &repo->filelists)
1621  || rpmrepoOpenMDFile(repo, &repo->other))
1622  rc = 1;
1623  if (rc) return rc;
1624 
1625 #ifdef REFERENCE
1626  for mydir in repo->directories {
1627  repo->baseurl = self._getFragmentUrl(repo->baseurl, mediano)
1628  /* XXX todo: rpmGetPath(mydir, "/", filematrix[mydir], NULL); */
1629  if (repoWriteMetadataDocs(repo, filematrix[mydir]))
1630  rc = 1;
1631  mediano++;
1632  }
1633  repo->baseurl = self._getFragmentUrl(repo->baseurl, 1)
1634 #endif
1635 
1636  if (repoWriteMetadataDocs(repo))
1637  rc = 1;
1638 
1639  if (!repo->quiet)
1640  fprintf(stderr, "\n");
1641  if (rpmrepoCloseMDFile(repo, &repo->primary)
1642  || rpmrepoCloseMDFile(repo, &repo->filelists)
1643  || rpmrepoCloseMDFile(repo, &repo->other))
1644  rc = 1;
1645 
1646  return rc;
1647 }
1648 
1649 /*==============================================================*/
1650 
1651 /*@unchecked@*/
1652 static int compression = -1;
1653 
1654 /*@unchecked@*/ /*@observer@*/
1655 static struct poptOption repoCompressionPoptTable[] = {
1656  { "uncompressed", '\0', POPT_ARG_VAL, &compression, 0,
1657  N_("don't compress"), NULL },
1658  { "gzip", 'Z', POPT_ARG_VAL, &compression, 1,
1659  N_("use gzip compression"), NULL },
1660  { "bzip2", '\0', POPT_ARG_VAL, &compression, 2,
1661  N_("use bzip2 compression"), NULL },
1662  { "lzma", '\0', POPT_ARG_VAL, &compression, 3,
1663  N_("use lzma compression"), NULL },
1664  { "xz", '\0', POPT_ARG_VAL, &compression, 4,
1665  N_("use xz compression"), NULL },
1666  POPT_TABLEEND
1667 };
1668 
1669 /*@unchecked@*/ /*@observer@*/
1670 static struct poptOption _rpmrepoOptions[] = {
1671 
1672  { "quiet", 'q', POPT_ARG_VAL, &__repo.quiet, 0,
1673  N_("output nothing except for serious errors"), NULL },
1674  { "verbose", 'v', 0, NULL, (int)'v',
1675  N_("output more debugging info."), NULL },
1676  { "dryrun", '\0', POPT_BIT_SET, &__repo.flags, REPO_FLAGS_DRYRUN,
1677  N_("sanity check arguments, don't create metadata"), NULL },
1678  { "excludes", 'x', POPT_ARG_ARGV, &__repo.exclude_patterns, 0,
1679  N_("glob PATTERN(s) to exclude"), N_("PATTERN") },
1680  { "includes", 'i', POPT_ARG_ARGV, &__repo.include_patterns, 0,
1681  N_("glob PATTERN(s) to include"), N_("PATTERN") },
1682  { "basedir", '\0', POPT_ARG_STRING|POPT_ARGFLAG_DOC_HIDDEN, &__repo.basedir, 0,
1683  N_("top level directory"), N_("DIR") },
1684  { "baseurl", 'u', POPT_ARG_STRING|POPT_ARGFLAG_DOC_HIDDEN, &__repo.baseurl, 0,
1685  N_("baseurl to append on all files"), N_("BASEURL") },
1686 #ifdef NOTYET
1687  { "groupfile", 'g', POPT_ARG_STRING|POPT_ARGFLAG_DOC_HIDDEN, &__repo.groupfile, 0,
1688  N_("path to groupfile to include in metadata"), N_("FILE") },
1689 #endif
1690  { "pretty", 'p', POPT_BIT_SET|POPT_ARGFLAG_DOC_HIDDEN, &__repo.flags, REPO_FLAGS_PRETTY,
1691  N_("make sure all xml generated is formatted"), NULL },
1692  { "checkts", 'C', POPT_BIT_SET|POPT_ARGFLAG_DOC_HIDDEN, &__repo.flags, REPO_FLAGS_CHECKTS,
1693  N_("check timestamps on files vs the metadata to see if we need to update"), NULL },
1694  { "database", 'd', POPT_BIT_SET, &__repo.flags, REPO_FLAGS_DATABASE,
1695  N_("create sqlite3 database files"), NULL },
1696  { "split", '\0', POPT_BIT_SET|POPT_ARGFLAG_DOC_HIDDEN, &__repo.flags, REPO_FLAGS_SPLIT,
1697  N_("generate split media"), NULL },
1698  { "pkglist", 'l', POPT_ARG_ARGV|POPT_ARGFLAG_DOC_HIDDEN, &__repo.manifests, 0,
1699  N_("use only the files listed in this file from the directory specified"), N_("FILE") },
1700  { "outputdir", 'o', POPT_ARG_STRING, &__repo.outputdir, 0,
1701  N_("<dir> = optional directory to output to"), N_("DIR") },
1702  { "skip-symlinks", 'S', POPT_BIT_SET, &__repo.flags, REPO_FLAGS_NOFOLLOW,
1703  N_("ignore symlinks of packages"), NULL },
1704  { "unique-md-filenames", '\0', POPT_BIT_SET|POPT_ARGFLAG_DOC_HIDDEN, &__repo.flags, REPO_FLAGS_UNIQUEMDFN,
1705  N_("include the file's checksum in the filename, helps with proxies"), NULL },
1706 
1707  POPT_TABLEEND
1708 
1709 };
1710 
1711 /*@unchecked@*/ /*@observer@*/
1712 static struct poptOption rpmrepoOptionsTable[] = {
1713 
1714  { NULL, '\0', POPT_ARG_INCLUDE_TABLE, _rpmrepoOptions, 0,
1715  N_("Repository options:"), NULL },
1716 
1717  { NULL, '\0', POPT_ARG_INCLUDE_TABLE, rpmioFtsPoptTable, 0,
1718  N_("Fts(3) traversal options:"), NULL },
1719 
1720  { NULL, '\0', POPT_ARG_INCLUDE_TABLE, repoCompressionPoptTable, 0,
1721  N_("Available compressions:"), NULL },
1722 
1723  { NULL, '\0', POPT_ARG_INCLUDE_TABLE, rpmioDigestPoptTable, 0,
1724  N_("Available digests:"), NULL },
1725 
1726  { NULL, '\0', POPT_ARG_INCLUDE_TABLE, rpmioAllPoptTable, 0,
1727  N_("Common options for all rpmio executables:"),
1728  NULL },
1729 
1730  POPT_AUTOALIAS
1731  POPT_AUTOHELP
1732  POPT_TABLEEND
1733 };
1734 
1735 static int rpmrepoInitPopt(rpmrepo repo, char ** av)
1736  /*@modifies repo @*/
1737 {
1738  void *use = repo->_item.use;
1739  void *pool = repo->_item.pool;
1740  int ac = argvCount((ARGV_t)av);
1741  poptContext con = rpmioInit(ac, av, rpmrepoOptionsTable);
1742  int rc = 0; /* XXX assume success */
1743  int xx;
1744  int i;
1745 
1746  *repo = *_repo; /* structure assignment */
1747  repo->_item.use = use;
1748  repo->_item.pool = pool;
1749 
1750  repo->con = con;
1751 
1752  /* XXX Impedanace match against poptIO common code. */
1753  if (rpmIsVerbose())
1754  repo->verbose++;
1755  if (rpmIsDebug())
1756  repo->verbose++;
1757 
1758  repo->ftsoptions = (rpmioFtsOpts ? rpmioFtsOpts : FTS_PHYSICAL);
1759  switch (repo->ftsoptions & (FTS_LOGICAL|FTS_PHYSICAL)) {
1760  case (FTS_LOGICAL|FTS_PHYSICAL):
1761  rpmrepoError(1, "FTS_LOGICAL and FTS_PYSICAL are mutually exclusive");
1762  /*@notreached@*/ break;
1763  case 0:
1764  repo->ftsoptions |= FTS_PHYSICAL;
1765  break;
1766  }
1767 
1768  repo->algo = (rpmioDigestHashAlgo >= 0
1769  ? (rpmioDigestHashAlgo & 0xff) : PGPHASHALGO_SHA1);
1770 
1771  repo->compression = (compression >= 0 ? compression : 1);
1772  switch (repo->compression) {
1773  case 0:
1774  repo->suffix = NULL;
1775  repo->wmode = "w.ufdio";
1776  break;
1777  default:
1778  /*@fallthrough@*/
1779  case 1:
1780  repo->suffix = ".gz";
1781  repo->wmode = "w9.gzdio";
1782  break;
1783  case 2:
1784  repo->suffix = ".bz2";
1785  repo->wmode = "w9.bzdio";
1786  break;
1787  case 3:
1788  repo->suffix = ".lzma";
1789  repo->wmode = "w.lzdio";
1790  break;
1791  case 4:
1792  repo->suffix = ".xz";
1793  repo->wmode = "w.xzdio";
1794  break;
1795  }
1796 
1797  repo->av = poptGetArgs(repo->con);
1798 
1799  if (repo->av == NULL || repo->av[0] == NULL)
1800  rpmrepoError(1, _("Must specify path(s) to index."));
1801 
1802  if (repo->av != NULL)
1803  for (i = 0; repo->av[i] != NULL; i++) {
1804  char fullpath[MAXPATHLEN];
1805  struct stat sb;
1806  const char * rpath;
1807  const char * lpath = NULL;
1808  int ut = urlPath(repo->av[i], &lpath);
1809  size_t nb = (size_t)(lpath - repo->av[i]);
1810  int isdir = (lpath[strlen(lpath)-1] == '/');
1811 
1812  /* Convert to absolute/clean/malloc'd path. */
1813  if (lpath[0] != '/') {
1814  if ((rpath = rpmrepoRealpath(lpath)) == NULL)
1815  rpmrepoError(1, _("Realpath(%s): %s"), lpath, strerror(errno));
1816  lpath = rpmGetPath(rpath, NULL);
1817  rpath = _free(rpath);
1818  } else
1819  lpath = rpmGetPath(lpath, NULL);
1820 
1821  /* Reattach the URI to the absolute/clean path. */
1822  /* XXX todo: rpmGenPath was confused by file:///path/file URI's. */
1823  switch (ut) {
1824  case URL_IS_DASH:
1825  case URL_IS_UNKNOWN:
1826  rpath = lpath;
1827  lpath = NULL;
1828  /*@switchbreak@*/ break;
1829  default:
1830 assert(nb < sizeof(fullpath));
1831  strncpy(fullpath, repo->av[i], nb);
1832  fullpath[nb] = '\0';
1833  rpath = rpmGenPath(fullpath, lpath, NULL);
1834  lpath = _free(lpath);
1835  /*@switchbreak@*/ break;
1836  }
1837 
1838  /* Add a trailing '/' on directories. */
1839  lpath = (isdir || (!Stat(rpath, &sb) && S_ISDIR(sb.st_mode))
1840  ? "/" : NULL);
1841  if (lpath != NULL) {
1842  lpath = rpmExpand(rpath, lpath, NULL);
1843  xx = argvAdd(&repo->directories, lpath);
1844  lpath = _free(lpath);
1845  } else {
1846  xx = argvAdd(&repo->pkglist, rpath);
1847  }
1848  rpath = _free(rpath);
1849  }
1850 
1851  return rc;
1852 }
1853 
1854 static void rpmrepoFini(void * _repo)
1855  /*@globals fileSystem @*/
1856  /*@modifies *_repo, fileSystem @*/
1857 {
1858  rpmrepo repo = _repo;
1859 
1860  repo->primary.digest = _free(repo->primary.digest);
1861  repo->primary.Zdigest = _free(repo->primary.Zdigest);
1862  repo->filelists.digest = _free(repo->filelists.digest);
1863  repo->filelists.Zdigest = _free(repo->filelists.Zdigest);
1864  repo->other.digest = _free(repo->other.digest);
1865  repo->other.Zdigest = _free(repo->other.Zdigest);
1866  repo->repomd.digest = _free(repo->repomd.digest);
1867  repo->repomd.Zdigest = _free(repo->repomd.Zdigest);
1868  repo->outputdir = _free(repo->outputdir);
1869  repo->pkglist = argvFree(repo->pkglist);
1870  repo->directories = argvFree(repo->directories);
1871  repo->manifests = argvFree(repo->manifests);
1872 /*@-onlytrans -refcounttrans @*/
1873  repo->excludeMire = mireFreeAll(repo->excludeMire, repo->nexcludes);
1874  repo->includeMire = mireFreeAll(repo->includeMire, repo->nincludes);
1875 /*@=onlytrans =refcounttrans @*/
1876  repo->exclude_patterns = argvFree(repo->exclude_patterns);
1877  repo->include_patterns = argvFree(repo->include_patterns);
1878 
1879  repo->con = poptFreeContext(repo->con);
1880 
1881 }
1882 
1883 /*@unchecked@*/ /*@only@*/ /*@null@*/
1885 
1887  /*@globals _rpmrepoPool, fileSystem @*/
1888  /*@modifies pool, _rpmrepoPool, fileSystem @*/
1889 {
1890  rpmrepo repo;
1891 
1892  if (_rpmrepoPool == NULL) {
1893  _rpmrepoPool = rpmioNewPool("repo", sizeof(*repo), -1, _rpmrepo_debug,
1894  NULL, NULL, rpmrepoFini);
1895  pool = _rpmrepoPool;
1896  }
1897  repo = (rpmrepo) rpmioGetPool(pool, sizeof(*repo));
1898  memset(((char *)repo)+sizeof(repo->_item), 0, sizeof(*repo)-sizeof(repo->_item));
1899  return repo;
1900 }
1901 
1902 rpmrepo rpmrepoNew(char ** av, int flags)
1903 {
1904  rpmrepo repo = rpmrepoGetPool(_rpmrepoPool);
1905  int xx;
1906 
1907  xx = rpmrepoInitPopt(repo, av);
1908 
1909  return rpmrepoLink(repo);
1910 }
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)
Initialize most everything needed by an rpmio executable context.
Definition: poptIO.c:767
int rpmrepoDoFinalMove(rpmrepo repo)
Rename temporary repository to final paths.
Definition: rpmrepo.c:1269
struct poptOption rpmioDigestPoptTable[]
Digest options using popt.
Definition: poptIO.c:152
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:551
static struct rpmrepo_s __repo
Definition: rpmrepo.c:298
static const char Packages_qfmt[]
Definition: rpmrepo.c:132
const char bson_timestamp_t * ts
Definition: bson.h:1004
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
const char const char * cmd
Definition: mongo.h:777
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:321
FD_t Fopen(const char *path, const char *_fmode)
fopen(3) clone.
Definition: rpmio.c:2840
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:615
DIGEST_CTX rpmDigestInit(pgpHashAlgo hashalgo, rpmDigestFlags flags)
Initialize digest context.
Definition: digest.c:247
char * rpmGetPath(const char *path,...)
Return (malloc'ed) expanded, canonicalized, file path.
Definition: macro.c:3443
static const char * fdGetOPath(FD_t fd)
static rpmrepo _repo
Definition: rpmrepo.c:391
#define __progname
Definition: system.h:363
int Access(const char *path, int amode)
access(2) clone.
Definition: rpmrpc.c:2196
static const char * filelists_sql_init[]
Definition: rpmrepo.c:176
const char int time
Definition: bson.h:1005
static const char * rpmrepoMDExpand(rpmrepo repo, rpmrfile rfile)
Return a repository metadata file item.
Definition: rpmrepo.c:1066
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:3024
struct poptOption rpmioFtsPoptTable[]
Popt option table for options to set Fts(3) options.
Definition: poptIO.c:542
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:623
int errno
u_short fts_namelen
Definition: fts.h:119
static int rpmrepoMkdir(rpmrepo repo, const char *dn)
Create directory path.
Definition: rpmrepo.c:495
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:516
const char * buffer
Definition: bson.h:289
pgpHashAlgo rpmioDigestHashAlgo
Definition: poptIO.c:147
static struct poptOption repoCompressionPoptTable[]
Definition: rpmrepo.c:1655
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:6730
static int rpmrepoRfileDigest(const rpmrepo repo, rpmrfile rfile, const char **digestp)
Compute digest of a file.
Definition: rpmrepo.c:906
static rpmop fdstat_op(FD_t fd, fdOpX opx)
static const char * rfileHeaderSprintf(Header h, const char *qfmt)
Return header query.
Definition: rpmrepo.c:1429
static int rpmioExists(const char *fn, struct stat *st)
Return stat(2) for a file.
Definition: rpmrepo.c:400
const char * str
Definition: bson.h:593
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:1083
static const char * algo2tagname(uint32_t algo)
Definition: rpmrepo.c:1027
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:986
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:1574
rpmioItem rpmioGetPool(rpmioPool pool, size_t size)
Get unused item from pool, or alloc a new item.
Definition: rpmmalloc.c:220
#define N_(Text)
Definition: system.h:531
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
const char const bson * data
Definition: mongo.h:463
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:1712
rpmRC rpmReadPackageFile(rpmts ts, FD_t fd, const char *fn, Header *hdrp)
Return package header from file handle, verifying digests/signatures.
Definition: package.c:114
Digest private data.
Definition: digest.c:130
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:3489
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:539
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
const char const bson const bson * op
Definition: mongo.h:505
char * rpmExpand(const char *arg,...)
Return (malloc'ed) concatenated macro expansion(s).
Definition: macro.c:3250
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:39
const char const bson int mongo_write_concern int flags
Definition: mongo.h:485
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:1365
int Ferror(FD_t fd)
ferror(3) clone.
Definition: rpmio.c:2951
static int rpmrfileXMLWrite(rpmrfile rfile, const char *spew)
Write to a repository metadata file.
Definition: rpmrepo.c:710
const char const int i
Definition: bson.h:778
const char const bson * query
Definition: mongo.h:569
urltype urlPath(const char *url, const char **pathp)
Return path component of URL.
Definition: url.c:430
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:682
static int rpmrepoFclose(rpmrepo repo, FD_t fd)
Close an I/O stream, accumulating uncompress/digest statistics.
Definition: rpmrepo.c:734
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:109
rpmrepo rpmrepoNew(char **av, int flags)
Create and load a repo wrapper.
Definition: rpmrepo.c:1902
static int compression
Definition: rpmrepo.c:1652
char * stpcpy(char *dest, const char *src)
static int rpmrepoOpenMDFile(const rpmrepo repo, rpmrfile rfile)
Open a repository metadata file.
Definition: rpmrepo.c:760
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:756
Structures and prototypes used for an "rpmts" transaction set.
static const char filelists_yaml_qfmt[]
Definition: rpmrepo.c:122
const bson * in
Definition: bson.h:746
const char * db
Definition: mongo.h:697
static const char * rpmrepoGetPath(rpmrepo repo, const char *dir, const char *type, int compress)
Return /repository/directory/component.markup.compression path.
Definition: rpmrepo.c:449
#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
const char char type
Definition: bson.h:908
struct rpmrepo_s * rpmrepo
Definition: rpmrepo.h:16
int Fileno(FD_t fd)
fileno(3) clone.
Definition: rpmio.c:2998
static rpmrepo rpmrepoGetPool(rpmioPool pool)
Definition: rpmrepo.c:1886
int rpmDigestFinal(DIGEST_CTX ctx, void *datap, size_t *lenp, int asAscii)
Return digest and destroy context.
Definition: digest.c:1000
static void rpmrepoProgress(rpmrepo repo, const char *item, int current, int total)
Display progress.
Definition: rpmrepo.c:466
#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:1527
#define _(Text)
Definition: system.h:29
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:980
#define xmalloc
Definition: system.h:32
static const char Sources_qfmt[]
Definition: rpmrepo.c:137
#define FTS_DP
Definition: fts.h:134
static void rpmrepoFini(void *_repo)
Definition: rpmrepo.c:1854
ARGstr_t * ARGV_t
Definition: argv.h:12
const char * baseurl
struct poptOption rpmioAllPoptTable[]
Popt option table for options shared by all modes and executables.
Definition: poptIO.c:564
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:1735
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:531
static const char filelists_xml_fini[]
Definition: rpmrepo.c:84
rpmioPool _rpmrepoPool
Definition: rpmrepo.c:1884
static int rpmrepoWriteMDFile(rpmrepo repo, rpmrfile rfile, Header h)
Export a single package's metadata to repository metadata file(s).
Definition: rpmrepo.c:1501
static struct poptOption _rpmrepoOptions[]
Definition: rpmrepo.c:1670
int _rpmrepo_debug
Definition: rpmrepo.c:66
#define W_OK
Definition: system.h:233
unsigned long int rpmtime_t
Definition: rpmsw.h:16
int Unlink(const char *path)
unlink(2) clone.
Definition: rpmrpc.c:397