Implement fallback for systems lacking open_memstream and fopenmem
[babeltrace.git] / formats / ctf / memstream.h
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
27 static inline
28 FILE *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 */
42 static inline
43 FILE *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
85 error_close:
86 ret = fclose(fp);
87 if (ret < 0) {
88 perror("close");
89 }
90 error_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
104 static inline
105 FILE *babeltrace_open_memstream(char **ptr, size_t *sizeloc)
106 {
107 return open_memstream(ptr, sizeloc);
108 }
109
110 static inline
111 int 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 */
127 static inline
128 FILE *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
154 error_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. */
163 static inline
164 int 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
214 error_close:
215 ret = fclose(fp);
216 if (ret < 0) {
217 perror("fclose");
218 }
219 error_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.052078 seconds and 4 git commands to generate.