2 FUSE: Filesystem in Userspace
3 Copyright (C) 2010 Miklos Szeredi <miklos@szeredi.hu>
5 This program can be distributed under the terms of the GNU LGPLv2.
6 See the file COPYING.LIB
12 #include "fuse_lowlevel.h"
18 size_t fuse_buf_size(const struct fuse_bufvec
*bufv
)
23 for (i
= 0; i
< bufv
->count
; i
++) {
24 if (bufv
->buf
[i
].size
== SIZE_MAX
)
27 size
+= bufv
->buf
[i
].size
;
33 static size_t min_size(size_t s1
, size_t s2
)
35 return s1
< s2
? s1
: s2
;
38 static ssize_t
fuse_buf_write(const struct fuse_buf
*dst
, size_t dst_off
,
39 const struct fuse_buf
*src
, size_t src_off
,
46 if (dst
->flags
& FUSE_BUF_FD_SEEK
) {
47 res
= pwrite(dst
->fd
, src
->mem
+ src_off
, len
,
50 res
= write(dst
->fd
, src
->mem
+ src_off
, len
);
61 if (!(dst
->flags
& FUSE_BUF_FD_RETRY
))
72 static ssize_t
fuse_buf_read(const struct fuse_buf
*dst
, size_t dst_off
,
73 const struct fuse_buf
*src
, size_t src_off
,
80 if (src
->flags
& FUSE_BUF_FD_SEEK
) {
81 res
= pread(src
->fd
, dst
->mem
+ dst_off
, len
,
84 res
= read(src
->fd
, dst
->mem
+ dst_off
, len
);
95 if (!(src
->flags
& FUSE_BUF_FD_RETRY
))
106 static ssize_t
fuse_buf_fd_to_fd(const struct fuse_buf
*dst
, size_t dst_off
,
107 const struct fuse_buf
*src
, size_t src_off
,
111 struct fuse_buf tmp
= {
121 size_t this_len
= min_size(tmp
.size
, len
);
124 res
= fuse_buf_read(&tmp
, 0, src
, src_off
, this_len
);
134 res
= fuse_buf_write(dst
, dst_off
, &tmp
, 0, read_len
);
156 static ssize_t
fuse_buf_splice(const struct fuse_buf
*dst
, size_t dst_off
,
157 const struct fuse_buf
*src
, size_t src_off
,
158 size_t len
, enum fuse_buf_copy_flags flags
)
160 int splice_flags
= 0;
161 off_t
*srcpos
= NULL
;
162 off_t
*dstpos
= NULL
;
168 if (flags
& FUSE_BUF_SPLICE_MOVE
)
169 splice_flags
|= SPLICE_F_MOVE
;
170 if (flags
& FUSE_BUF_SPLICE_NONBLOCK
)
171 splice_flags
|= SPLICE_F_NONBLOCK
;
173 if (src
->flags
& FUSE_BUF_FD_SEEK
) {
174 srcpos_val
= src
->pos
+ src_off
;
175 srcpos
= &srcpos_val
;
177 if (dst
->flags
& FUSE_BUF_FD_SEEK
) {
178 dstpos_val
= dst
->pos
+ dst_off
;
179 dstpos
= &dstpos_val
;
183 res
= splice(src
->fd
, srcpos
, dst
->fd
, dstpos
, len
,
189 if (errno
!= EINVAL
|| (flags
& FUSE_BUF_FORCE_SPLICE
))
192 /* Maybe splice is not supported for this combination */
193 return fuse_buf_fd_to_fd(dst
, dst_off
, src
, src_off
,
200 if (!(src
->flags
& FUSE_BUF_FD_RETRY
) &&
201 !(dst
->flags
& FUSE_BUF_FD_RETRY
)) {
212 static ssize_t
fuse_buf_copy_one(const struct fuse_buf
*dst
, size_t dst_off
,
213 const struct fuse_buf
*src
, size_t src_off
,
214 size_t len
, enum fuse_buf_copy_flags flags
)
216 int src_is_fd
= src
->flags
& FUSE_BUF_IS_FD
;
217 int dst_is_fd
= dst
->flags
& FUSE_BUF_IS_FD
;
219 if (!src_is_fd
&& !dst_is_fd
) {
220 void *dstmem
= dst
->mem
+ dst_off
;
221 void *srcmem
= src
->mem
+ src_off
;
223 if (dstmem
!= srcmem
) {
224 if (dstmem
+ len
<= srcmem
|| srcmem
+ len
<= dstmem
)
225 memcpy(dstmem
, srcmem
, len
);
227 memmove(dstmem
, srcmem
, len
);
231 } else if (!src_is_fd
) {
232 return fuse_buf_write(dst
, dst_off
, src
, src_off
, len
);
233 } else if (!dst_is_fd
) {
234 return fuse_buf_read(dst
, dst_off
, src
, src_off
, len
);
235 } else if (flags
& FUSE_BUF_NO_SPLICE
) {
236 return fuse_buf_fd_to_fd(dst
, dst_off
, src
, src_off
, len
);
238 return fuse_buf_splice(dst
, dst_off
, src
, src_off
, len
, flags
);
242 static const struct fuse_buf
*fuse_bufvec_current(struct fuse_bufvec
*bufv
)
244 if (bufv
->idx
< bufv
->count
)
245 return &bufv
->buf
[bufv
->idx
];
250 static int fuse_bufvec_advance(struct fuse_bufvec
*bufv
, size_t len
)
252 const struct fuse_buf
*buf
= fuse_bufvec_current(bufv
);
255 assert(bufv
->off
<= buf
->size
);
256 if (bufv
->off
== buf
->size
) {
257 assert(bufv
->idx
< bufv
->count
);
259 if (bufv
->idx
== bufv
->count
)
266 ssize_t
fuse_buf_copy(struct fuse_bufvec
*dstv
, struct fuse_bufvec
*srcv
,
267 enum fuse_buf_copy_flags flags
)
272 return fuse_buf_size(dstv
);
275 const struct fuse_buf
*src
= fuse_bufvec_current(srcv
);
276 const struct fuse_buf
*dst
= fuse_bufvec_current(dstv
);
282 if (src
== NULL
|| dst
== NULL
)
285 src_len
= src
->size
- srcv
->off
;
286 dst_len
= dst
->size
- dstv
->off
;
287 len
= min_size(src_len
, dst_len
);
289 res
= fuse_buf_copy_one(dst
, dstv
->off
, src
, srcv
->off
, len
, flags
);
297 if (!fuse_bufvec_advance(srcv
, res
) ||
298 !fuse_bufvec_advance(dstv
, res
))