]> git.proxmox.com Git - mirror_qemu.git/blame - tools/virtiofsd/buffer.c
virtiofsd: Fix fuse_daemonize ignored return values
[mirror_qemu.git] / tools / virtiofsd / buffer.c
CommitLineData
ffcf8d9f 1/*
7387863d
DDAG
2 * FUSE: Filesystem in Userspace
3 * Copyright (C) 2010 Miklos Szeredi <miklos@szeredi.hu>
4 *
5 * Functions for dealing with `struct fuse_buf` and `struct
6 * fuse_bufvec`.
7 *
8 * This program can be distributed under the terms of the GNU LGPLv2.
9 * See the file COPYING.LIB
10 */
ffcf8d9f
DDAG
11
12#define _GNU_SOURCE
13
14#include "config.h"
15#include "fuse_i.h"
16#include "fuse_lowlevel.h"
7387863d
DDAG
17#include <assert.h>
18#include <errno.h>
ffcf8d9f
DDAG
19#include <string.h>
20#include <unistd.h>
ffcf8d9f
DDAG
21
22size_t fuse_buf_size(const struct fuse_bufvec *bufv)
23{
7387863d
DDAG
24 size_t i;
25 size_t size = 0;
26
27 for (i = 0; i < bufv->count; i++) {
28 if (bufv->buf[i].size == SIZE_MAX) {
29 size = SIZE_MAX;
30 } else {
31 size += bufv->buf[i].size;
32 }
33 }
34
35 return size;
ffcf8d9f
DDAG
36}
37
38static size_t min_size(size_t s1, size_t s2)
39{
7387863d 40 return s1 < s2 ? s1 : s2;
ffcf8d9f
DDAG
41}
42
43static ssize_t fuse_buf_write(const struct fuse_buf *dst, size_t dst_off,
7387863d
DDAG
44 const struct fuse_buf *src, size_t src_off,
45 size_t len)
ffcf8d9f 46{
7387863d
DDAG
47 ssize_t res = 0;
48 size_t copied = 0;
49
50 while (len) {
51 if (dst->flags & FUSE_BUF_FD_SEEK) {
52 res = pwrite(dst->fd, (char *)src->mem + src_off, len,
53 dst->pos + dst_off);
54 } else {
55 res = write(dst->fd, (char *)src->mem + src_off, len);
56 }
57 if (res == -1) {
58 if (!copied) {
59 return -errno;
60 }
61 break;
62 }
63 if (res == 0) {
64 break;
65 }
66
67 copied += res;
68 if (!(dst->flags & FUSE_BUF_FD_RETRY)) {
69 break;
70 }
71
72 src_off += res;
73 dst_off += res;
74 len -= res;
75 }
76
77 return copied;
ffcf8d9f
DDAG
78}
79
80static ssize_t fuse_buf_read(const struct fuse_buf *dst, size_t dst_off,
7387863d
DDAG
81 const struct fuse_buf *src, size_t src_off,
82 size_t len)
ffcf8d9f 83{
7387863d
DDAG
84 ssize_t res = 0;
85 size_t copied = 0;
86
87 while (len) {
88 if (src->flags & FUSE_BUF_FD_SEEK) {
89 res = pread(src->fd, (char *)dst->mem + dst_off, len,
90 src->pos + src_off);
91 } else {
92 res = read(src->fd, (char *)dst->mem + dst_off, len);
93 }
94 if (res == -1) {
95 if (!copied) {
96 return -errno;
97 }
98 break;
99 }
100 if (res == 0) {
101 break;
102 }
103
104 copied += res;
105 if (!(src->flags & FUSE_BUF_FD_RETRY)) {
106 break;
107 }
108
109 dst_off += res;
110 src_off += res;
111 len -= res;
112 }
113
114 return copied;
ffcf8d9f
DDAG
115}
116
117static ssize_t fuse_buf_fd_to_fd(const struct fuse_buf *dst, size_t dst_off,
7387863d
DDAG
118 const struct fuse_buf *src, size_t src_off,
119 size_t len)
ffcf8d9f 120{
7387863d
DDAG
121 char buf[4096];
122 struct fuse_buf tmp = {
123 .size = sizeof(buf),
124 .flags = 0,
125 };
126 ssize_t res;
127 size_t copied = 0;
128
129 tmp.mem = buf;
130
131 while (len) {
132 size_t this_len = min_size(tmp.size, len);
133 size_t read_len;
134
135 res = fuse_buf_read(&tmp, 0, src, src_off, this_len);
136 if (res < 0) {
137 if (!copied) {
138 return res;
139 }
140 break;
141 }
142 if (res == 0) {
143 break;
144 }
145
146 read_len = res;
147 res = fuse_buf_write(dst, dst_off, &tmp, 0, read_len);
148 if (res < 0) {
149 if (!copied) {
150 return res;
151 }
152 break;
153 }
154 if (res == 0) {
155 break;
156 }
157
158 copied += res;
159
160 if (res < this_len) {
161 break;
162 }
163
164 dst_off += res;
165 src_off += res;
166 len -= res;
167 }
168
169 return copied;
ffcf8d9f
DDAG
170}
171
ffcf8d9f 172static ssize_t fuse_buf_copy_one(const struct fuse_buf *dst, size_t dst_off,
7387863d 173 const struct fuse_buf *src, size_t src_off,
8c3fe75e 174 size_t len)
ffcf8d9f 175{
7387863d
DDAG
176 int src_is_fd = src->flags & FUSE_BUF_IS_FD;
177 int dst_is_fd = dst->flags & FUSE_BUF_IS_FD;
178
179 if (!src_is_fd && !dst_is_fd) {
180 char *dstmem = (char *)dst->mem + dst_off;
181 char *srcmem = (char *)src->mem + src_off;
182
183 if (dstmem != srcmem) {
184 if (dstmem + len <= srcmem || srcmem + len <= dstmem) {
185 memcpy(dstmem, srcmem, len);
186 } else {
187 memmove(dstmem, srcmem, len);
188 }
189 }
190
191 return len;
192 } else if (!src_is_fd) {
193 return fuse_buf_write(dst, dst_off, src, src_off, len);
194 } else if (!dst_is_fd) {
195 return fuse_buf_read(dst, dst_off, src, src_off, len);
196 } else {
197 return fuse_buf_fd_to_fd(dst, dst_off, src, src_off, len);
198 }
ffcf8d9f
DDAG
199}
200
201static const struct fuse_buf *fuse_bufvec_current(struct fuse_bufvec *bufv)
202{
7387863d
DDAG
203 if (bufv->idx < bufv->count) {
204 return &bufv->buf[bufv->idx];
205 } else {
206 return NULL;
207 }
ffcf8d9f
DDAG
208}
209
210static int fuse_bufvec_advance(struct fuse_bufvec *bufv, size_t len)
211{
7387863d
DDAG
212 const struct fuse_buf *buf = fuse_bufvec_current(bufv);
213
214 bufv->off += len;
215 assert(bufv->off <= buf->size);
216 if (bufv->off == buf->size) {
217 assert(bufv->idx < bufv->count);
218 bufv->idx++;
219 if (bufv->idx == bufv->count) {
220 return 0;
221 }
222 bufv->off = 0;
223 }
224 return 1;
ffcf8d9f
DDAG
225}
226
8c3fe75e 227ssize_t fuse_buf_copy(struct fuse_bufvec *dstv, struct fuse_bufvec *srcv)
ffcf8d9f 228{
7387863d
DDAG
229 size_t copied = 0;
230
231 if (dstv == srcv) {
232 return fuse_buf_size(dstv);
233 }
234
235 for (;;) {
236 const struct fuse_buf *src = fuse_bufvec_current(srcv);
237 const struct fuse_buf *dst = fuse_bufvec_current(dstv);
238 size_t src_len;
239 size_t dst_len;
240 size_t len;
241 ssize_t res;
242
243 if (src == NULL || dst == NULL) {
244 break;
245 }
246
247 src_len = src->size - srcv->off;
248 dst_len = dst->size - dstv->off;
249 len = min_size(src_len, dst_len);
250
8c3fe75e 251 res = fuse_buf_copy_one(dst, dstv->off, src, srcv->off, len);
7387863d
DDAG
252 if (res < 0) {
253 if (!copied) {
254 return res;
255 }
256 break;
257 }
258 copied += res;
259
260 if (!fuse_bufvec_advance(srcv, res) ||
261 !fuse_bufvec_advance(dstv, res)) {
262 break;
263 }
264
265 if (res < len) {
266 break;
267 }
268 }
269
270 return copied;
ffcf8d9f 271}