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