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