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