"Fossies" - the Fresh Open Source Software Archive

Member "fuse-3.2.3/lib/buffer.c" (11 May 2018, 6529 Bytes) of package /linux/misc/fuse-3.2.3.tar.xz:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style: standard) with prefixed line numbers and code folding option. Alternatively you can here view or download the uninterpreted source code file. For more information about "buffer.c" see the Fossies "Dox" file reference documentation.

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