Move to kernel style SPDX license identifiers
[babeltrace.git] / src / compat / memstream.h
1 /*
2 * SPDX-License-Identifier: MIT
3 *
4 * Copyright 2012 (c) Mathieu Desnoyers <mathieu.desnoyers@efficios.com>
5 *
6 * memstream compatibility layer.
7 */
8
9 #ifndef _BABELTRACE_FORMAT_CTF_MEMSTREAM_H
10 #define _BABELTRACE_FORMAT_CTF_MEMSTREAM_H
11
12 #ifdef BABELTRACE_HAVE_FMEMOPEN
13 #include <stdio.h>
14
15 static inline
16 FILE *bt_fmemopen(void *buf, size_t size, const char *mode)
17 {
18 return fmemopen(buf, size, mode);
19 }
20
21 #else /* BABELTRACE_HAVE_FMEMOPEN */
22
23 #include <unistd.h>
24 #include <stdlib.h>
25 #include <stdio.h>
26 #include <string.h>
27 #include <errno.h>
28 #include "compat/endian.h"
29
30 #ifdef __MINGW32__
31
32 #include <io.h>
33 #include <glib.h>
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 */
39 static inline
40 FILE *bt_fmemopen(void *buf, size_t size, const char *mode)
41 {
42 char *tmpname;
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 }
53
54 /* Build a temporary filename */
55 tmpname = g_build_filename(g_get_tmp_dir(), "babeltrace-tmp-XXXXXX", NULL);
56 if (!_mktemp(tmpname)) {
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
85 error_close:
86 ret = fclose(fp);
87 if (ret < 0) {
88 perror("close");
89 }
90 error_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 */
101 static inline
102 FILE *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);
117 ret = mkstemp(tmpname);
118 if (ret < 0) {
119 g_free(tmpname);
120 return NULL;
121 }
122 /*
123 * We need to write to the file.
124 */
125 fp = fdopen(ret, "wb+");
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 }
144 g_free(tmpname);
145 return fp;
146
147 error_close:
148 ret = fclose(fp);
149 if (ret < 0) {
150 perror("close");
151 }
152 error_unlink:
153 ret = unlink(tmpname);
154 if (ret < 0) {
155 perror("unlink");
156 }
157 g_free(tmpname);
158 return NULL;
159 }
160
161 #endif /* __MINGW32__ */
162
163 #endif /* BABELTRACE_HAVE_FMEMOPEN */
164
165
166 #ifdef BABELTRACE_HAVE_OPEN_MEMSTREAM
167
168 #include <stdio.h>
169
170 static inline
171 FILE *bt_open_memstream(char **ptr, size_t *sizeloc)
172 {
173 return open_memstream(ptr, sizeloc);
174 }
175
176 static inline
177 int bt_close_memstream(char **buf, size_t *size, FILE *fp)
178 {
179 return fclose(fp);
180 }
181
182 #else /* BABELTRACE_HAVE_OPEN_MEMSTREAM */
183
184 #include <stdlib.h>
185 #include <stdio.h>
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 */
196 static inline
197 FILE *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
204 if (!_mktemp(tmpname)) {
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
220 error_free:
221 g_free(tmpname);
222 return NULL;
223 }
224
225 #else /* __MINGW32__ */
226
227 /*
228 * Fallback for systems which don't have open_memstream. Create FILE *
229 * with bt_open_memstream, but require call to
230 * bt_close_memstream to flush all data written to the FILE *
231 * into the buffer (which we allocate).
232 */
233 static inline
234 FILE *bt_open_memstream(char **ptr, size_t *sizeloc)
235 {
236 char *tmpname;
237 int ret;
238 FILE *fp;
239
240 tmpname = g_build_filename(g_get_tmp_dir(), "babeltrace-tmp-XXXXXX", NULL);
241
242 ret = mkstemp(tmpname);
243 if (ret < 0) {
244 perror("mkstemp");
245 g_free(tmpname);
246 return NULL;
247 }
248 fp = fdopen(ret, "wb+");
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 }
261 g_free(tmpname);
262 return fp;
263
264 error_unlink:
265 ret = unlink(tmpname);
266 if (ret < 0) {
267 perror("unlink");
268 }
269 g_free(tmpname);
270 return NULL;
271 }
272
273 #endif /* __MINGW32__ */
274
275 /* Get file size, allocate buffer, copy. */
276 static inline
277 int bt_close_memstream(char **buf, size_t *size, FILE *fp)
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
327 error_close:
328 ret = fclose(fp);
329 if (ret < 0) {
330 perror("fclose");
331 }
332 error_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.035719 seconds and 4 git commands to generate.