2 * FUSE: Filesystem in Userspace
3 * Copyright (C) 2010 Miklos Szeredi <miklos@szeredi.hu>
5 * Functions for dealing with `struct fuse_buf` and `struct
8 * This program can be distributed under the terms of the GNU LGPLv2.
9 * See the file COPYING.LIB
12 #include "qemu/osdep.h"
14 #include "fuse_lowlevel.h"
21 size_t fuse_buf_size(const struct fuse_bufvec
*bufv
)
26 for (i
= 0; i
< bufv
->count
; i
++) {
27 if (bufv
->buf
[i
].size
== SIZE_MAX
) {
30 size
+= bufv
->buf
[i
].size
;
37 static ssize_t
fuse_buf_writev(struct fuse_buf
*out_buf
,
38 struct fuse_bufvec
*in_buf
)
41 size_t iovcnt
= in_buf
->count
;
45 iov
= calloc(iovcnt
, sizeof(struct iovec
));
50 for (i
= 0, j
= 0; i
< iovcnt
; i
++) {
51 /* Skip the buf with 0 size */
52 if (in_buf
->buf
[i
].size
) {
53 iov
[j
].iov_base
= in_buf
->buf
[i
].mem
;
54 iov
[j
].iov_len
= in_buf
->buf
[i
].size
;
59 if (out_buf
->flags
& FUSE_BUF_FD_SEEK
) {
60 res
= pwritev(fd
, iov
, iovcnt
, out_buf
->pos
);
62 res
= writev(fd
, iov
, iovcnt
);
73 static size_t min_size(size_t s1
, size_t s2
)
75 return s1
< s2
? s1
: s2
;
78 static ssize_t
fuse_buf_write(const struct fuse_buf
*dst
, size_t dst_off
,
79 const struct fuse_buf
*src
, size_t src_off
,
86 if (dst
->flags
& FUSE_BUF_FD_SEEK
) {
87 res
= pwrite(dst
->fd
, (char *)src
->mem
+ src_off
, len
,
90 res
= write(dst
->fd
, (char *)src
->mem
+ src_off
, len
);
103 if (!(dst
->flags
& FUSE_BUF_FD_RETRY
)) {
115 static ssize_t
fuse_buf_read(const struct fuse_buf
*dst
, size_t dst_off
,
116 const struct fuse_buf
*src
, size_t src_off
,
123 if (src
->flags
& FUSE_BUF_FD_SEEK
) {
124 res
= pread(src
->fd
, (char *)dst
->mem
+ dst_off
, len
,
127 res
= read(src
->fd
, (char *)dst
->mem
+ dst_off
, len
);
140 if (!(src
->flags
& FUSE_BUF_FD_RETRY
)) {
152 static ssize_t
fuse_buf_fd_to_fd(const struct fuse_buf
*dst
, size_t dst_off
,
153 const struct fuse_buf
*src
, size_t src_off
,
157 struct fuse_buf tmp
= {
167 size_t this_len
= min_size(tmp
.size
, len
);
170 res
= fuse_buf_read(&tmp
, 0, src
, src_off
, this_len
);
182 res
= fuse_buf_write(dst
, dst_off
, &tmp
, 0, read_len
);
195 if (res
< this_len
) {
207 static ssize_t
fuse_buf_copy_one(const struct fuse_buf
*dst
, size_t dst_off
,
208 const struct fuse_buf
*src
, size_t src_off
,
211 int src_is_fd
= src
->flags
& FUSE_BUF_IS_FD
;
212 int dst_is_fd
= dst
->flags
& FUSE_BUF_IS_FD
;
214 if (!src_is_fd
&& !dst_is_fd
) {
215 char *dstmem
= (char *)dst
->mem
+ dst_off
;
216 char *srcmem
= (char *)src
->mem
+ src_off
;
218 if (dstmem
!= srcmem
) {
219 if (dstmem
+ len
<= srcmem
|| srcmem
+ len
<= dstmem
) {
220 memcpy(dstmem
, srcmem
, len
);
222 memmove(dstmem
, srcmem
, len
);
227 } else if (!src_is_fd
) {
228 return fuse_buf_write(dst
, dst_off
, src
, src_off
, len
);
229 } else if (!dst_is_fd
) {
230 return fuse_buf_read(dst
, dst_off
, src
, src_off
, len
);
232 return fuse_buf_fd_to_fd(dst
, dst_off
, src
, src_off
, len
);
236 static const struct fuse_buf
*fuse_bufvec_current(struct fuse_bufvec
*bufv
)
238 if (bufv
->idx
< bufv
->count
) {
239 return &bufv
->buf
[bufv
->idx
];
245 static int fuse_bufvec_advance(struct fuse_bufvec
*bufv
, size_t len
)
247 const struct fuse_buf
*buf
= fuse_bufvec_current(bufv
);
250 assert(bufv
->off
<= buf
->size
);
251 if (bufv
->off
== buf
->size
) {
252 assert(bufv
->idx
< bufv
->count
);
254 if (bufv
->idx
== bufv
->count
) {
262 ssize_t
fuse_buf_copy(struct fuse_bufvec
*dstv
, struct fuse_bufvec
*srcv
)
264 size_t copied
= 0, i
;
267 return fuse_buf_size(dstv
);
271 * use writev to improve bandwidth when all the
272 * src buffers already mapped by the daemon
275 for (i
= 0; i
< srcv
->count
; i
++) {
276 if (srcv
->buf
[i
].flags
& FUSE_BUF_IS_FD
) {
280 if ((i
== srcv
->count
) && (dstv
->count
== 1) &&
282 (dstv
->buf
[0].flags
& FUSE_BUF_IS_FD
)) {
283 dstv
->buf
[0].pos
+= dstv
->off
;
284 return fuse_buf_writev(&dstv
->buf
[0], srcv
);
288 const struct fuse_buf
*src
= fuse_bufvec_current(srcv
);
289 const struct fuse_buf
*dst
= fuse_bufvec_current(dstv
);
295 if (src
== NULL
|| dst
== NULL
) {
299 src_len
= src
->size
- srcv
->off
;
300 dst_len
= dst
->size
- dstv
->off
;
301 len
= min_size(src_len
, dst_len
);
303 res
= fuse_buf_copy_one(dst
, dstv
->off
, src
, srcv
->off
, len
);
312 if (!fuse_bufvec_advance(srcv
, res
) ||
313 !fuse_bufvec_advance(dstv
, res
)) {
325 void *fuse_mbuf_iter_advance(struct fuse_mbuf_iter
*iter
, size_t len
)
329 if (len
> iter
->size
- iter
->pos
) {
333 ptr
= iter
->mem
+ iter
->pos
;
338 const char *fuse_mbuf_iter_advance_str(struct fuse_mbuf_iter
*iter
)
340 const char *str
= iter
->mem
+ iter
->pos
;
341 size_t remaining
= iter
->size
- iter
->pos
;
344 for (i
= 0; i
< remaining
; i
++) {
345 if (str
[i
] == '\0') {