From f8370579c39fce61e32be29bd3c6ba8e3b762211 Mon Sep 17 00:00:00 2001 From: Mathieu Desnoyers Date: Tue, 6 Mar 2012 17:47:56 -0500 Subject: [PATCH] Implement fallback for systems lacking open_memstream and fopenmem Signed-off-by: Mathieu Desnoyers --- configure.ac | 14 +++ formats/ctf/ctf.c | 13 ++- formats/ctf/memstream.h | 227 ++++++++++++++++++++++++++++++++++++++++ 3 files changed, 251 insertions(+), 3 deletions(-) create mode 100644 formats/ctf/memstream.h diff --git a/configure.ac b/configure.ac index 3b214104..14061994 100644 --- a/configure.ac +++ b/configure.ac @@ -56,6 +56,20 @@ AC_CHECK_LIB([uuid], [uuid_generate], AM_CONDITIONAL([BABELTRACE_BUILD_WITH_LIBUUID], [test "x$have_libuuid" = "xyes"]) AM_CONDITIONAL([BABELTRACE_BUILD_WITH_LIBC_UUID], [test "x$have_libc_uuid" = "xyes"]) +# Check for fmemopen +AC_CHECK_LIB([c], [fmemopen], +[ + AC_DEFINE_UNQUOTED([BABELTRACE_HAVE_FMEMOPEN], 1, [Has fmemopen support.]) +] +) + +# Check for open_memstream +AC_CHECK_LIB([c], [open_memstream], +[ + AC_DEFINE_UNQUOTED([BABELTRACE_HAVE_OPEN_MEMSTREAM], 1, [Has open_memstream support.]) +] +) + AC_CHECK_LIB([popt], [poptGetContext], [], [AC_MSG_ERROR([Cannot find popt.])] ) diff --git a/formats/ctf/ctf.c b/formats/ctf/ctf.c index 4f14d7a0..8608b5a1 100644 --- a/formats/ctf/ctf.c +++ b/formats/ctf/ctf.c @@ -41,6 +41,7 @@ #include "metadata/ctf-parser.h" #include "metadata/ctf-ast.h" #include "events-private.h" +#include "memstream.h" /* * We currently simply map a page to read the packet header and packet @@ -747,7 +748,7 @@ int ctf_open_trace_metadata_stream_read(struct ctf_trace *td, FILE **fp, * because its size includes garbage at the end (after final * \0). This is the allocated size, not the actual string size. */ - out = open_memstream(buf, &size); + out = babeltrace_open_memstream(buf, &size); if (out == NULL) { perror("Metadata open_memstream"); return -errno; @@ -762,10 +763,16 @@ int ctf_open_trace_metadata_stream_read(struct ctf_trace *td, FILE **fp, break; } } - fclose(out); /* flush the buffer */ + /* close to flush the buffer */ + ret = babeltrace_close_memstream(buf, &size, out); + if (ret < 0) { + perror("babeltrace_flush_memstream"); + fclose(in); + return -errno; + } fclose(in); /* open for reading */ - *fp = fmemopen(*buf, strlen(*buf), "rb"); + *fp = babeltrace_fmemopen(*buf, strlen(*buf), "rb"); if (!*fp) { perror("Metadata fmemopen"); return -errno; diff --git a/formats/ctf/memstream.h b/formats/ctf/memstream.h new file mode 100644 index 00000000..0eb85a3b --- /dev/null +++ b/formats/ctf/memstream.h @@ -0,0 +1,227 @@ +#ifndef _BABELTRACE_FORMAT_CTF_MEMSTREAM_H +#define _BABELTRACE_FORMAT_CTF_MEMSTREAM_H + +/* + * format/ctf/memstream.h + * + * Copyright 2012 (c) - Mathieu Desnoyers + * + * memstream compatibility layer. + * + * THIS MATERIAL IS PROVIDED AS IS, WITH ABSOLUTELY NO WARRANTY EXPRESSED + * OR IMPLIED. ANY USE IS AT YOUR OWN RISK. + * + * Permission is hereby granted to use or copy this program + * for any purpose, provided the above notices are retained on all copies. + * Permission to modify the code and to distribute modified code is granted, + * provided the above notices are retained, and a notice that the code was + * modified is included with the above copyright notice. + */ + +#define _GNU_SOURCE +#include + +#ifdef BABELTRACE_HAVE_FMEMOPEN +#include + +static inline +FILE *babeltrace_fmemopen(void *buf, size_t size, const char *mode) +{ + return fmemopen(buf, size, mode); +} + +#else /* BABELTRACE_HAVE_FMEMOPEN */ + +#include +#include + +/* + * Fallback for systems which don't have fmemopen. Copy buffer to a + * temporary file, and use that file as FILE * input. + */ +static inline +FILE *babeltrace_fmemopen(void *buf, size_t size, const char *mode) +{ + char tmpname[PATH_MAX]; + size_t len; + FILE *fp; + int ret; + + /* + * Support reading only. + */ + if (strcmp(mode, "rb") != 0) { + return NULL; + } + strncpy(tmpname, "/tmp/babeltrace-tmp-XXXXXX", PATH_MAX); + ret = mkstemp(tmpname); + if (ret < 0) { + return NULL; + } + /* + * We need to write to the file. + */ + fp = fdopen(ret, "w+"); + if (!fp) { + goto error_unlink; + } + /* Copy the entire buffer to the file */ + len = fwrite(buf, sizeof(char), size, fp); + if (len != size) { + goto error_close; + } + ret = fseek(fp, 0L, SEEK_SET); + if (ret < 0) { + perror("fseek"); + goto error_close; + } + /* We keep the handle open, but can unlink the file on the VFS. */ + ret = unlink(tmpname); + if (ret < 0) { + perror("unlink"); + } + return fp; + +error_close: + ret = fclose(fp); + if (ret < 0) { + perror("close"); + } +error_unlink: + ret = unlink(tmpname); + if (ret < 0) { + perror("unlink"); + } + return NULL; +} + +#endif /* BABELTRACE_HAVE_FMEMOPEN */ + +#ifdef BABELTRACE_HAVE_OPEN_MEMSTREAM + +#include + +static inline +FILE *babeltrace_open_memstream(char **ptr, size_t *sizeloc) +{ + return open_memstream(ptr, sizeloc); +} + +static inline +int babeltrace_close_memstream(char **buf, size_t *size, FILE *fp) +{ + return fclose(fp); +} + +#else /* BABELTRACE_HAVE_OPEN_MEMSTREAM */ + +#include +#include + +/* + * Fallback for systems which don't have open_memstream. Create FILE * + * with babeltrace_open_memstream, but require call to + * babeltrace_close_memstream to flush all data written to the FILE * + * into the buffer (which we allocate). + */ +static inline +FILE *babeltrace_open_memstream(char **ptr, size_t *sizeloc) +{ + char tmpname[PATH_MAX]; + int ret; + FILE *fp; + + strncpy(tmpname, "/tmp/babeltrace-tmp-XXXXXX", PATH_MAX); + ret = mkstemp(tmpname); + if (ret < 0) { + return NULL; + } + fp = fdopen(ret, "w+"); + if (!fp) { + goto error_unlink; + } + /* + * babeltrace_flush_memstream will update the buffer content + * with read from fp. No need to keep the file around, just the + * handle. + */ + ret = unlink(tmpname); + if (ret < 0) { + perror("unlink"); + } + return fp; + +error_unlink: + ret = unlink(tmpname); + if (ret < 0) { + perror("unlink"); + } + return NULL; +} + +/* Get file size, allocate buffer, copy. */ +static inline +int babeltrace_close_memstream(char **buf, size_t *size, FILE *fp) +{ + size_t len, n; + long pos; + int ret; + + ret = fflush(fp); + if (ret < 0) { + perror("fflush"); + return ret; + } + ret = fseek(fp, 0L, SEEK_END); + if (ret < 0) { + perror("fseek"); + return ret; + } + pos = ftell(fp); + if (ret < 0) { + perror("ftell"); + return ret; + } + *size = pos; + /* add final \0 */ + *buf = calloc(pos + 1, sizeof(char)); + if (!*buf) { + return -ENOMEM; + } + ret = fseek(fp, 0L, SEEK_SET); + if (ret < 0) { + perror("fseek"); + goto error_free; + } + /* Copy the entire file into the buffer */ + n = 0; + clearerr(fp); + while (!feof(fp) && !ferror(fp) && (*size - n > 0)) { + len = fread(*buf, sizeof(char), *size - n, fp); + n += len; + } + if (n != *size) { + ret = -1; + goto error_close; + } + ret = fclose(fp); + if (ret < 0) { + perror("fclose"); + return ret; + } + return 0; + +error_close: + ret = fclose(fp); + if (ret < 0) { + perror("fclose"); + } +error_free: + free(*buf); + *buf = NULL; + return ret; +} + +#endif /* BABELTRACE_HAVE_OPEN_MEMSTREAM */ + +#endif /* _BABELTRACE_FORMAT_CTF_MEMSTREAM_H */ -- 2.34.1