root / qemu-file.c @ 216db403
History | View | Annotate | Download (17.5 kB)
1 | 093c455a | Eduardo Habkost | #include "qemu-common.h" |
---|---|---|---|
2 | 093c455a | Eduardo Habkost | #include "qemu/iov.h" |
3 | 093c455a | Eduardo Habkost | #include "qemu/sockets.h" |
4 | 093c455a | Eduardo Habkost | #include "block/coroutine.h" |
5 | 093c455a | Eduardo Habkost | #include "migration/migration.h" |
6 | 093c455a | Eduardo Habkost | #include "migration/qemu-file.h" |
7 | 093c455a | Eduardo Habkost | |
8 | 093c455a | Eduardo Habkost | #define IO_BUF_SIZE 32768 |
9 | 093c455a | Eduardo Habkost | #define MAX_IOV_SIZE MIN(IOV_MAX, 64) |
10 | 093c455a | Eduardo Habkost | |
11 | 093c455a | Eduardo Habkost | struct QEMUFile {
|
12 | 093c455a | Eduardo Habkost | const QEMUFileOps *ops;
|
13 | 093c455a | Eduardo Habkost | void *opaque;
|
14 | 093c455a | Eduardo Habkost | |
15 | 093c455a | Eduardo Habkost | int64_t bytes_xfer; |
16 | 093c455a | Eduardo Habkost | int64_t xfer_limit; |
17 | 093c455a | Eduardo Habkost | |
18 | 093c455a | Eduardo Habkost | int64_t pos; /* start of buffer when writing, end of buffer
|
19 | 093c455a | Eduardo Habkost | when reading */
|
20 | 093c455a | Eduardo Habkost | int buf_index;
|
21 | 093c455a | Eduardo Habkost | int buf_size; /* 0 when writing */ |
22 | 093c455a | Eduardo Habkost | uint8_t buf[IO_BUF_SIZE]; |
23 | 093c455a | Eduardo Habkost | |
24 | 093c455a | Eduardo Habkost | struct iovec iov[MAX_IOV_SIZE];
|
25 | 093c455a | Eduardo Habkost | unsigned int iovcnt; |
26 | 093c455a | Eduardo Habkost | |
27 | 093c455a | Eduardo Habkost | int last_error;
|
28 | 093c455a | Eduardo Habkost | }; |
29 | 093c455a | Eduardo Habkost | |
30 | 093c455a | Eduardo Habkost | typedef struct QEMUFileStdio { |
31 | 093c455a | Eduardo Habkost | FILE *stdio_file; |
32 | 093c455a | Eduardo Habkost | QEMUFile *file; |
33 | 093c455a | Eduardo Habkost | } QEMUFileStdio; |
34 | 093c455a | Eduardo Habkost | |
35 | 093c455a | Eduardo Habkost | typedef struct QEMUFileSocket { |
36 | 093c455a | Eduardo Habkost | int fd;
|
37 | 093c455a | Eduardo Habkost | QEMUFile *file; |
38 | 093c455a | Eduardo Habkost | } QEMUFileSocket; |
39 | 093c455a | Eduardo Habkost | |
40 | 093c455a | Eduardo Habkost | static ssize_t socket_writev_buffer(void *opaque, struct iovec *iov, int iovcnt, |
41 | 093c455a | Eduardo Habkost | int64_t pos) |
42 | 093c455a | Eduardo Habkost | { |
43 | 093c455a | Eduardo Habkost | QEMUFileSocket *s = opaque; |
44 | 093c455a | Eduardo Habkost | ssize_t len; |
45 | 093c455a | Eduardo Habkost | ssize_t size = iov_size(iov, iovcnt); |
46 | 093c455a | Eduardo Habkost | |
47 | 093c455a | Eduardo Habkost | len = iov_send(s->fd, iov, iovcnt, 0, size);
|
48 | 093c455a | Eduardo Habkost | if (len < size) {
|
49 | 093c455a | Eduardo Habkost | len = -socket_error(); |
50 | 093c455a | Eduardo Habkost | } |
51 | 093c455a | Eduardo Habkost | return len;
|
52 | 093c455a | Eduardo Habkost | } |
53 | 093c455a | Eduardo Habkost | |
54 | 093c455a | Eduardo Habkost | static int socket_get_fd(void *opaque) |
55 | 093c455a | Eduardo Habkost | { |
56 | 093c455a | Eduardo Habkost | QEMUFileSocket *s = opaque; |
57 | 093c455a | Eduardo Habkost | |
58 | 093c455a | Eduardo Habkost | return s->fd;
|
59 | 093c455a | Eduardo Habkost | } |
60 | 093c455a | Eduardo Habkost | |
61 | 093c455a | Eduardo Habkost | static int socket_get_buffer(void *opaque, uint8_t *buf, int64_t pos, int size) |
62 | 093c455a | Eduardo Habkost | { |
63 | 093c455a | Eduardo Habkost | QEMUFileSocket *s = opaque; |
64 | 093c455a | Eduardo Habkost | ssize_t len; |
65 | 093c455a | Eduardo Habkost | |
66 | 093c455a | Eduardo Habkost | for (;;) {
|
67 | 093c455a | Eduardo Habkost | len = qemu_recv(s->fd, buf, size, 0);
|
68 | 093c455a | Eduardo Habkost | if (len != -1) { |
69 | 093c455a | Eduardo Habkost | break;
|
70 | 093c455a | Eduardo Habkost | } |
71 | 093c455a | Eduardo Habkost | if (socket_error() == EAGAIN) {
|
72 | 093c455a | Eduardo Habkost | yield_until_fd_readable(s->fd); |
73 | 093c455a | Eduardo Habkost | } else if (socket_error() != EINTR) { |
74 | 093c455a | Eduardo Habkost | break;
|
75 | 093c455a | Eduardo Habkost | } |
76 | 093c455a | Eduardo Habkost | } |
77 | 093c455a | Eduardo Habkost | |
78 | 093c455a | Eduardo Habkost | if (len == -1) { |
79 | 093c455a | Eduardo Habkost | len = -socket_error(); |
80 | 093c455a | Eduardo Habkost | } |
81 | 093c455a | Eduardo Habkost | return len;
|
82 | 093c455a | Eduardo Habkost | } |
83 | 093c455a | Eduardo Habkost | |
84 | 093c455a | Eduardo Habkost | static int socket_close(void *opaque) |
85 | 093c455a | Eduardo Habkost | { |
86 | 093c455a | Eduardo Habkost | QEMUFileSocket *s = opaque; |
87 | 093c455a | Eduardo Habkost | closesocket(s->fd); |
88 | 093c455a | Eduardo Habkost | g_free(s); |
89 | 093c455a | Eduardo Habkost | return 0; |
90 | 093c455a | Eduardo Habkost | } |
91 | 093c455a | Eduardo Habkost | |
92 | 093c455a | Eduardo Habkost | static int stdio_get_fd(void *opaque) |
93 | 093c455a | Eduardo Habkost | { |
94 | 093c455a | Eduardo Habkost | QEMUFileStdio *s = opaque; |
95 | 093c455a | Eduardo Habkost | |
96 | 093c455a | Eduardo Habkost | return fileno(s->stdio_file);
|
97 | 093c455a | Eduardo Habkost | } |
98 | 093c455a | Eduardo Habkost | |
99 | 093c455a | Eduardo Habkost | static int stdio_put_buffer(void *opaque, const uint8_t *buf, int64_t pos, |
100 | 093c455a | Eduardo Habkost | int size)
|
101 | 093c455a | Eduardo Habkost | { |
102 | 093c455a | Eduardo Habkost | QEMUFileStdio *s = opaque; |
103 | 093c455a | Eduardo Habkost | return fwrite(buf, 1, size, s->stdio_file); |
104 | 093c455a | Eduardo Habkost | } |
105 | 093c455a | Eduardo Habkost | |
106 | 093c455a | Eduardo Habkost | static int stdio_get_buffer(void *opaque, uint8_t *buf, int64_t pos, int size) |
107 | 093c455a | Eduardo Habkost | { |
108 | 093c455a | Eduardo Habkost | QEMUFileStdio *s = opaque; |
109 | 093c455a | Eduardo Habkost | FILE *fp = s->stdio_file; |
110 | 093c455a | Eduardo Habkost | int bytes;
|
111 | 093c455a | Eduardo Habkost | |
112 | 093c455a | Eduardo Habkost | for (;;) {
|
113 | 093c455a | Eduardo Habkost | clearerr(fp); |
114 | 093c455a | Eduardo Habkost | bytes = fread(buf, 1, size, fp);
|
115 | 093c455a | Eduardo Habkost | if (bytes != 0 || !ferror(fp)) { |
116 | 093c455a | Eduardo Habkost | break;
|
117 | 093c455a | Eduardo Habkost | } |
118 | 093c455a | Eduardo Habkost | if (errno == EAGAIN) {
|
119 | 093c455a | Eduardo Habkost | yield_until_fd_readable(fileno(fp)); |
120 | 093c455a | Eduardo Habkost | } else if (errno != EINTR) { |
121 | 093c455a | Eduardo Habkost | break;
|
122 | 093c455a | Eduardo Habkost | } |
123 | 093c455a | Eduardo Habkost | } |
124 | 093c455a | Eduardo Habkost | return bytes;
|
125 | 093c455a | Eduardo Habkost | } |
126 | 093c455a | Eduardo Habkost | |
127 | 093c455a | Eduardo Habkost | static int stdio_pclose(void *opaque) |
128 | 093c455a | Eduardo Habkost | { |
129 | 093c455a | Eduardo Habkost | QEMUFileStdio *s = opaque; |
130 | 093c455a | Eduardo Habkost | int ret;
|
131 | 093c455a | Eduardo Habkost | ret = pclose(s->stdio_file); |
132 | 093c455a | Eduardo Habkost | if (ret == -1) { |
133 | 093c455a | Eduardo Habkost | ret = -errno; |
134 | 093c455a | Eduardo Habkost | } else if (!WIFEXITED(ret) || WEXITSTATUS(ret) != 0) { |
135 | 093c455a | Eduardo Habkost | /* close succeeded, but non-zero exit code: */
|
136 | 093c455a | Eduardo Habkost | ret = -EIO; /* fake errno value */
|
137 | 093c455a | Eduardo Habkost | } |
138 | 093c455a | Eduardo Habkost | g_free(s); |
139 | 093c455a | Eduardo Habkost | return ret;
|
140 | 093c455a | Eduardo Habkost | } |
141 | 093c455a | Eduardo Habkost | |
142 | 093c455a | Eduardo Habkost | static int stdio_fclose(void *opaque) |
143 | 093c455a | Eduardo Habkost | { |
144 | 093c455a | Eduardo Habkost | QEMUFileStdio *s = opaque; |
145 | 093c455a | Eduardo Habkost | int ret = 0; |
146 | 093c455a | Eduardo Habkost | |
147 | 093c455a | Eduardo Habkost | if (s->file->ops->put_buffer || s->file->ops->writev_buffer) {
|
148 | 093c455a | Eduardo Habkost | int fd = fileno(s->stdio_file);
|
149 | 093c455a | Eduardo Habkost | struct stat st;
|
150 | 093c455a | Eduardo Habkost | |
151 | 093c455a | Eduardo Habkost | ret = fstat(fd, &st); |
152 | 093c455a | Eduardo Habkost | if (ret == 0 && S_ISREG(st.st_mode)) { |
153 | 093c455a | Eduardo Habkost | /*
|
154 | 093c455a | Eduardo Habkost | * If the file handle is a regular file make sure the
|
155 | 093c455a | Eduardo Habkost | * data is flushed to disk before signaling success.
|
156 | 093c455a | Eduardo Habkost | */
|
157 | 093c455a | Eduardo Habkost | ret = fsync(fd); |
158 | 093c455a | Eduardo Habkost | if (ret != 0) { |
159 | 093c455a | Eduardo Habkost | ret = -errno; |
160 | 093c455a | Eduardo Habkost | return ret;
|
161 | 093c455a | Eduardo Habkost | } |
162 | 093c455a | Eduardo Habkost | } |
163 | 093c455a | Eduardo Habkost | } |
164 | 093c455a | Eduardo Habkost | if (fclose(s->stdio_file) == EOF) { |
165 | 093c455a | Eduardo Habkost | ret = -errno; |
166 | 093c455a | Eduardo Habkost | } |
167 | 093c455a | Eduardo Habkost | g_free(s); |
168 | 093c455a | Eduardo Habkost | return ret;
|
169 | 093c455a | Eduardo Habkost | } |
170 | 093c455a | Eduardo Habkost | |
171 | 093c455a | Eduardo Habkost | static const QEMUFileOps stdio_pipe_read_ops = { |
172 | 093c455a | Eduardo Habkost | .get_fd = stdio_get_fd, |
173 | 093c455a | Eduardo Habkost | .get_buffer = stdio_get_buffer, |
174 | 093c455a | Eduardo Habkost | .close = stdio_pclose |
175 | 093c455a | Eduardo Habkost | }; |
176 | 093c455a | Eduardo Habkost | |
177 | 093c455a | Eduardo Habkost | static const QEMUFileOps stdio_pipe_write_ops = { |
178 | 093c455a | Eduardo Habkost | .get_fd = stdio_get_fd, |
179 | 093c455a | Eduardo Habkost | .put_buffer = stdio_put_buffer, |
180 | 093c455a | Eduardo Habkost | .close = stdio_pclose |
181 | 093c455a | Eduardo Habkost | }; |
182 | 093c455a | Eduardo Habkost | |
183 | 093c455a | Eduardo Habkost | QEMUFile *qemu_popen_cmd(const char *command, const char *mode) |
184 | 093c455a | Eduardo Habkost | { |
185 | 093c455a | Eduardo Habkost | FILE *stdio_file; |
186 | 093c455a | Eduardo Habkost | QEMUFileStdio *s; |
187 | 093c455a | Eduardo Habkost | |
188 | 093c455a | Eduardo Habkost | if (mode == NULL || (mode[0] != 'r' && mode[0] != 'w') || mode[1] != 0) { |
189 | 093c455a | Eduardo Habkost | fprintf(stderr, "qemu_popen: Argument validity check failed\n");
|
190 | 093c455a | Eduardo Habkost | return NULL; |
191 | 093c455a | Eduardo Habkost | } |
192 | 093c455a | Eduardo Habkost | |
193 | 093c455a | Eduardo Habkost | stdio_file = popen(command, mode); |
194 | 093c455a | Eduardo Habkost | if (stdio_file == NULL) { |
195 | 093c455a | Eduardo Habkost | return NULL; |
196 | 093c455a | Eduardo Habkost | } |
197 | 093c455a | Eduardo Habkost | |
198 | 093c455a | Eduardo Habkost | s = g_malloc0(sizeof(QEMUFileStdio));
|
199 | 093c455a | Eduardo Habkost | |
200 | 093c455a | Eduardo Habkost | s->stdio_file = stdio_file; |
201 | 093c455a | Eduardo Habkost | |
202 | 093c455a | Eduardo Habkost | if (mode[0] == 'r') { |
203 | 093c455a | Eduardo Habkost | s->file = qemu_fopen_ops(s, &stdio_pipe_read_ops); |
204 | 093c455a | Eduardo Habkost | } else {
|
205 | 093c455a | Eduardo Habkost | s->file = qemu_fopen_ops(s, &stdio_pipe_write_ops); |
206 | 093c455a | Eduardo Habkost | } |
207 | 093c455a | Eduardo Habkost | return s->file;
|
208 | 093c455a | Eduardo Habkost | } |
209 | 093c455a | Eduardo Habkost | |
210 | 093c455a | Eduardo Habkost | static const QEMUFileOps stdio_file_read_ops = { |
211 | 093c455a | Eduardo Habkost | .get_fd = stdio_get_fd, |
212 | 093c455a | Eduardo Habkost | .get_buffer = stdio_get_buffer, |
213 | 093c455a | Eduardo Habkost | .close = stdio_fclose |
214 | 093c455a | Eduardo Habkost | }; |
215 | 093c455a | Eduardo Habkost | |
216 | 093c455a | Eduardo Habkost | static const QEMUFileOps stdio_file_write_ops = { |
217 | 093c455a | Eduardo Habkost | .get_fd = stdio_get_fd, |
218 | 093c455a | Eduardo Habkost | .put_buffer = stdio_put_buffer, |
219 | 093c455a | Eduardo Habkost | .close = stdio_fclose |
220 | 093c455a | Eduardo Habkost | }; |
221 | 093c455a | Eduardo Habkost | |
222 | 093c455a | Eduardo Habkost | static ssize_t unix_writev_buffer(void *opaque, struct iovec *iov, int iovcnt, |
223 | 093c455a | Eduardo Habkost | int64_t pos) |
224 | 093c455a | Eduardo Habkost | { |
225 | 093c455a | Eduardo Habkost | QEMUFileSocket *s = opaque; |
226 | 093c455a | Eduardo Habkost | ssize_t len, offset; |
227 | 093c455a | Eduardo Habkost | ssize_t size = iov_size(iov, iovcnt); |
228 | 093c455a | Eduardo Habkost | ssize_t total = 0;
|
229 | 093c455a | Eduardo Habkost | |
230 | 093c455a | Eduardo Habkost | assert(iovcnt > 0);
|
231 | 093c455a | Eduardo Habkost | offset = 0;
|
232 | 093c455a | Eduardo Habkost | while (size > 0) { |
233 | 093c455a | Eduardo Habkost | /* Find the next start position; skip all full-sized vector elements */
|
234 | 093c455a | Eduardo Habkost | while (offset >= iov[0].iov_len) { |
235 | 093c455a | Eduardo Habkost | offset -= iov[0].iov_len;
|
236 | 093c455a | Eduardo Habkost | iov++, iovcnt--; |
237 | 093c455a | Eduardo Habkost | } |
238 | 093c455a | Eduardo Habkost | |
239 | 093c455a | Eduardo Habkost | /* skip `offset' bytes from the (now) first element, undo it on exit */
|
240 | 093c455a | Eduardo Habkost | assert(iovcnt > 0);
|
241 | 093c455a | Eduardo Habkost | iov[0].iov_base += offset;
|
242 | 093c455a | Eduardo Habkost | iov[0].iov_len -= offset;
|
243 | 093c455a | Eduardo Habkost | |
244 | 093c455a | Eduardo Habkost | do {
|
245 | 093c455a | Eduardo Habkost | len = writev(s->fd, iov, iovcnt); |
246 | 093c455a | Eduardo Habkost | } while (len == -1 && errno == EINTR); |
247 | 093c455a | Eduardo Habkost | if (len == -1) { |
248 | 093c455a | Eduardo Habkost | return -errno;
|
249 | 093c455a | Eduardo Habkost | } |
250 | 093c455a | Eduardo Habkost | |
251 | 093c455a | Eduardo Habkost | /* Undo the changes above */
|
252 | 093c455a | Eduardo Habkost | iov[0].iov_base -= offset;
|
253 | 093c455a | Eduardo Habkost | iov[0].iov_len += offset;
|
254 | 093c455a | Eduardo Habkost | |
255 | 093c455a | Eduardo Habkost | /* Prepare for the next iteration */
|
256 | 093c455a | Eduardo Habkost | offset += len; |
257 | 093c455a | Eduardo Habkost | total += len; |
258 | 093c455a | Eduardo Habkost | size -= len; |
259 | 093c455a | Eduardo Habkost | } |
260 | 093c455a | Eduardo Habkost | |
261 | 093c455a | Eduardo Habkost | return total;
|
262 | 093c455a | Eduardo Habkost | } |
263 | 093c455a | Eduardo Habkost | |
264 | 093c455a | Eduardo Habkost | static int unix_get_buffer(void *opaque, uint8_t *buf, int64_t pos, int size) |
265 | 093c455a | Eduardo Habkost | { |
266 | 093c455a | Eduardo Habkost | QEMUFileSocket *s = opaque; |
267 | 093c455a | Eduardo Habkost | ssize_t len; |
268 | 093c455a | Eduardo Habkost | |
269 | 093c455a | Eduardo Habkost | for (;;) {
|
270 | 093c455a | Eduardo Habkost | len = read(s->fd, buf, size); |
271 | 093c455a | Eduardo Habkost | if (len != -1) { |
272 | 093c455a | Eduardo Habkost | break;
|
273 | 093c455a | Eduardo Habkost | } |
274 | 093c455a | Eduardo Habkost | if (errno == EAGAIN) {
|
275 | 093c455a | Eduardo Habkost | yield_until_fd_readable(s->fd); |
276 | 093c455a | Eduardo Habkost | } else if (errno != EINTR) { |
277 | 093c455a | Eduardo Habkost | break;
|
278 | 093c455a | Eduardo Habkost | } |
279 | 093c455a | Eduardo Habkost | } |
280 | 093c455a | Eduardo Habkost | |
281 | 093c455a | Eduardo Habkost | if (len == -1) { |
282 | 093c455a | Eduardo Habkost | len = -errno; |
283 | 093c455a | Eduardo Habkost | } |
284 | 093c455a | Eduardo Habkost | return len;
|
285 | 093c455a | Eduardo Habkost | } |
286 | 093c455a | Eduardo Habkost | |
287 | 093c455a | Eduardo Habkost | static int unix_close(void *opaque) |
288 | 093c455a | Eduardo Habkost | { |
289 | 093c455a | Eduardo Habkost | QEMUFileSocket *s = opaque; |
290 | 093c455a | Eduardo Habkost | close(s->fd); |
291 | 093c455a | Eduardo Habkost | g_free(s); |
292 | 093c455a | Eduardo Habkost | return 0; |
293 | 093c455a | Eduardo Habkost | } |
294 | 093c455a | Eduardo Habkost | |
295 | 093c455a | Eduardo Habkost | static const QEMUFileOps unix_read_ops = { |
296 | 093c455a | Eduardo Habkost | .get_fd = socket_get_fd, |
297 | 093c455a | Eduardo Habkost | .get_buffer = unix_get_buffer, |
298 | 093c455a | Eduardo Habkost | .close = unix_close |
299 | 093c455a | Eduardo Habkost | }; |
300 | 093c455a | Eduardo Habkost | |
301 | 093c455a | Eduardo Habkost | static const QEMUFileOps unix_write_ops = { |
302 | 093c455a | Eduardo Habkost | .get_fd = socket_get_fd, |
303 | 093c455a | Eduardo Habkost | .writev_buffer = unix_writev_buffer, |
304 | 093c455a | Eduardo Habkost | .close = unix_close |
305 | 093c455a | Eduardo Habkost | }; |
306 | 093c455a | Eduardo Habkost | |
307 | 093c455a | Eduardo Habkost | QEMUFile *qemu_fdopen(int fd, const char *mode) |
308 | 093c455a | Eduardo Habkost | { |
309 | 093c455a | Eduardo Habkost | QEMUFileSocket *s; |
310 | 093c455a | Eduardo Habkost | |
311 | 093c455a | Eduardo Habkost | if (mode == NULL || |
312 | 093c455a | Eduardo Habkost | (mode[0] != 'r' && mode[0] != 'w') || |
313 | 093c455a | Eduardo Habkost | mode[1] != 'b' || mode[2] != 0) { |
314 | 093c455a | Eduardo Habkost | fprintf(stderr, "qemu_fdopen: Argument validity check failed\n");
|
315 | 093c455a | Eduardo Habkost | return NULL; |
316 | 093c455a | Eduardo Habkost | } |
317 | 093c455a | Eduardo Habkost | |
318 | 093c455a | Eduardo Habkost | s = g_malloc0(sizeof(QEMUFileSocket));
|
319 | 093c455a | Eduardo Habkost | s->fd = fd; |
320 | 093c455a | Eduardo Habkost | |
321 | 093c455a | Eduardo Habkost | if (mode[0] == 'r') { |
322 | 093c455a | Eduardo Habkost | s->file = qemu_fopen_ops(s, &unix_read_ops); |
323 | 093c455a | Eduardo Habkost | } else {
|
324 | 093c455a | Eduardo Habkost | s->file = qemu_fopen_ops(s, &unix_write_ops); |
325 | 093c455a | Eduardo Habkost | } |
326 | 093c455a | Eduardo Habkost | return s->file;
|
327 | 093c455a | Eduardo Habkost | } |
328 | 093c455a | Eduardo Habkost | |
329 | 093c455a | Eduardo Habkost | static const QEMUFileOps socket_read_ops = { |
330 | 093c455a | Eduardo Habkost | .get_fd = socket_get_fd, |
331 | 093c455a | Eduardo Habkost | .get_buffer = socket_get_buffer, |
332 | 093c455a | Eduardo Habkost | .close = socket_close |
333 | 093c455a | Eduardo Habkost | }; |
334 | 093c455a | Eduardo Habkost | |
335 | 093c455a | Eduardo Habkost | static const QEMUFileOps socket_write_ops = { |
336 | 093c455a | Eduardo Habkost | .get_fd = socket_get_fd, |
337 | 093c455a | Eduardo Habkost | .writev_buffer = socket_writev_buffer, |
338 | 093c455a | Eduardo Habkost | .close = socket_close |
339 | 093c455a | Eduardo Habkost | }; |
340 | 093c455a | Eduardo Habkost | |
341 | 093c455a | Eduardo Habkost | bool qemu_file_mode_is_not_valid(const char *mode) |
342 | 093c455a | Eduardo Habkost | { |
343 | 093c455a | Eduardo Habkost | if (mode == NULL || |
344 | 093c455a | Eduardo Habkost | (mode[0] != 'r' && mode[0] != 'w') || |
345 | 093c455a | Eduardo Habkost | mode[1] != 'b' || mode[2] != 0) { |
346 | 093c455a | Eduardo Habkost | fprintf(stderr, "qemu_fopen: Argument validity check failed\n");
|
347 | 093c455a | Eduardo Habkost | return true; |
348 | 093c455a | Eduardo Habkost | } |
349 | 093c455a | Eduardo Habkost | |
350 | 093c455a | Eduardo Habkost | return false; |
351 | 093c455a | Eduardo Habkost | } |
352 | 093c455a | Eduardo Habkost | |
353 | 093c455a | Eduardo Habkost | QEMUFile *qemu_fopen_socket(int fd, const char *mode) |
354 | 093c455a | Eduardo Habkost | { |
355 | 093c455a | Eduardo Habkost | QEMUFileSocket *s; |
356 | 093c455a | Eduardo Habkost | |
357 | 093c455a | Eduardo Habkost | if (qemu_file_mode_is_not_valid(mode)) {
|
358 | 093c455a | Eduardo Habkost | return NULL; |
359 | 093c455a | Eduardo Habkost | } |
360 | 093c455a | Eduardo Habkost | |
361 | 093c455a | Eduardo Habkost | s = g_malloc0(sizeof(QEMUFileSocket));
|
362 | 093c455a | Eduardo Habkost | s->fd = fd; |
363 | 093c455a | Eduardo Habkost | if (mode[0] == 'w') { |
364 | 093c455a | Eduardo Habkost | qemu_set_block(s->fd); |
365 | 093c455a | Eduardo Habkost | s->file = qemu_fopen_ops(s, &socket_write_ops); |
366 | 093c455a | Eduardo Habkost | } else {
|
367 | 093c455a | Eduardo Habkost | s->file = qemu_fopen_ops(s, &socket_read_ops); |
368 | 093c455a | Eduardo Habkost | } |
369 | 093c455a | Eduardo Habkost | return s->file;
|
370 | 093c455a | Eduardo Habkost | } |
371 | 093c455a | Eduardo Habkost | |
372 | 093c455a | Eduardo Habkost | QEMUFile *qemu_fopen(const char *filename, const char *mode) |
373 | 093c455a | Eduardo Habkost | { |
374 | 093c455a | Eduardo Habkost | QEMUFileStdio *s; |
375 | 093c455a | Eduardo Habkost | |
376 | 093c455a | Eduardo Habkost | if (qemu_file_mode_is_not_valid(mode)) {
|
377 | 093c455a | Eduardo Habkost | return NULL; |
378 | 093c455a | Eduardo Habkost | } |
379 | 093c455a | Eduardo Habkost | |
380 | 093c455a | Eduardo Habkost | s = g_malloc0(sizeof(QEMUFileStdio));
|
381 | 093c455a | Eduardo Habkost | |
382 | 093c455a | Eduardo Habkost | s->stdio_file = fopen(filename, mode); |
383 | 093c455a | Eduardo Habkost | if (!s->stdio_file) {
|
384 | 093c455a | Eduardo Habkost | goto fail;
|
385 | 093c455a | Eduardo Habkost | } |
386 | 093c455a | Eduardo Habkost | |
387 | 093c455a | Eduardo Habkost | if (mode[0] == 'w') { |
388 | 093c455a | Eduardo Habkost | s->file = qemu_fopen_ops(s, &stdio_file_write_ops); |
389 | 093c455a | Eduardo Habkost | } else {
|
390 | 093c455a | Eduardo Habkost | s->file = qemu_fopen_ops(s, &stdio_file_read_ops); |
391 | 093c455a | Eduardo Habkost | } |
392 | 093c455a | Eduardo Habkost | return s->file;
|
393 | 093c455a | Eduardo Habkost | fail:
|
394 | 093c455a | Eduardo Habkost | g_free(s); |
395 | 093c455a | Eduardo Habkost | return NULL; |
396 | 093c455a | Eduardo Habkost | } |
397 | 093c455a | Eduardo Habkost | |
398 | 093c455a | Eduardo Habkost | QEMUFile *qemu_fopen_ops(void *opaque, const QEMUFileOps *ops) |
399 | 093c455a | Eduardo Habkost | { |
400 | 093c455a | Eduardo Habkost | QEMUFile *f; |
401 | 093c455a | Eduardo Habkost | |
402 | 093c455a | Eduardo Habkost | f = g_malloc0(sizeof(QEMUFile));
|
403 | 093c455a | Eduardo Habkost | |
404 | 093c455a | Eduardo Habkost | f->opaque = opaque; |
405 | 093c455a | Eduardo Habkost | f->ops = ops; |
406 | 093c455a | Eduardo Habkost | return f;
|
407 | 093c455a | Eduardo Habkost | } |
408 | 093c455a | Eduardo Habkost | |
409 | 093c455a | Eduardo Habkost | /*
|
410 | 093c455a | Eduardo Habkost | * Get last error for stream f
|
411 | 093c455a | Eduardo Habkost | *
|
412 | 093c455a | Eduardo Habkost | * Return negative error value if there has been an error on previous
|
413 | 093c455a | Eduardo Habkost | * operations, return 0 if no error happened.
|
414 | 093c455a | Eduardo Habkost | *
|
415 | 093c455a | Eduardo Habkost | */
|
416 | 093c455a | Eduardo Habkost | int qemu_file_get_error(QEMUFile *f)
|
417 | 093c455a | Eduardo Habkost | { |
418 | 093c455a | Eduardo Habkost | return f->last_error;
|
419 | 093c455a | Eduardo Habkost | } |
420 | 093c455a | Eduardo Habkost | |
421 | 093c455a | Eduardo Habkost | void qemu_file_set_error(QEMUFile *f, int ret) |
422 | 093c455a | Eduardo Habkost | { |
423 | 093c455a | Eduardo Habkost | if (f->last_error == 0) { |
424 | 093c455a | Eduardo Habkost | f->last_error = ret; |
425 | 093c455a | Eduardo Habkost | } |
426 | 093c455a | Eduardo Habkost | } |
427 | 093c455a | Eduardo Habkost | |
428 | 093c455a | Eduardo Habkost | static inline bool qemu_file_is_writable(QEMUFile *f) |
429 | 093c455a | Eduardo Habkost | { |
430 | 093c455a | Eduardo Habkost | return f->ops->writev_buffer || f->ops->put_buffer;
|
431 | 093c455a | Eduardo Habkost | } |
432 | 093c455a | Eduardo Habkost | |
433 | 093c455a | Eduardo Habkost | /**
|
434 | 093c455a | Eduardo Habkost | * Flushes QEMUFile buffer
|
435 | 093c455a | Eduardo Habkost | *
|
436 | 093c455a | Eduardo Habkost | * If there is writev_buffer QEMUFileOps it uses it otherwise uses
|
437 | 093c455a | Eduardo Habkost | * put_buffer ops.
|
438 | 093c455a | Eduardo Habkost | */
|
439 | 093c455a | Eduardo Habkost | void qemu_fflush(QEMUFile *f)
|
440 | 093c455a | Eduardo Habkost | { |
441 | 093c455a | Eduardo Habkost | ssize_t ret = 0;
|
442 | 093c455a | Eduardo Habkost | |
443 | 093c455a | Eduardo Habkost | if (!qemu_file_is_writable(f)) {
|
444 | 093c455a | Eduardo Habkost | return;
|
445 | 093c455a | Eduardo Habkost | } |
446 | 093c455a | Eduardo Habkost | |
447 | 093c455a | Eduardo Habkost | if (f->ops->writev_buffer) {
|
448 | 093c455a | Eduardo Habkost | if (f->iovcnt > 0) { |
449 | 093c455a | Eduardo Habkost | ret = f->ops->writev_buffer(f->opaque, f->iov, f->iovcnt, f->pos); |
450 | 093c455a | Eduardo Habkost | } |
451 | 093c455a | Eduardo Habkost | } else {
|
452 | 093c455a | Eduardo Habkost | if (f->buf_index > 0) { |
453 | 093c455a | Eduardo Habkost | ret = f->ops->put_buffer(f->opaque, f->buf, f->pos, f->buf_index); |
454 | 093c455a | Eduardo Habkost | } |
455 | 093c455a | Eduardo Habkost | } |
456 | 093c455a | Eduardo Habkost | if (ret >= 0) { |
457 | 093c455a | Eduardo Habkost | f->pos += ret; |
458 | 093c455a | Eduardo Habkost | } |
459 | 093c455a | Eduardo Habkost | f->buf_index = 0;
|
460 | 093c455a | Eduardo Habkost | f->iovcnt = 0;
|
461 | 093c455a | Eduardo Habkost | if (ret < 0) { |
462 | 093c455a | Eduardo Habkost | qemu_file_set_error(f, ret); |
463 | 093c455a | Eduardo Habkost | } |
464 | 093c455a | Eduardo Habkost | } |
465 | 093c455a | Eduardo Habkost | |
466 | 093c455a | Eduardo Habkost | void ram_control_before_iterate(QEMUFile *f, uint64_t flags)
|
467 | 093c455a | Eduardo Habkost | { |
468 | 093c455a | Eduardo Habkost | int ret = 0; |
469 | 093c455a | Eduardo Habkost | |
470 | 093c455a | Eduardo Habkost | if (f->ops->before_ram_iterate) {
|
471 | 093c455a | Eduardo Habkost | ret = f->ops->before_ram_iterate(f, f->opaque, flags); |
472 | 093c455a | Eduardo Habkost | if (ret < 0) { |
473 | 093c455a | Eduardo Habkost | qemu_file_set_error(f, ret); |
474 | 093c455a | Eduardo Habkost | } |
475 | 093c455a | Eduardo Habkost | } |
476 | 093c455a | Eduardo Habkost | } |
477 | 093c455a | Eduardo Habkost | |
478 | 093c455a | Eduardo Habkost | void ram_control_after_iterate(QEMUFile *f, uint64_t flags)
|
479 | 093c455a | Eduardo Habkost | { |
480 | 093c455a | Eduardo Habkost | int ret = 0; |
481 | 093c455a | Eduardo Habkost | |
482 | 093c455a | Eduardo Habkost | if (f->ops->after_ram_iterate) {
|
483 | 093c455a | Eduardo Habkost | ret = f->ops->after_ram_iterate(f, f->opaque, flags); |
484 | 093c455a | Eduardo Habkost | if (ret < 0) { |
485 | 093c455a | Eduardo Habkost | qemu_file_set_error(f, ret); |
486 | 093c455a | Eduardo Habkost | } |
487 | 093c455a | Eduardo Habkost | } |
488 | 093c455a | Eduardo Habkost | } |
489 | 093c455a | Eduardo Habkost | |
490 | 093c455a | Eduardo Habkost | void ram_control_load_hook(QEMUFile *f, uint64_t flags)
|
491 | 093c455a | Eduardo Habkost | { |
492 | 093c455a | Eduardo Habkost | int ret = -EINVAL;
|
493 | 093c455a | Eduardo Habkost | |
494 | 093c455a | Eduardo Habkost | if (f->ops->hook_ram_load) {
|
495 | 093c455a | Eduardo Habkost | ret = f->ops->hook_ram_load(f, f->opaque, flags); |
496 | 093c455a | Eduardo Habkost | if (ret < 0) { |
497 | 093c455a | Eduardo Habkost | qemu_file_set_error(f, ret); |
498 | 093c455a | Eduardo Habkost | } |
499 | 093c455a | Eduardo Habkost | } else {
|
500 | 093c455a | Eduardo Habkost | qemu_file_set_error(f, ret); |
501 | 093c455a | Eduardo Habkost | } |
502 | 093c455a | Eduardo Habkost | } |
503 | 093c455a | Eduardo Habkost | |
504 | 093c455a | Eduardo Habkost | size_t ram_control_save_page(QEMUFile *f, ram_addr_t block_offset, |
505 | 093c455a | Eduardo Habkost | ram_addr_t offset, size_t size, int *bytes_sent)
|
506 | 093c455a | Eduardo Habkost | { |
507 | 093c455a | Eduardo Habkost | if (f->ops->save_page) {
|
508 | 093c455a | Eduardo Habkost | int ret = f->ops->save_page(f, f->opaque, block_offset,
|
509 | 093c455a | Eduardo Habkost | offset, size, bytes_sent); |
510 | 093c455a | Eduardo Habkost | |
511 | 093c455a | Eduardo Habkost | if (ret != RAM_SAVE_CONTROL_DELAYED) {
|
512 | 093c455a | Eduardo Habkost | if (bytes_sent && *bytes_sent > 0) { |
513 | 093c455a | Eduardo Habkost | qemu_update_position(f, *bytes_sent); |
514 | 093c455a | Eduardo Habkost | } else if (ret < 0) { |
515 | 093c455a | Eduardo Habkost | qemu_file_set_error(f, ret); |
516 | 093c455a | Eduardo Habkost | } |
517 | 093c455a | Eduardo Habkost | } |
518 | 093c455a | Eduardo Habkost | |
519 | 093c455a | Eduardo Habkost | return ret;
|
520 | 093c455a | Eduardo Habkost | } |
521 | 093c455a | Eduardo Habkost | |
522 | 093c455a | Eduardo Habkost | return RAM_SAVE_CONTROL_NOT_SUPP;
|
523 | 093c455a | Eduardo Habkost | } |
524 | 093c455a | Eduardo Habkost | |
525 | 093c455a | Eduardo Habkost | static void qemu_fill_buffer(QEMUFile *f) |
526 | 093c455a | Eduardo Habkost | { |
527 | 093c455a | Eduardo Habkost | int len;
|
528 | 093c455a | Eduardo Habkost | int pending;
|
529 | 093c455a | Eduardo Habkost | |
530 | 093c455a | Eduardo Habkost | assert(!qemu_file_is_writable(f)); |
531 | 093c455a | Eduardo Habkost | |
532 | 093c455a | Eduardo Habkost | pending = f->buf_size - f->buf_index; |
533 | 093c455a | Eduardo Habkost | if (pending > 0) { |
534 | 093c455a | Eduardo Habkost | memmove(f->buf, f->buf + f->buf_index, pending); |
535 | 093c455a | Eduardo Habkost | } |
536 | 093c455a | Eduardo Habkost | f->buf_index = 0;
|
537 | 093c455a | Eduardo Habkost | f->buf_size = pending; |
538 | 093c455a | Eduardo Habkost | |
539 | 093c455a | Eduardo Habkost | len = f->ops->get_buffer(f->opaque, f->buf + pending, f->pos, |
540 | 093c455a | Eduardo Habkost | IO_BUF_SIZE - pending); |
541 | 093c455a | Eduardo Habkost | if (len > 0) { |
542 | 093c455a | Eduardo Habkost | f->buf_size += len; |
543 | 093c455a | Eduardo Habkost | f->pos += len; |
544 | 093c455a | Eduardo Habkost | } else if (len == 0) { |
545 | 093c455a | Eduardo Habkost | qemu_file_set_error(f, -EIO); |
546 | 093c455a | Eduardo Habkost | } else if (len != -EAGAIN) { |
547 | 093c455a | Eduardo Habkost | qemu_file_set_error(f, len); |
548 | 093c455a | Eduardo Habkost | } |
549 | 093c455a | Eduardo Habkost | } |
550 | 093c455a | Eduardo Habkost | |
551 | 093c455a | Eduardo Habkost | int qemu_get_fd(QEMUFile *f)
|
552 | 093c455a | Eduardo Habkost | { |
553 | 093c455a | Eduardo Habkost | if (f->ops->get_fd) {
|
554 | 093c455a | Eduardo Habkost | return f->ops->get_fd(f->opaque);
|
555 | 093c455a | Eduardo Habkost | } |
556 | 093c455a | Eduardo Habkost | return -1; |
557 | 093c455a | Eduardo Habkost | } |
558 | 093c455a | Eduardo Habkost | |
559 | 093c455a | Eduardo Habkost | void qemu_update_position(QEMUFile *f, size_t size)
|
560 | 093c455a | Eduardo Habkost | { |
561 | 093c455a | Eduardo Habkost | f->pos += size; |
562 | 093c455a | Eduardo Habkost | } |
563 | 093c455a | Eduardo Habkost | |
564 | 093c455a | Eduardo Habkost | /** Closes the file
|
565 | 093c455a | Eduardo Habkost | *
|
566 | 093c455a | Eduardo Habkost | * Returns negative error value if any error happened on previous operations or
|
567 | 093c455a | Eduardo Habkost | * while closing the file. Returns 0 or positive number on success.
|
568 | 093c455a | Eduardo Habkost | *
|
569 | 093c455a | Eduardo Habkost | * The meaning of return value on success depends on the specific backend
|
570 | 093c455a | Eduardo Habkost | * being used.
|
571 | 093c455a | Eduardo Habkost | */
|
572 | 093c455a | Eduardo Habkost | int qemu_fclose(QEMUFile *f)
|
573 | 093c455a | Eduardo Habkost | { |
574 | 093c455a | Eduardo Habkost | int ret;
|
575 | 093c455a | Eduardo Habkost | qemu_fflush(f); |
576 | 093c455a | Eduardo Habkost | ret = qemu_file_get_error(f); |
577 | 093c455a | Eduardo Habkost | |
578 | 093c455a | Eduardo Habkost | if (f->ops->close) {
|
579 | 093c455a | Eduardo Habkost | int ret2 = f->ops->close(f->opaque);
|
580 | 093c455a | Eduardo Habkost | if (ret >= 0) { |
581 | 093c455a | Eduardo Habkost | ret = ret2; |
582 | 093c455a | Eduardo Habkost | } |
583 | 093c455a | Eduardo Habkost | } |
584 | 093c455a | Eduardo Habkost | /* If any error was spotted before closing, we should report it
|
585 | 093c455a | Eduardo Habkost | * instead of the close() return value.
|
586 | 093c455a | Eduardo Habkost | */
|
587 | 093c455a | Eduardo Habkost | if (f->last_error) {
|
588 | 093c455a | Eduardo Habkost | ret = f->last_error; |
589 | 093c455a | Eduardo Habkost | } |
590 | 093c455a | Eduardo Habkost | g_free(f); |
591 | 093c455a | Eduardo Habkost | return ret;
|
592 | 093c455a | Eduardo Habkost | } |
593 | 093c455a | Eduardo Habkost | |
594 | 093c455a | Eduardo Habkost | static void add_to_iovec(QEMUFile *f, const uint8_t *buf, int size) |
595 | 093c455a | Eduardo Habkost | { |
596 | 093c455a | Eduardo Habkost | /* check for adjacent buffer and coalesce them */
|
597 | 093c455a | Eduardo Habkost | if (f->iovcnt > 0 && buf == f->iov[f->iovcnt - 1].iov_base + |
598 | 093c455a | Eduardo Habkost | f->iov[f->iovcnt - 1].iov_len) {
|
599 | 093c455a | Eduardo Habkost | f->iov[f->iovcnt - 1].iov_len += size;
|
600 | 093c455a | Eduardo Habkost | } else {
|
601 | 093c455a | Eduardo Habkost | f->iov[f->iovcnt].iov_base = (uint8_t *)buf; |
602 | 093c455a | Eduardo Habkost | f->iov[f->iovcnt++].iov_len = size; |
603 | 093c455a | Eduardo Habkost | } |
604 | 093c455a | Eduardo Habkost | |
605 | 093c455a | Eduardo Habkost | if (f->iovcnt >= MAX_IOV_SIZE) {
|
606 | 093c455a | Eduardo Habkost | qemu_fflush(f); |
607 | 093c455a | Eduardo Habkost | } |
608 | 093c455a | Eduardo Habkost | } |
609 | 093c455a | Eduardo Habkost | |
610 | 093c455a | Eduardo Habkost | void qemu_put_buffer_async(QEMUFile *f, const uint8_t *buf, int size) |
611 | 093c455a | Eduardo Habkost | { |
612 | 093c455a | Eduardo Habkost | if (!f->ops->writev_buffer) {
|
613 | 093c455a | Eduardo Habkost | qemu_put_buffer(f, buf, size); |
614 | 093c455a | Eduardo Habkost | return;
|
615 | 093c455a | Eduardo Habkost | } |
616 | 093c455a | Eduardo Habkost | |
617 | 093c455a | Eduardo Habkost | if (f->last_error) {
|
618 | 093c455a | Eduardo Habkost | return;
|
619 | 093c455a | Eduardo Habkost | } |
620 | 093c455a | Eduardo Habkost | |
621 | 093c455a | Eduardo Habkost | f->bytes_xfer += size; |
622 | 093c455a | Eduardo Habkost | add_to_iovec(f, buf, size); |
623 | 093c455a | Eduardo Habkost | } |
624 | 093c455a | Eduardo Habkost | |
625 | 093c455a | Eduardo Habkost | void qemu_put_buffer(QEMUFile *f, const uint8_t *buf, int size) |
626 | 093c455a | Eduardo Habkost | { |
627 | 093c455a | Eduardo Habkost | int l;
|
628 | 093c455a | Eduardo Habkost | |
629 | 093c455a | Eduardo Habkost | if (f->last_error) {
|
630 | 093c455a | Eduardo Habkost | return;
|
631 | 093c455a | Eduardo Habkost | } |
632 | 093c455a | Eduardo Habkost | |
633 | 093c455a | Eduardo Habkost | while (size > 0) { |
634 | 093c455a | Eduardo Habkost | l = IO_BUF_SIZE - f->buf_index; |
635 | 093c455a | Eduardo Habkost | if (l > size) {
|
636 | 093c455a | Eduardo Habkost | l = size; |
637 | 093c455a | Eduardo Habkost | } |
638 | 093c455a | Eduardo Habkost | memcpy(f->buf + f->buf_index, buf, l); |
639 | 093c455a | Eduardo Habkost | f->bytes_xfer += l; |
640 | 093c455a | Eduardo Habkost | if (f->ops->writev_buffer) {
|
641 | 093c455a | Eduardo Habkost | add_to_iovec(f, f->buf + f->buf_index, l); |
642 | 093c455a | Eduardo Habkost | } |
643 | 093c455a | Eduardo Habkost | f->buf_index += l; |
644 | 093c455a | Eduardo Habkost | if (f->buf_index == IO_BUF_SIZE) {
|
645 | 093c455a | Eduardo Habkost | qemu_fflush(f); |
646 | 093c455a | Eduardo Habkost | } |
647 | 093c455a | Eduardo Habkost | if (qemu_file_get_error(f)) {
|
648 | 093c455a | Eduardo Habkost | break;
|
649 | 093c455a | Eduardo Habkost | } |
650 | 093c455a | Eduardo Habkost | buf += l; |
651 | 093c455a | Eduardo Habkost | size -= l; |
652 | 093c455a | Eduardo Habkost | } |
653 | 093c455a | Eduardo Habkost | } |
654 | 093c455a | Eduardo Habkost | |
655 | 093c455a | Eduardo Habkost | void qemu_put_byte(QEMUFile *f, int v) |
656 | 093c455a | Eduardo Habkost | { |
657 | 093c455a | Eduardo Habkost | if (f->last_error) {
|
658 | 093c455a | Eduardo Habkost | return;
|
659 | 093c455a | Eduardo Habkost | } |
660 | 093c455a | Eduardo Habkost | |
661 | 093c455a | Eduardo Habkost | f->buf[f->buf_index] = v; |
662 | 093c455a | Eduardo Habkost | f->bytes_xfer++; |
663 | 093c455a | Eduardo Habkost | if (f->ops->writev_buffer) {
|
664 | 093c455a | Eduardo Habkost | add_to_iovec(f, f->buf + f->buf_index, 1);
|
665 | 093c455a | Eduardo Habkost | } |
666 | 093c455a | Eduardo Habkost | f->buf_index++; |
667 | 093c455a | Eduardo Habkost | if (f->buf_index == IO_BUF_SIZE) {
|
668 | 093c455a | Eduardo Habkost | qemu_fflush(f); |
669 | 093c455a | Eduardo Habkost | } |
670 | 093c455a | Eduardo Habkost | } |
671 | 093c455a | Eduardo Habkost | |
672 | 093c455a | Eduardo Habkost | void qemu_file_skip(QEMUFile *f, int size) |
673 | 093c455a | Eduardo Habkost | { |
674 | 093c455a | Eduardo Habkost | if (f->buf_index + size <= f->buf_size) {
|
675 | 093c455a | Eduardo Habkost | f->buf_index += size; |
676 | 093c455a | Eduardo Habkost | } |
677 | 093c455a | Eduardo Habkost | } |
678 | 093c455a | Eduardo Habkost | |
679 | 093c455a | Eduardo Habkost | int qemu_peek_buffer(QEMUFile *f, uint8_t *buf, int size, size_t offset) |
680 | 093c455a | Eduardo Habkost | { |
681 | 093c455a | Eduardo Habkost | int pending;
|
682 | 093c455a | Eduardo Habkost | int index;
|
683 | 093c455a | Eduardo Habkost | |
684 | 093c455a | Eduardo Habkost | assert(!qemu_file_is_writable(f)); |
685 | 093c455a | Eduardo Habkost | |
686 | 093c455a | Eduardo Habkost | index = f->buf_index + offset; |
687 | 093c455a | Eduardo Habkost | pending = f->buf_size - index; |
688 | 093c455a | Eduardo Habkost | if (pending < size) {
|
689 | 093c455a | Eduardo Habkost | qemu_fill_buffer(f); |
690 | 093c455a | Eduardo Habkost | index = f->buf_index + offset; |
691 | 093c455a | Eduardo Habkost | pending = f->buf_size - index; |
692 | 093c455a | Eduardo Habkost | } |
693 | 093c455a | Eduardo Habkost | |
694 | 093c455a | Eduardo Habkost | if (pending <= 0) { |
695 | 093c455a | Eduardo Habkost | return 0; |
696 | 093c455a | Eduardo Habkost | } |
697 | 093c455a | Eduardo Habkost | if (size > pending) {
|
698 | 093c455a | Eduardo Habkost | size = pending; |
699 | 093c455a | Eduardo Habkost | } |
700 | 093c455a | Eduardo Habkost | |
701 | 093c455a | Eduardo Habkost | memcpy(buf, f->buf + index, size); |
702 | 093c455a | Eduardo Habkost | return size;
|
703 | 093c455a | Eduardo Habkost | } |
704 | 093c455a | Eduardo Habkost | |
705 | 093c455a | Eduardo Habkost | int qemu_get_buffer(QEMUFile *f, uint8_t *buf, int size) |
706 | 093c455a | Eduardo Habkost | { |
707 | 093c455a | Eduardo Habkost | int pending = size;
|
708 | 093c455a | Eduardo Habkost | int done = 0; |
709 | 093c455a | Eduardo Habkost | |
710 | 093c455a | Eduardo Habkost | while (pending > 0) { |
711 | 093c455a | Eduardo Habkost | int res;
|
712 | 093c455a | Eduardo Habkost | |
713 | 093c455a | Eduardo Habkost | res = qemu_peek_buffer(f, buf, pending, 0);
|
714 | 093c455a | Eduardo Habkost | if (res == 0) { |
715 | 093c455a | Eduardo Habkost | return done;
|
716 | 093c455a | Eduardo Habkost | } |
717 | 093c455a | Eduardo Habkost | qemu_file_skip(f, res); |
718 | 093c455a | Eduardo Habkost | buf += res; |
719 | 093c455a | Eduardo Habkost | pending -= res; |
720 | 093c455a | Eduardo Habkost | done += res; |
721 | 093c455a | Eduardo Habkost | } |
722 | 093c455a | Eduardo Habkost | return done;
|
723 | 093c455a | Eduardo Habkost | } |
724 | 093c455a | Eduardo Habkost | |
725 | 093c455a | Eduardo Habkost | int qemu_peek_byte(QEMUFile *f, int offset) |
726 | 093c455a | Eduardo Habkost | { |
727 | 093c455a | Eduardo Habkost | int index = f->buf_index + offset;
|
728 | 093c455a | Eduardo Habkost | |
729 | 093c455a | Eduardo Habkost | assert(!qemu_file_is_writable(f)); |
730 | 093c455a | Eduardo Habkost | |
731 | 093c455a | Eduardo Habkost | if (index >= f->buf_size) {
|
732 | 093c455a | Eduardo Habkost | qemu_fill_buffer(f); |
733 | 093c455a | Eduardo Habkost | index = f->buf_index + offset; |
734 | 093c455a | Eduardo Habkost | if (index >= f->buf_size) {
|
735 | 093c455a | Eduardo Habkost | return 0; |
736 | 093c455a | Eduardo Habkost | } |
737 | 093c455a | Eduardo Habkost | } |
738 | 093c455a | Eduardo Habkost | return f->buf[index];
|
739 | 093c455a | Eduardo Habkost | } |
740 | 093c455a | Eduardo Habkost | |
741 | 093c455a | Eduardo Habkost | int qemu_get_byte(QEMUFile *f)
|
742 | 093c455a | Eduardo Habkost | { |
743 | 093c455a | Eduardo Habkost | int result;
|
744 | 093c455a | Eduardo Habkost | |
745 | 093c455a | Eduardo Habkost | result = qemu_peek_byte(f, 0);
|
746 | 093c455a | Eduardo Habkost | qemu_file_skip(f, 1);
|
747 | 093c455a | Eduardo Habkost | return result;
|
748 | 093c455a | Eduardo Habkost | } |
749 | 093c455a | Eduardo Habkost | |
750 | 093c455a | Eduardo Habkost | int64_t qemu_ftell(QEMUFile *f) |
751 | 093c455a | Eduardo Habkost | { |
752 | 093c455a | Eduardo Habkost | qemu_fflush(f); |
753 | 093c455a | Eduardo Habkost | return f->pos;
|
754 | 093c455a | Eduardo Habkost | } |
755 | 093c455a | Eduardo Habkost | |
756 | 093c455a | Eduardo Habkost | int qemu_file_rate_limit(QEMUFile *f)
|
757 | 093c455a | Eduardo Habkost | { |
758 | 093c455a | Eduardo Habkost | if (qemu_file_get_error(f)) {
|
759 | 093c455a | Eduardo Habkost | return 1; |
760 | 093c455a | Eduardo Habkost | } |
761 | 093c455a | Eduardo Habkost | if (f->xfer_limit > 0 && f->bytes_xfer > f->xfer_limit) { |
762 | 093c455a | Eduardo Habkost | return 1; |
763 | 093c455a | Eduardo Habkost | } |
764 | 093c455a | Eduardo Habkost | return 0; |
765 | 093c455a | Eduardo Habkost | } |
766 | 093c455a | Eduardo Habkost | |
767 | 093c455a | Eduardo Habkost | int64_t qemu_file_get_rate_limit(QEMUFile *f) |
768 | 093c455a | Eduardo Habkost | { |
769 | 093c455a | Eduardo Habkost | return f->xfer_limit;
|
770 | 093c455a | Eduardo Habkost | } |
771 | 093c455a | Eduardo Habkost | |
772 | 093c455a | Eduardo Habkost | void qemu_file_set_rate_limit(QEMUFile *f, int64_t limit)
|
773 | 093c455a | Eduardo Habkost | { |
774 | 093c455a | Eduardo Habkost | f->xfer_limit = limit; |
775 | 093c455a | Eduardo Habkost | } |
776 | 093c455a | Eduardo Habkost | |
777 | 093c455a | Eduardo Habkost | void qemu_file_reset_rate_limit(QEMUFile *f)
|
778 | 093c455a | Eduardo Habkost | { |
779 | 093c455a | Eduardo Habkost | f->bytes_xfer = 0;
|
780 | 093c455a | Eduardo Habkost | } |
781 | 093c455a | Eduardo Habkost | |
782 | 093c455a | Eduardo Habkost | void qemu_put_be16(QEMUFile *f, unsigned int v) |
783 | 093c455a | Eduardo Habkost | { |
784 | 093c455a | Eduardo Habkost | qemu_put_byte(f, v >> 8);
|
785 | 093c455a | Eduardo Habkost | qemu_put_byte(f, v); |
786 | 093c455a | Eduardo Habkost | } |
787 | 093c455a | Eduardo Habkost | |
788 | 093c455a | Eduardo Habkost | void qemu_put_be32(QEMUFile *f, unsigned int v) |
789 | 093c455a | Eduardo Habkost | { |
790 | 093c455a | Eduardo Habkost | qemu_put_byte(f, v >> 24);
|
791 | 093c455a | Eduardo Habkost | qemu_put_byte(f, v >> 16);
|
792 | 093c455a | Eduardo Habkost | qemu_put_byte(f, v >> 8);
|
793 | 093c455a | Eduardo Habkost | qemu_put_byte(f, v); |
794 | 093c455a | Eduardo Habkost | } |
795 | 093c455a | Eduardo Habkost | |
796 | 093c455a | Eduardo Habkost | void qemu_put_be64(QEMUFile *f, uint64_t v)
|
797 | 093c455a | Eduardo Habkost | { |
798 | 093c455a | Eduardo Habkost | qemu_put_be32(f, v >> 32);
|
799 | 093c455a | Eduardo Habkost | qemu_put_be32(f, v); |
800 | 093c455a | Eduardo Habkost | } |
801 | 093c455a | Eduardo Habkost | |
802 | 093c455a | Eduardo Habkost | unsigned int qemu_get_be16(QEMUFile *f) |
803 | 093c455a | Eduardo Habkost | { |
804 | 093c455a | Eduardo Habkost | unsigned int v; |
805 | 093c455a | Eduardo Habkost | v = qemu_get_byte(f) << 8;
|
806 | 093c455a | Eduardo Habkost | v |= qemu_get_byte(f); |
807 | 093c455a | Eduardo Habkost | return v;
|
808 | 093c455a | Eduardo Habkost | } |
809 | 093c455a | Eduardo Habkost | |
810 | 093c455a | Eduardo Habkost | unsigned int qemu_get_be32(QEMUFile *f) |
811 | 093c455a | Eduardo Habkost | { |
812 | 093c455a | Eduardo Habkost | unsigned int v; |
813 | 093c455a | Eduardo Habkost | v = qemu_get_byte(f) << 24;
|
814 | 093c455a | Eduardo Habkost | v |= qemu_get_byte(f) << 16;
|
815 | 093c455a | Eduardo Habkost | v |= qemu_get_byte(f) << 8;
|
816 | 093c455a | Eduardo Habkost | v |= qemu_get_byte(f); |
817 | 093c455a | Eduardo Habkost | return v;
|
818 | 093c455a | Eduardo Habkost | } |
819 | 093c455a | Eduardo Habkost | |
820 | 093c455a | Eduardo Habkost | uint64_t qemu_get_be64(QEMUFile *f) |
821 | 093c455a | Eduardo Habkost | { |
822 | 093c455a | Eduardo Habkost | uint64_t v; |
823 | 093c455a | Eduardo Habkost | v = (uint64_t)qemu_get_be32(f) << 32;
|
824 | 093c455a | Eduardo Habkost | v |= qemu_get_be32(f); |
825 | 093c455a | Eduardo Habkost | return v;
|
826 | 093c455a | Eduardo Habkost | } |