rpm 5.3.12
|
00001 00005 #include "system.h" 00006 00007 #if defined(WITH_DBSQL) 00008 #include <db51/dbsql.h> 00009 #elif defined(WITH_SQLITE) 00010 #include <sqlite3.h> 00011 #ifdef __LCLINT__ 00012 /*@-incondefs -redecl @*/ 00013 extern const char *sqlite3_errmsg(sqlite3 *db) 00014 /*@*/; 00015 extern int sqlite3_open( 00016 const char *filename, /* Database filename (UTF-8) */ 00017 /*@out@*/ sqlite3 **ppDb /* OUT: SQLite db handle */ 00018 ) 00019 /*@modifies *ppDb @*/; 00020 extern int sqlite3_exec( 00021 sqlite3 *db, /* An open database */ 00022 const char *sql, /* SQL to be evaluted */ 00023 int (*callback)(void*,int,char**,char**), /* Callback function */ 00024 void *, /* 1st argument to callback */ 00025 /*@out@*/ char **errmsg /* Error msg written here */ 00026 ) 00027 /*@modifies db, *errmsg @*/; 00028 extern int sqlite3_prepare( 00029 sqlite3 *db, /* Database handle */ 00030 const char *zSql, /* SQL statement, UTF-8 encoded */ 00031 int nByte, /* Maximum length of zSql in bytes. */ 00032 /*@out@*/ sqlite3_stmt **ppStmt, /* OUT: Statement handle */ 00033 /*@out@*/ const char **pzTail /* OUT: Pointer to unused portion of zSql */ 00034 ) 00035 /*@modifies *ppStmt, *pzTail @*/; 00036 extern int sqlite3_reset(sqlite3_stmt *pStmt) 00037 /*@modifies pStmt @*/; 00038 extern int sqlite3_step(sqlite3_stmt *pStmt) 00039 /*@modifies pStmt @*/; 00040 extern int sqlite3_finalize(/*@only@*/ sqlite3_stmt *pStmt) 00041 /*@modifies pStmt @*/; 00042 extern int sqlite3_close(sqlite3 * db) 00043 /*@modifies db @*/; 00044 /*@=incondefs =redecl @*/ 00045 #endif /* __LCLINT__ */ 00046 #endif /* WITH_SQLITE */ 00047 00048 #include <rpmio_internal.h> /* XXX fdInitDigest() et al */ 00049 #include <rpmiotypes.h> 00050 #include <rpmio.h> /* for *Pool methods */ 00051 #include <rpmlog.h> 00052 #include <rpmurl.h> 00053 #include <poptIO.h> 00054 00055 #define _RPMREPO_INTERNAL 00056 #include <rpmrepo.h> 00057 00058 #include <rpmtypes.h> 00059 #include <rpmtag.h> 00060 #include <pkgio.h> 00061 #include <rpmts.h> 00062 00063 #include "debug.h" 00064 00065 /*@unchecked@*/ 00066 int _rpmrepo_debug = 0; 00067 00068 #define REPODBG(_l) if (_rpmrepo_debug) fprintf _l 00069 00070 /*==============================================================*/ 00071 00072 /*@unchecked@*/ /*@observer@*/ 00073 static const char primary_xml_init[] = 00074 "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n" 00075 "<metadata xmlns=\"http://linux.duke.edu/metadata/common\" xmlns:rpm=\"http://linux.duke.edu/metadata/rpm\" packages=\"0\">\n"; 00076 /*@unchecked@*/ /*@observer@*/ 00077 static const char primary_xml_fini[] = "</metadata>\n"; 00078 00079 /*@unchecked@*/ /*@observer@*/ 00080 static const char filelists_xml_init[] = 00081 "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n" 00082 "<filelists xmlns=\"http://linux.duke.edu/metadata/filelists\" packages=\"0\">\n"; 00083 /*@unchecked@*/ /*@observer@*/ 00084 static const char filelists_xml_fini[] = "</filelists>\n"; 00085 00086 /*@unchecked@*/ /*@observer@*/ 00087 static const char other_xml_init[] = 00088 "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n" 00089 "<otherdata xmlns=\"http://linux.duke.edu/metadata/other\" packages=\"0\">\n"; 00090 /*@unchecked@*/ /*@observer@*/ 00091 static const char other_xml_fini[] = "</otherdata>\n"; 00092 00093 /*@unchecked@*/ /*@observer@*/ 00094 static const char repomd_xml_init[] = "\ 00095 <?xml version=\"1.0\" encoding=\"UTF-8\"?>\n\ 00096 <repomd xmlns=\"http://linux.duke.edu/metadata/repo\">\n"; 00097 /*@unchecked@*/ /*@observer@*/ 00098 static const char repomd_xml_fini[] = "</repomd>\n"; 00099 00100 /* XXX todo: wire up popt aliases and bury the --queryformat glop externally. */ 00101 /*@unchecked@*/ /*@observer@*/ 00102 static const char primary_xml_qfmt[] = 00103 #include "yum_primary_xml" 00104 ; 00105 00106 /*@unchecked@*/ /*@observer@*/ 00107 static const char filelists_xml_qfmt[] = 00108 #include "yum_filelists_xml" 00109 ; 00110 00111 /*@unchecked@*/ /*@observer@*/ 00112 static const char other_xml_qfmt[] = 00113 #include "yum_other_xml" 00114 ; 00115 00116 /*@unchecked@*/ /*@observer@*/ 00117 static const char primary_yaml_qfmt[] = 00118 #include "wnh_primary_yaml" 00119 ; 00120 00121 /*@unchecked@*/ /*@observer@*/ 00122 static const char filelists_yaml_qfmt[] = 00123 #include "wnh_filelists_yaml" 00124 ; 00125 00126 /*@unchecked@*/ /*@observer@*/ 00127 static const char other_yaml_qfmt[] = 00128 #include "wnh_other_yaml" 00129 ; 00130 00131 /*@unchecked@*/ /*@observer@*/ 00132 static const char Packages_qfmt[] = 00133 #include "deb_Packages" 00134 ; 00135 00136 /*@unchecked@*/ /*@observer@*/ 00137 static const char Sources_qfmt[] = 00138 #include "deb_Sources" 00139 ; 00140 00141 /*@-nullassign@*/ 00142 /*@unchecked@*/ /*@observer@*/ 00143 static const char *primary_sql_init[] = { 00144 "PRAGMA synchronous = \"OFF\";", 00145 "pragma locking_mode = \"EXCLUSIVE\";", 00146 "CREATE TABLE conflicts ( pkgKey INTEGER, name TEXT, flags TEXT, epoch TEXT, version TEXT, release TEXT );", 00147 "CREATE TABLE db_info (dbversion INTEGER, checksum TEXT);", 00148 "CREATE TABLE files ( pkgKey INTEGER, name TEXT, type TEXT );", 00149 "CREATE TABLE obsoletes ( pkgKey INTEGER, name TEXT, flags TEXT, epoch TEXT, version TEXT, release TEXT );", 00150 "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);", 00151 "CREATE TABLE provides ( pkgKey INTEGER, name TEXT, flags TEXT, epoch TEXT, version TEXT, release TEXT );", 00152 "CREATE TABLE requires ( pkgKey INTEGER, name TEXT, flags TEXT, epoch TEXT, version TEXT, release TEXT );", 00153 "CREATE INDEX filenames ON files (name);", 00154 "CREATE INDEX packageId ON packages (pkgId);", 00155 "CREATE INDEX packagename ON packages (name);", 00156 "CREATE INDEX pkgconflicts on conflicts (pkgKey);", 00157 "CREATE INDEX pkgobsoletes on obsoletes (pkgKey);", 00158 "CREATE INDEX pkgprovides on provides (pkgKey);", 00159 "CREATE INDEX pkgrequires on requires (pkgKey);", 00160 "CREATE INDEX providesname ON provides (name);", 00161 "CREATE INDEX requiresname ON requires (name);", 00162 "CREATE TRIGGER removals AFTER DELETE ON packages\ 00163 \n BEGIN\n\ 00164 \n DELETE FROM files WHERE pkgKey = old.pkgKey;\ 00165 \n DELETE FROM requires WHERE pkgKey = old.pkgKey;\ 00166 \n DELETE FROM provides WHERE pkgKey = old.pkgKey;\ 00167 \n DELETE FROM conflicts WHERE pkgKey = old.pkgKey;\ 00168 \n DELETE FROM obsoletes WHERE pkgKey = old.pkgKey;\ 00169 \n END;", 00170 "INSERT into db_info values (9, 'direct_create');", 00171 NULL 00172 }; 00173 /*XXX todo: DBVERSION needs to be set */ 00174 00175 /*@unchecked@*/ /*@observer@*/ 00176 static const char *filelists_sql_init[] = { 00177 "PRAGMA synchronous = \"OFF\";", 00178 "pragma locking_mode = \"EXCLUSIVE\";", 00179 "CREATE TABLE db_info (dbversion INTEGER, checksum TEXT);", 00180 "CREATE TABLE filelist ( pkgKey INTEGER, name TEXT, type TEXT );", 00181 "CREATE TABLE packages ( pkgKey INTEGER PRIMARY KEY, pkgId TEXT);", 00182 "CREATE INDEX filelistnames ON filelist (name);", 00183 "CREATE INDEX keyfile ON filelist (pkgKey);", 00184 "CREATE INDEX pkgId ON packages (pkgId);", 00185 "CREATE TRIGGER remove_filelist AFTER DELETE ON packages\ 00186 \n BEGIN\ 00187 \n DELETE FROM filelist WHERE pkgKey = old.pkgKey;\ 00188 \n END;", 00189 "INSERT into db_info values (9, 'direct_create');", 00190 NULL 00191 }; 00192 /*XXX todo: DBVERSION needs to be set */ 00193 00194 /*@unchecked@*/ /*@observer@*/ 00195 static const char *other_sql_init[] = { 00196 "PRAGMA synchronous = \"OFF\";", 00197 "pragma locking_mode = \"EXCLUSIVE\";", 00198 "CREATE TABLE changelog ( pkgKey INTEGER, author TEXT, date INTEGER, changelog TEXT);", 00199 "CREATE TABLE db_info (dbversion INTEGER, checksum TEXT);", 00200 "CREATE TABLE packages ( pkgKey INTEGER PRIMARY KEY, pkgId TEXT);", 00201 "CREATE INDEX keychange ON changelog (pkgKey);", 00202 "CREATE INDEX pkgId ON packages (pkgId);", 00203 "CREATE TRIGGER remove_changelogs AFTER DELETE ON packages\ 00204 \n BEGIN\ 00205 \n DELETE FROM changelog WHERE pkgKey = old.pkgKey;\ 00206 \n END;", 00207 "INSERT into db_info values (9, 'direct_create');", 00208 NULL 00209 }; 00210 /*XXX todo: DBVERSION needs to be set */ 00211 /*@=nullassign@*/ 00212 00213 /* packages 1 pkgKey INTEGER PRIMARY KEY */ 00214 /* packages 2 pkgId TEXT */ 00215 /* packages 3 name TEXT */ 00216 /* packages 4 arch TEXT */ 00217 /* packages 5 version TEXT */ 00218 /* packages 6 epoch TEXT */ 00219 /* packages 7 release TEXT */ 00220 /* packages 8 summary TEXT */ 00221 /* packages 9 description TEXT */ 00222 /* packages 10 url TEXT */ 00223 /* packages 11 time_file INTEGER */ 00224 /* packages 12 time_build INTEGER */ 00225 /* packages 13 rpm_license TEXT */ 00226 /* packages 14 rpm_vendor TEXT */ 00227 /* packages 15 rpm_group TEXT */ 00228 /* packages 16 rpm_buildhost TEXT */ 00229 /* packages 17 rpm_sourcerpm TEXT */ 00230 /* packages 18 rpm_header_start INTEGER */ 00231 /* packages 19 rpm_header_end INTEGER */ 00232 /* packages 20 rpm_packager TEXT */ 00233 /* packages 21 size_package INTEGER */ 00234 /* packages 22 size_installed INTEGER */ 00235 /* packages 23 size_archive INTEGER */ 00236 /* packages 24 location_href TEXT */ 00237 /* packages 25 location_base TEXT */ 00238 /* packages 26 checksum_type TEXT */ 00239 /* obsoletes 1 pkgKey INTEGER */ 00240 /* obsoletes 2 name TEXT */ 00241 /* obsoletes 3 flags TEXT */ 00242 /* obsoletes 4 epoch TEXT */ 00243 /* obsoletes 5 version TEXT */ 00244 /* obsoletes 6 release TEXT */ 00245 /* provides 1 pkgKey INTEGER */ 00246 /* provides 2 name TEXT */ 00247 /* provides 3 flags TEXT */ 00248 /* provides 4 epoch TEXT */ 00249 /* provides 5 version TEXT */ 00250 /* provides 6 release TEXT */ 00251 /* conflicts 1 pkgKey INTEGER */ 00252 /* conflicts 2 name TEXT */ 00253 /* conflicts 3 flags TEXT */ 00254 /* conflicts 4 epoch TEXT */ 00255 /* conflicts 5 version TEXT */ 00256 /* conflicts 6 release TEXT */ 00257 /* requires 1 pkgKey INTEGER */ 00258 /* requires 2 name TEXT */ 00259 /* requires 3 flags TEXT */ 00260 /* requires 4 epoch TEXT */ 00261 /* requires 5 version TEXT */ 00262 /* requires 6 release TEXT */ 00263 /* files 1 pkgKey INTEGER */ 00264 /* files 2 name TEXT */ 00265 /* files 3 type TEXT */ 00266 00267 /*@unchecked@*/ /*@observer@*/ 00268 static const char primary_sql_qfmt[] = 00269 #include "yum_primary_sqlite" 00270 ; 00271 00272 /* packages 1 pkgKey INTEGER PRIMARY KEY */ 00273 /* packages 2 pkgId TEXT */ 00274 /* filelist 1 pkgKey INTEGER */ 00275 /* filelist 2 name TEXT */ 00276 /* filelist 3 type TEXT */ 00277 00278 /*@unchecked@*/ /*@observer@*/ 00279 static const char filelists_sql_qfmt[] = 00280 #include "yum_filelists_sqlite" 00281 ; 00282 00283 /* packages 1 pkgKey INTEGER PRIMARY KEY */ 00284 /* packages 2 pkgId TEXT */ 00285 /* changelog 1 pkgKey INTEGER */ 00286 /* changelog 2 author TEXT */ 00287 /* changelog 3 date INTEGER */ 00288 /* changelog 4 changelog TEXT */ 00289 00290 /*@unchecked@*/ /*@observer@*/ 00291 static const char other_sql_qfmt[] = 00292 #include "yum_other_sqlite" 00293 ; 00294 00295 /* XXX static when ready. */ 00296 /*@-fullinitblock@*/ 00297 /*@unchecked@*/ 00298 static struct rpmrepo_s __repo = { 00299 .flags = REPO_FLAGS_PRETTY, 00300 00301 .tempdir = ".repodata", 00302 .finaldir = "repodata", 00303 .olddir = ".olddata", 00304 .markup = ".xml", 00305 .pkgalgo = PGPHASHALGO_SHA1, 00306 .algo = PGPHASHALGO_SHA1, 00307 .primary = { 00308 .type = "primary", 00309 .xml_init= primary_xml_init, 00310 .xml_qfmt= primary_xml_qfmt, 00311 .xml_fini= primary_xml_fini, 00312 .sql_init= primary_sql_init, 00313 .sql_qfmt= primary_sql_qfmt, 00314 #ifdef NOTYET /* XXX char **?!? */ 00315 .sql_fini= NULL, 00316 #endif 00317 .yaml_init= NULL, 00318 .yaml_qfmt= primary_yaml_qfmt, 00319 .yaml_fini= NULL, 00320 .Packages_init= NULL, 00321 .Packages_qfmt= NULL, 00322 .Packages_fini= NULL, 00323 .Sources_init= NULL, 00324 .Sources_qfmt= NULL, 00325 .Sources_fini= NULL 00326 }, 00327 .filelists = { 00328 .type = "filelists", 00329 .xml_init= filelists_xml_init, 00330 .xml_qfmt= filelists_xml_qfmt, 00331 .xml_fini= filelists_xml_fini, 00332 .sql_init= filelists_sql_init, 00333 .sql_qfmt= filelists_sql_qfmt, 00334 #ifdef NOTYET /* XXX char **?!? */ 00335 .sql_fini= NULL, 00336 #endif 00337 .yaml_init= NULL, 00338 .yaml_qfmt= filelists_yaml_qfmt, 00339 .yaml_fini= NULL, 00340 .Packages_init= NULL, 00341 .Packages_qfmt= NULL, 00342 .Packages_fini= NULL, 00343 .Sources_init= NULL, 00344 .Sources_qfmt= NULL, 00345 .Sources_fini= NULL 00346 }, 00347 .other = { 00348 .type = "other", 00349 .xml_init= other_xml_init, 00350 .xml_qfmt= other_xml_qfmt, 00351 .xml_fini= other_xml_fini, 00352 .sql_init= other_sql_init, 00353 .sql_qfmt= other_sql_qfmt, 00354 #ifdef NOTYET /* XXX char **?!? */ 00355 .sql_fini= NULL, 00356 #endif 00357 .yaml_init= NULL, 00358 .yaml_qfmt= other_yaml_qfmt, 00359 .yaml_fini= NULL, 00360 .Packages_init= NULL, 00361 .Packages_qfmt= NULL, 00362 .Packages_fini= NULL, 00363 .Sources_init= NULL, 00364 .Sources_qfmt= NULL, 00365 .Sources_fini= NULL 00366 }, 00367 .repomd = { 00368 .type = "repomd", 00369 .xml_init= repomd_xml_init, 00370 .xml_qfmt= NULL, 00371 .xml_fini= repomd_xml_fini, 00372 .sql_init= NULL, 00373 .sql_qfmt= NULL, 00374 #ifdef NOTYET /* XXX char **?!? */ 00375 .sql_fini= NULL, 00376 #endif 00377 .yaml_init= NULL, 00378 .yaml_qfmt= NULL, 00379 .yaml_fini= NULL, 00380 .Packages_init= NULL, 00381 .Packages_qfmt= Packages_qfmt, 00382 .Packages_fini= NULL, 00383 .Sources_init= NULL, 00384 .Sources_qfmt= Sources_qfmt, 00385 .Sources_fini= NULL 00386 } 00387 }; 00388 /*@=fullinitblock@*/ 00389 00390 /*@unchecked@*/ 00391 static rpmrepo _repo = &__repo; 00392 00393 /*==============================================================*/ 00394 00400 static int rpmioExists(const char * fn, /*@out@*/ struct stat * st) 00401 /*@globals h_errno, fileSystem, internalState @*/ 00402 /*@modifies st, fileSystem, internalState @*/ 00403 { 00404 return (Stat(fn, st) == 0); 00405 } 00406 00412 static time_t rpmioCtime(const char * fn) 00413 /*@globals h_errno, fileSystem, internalState @*/ 00414 /*@modifies fileSystem, internalState @*/ 00415 { 00416 struct stat sb; 00417 time_t stctime = 0; 00418 00419 if (rpmioExists(fn, &sb)) 00420 stctime = sb.st_ctime; 00421 return stctime; 00422 } 00423 00424 /*==============================================================*/ 00425 00426 void 00427 rpmrepoError(int lvl, const char *fmt, ...) 00428 { 00429 va_list ap; 00430 00431 va_start(ap, fmt); 00432 (void) fflush(NULL); 00433 (void) fprintf(stderr, "%s: ", __progname); 00434 (void) vfprintf(stderr, fmt, ap); 00435 va_end (ap); 00436 (void) fprintf(stderr, "\n"); 00437 if (lvl) 00438 exit(EXIT_FAILURE); 00439 } 00440 00448 static const char * rpmrepoGetPath(rpmrepo repo, const char * dir, 00449 const char * type, int compress) 00450 /*@globals h_errno, rpmGlobalMacroContext, internalState @*/ 00451 /*@modifies rpmGlobalMacroContext, internalState @*/ 00452 { 00453 return rpmGetPath(repo->outputdir, "/", dir, "/", type, 00454 (repo->markup != NULL ? repo->markup : ""), 00455 (repo->suffix != NULL && compress ? repo->suffix : ""), NULL); 00456 } 00457 00465 static void rpmrepoProgress(/*@unused@*/ rpmrepo repo, 00466 /*@null@*/ const char * item, int current, int total) 00467 /*@globals fileSystem, internalState @*/ 00468 /*@modifies fileSystem, internalState @*/ 00469 { 00470 static size_t ncols = 80 - 1; /* XXX TIOCGWINSIZ */ 00471 const char * bn = (item != NULL ? strrchr(item, '/') : NULL); 00472 size_t nb; 00473 00474 if (bn != NULL) 00475 bn++; 00476 else 00477 bn = item; 00478 nb = fprintf(stdout, "\r%s: %d/%d", __progname, current, total); 00479 if (bn != NULL) 00480 nb += fprintf(stdout, " - %s", bn); 00481 nb--; 00482 if (nb < ncols) 00483 fprintf(stdout, "%*s", (int)(ncols - nb), ""); 00484 ncols = nb; 00485 (void) fflush(stdout); 00486 } 00487 00494 static int rpmrepoMkdir(rpmrepo repo, const char * dn) 00495 /*@globals rpmGlobalMacroContext, h_errno, fileSystem, internalState @*/ 00496 /*@modifies rpmGlobalMacroContext, fileSystem, internalState @*/ 00497 { 00498 const char * dnurl = rpmGetPath(repo->outputdir, "/", dn, NULL); 00499 /*@-mods@*/ 00500 int ut = urlPath(dnurl, &dn); 00501 /*@=mods@*/ 00502 int rc = 0;; 00503 00504 /* XXX todo: rpmioMkpath doesn't grok URI's */ 00505 if (ut == URL_IS_UNKNOWN) 00506 rc = rpmioMkpath(dn, 0755, (uid_t)-1, (gid_t)-1); 00507 else 00508 rc = (Mkdir(dnurl, 0755) == 0 || errno == EEXIST ? 0 : -1); 00509 if (rc) 00510 rpmrepoError(0, _("Cannot create/verify %s: %s"), dnurl, strerror(errno)); 00511 dnurl = _free(dnurl); 00512 return rc; 00513 } 00514 00515 const char * rpmrepoRealpath(const char * lpath) 00516 { 00517 /* XXX GLIBC: realpath(path, NULL) return malloc'd */ 00518 const char *rpath = Realpath(lpath, NULL); 00519 if (rpath == NULL) { 00520 char fullpath[MAXPATHLEN]; 00521 rpath = Realpath(lpath, fullpath); 00522 if (rpath != NULL) 00523 rpath = xstrdup(rpath); 00524 } 00525 return rpath; 00526 } 00527 00528 /*==============================================================*/ 00529 00530 int rpmrepoTestSetupDirs(rpmrepo repo) 00531 { 00532 const char ** directories = repo->directories; 00533 struct stat sb, *st = &sb; 00534 const char * dn; 00535 const char * fn; 00536 int rc = 0; 00537 00538 /* XXX todo: check repo->pkglist existence? */ 00539 00540 if (directories != NULL) 00541 while ((dn = *directories++) != NULL) { 00542 if (!rpmioExists(dn, st) || !S_ISDIR(st->st_mode)) { 00543 rpmrepoError(0, _("Directory %s must exist"), dn); 00544 rc = 1; 00545 } 00546 } 00547 00548 /* XXX todo create outputdir if it doesn't exist? */ 00549 if (!rpmioExists(repo->outputdir, st)) { 00550 rpmrepoError(0, _("Directory %s does not exist."), repo->outputdir); 00551 rc = 1; 00552 } 00553 if (Access(repo->outputdir, W_OK)) { 00554 rpmrepoError(0, _("Directory %s must be writable."), repo->outputdir); 00555 rc = 1; 00556 } 00557 00558 if (rpmrepoMkdir(repo, repo->tempdir) 00559 || rpmrepoMkdir(repo, repo->finaldir)) 00560 rc = 1; 00561 00562 dn = rpmGetPath(repo->outputdir, "/", repo->olddir, NULL); 00563 if (rpmioExists(dn, st)) { 00564 rpmrepoError(0, _("Old data directory exists, please remove: %s"), dn); 00565 rc = 1; 00566 } 00567 dn = _free(dn); 00568 00569 { /*@observer@*/ 00570 static const char * dirs[] = { ".repodata", "repodata", NULL }; 00571 /*@observer@*/ 00572 static const char * types[] = 00573 { "primary", "filelists", "other", "repomd", NULL }; 00574 const char ** dirp, ** typep; 00575 for (dirp = dirs; *dirp != NULL; dirp++) { 00576 for (typep = types; *typep != NULL; typep++) { 00577 fn = rpmrepoGetPath(repo, *dirp, *typep, strcmp(*typep, "repomd")); 00578 if (rpmioExists(fn, st)) { 00579 if (Access(fn, W_OK)) { 00580 rpmrepoError(0, _("Path must be writable: %s"), fn); 00581 rc = 1; 00582 } else 00583 if (REPO_ISSET(CHECKTS) && st->st_ctime > repo->mdtimestamp) 00584 repo->mdtimestamp = st->st_ctime; 00585 } 00586 fn = _free(fn); 00587 } 00588 } 00589 } 00590 00591 #ifdef NOTYET /* XXX repo->package_dir needs to go away. */ 00592 if (repo->groupfile != NULL) { 00593 if (REPO_ISSET(SPLIT) || repo->groupfile[0] != '/') { 00594 fn = rpmGetPath(repo->package_dir, "/", repo->groupfile, NULL); 00595 repo->groupfile = _free(repo->groupfile); 00596 repo->groupfile = fn; 00597 fn = NULL; 00598 } 00599 if (!rpmioExists(repo->groupfile, st)) { 00600 rpmrepoError(0, _("groupfile %s cannot be found."), repo->groupfile); 00601 rc = 1; 00602 } 00603 } 00604 #endif 00605 return rc; 00606 } 00607 00614 static int chkSuffix(const char * fn, const char * suffix) 00615 /*@*/ 00616 { 00617 size_t flen = strlen(fn); 00618 size_t slen = strlen(suffix); 00619 return (flen > slen && !strcmp(fn + flen - slen, suffix)); 00620 } 00621 00622 const char ** rpmrepoGetFileList(rpmrepo repo, const char *roots[], 00623 const char * ext) 00624 { 00625 const char ** pkglist = NULL; 00626 FTS * t; 00627 FTSENT * p; 00628 int xx; 00629 00630 if ((t = Fts_open((char *const *)roots, repo->ftsoptions, NULL)) == NULL) 00631 rpmrepoError(1, _("Fts_open: %s"), strerror(errno)); 00632 00633 while ((p = Fts_read(t)) != NULL) { 00634 #ifdef NOTYET 00635 const char * fts_name = p->fts_name; 00636 size_t fts_namelen = p->fts_namelen; 00637 00638 /* XXX fts(3) (and Fts(3)) have fts_name = "" with pesky trailing '/' */ 00639 if (p->fts_level == 0 && fts_namelen == 0) { 00640 fts_name = "."; 00641 fts_namelen = sizeof(".") - 1; 00642 } 00643 #endif 00644 00645 /* Should this element be excluded/included? */ 00646 /* XXX todo: apply globs to fts_path rather than fts_name? */ 00647 /*@-onlytrans@*/ 00648 if (mireApply(repo->excludeMire, repo->nexcludes, p->fts_name, 0, -1) >= 0) 00649 continue; 00650 if (mireApply(repo->includeMire, repo->nincludes, p->fts_name, 0, +1) < 0) 00651 continue; 00652 /*@=onlytrans@*/ 00653 00654 switch (p->fts_info) { 00655 case FTS_D: 00656 case FTS_DP: 00657 default: 00658 continue; 00659 /*@notreached@*/ /*@switchbreak@*/ break; 00660 case FTS_SL: 00661 if (REPO_ISSET(NOFOLLOW)) 00662 continue; 00663 /* XXX todo: fuss with symlinks */ 00664 /*@notreached@*/ /*@switchbreak@*/ break; 00665 case FTS_F: 00666 /* Is this a *.rpm file? */ 00667 if (chkSuffix(p->fts_name, ext)) 00668 xx = argvAdd(&pkglist, p->fts_path); 00669 /*@switchbreak@*/ break; 00670 } 00671 } 00672 00673 (void) Fts_close(t); 00674 00675 if (_rpmrepo_debug) 00676 argvPrint("pkglist", pkglist, NULL); 00677 00678 return pkglist; 00679 } 00680 00681 int rpmrepoCheckTimeStamps(rpmrepo repo) 00682 { 00683 int rc = 0; 00684 00685 if (REPO_ISSET(CHECKTS)) { 00686 const char ** pkg; 00687 00688 if (repo->pkglist != NULL) 00689 for (pkg = repo->pkglist; *pkg != NULL ; pkg++) { 00690 struct stat sb, *st = &sb; 00691 if (!rpmioExists(*pkg, st)) { 00692 rpmrepoError(0, _("cannot get to file: %s"), *pkg); 00693 rc = 1; 00694 } else if (st->st_ctime > repo->mdtimestamp) 00695 rc = 1; 00696 } 00697 } else 00698 rc = 1; 00699 00700 return rc; 00701 } 00702 00709 static int rpmrfileXMLWrite(rpmrfile rfile, const char * spew) 00710 /*@globals fileSystem @*/ 00711 /*@modifies rfile, fileSystem @*/ 00712 { 00713 size_t nspew = (spew != NULL ? strlen(spew) : 0); 00714 /*@-nullpass@*/ /* XXX spew != NULL @*/ 00715 size_t nb = (nspew > 0 ? Fwrite(spew, 1, nspew, rfile->fd) : 0); 00716 /*@=nullpass@*/ 00717 int rc = 0; 00718 if (nspew != nb) { 00719 rpmrepoError(0, _("Fwrite failed: expected write %u != %u bytes: %s\n"), 00720 (unsigned)nspew, (unsigned)nb, Fstrerror(rfile->fd)); 00721 rc = 1; 00722 } 00723 spew = _free(spew); 00724 return rc; 00725 } 00726 00733 static int rpmrepoFclose(rpmrepo repo, FD_t fd) 00734 /*@modifies repo, fd @*/ 00735 { 00736 int rc = 0; 00737 00738 if (fd != NULL) { 00739 #ifdef NOTYET 00740 rpmts ts = repo->_ts; 00741 if (ts != NULL) { 00742 (void) rpmswAdd(rpmtsOp(ts, RPMTS_OP_UNCOMPRESS), 00743 fdstat_op(fd, FDSTAT_READ)); 00744 (void) rpmswAdd(rpmtsOp(ts, RPMTS_OP_DIGEST), 00745 fdstat_op(fd, FDSTAT_DIGEST)); 00746 } 00747 #endif 00748 rc = Fclose(fd); 00749 } 00750 return rc; 00751 } 00752 00759 static int rpmrepoOpenMDFile(const rpmrepo repo, rpmrfile rfile) 00760 /*@globals h_errno, rpmGlobalMacroContext, fileSystem, internalState @*/ 00761 /*@modifies rfile, rpmGlobalMacroContext, fileSystem, internalState @*/ 00762 { 00763 const char * spew = rfile->xml_init; 00764 size_t nspew = strlen(spew); 00765 const char * fn = rpmrepoGetPath(repo, repo->tempdir, rfile->type, 1); 00766 const char * tail; 00767 size_t nb; 00768 int rc = 0; 00769 00770 rfile->fd = Fopen(fn, repo->wmode); 00771 assert(rfile->fd != NULL); 00772 00773 if (repo->algo != PGPHASHALGO_NONE) 00774 fdInitDigest(rfile->fd, repo->algo, 0); 00775 00776 if ((tail = strstr(spew, " packages=\"0\">\n")) != NULL) 00777 nspew -= strlen(tail); 00778 00779 nb = Fwrite(spew, 1, nspew, rfile->fd); 00780 00781 if (tail != NULL) { 00782 char buf[64]; 00783 size_t tnb = snprintf(buf, sizeof(buf), " packages=\"%d\">\n", 00784 repo->pkgcount); 00785 nspew += tnb; 00786 nb += Fwrite(buf, 1, tnb, rfile->fd); 00787 } 00788 if (nspew != nb) { 00789 rpmrepoError(0, _("Fwrite failed: expected write %u != %u bytes: %s\n"), 00790 (unsigned)nspew, (unsigned)nb, Fstrerror(rfile->fd)); 00791 rc = 1; 00792 } 00793 00794 fn = _free(fn); 00795 00796 #if defined(WITH_SQLITE) 00797 if (REPO_ISSET(DATABASE)) { 00798 const char ** stmt; 00799 int xx; 00800 fn = rpmGetPath(repo->outputdir, "/", repo->tempdir, "/", 00801 rfile->type, ".sqlite", NULL); 00802 if ((xx = sqlite3_open(fn, &rfile->sqldb)) != SQLITE_OK) 00803 rpmrepoError(1, "sqlite3_open(%s): %s", fn, sqlite3_errmsg(rfile->sqldb)); 00804 for (stmt = rfile->sql_init; *stmt != NULL; stmt++) { 00805 char * msg; 00806 xx = sqlite3_exec(rfile->sqldb, *stmt, NULL, NULL, &msg); 00807 if (xx != SQLITE_OK) 00808 rpmrepoError(1, "sqlite3_exec(%s, \"%s\"): %s\n", fn, *stmt, 00809 (msg != NULL ? msg : "failed")); 00810 } 00811 fn = _free(fn); 00812 } 00813 #endif 00814 00815 return rc; 00816 } 00817 00818 #if defined(WITH_SQLITE) 00819 00824 static int rpmrfileSQL(rpmrfile rfile, const char * msg, int rc) 00825 /*@globals fileSystem @*/ 00826 /*@modifies fileSystem @*/ 00827 { 00828 if (rc != SQLITE_OK || _rpmrepo_debug) 00829 rpmrepoError(0, "sqlite3_%s(%s): %s", msg, rfile->type, 00830 sqlite3_errmsg(rfile->sqldb)); 00831 return rc; 00832 } 00833 00839 static int rpmrfileSQLStep(rpmrfile rfile, sqlite3_stmt * stmt) 00840 /*@globals fileSystem @*/ 00841 /*@modifies fileSystem @*/ 00842 { 00843 int loop = 1; 00844 int rc = 0; 00845 int xx; 00846 00847 /*@-infloops@*/ 00848 while (loop) { 00849 rc = sqlite3_step(stmt); 00850 switch (rc) { 00851 default: 00852 rc = rpmrfileSQL(rfile, "step", rc); 00853 /*@fallthrough@*/ 00854 case SQLITE_DONE: 00855 loop = 0; 00856 /*@switchbreak@*/ break; 00857 } 00858 } 00859 /*@=infloops@*/ 00860 00861 xx = rpmrfileSQL(rfile, "reset", 00862 sqlite3_reset(stmt)); 00863 00864 return rc; 00865 } 00866 00873 static int rpmrfileSQLWrite(rpmrfile rfile, const char * cmd) 00874 /*@globals fileSystem @*/ 00875 /*@modifies fileSystem @*/ 00876 { 00877 sqlite3_stmt * stmt; 00878 const char * tail; 00879 int xx; 00880 00881 xx = rpmrfileSQL(rfile, "prepare", 00882 sqlite3_prepare(rfile->sqldb, cmd, (int)strlen(cmd), &stmt, &tail)); 00883 00884 xx = rpmrfileSQL(rfile, "reset", 00885 sqlite3_reset(stmt)); 00886 00887 xx = rpmrfileSQLStep(rfile, stmt); 00888 00889 xx = rpmrfileSQL(rfile, "finalize", 00890 sqlite3_finalize(stmt)); 00891 00892 cmd = _free(cmd); 00893 00894 return 0; 00895 } 00896 #endif /* WITH_SQLITE */ 00897 00902 static int rpmrepoRfileDigest(const rpmrepo repo, rpmrfile rfile, 00903 const char ** digestp) 00904 /*@modifies *digestp @*/ 00905 { 00906 static int asAscii = 1; 00907 struct stat sb, *st = &sb; 00908 const char * fn = rpmrepoGetPath(repo, repo->tempdir, rfile->type, 1); 00909 const char * path = NULL; 00910 int ut = urlPath(fn, &path); 00911 FD_t fd = NULL; 00912 int rc = 1; 00913 int xx; 00914 00915 memset(st, 0, sizeof(*st)); 00916 if (!rpmioExists(fn, st)) 00917 goto exit; 00918 fd = Fopen(fn, "r.ufdio"); 00919 if (fd == NULL || Ferror(fd)) 00920 goto exit; 00921 00922 switch (ut) { 00923 case URL_IS_PATH: 00924 case URL_IS_UNKNOWN: 00925 #if defined(HAVE_MMAP) 00926 { void * mapped = (void *)-1; 00927 00928 if (st->st_size > 0) 00929 mapped = mmap(NULL, st->st_size, PROT_READ, MAP_SHARED, Fileno(fd), 0); 00930 if (mapped != (void *)-1) { 00931 #ifdef NOTYET 00932 rpmts ts = repo->_ts; 00933 rpmop op = rpmtsOp(ts, RPMTS_OP_DIGEST); 00934 rpmtime_t tstamp = rpmswEnter(op, 0); 00935 #endif 00936 DIGEST_CTX ctx = rpmDigestInit(repo->algo, RPMDIGEST_NONE); 00937 xx = rpmDigestUpdate(ctx, mapped, st->st_size); 00938 xx = rpmDigestFinal(ctx, digestp, NULL, asAscii); 00939 #ifdef NOTYET 00940 tstamp = rpmswExit(op, st->st_size); 00941 #endif 00942 xx = munmap(mapped, st->st_size); 00943 break; 00944 } 00945 } /*@fallthrough@*/ 00946 #endif 00947 default: 00948 { char buf[64 * BUFSIZ]; 00949 size_t nb; 00950 size_t fsize = 0; 00951 00952 fdInitDigest(fd, repo->algo, 0); 00953 while ((nb = Fread(buf, sizeof(buf[0]), sizeof(buf), fd)) > 0) 00954 fsize += nb; 00955 if (Ferror(fd)) 00956 goto exit; 00957 fdFiniDigest(fd, repo->algo, digestp, NULL, asAscii); 00958 } break; 00959 } 00960 00961 rc = 0; 00962 00963 exit: 00964 if (fd) 00965 xx = rpmrepoFclose(repo, fd); 00966 fn = _free(fn); 00967 return rc; 00968 } 00969 00976 static int rpmrepoCloseMDFile(const rpmrepo repo, rpmrfile rfile) 00977 /*@globals h_errno, rpmGlobalMacroContext, fileSystem, internalState @*/ 00978 /*@modifies rfile, rpmGlobalMacroContext, fileSystem, internalState @*/ 00979 { 00980 static int asAscii = 1; 00981 char * xmlfn = xstrdup(fdGetOPath(rfile->fd)); 00982 int rc = 0; 00983 00984 if (!repo->quiet) 00985 rpmrepoError(0, _("Saving %s metadata"), basename(xmlfn)); 00986 00987 if (rpmrfileXMLWrite(rfile, xstrdup(rfile->xml_fini))) 00988 rc = 1; 00989 00990 if (repo->algo > 0) 00991 fdFiniDigest(rfile->fd, repo->algo, &rfile->digest, NULL, asAscii); 00992 else 00993 rfile->digest = xstrdup(""); 00994 00995 (void) rpmrepoFclose(repo, rfile->fd); 00996 rfile->fd = NULL; 00997 00998 /* Compute the (usually compressed) ouput file digest too. */ 00999 rfile->Zdigest = NULL; 01000 (void) rpmrepoRfileDigest(repo, rfile, &rfile->Zdigest); 01001 01002 #if defined(WITH_SQLITE) 01003 if (REPO_ISSET(DATABASE) && rfile->sqldb != NULL) { 01004 const char *dbfn = rpmGetPath(repo->outputdir, "/", repo->tempdir, "/", 01005 rfile->type, ".sqlite", NULL); 01006 int xx; 01007 if ((xx = sqlite3_close(rfile->sqldb)) != SQLITE_OK) 01008 rpmrepoError(1, "sqlite3_close(%s): %s", dbfn, sqlite3_errmsg(rfile->sqldb)); 01009 rfile->sqldb = NULL; 01010 dbfn = _free(dbfn); 01011 } 01012 #endif 01013 01014 rfile->ctime = rpmioCtime(xmlfn); 01015 xmlfn = _free(xmlfn); 01016 01017 return rc; 01018 } 01019 01022 static /*@observer@*/ /*@null@*/ const char * 01023 algo2tagname(uint32_t algo) 01024 /*@*/ 01025 { 01026 const char * tagname = NULL; 01027 01028 switch (algo) { 01029 case PGPHASHALGO_NONE: tagname = "none"; break; 01030 case PGPHASHALGO_MD5: tagname = "md5"; break; 01031 /* XXX todo: should be "sha1" */ 01032 case PGPHASHALGO_SHA1: tagname = "sha"; break; 01033 case PGPHASHALGO_RIPEMD160: tagname = "rmd160"; break; 01034 case PGPHASHALGO_MD2: tagname = "md2"; break; 01035 case PGPHASHALGO_TIGER192: tagname = "tiger192"; break; 01036 case PGPHASHALGO_HAVAL_5_160: tagname = "haval160"; break; 01037 case PGPHASHALGO_SHA256: tagname = "sha256"; break; 01038 case PGPHASHALGO_SHA384: tagname = "sha384"; break; 01039 case PGPHASHALGO_SHA512: tagname = "sha512"; break; 01040 case PGPHASHALGO_MD4: tagname = "md4"; break; 01041 case PGPHASHALGO_RIPEMD128: tagname = "rmd128"; break; 01042 case PGPHASHALGO_CRC32: tagname = "crc32"; break; 01043 case PGPHASHALGO_ADLER32: tagname = "adler32"; break; 01044 case PGPHASHALGO_CRC64: tagname = "crc64"; break; 01045 case PGPHASHALGO_JLU32: tagname = "jlu32"; break; 01046 case PGPHASHALGO_SHA224: tagname = "sha224"; break; 01047 case PGPHASHALGO_RIPEMD256: tagname = "rmd256"; break; 01048 case PGPHASHALGO_RIPEMD320: tagname = "rmd320"; break; 01049 case PGPHASHALGO_SALSA10: tagname = "salsa10"; break; 01050 case PGPHASHALGO_SALSA20: tagname = "salsa20"; break; 01051 default: tagname = NULL; break; 01052 } 01053 return tagname; 01054 } 01055 01061 static const char * rpmrepoMDExpand(rpmrepo repo, rpmrfile rfile) 01062 /*@globals h_errno, rpmGlobalMacroContext, internalState @*/ 01063 /*@modifies rpmGlobalMacroContext, internalState @*/ 01064 { 01065 const char * spewalgo = algo2tagname(repo->algo); 01066 char spewtime[64]; 01067 01068 (void) snprintf(spewtime, sizeof(spewtime), "%u", (unsigned)rfile->ctime); 01069 return rpmExpand("\ 01070 <data type=\"", rfile->type, "\">\n\ 01071 <checksum type=\"", spewalgo, "\">", rfile->Zdigest, "</checksum>\n\ 01072 <timestamp>", spewtime, "</timestamp>\n\ 01073 <open-checksum type=\"",spewalgo,"\">", rfile->digest, "</open-checksum>\n\ 01074 <location href=\"", repo->finaldir, "/", rfile->type, (repo->markup != NULL ? repo->markup : ""), (repo->suffix != NULL ? repo->suffix : ""), "\"/>\n\ 01075 </data>\n", NULL); 01076 } 01077 01078 int rpmrepoDoRepoMetadata(rpmrepo repo) 01079 { 01080 rpmrfile rfile = &repo->repomd; 01081 const char * fn = rpmrepoGetPath(repo, repo->tempdir, rfile->type, 0); 01082 int rc = 0; 01083 01084 if ((rfile->fd = Fopen(fn, "w.ufdio")) != NULL) { /* no compression */ 01085 if (rpmrfileXMLWrite(rfile, xstrdup(rfile->xml_init)) 01086 || rpmrfileXMLWrite(rfile, rpmrepoMDExpand(repo, &repo->other)) 01087 || rpmrfileXMLWrite(rfile, rpmrepoMDExpand(repo, &repo->filelists)) 01088 || rpmrfileXMLWrite(rfile, rpmrepoMDExpand(repo, &repo->primary)) 01089 || rpmrfileXMLWrite(rfile, xstrdup(rfile->xml_fini))) 01090 rc = 1; 01091 (void) rpmrepoFclose(repo, rfile->fd); 01092 rfile->fd = NULL; 01093 } 01094 01095 fn = _free(fn); 01096 if (rc) return rc; 01097 01098 #ifdef NOTYET 01099 def doRepoMetadata(self): 01100 """wrapper to generate the repomd.xml file that stores the info on the other files""" 01101 const char * repopath = 01102 rpmGetPath(repo->outputdir, "/", repo->tempdir, NULL); 01103 repodoc = libxml2.newDoc("1.0") 01104 reporoot = repodoc.newChild(None, "repomd", None) 01105 repons = reporoot.newNs("http://linux.duke.edu/metadata/repo", None) 01106 reporoot.setNs(repons) 01107 repopath = rpmGetPath(repo->outputdir, "/", repo->tempdir, NULL); 01108 fn = rpmrepoGetPath(repo, repo->tempdir, repo->repomd.type, 1); 01109 01110 repoid = "garbageid"; 01111 01112 if (REPO_ISSET(DATABASE)) { 01113 if (!repo->quiet) rpmrepoError(0, _("Generating sqlite DBs")); 01114 try: 01115 dbversion = str(sqlitecachec.DBVERSION) 01116 except AttributeError: 01117 dbversion = "9" 01118 rp = sqlitecachec.RepodataParserSqlite(repopath, repoid, None) 01119 } 01120 01121 { static const char * types[] = 01122 { "primary", "filelists", "other", NULL }; 01123 const char ** typep; 01124 for (typep = types; *typep != NULL; typep++) { 01125 complete_path = rpmrepoGetPath(repo, repo->tempdir, *typep, 1); 01126 01127 zfo = _gzipOpen(complete_path) 01128 uncsum = misc.checksum(algo2tagname(repo->algo), zfo) 01129 zfo.close() 01130 csum = misc.checksum(algo2tagname(repo->algo), complete_path) 01131 (void) rpmioExists(complete_path, st) 01132 timestamp = os.stat(complete_path)[8] 01133 01134 db_csums = {} 01135 db_compressed_sums = {} 01136 01137 if (REPO_ISSET(repo)) { 01138 if (repo->verbose) { 01139 time_t now = time(NULL); 01140 rpmrepoError(0, _("Starting %s db creation: %s"), 01141 *typep, ctime(&now)); 01142 } 01143 01144 if (!strcmp(*typep, "primary")) 01145 rp.getPrimary(complete_path, csum) 01146 else if (!strcmp(*typep, "filelists")); 01147 rp.getFilelists(complete_path, csum) 01148 else if (!strcmp(*typep, "other")) 01149 rp.getOtherdata(complete_path, csum) 01150 01151 { const char * tmp_result_path = 01152 rpmGetPath(repo->outputdir, "/", repo->tempdir, "/", 01153 *typep, ".xml.gz.sqlite", NULL); 01154 const char * resultpath = 01155 rpmGetPath(repo->outputdir, "/", repo->tempdir, "/", 01156 *typep, ".sqlite", NULL); 01157 01158 /* rename from silly name to not silly name */ 01159 xx = Rename(tmp_result_path, resultpath); 01160 tmp_result_path = _free(tmp_result_path); 01161 result_compressed = 01162 rpmGetPath(repo->outputdir, "/", repo->tempdir, "/", 01163 *typep, ".sqlite.bz2", NULL); 01164 db_csums[*typep] = misc.checksum(algo2tagname(repo->algo), resultpath) 01165 01166 /* compress the files */ 01167 bzipFile(resultpath, result_compressed) 01168 /* csum the compressed file */ 01169 db_compressed_sums[*typep] = misc.checksum(algo2tagname(repo->algo), result_compressed) 01170 /* remove the uncompressed file */ 01171 xx = Unlink(resultpath); 01172 resultpath = _free(resultpath); 01173 } 01174 01175 if (REPO_ISSET(UNIQUEMDFN)) { 01176 const char * csum_result_compressed = 01177 rpmGetPath(repo->outputdir, "/", repo->tempdir, "/", 01178 db_compressed_sums[*typep], "-", *typep, ".sqlite.bz2", NULL); 01179 xx = Rename(result_compressed, csum_result_compressed); 01180 result_compressed = _free(result_compressed); 01181 result_compressed = csum_result_compressed; 01182 } 01183 01184 /* timestamp the compressed file */ 01185 (void) rpmioExists(result_compressed, st) 01186 db_timestamp = os.stat(result_compressed)[8] 01187 01188 /* add this data as a section to the repomdxml */ 01189 db_data_type = rpmExpand(*typep, "_db", NULL); 01190 data = reporoot.newChild(None, 'data', None) 01191 data.newProp('type', db_data_type) 01192 location = data.newChild(None, 'location', None) 01193 if (repo->baseurl != NULL) { 01194 location.newProp('xml:base', repo->baseurl) 01195 } 01196 01197 location.newProp('href', rpmGetPath(repo->finaldir, "/", *typep, ".sqlite.bz2", NULL)); 01198 checksum = data.newChild(None, 'checksum', db_compressed_sums[*typep]) 01199 checksum.newProp('type', algo2tagname(repo->algo)) 01200 db_tstamp = data.newChild(None, 'timestamp', str(db_timestamp)) 01201 unchecksum = data.newChild(None, 'open-checksum', db_csums[*typep]) 01202 unchecksum.newProp('type', algo2tagname(repo->algo)) 01203 database_version = data.newChild(None, 'database_version', dbversion) 01204 if (repo->verbose) { 01205 time_t now = time(NULL); 01206 rpmrepoError(0, _("Ending %s db creation: %s"), 01207 *typep, ctime(&now)); 01208 } 01209 } 01210 01211 data = reporoot.newChild(None, 'data', None) 01212 data.newProp('type', *typep) 01213 01214 checksum = data.newChild(None, 'checksum', csum) 01215 checksum.newProp('type', algo2tagname(repo->algo)) 01216 timestamp = data.newChild(None, 'timestamp', str(timestamp)) 01217 unchecksum = data.newChild(None, 'open-checksum', uncsum) 01218 unchecksum.newProp('type', algo2tagname(repo->algo)) 01219 location = data.newChild(None, 'location', None) 01220 if (repo->baseurl != NULL) 01221 location.newProp('xml:base', repo->baseurl) 01222 if (REPO_ISSET(UNIQUEMDFN)) { 01223 orig_file = rpmrepoGetPath(repo, repo->tempdir, *typep, strcmp(*typep, "repomd")); 01224 res_file = rpmExpand(csum, "-", *typep, 01225 (repo->markup ? repo->markup : ""), 01226 (repo->suffix && strcmp(*typep, "repomd") ? repo->suffix : ""), NULL); 01227 dest_file = rpmGetPath(repo->outputdir, "/", repo->tempdir, "/", res_file, NULL); 01228 xx = Rename(orig_file, dest_file); 01229 01230 } else 01231 res_file = rpmExpand(*typep, 01232 (repo->markup ? repo->markup : ""), 01233 (repo->suffix && strcmp(*typep, "repomd") ? repo->suffix : ""), NULL); 01234 01235 location.newProp('href', rpmGetPath(repo->finaldir, "/", res_file, NULL)); 01236 } 01237 } 01238 01239 if (!repo->quiet && REPO_ISSET(DATABASE)) 01240 rpmrepoError(0, _("Sqlite DBs complete")); 01241 01242 if (repo->groupfile != NULL) { 01243 self.addArbitraryMetadata(repo->groupfile, 'group_gz', reporoot) 01244 self.addArbitraryMetadata(repo->groupfile, 'group', reporoot, compress=False) 01245 } 01246 01247 /* save it down */ 01248 try: 01249 repodoc.saveFormatFileEnc(fn, 'UTF-8', 1) 01250 except: 01251 rpmrepoError(0, _("Error saving temp file for %s%s%s: %s"), 01252 rfile->type, 01253 (repo->markup ? repo->markup : ""), 01254 (repo->suffix && strcmp(*typep, "repomd") ? repo->suffix : ""), 01255 fn); 01256 rpmrepoError(1, _("Could not save temp file: %s"), fn); 01257 01258 del repodoc 01259 #endif 01260 01261 return rc; 01262 } 01263 01264 int rpmrepoDoFinalMove(rpmrepo repo) 01265 { 01266 char * output_final_dir = 01267 rpmGetPath(repo->outputdir, "/", repo->finaldir, NULL); 01268 char * output_old_dir = 01269 rpmGetPath(repo->outputdir, "/", repo->olddir, NULL); 01270 struct stat sb, *st = &sb; 01271 int xx; 01272 01273 if (rpmioExists(output_final_dir, st)) { 01274 if ((xx = Rename(output_final_dir, output_old_dir)) != 0) 01275 rpmrepoError(1, _("Error moving final %s to old dir %s"), 01276 output_final_dir, output_old_dir); 01277 } 01278 01279 { const char * output_temp_dir = 01280 rpmGetPath(repo->outputdir, "/", repo->tempdir, NULL); 01281 if ((xx = Rename(output_temp_dir, output_final_dir)) != 0) { 01282 xx = Rename(output_old_dir, output_final_dir); 01283 rpmrepoError(1, _("Error moving final metadata into place")); 01284 } 01285 output_temp_dir = _free(output_temp_dir); 01286 } 01287 01288 /* Merge old tree into new, unlink/rename as needed. */ 01289 { 01290 char *const _av[] = { output_old_dir, NULL }; 01291 int _ftsoptions = FTS_NOCHDIR | FTS_PHYSICAL | FTS_XDEV; 01292 int (*_compar)(const FTSENT **, const FTSENT **) = NULL; 01293 FTS * t = Fts_open(_av, _ftsoptions, _compar); 01294 FTSENT * p = NULL; 01295 01296 if (t != NULL) 01297 while ((p = Fts_read(t)) != NULL) { 01298 const char * opath = p->fts_accpath; 01299 const char * ofn = p->fts_path; 01300 const char * obn = p->fts_name; 01301 const char * nfn = NULL; 01302 switch (p->fts_info) { 01303 default: 01304 break; 01305 case FTS_DP: 01306 /* Remove empty directories on post-traversal visit. */ 01307 if ((xx = Rmdir(opath)) != 0) 01308 rpmrepoError(1, _("Could not remove old metadata directory: %s: %s"), 01309 ofn, strerror(errno)); 01310 break; 01311 case FTS_F: 01312 /* Remove all non-toplevel files. */ 01313 if (p->fts_level > 0) { 01314 if ((xx = Unlink(opath)) != 0) 01315 rpmrepoError(1, _("Could not remove old metadata file: %s: %s"), 01316 ofn, strerror(errno)); 01317 break; 01318 } 01319 01320 /* Remove/rename toplevel files, dependent on target existence. */ 01321 nfn = rpmGetPath(output_final_dir, "/", obn, NULL); 01322 if (rpmioExists(nfn, st)) { 01323 if ((xx = Unlink(opath)) != 0) 01324 rpmrepoError(1, _("Could not remove old metadata file: %s: %s"), 01325 ofn, strerror(errno)); 01326 } else { 01327 if ((xx = Rename(opath, nfn)) != 0) 01328 rpmrepoError(1, _("Could not restore old non-metadata file: %s -> %s: %s"), 01329 ofn, nfn, strerror(errno)); 01330 } 01331 nfn = _free(nfn); 01332 break; 01333 case FTS_SL: 01334 case FTS_SLNONE: 01335 /* Remove all symlinks. */ 01336 if ((xx = Unlink(opath)) != 0) 01337 rpmrepoError(1, _("Could not remove old metadata symlink: %s: %s"), 01338 ofn, strerror(errno)); 01339 break; 01340 } 01341 } 01342 if (t != NULL) 01343 Fts_close(t); 01344 } 01345 01346 output_old_dir = _free(output_old_dir); 01347 output_final_dir = _free(output_final_dir); 01348 01349 return 0; 01350 } 01351 01352 /*==============================================================*/ 01353 01360 static Header rpmrepoReadHeader(rpmrepo repo, const char * path) 01361 /*@globals rpmGlobalMacroContext, h_errno, fileSystem, internalState @*/ 01362 /*@modifies repo, rpmGlobalMacroContext, fileSystem, internalState @*/ 01363 { 01364 /* XXX todo: read the payload and collect the blessed file digest. */ 01365 FD_t fd = Fopen(path, "r.ufdio"); 01366 Header h = NULL; 01367 01368 if (fd != NULL) { 01369 rpmts ts = repo->_ts; 01370 uint32_t algo = repo->pkgalgo; 01371 rpmRC rpmrc; 01372 01373 if (algo != PGPHASHALGO_NONE) 01374 fdInitDigest(fd, algo, 0); 01375 01376 /* XXX what if path needs expansion? */ 01377 rpmrc = rpmReadPackageFile(ts, fd, path, &h); 01378 if (algo != PGPHASHALGO_NONE) { 01379 char buffer[32 * BUFSIZ]; 01380 size_t nb = sizeof(buffer); 01381 size_t nr; 01382 while ((nr = Fread(buffer, sizeof(buffer[0]), nb, fd)) == nb) 01383 {}; 01384 if (Ferror(fd)) { 01385 fprintf(stderr, _("%s: Fread(%s) failed: %s\n"), 01386 __progname, path, Fstrerror(fd)); 01387 rpmrc = RPMRC_FAIL; 01388 } else { 01389 static int asAscii = 1; 01390 const char *digest = NULL; 01391 fdFiniDigest(fd, algo, &digest, NULL, asAscii); 01392 (void) headerSetDigest(h, digest); 01393 digest = _free(digest); 01394 } 01395 } 01396 01397 (void) Fclose(fd); 01398 01399 switch (rpmrc) { 01400 case RPMRC_NOTFOUND: 01401 case RPMRC_FAIL: 01402 default: 01403 (void) headerFree(h); 01404 h = NULL; 01405 break; 01406 case RPMRC_NOTTRUSTED: 01407 case RPMRC_NOKEY: 01408 case RPMRC_OK: 01409 if (repo->baseurl) 01410 (void) headerSetBaseURL(h, repo->baseurl); 01411 (void) headerSetInstance(h, (uint32_t)repo->current+1); 01412 break; 01413 } 01414 } 01415 return h; 01416 } 01417 01424 static const char * rfileHeaderSprintf(Header h, const char * qfmt) 01425 /*@globals fileSystem @*/ 01426 /*@modifies h, fileSystem @*/ 01427 { 01428 const char * msg = NULL; 01429 const char * s = headerSprintf(h, qfmt, NULL, NULL, &msg); 01430 if (s == NULL) 01431 rpmrepoError(1, _("headerSprintf(%s): %s"), qfmt, msg); 01432 assert(s != NULL); 01433 return s; 01434 } 01435 01436 #if defined(WITH_SQLITE) 01437 01443 static const char * rfileHeaderSprintfHack(Header h, const char * qfmt) 01444 /*@globals fileSystem @*/ 01445 /*@modifies h, fileSystem @*/ 01446 { 01447 static const char mark[] = "'XXX'"; 01448 static size_t nmark = sizeof("'XXX'") - 1; 01449 const char * msg = NULL; 01450 char * s = (char *) headerSprintf(h, qfmt, NULL, NULL, &msg); 01451 char * f, * fe; 01452 int nsubs = 0; 01453 01454 if (s == NULL) 01455 rpmrepoError(1, _("headerSprintf(%s): %s"), qfmt, msg); 01456 assert(s != NULL); 01457 01458 /* XXX Find & replace 'XXX' with '%{DBINSTANCE}' the hard way. */ 01459 /*@-nullptrarith@*/ 01460 for (f = s; *f != '\0' && (fe = strstr(f, "'XXX'")) != NULL; fe += nmark, f = fe) 01461 nsubs++; 01462 /*@=nullptrarith@*/ 01463 01464 if (nsubs > 0) { 01465 char instance[64]; 01466 int xx = snprintf(instance, sizeof(instance), "'%u'", 01467 (uint32_t) headerGetInstance(h)); 01468 size_t tlen = strlen(s) + nsubs * ((int)strlen(instance) - (int)nmark); 01469 char * t = xmalloc(tlen + 1); 01470 char * te = t; 01471 01472 xx = xx; 01473 /*@-nullptrarith@*/ 01474 for (f = s; *f != '\0' && (fe = strstr(f, mark)) != NULL; fe += nmark, f = fe) { 01475 *fe = '\0'; 01476 te = stpcpy( stpcpy(te, f), instance); 01477 } 01478 /*@=nullptrarith@*/ 01479 if (*f != '\0') 01480 te = stpcpy(te, f); 01481 s = _free(s); 01482 s = t; 01483 } 01484 01485 return s; 01486 } 01487 #endif 01488 01496 static int rpmrepoWriteMDFile(rpmrepo repo, rpmrfile rfile, Header h) 01497 /*@globals fileSystem @*/ 01498 /*@modifies rfile, h, fileSystem @*/ 01499 { 01500 int rc = 0; 01501 01502 if (rfile->xml_qfmt != NULL) { 01503 if (rpmrfileXMLWrite(rfile, rfileHeaderSprintf(h, rfile->xml_qfmt))) 01504 rc = 1; 01505 } 01506 01507 #if defined(WITH_SQLITE) 01508 if (REPO_ISSET(DATABASE)) { 01509 if (rpmrfileSQLWrite(rfile, rfileHeaderSprintfHack(h, rfile->sql_qfmt))) 01510 rc = 1; 01511 } 01512 #endif 01513 01514 return rc; 01515 } 01516 01522 static int repoWriteMetadataDocs(rpmrepo repo) 01523 /*@globals h_errno, rpmGlobalMacroContext, fileSystem, internalState @*/ 01524 /*@modifies repo, rpmGlobalMacroContext, fileSystem, internalState @*/ 01525 { 01526 const char ** pkglist = repo->pkglist; 01527 const char * pkg; 01528 int rc = 0; 01529 01530 if (pkglist) 01531 while ((pkg = *pkglist++) != NULL) { 01532 Header h = rpmrepoReadHeader(repo, pkg); 01533 01534 repo->current++; 01535 01536 /* XXX repoReadHeader() displays error. Continuing is foolish */ 01537 if (h == NULL) { 01538 rc = 1; 01539 break; 01540 } 01541 01542 #ifdef REFERENCE 01543 /* XXX todo: rpmGetPath(mydir, "/", filematrix[mydir], NULL); */ 01544 reldir = (pkgpath != NULL ? pkgpath : rpmGetPath(repo->basedir, "/", repo->directories[0], NULL)); 01545 self.primaryfile.write(po.do_primary_xml_dump(reldir, baseurl=repo->baseurl)) 01546 self.flfile.write(po.do_filelists_xml_dump()) 01547 self.otherfile.write(po.do_other_xml_dump()) 01548 #endif 01549 01550 if (rpmrepoWriteMDFile(repo, &repo->primary, h) 01551 || rpmrepoWriteMDFile(repo, &repo->filelists, h) 01552 || rpmrepoWriteMDFile(repo, &repo->other, h)) 01553 rc = 1; 01554 01555 (void) headerFree(h); 01556 h = NULL; 01557 if (rc) break; 01558 01559 if (!repo->quiet) { 01560 if (repo->verbose) 01561 rpmrepoError(0, "%d/%d - %s", repo->current, repo->pkgcount, pkg); 01562 else 01563 rpmrepoProgress(repo, pkg, repo->current, repo->pkgcount); 01564 } 01565 } 01566 return rc; 01567 } 01568 01569 int rpmrepoDoPkgMetadata(rpmrepo repo) 01570 { 01571 int rc = 0; 01572 01573 repo->current = 0; 01574 01575 #ifdef REFERENCE 01576 def _getFragmentUrl(self, url, fragment): 01577 import urlparse 01578 urlparse.uses_fragment.append('media') 01579 if not url: 01580 return url 01581 (scheme, netloc, path, query, fragid) = urlparse.urlsplit(url) 01582 return urlparse.urlunsplit((scheme, netloc, path, query, str(fragment))) 01583 01584 def doPkgMetadata(self): 01585 """all the heavy lifting for the package metadata""" 01586 if (argvCount(repo->directories) == 1) { 01587 MetaDataGenerator.doPkgMetadata(self) 01588 return 01589 } 01590 01591 ARGV_t roots = NULL; 01592 filematrix = {} 01593 for mydir in repo->directories { 01594 if (mydir[0] == '/') 01595 thisdir = xstrdup(mydir); 01596 else if (mydir[0] == '.' && mydir[1] == '.' && mydir[2] == '/') 01597 thisdir = Realpath(mydir, NULL); 01598 else 01599 thisdir = rpmGetPath(repo->basedir, "/", mydir, NULL); 01600 01601 xx = argvAdd(&roots, thisdir); 01602 thisdir = _free(thisdir); 01603 01604 filematrix[mydir] = rpmrepoGetFileList(repo, roots, '.rpm') 01605 self.trimRpms(filematrix[mydir]) 01606 repo->pkgcount = argvCount(filematrix[mydir]); 01607 roots = argvFree(roots); 01608 } 01609 01610 mediano = 1; 01611 repo->baseurl = self._getFragmentUrl(repo->baseurl, mediano) 01612 #endif 01613 01614 if (rpmrepoOpenMDFile(repo, &repo->primary) 01615 || rpmrepoOpenMDFile(repo, &repo->filelists) 01616 || rpmrepoOpenMDFile(repo, &repo->other)) 01617 rc = 1; 01618 if (rc) return rc; 01619 01620 #ifdef REFERENCE 01621 for mydir in repo->directories { 01622 repo->baseurl = self._getFragmentUrl(repo->baseurl, mediano) 01623 /* XXX todo: rpmGetPath(mydir, "/", filematrix[mydir], NULL); */ 01624 if (repoWriteMetadataDocs(repo, filematrix[mydir])) 01625 rc = 1; 01626 mediano++; 01627 } 01628 repo->baseurl = self._getFragmentUrl(repo->baseurl, 1) 01629 #endif 01630 01631 if (repoWriteMetadataDocs(repo)) 01632 rc = 1; 01633 01634 if (!repo->quiet) 01635 fprintf(stderr, "\n"); 01636 if (rpmrepoCloseMDFile(repo, &repo->primary) 01637 || rpmrepoCloseMDFile(repo, &repo->filelists) 01638 || rpmrepoCloseMDFile(repo, &repo->other)) 01639 rc = 1; 01640 01641 return rc; 01642 } 01643 01644 /*==============================================================*/ 01645 01646 /*@unchecked@*/ 01647 static int compression = -1; 01648 01649 /*@unchecked@*/ /*@observer@*/ 01650 static struct poptOption repoCompressionPoptTable[] = { 01651 { "uncompressed", '\0', POPT_ARG_VAL, &compression, 0, 01652 N_("don't compress"), NULL }, 01653 { "gzip", 'Z', POPT_ARG_VAL, &compression, 1, 01654 N_("use gzip compression"), NULL }, 01655 { "bzip2", '\0', POPT_ARG_VAL, &compression, 2, 01656 N_("use bzip2 compression"), NULL }, 01657 { "lzma", '\0', POPT_ARG_VAL, &compression, 3, 01658 N_("use lzma compression"), NULL }, 01659 { "xz", '\0', POPT_ARG_VAL, &compression, 4, 01660 N_("use xz compression"), NULL }, 01661 POPT_TABLEEND 01662 }; 01663 01664 /*@unchecked@*/ /*@observer@*/ 01665 static struct poptOption _rpmrepoOptions[] = { 01666 01667 { "quiet", 'q', POPT_ARG_VAL, &__repo.quiet, 0, 01668 N_("output nothing except for serious errors"), NULL }, 01669 { "verbose", 'v', 0, NULL, (int)'v', 01670 N_("output more debugging info."), NULL }, 01671 { "dryrun", '\0', POPT_BIT_SET, &__repo.flags, REPO_FLAGS_DRYRUN, 01672 N_("sanity check arguments, don't create metadata"), NULL }, 01673 { "excludes", 'x', POPT_ARG_ARGV, &__repo.exclude_patterns, 0, 01674 N_("glob PATTERN(s) to exclude"), N_("PATTERN") }, 01675 { "includes", 'i', POPT_ARG_ARGV, &__repo.include_patterns, 0, 01676 N_("glob PATTERN(s) to include"), N_("PATTERN") }, 01677 { "basedir", '\0', POPT_ARG_STRING|POPT_ARGFLAG_DOC_HIDDEN, &__repo.basedir, 0, 01678 N_("top level directory"), N_("DIR") }, 01679 { "baseurl", 'u', POPT_ARG_STRING|POPT_ARGFLAG_DOC_HIDDEN, &__repo.baseurl, 0, 01680 N_("baseurl to append on all files"), N_("BASEURL") }, 01681 #ifdef NOTYET 01682 { "groupfile", 'g', POPT_ARG_STRING|POPT_ARGFLAG_DOC_HIDDEN, &__repo.groupfile, 0, 01683 N_("path to groupfile to include in metadata"), N_("FILE") }, 01684 #endif 01685 { "pretty", 'p', POPT_BIT_SET|POPT_ARGFLAG_DOC_HIDDEN, &__repo.flags, REPO_FLAGS_PRETTY, 01686 N_("make sure all xml generated is formatted"), NULL }, 01687 { "checkts", 'C', POPT_BIT_SET|POPT_ARGFLAG_DOC_HIDDEN, &__repo.flags, REPO_FLAGS_CHECKTS, 01688 N_("check timestamps on files vs the metadata to see if we need to update"), NULL }, 01689 { "database", 'd', POPT_BIT_SET, &__repo.flags, REPO_FLAGS_DATABASE, 01690 N_("create sqlite3 database files"), NULL }, 01691 { "split", '\0', POPT_BIT_SET|POPT_ARGFLAG_DOC_HIDDEN, &__repo.flags, REPO_FLAGS_SPLIT, 01692 N_("generate split media"), NULL }, 01693 { "pkglist", 'l', POPT_ARG_ARGV|POPT_ARGFLAG_DOC_HIDDEN, &__repo.manifests, 0, 01694 N_("use only the files listed in this file from the directory specified"), N_("FILE") }, 01695 { "outputdir", 'o', POPT_ARG_STRING, &__repo.outputdir, 0, 01696 N_("<dir> = optional directory to output to"), N_("DIR") }, 01697 { "skip-symlinks", 'S', POPT_BIT_SET, &__repo.flags, REPO_FLAGS_NOFOLLOW, 01698 N_("ignore symlinks of packages"), NULL }, 01699 { "unique-md-filenames", '\0', POPT_BIT_SET|POPT_ARGFLAG_DOC_HIDDEN, &__repo.flags, REPO_FLAGS_UNIQUEMDFN, 01700 N_("include the file's checksum in the filename, helps with proxies"), NULL }, 01701 01702 POPT_TABLEEND 01703 01704 }; 01705 01706 /*@unchecked@*/ /*@observer@*/ 01707 static struct poptOption rpmrepoOptionsTable[] = { 01708 01709 { NULL, '\0', POPT_ARG_INCLUDE_TABLE, _rpmrepoOptions, 0, 01710 N_("Repository options:"), NULL }, 01711 01712 { NULL, '\0', POPT_ARG_INCLUDE_TABLE, rpmioFtsPoptTable, 0, 01713 N_("Fts(3) traversal options:"), NULL }, 01714 01715 { NULL, '\0', POPT_ARG_INCLUDE_TABLE, repoCompressionPoptTable, 0, 01716 N_("Available compressions:"), NULL }, 01717 01718 { NULL, '\0', POPT_ARG_INCLUDE_TABLE, rpmioDigestPoptTable, 0, 01719 N_("Available digests:"), NULL }, 01720 01721 { NULL, '\0', POPT_ARG_INCLUDE_TABLE, rpmioAllPoptTable, 0, 01722 N_("Common options for all rpmio executables:"), 01723 NULL }, 01724 01725 POPT_AUTOALIAS 01726 POPT_AUTOHELP 01727 POPT_TABLEEND 01728 }; 01729 01730 static int rpmrepoInitPopt(rpmrepo repo, char ** av) 01731 /*@modifies repo @*/ 01732 { 01733 void *use = repo->_item.use; 01734 void *pool = repo->_item.pool; 01735 int ac = argvCount((ARGV_t)av); 01736 poptContext con = rpmioInit(ac, av, rpmrepoOptionsTable); 01737 int rc = 0; /* XXX assume success */ 01738 int xx; 01739 int i; 01740 01741 *repo = *_repo; /* structure assignment */ 01742 repo->_item.use = use; 01743 repo->_item.pool = pool; 01744 01745 repo->con = con; 01746 01747 /* XXX Impedanace match against poptIO common code. */ 01748 if (rpmIsVerbose()) 01749 repo->verbose++; 01750 if (rpmIsDebug()) 01751 repo->verbose++; 01752 01753 repo->ftsoptions = (rpmioFtsOpts ? rpmioFtsOpts : FTS_PHYSICAL); 01754 switch (repo->ftsoptions & (FTS_LOGICAL|FTS_PHYSICAL)) { 01755 case (FTS_LOGICAL|FTS_PHYSICAL): 01756 rpmrepoError(1, "FTS_LOGICAL and FTS_PYSICAL are mutually exclusive"); 01757 /*@notreached@*/ break; 01758 case 0: 01759 repo->ftsoptions |= FTS_PHYSICAL; 01760 break; 01761 } 01762 01763 repo->algo = (rpmioDigestHashAlgo >= 0 01764 ? (rpmioDigestHashAlgo & 0xff) : PGPHASHALGO_SHA1); 01765 01766 repo->compression = (compression >= 0 ? compression : 1); 01767 switch (repo->compression) { 01768 case 0: 01769 repo->suffix = NULL; 01770 repo->wmode = "w.ufdio"; 01771 break; 01772 default: 01773 /*@fallthrough@*/ 01774 case 1: 01775 repo->suffix = ".gz"; 01776 repo->wmode = "w9.gzdio"; 01777 break; 01778 case 2: 01779 repo->suffix = ".bz2"; 01780 repo->wmode = "w9.bzdio"; 01781 break; 01782 case 3: 01783 repo->suffix = ".lzma"; 01784 repo->wmode = "w.lzdio"; 01785 break; 01786 case 4: 01787 repo->suffix = ".xz"; 01788 repo->wmode = "w.xzdio"; 01789 break; 01790 } 01791 01792 repo->av = poptGetArgs(repo->con); 01793 01794 if (repo->av == NULL || repo->av[0] == NULL) 01795 rpmrepoError(1, _("Must specify path(s) to index.")); 01796 01797 if (repo->av != NULL) 01798 for (i = 0; repo->av[i] != NULL; i++) { 01799 char fullpath[MAXPATHLEN]; 01800 struct stat sb; 01801 const char * rpath; 01802 const char * lpath = NULL; 01803 int ut = urlPath(repo->av[i], &lpath); 01804 size_t nb = (size_t)(lpath - repo->av[i]); 01805 int isdir = (lpath[strlen(lpath)-1] == '/'); 01806 01807 /* Convert to absolute/clean/malloc'd path. */ 01808 if (lpath[0] != '/') { 01809 if ((rpath = rpmrepoRealpath(lpath)) == NULL) 01810 rpmrepoError(1, _("Realpath(%s): %s"), lpath, strerror(errno)); 01811 lpath = rpmGetPath(rpath, NULL); 01812 rpath = _free(rpath); 01813 } else 01814 lpath = rpmGetPath(lpath, NULL); 01815 01816 /* Reattach the URI to the absolute/clean path. */ 01817 /* XXX todo: rpmGenPath was confused by file:///path/file URI's. */ 01818 switch (ut) { 01819 case URL_IS_DASH: 01820 case URL_IS_UNKNOWN: 01821 rpath = lpath; 01822 lpath = NULL; 01823 /*@switchbreak@*/ break; 01824 default: 01825 assert(nb < sizeof(fullpath)); 01826 strncpy(fullpath, repo->av[i], nb); 01827 fullpath[nb] = '\0'; 01828 rpath = rpmGenPath(fullpath, lpath, NULL); 01829 lpath = _free(lpath); 01830 /*@switchbreak@*/ break; 01831 } 01832 01833 /* Add a trailing '/' on directories. */ 01834 lpath = (isdir || (!Stat(rpath, &sb) && S_ISDIR(sb.st_mode)) 01835 ? "/" : NULL); 01836 if (lpath != NULL) { 01837 lpath = rpmExpand(rpath, lpath, NULL); 01838 xx = argvAdd(&repo->directories, lpath); 01839 lpath = _free(lpath); 01840 } else { 01841 xx = argvAdd(&repo->pkglist, rpath); 01842 } 01843 rpath = _free(rpath); 01844 } 01845 01846 return rc; 01847 } 01848 01849 static void rpmrepoFini(void * _repo) 01850 /*@globals fileSystem @*/ 01851 /*@modifies *_repo, fileSystem @*/ 01852 { 01853 rpmrepo repo = _repo; 01854 01855 repo->primary.digest = _free(repo->primary.digest); 01856 repo->primary.Zdigest = _free(repo->primary.Zdigest); 01857 repo->filelists.digest = _free(repo->filelists.digest); 01858 repo->filelists.Zdigest = _free(repo->filelists.Zdigest); 01859 repo->other.digest = _free(repo->other.digest); 01860 repo->other.Zdigest = _free(repo->other.Zdigest); 01861 repo->repomd.digest = _free(repo->repomd.digest); 01862 repo->repomd.Zdigest = _free(repo->repomd.Zdigest); 01863 repo->outputdir = _free(repo->outputdir); 01864 repo->pkglist = argvFree(repo->pkglist); 01865 repo->directories = argvFree(repo->directories); 01866 repo->manifests = argvFree(repo->manifests); 01867 /*@-onlytrans -refcounttrans @*/ 01868 repo->excludeMire = mireFreeAll(repo->excludeMire, repo->nexcludes); 01869 repo->includeMire = mireFreeAll(repo->includeMire, repo->nincludes); 01870 /*@=onlytrans =refcounttrans @*/ 01871 repo->exclude_patterns = argvFree(repo->exclude_patterns); 01872 repo->include_patterns = argvFree(repo->include_patterns); 01873 01874 repo->con = poptFreeContext(repo->con); 01875 01876 } 01877 01878 /*@unchecked@*/ /*@only@*/ /*@null@*/ 01879 rpmioPool _rpmrepoPool = NULL; 01880 01881 static rpmrepo rpmrepoGetPool(/*@null@*/ rpmioPool pool) 01882 /*@globals _rpmrepoPool, fileSystem @*/ 01883 /*@modifies pool, _rpmrepoPool, fileSystem @*/ 01884 { 01885 rpmrepo repo; 01886 01887 if (_rpmrepoPool == NULL) { 01888 _rpmrepoPool = rpmioNewPool("repo", sizeof(*repo), -1, _rpmrepo_debug, 01889 NULL, NULL, rpmrepoFini); 01890 pool = _rpmrepoPool; 01891 } 01892 repo = (rpmrepo) rpmioGetPool(pool, sizeof(*repo)); 01893 memset(((char *)repo)+sizeof(repo->_item), 0, sizeof(*repo)-sizeof(repo->_item)); 01894 return repo; 01895 } 01896 01897 rpmrepo rpmrepoNew(char ** av, int flags) 01898 { 01899 rpmrepo repo = rpmrepoGetPool(_rpmrepoPool); 01900 int xx; 01901 01902 xx = rpmrepoInitPopt(repo, av); 01903 01904 return rpmrepoLink(repo); 01905 }