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