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
);
254 assert(bufv
->off
<= buf
->size
);
255 if (bufv
->off
== buf
->size
) {
256 assert(bufv
->idx
< bufv
->count
);
258 if (bufv
->idx
== bufv
->count
) {
266 ssize_t
fuse_buf_copy(struct fuse_bufvec
*dstv
, struct fuse_bufvec
*srcv
)
268 size_t copied
= 0, i
;
271 return fuse_buf_size(dstv
);
275 * use writev to improve bandwidth when all the
276 * src buffers already mapped by the daemon
279 for (i
= 0; i
< srcv
->count
; i
++) {
280 if (srcv
->buf
[i
].flags
& FUSE_BUF_IS_FD
) {
284 if ((i
== srcv
->count
) && (dstv
->count
== 1) &&
286 (dstv
->buf
[0].flags
& FUSE_BUF_IS_FD
)) {
287 dstv
->buf
[0].pos
+= dstv
->off
;
288 return fuse_buf_writev(&dstv
->buf
[0], srcv
);
292 const struct fuse_buf
*src
= fuse_bufvec_current(srcv
);
293 const struct fuse_buf
*dst
= fuse_bufvec_current(dstv
);
299 if (src
== NULL
|| dst
== NULL
) {
303 src_len
= src
->size
- srcv
->off
;
304 dst_len
= dst
->size
- dstv
->off
;
305 len
= min_size(src_len
, dst_len
);
307 res
= fuse_buf_copy_one(dst
, dstv
->off
, src
, srcv
->off
, len
);
316 if (!fuse_bufvec_advance(srcv
, res
) ||
317 !fuse_bufvec_advance(dstv
, res
)) {
329 void *fuse_mbuf_iter_advance(struct fuse_mbuf_iter
*iter
, size_t len
)
333 if (len
> iter
->size
- iter
->pos
) {
337 ptr
= iter
->mem
+ iter
->pos
;
342 const char *fuse_mbuf_iter_advance_str(struct fuse_mbuf_iter
*iter
)
344 const char *str
= iter
->mem
+ iter
->pos
;
345 size_t remaining
= iter
->size
- iter
->pos
;
348 for (i
= 0; i
< remaining
; i
++) {
349 if (str
[i
] == '\0') {