Move to kernel style SPDX license identifiers
[babeltrace.git] / src / compat / memstream.h
CommitLineData
f8370579 1/*
0235b0db 2 * SPDX-License-Identifier: MIT
f8370579 3 *
0235b0db 4 * Copyright 2012 (c) Mathieu Desnoyers <mathieu.desnoyers@efficios.com>
f8370579 5 *
0235b0db 6 * memstream compatibility layer.
f8370579
MD
7 */
8
0235b0db
MJ
9#ifndef _BABELTRACE_FORMAT_CTF_MEMSTREAM_H
10#define _BABELTRACE_FORMAT_CTF_MEMSTREAM_H
11
f8370579
MD
12#ifdef BABELTRACE_HAVE_FMEMOPEN
13#include <stdio.h>
14
15static inline
0cbbc8b8 16FILE *bt_fmemopen(void *buf, size_t size, const char *mode)
f8370579
MD
17{
18 return fmemopen(buf, size, mode);
19}
20
21#else /* BABELTRACE_HAVE_FMEMOPEN */
22
b8d6e1fc 23#include <unistd.h>
f8370579
MD
24#include <stdlib.h>
25#include <stdio.h>
b776eaa4
MJ
26#include <string.h>
27#include <errno.h>
578e048b 28#include "compat/endian.h"
b776eaa4
MJ
29
30#ifdef __MINGW32__
31
32#include <io.h>
33#include <glib.h>
f8370579
MD
34
35/*
36 * Fallback for systems which don't have fmemopen. Copy buffer to a
37 * temporary file, and use that file as FILE * input.
38 */
39static inline
0cbbc8b8 40FILE *bt_fmemopen(void *buf, size_t size, const char *mode)
f8370579 41{
b776eaa4 42 char *tmpname;
f8370579
MD
43 size_t len;
44 FILE *fp;
45 int ret;
46
47 /*
48 * Support reading only.
49 */
50 if (strcmp(mode, "rb") != 0) {
51 return NULL;
52 }
b776eaa4
MJ
53
54 /* Build a temporary filename */
55 tmpname = g_build_filename(g_get_tmp_dir(), "babeltrace-tmp-XXXXXX", NULL);
5084732e 56 if (!_mktemp(tmpname)) {
b776eaa4
MJ
57 goto error_free;
58 }
59
60 /*
61 * Open as a read/write binary temporary deleted on close file.
62 * Will be deleted when the last file pointer is closed.
63 */
64 fp = fopen(tmpname, "w+bTD");
65 if (!fp) {
66 goto error_free;
67 }
68
69 /* Copy the entire buffer to the file */
70 len = fwrite(buf, sizeof(char), size, fp);
71 if (len != size) {
72 goto error_close;
73 }
74
75 /* Set the file pointer to the start of file */
76 ret = fseek(fp, 0L, SEEK_SET);
77 if (ret < 0) {
78 perror("fseek");
79 goto error_close;
80 }
81
82 g_free(tmpname);
83 return fp;
84
85error_close:
86 ret = fclose(fp);
87 if (ret < 0) {
88 perror("close");
89 }
90error_free:
91 g_free(tmpname);
92 return NULL;
93}
94
95#else /* __MINGW32__ */
96
97/*
98 * Fallback for systems which don't have fmemopen. Copy buffer to a
99 * temporary file, and use that file as FILE * input.
100 */
101static inline
102FILE *bt_fmemopen(void *buf, size_t size, const char *mode)
103{
104 char *tmpname;
105 size_t len;
106 FILE *fp;
107 int ret;
108
109 /*
110 * Support reading only.
111 */
112 if (strcmp(mode, "rb") != 0) {
113 return NULL;
114 }
115
116 tmpname = g_build_filename(g_get_tmp_dir(), "babeltrace-tmp-XXXXXX", NULL);
f8370579
MD
117 ret = mkstemp(tmpname);
118 if (ret < 0) {
b776eaa4 119 g_free(tmpname);
f8370579
MD
120 return NULL;
121 }
122 /*
123 * We need to write to the file.
124 */
7eb22883 125 fp = fdopen(ret, "wb+");
f8370579
MD
126 if (!fp) {
127 goto error_unlink;
128 }
129 /* Copy the entire buffer to the file */
130 len = fwrite(buf, sizeof(char), size, fp);
131 if (len != size) {
132 goto error_close;
133 }
134 ret = fseek(fp, 0L, SEEK_SET);
135 if (ret < 0) {
136 perror("fseek");
137 goto error_close;
138 }
139 /* We keep the handle open, but can unlink the file on the VFS. */
140 ret = unlink(tmpname);
141 if (ret < 0) {
142 perror("unlink");
143 }
b776eaa4 144 g_free(tmpname);
f8370579
MD
145 return fp;
146
147error_close:
148 ret = fclose(fp);
149 if (ret < 0) {
150 perror("close");
151 }
152error_unlink:
153 ret = unlink(tmpname);
154 if (ret < 0) {
155 perror("unlink");
156 }
b776eaa4 157 g_free(tmpname);
f8370579
MD
158 return NULL;
159}
160
b776eaa4
MJ
161#endif /* __MINGW32__ */
162
f8370579
MD
163#endif /* BABELTRACE_HAVE_FMEMOPEN */
164
b776eaa4 165
f8370579
MD
166#ifdef BABELTRACE_HAVE_OPEN_MEMSTREAM
167
168#include <stdio.h>
169
170static inline
0cbbc8b8 171FILE *bt_open_memstream(char **ptr, size_t *sizeloc)
f8370579
MD
172{
173 return open_memstream(ptr, sizeloc);
174}
175
176static inline
0cbbc8b8 177int bt_close_memstream(char **buf, size_t *size, FILE *fp)
f8370579
MD
178{
179 return fclose(fp);
180}
181
182#else /* BABELTRACE_HAVE_OPEN_MEMSTREAM */
183
184#include <stdlib.h>
185#include <stdio.h>
b776eaa4
MJ
186#include <glib.h>
187
188#ifdef __MINGW32__
189
190/*
191 * Fallback for systems which don't have open_memstream. Create FILE *
192 * with bt_open_memstream, but require call to
193 * bt_close_memstream to flush all data written to the FILE *
194 * into the buffer (which we allocate).
195 */
196static inline
197FILE *bt_open_memstream(char **ptr, size_t *sizeloc)
198{
199 char *tmpname;
200 FILE *fp;
201
202 tmpname = g_build_filename(g_get_tmp_dir(), "babeltrace-tmp-XXXXXX", NULL);
203
5084732e 204 if (!_mktemp(tmpname)) {
b776eaa4
MJ
205 goto error_free;
206 }
207
208 /*
209 * Open as a read/write binary temporary deleted on close file.
210 * Will be deleted when the last file pointer is closed.
211 */
212 fp = fopen(tmpname, "w+bTD");
213 if (!fp) {
214 goto error_free;
215 }
216
217 g_free(tmpname);
218 return fp;
219
220error_free:
221 g_free(tmpname);
222 return NULL;
223}
224
225#else /* __MINGW32__ */
f8370579
MD
226
227/*
228 * Fallback for systems which don't have open_memstream. Create FILE *
0cbbc8b8
MJ
229 * with bt_open_memstream, but require call to
230 * bt_close_memstream to flush all data written to the FILE *
f8370579
MD
231 * into the buffer (which we allocate).
232 */
233static inline
0cbbc8b8 234FILE *bt_open_memstream(char **ptr, size_t *sizeloc)
f8370579 235{
b776eaa4 236 char *tmpname;
f8370579
MD
237 int ret;
238 FILE *fp;
239
b776eaa4
MJ
240 tmpname = g_build_filename(g_get_tmp_dir(), "babeltrace-tmp-XXXXXX", NULL);
241
f8370579
MD
242 ret = mkstemp(tmpname);
243 if (ret < 0) {
b776eaa4
MJ
244 perror("mkstemp");
245 g_free(tmpname);
f8370579
MD
246 return NULL;
247 }
7eb22883 248 fp = fdopen(ret, "wb+");
f8370579
MD
249 if (!fp) {
250 goto error_unlink;
251 }
252 /*
253 * babeltrace_flush_memstream will update the buffer content
254 * with read from fp. No need to keep the file around, just the
255 * handle.
256 */
257 ret = unlink(tmpname);
258 if (ret < 0) {
259 perror("unlink");
260 }
b776eaa4 261 g_free(tmpname);
f8370579
MD
262 return fp;
263
264error_unlink:
265 ret = unlink(tmpname);
266 if (ret < 0) {
267 perror("unlink");
268 }
b776eaa4 269 g_free(tmpname);
f8370579
MD
270 return NULL;
271}
272
b776eaa4
MJ
273#endif /* __MINGW32__ */
274
f8370579
MD
275/* Get file size, allocate buffer, copy. */
276static inline
0cbbc8b8 277int bt_close_memstream(char **buf, size_t *size, FILE *fp)
f8370579
MD
278{
279 size_t len, n;
280 long pos;
281 int ret;
282
283 ret = fflush(fp);
284 if (ret < 0) {
285 perror("fflush");
286 return ret;
287 }
288 ret = fseek(fp, 0L, SEEK_END);
289 if (ret < 0) {
290 perror("fseek");
291 return ret;
292 }
293 pos = ftell(fp);
294 if (ret < 0) {
295 perror("ftell");
296 return ret;
297 }
298 *size = pos;
299 /* add final \0 */
300 *buf = calloc(pos + 1, sizeof(char));
301 if (!*buf) {
302 return -ENOMEM;
303 }
304 ret = fseek(fp, 0L, SEEK_SET);
305 if (ret < 0) {
306 perror("fseek");
307 goto error_free;
308 }
309 /* Copy the entire file into the buffer */
310 n = 0;
311 clearerr(fp);
312 while (!feof(fp) && !ferror(fp) && (*size - n > 0)) {
313 len = fread(*buf, sizeof(char), *size - n, fp);
314 n += len;
315 }
316 if (n != *size) {
317 ret = -1;
318 goto error_close;
319 }
320 ret = fclose(fp);
321 if (ret < 0) {
322 perror("fclose");
323 return ret;
324 }
325 return 0;
326
327error_close:
328 ret = fclose(fp);
329 if (ret < 0) {
330 perror("fclose");
331 }
332error_free:
333 free(*buf);
334 *buf = NULL;
335 return ret;
336}
337
338#endif /* BABELTRACE_HAVE_OPEN_MEMSTREAM */
339
340#endif /* _BABELTRACE_FORMAT_CTF_MEMSTREAM_H */
This page took 0.094068 seconds and 4 git commands to generate.