summaryrefslogtreecommitdiff
path: root/rpmio/rpmfileutil.c
diff options
context:
space:
mode:
authorPanu Matilainen <pmatilai@redhat.com>2007-11-22 16:06:11 +0200
committerPanu Matilainen <pmatilai@redhat.com>2007-11-22 16:06:11 +0200
commite063854e118b92af3072e888e0887b2943187895 (patch)
tree03848d0a70e7aa585103f50146e9e16d323ae05d /rpmio/rpmfileutil.c
parentb32cca34808e46bb5ce6972c99d95b3e53f555ab (diff)
downloadlibrpm-tizen-e063854e118b92af3072e888e0887b2943187895.tar.gz
librpm-tizen-e063854e118b92af3072e888e0887b2943187895.tar.bz2
librpm-tizen-e063854e118b92af3072e888e0887b2943187895.zip
Calculating file checksums aint legacy activity
- move the checksumming into librpmio - rename domd5() to rpmDoDigest() with future expansion for specifying digest algorithm type (ignored for now) - rearrange parameters to leave return types last - one less rpmio_internal outside rpmio/, whee... - used all over the rpm tree, and it knows about handling prelinked files so potentially useful for outside users, might as well export it - new public header rpmfilutil.h for collecting this sort of stuff
Diffstat (limited to 'rpmio/rpmfileutil.c')
-rw-r--r--rpmio/rpmfileutil.c221
1 files changed, 221 insertions, 0 deletions
diff --git a/rpmio/rpmfileutil.c b/rpmio/rpmfileutil.c
new file mode 100644
index 000000000..e79a65ad3
--- /dev/null
+++ b/rpmio/rpmfileutil.c
@@ -0,0 +1,221 @@
+#include "system.h"
+
+#if HAVE_GELF_H
+
+#include <gelf.h>
+
+#if !defined(DT_GNU_PRELINKED)
+#define DT_GNU_PRELINKED 0x6ffffdf5
+#endif
+#if !defined(DT_GNU_LIBLIST)
+#define DT_GNU_LIBLIST 0x6ffffef9
+#endif
+
+#endif
+
+#include "rpmio_internal.h"
+#include <rpmfileutil.h>
+#include <rpmurl.h>
+#include <rpmmacro.h>
+#include <argv.h>
+
+static int open_dso(const char * path, pid_t * pidp, size_t *fsizep)
+{
+ static const char * cmd = NULL;
+ static int initted = 0;
+ int fdno;
+
+ if (!initted) {
+ cmd = rpmExpand("%{?__prelink_undo_cmd}", NULL);
+ initted++;
+ }
+
+ if (pidp) *pidp = 0;
+
+ if (fsizep) {
+ struct stat sb, * st = &sb;
+ if (stat(path, st) < 0)
+ return -1;
+ *fsizep = st->st_size;
+ }
+
+ fdno = open(path, O_RDONLY);
+ if (fdno < 0)
+ return fdno;
+
+ if (!(cmd && *cmd))
+ return fdno;
+
+#if HAVE_GELF_H && HAVE_LIBELF
+ { Elf *elf = NULL;
+ Elf_Scn *scn = NULL;
+ Elf_Data *data = NULL;
+ GElf_Ehdr ehdr;
+ GElf_Shdr shdr;
+ GElf_Dyn dyn;
+ int bingo;
+
+ (void) elf_version(EV_CURRENT);
+
+ if ((elf = elf_begin (fdno, ELF_C_READ, NULL)) == NULL
+ || elf_kind(elf) != ELF_K_ELF
+ || gelf_getehdr(elf, &ehdr) == NULL
+ || !(ehdr.e_type == ET_DYN || ehdr.e_type == ET_EXEC))
+ goto exit;
+
+ bingo = 0;
+ while (!bingo && (scn = elf_nextscn(elf, scn)) != NULL) {
+ (void) gelf_getshdr(scn, &shdr);
+ if (shdr.sh_type != SHT_DYNAMIC)
+ continue;
+ while (!bingo && (data = elf_getdata (scn, data)) != NULL) {
+ int maxndx = data->d_size / shdr.sh_entsize;
+ int ndx;
+
+ for (ndx = 0; ndx < maxndx; ++ndx) {
+ (void) gelf_getdyn (data, ndx, &dyn);
+ if (!(dyn.d_tag == DT_GNU_PRELINKED || dyn.d_tag == DT_GNU_LIBLIST))
+ continue;
+ bingo = 1;
+ break;
+ }
+ }
+ }
+
+ if (pidp != NULL && bingo) {
+ int pipes[2];
+ pid_t pid;
+ int xx;
+
+ xx = close(fdno);
+ pipes[0] = pipes[1] = -1;
+ xx = pipe(pipes);
+ if (!(pid = fork())) {
+ ARGV_t av, lib;
+ argvSplit(&av, cmd, " ");
+
+ xx = close(pipes[0]);
+ xx = dup2(pipes[1], STDOUT_FILENO);
+ xx = close(pipes[1]);
+ if ((lib = argvSearch(av, "library", NULL)) != NULL) {
+ *lib = path;
+ unsetenv("MALLOC_CHECK_");
+ xx = execve(av[0], (char *const *)av+1, environ);
+ }
+ _exit(127);
+ }
+ *pidp = pid;
+ fdno = pipes[0];
+ xx = close(pipes[1]);
+ }
+
+exit:
+ if (elf) (void) elf_end(elf);
+ }
+#endif
+
+ return fdno;
+}
+
+int rpmDoDigest(pgpHashAlgo algo, const char * fn,int asAscii,
+ unsigned char * digest, size_t * fsizep)
+{
+ const char * path;
+ urltype ut = urlPath(fn, &path);
+ unsigned char * md5sum = NULL;
+ size_t md5len;
+ unsigned char buf[32*BUFSIZ];
+ FD_t fd;
+ size_t fsize = 0;
+ pid_t pid = 0;
+ int rc = 0;
+ int fdno;
+
+ fdno = open_dso(path, &pid, &fsize);
+ if (fdno < 0) {
+ rc = 1;
+ goto exit;
+ }
+
+ /* file to large (32 MB), do not mmap file */
+ if (fsize > (size_t) 32*1024*1024)
+ if (ut == URL_IS_PATH || ut == URL_IS_UNKNOWN)
+ ut = URL_IS_DASH; /* force fd io */
+
+ switch(ut) {
+ case URL_IS_PATH:
+ case URL_IS_UNKNOWN:
+#ifdef HAVE_MMAP
+ if (pid == 0) {
+ DIGEST_CTX ctx;
+ void * mapped;
+
+ if (fsize) {
+ mapped = mmap(NULL, fsize, PROT_READ, MAP_SHARED, fdno, 0);
+ if (mapped == (void *)-1) {
+ xx = close(fdno);
+ rc = 1;
+ break;
+ }
+
+#ifdef MADV_SEQUENTIAL
+ xx = madvise(mapped, fsize, MADV_SEQUENTIAL);
+#endif
+ }
+
+ ctx = rpmDigestInit(PGPHASHALGO_MD5, RPMDIGEST_NONE);
+ if (fsize)
+ xx = rpmDigestUpdate(ctx, mapped, fsize);
+ xx = rpmDigestFinal(ctx, (void **)&md5sum, &md5len, asAscii);
+ if (fsize)
+ xx = munmap(mapped, fsize);
+ xx = close(fdno);
+ break;
+ }
+#endif
+ case URL_IS_HTTPS:
+ case URL_IS_HTTP:
+ case URL_IS_FTP:
+ case URL_IS_HKP:
+ case URL_IS_DASH:
+ default:
+ /* Either use the pipe to prelink -y or open the URL. */
+ fd = (pid != 0) ? fdDup(fdno) : Fopen(fn, "r.ufdio");
+ (void) close(fdno);
+ if (fd == NULL || Ferror(fd)) {
+ rc = 1;
+ if (fd != NULL)
+ (void) Fclose(fd);
+ break;
+ }
+
+ fdInitDigest(fd, PGPHASHALGO_MD5, 0);
+ fsize = 0;
+ while ((rc = Fread(buf, sizeof(buf[0]), sizeof(buf), fd)) > 0)
+ fsize += rc;
+ fdFiniDigest(fd, PGPHASHALGO_MD5, (void **)&md5sum, &md5len, asAscii);
+ if (Ferror(fd))
+ rc = 1;
+
+ (void) Fclose(fd);
+ break;
+ }
+
+ /* Reap the prelink -y helper. */
+ if (pid) {
+ int status;
+ (void) waitpid(pid, &status, 0);
+ if (!WIFEXITED(status) || WEXITSTATUS(status))
+ rc = 1;
+ }
+
+exit:
+ if (fsizep)
+ *fsizep = fsize;
+ if (!rc)
+ memcpy(digest, md5sum, md5len);
+ md5sum = _free(md5sum);
+
+ return rc;
+}
+