"Fossies" - the Fresh Open Source Software Archive

Member "fuse-3.10.4/doc/html/passthrough__ll_8c_source.html" (9 Jun 2021, 220907 Bytes) of package /linux/misc/fuse-3.10.4.tar.xz:


Caution: In this restricted "Fossies" environment the current HTML page may not be correctly presentated and may have some non-functional links. You can here alternatively try to browse the pure source code or just view or download the uninterpreted raw source code. If the rendering is insufficient you may try to find and view the page on the project site itself.

libfuse
passthrough_ll.c
Go to the documentation of this file.
1 /*
2  FUSE: Filesystem in Userspace
3  Copyright (C) 2001-2007 Miklos Szeredi <miklos@szeredi.hu>
4 
5  This program can be distributed under the terms of the GNU GPLv2.
6  See the file COPYING.
7 */
8 
37 #define _GNU_SOURCE
38 #define FUSE_USE_VERSION 34
39 
40 #include "config.h"
41 
42 #include <fuse_lowlevel.h>
43 #include <unistd.h>
44 #include <stdlib.h>
45 #include <stdio.h>
46 #include <stddef.h>
47 #include <stdbool.h>
48 #include <string.h>
49 #include <limits.h>
50 #include <dirent.h>
51 #include <assert.h>
52 #include <errno.h>
53 #include <inttypes.h>
54 #include <pthread.h>
55 #include <sys/file.h>
56 #include <sys/xattr.h>
57 
58 #include "passthrough_helpers.h"
59 
60 /* We are re-using pointers to our `struct lo_inode` and `struct
61  lo_dirp` elements as inodes. This means that we must be able to
62  store uintptr_t values in a fuse_ino_t variable. The following
63  incantation checks this condition at compile time. */
64 #if defined(__GNUC__) && (__GNUC__ > 4 || __GNUC__ == 4 && __GNUC_MINOR__ >= 6) && !defined __cplusplus
65 _Static_assert(sizeof(fuse_ino_t) >= sizeof(uintptr_t),
66  "fuse_ino_t too small to hold uintptr_t values!");
67 #else
68 struct _uintptr_to_must_hold_fuse_ino_t_dummy_struct \
69  { unsigned _uintptr_to_must_hold_fuse_ino_t:
70  ((sizeof(fuse_ino_t) >= sizeof(uintptr_t)) ? 1 : -1); };
71 #endif
72 
73 struct lo_inode {
74  struct lo_inode *next; /* protected by lo->mutex */
75  struct lo_inode *prev; /* protected by lo->mutex */
76  int fd;
77  ino_t ino;
78  dev_t dev;
79  uint64_t refcount; /* protected by lo->mutex */
80 };
81 
82 enum {
83  CACHE_NEVER,
84  CACHE_NORMAL,
85  CACHE_ALWAYS,
86 };
87 
88 struct lo_data {
89  pthread_mutex_t mutex;
90  int debug;
91  int writeback;
92  int flock;
93  int xattr;
94  const char *source;
95  double timeout;
96  int cache;
97  int timeout_set;
98  struct lo_inode root; /* protected by lo->mutex */
99 };
100 
101 static const struct fuse_opt lo_opts[] = {
102  { "writeback",
103  offsetof(struct lo_data, writeback), 1 },
104  { "no_writeback",
105  offsetof(struct lo_data, writeback), 0 },
106  { "source=%s",
107  offsetof(struct lo_data, source), 0 },
108  { "flock",
109  offsetof(struct lo_data, flock), 1 },
110  { "no_flock",
111  offsetof(struct lo_data, flock), 0 },
112  { "xattr",
113  offsetof(struct lo_data, xattr), 1 },
114  { "no_xattr",
115  offsetof(struct lo_data, xattr), 0 },
116  { "timeout=%lf",
117  offsetof(struct lo_data, timeout), 0 },
118  { "timeout=",
119  offsetof(struct lo_data, timeout_set), 1 },
120  { "cache=never",
121  offsetof(struct lo_data, cache), CACHE_NEVER },
122  { "cache=auto",
123  offsetof(struct lo_data, cache), CACHE_NORMAL },
124  { "cache=always",
125  offsetof(struct lo_data, cache), CACHE_ALWAYS },
126 
128 };
129 
130 static struct lo_data *lo_data(fuse_req_t req)
131 {
132  return (struct lo_data *) fuse_req_userdata(req);
133 }
134 
135 static struct lo_inode *lo_inode(fuse_req_t req, fuse_ino_t ino)
136 {
137  if (ino == FUSE_ROOT_ID)
138  return &lo_data(req)->root;
139  else
140  return (struct lo_inode *) (uintptr_t) ino;
141 }
142 
143 static int lo_fd(fuse_req_t req, fuse_ino_t ino)
144 {
145  return lo_inode(req, ino)->fd;
146 }
147 
148 static bool lo_debug(fuse_req_t req)
149 {
150  return lo_data(req)->debug != 0;
151 }
152 
153 static void lo_init(void *userdata,
154  struct fuse_conn_info *conn)
155 {
156  struct lo_data *lo = (struct lo_data*) userdata;
157 
158  if(conn->capable & FUSE_CAP_EXPORT_SUPPORT)
159  conn->want |= FUSE_CAP_EXPORT_SUPPORT;
160 
161  if (lo->writeback &&
163  if (lo->debug)
164  fuse_log(FUSE_LOG_DEBUG, "lo_init: activating writeback\n");
166  }
167  if (lo->flock && conn->capable & FUSE_CAP_FLOCK_LOCKS) {
168  if (lo->debug)
169  fuse_log(FUSE_LOG_DEBUG, "lo_init: activating flock locks\n");
170  conn->want |= FUSE_CAP_FLOCK_LOCKS;
171  }
172 }
173 
174 static void lo_destroy(void *userdata)
175 {
176  struct lo_data *lo = (struct lo_data*) userdata;
177 
178  while (lo->root.next != &lo->root) {
179  struct lo_inode* next = lo->root.next;
180  lo->root.next = next->next;
181  free(next);
182  }
183 }
184 
185 static void lo_getattr(fuse_req_t req, fuse_ino_t ino,
186  struct fuse_file_info *fi)
187 {
188  int res;
189  struct stat buf;
190  struct lo_data *lo = lo_data(req);
191 
192  (void) fi;
193 
194  res = fstatat(lo_fd(req, ino), "", &buf, AT_EMPTY_PATH | AT_SYMLINK_NOFOLLOW);
195  if (res == -1)
196  return (void) fuse_reply_err(req, errno);
197 
198  fuse_reply_attr(req, &buf, lo->timeout);
199 }
200 
201 static void lo_setattr(fuse_req_t req, fuse_ino_t ino, struct stat *attr,
202  int valid, struct fuse_file_info *fi)
203 {
204  int saverr;
205  char procname[64];
206  struct lo_inode *inode = lo_inode(req, ino);
207  int ifd = inode->fd;
208  int res;
209 
210  if (valid & FUSE_SET_ATTR_MODE) {
211  if (fi) {
212  res = fchmod(fi->fh, attr->st_mode);
213  } else {
214  sprintf(procname, "/proc/self/fd/%i", ifd);
215  res = chmod(procname, attr->st_mode);
216  }
217  if (res == -1)
218  goto out_err;
219  }
220  if (valid & (FUSE_SET_ATTR_UID | FUSE_SET_ATTR_GID)) {
221  uid_t uid = (valid & FUSE_SET_ATTR_UID) ?
222  attr->st_uid : (uid_t) -1;
223  gid_t gid = (valid & FUSE_SET_ATTR_GID) ?
224  attr->st_gid : (gid_t) -1;
225 
226  res = fchownat(ifd, "", uid, gid,
227  AT_EMPTY_PATH | AT_SYMLINK_NOFOLLOW);
228  if (res == -1)
229  goto out_err;
230  }
231  if (valid & FUSE_SET_ATTR_SIZE) {
232  if (fi) {
233  res = ftruncate(fi->fh, attr->st_size);
234  } else {
235  sprintf(procname, "/proc/self/fd/%i", ifd);
236  res = truncate(procname, attr->st_size);
237  }
238  if (res == -1)
239  goto out_err;
240  }
241  if (valid & (FUSE_SET_ATTR_ATIME | FUSE_SET_ATTR_MTIME)) {
242  struct timespec tv[2];
243 
244  tv[0].tv_sec = 0;
245  tv[1].tv_sec = 0;
246  tv[0].tv_nsec = UTIME_OMIT;
247  tv[1].tv_nsec = UTIME_OMIT;
248 
249  if (valid & FUSE_SET_ATTR_ATIME_NOW)
250  tv[0].tv_nsec = UTIME_NOW;
251  else if (valid & FUSE_SET_ATTR_ATIME)
252  tv[0] = attr->st_atim;
253 
254  if (valid & FUSE_SET_ATTR_MTIME_NOW)
255  tv[1].tv_nsec = UTIME_NOW;
256  else if (valid & FUSE_SET_ATTR_MTIME)
257  tv[1] = attr->st_mtim;
258 
259  if (fi)
260  res = futimens(fi->fh, tv);
261  else {
262  sprintf(procname, "/proc/self/fd/%i", ifd);
263  res = utimensat(AT_FDCWD, procname, tv, 0);
264  }
265  if (res == -1)
266  goto out_err;
267  }
268 
269  return lo_getattr(req, ino, fi);
270 
271 out_err:
272  saverr = errno;
273  fuse_reply_err(req, saverr);
274 }
275 
276 static struct lo_inode *lo_find(struct lo_data *lo, struct stat *st)
277 {
278  struct lo_inode *p;
279  struct lo_inode *ret = NULL;
280 
281  pthread_mutex_lock(&lo->mutex);
282  for (p = lo->root.next; p != &lo->root; p = p->next) {
283  if (p->ino == st->st_ino && p->dev == st->st_dev) {
284  assert(p->refcount > 0);
285  ret = p;
286  ret->refcount++;
287  break;
288  }
289  }
290  pthread_mutex_unlock(&lo->mutex);
291  return ret;
292 }
293 
294 static int lo_do_lookup(fuse_req_t req, fuse_ino_t parent, const char *name,
295  struct fuse_entry_param *e)
296 {
297  int newfd;
298  int res;
299  int saverr;
300  struct lo_data *lo = lo_data(req);
301  struct lo_inode *inode;
302 
303  memset(e, 0, sizeof(*e));
304  e->attr_timeout = lo->timeout;
305  e->entry_timeout = lo->timeout;
306 
307  newfd = openat(lo_fd(req, parent), name, O_PATH | O_NOFOLLOW);
308  if (newfd == -1)
309  goto out_err;
310 
311  res = fstatat(newfd, "", &e->attr, AT_EMPTY_PATH | AT_SYMLINK_NOFOLLOW);
312  if (res == -1)
313  goto out_err;
314 
315  inode = lo_find(lo_data(req), &e->attr);
316  if (inode) {
317  close(newfd);
318  newfd = -1;
319  } else {
320  struct lo_inode *prev, *next;
321 
322  saverr = ENOMEM;
323  inode = calloc(1, sizeof(struct lo_inode));
324  if (!inode)
325  goto out_err;
326 
327  inode->refcount = 1;
328  inode->fd = newfd;
329  inode->ino = e->attr.st_ino;
330  inode->dev = e->attr.st_dev;
331 
332  pthread_mutex_lock(&lo->mutex);
333  prev = &lo->root;
334  next = prev->next;
335  next->prev = inode;
336  inode->next = next;
337  inode->prev = prev;
338  prev->next = inode;
339  pthread_mutex_unlock(&lo->mutex);
340  }
341  e->ino = (uintptr_t) inode;
342 
343  if (lo_debug(req))
344  fuse_log(FUSE_LOG_DEBUG, " %lli/%s -> %lli\n",
345  (unsigned long long) parent, name, (unsigned long long) e->ino);
346 
347  return 0;
348 
349 out_err:
350  saverr = errno;
351  if (newfd != -1)
352  close(newfd);
353  return saverr;
354 }
355 
356 static void lo_lookup(fuse_req_t req, fuse_ino_t parent, const char *name)
357 {
358  struct fuse_entry_param e;
359  int err;
360 
361  if (lo_debug(req))
362  fuse_log(FUSE_LOG_DEBUG, "lo_lookup(parent=%" PRIu64 ", name=%s)\n",
363  parent, name);
364 
365  err = lo_do_lookup(req, parent, name, &e);
366  if (err)
367  fuse_reply_err(req, err);
368  else
369  fuse_reply_entry(req, &e);
370 }
371 
372 static void lo_mknod_symlink(fuse_req_t req, fuse_ino_t parent,
373  const char *name, mode_t mode, dev_t rdev,
374  const char *link)
375 {
376  int res;
377  int saverr;
378  struct lo_inode *dir = lo_inode(req, parent);
379  struct fuse_entry_param e;
380 
381  res = mknod_wrapper(dir->fd, name, link, mode, rdev);
382 
383  saverr = errno;
384  if (res == -1)
385  goto out;
386 
387  saverr = lo_do_lookup(req, parent, name, &e);
388  if (saverr)
389  goto out;
390 
391  if (lo_debug(req))
392  fuse_log(FUSE_LOG_DEBUG, " %lli/%s -> %lli\n",
393  (unsigned long long) parent, name, (unsigned long long) e.ino);
394 
395  fuse_reply_entry(req, &e);
396  return;
397 
398 out:
399  fuse_reply_err(req, saverr);
400 }
401 
402 static void lo_mknod(fuse_req_t req, fuse_ino_t parent,
403  const char *name, mode_t mode, dev_t rdev)
404 {
405  lo_mknod_symlink(req, parent, name, mode, rdev, NULL);
406 }
407 
408 static void lo_mkdir(fuse_req_t req, fuse_ino_t parent, const char *name,
409  mode_t mode)
410 {
411  lo_mknod_symlink(req, parent, name, S_IFDIR | mode, 0, NULL);
412 }
413 
414 static void lo_symlink(fuse_req_t req, const char *link,
415  fuse_ino_t parent, const char *name)
416 {
417  lo_mknod_symlink(req, parent, name, S_IFLNK, 0, link);
418 }
419 
420 static void lo_link(fuse_req_t req, fuse_ino_t ino, fuse_ino_t parent,
421  const char *name)
422 {
423  int res;
424  struct lo_data *lo = lo_data(req);
425  struct lo_inode *inode = lo_inode(req, ino);
426  struct fuse_entry_param e;
427  char procname[64];
428  int saverr;
429 
430  memset(&e, 0, sizeof(struct fuse_entry_param));
431  e.attr_timeout = lo->timeout;
432  e.entry_timeout = lo->timeout;
433 
434  sprintf(procname, "/proc/self/fd/%i", inode->fd);
435  res = linkat(AT_FDCWD, procname, lo_fd(req, parent), name,
436  AT_SYMLINK_FOLLOW);
437  if (res == -1)
438  goto out_err;
439 
440  res = fstatat(inode->fd, "", &e.attr, AT_EMPTY_PATH | AT_SYMLINK_NOFOLLOW);
441  if (res == -1)
442  goto out_err;
443 
444  pthread_mutex_lock(&lo->mutex);
445  inode->refcount++;
446  pthread_mutex_unlock(&lo->mutex);
447  e.ino = (uintptr_t) inode;
448 
449  if (lo_debug(req))
450  fuse_log(FUSE_LOG_DEBUG, " %lli/%s -> %lli\n",
451  (unsigned long long) parent, name,
452  (unsigned long long) e.ino);
453 
454  fuse_reply_entry(req, &e);
455  return;
456 
457 out_err:
458  saverr = errno;
459  fuse_reply_err(req, saverr);
460 }
461 
462 static void lo_rmdir(fuse_req_t req, fuse_ino_t parent, const char *name)
463 {
464  int res;
465 
466  res = unlinkat(lo_fd(req, parent), name, AT_REMOVEDIR);
467 
468  fuse_reply_err(req, res == -1 ? errno : 0);
469 }
470 
471 static void lo_rename(fuse_req_t req, fuse_ino_t parent, const char *name,
472  fuse_ino_t newparent, const char *newname,
473  unsigned int flags)
474 {
475  int res;
476 
477  if (flags) {
478  fuse_reply_err(req, EINVAL);
479  return;
480  }
481 
482  res = renameat(lo_fd(req, parent), name,
483  lo_fd(req, newparent), newname);
484 
485  fuse_reply_err(req, res == -1 ? errno : 0);
486 }
487 
488 static void lo_unlink(fuse_req_t req, fuse_ino_t parent, const char *name)
489 {
490  int res;
491 
492  res = unlinkat(lo_fd(req, parent), name, 0);
493 
494  fuse_reply_err(req, res == -1 ? errno : 0);
495 }
496 
497 static void unref_inode(struct lo_data *lo, struct lo_inode *inode, uint64_t n)
498 {
499  if (!inode)
500  return;
501 
502  pthread_mutex_lock(&lo->mutex);
503  assert(inode->refcount >= n);
504  inode->refcount -= n;
505  if (!inode->refcount) {
506  struct lo_inode *prev, *next;
507 
508  prev = inode->prev;
509  next = inode->next;
510  next->prev = prev;
511  prev->next = next;
512 
513  pthread_mutex_unlock(&lo->mutex);
514  close(inode->fd);
515  free(inode);
516 
517  } else {
518  pthread_mutex_unlock(&lo->mutex);
519  }
520 }
521 
522 static void lo_forget_one(fuse_req_t req, fuse_ino_t ino, uint64_t nlookup)
523 {
524  struct lo_data *lo = lo_data(req);
525  struct lo_inode *inode = lo_inode(req, ino);
526 
527  if (lo_debug(req)) {
528  fuse_log(FUSE_LOG_DEBUG, " forget %lli %lli -%lli\n",
529  (unsigned long long) ino,
530  (unsigned long long) inode->refcount,
531  (unsigned long long) nlookup);
532  }
533 
534  unref_inode(lo, inode, nlookup);
535 }
536 
537 static void lo_forget(fuse_req_t req, fuse_ino_t ino, uint64_t nlookup)
538 {
539  lo_forget_one(req, ino, nlookup);
540  fuse_reply_none(req);
541 }
542 
543 static void lo_forget_multi(fuse_req_t req, size_t count,
544  struct fuse_forget_data *forgets)
545 {
546  int i;
547 
548  for (i = 0; i < count; i++)
549  lo_forget_one(req, forgets[i].ino, forgets[i].nlookup);
550  fuse_reply_none(req);
551 }
552 
553 static void lo_readlink(fuse_req_t req, fuse_ino_t ino)
554 {
555  char buf[PATH_MAX + 1];
556  int res;
557 
558  res = readlinkat(lo_fd(req, ino), "", buf, sizeof(buf));
559  if (res == -1)
560  return (void) fuse_reply_err(req, errno);
561 
562  if (res == sizeof(buf))
563  return (void) fuse_reply_err(req, ENAMETOOLONG);
564 
565  buf[res] = '\0';
566 
567  fuse_reply_readlink(req, buf);
568 }
569 
570 struct lo_dirp {
571  DIR *dp;
572  struct dirent *entry;
573  off_t offset;
574 };
575 
576 static struct lo_dirp *lo_dirp(struct fuse_file_info *fi)
577 {
578  return (struct lo_dirp *) (uintptr_t) fi->fh;
579 }
580 
581 static void lo_opendir(fuse_req_t req, fuse_ino_t ino, struct fuse_file_info *fi)
582 {
583  int error = ENOMEM;
584  struct lo_data *lo = lo_data(req);
585  struct lo_dirp *d;
586  int fd;
587 
588  d = calloc(1, sizeof(struct lo_dirp));
589  if (d == NULL)
590  goto out_err;
591 
592  fd = openat(lo_fd(req, ino), ".", O_RDONLY);
593  if (fd == -1)
594  goto out_errno;
595 
596  d->dp = fdopendir(fd);
597  if (d->dp == NULL)
598  goto out_errno;
599 
600  d->offset = 0;
601  d->entry = NULL;
602 
603  fi->fh = (uintptr_t) d;
604  if (lo->cache == CACHE_ALWAYS)
605  fi->cache_readdir = 1;
606  fuse_reply_open(req, fi);
607  return;
608 
609 out_errno:
610  error = errno;
611 out_err:
612  if (d) {
613  if (fd != -1)
614  close(fd);
615  free(d);
616  }
617  fuse_reply_err(req, error);
618 }
619 
620 static int is_dot_or_dotdot(const char *name)
621 {
622  return name[0] == '.' && (name[1] == '\0' ||
623  (name[1] == '.' && name[2] == '\0'));
624 }
625 
626 static void lo_do_readdir(fuse_req_t req, fuse_ino_t ino, size_t size,
627  off_t offset, struct fuse_file_info *fi, int plus)
628 {
629  struct lo_dirp *d = lo_dirp(fi);
630  char *buf;
631  char *p;
632  size_t rem = size;
633  int err;
634 
635  (void) ino;
636 
637  buf = calloc(1, size);
638  if (!buf) {
639  err = ENOMEM;
640  goto error;
641  }
642  p = buf;
643 
644  if (offset != d->offset) {
645  seekdir(d->dp, offset);
646  d->entry = NULL;
647  d->offset = offset;
648  }
649  while (1) {
650  size_t entsize;
651  off_t nextoff;
652  const char *name;
653 
654  if (!d->entry) {
655  errno = 0;
656  d->entry = readdir(d->dp);
657  if (!d->entry) {
658  if (errno) { // Error
659  err = errno;
660  goto error;
661  } else { // End of stream
662  break;
663  }
664  }
665  }
666  nextoff = d->entry->d_off;
667  name = d->entry->d_name;
668  fuse_ino_t entry_ino = 0;
669  if (plus) {
670  struct fuse_entry_param e;
671  if (is_dot_or_dotdot(name)) {
672  e = (struct fuse_entry_param) {
673  .attr.st_ino = d->entry->d_ino,
674  .attr.st_mode = d->entry->d_type << 12,
675  };
676  } else {
677  err = lo_do_lookup(req, ino, name, &e);
678  if (err)
679  goto error;
680  entry_ino = e.ino;
681  }
682 
683  entsize = fuse_add_direntry_plus(req, p, rem, name,
684  &e, nextoff);
685  } else {
686  struct stat st = {
687  .st_ino = d->entry->d_ino,
688  .st_mode = d->entry->d_type << 12,
689  };
690  entsize = fuse_add_direntry(req, p, rem, name,
691  &st, nextoff);
692  }
693  if (entsize > rem) {
694  if (entry_ino != 0)
695  lo_forget_one(req, entry_ino, 1);
696  break;
697  }
698 
699  p += entsize;
700  rem -= entsize;
701 
702  d->entry = NULL;
703  d->offset = nextoff;
704  }
705 
706  err = 0;
707 error:
708  // If there's an error, we can only signal it if we haven't stored
709  // any entries yet - otherwise we'd end up with wrong lookup
710  // counts for the entries that are already in the buffer. So we
711  // return what we've collected until that point.
712  if (err && rem == size)
713  fuse_reply_err(req, err);
714  else
715  fuse_reply_buf(req, buf, size - rem);
716  free(buf);
717 }
718 
719 static void lo_readdir(fuse_req_t req, fuse_ino_t ino, size_t size,
720  off_t offset, struct fuse_file_info *fi)
721 {
722  lo_do_readdir(req, ino, size, offset, fi, 0);
723 }
724 
725 static void lo_readdirplus(fuse_req_t req, fuse_ino_t ino, size_t size,
726  off_t offset, struct fuse_file_info *fi)
727 {
728  lo_do_readdir(req, ino, size, offset, fi, 1);
729 }
730 
731 static void lo_releasedir(fuse_req_t req, fuse_ino_t ino, struct fuse_file_info *fi)
732 {
733  struct lo_dirp *d = lo_dirp(fi);
734  (void) ino;
735  closedir(d->dp);
736  free(d);
737  fuse_reply_err(req, 0);
738 }
739 
740 static void lo_create(fuse_req_t req, fuse_ino_t parent, const char *name,
741  mode_t mode, struct fuse_file_info *fi)
742 {
743  int fd;
744  struct lo_data *lo = lo_data(req);
745  struct fuse_entry_param e;
746  int err;
747 
748  if (lo_debug(req))
749  fuse_log(FUSE_LOG_DEBUG, "lo_create(parent=%" PRIu64 ", name=%s)\n",
750  parent, name);
751 
752  fd = openat(lo_fd(req, parent), name,
753  (fi->flags | O_CREAT) & ~O_NOFOLLOW, mode);
754  if (fd == -1)
755  return (void) fuse_reply_err(req, errno);
756 
757  fi->fh = fd;
758  if (lo->cache == CACHE_NEVER)
759  fi->direct_io = 1;
760  else if (lo->cache == CACHE_ALWAYS)
761  fi->keep_cache = 1;
762 
763  err = lo_do_lookup(req, parent, name, &e);
764  if (err)
765  fuse_reply_err(req, err);
766  else
767  fuse_reply_create(req, &e, fi);
768 }
769 
770 static void lo_fsyncdir(fuse_req_t req, fuse_ino_t ino, int datasync,
771  struct fuse_file_info *fi)
772 {
773  int res;
774  int fd = dirfd(lo_dirp(fi)->dp);
775  (void) ino;
776  if (datasync)
777  res = fdatasync(fd);
778  else
779  res = fsync(fd);
780  fuse_reply_err(req, res == -1 ? errno : 0);
781 }
782 
783 static void lo_open(fuse_req_t req, fuse_ino_t ino, struct fuse_file_info *fi)
784 {
785  int fd;
786  char buf[64];
787  struct lo_data *lo = lo_data(req);
788 
789  if (lo_debug(req))
790  fuse_log(FUSE_LOG_DEBUG, "lo_open(ino=%" PRIu64 ", flags=%d)\n",
791  ino, fi->flags);
792 
793  /* With writeback cache, kernel may send read requests even
794  when userspace opened write-only */
795  if (lo->writeback && (fi->flags & O_ACCMODE) == O_WRONLY) {
796  fi->flags &= ~O_ACCMODE;
797  fi->flags |= O_RDWR;
798  }
799 
800  /* With writeback cache, O_APPEND is handled by the kernel.
801  This breaks atomicity (since the file may change in the
802  underlying filesystem, so that the kernel's idea of the
803  end of the file isn't accurate anymore). In this example,
804  we just accept that. A more rigorous filesystem may want
805  to return an error here */
806  if (lo->writeback && (fi->flags & O_APPEND))
807  fi->flags &= ~O_APPEND;
808 
809  sprintf(buf, "/proc/self/fd/%i", lo_fd(req, ino));
810  fd = open(buf, fi->flags & ~O_NOFOLLOW);
811  if (fd == -1)
812  return (void) fuse_reply_err(req, errno);
813 
814  fi->fh = fd;
815  if (lo->cache == CACHE_NEVER)
816  fi->direct_io = 1;
817  else if (lo->cache == CACHE_ALWAYS)
818  fi->keep_cache = 1;
819  fuse_reply_open(req, fi);
820 }
821 
822 static void lo_release(fuse_req_t req, fuse_ino_t ino, struct fuse_file_info *fi)
823 {
824  (void) ino;
825 
826  close(fi->fh);
827  fuse_reply_err(req, 0);
828 }
829 
830 static void lo_flush(fuse_req_t req, fuse_ino_t ino, struct fuse_file_info *fi)
831 {
832  int res;
833  (void) ino;
834  res = close(dup(fi->fh));
835  fuse_reply_err(req, res == -1 ? errno : 0);
836 }
837 
838 static void lo_fsync(fuse_req_t req, fuse_ino_t ino, int datasync,
839  struct fuse_file_info *fi)
840 {
841  int res;
842  (void) ino;
843  if (datasync)
844  res = fdatasync(fi->fh);
845  else
846  res = fsync(fi->fh);
847  fuse_reply_err(req, res == -1 ? errno : 0);
848 }
849 
850 static void lo_read(fuse_req_t req, fuse_ino_t ino, size_t size,
851  off_t offset, struct fuse_file_info *fi)
852 {
853  struct fuse_bufvec buf = FUSE_BUFVEC_INIT(size);
854 
855  if (lo_debug(req))
856  fuse_log(FUSE_LOG_DEBUG, "lo_read(ino=%" PRIu64 ", size=%zd, "
857  "off=%lu)\n", ino, size, (unsigned long) offset);
858 
860  buf.buf[0].fd = fi->fh;
861  buf.buf[0].pos = offset;
862 
864 }
865 
866 static void lo_write_buf(fuse_req_t req, fuse_ino_t ino,
867  struct fuse_bufvec *in_buf, off_t off,
868  struct fuse_file_info *fi)
869 {
870  (void) ino;
871  ssize_t res;
872  struct fuse_bufvec out_buf = FUSE_BUFVEC_INIT(fuse_buf_size(in_buf));
873 
874  out_buf.buf[0].flags = FUSE_BUF_IS_FD | FUSE_BUF_FD_SEEK;
875  out_buf.buf[0].fd = fi->fh;
876  out_buf.buf[0].pos = off;
877 
878  if (lo_debug(req))
879  fuse_log(FUSE_LOG_DEBUG, "lo_write(ino=%" PRIu64 ", size=%zd, off=%lu)\n",
880  ino, out_buf.buf[0].size, (unsigned long) off);
881 
882  res = fuse_buf_copy(&out_buf, in_buf, 0);
883  if(res < 0)
884  fuse_reply_err(req, -res);
885  else
886  fuse_reply_write(req, (size_t) res);
887 }
888 
889 static void lo_statfs(fuse_req_t req, fuse_ino_t ino)
890 {
891  int res;
892  struct statvfs stbuf;
893 
894  res = fstatvfs(lo_fd(req, ino), &stbuf);
895  if (res == -1)
896  fuse_reply_err(req, errno);
897  else
898  fuse_reply_statfs(req, &stbuf);
899 }
900 
901 static void lo_fallocate(fuse_req_t req, fuse_ino_t ino, int mode,
902  off_t offset, off_t length, struct fuse_file_info *fi)
903 {
904  int err = EOPNOTSUPP;
905  (void) ino;
906 
907 #ifdef HAVE_FALLOCATE
908  err = fallocate(fi->fh, mode, offset, length);
909  if (err < 0)
910  err = errno;
911 
912 #elif defined(HAVE_POSIX_FALLOCATE)
913  if (mode) {
914  fuse_reply_err(req, EOPNOTSUPP);
915  return;
916  }
917 
918  err = posix_fallocate(fi->fh, offset, length);
919 #endif
920 
921  fuse_reply_err(req, err);
922 }
923 
924 static void lo_flock(fuse_req_t req, fuse_ino_t ino, struct fuse_file_info *fi,
925  int op)
926 {
927  int res;
928  (void) ino;
929 
930  res = flock(fi->fh, op);
931 
932  fuse_reply_err(req, res == -1 ? errno : 0);
933 }
934 
935 static void lo_getxattr(fuse_req_t req, fuse_ino_t ino, const char *name,
936  size_t size)
937 {
938  char *value = NULL;
939  char procname[64];
940  struct lo_inode *inode = lo_inode(req, ino);
941  ssize_t ret;
942  int saverr;
943 
944  saverr = ENOSYS;
945  if (!lo_data(req)->xattr)
946  goto out;
947 
948  if (lo_debug(req)) {
949  fuse_log(FUSE_LOG_DEBUG, "lo_getxattr(ino=%" PRIu64 ", name=%s size=%zd)\n",
950  ino, name, size);
951  }
952 
953  sprintf(procname, "/proc/self/fd/%i", inode->fd);
954 
955  if (size) {
956  value = malloc(size);
957  if (!value)
958  goto out_err;
959 
960  ret = getxattr(procname, name, value, size);
961  if (ret == -1)
962  goto out_err;
963  saverr = 0;
964  if (ret == 0)
965  goto out;
966 
967  fuse_reply_buf(req, value, ret);
968  } else {
969  ret = getxattr(procname, name, NULL, 0);
970  if (ret == -1)
971  goto out_err;
972 
973  fuse_reply_xattr(req, ret);
974  }
975 out_free:
976  free(value);
977  return;
978 
979 out_err:
980  saverr = errno;
981 out:
982  fuse_reply_err(req, saverr);
983  goto out_free;
984 }
985 
986 static void lo_listxattr(fuse_req_t req, fuse_ino_t ino, size_t size)
987 {
988  char *value = NULL;
989  char procname[64];
990  struct lo_inode *inode = lo_inode(req, ino);
991  ssize_t ret;
992  int saverr;
993 
994  saverr = ENOSYS;
995  if (!lo_data(req)->xattr)
996  goto out;
997 
998  if (lo_debug(req)) {
999  fuse_log(FUSE_LOG_DEBUG, "lo_listxattr(ino=%" PRIu64 ", size=%zd)\n",
1000  ino, size);
1001  }
1002 
1003  sprintf(procname, "/proc/self/fd/%i", inode->fd);
1004 
1005  if (size) {
1006  value = malloc(size);
1007  if (!value)
1008  goto out_err;
1009 
1010  ret = listxattr(procname, value, size);
1011  if (ret == -1)
1012  goto out_err;
1013  saverr = 0;
1014  if (ret == 0)
1015  goto out;
1016 
1017  fuse_reply_buf(req, value, ret);
1018  } else {
1019  ret = listxattr(procname, NULL, 0);
1020  if (ret == -1)
1021  goto out_err;
1022 
1023  fuse_reply_xattr(req, ret);
1024  }
1025 out_free:
1026  free(value);
1027  return;
1028 
1029 out_err:
1030  saverr = errno;
1031 out:
1032  fuse_reply_err(req, saverr);
1033  goto out_free;
1034 }
1035 
1036 static void lo_setxattr(fuse_req_t req, fuse_ino_t ino, const char *name,
1037  const char *value, size_t size, int flags)
1038 {
1039  char procname[64];
1040  struct lo_inode *inode = lo_inode(req, ino);
1041  ssize_t ret;
1042  int saverr;
1043 
1044  saverr = ENOSYS;
1045  if (!lo_data(req)->xattr)
1046  goto out;
1047 
1048  if (lo_debug(req)) {
1049  fuse_log(FUSE_LOG_DEBUG, "lo_setxattr(ino=%" PRIu64 ", name=%s value=%s size=%zd)\n",
1050  ino, name, value, size);
1051  }
1052 
1053  sprintf(procname, "/proc/self/fd/%i", inode->fd);
1054 
1055  ret = setxattr(procname, name, value, size, flags);
1056  saverr = ret == -1 ? errno : 0;
1057 
1058 out:
1059  fuse_reply_err(req, saverr);
1060 }
1061 
1062 static void lo_removexattr(fuse_req_t req, fuse_ino_t ino, const char *name)
1063 {
1064  char procname[64];
1065  struct lo_inode *inode = lo_inode(req, ino);
1066  ssize_t ret;
1067  int saverr;
1068 
1069  saverr = ENOSYS;
1070  if (!lo_data(req)->xattr)
1071  goto out;
1072 
1073  if (lo_debug(req)) {
1074  fuse_log(FUSE_LOG_DEBUG, "lo_removexattr(ino=%" PRIu64 ", name=%s)\n",
1075  ino, name);
1076  }
1077 
1078  sprintf(procname, "/proc/self/fd/%i", inode->fd);
1079 
1080  ret = removexattr(procname, name);
1081  saverr = ret == -1 ? errno : 0;
1082 
1083 out:
1084  fuse_reply_err(req, saverr);
1085 }
1086 
1087 #ifdef HAVE_COPY_FILE_RANGE
1088 static void lo_copy_file_range(fuse_req_t req, fuse_ino_t ino_in, off_t off_in,
1089  struct fuse_file_info *fi_in,
1090  fuse_ino_t ino_out, off_t off_out,
1091  struct fuse_file_info *fi_out, size_t len,
1092  int flags)
1093 {
1094  ssize_t res;
1095 
1096  if (lo_debug(req))
1097  fuse_log(FUSE_LOG_DEBUG, "lo_copy_file_range(ino=%" PRIu64 "/fd=%lu, "
1098  "off=%lu, ino=%" PRIu64 "/fd=%lu, "
1099  "off=%lu, size=%zd, flags=0x%x)\n",
1100  ino_in, fi_in->fh, off_in, ino_out, fi_out->fh, off_out,
1101  len, flags);
1102 
1103  res = copy_file_range(fi_in->fh, &off_in, fi_out->fh, &off_out, len,
1104  flags);
1105  if (res < 0)
1106  fuse_reply_err(req, errno);
1107  else
1108  fuse_reply_write(req, res);
1109 }
1110 #endif
1111 
1112 static void lo_lseek(fuse_req_t req, fuse_ino_t ino, off_t off, int whence,
1113  struct fuse_file_info *fi)
1114 {
1115  off_t res;
1116 
1117  (void)ino;
1118  res = lseek(fi->fh, off, whence);
1119  if (res != -1)
1120  fuse_reply_lseek(req, res);
1121  else
1122  fuse_reply_err(req, errno);
1123 }
1124 
1125 static const struct fuse_lowlevel_ops lo_oper = {
1126  .init = lo_init,
1127  .destroy = lo_destroy,
1128  .lookup = lo_lookup,
1129  .mkdir = lo_mkdir,
1130  .mknod = lo_mknod,
1131  .symlink = lo_symlink,
1132  .link = lo_link,
1133  .unlink = lo_unlink,
1134  .rmdir = lo_rmdir,
1135  .rename = lo_rename,
1136  .forget = lo_forget,
1137  .forget_multi = lo_forget_multi,
1138  .getattr = lo_getattr,
1139  .setattr = lo_setattr,
1140  .readlink = lo_readlink,
1141  .opendir = lo_opendir,
1142  .readdir = lo_readdir,
1143  .readdirplus = lo_readdirplus,
1144  .releasedir = lo_releasedir,
1145  .fsyncdir = lo_fsyncdir,
1146  .create = lo_create,
1147  .open = lo_open,
1148  .release = lo_release,
1149  .flush = lo_flush,
1150  .fsync = lo_fsync,
1151  .read = lo_read,
1152  .write_buf = lo_write_buf,
1153  .statfs = lo_statfs,
1154  .fallocate = lo_fallocate,
1155  .flock = lo_flock,
1156  .getxattr = lo_getxattr,
1157  .listxattr = lo_listxattr,
1158  .setxattr = lo_setxattr,
1159  .removexattr = lo_removexattr,
1160 #ifdef HAVE_COPY_FILE_RANGE
1161  .copy_file_range = lo_copy_file_range,
1162 #endif
1163  .lseek = lo_lseek,
1164 };
1165 
1166 int main(int argc, char *argv[])
1167 {
1168  struct fuse_args args = FUSE_ARGS_INIT(argc, argv);
1169  struct fuse_session *se;
1170  struct fuse_cmdline_opts opts;
1171  struct fuse_loop_config config;
1172  struct lo_data lo = { .debug = 0,
1173  .writeback = 0 };
1174  int ret = -1;
1175 
1176  /* Don't mask creation mode, kernel already did that */
1177  umask(0);
1178 
1179  pthread_mutex_init(&lo.mutex, NULL);
1180  lo.root.next = lo.root.prev = &lo.root;
1181  lo.root.fd = -1;
1182  lo.cache = CACHE_NORMAL;
1183 
1184  if (fuse_parse_cmdline(&args, &opts) != 0)
1185  return 1;
1186  if (opts.show_help) {
1187  printf("usage: %s [options] <mountpoint>\n\n", argv[0]);
1190  ret = 0;
1191  goto err_out1;
1192  } else if (opts.show_version) {
1193  printf("FUSE library version %s\n", fuse_pkgversion());
1195  ret = 0;
1196  goto err_out1;
1197  }
1198 
1199  if(opts.mountpoint == NULL) {
1200  printf("usage: %s [options] <mountpoint>\n", argv[0]);
1201  printf(" %s --help\n", argv[0]);
1202  ret = 1;
1203  goto err_out1;
1204  }
1205 
1206  if (fuse_opt_parse(&args, &lo, lo_opts, NULL)== -1)
1207  return 1;
1208 
1209  lo.debug = opts.debug;
1210  lo.root.refcount = 2;
1211  if (lo.source) {
1212  struct stat stat;
1213  int res;
1214 
1215  res = lstat(lo.source, &stat);
1216  if (res == -1) {
1217  fuse_log(FUSE_LOG_ERR, "failed to stat source (\"%s\"): %m\n",
1218  lo.source);
1219  exit(1);
1220  }
1221  if (!S_ISDIR(stat.st_mode)) {
1222  fuse_log(FUSE_LOG_ERR, "source is not a directory\n");
1223  exit(1);
1224  }
1225 
1226  } else {
1227  lo.source = "/";
1228  }
1229  if (!lo.timeout_set) {
1230  switch (lo.cache) {
1231  case CACHE_NEVER:
1232  lo.timeout = 0.0;
1233  break;
1234 
1235  case CACHE_NORMAL:
1236  lo.timeout = 1.0;
1237  break;
1238 
1239  case CACHE_ALWAYS:
1240  lo.timeout = 86400.0;
1241  break;
1242  }
1243  } else if (lo.timeout < 0) {
1244  fuse_log(FUSE_LOG_ERR, "timeout is negative (%lf)\n",
1245  lo.timeout);
1246  exit(1);
1247  }
1248 
1249  lo.root.fd = open(lo.source, O_PATH);
1250  if (lo.root.fd == -1) {
1251  fuse_log(FUSE_LOG_ERR, "open(\"%s\", O_PATH): %m\n",
1252  lo.source);
1253  exit(1);
1254  }
1255 
1256  se = fuse_session_new(&args, &lo_oper, sizeof(lo_oper), &lo);
1257  if (se == NULL)
1258  goto err_out1;
1259 
1260  if (fuse_set_signal_handlers(se) != 0)
1261  goto err_out2;
1262 
1263  if (fuse_session_mount(se, opts.mountpoint) != 0)
1264  goto err_out3;
1265 
1266  fuse_daemonize(opts.foreground);
1267 
1268  /* Block until ctrl+c or fusermount -u */
1269  if (opts.singlethread)
1270  ret = fuse_session_loop(se);
1271  else {
1272  config.clone_fd = opts.clone_fd;
1273  config.max_idle_threads = opts.max_idle_threads;
1274  ret = fuse_session_loop_mt(se, &config);
1275  }
1276 
1278 err_out3:
1280 err_out2:
1282 err_out1:
1283  free(opts.mountpoint);
1284  fuse_opt_free_args(&args);
1285 
1286  if (lo.root.fd >= 0)
1287  close(lo.root.fd);
1288 
1289  return ret ? 1 : 0;
1290 }
void fuse_session_destroy(struct fuse_session *se)
int fuse_reply_err(fuse_req_t req, int err)
size_t off
Definition: fuse_common.h:757
struct fuse_session * fuse_session_new(struct fuse_args *args, const struct fuse_lowlevel_ops *op, size_t op_size, void *userdata)
unsigned capable
Definition: fuse_common.h:459
uint64_t fh
Definition: fuse_common.h:93
int fuse_session_loop(struct fuse_session *se)
Definition: fuse_loop.c:19
void fuse_lowlevel_help(void)
unsigned int direct_io
Definition: fuse_common.h:57
size_t fuse_add_direntry_plus(fuse_req_t req, char *buf, size_t bufsize, const char *name, const struct fuse_entry_param *e, off_t off)
int fuse_reply_data(fuse_req_t req, struct fuse_bufvec *bufv, enum fuse_buf_copy_flags flags)
int fuse_daemonize(int foreground)
Definition: helper.c:225
int fuse_session_mount(struct fuse_session *se, const char *mountpoint)
int fuse_opt_parse(struct fuse_args *args, void *data, const struct fuse_opt opts[], fuse_opt_proc_t proc)
Definition: fuse_opt.c:398
struct fuse_req * fuse_req_t
Definition: fuse_lowlevel.h:49
struct stat attr
Definition: fuse_lowlevel.h:88
size_t fuse_add_direntry(fuse_req_t req, char *buf, size_t bufsize, const char *name, const struct stat *stbuf, off_t off)
void * fuse_req_userdata(fuse_req_t req)
unsigned int keep_cache
Definition: fuse_common.h:64
Definition: fuse_lowlevel.h:59
#define FUSE_CAP_EXPORT_SUPPORT
Definition: fuse_common.h:165
fuse_ino_t ino
Definition: fuse_lowlevel.h:67
int fuse_parse_cmdline(struct fuse_args *args, struct fuse_cmdline_opts *opts)
Definition: helper.c:202
int fuse_reply_xattr(fuse_req_t req, size_t count)
void fuse_cmdline_help(void)
Definition: helper.c:129
int fuse_reply_entry(fuse_req_t req, const struct fuse_entry_param *e)
int fuse_set_signal_handlers(struct fuse_session *se)
Definition: fuse_signals.c:62
int fuse_reply_lseek(fuse_req_t req, off_t off)
off_t pos
Definition: fuse_common.h:732
void fuse_remove_signal_handlers(struct fuse_session *se)
Definition: fuse_signals.c:79
void fuse_lowlevel_version(void)
void fuse_reply_none(fuse_req_t req)
void fuse_opt_free_args(struct fuse_args *args)
Definition: fuse_opt.c:34
int fuse_reply_attr(fuse_req_t req, const struct stat *attr, double attr_timeout)
void fuse_session_unmount(struct fuse_session *se)
#define FUSE_OPT_END
Definition: fuse_opt.h:104
enum fuse_buf_flags flags
Definition: fuse_common.h:711
int fuse_reply_statfs(fuse_req_t req, const struct statvfs *stbuf)
#define FUSE_ROOT_ID
Definition: fuse_lowlevel.h:43
#define FUSE_CAP_FLOCK_LOCKS
Definition: fuse_common.h:211
uint64_t fuse_ino_t
Definition: fuse_lowlevel.h:46
int fuse_session_loop_mt(struct fuse_session *se, struct fuse_loop_config *config)
int fuse_reply_create(fuse_req_t req, const struct fuse_entry_param *e, const struct fuse_file_info *fi)
int fuse_reply_write(fuse_req_t req, size_t count)
#define FUSE_CAP_WRITEBACK_CACHE
Definition: fuse_common.h:296
int fuse_reply_open(fuse_req_t req, const struct fuse_file_info *fi)
unsigned int cache_readdir
Definition: fuse_common.h:84
void fuse_log(enum fuse_log_level level, const char *fmt,...)
Definition: fuse_log.c:33
struct fuse_buf buf[1]
Definition: fuse_common.h:762
unsigned want
Definition: fuse_common.h:467
const char * fuse_pkgversion(void)
Definition: fuse.c:5122
#define FUSE_ARGS_INIT(argc, argv)
Definition: fuse_opt.h:123
size_t fuse_buf_size(const struct fuse_bufvec *bufv)
Definition: buffer.c:22
ssize_t fuse_buf_copy(struct fuse_bufvec *dst, struct fuse_bufvec *src, enum fuse_buf_copy_flags flags)
Definition: buffer.c:284
size_t size
Definition: fuse_common.h:706
double entry_timeout
double attr_timeout
Definition: fuse_lowlevel.h:94
int fuse_reply_readlink(fuse_req_t req, const char *link)
int fuse_reply_buf(fuse_req_t req, const char *buf, size_t size)
void(* init)(void *userdata, struct fuse_conn_info *conn)