Implement fallback for systems lacking open_memstream and fopenmem
[babeltrace.git] / formats / ctf / memstream.h
CommitLineData
f8370579
MD
1#ifndef _BABELTRACE_FORMAT_CTF_MEMSTREAM_H
2#define _BABELTRACE_FORMAT_CTF_MEMSTREAM_H
3
4/*
5 * format/ctf/memstream.h
6 *
7 * Copyright 2012 (c) - Mathieu Desnoyers <mathieu.desnoyers@efficios.com>
8 *
9 * memstream compatibility layer.
10 *
11 * THIS MATERIAL IS PROVIDED AS IS, WITH ABSOLUTELY NO WARRANTY EXPRESSED
12 * OR IMPLIED. ANY USE IS AT YOUR OWN RISK.
13 *
14 * Permission is hereby granted to use or copy this program
15 * for any purpose, provided the above notices are retained on all copies.
16 * Permission to modify the code and to distribute modified code is granted,
17 * provided the above notices are retained, and a notice that the code was
18 * modified is included with the above copyright notice.
19 */
20
21#define _GNU_SOURCE
22#include <config.h>
23
24#ifdef BABELTRACE_HAVE_FMEMOPEN
25#include <stdio.h>
26
27static inline
28FILE *babeltrace_fmemopen(void *buf, size_t size, const char *mode)
29{
30 return fmemopen(buf, size, mode);
31}
32
33#else /* BABELTRACE_HAVE_FMEMOPEN */
34
35#include <stdlib.h>
36#include <stdio.h>
37
38/*
39 * Fallback for systems which don't have fmemopen. Copy buffer to a
40 * temporary file, and use that file as FILE * input.
41 */
42static inline
43FILE *babeltrace_fmemopen(void *buf, size_t size, const char *mode)
44{
45 char tmpname[PATH_MAX];
46 size_t len;
47 FILE *fp;
48 int ret;
49
50 /*
51 * Support reading only.
52 */
53 if (strcmp(mode, "rb") != 0) {
54 return NULL;
55 }
56 strncpy(tmpname, "/tmp/babeltrace-tmp-XXXXXX", PATH_MAX);
57 ret = mkstemp(tmpname);
58 if (ret < 0) {
59 return NULL;
60 }
61 /*
62 * We need to write to the file.
63 */
64 fp = fdopen(ret, "w+");
65 if (!fp) {
66 goto error_unlink;
67 }
68 /* Copy the entire buffer to the file */
69 len = fwrite(buf, sizeof(char), size, fp);
70 if (len != size) {
71 goto error_close;
72 }
73 ret = fseek(fp, 0L, SEEK_SET);
74 if (ret < 0) {
75 perror("fseek");
76 goto error_close;
77 }
78 /* We keep the handle open, but can unlink the file on the VFS. */
79 ret = unlink(tmpname);
80 if (ret < 0) {
81 perror("unlink");
82 }
83 return fp;
84
85error_close:
86 ret = fclose(fp);
87 if (ret < 0) {
88 perror("close");
89 }
90error_unlink:
91 ret = unlink(tmpname);
92 if (ret < 0) {
93 perror("unlink");
94 }
95 return NULL;
96}
97
98#endif /* BABELTRACE_HAVE_FMEMOPEN */
99
100#ifdef BABELTRACE_HAVE_OPEN_MEMSTREAM
101
102#include <stdio.h>
103
104static inline
105FILE *babeltrace_open_memstream(char **ptr, size_t *sizeloc)
106{
107 return open_memstream(ptr, sizeloc);
108}
109
110static inline
111int babeltrace_close_memstream(char **buf, size_t *size, FILE *fp)
112{
113 return fclose(fp);
114}
115
116#else /* BABELTRACE_HAVE_OPEN_MEMSTREAM */
117
118#include <stdlib.h>
119#include <stdio.h>
120
121/*
122 * Fallback for systems which don't have open_memstream. Create FILE *
123 * with babeltrace_open_memstream, but require call to
124 * babeltrace_close_memstream to flush all data written to the FILE *
125 * into the buffer (which we allocate).
126 */
127static inline
128FILE *babeltrace_open_memstream(char **ptr, size_t *sizeloc)
129{
130 char tmpname[PATH_MAX];
131 int ret;
132 FILE *fp;
133
134 strncpy(tmpname, "/tmp/babeltrace-tmp-XXXXXX", PATH_MAX);
135 ret = mkstemp(tmpname);
136 if (ret < 0) {
137 return NULL;
138 }
139 fp = fdopen(ret, "w+");
140 if (!fp) {
141 goto error_unlink;
142 }
143 /*
144 * babeltrace_flush_memstream will update the buffer content
145 * with read from fp. No need to keep the file around, just the
146 * handle.
147 */
148 ret = unlink(tmpname);
149 if (ret < 0) {
150 perror("unlink");
151 }
152 return fp;
153
154error_unlink:
155 ret = unlink(tmpname);
156 if (ret < 0) {
157 perror("unlink");
158 }
159 return NULL;
160}
161
162/* Get file size, allocate buffer, copy. */
163static inline
164int babeltrace_close_memstream(char **buf, size_t *size, FILE *fp)
165{
166 size_t len, n;
167 long pos;
168 int ret;
169
170 ret = fflush(fp);
171 if (ret < 0) {
172 perror("fflush");
173 return ret;
174 }
175 ret = fseek(fp, 0L, SEEK_END);
176 if (ret < 0) {
177 perror("fseek");
178 return ret;
179 }
180 pos = ftell(fp);
181 if (ret < 0) {
182 perror("ftell");
183 return ret;
184 }
185 *size = pos;
186 /* add final \0 */
187 *buf = calloc(pos + 1, sizeof(char));
188 if (!*buf) {
189 return -ENOMEM;
190 }
191 ret = fseek(fp, 0L, SEEK_SET);
192 if (ret < 0) {
193 perror("fseek");
194 goto error_free;
195 }
196 /* Copy the entire file into the buffer */
197 n = 0;
198 clearerr(fp);
199 while (!feof(fp) && !ferror(fp) && (*size - n > 0)) {
200 len = fread(*buf, sizeof(char), *size - n, fp);
201 n += len;
202 }
203 if (n != *size) {
204 ret = -1;
205 goto error_close;
206 }
207 ret = fclose(fp);
208 if (ret < 0) {
209 perror("fclose");
210 return ret;
211 }
212 return 0;
213
214error_close:
215 ret = fclose(fp);
216 if (ret < 0) {
217 perror("fclose");
218 }
219error_free:
220 free(*buf);
221 *buf = NULL;
222 return ret;
223}
224
225#endif /* BABELTRACE_HAVE_OPEN_MEMSTREAM */
226
227#endif /* _BABELTRACE_FORMAT_CTF_MEMSTREAM_H */
This page took 0.030655 seconds and 4 git commands to generate.