Port: unlink() requires unistd.h on Solaris and macOS
[babeltrace.git] / include / babeltrace / compat / memstream-internal.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 *
eb31c5e6
MD
11 * Permission is hereby granted, free of charge, to any person obtaining a copy
12 * of this software and associated documentation files (the "Software"), to deal
13 * in the Software without restriction, including without limitation the rights
14 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
15 * copies of the Software, and to permit persons to whom the Software is
16 * furnished to do so, subject to the following conditions:
f8370579 17 *
eb31c5e6
MD
18 * The above copyright notice and this permission notice shall be included in
19 * all copies or substantial portions of the Software.
c462e188
MD
20 *
21 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
22 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
23 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
24 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
25 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
26 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
27 * SOFTWARE.
f8370579
MD
28 */
29
f8370579
MD
30#ifdef BABELTRACE_HAVE_FMEMOPEN
31#include <stdio.h>
32
33static inline
0cbbc8b8 34FILE *bt_fmemopen(void *buf, size_t size, const char *mode)
f8370579
MD
35{
36 return fmemopen(buf, size, mode);
37}
38
39#else /* BABELTRACE_HAVE_FMEMOPEN */
40
b8d6e1fc 41#include <unistd.h>
f8370579
MD
42#include <stdlib.h>
43#include <stdio.h>
b776eaa4
MJ
44#include <string.h>
45#include <errno.h>
46#include <babeltrace/endian-internal.h>
47
48#ifdef __MINGW32__
49
50#include <io.h>
51#include <glib.h>
f8370579
MD
52
53/*
54 * Fallback for systems which don't have fmemopen. Copy buffer to a
55 * temporary file, and use that file as FILE * input.
56 */
57static inline
0cbbc8b8 58FILE *bt_fmemopen(void *buf, size_t size, const char *mode)
f8370579 59{
b776eaa4 60 char *tmpname;
f8370579
MD
61 size_t len;
62 FILE *fp;
63 int ret;
64
65 /*
66 * Support reading only.
67 */
68 if (strcmp(mode, "rb") != 0) {
69 return NULL;
70 }
b776eaa4
MJ
71
72 /* Build a temporary filename */
73 tmpname = g_build_filename(g_get_tmp_dir(), "babeltrace-tmp-XXXXXX", NULL);
74 if (_mktemp(tmpname) == NULL) {
75 goto error_free;
76 }
77
78 /*
79 * Open as a read/write binary temporary deleted on close file.
80 * Will be deleted when the last file pointer is closed.
81 */
82 fp = fopen(tmpname, "w+bTD");
83 if (!fp) {
84 goto error_free;
85 }
86
87 /* Copy the entire buffer to the file */
88 len = fwrite(buf, sizeof(char), size, fp);
89 if (len != size) {
90 goto error_close;
91 }
92
93 /* Set the file pointer to the start of file */
94 ret = fseek(fp, 0L, SEEK_SET);
95 if (ret < 0) {
96 perror("fseek");
97 goto error_close;
98 }
99
100 g_free(tmpname);
101 return fp;
102
103error_close:
104 ret = fclose(fp);
105 if (ret < 0) {
106 perror("close");
107 }
108error_free:
109 g_free(tmpname);
110 return NULL;
111}
112
113#else /* __MINGW32__ */
114
115/*
116 * Fallback for systems which don't have fmemopen. Copy buffer to a
117 * temporary file, and use that file as FILE * input.
118 */
119static inline
120FILE *bt_fmemopen(void *buf, size_t size, const char *mode)
121{
122 char *tmpname;
123 size_t len;
124 FILE *fp;
125 int ret;
126
127 /*
128 * Support reading only.
129 */
130 if (strcmp(mode, "rb") != 0) {
131 return NULL;
132 }
133
134 tmpname = g_build_filename(g_get_tmp_dir(), "babeltrace-tmp-XXXXXX", NULL);
f8370579
MD
135 ret = mkstemp(tmpname);
136 if (ret < 0) {
b776eaa4 137 g_free(tmpname);
f8370579
MD
138 return NULL;
139 }
140 /*
141 * We need to write to the file.
142 */
143 fp = fdopen(ret, "w+");
144 if (!fp) {
145 goto error_unlink;
146 }
147 /* Copy the entire buffer to the file */
148 len = fwrite(buf, sizeof(char), size, fp);
149 if (len != size) {
150 goto error_close;
151 }
152 ret = fseek(fp, 0L, SEEK_SET);
153 if (ret < 0) {
154 perror("fseek");
155 goto error_close;
156 }
157 /* We keep the handle open, but can unlink the file on the VFS. */
158 ret = unlink(tmpname);
159 if (ret < 0) {
160 perror("unlink");
161 }
b776eaa4 162 g_free(tmpname);
f8370579
MD
163 return fp;
164
165error_close:
166 ret = fclose(fp);
167 if (ret < 0) {
168 perror("close");
169 }
170error_unlink:
171 ret = unlink(tmpname);
172 if (ret < 0) {
173 perror("unlink");
174 }
b776eaa4 175 g_free(tmpname);
f8370579
MD
176 return NULL;
177}
178
b776eaa4
MJ
179#endif /* __MINGW32__ */
180
f8370579
MD
181#endif /* BABELTRACE_HAVE_FMEMOPEN */
182
b776eaa4 183
f8370579
MD
184#ifdef BABELTRACE_HAVE_OPEN_MEMSTREAM
185
186#include <stdio.h>
187
188static inline
0cbbc8b8 189FILE *bt_open_memstream(char **ptr, size_t *sizeloc)
f8370579
MD
190{
191 return open_memstream(ptr, sizeloc);
192}
193
194static inline
0cbbc8b8 195int bt_close_memstream(char **buf, size_t *size, FILE *fp)
f8370579
MD
196{
197 return fclose(fp);
198}
199
200#else /* BABELTRACE_HAVE_OPEN_MEMSTREAM */
201
202#include <stdlib.h>
203#include <stdio.h>
b776eaa4
MJ
204#include <glib.h>
205
206#ifdef __MINGW32__
207
208/*
209 * Fallback for systems which don't have open_memstream. Create FILE *
210 * with bt_open_memstream, but require call to
211 * bt_close_memstream to flush all data written to the FILE *
212 * into the buffer (which we allocate).
213 */
214static inline
215FILE *bt_open_memstream(char **ptr, size_t *sizeloc)
216{
217 char *tmpname;
218 FILE *fp;
219
220 tmpname = g_build_filename(g_get_tmp_dir(), "babeltrace-tmp-XXXXXX", NULL);
221
222 if (_mktemp(tmpname) == NULL) {
223 goto error_free;
224 }
225
226 /*
227 * Open as a read/write binary temporary deleted on close file.
228 * Will be deleted when the last file pointer is closed.
229 */
230 fp = fopen(tmpname, "w+bTD");
231 if (!fp) {
232 goto error_free;
233 }
234
235 g_free(tmpname);
236 return fp;
237
238error_free:
239 g_free(tmpname);
240 return NULL;
241}
242
243#else /* __MINGW32__ */
f8370579
MD
244
245/*
246 * Fallback for systems which don't have open_memstream. Create FILE *
0cbbc8b8
MJ
247 * with bt_open_memstream, but require call to
248 * bt_close_memstream to flush all data written to the FILE *
f8370579
MD
249 * into the buffer (which we allocate).
250 */
251static inline
0cbbc8b8 252FILE *bt_open_memstream(char **ptr, size_t *sizeloc)
f8370579 253{
b776eaa4 254 char *tmpname;
f8370579
MD
255 int ret;
256 FILE *fp;
257
b776eaa4
MJ
258 tmpname = g_build_filename(g_get_tmp_dir(), "babeltrace-tmp-XXXXXX", NULL);
259
f8370579
MD
260 ret = mkstemp(tmpname);
261 if (ret < 0) {
b776eaa4
MJ
262 perror("mkstemp");
263 g_free(tmpname);
f8370579
MD
264 return NULL;
265 }
266 fp = fdopen(ret, "w+");
267 if (!fp) {
268 goto error_unlink;
269 }
270 /*
271 * babeltrace_flush_memstream will update the buffer content
272 * with read from fp. No need to keep the file around, just the
273 * handle.
274 */
275 ret = unlink(tmpname);
276 if (ret < 0) {
277 perror("unlink");
278 }
b776eaa4 279 g_free(tmpname);
f8370579
MD
280 return fp;
281
282error_unlink:
283 ret = unlink(tmpname);
284 if (ret < 0) {
285 perror("unlink");
286 }
b776eaa4 287 g_free(tmpname);
f8370579
MD
288 return NULL;
289}
290
b776eaa4
MJ
291#endif /* __MINGW32__ */
292
f8370579
MD
293/* Get file size, allocate buffer, copy. */
294static inline
0cbbc8b8 295int bt_close_memstream(char **buf, size_t *size, FILE *fp)
f8370579
MD
296{
297 size_t len, n;
298 long pos;
299 int ret;
300
301 ret = fflush(fp);
302 if (ret < 0) {
303 perror("fflush");
304 return ret;
305 }
306 ret = fseek(fp, 0L, SEEK_END);
307 if (ret < 0) {
308 perror("fseek");
309 return ret;
310 }
311 pos = ftell(fp);
312 if (ret < 0) {
313 perror("ftell");
314 return ret;
315 }
316 *size = pos;
317 /* add final \0 */
318 *buf = calloc(pos + 1, sizeof(char));
319 if (!*buf) {
320 return -ENOMEM;
321 }
322 ret = fseek(fp, 0L, SEEK_SET);
323 if (ret < 0) {
324 perror("fseek");
325 goto error_free;
326 }
327 /* Copy the entire file into the buffer */
328 n = 0;
329 clearerr(fp);
330 while (!feof(fp) && !ferror(fp) && (*size - n > 0)) {
331 len = fread(*buf, sizeof(char), *size - n, fp);
332 n += len;
333 }
334 if (n != *size) {
335 ret = -1;
336 goto error_close;
337 }
338 ret = fclose(fp);
339 if (ret < 0) {
340 perror("fclose");
341 return ret;
342 }
343 return 0;
344
345error_close:
346 ret = fclose(fp);
347 if (ret < 0) {
348 perror("fclose");
349 }
350error_free:
351 free(*buf);
352 *buf = NULL;
353 return ret;
354}
355
356#endif /* BABELTRACE_HAVE_OPEN_MEMSTREAM */
357
358#endif /* _BABELTRACE_FORMAT_CTF_MEMSTREAM_H */
This page took 0.056443 seconds and 4 git commands to generate.