xref: /aosp_15_r20/external/libfuse/lib/buffer.c (revision 9e5649576b786774a32d7b0252c9cd8c6538fa49)
1*9e564957SAndroid Build Coastguard Worker /*
2*9e564957SAndroid Build Coastguard Worker   FUSE: Filesystem in Userspace
3*9e564957SAndroid Build Coastguard Worker   Copyright (C) 2010  Miklos Szeredi <[email protected]>
4*9e564957SAndroid Build Coastguard Worker 
5*9e564957SAndroid Build Coastguard Worker   Functions for dealing with `struct fuse_buf` and `struct
6*9e564957SAndroid Build Coastguard Worker   fuse_bufvec`.
7*9e564957SAndroid Build Coastguard Worker 
8*9e564957SAndroid Build Coastguard Worker   This program can be distributed under the terms of the GNU LGPLv2.
9*9e564957SAndroid Build Coastguard Worker   See the file COPYING.LIB
10*9e564957SAndroid Build Coastguard Worker */
11*9e564957SAndroid Build Coastguard Worker 
12*9e564957SAndroid Build Coastguard Worker #define _GNU_SOURCE
13*9e564957SAndroid Build Coastguard Worker 
14*9e564957SAndroid Build Coastguard Worker #include "fuse_config.h"
15*9e564957SAndroid Build Coastguard Worker #include "fuse_i.h"
16*9e564957SAndroid Build Coastguard Worker #include "fuse_lowlevel.h"
17*9e564957SAndroid Build Coastguard Worker #include <string.h>
18*9e564957SAndroid Build Coastguard Worker #include <unistd.h>
19*9e564957SAndroid Build Coastguard Worker #include <errno.h>
20*9e564957SAndroid Build Coastguard Worker #include <assert.h>
21*9e564957SAndroid Build Coastguard Worker 
fuse_buf_size(const struct fuse_bufvec * bufv)22*9e564957SAndroid Build Coastguard Worker size_t fuse_buf_size(const struct fuse_bufvec *bufv)
23*9e564957SAndroid Build Coastguard Worker {
24*9e564957SAndroid Build Coastguard Worker 	size_t i;
25*9e564957SAndroid Build Coastguard Worker 	size_t size = 0;
26*9e564957SAndroid Build Coastguard Worker 
27*9e564957SAndroid Build Coastguard Worker 	for (i = 0; i < bufv->count; i++) {
28*9e564957SAndroid Build Coastguard Worker 		if (bufv->buf[i].size == SIZE_MAX)
29*9e564957SAndroid Build Coastguard Worker 			size = SIZE_MAX;
30*9e564957SAndroid Build Coastguard Worker 		else
31*9e564957SAndroid Build Coastguard Worker 			size += bufv->buf[i].size;
32*9e564957SAndroid Build Coastguard Worker 	}
33*9e564957SAndroid Build Coastguard Worker 
34*9e564957SAndroid Build Coastguard Worker 	return size;
35*9e564957SAndroid Build Coastguard Worker }
36*9e564957SAndroid Build Coastguard Worker 
min_size(size_t s1,size_t s2)37*9e564957SAndroid Build Coastguard Worker static size_t min_size(size_t s1, size_t s2)
38*9e564957SAndroid Build Coastguard Worker {
39*9e564957SAndroid Build Coastguard Worker 	return s1 < s2 ? s1 : s2;
40*9e564957SAndroid Build Coastguard Worker }
41*9e564957SAndroid Build Coastguard Worker 
fuse_buf_write(const struct fuse_buf * dst,size_t dst_off,const struct fuse_buf * src,size_t src_off,size_t len)42*9e564957SAndroid Build Coastguard Worker static ssize_t fuse_buf_write(const struct fuse_buf *dst, size_t dst_off,
43*9e564957SAndroid Build Coastguard Worker 			      const struct fuse_buf *src, size_t src_off,
44*9e564957SAndroid Build Coastguard Worker 			      size_t len)
45*9e564957SAndroid Build Coastguard Worker {
46*9e564957SAndroid Build Coastguard Worker 	ssize_t res = 0;
47*9e564957SAndroid Build Coastguard Worker 	size_t copied = 0;
48*9e564957SAndroid Build Coastguard Worker 
49*9e564957SAndroid Build Coastguard Worker 	while (len) {
50*9e564957SAndroid Build Coastguard Worker 		if (dst->flags & FUSE_BUF_FD_SEEK) {
51*9e564957SAndroid Build Coastguard Worker 			res = pwrite(dst->fd, (char *)src->mem + src_off, len,
52*9e564957SAndroid Build Coastguard Worker 				     dst->pos + dst_off);
53*9e564957SAndroid Build Coastguard Worker 		} else {
54*9e564957SAndroid Build Coastguard Worker 			res = write(dst->fd, (char *)src->mem + src_off, len);
55*9e564957SAndroid Build Coastguard Worker 		}
56*9e564957SAndroid Build Coastguard Worker 		if (res == -1) {
57*9e564957SAndroid Build Coastguard Worker 			if (!copied)
58*9e564957SAndroid Build Coastguard Worker 				return -errno;
59*9e564957SAndroid Build Coastguard Worker 			break;
60*9e564957SAndroid Build Coastguard Worker 		}
61*9e564957SAndroid Build Coastguard Worker 		if (res == 0)
62*9e564957SAndroid Build Coastguard Worker 			break;
63*9e564957SAndroid Build Coastguard Worker 
64*9e564957SAndroid Build Coastguard Worker 		copied += res;
65*9e564957SAndroid Build Coastguard Worker 		if (!(dst->flags & FUSE_BUF_FD_RETRY))
66*9e564957SAndroid Build Coastguard Worker 			break;
67*9e564957SAndroid Build Coastguard Worker 
68*9e564957SAndroid Build Coastguard Worker 		src_off += res;
69*9e564957SAndroid Build Coastguard Worker 		dst_off += res;
70*9e564957SAndroid Build Coastguard Worker 		len -= res;
71*9e564957SAndroid Build Coastguard Worker 	}
72*9e564957SAndroid Build Coastguard Worker 
73*9e564957SAndroid Build Coastguard Worker 	return copied;
74*9e564957SAndroid Build Coastguard Worker }
75*9e564957SAndroid Build Coastguard Worker 
fuse_buf_read(const struct fuse_buf * dst,size_t dst_off,const struct fuse_buf * src,size_t src_off,size_t len)76*9e564957SAndroid Build Coastguard Worker static ssize_t fuse_buf_read(const struct fuse_buf *dst, size_t dst_off,
77*9e564957SAndroid Build Coastguard Worker 			     const struct fuse_buf *src, size_t src_off,
78*9e564957SAndroid Build Coastguard Worker 			     size_t len)
79*9e564957SAndroid Build Coastguard Worker {
80*9e564957SAndroid Build Coastguard Worker 	ssize_t res = 0;
81*9e564957SAndroid Build Coastguard Worker 	size_t copied = 0;
82*9e564957SAndroid Build Coastguard Worker 
83*9e564957SAndroid Build Coastguard Worker 	while (len) {
84*9e564957SAndroid Build Coastguard Worker 		if (src->flags & FUSE_BUF_FD_SEEK) {
85*9e564957SAndroid Build Coastguard Worker 			res = pread(src->fd, (char *)dst->mem + dst_off, len,
86*9e564957SAndroid Build Coastguard Worker 				     src->pos + src_off);
87*9e564957SAndroid Build Coastguard Worker 		} else {
88*9e564957SAndroid Build Coastguard Worker 			res = read(src->fd, (char *)dst->mem + dst_off, len);
89*9e564957SAndroid Build Coastguard Worker 		}
90*9e564957SAndroid Build Coastguard Worker 		if (res == -1) {
91*9e564957SAndroid Build Coastguard Worker 			if (!copied)
92*9e564957SAndroid Build Coastguard Worker 				return -errno;
93*9e564957SAndroid Build Coastguard Worker 			break;
94*9e564957SAndroid Build Coastguard Worker 		}
95*9e564957SAndroid Build Coastguard Worker 		if (res == 0)
96*9e564957SAndroid Build Coastguard Worker 			break;
97*9e564957SAndroid Build Coastguard Worker 
98*9e564957SAndroid Build Coastguard Worker 		copied += res;
99*9e564957SAndroid Build Coastguard Worker 		if (!(src->flags & FUSE_BUF_FD_RETRY))
100*9e564957SAndroid Build Coastguard Worker 			break;
101*9e564957SAndroid Build Coastguard Worker 
102*9e564957SAndroid Build Coastguard Worker 		dst_off += res;
103*9e564957SAndroid Build Coastguard Worker 		src_off += res;
104*9e564957SAndroid Build Coastguard Worker 		len -= res;
105*9e564957SAndroid Build Coastguard Worker 	}
106*9e564957SAndroid Build Coastguard Worker 
107*9e564957SAndroid Build Coastguard Worker 	return copied;
108*9e564957SAndroid Build Coastguard Worker }
109*9e564957SAndroid Build Coastguard Worker 
fuse_buf_fd_to_fd(const struct fuse_buf * dst,size_t dst_off,const struct fuse_buf * src,size_t src_off,size_t len)110*9e564957SAndroid Build Coastguard Worker static ssize_t fuse_buf_fd_to_fd(const struct fuse_buf *dst, size_t dst_off,
111*9e564957SAndroid Build Coastguard Worker 				 const struct fuse_buf *src, size_t src_off,
112*9e564957SAndroid Build Coastguard Worker 				 size_t len)
113*9e564957SAndroid Build Coastguard Worker {
114*9e564957SAndroid Build Coastguard Worker 	char buf[4096];
115*9e564957SAndroid Build Coastguard Worker 	struct fuse_buf tmp = {
116*9e564957SAndroid Build Coastguard Worker 		.size = sizeof(buf),
117*9e564957SAndroid Build Coastguard Worker 		.flags = 0,
118*9e564957SAndroid Build Coastguard Worker 	};
119*9e564957SAndroid Build Coastguard Worker 	ssize_t res;
120*9e564957SAndroid Build Coastguard Worker 	size_t copied = 0;
121*9e564957SAndroid Build Coastguard Worker 
122*9e564957SAndroid Build Coastguard Worker 	tmp.mem = buf;
123*9e564957SAndroid Build Coastguard Worker 
124*9e564957SAndroid Build Coastguard Worker 	while (len) {
125*9e564957SAndroid Build Coastguard Worker 		size_t this_len = min_size(tmp.size, len);
126*9e564957SAndroid Build Coastguard Worker 		size_t read_len;
127*9e564957SAndroid Build Coastguard Worker 
128*9e564957SAndroid Build Coastguard Worker 		res = fuse_buf_read(&tmp, 0, src, src_off, this_len);
129*9e564957SAndroid Build Coastguard Worker 		if (res < 0) {
130*9e564957SAndroid Build Coastguard Worker 			if (!copied)
131*9e564957SAndroid Build Coastguard Worker 				return res;
132*9e564957SAndroid Build Coastguard Worker 			break;
133*9e564957SAndroid Build Coastguard Worker 		}
134*9e564957SAndroid Build Coastguard Worker 		if (res == 0)
135*9e564957SAndroid Build Coastguard Worker 			break;
136*9e564957SAndroid Build Coastguard Worker 
137*9e564957SAndroid Build Coastguard Worker 		read_len = res;
138*9e564957SAndroid Build Coastguard Worker 		res = fuse_buf_write(dst, dst_off, &tmp, 0, read_len);
139*9e564957SAndroid Build Coastguard Worker 		if (res < 0) {
140*9e564957SAndroid Build Coastguard Worker 			if (!copied)
141*9e564957SAndroid Build Coastguard Worker 				return res;
142*9e564957SAndroid Build Coastguard Worker 			break;
143*9e564957SAndroid Build Coastguard Worker 		}
144*9e564957SAndroid Build Coastguard Worker 		if (res == 0)
145*9e564957SAndroid Build Coastguard Worker 			break;
146*9e564957SAndroid Build Coastguard Worker 
147*9e564957SAndroid Build Coastguard Worker 		copied += res;
148*9e564957SAndroid Build Coastguard Worker 
149*9e564957SAndroid Build Coastguard Worker 		if (res < this_len)
150*9e564957SAndroid Build Coastguard Worker 			break;
151*9e564957SAndroid Build Coastguard Worker 
152*9e564957SAndroid Build Coastguard Worker 		dst_off += res;
153*9e564957SAndroid Build Coastguard Worker 		src_off += res;
154*9e564957SAndroid Build Coastguard Worker 		len -= res;
155*9e564957SAndroid Build Coastguard Worker 	}
156*9e564957SAndroid Build Coastguard Worker 
157*9e564957SAndroid Build Coastguard Worker 	return copied;
158*9e564957SAndroid Build Coastguard Worker }
159*9e564957SAndroid Build Coastguard Worker 
160*9e564957SAndroid Build Coastguard Worker #ifdef HAVE_SPLICE
fuse_buf_splice(const struct fuse_buf * dst,size_t dst_off,const struct fuse_buf * src,size_t src_off,size_t len,enum fuse_buf_copy_flags flags)161*9e564957SAndroid Build Coastguard Worker static ssize_t fuse_buf_splice(const struct fuse_buf *dst, size_t dst_off,
162*9e564957SAndroid Build Coastguard Worker 			       const struct fuse_buf *src, size_t src_off,
163*9e564957SAndroid Build Coastguard Worker 			       size_t len, enum fuse_buf_copy_flags flags)
164*9e564957SAndroid Build Coastguard Worker {
165*9e564957SAndroid Build Coastguard Worker 	int splice_flags = 0;
166*9e564957SAndroid Build Coastguard Worker 	off_t *srcpos = NULL;
167*9e564957SAndroid Build Coastguard Worker 	off_t *dstpos = NULL;
168*9e564957SAndroid Build Coastguard Worker 	off_t srcpos_val;
169*9e564957SAndroid Build Coastguard Worker 	off_t dstpos_val;
170*9e564957SAndroid Build Coastguard Worker 	ssize_t res;
171*9e564957SAndroid Build Coastguard Worker 	size_t copied = 0;
172*9e564957SAndroid Build Coastguard Worker 
173*9e564957SAndroid Build Coastguard Worker 	if (flags & FUSE_BUF_SPLICE_MOVE)
174*9e564957SAndroid Build Coastguard Worker 		splice_flags |= SPLICE_F_MOVE;
175*9e564957SAndroid Build Coastguard Worker 	if (flags & FUSE_BUF_SPLICE_NONBLOCK)
176*9e564957SAndroid Build Coastguard Worker 		splice_flags |= SPLICE_F_NONBLOCK;
177*9e564957SAndroid Build Coastguard Worker 
178*9e564957SAndroid Build Coastguard Worker 	if (src->flags & FUSE_BUF_FD_SEEK) {
179*9e564957SAndroid Build Coastguard Worker 		srcpos_val = src->pos + src_off;
180*9e564957SAndroid Build Coastguard Worker 		srcpos = &srcpos_val;
181*9e564957SAndroid Build Coastguard Worker 	}
182*9e564957SAndroid Build Coastguard Worker 	if (dst->flags & FUSE_BUF_FD_SEEK) {
183*9e564957SAndroid Build Coastguard Worker 		dstpos_val = dst->pos + dst_off;
184*9e564957SAndroid Build Coastguard Worker 		dstpos = &dstpos_val;
185*9e564957SAndroid Build Coastguard Worker 	}
186*9e564957SAndroid Build Coastguard Worker 
187*9e564957SAndroid Build Coastguard Worker 	while (len) {
188*9e564957SAndroid Build Coastguard Worker 		res = splice(src->fd, srcpos, dst->fd, dstpos, len,
189*9e564957SAndroid Build Coastguard Worker 			     splice_flags);
190*9e564957SAndroid Build Coastguard Worker 		if (res == -1) {
191*9e564957SAndroid Build Coastguard Worker 			if (copied)
192*9e564957SAndroid Build Coastguard Worker 				break;
193*9e564957SAndroid Build Coastguard Worker 
194*9e564957SAndroid Build Coastguard Worker 			if (errno != EINVAL || (flags & FUSE_BUF_FORCE_SPLICE))
195*9e564957SAndroid Build Coastguard Worker 				return -errno;
196*9e564957SAndroid Build Coastguard Worker 
197*9e564957SAndroid Build Coastguard Worker 			/* Maybe splice is not supported for this combination */
198*9e564957SAndroid Build Coastguard Worker 			return fuse_buf_fd_to_fd(dst, dst_off, src, src_off,
199*9e564957SAndroid Build Coastguard Worker 						 len);
200*9e564957SAndroid Build Coastguard Worker 		}
201*9e564957SAndroid Build Coastguard Worker 		if (res == 0)
202*9e564957SAndroid Build Coastguard Worker 			break;
203*9e564957SAndroid Build Coastguard Worker 
204*9e564957SAndroid Build Coastguard Worker 		copied += res;
205*9e564957SAndroid Build Coastguard Worker 		if (!(src->flags & FUSE_BUF_FD_RETRY) &&
206*9e564957SAndroid Build Coastguard Worker 		    !(dst->flags & FUSE_BUF_FD_RETRY)) {
207*9e564957SAndroid Build Coastguard Worker 			break;
208*9e564957SAndroid Build Coastguard Worker 		}
209*9e564957SAndroid Build Coastguard Worker 
210*9e564957SAndroid Build Coastguard Worker 		len -= res;
211*9e564957SAndroid Build Coastguard Worker 	}
212*9e564957SAndroid Build Coastguard Worker 
213*9e564957SAndroid Build Coastguard Worker 	return copied;
214*9e564957SAndroid Build Coastguard Worker }
215*9e564957SAndroid Build Coastguard Worker #else
fuse_buf_splice(const struct fuse_buf * dst,size_t dst_off,const struct fuse_buf * src,size_t src_off,size_t len,enum fuse_buf_copy_flags flags)216*9e564957SAndroid Build Coastguard Worker static ssize_t fuse_buf_splice(const struct fuse_buf *dst, size_t dst_off,
217*9e564957SAndroid Build Coastguard Worker 			       const struct fuse_buf *src, size_t src_off,
218*9e564957SAndroid Build Coastguard Worker 			       size_t len, enum fuse_buf_copy_flags flags)
219*9e564957SAndroid Build Coastguard Worker {
220*9e564957SAndroid Build Coastguard Worker 	(void) flags;
221*9e564957SAndroid Build Coastguard Worker 
222*9e564957SAndroid Build Coastguard Worker 	return fuse_buf_fd_to_fd(dst, dst_off, src, src_off, len);
223*9e564957SAndroid Build Coastguard Worker }
224*9e564957SAndroid Build Coastguard Worker #endif
225*9e564957SAndroid Build Coastguard Worker 
226*9e564957SAndroid Build Coastguard Worker 
fuse_buf_copy_one(const struct fuse_buf * dst,size_t dst_off,const struct fuse_buf * src,size_t src_off,size_t len,enum fuse_buf_copy_flags flags)227*9e564957SAndroid Build Coastguard Worker static ssize_t fuse_buf_copy_one(const struct fuse_buf *dst, size_t dst_off,
228*9e564957SAndroid Build Coastguard Worker 				 const struct fuse_buf *src, size_t src_off,
229*9e564957SAndroid Build Coastguard Worker 				 size_t len, enum fuse_buf_copy_flags flags)
230*9e564957SAndroid Build Coastguard Worker {
231*9e564957SAndroid Build Coastguard Worker 	int src_is_fd = src->flags & FUSE_BUF_IS_FD;
232*9e564957SAndroid Build Coastguard Worker 	int dst_is_fd = dst->flags & FUSE_BUF_IS_FD;
233*9e564957SAndroid Build Coastguard Worker 
234*9e564957SAndroid Build Coastguard Worker 	if (!src_is_fd && !dst_is_fd) {
235*9e564957SAndroid Build Coastguard Worker 		char *dstmem = (char *)dst->mem + dst_off;
236*9e564957SAndroid Build Coastguard Worker 		char *srcmem = (char *)src->mem + src_off;
237*9e564957SAndroid Build Coastguard Worker 
238*9e564957SAndroid Build Coastguard Worker 		if (dstmem != srcmem) {
239*9e564957SAndroid Build Coastguard Worker 			if (dstmem + len <= srcmem || srcmem + len <= dstmem)
240*9e564957SAndroid Build Coastguard Worker 				memcpy(dstmem, srcmem, len);
241*9e564957SAndroid Build Coastguard Worker 			else
242*9e564957SAndroid Build Coastguard Worker 				memmove(dstmem, srcmem, len);
243*9e564957SAndroid Build Coastguard Worker 		}
244*9e564957SAndroid Build Coastguard Worker 
245*9e564957SAndroid Build Coastguard Worker 		return len;
246*9e564957SAndroid Build Coastguard Worker 	} else if (!src_is_fd) {
247*9e564957SAndroid Build Coastguard Worker 		return fuse_buf_write(dst, dst_off, src, src_off, len);
248*9e564957SAndroid Build Coastguard Worker 	} else if (!dst_is_fd) {
249*9e564957SAndroid Build Coastguard Worker 		return fuse_buf_read(dst, dst_off, src, src_off, len);
250*9e564957SAndroid Build Coastguard Worker 	} else if (flags & FUSE_BUF_NO_SPLICE) {
251*9e564957SAndroid Build Coastguard Worker 		return fuse_buf_fd_to_fd(dst, dst_off, src, src_off, len);
252*9e564957SAndroid Build Coastguard Worker 	} else {
253*9e564957SAndroid Build Coastguard Worker 		return fuse_buf_splice(dst, dst_off, src, src_off, len, flags);
254*9e564957SAndroid Build Coastguard Worker 	}
255*9e564957SAndroid Build Coastguard Worker }
256*9e564957SAndroid Build Coastguard Worker 
fuse_bufvec_current(struct fuse_bufvec * bufv)257*9e564957SAndroid Build Coastguard Worker static const struct fuse_buf *fuse_bufvec_current(struct fuse_bufvec *bufv)
258*9e564957SAndroid Build Coastguard Worker {
259*9e564957SAndroid Build Coastguard Worker 	if (bufv->idx < bufv->count)
260*9e564957SAndroid Build Coastguard Worker 		return &bufv->buf[bufv->idx];
261*9e564957SAndroid Build Coastguard Worker 	else
262*9e564957SAndroid Build Coastguard Worker 		return NULL;
263*9e564957SAndroid Build Coastguard Worker }
264*9e564957SAndroid Build Coastguard Worker 
fuse_bufvec_advance(struct fuse_bufvec * bufv,size_t len)265*9e564957SAndroid Build Coastguard Worker static int fuse_bufvec_advance(struct fuse_bufvec *bufv, size_t len)
266*9e564957SAndroid Build Coastguard Worker {
267*9e564957SAndroid Build Coastguard Worker 	const struct fuse_buf *buf = fuse_bufvec_current(bufv);
268*9e564957SAndroid Build Coastguard Worker 
269*9e564957SAndroid Build Coastguard Worker 	if (!buf)
270*9e564957SAndroid Build Coastguard Worker 		return 0;
271*9e564957SAndroid Build Coastguard Worker 
272*9e564957SAndroid Build Coastguard Worker 	bufv->off += len;
273*9e564957SAndroid Build Coastguard Worker 	assert(bufv->off <= buf->size);
274*9e564957SAndroid Build Coastguard Worker 	if (bufv->off == buf->size) {
275*9e564957SAndroid Build Coastguard Worker 		assert(bufv->idx < bufv->count);
276*9e564957SAndroid Build Coastguard Worker 		bufv->idx++;
277*9e564957SAndroid Build Coastguard Worker 		if (bufv->idx == bufv->count)
278*9e564957SAndroid Build Coastguard Worker 			return 0;
279*9e564957SAndroid Build Coastguard Worker 		bufv->off = 0;
280*9e564957SAndroid Build Coastguard Worker 	}
281*9e564957SAndroid Build Coastguard Worker 	return 1;
282*9e564957SAndroid Build Coastguard Worker }
283*9e564957SAndroid Build Coastguard Worker 
fuse_buf_copy(struct fuse_bufvec * dstv,struct fuse_bufvec * srcv,enum fuse_buf_copy_flags flags)284*9e564957SAndroid Build Coastguard Worker ssize_t fuse_buf_copy(struct fuse_bufvec *dstv, struct fuse_bufvec *srcv,
285*9e564957SAndroid Build Coastguard Worker 		      enum fuse_buf_copy_flags flags)
286*9e564957SAndroid Build Coastguard Worker {
287*9e564957SAndroid Build Coastguard Worker 	size_t copied = 0;
288*9e564957SAndroid Build Coastguard Worker 
289*9e564957SAndroid Build Coastguard Worker 	if (dstv == srcv)
290*9e564957SAndroid Build Coastguard Worker 		return fuse_buf_size(dstv);
291*9e564957SAndroid Build Coastguard Worker 
292*9e564957SAndroid Build Coastguard Worker 	for (;;) {
293*9e564957SAndroid Build Coastguard Worker 		const struct fuse_buf *src = fuse_bufvec_current(srcv);
294*9e564957SAndroid Build Coastguard Worker 		const struct fuse_buf *dst = fuse_bufvec_current(dstv);
295*9e564957SAndroid Build Coastguard Worker 		size_t src_len;
296*9e564957SAndroid Build Coastguard Worker 		size_t dst_len;
297*9e564957SAndroid Build Coastguard Worker 		size_t len;
298*9e564957SAndroid Build Coastguard Worker 		ssize_t res;
299*9e564957SAndroid Build Coastguard Worker 
300*9e564957SAndroid Build Coastguard Worker 		if (src == NULL || dst == NULL)
301*9e564957SAndroid Build Coastguard Worker 			break;
302*9e564957SAndroid Build Coastguard Worker 
303*9e564957SAndroid Build Coastguard Worker 		src_len = src->size - srcv->off;
304*9e564957SAndroid Build Coastguard Worker 		dst_len = dst->size - dstv->off;
305*9e564957SAndroid Build Coastguard Worker 		len = min_size(src_len, dst_len);
306*9e564957SAndroid Build Coastguard Worker 
307*9e564957SAndroid Build Coastguard Worker 		res = fuse_buf_copy_one(dst, dstv->off, src, srcv->off, len, flags);
308*9e564957SAndroid Build Coastguard Worker 		if (res < 0) {
309*9e564957SAndroid Build Coastguard Worker 			if (!copied)
310*9e564957SAndroid Build Coastguard Worker 				return res;
311*9e564957SAndroid Build Coastguard Worker 			break;
312*9e564957SAndroid Build Coastguard Worker 		}
313*9e564957SAndroid Build Coastguard Worker 		copied += res;
314*9e564957SAndroid Build Coastguard Worker 
315*9e564957SAndroid Build Coastguard Worker 		if (!fuse_bufvec_advance(srcv, res) ||
316*9e564957SAndroid Build Coastguard Worker 		    !fuse_bufvec_advance(dstv, res))
317*9e564957SAndroid Build Coastguard Worker 			break;
318*9e564957SAndroid Build Coastguard Worker 
319*9e564957SAndroid Build Coastguard Worker 		if (res < len)
320*9e564957SAndroid Build Coastguard Worker 			break;
321*9e564957SAndroid Build Coastguard Worker 	}
322*9e564957SAndroid Build Coastguard Worker 
323*9e564957SAndroid Build Coastguard Worker 	return copied;
324*9e564957SAndroid Build Coastguard Worker }
325