10 #include "rpmio_internal.h"
12 #include <rpmmacro.h> /* XXX for rpmGetPath */
18 /*@access Header@*/ /* XXX compared with NULL */
19 /*@access FD_t@*/ /* XXX compared with NULL */
21 int domd5(const char * fn, unsigned char * digest, int asAscii)
25 FD_t fd = Fopen(fn, "r.ufdio");
26 unsigned char buf[BUFSIZ];
27 unsigned char * md5sum = NULL;
30 if (fd == NULL || Ferror(fd)) {
36 fdInitDigest(fd, PGPHASHALGO_MD5, 0);
38 while ((rc = Fread(buf, sizeof(buf[0]), sizeof(buf), fd)) > 0)
40 fdFiniDigest(fd, PGPHASHALGO_MD5, (void **)&md5sum, &md5len, asAscii);
47 memcpy(digest, md5sum, md5len);
48 md5sum = _free(md5sum);
53 /*@-exportheadervar@*/
54 /* just to put a marker in librpm.a */
56 /*@unused@*/ /*@observer@*/ char * RPMVERSION = VERSION;
57 /*@=exportheadervar@*/
59 char ** splitString(const char * str, int length, char sep)
67 s = xmalloc(length + 1);
70 for (source = str, dest = s, i = 0; i < length; i++, source++, dest++) {
72 if (*dest == sep) fields++;
77 list = xmalloc(sizeof(*list) * (fields + 1));
95 void freeSplitString(char ** list)
97 /*@-unqualifiedtrans@*/
98 list[0] = _free(list[0]);
99 /*@=unqualifiedtrans@*/
103 int doputenv(const char *str)
107 /* FIXME: this leaks memory! */
108 a = xmalloc(strlen(str) + 1);
113 int dosetenv(const char * name, const char * value, int overwrite)
117 if (!overwrite && getenv(name)) return 0;
119 /* FIXME: this leaks memory! */
120 a = xmalloc(strlen(name) + strlen(value) + sizeof("="));
121 (void) stpcpy( stpcpy( stpcpy( a, name), "="), value);
125 static int rpmMkpath(const char * path, mode_t mode, uid_t uid, gid_t gid)
126 /*@globals fileSystem @*/
127 /*@modifies fileSystem @*/
135 d = alloca(strlen(path)+2);
136 de = stpcpy(d, path);
138 for (de = d; *de != '\0'; de++) {
142 while (*de && *de != '/') de++;
151 /*@notreached@*/ /*@switchbreak@*/ break;
153 /*@switchbreak@*/ break;
159 if (!(uid == (uid_t) -1 && gid == (gid_t) -1)) {
160 rc = chown(d, uid, gid);
164 } else if (!S_ISDIR(st.st_mode)) {
171 rpmMessage(RPMMESS_WARNING, "created %%_tmppath directory %s\n", path);
175 int makeTempFile(const char * prefix, const char ** fnptr, FD_t * fdptr)
177 const char * tpmacro = "%{?_tmppath:%{_tmppath}}%{!?_tmppath:/var/tmp}";
178 const char * tempfn = NULL;
179 const char * tfn = NULL;
180 static int _initialized = 0;
186 if (!prefix) prefix = "";
189 /* Create the temp directory if it doesn't already exist. */
193 tempfn = rpmGenPath(prefix, tpmacro, NULL);
194 if (rpmMkpath(tempfn, 0755, (uid_t) -1, (gid_t) -1))
199 /* XXX should probably use mkstemp here */
201 ran = rand() % 100000;
203 /* maybe this should use link/stat? */
208 sprintf(tfnbuf, "rpm-tmp.%d", ran++);
209 tempfn = _free(tempfn);
210 tempfn = rpmGenPath(prefix, tpmacro, tfnbuf);
212 strcpy(tfnbuf, "rpm-tmp.XXXXXX");
213 tempfn = _free(tempfn);
214 tempfn = rpmGenPath(prefix, tpmacro, mktemp(tfnbuf));
217 temput = urlPath(tempfn, &tfn);
218 if (*tfn == '\0') goto errxit;
224 /*@notreached@*/ /*@switchbreak@*/ break;
226 /*@switchbreak@*/ break;
229 fd = Fopen(tempfn, "w+x.ufdio");
230 /* XXX FIXME: errno may not be correct for ufdio */
231 } while ((fd == NULL || Ferror(fd)) && errno == EEXIST);
233 if (fd == NULL || Ferror(fd))
239 { struct stat sb, sb2;
240 if (!stat(tfn, &sb) && S_ISLNK(sb.st_mode)) {
241 rpmError(RPMERR_SCRIPT, _("error creating temporary file %s\n"), tfn);
245 if (sb.st_nlink != 1) {
246 rpmError(RPMERR_SCRIPT, _("error creating temporary file %s\n"), tfn);
250 if (fstat(Fileno(fd), &sb2) == 0) {
251 if (sb2.st_ino != sb.st_ino || sb2.st_dev != sb.st_dev) {
252 rpmError(RPMERR_SCRIPT, _("error creating temporary file %s\n"), tfn);
265 tempfn = _free(tempfn);
272 tempfn = _free(tempfn);
274 if (fd) (void) Fclose(fd);
279 char * currentDirectory(void)
285 currDir = xmalloc(currDirLen);
286 while (!getcwd(currDir, currDirLen) && errno == ERANGE) {
288 currDir = xrealloc(currDir, currDirLen);
294 /*@-exportheadervar@*/
296 int _noDirTokens = 0;
297 /*@=exportheadervar@*/
299 static int dncmp(const void * a, const void * b)
301 const char *const * first = a;
302 const char *const * second = b;
303 return strcmp(*first, *second);
306 void compressFilelist(Header h)
308 HGE_t hge = (HGE_t)headerGetEntryMinMemory;
309 HAE_t hae = (HAE_t)headerAddEntry;
310 HRE_t hre = (HRE_t)headerRemoveEntry;
311 HFD_t hfd = headerFreeData;
313 const char ** dirNames;
314 const char ** baseNames;
322 * This assumes the file list is already sorted, and begins with a
323 * single '/'. That assumption isn't critical, but it makes things go
327 if (headerIsEntry(h, RPMTAG_DIRNAMES)) {
328 xx = hre(h, RPMTAG_OLDFILENAMES);
329 return; /* Already converted. */
332 if (!hge(h, RPMTAG_OLDFILENAMES, &fnt, (void **) &fileNames, &count))
333 return; /* no file list */
334 if (fileNames == NULL || count <= 0)
337 dirNames = alloca(sizeof(*dirNames) * count); /* worst case */
338 baseNames = alloca(sizeof(*dirNames) * count);
339 dirIndexes = alloca(sizeof(*dirIndexes) * count);
341 if (fileNames[0][0] != '/') {
342 /* HACK. Source RPM, so just do things differently */
344 dirNames[dirIndex] = "";
345 for (i = 0; i < count; i++) {
346 dirIndexes[i] = dirIndex;
347 baseNames[i] = fileNames[i];
353 for (i = 0; i < count; i++) {
354 const char ** needle;
359 if (fileNames[i] == NULL) /* XXX can't happen */
361 baseName = strrchr(fileNames[i], '/') + 1;
362 len = baseName - fileNames[i];
364 savechar = *baseName;
367 (needle = bsearch(&fileNames[i], dirNames, dirIndex + 1, sizeof(dirNames[0]), dncmp)) == NULL) {
368 char *s = alloca(len + 1);
369 memcpy(s, fileNames[i], len + 1);
371 dirIndexes[i] = ++dirIndex;
372 dirNames[dirIndex] = s;
374 dirIndexes[i] = needle - dirNames;
376 *baseName = savechar;
377 baseNames[i] = baseName;
383 xx = hae(h, RPMTAG_DIRINDEXES, RPM_INT32_TYPE, dirIndexes, count);
384 xx = hae(h, RPMTAG_BASENAMES, RPM_STRING_ARRAY_TYPE,
386 xx = hae(h, RPMTAG_DIRNAMES, RPM_STRING_ARRAY_TYPE,
387 dirNames, dirIndex + 1);
390 fileNames = hfd(fileNames, fnt);
392 xx = hre(h, RPMTAG_OLDFILENAMES);
396 * This is pretty straight-forward. The only thing that even resembles a trick
397 * is getting all of this into a single xmalloc'd block.
399 static void doBuildFileList(Header h, /*@out@*/ const char *** fileListPtr,
400 /*@out@*/ int * fileCountPtr, rpmTag baseNameTag,
401 rpmTag dirNameTag, rpmTag dirIndexesTag)
402 /*@modifies *fileListPtr, *fileCountPtr @*/
404 HGE_t hge = (HGE_t)headerGetEntryMinMemory;
405 HFD_t hfd = headerFreeData;
406 const char ** baseNames;
407 const char ** dirNames;
410 const char ** fileNames;
416 if (!hge(h, baseNameTag, &bnt, (void **) &baseNames, &count)) {
417 if (fileListPtr) *fileListPtr = NULL;
418 if (fileCountPtr) *fileCountPtr = 0;
419 return; /* no file list */
422 xx = hge(h, dirNameTag, &dnt, (void **) &dirNames, NULL);
423 xx = hge(h, dirIndexesTag, NULL, (void **) &dirIndexes, &count);
425 size = sizeof(*fileNames) * count;
426 for (i = 0; i < count; i++)
427 size += strlen(baseNames[i]) + strlen(dirNames[dirIndexes[i]]) + 1;
429 fileNames = xmalloc(size);
430 data = ((char *) fileNames) + (sizeof(*fileNames) * count);
432 for (i = 0; i < count; i++) {
434 data = stpcpy( stpcpy(data, dirNames[dirIndexes[i]]), baseNames[i]);
438 baseNames = hfd(baseNames, bnt);
439 dirNames = hfd(dirNames, dnt);
443 *fileListPtr = fileNames;
445 fileNames = _free(fileNames);
447 if (fileCountPtr) *fileCountPtr = count;
450 void expandFilelist(Header h)
452 HAE_t hae = (HAE_t)headerAddEntry;
453 HRE_t hre = (HRE_t)headerRemoveEntry;
454 const char ** fileNames = NULL;
459 if (!headerIsEntry(h, RPMTAG_OLDFILENAMES)) {
460 doBuildFileList(h, &fileNames, &count, RPMTAG_BASENAMES,
461 RPMTAG_DIRNAMES, RPMTAG_DIRINDEXES);
462 if (fileNames == NULL || count <= 0)
464 xx = hae(h, RPMTAG_OLDFILENAMES, RPM_STRING_ARRAY_TYPE,
466 fileNames = _free(fileNames);
470 xx = hre(h, RPMTAG_DIRNAMES);
471 xx = hre(h, RPMTAG_BASENAMES);
472 xx = hre(h, RPMTAG_DIRINDEXES);
476 void rpmBuildFileList(Header h, const char *** fileListPtr, int * fileCountPtr)
478 doBuildFileList(h, fileListPtr, fileCountPtr, RPMTAG_BASENAMES,
479 RPMTAG_DIRNAMES, RPMTAG_DIRINDEXES);
482 void buildOrigFileList(Header h, const char *** fileListPtr, int * fileCountPtr)
484 doBuildFileList(h, fileListPtr, fileCountPtr, RPMTAG_ORIGBASENAMES,
485 RPMTAG_ORIGDIRNAMES, RPMTAG_ORIGDIRINDEXES);
488 /* glob_pattern_p() taken from bash
489 * Copyright (C) 1985, 1988, 1989 Free Software Foundation, Inc.
491 * Return nonzero if PATTERN has any special globbing chars in it.
493 int myGlobPatternP (const char *patternURL)
499 (void) urlPath(patternURL, &p);
500 while ((c = *p++) != '\0')
505 case '[': /* Only accept an open brace if there is a close */
506 open++; /* brace to match it. Bracket expressions must be */
507 continue; /* complete, according to Posix.2 */
520 static int glob_error(/*@unused@*/const char *foo, /*@unused@*/int bar)
525 int rpmGlob(const char * patterns, int * argcPtr, const char *** argvPtr)
528 const char ** av = NULL;
530 const char ** argv = NULL;
532 const char * globURL;
533 char * globRoot = NULL;
540 rc = poptParseArgvString(patterns, &ac, &av);
544 for (j = 0; j < ac; j++) {
545 if (!myGlobPatternP(av[j])) {
547 argv = xmalloc((argc+2) * sizeof(*argv));
549 argv = xrealloc(argv, (argc+2) * sizeof(*argv));
550 argv[argc] = xstrdup(av[j]);
552 fprintf(stderr, "*** rpmGlob argv[%d] \"%s\"\n", argc, argv[argc]);
559 rc = Glob(av[j], 0, glob_error, &gl);
563 /* XXX Prepend the URL leader for globs that have stripped it off */
565 for (i = 0; i < gl.gl_pathc; i++) {
566 if ((nb = strlen(&(gl.gl_pathv[i][0]))) > maxb)
570 ut = urlPath(av[j], &path);
571 nb = ((ut > URL_IS_DASH) ? (path - av[j]) : 0);
574 globURL = globRoot = xmalloc(maxb);
581 strncpy(globRoot, av[j], nb);
582 /*@switchbreak@*/ break;
584 /*@switchbreak@*/ break;
589 fprintf(stderr, "*** GLOB maxb %d diskURL %d %*s globURL %p %s\n", (int)maxb, (int)nb, (int)nb, av[j], globURL, globURL);
593 argv = xmalloc((gl.gl_pathc+1) * sizeof(*argv));
594 else if (gl.gl_pathc > 0)
595 argv = xrealloc(argv, (argc+gl.gl_pathc+1) * sizeof(*argv));
597 for (i = 0; i < gl.gl_pathc; i++) {
598 const char * globFile = &(gl.gl_pathv[i][0]);
599 if (globRoot > globURL && globRoot[-1] == '/')
600 while (*globFile == '/') globFile++;
601 strcpy(globRoot, globFile);
603 fprintf(stderr, "*** rpmGlob argv[%d] \"%s\"\n", argc, globURL);
604 argv[argc++] = xstrdup(globURL);
606 /*@-immediatetrans@*/
608 /*@=immediatetrans@*/
609 globURL = _free(globURL);
611 if (argv != NULL && argc > 0) {
624 if (rc || argvPtr == NULL) {
626 for (i = 0; i < argc; i++)
627 argv[i] = _free(argv[i]);
634 * XXX This is a "dressed" entry to headerGetEntry to do:
635 * 1) DIRNAME/BASENAME/DIRINDICES -> FILENAMES tag conversions.
636 * 2) i18n lookaside (if enabled).
638 int rpmHeaderGetEntry(Header h, int_32 tag, int_32 *type,
642 case RPMTAG_OLDFILENAMES:
643 { const char ** fl = NULL;
645 rpmBuildFileList(h, &fl, &count);
649 if (type) *type = RPM_STRING_ARRAY_TYPE;
654 } /*@notreached@*/ break;
657 case RPMTAG_DESCRIPTION:
664 (void) stpcpy( stpcpy( stpcpy( fmt, "%{"), tagName(tag)), "}\n");
666 /* XXX FIXME: memory leak. */
667 msgstr = headerSprintf(h, fmt, rpmTagTable, rpmHeaderFormats, &errstr);
669 *p = (void *) msgstr;
670 if (type) *type = RPM_STRING_TYPE;
677 } /*@notreached@*/ break;
680 return headerGetEntry(h, tag, type, p, c);
681 /*@notreached@*/ break;
687 * XXX Yet Another dressed entry to unify signature/header tag retrieval.
689 int rpmPackageGetEntry( /*@unused@*/ void *leadp, Header sigs, Header h,
690 int_32 tag, int_32 *type, void **p, int_32 *c)
695 case RPMTAG_SIGSIZE: sigtag = RPMSIGTAG_SIZE; break;
696 case RPMTAG_SIGLEMD5_1: sigtag = RPMSIGTAG_LEMD5_1; break;
697 case RPMTAG_SIGPGP: sigtag = RPMSIGTAG_PGP; break;
698 case RPMTAG_SIGLEMD5_2: sigtag = RPMSIGTAG_LEMD5_2; break;
699 case RPMTAG_SIGMD5: sigtag = RPMSIGTAG_MD5; break;
700 case RPMTAG_SIGGPG: sigtag = RPMSIGTAG_GPG; break;
701 case RPMTAG_SIGPGP5: sigtag = RPMSIGTAG_GPG; break;
704 return rpmHeaderGetEntry(h, tag, type, p, c);
705 /*@notreached@*/ break;
708 if (headerIsEntry(h, tag))
709 return rpmHeaderGetEntry(h, tag, type, p, c);
716 return headerGetEntry(sigs, sigtag, type, p, c);
720 * Up to rpm 3.0.4, packages implicitly provided their own name-version-release.
721 * Retrofit an explicit "Provides: name = epoch:version-release.
723 void providePackageNVR(Header h)
725 HGE_t hge = (HGE_t)headerGetEntryMinMemory;
726 HFD_t hfd = headerFreeData;
727 const char *name, *version, *release;
731 int_32 pFlags = RPMSENSE_EQUAL;
732 const char ** provides = NULL;
733 const char ** providesEVR = NULL;
735 int_32 * provideFlags = NULL;
740 /* Generate provides for this package name-version-release. */
741 xx = headerNVR(h, &name, &version, &release);
742 if (!(name && version && release))
744 pEVR = p = alloca(21 + strlen(version) + 1 + strlen(release) + 1);
746 if (hge(h, RPMTAG_EPOCH, NULL, (void **) &epoch, NULL)) {
747 sprintf(p, "%d:", *epoch);
751 (void) stpcpy( stpcpy( stpcpy(p, version) , "-") , release);
754 * Rpm prior to 3.0.3 does not have versioned provides.
755 * If no provides at all are available, we can just add.
757 if (!hge(h, RPMTAG_PROVIDENAME, &pnt, (void **) &provides, &providesCount))
761 * Otherwise, fill in entries on legacy packages.
763 if (!hge(h, RPMTAG_PROVIDEVERSION, &pvt, (void **) &providesEVR, NULL)) {
764 for (i = 0; i < providesCount; i++) {
766 int_32 fdummy = RPMSENSE_ANY;
767 xx = headerAddOrAppendEntry(h, RPMTAG_PROVIDEVERSION, RPM_STRING_ARRAY_TYPE,
769 xx = headerAddOrAppendEntry(h, RPMTAG_PROVIDEFLAGS, RPM_INT32_TYPE,
775 xx = hge(h, RPMTAG_PROVIDEFLAGS, NULL, (void **) &provideFlags, NULL);
777 if (provides && providesEVR && provideFlags)
778 for (i = 0; i < providesCount; i++) {
779 if (!(provides[i] && providesEVR[i]))
781 if (!(provideFlags[i] == RPMSENSE_EQUAL &&
782 !strcmp(name, provides[i]) && !strcmp(pEVR, providesEVR[i])))
789 provides = hfd(provides, pnt);
790 providesEVR = hfd(providesEVR, pvt);
793 xx = headerAddOrAppendEntry(h, RPMTAG_PROVIDENAME, RPM_STRING_ARRAY_TYPE,
795 xx = headerAddOrAppendEntry(h, RPMTAG_PROVIDEFLAGS, RPM_INT32_TYPE,
797 xx = headerAddOrAppendEntry(h, RPMTAG_PROVIDEVERSION, RPM_STRING_ARRAY_TYPE,