You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

326 lines
7.0 KiB

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