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