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"
16 size_t fuse_buf_size(const struct fuse_bufvec
*bufv
)
21 for (i
= 0; i
< bufv
->count
; i
++) {
22 if (bufv
->buf
[i
].size
== SIZE_MAX
) {
25 size
+= bufv
->buf
[i
].size
;
32 static ssize_t
fuse_buf_writev(struct fuse_buf
*out_buf
,
33 struct fuse_bufvec
*in_buf
)
36 size_t iovcnt
= in_buf
->count
;
40 iov
= calloc(iovcnt
, sizeof(struct iovec
));
45 for (i
= 0, j
= 0; i
< iovcnt
; i
++) {
46 /* Skip the buf with 0 size */
47 if (in_buf
->buf
[i
].size
) {
48 iov
[j
].iov_base
= in_buf
->buf
[i
].mem
;
49 iov
[j
].iov_len
= in_buf
->buf
[i
].size
;
54 if (out_buf
->flags
& FUSE_BUF_FD_SEEK
) {
55 res
= pwritev(fd
, iov
, iovcnt
, out_buf
->pos
);
57 res
= writev(fd
, iov
, iovcnt
);
68 static size_t min_size(size_t s1
, size_t s2
)
70 return s1
< s2
? s1
: s2
;
73 static ssize_t
fuse_buf_write(const struct fuse_buf
*dst
, size_t dst_off
,
74 const struct fuse_buf
*src
, size_t src_off
,
81 if (dst
->flags
& FUSE_BUF_FD_SEEK
) {
82 res
= pwrite(dst
->fd
, (char *)src
->mem
+ src_off
, len
,
85 res
= write(dst
->fd
, (char *)src
->mem
+ src_off
, len
);
98 if (!(dst
->flags
& FUSE_BUF_FD_RETRY
)) {
110 static ssize_t
fuse_buf_read(const struct fuse_buf
*dst
, size_t dst_off
,
111 const struct fuse_buf
*src
, size_t src_off
,
118 if (src
->flags
& FUSE_BUF_FD_SEEK
) {
119 res
= pread(src
->fd
, (char *)dst
->mem
+ dst_off
, len
,
122 res
= read(src
->fd
, (char *)dst
->mem
+ dst_off
, len
);
135 if (!(src
->flags
& FUSE_BUF_FD_RETRY
)) {
147 static ssize_t
fuse_buf_fd_to_fd(const struct fuse_buf
*dst
, size_t dst_off
,
148 const struct fuse_buf
*src
, size_t src_off
,
152 struct fuse_buf tmp
= {
162 size_t this_len
= min_size(tmp
.size
, len
);
165 res
= fuse_buf_read(&tmp
, 0, src
, src_off
, this_len
);
177 res
= fuse_buf_write(dst
, dst_off
, &tmp
, 0, read_len
);
190 if (res
< this_len
) {
202 static ssize_t
fuse_buf_copy_one(const struct fuse_buf
*dst
, size_t dst_off
,
203 const struct fuse_buf
*src
, size_t src_off
,
206 int src_is_fd
= src
->flags
& FUSE_BUF_IS_FD
;
207 int dst_is_fd
= dst
->flags
& FUSE_BUF_IS_FD
;
209 if (!src_is_fd
&& !dst_is_fd
) {
210 char *dstmem
= (char *)dst
->mem
+ dst_off
;
211 char *srcmem
= (char *)src
->mem
+ src_off
;
213 if (dstmem
!= srcmem
) {
214 if (dstmem
+ len
<= srcmem
|| srcmem
+ len
<= dstmem
) {
215 memcpy(dstmem
, srcmem
, len
);
217 memmove(dstmem
, srcmem
, len
);
222 } else if (!src_is_fd
) {
223 return fuse_buf_write(dst
, dst_off
, src
, src_off
, len
);
224 } else if (!dst_is_fd
) {
225 return fuse_buf_read(dst
, dst_off
, src
, src_off
, len
);
227 return fuse_buf_fd_to_fd(dst
, dst_off
, src
, src_off
, len
);
231 static const struct fuse_buf
*fuse_bufvec_current(struct fuse_bufvec
*bufv
)
233 if (bufv
->idx
< bufv
->count
) {
234 return &bufv
->buf
[bufv
->idx
];
240 static int fuse_bufvec_advance(struct fuse_bufvec
*bufv
, size_t len
)
242 const struct fuse_buf
*buf
= fuse_bufvec_current(bufv
);
249 assert(bufv
->off
<= buf
->size
);
250 if (bufv
->off
== buf
->size
) {
251 assert(bufv
->idx
< bufv
->count
);
253 if (bufv
->idx
== bufv
->count
) {
261 ssize_t
fuse_buf_copy(struct fuse_bufvec
*dstv
, struct fuse_bufvec
*srcv
)
263 size_t copied
= 0, i
;
266 return fuse_buf_size(dstv
);
270 * use writev to improve bandwidth when all the
271 * src buffers already mapped by the daemon
274 for (i
= 0; i
< srcv
->count
; i
++) {
275 if (srcv
->buf
[i
].flags
& FUSE_BUF_IS_FD
) {
279 if ((i
== srcv
->count
) && (dstv
->count
== 1) &&
281 (dstv
->buf
[0].flags
& FUSE_BUF_IS_FD
)) {
282 dstv
->buf
[0].pos
+= dstv
->off
;
283 return fuse_buf_writev(&dstv
->buf
[0], srcv
);
287 const struct fuse_buf
*src
= fuse_bufvec_current(srcv
);
288 const struct fuse_buf
*dst
= fuse_bufvec_current(dstv
);
294 if (src
== NULL
|| dst
== NULL
) {
298 src_len
= src
->size
- srcv
->off
;
299 dst_len
= dst
->size
- dstv
->off
;
300 len
= min_size(src_len
, dst_len
);
302 res
= fuse_buf_copy_one(dst
, dstv
->off
, src
, srcv
->off
, len
);
311 if (!fuse_bufvec_advance(srcv
, res
) ||
312 !fuse_bufvec_advance(dstv
, res
)) {
324 void *fuse_mbuf_iter_advance(struct fuse_mbuf_iter
*iter
, size_t len
)
328 if (len
> iter
->size
- iter
->pos
) {
332 ptr
= iter
->mem
+ iter
->pos
;
337 const char *fuse_mbuf_iter_advance_str(struct fuse_mbuf_iter
*iter
)
339 const char *str
= iter
->mem
+ iter
->pos
;
340 size_t remaining
= iter
->size
- iter
->pos
;
343 for (i
= 0; i
< remaining
; i
++) {
344 if (str
[i
] == '\0') {