libfuse
passthrough_fh.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  Copyright (C) 2011 Sebastian Pipping <sebastian@pipping.org>
5 
6  This program can be distributed under the terms of the GNU GPLv2.
7  See the file COPYING.
8 */
9 
26 #define FUSE_USE_VERSION 31
27 
28 #define _GNU_SOURCE
29 
30 #include <fuse.h>
31 
32 #ifdef HAVE_LIBULOCKMGR
33 #include <ulockmgr.h>
34 #endif
35 
36 #include <stdio.h>
37 #include <stdlib.h>
38 #include <string.h>
39 #include <unistd.h>
40 #include <fcntl.h>
41 #include <sys/stat.h>
42 #include <dirent.h>
43 #include <errno.h>
44 #include <sys/time.h>
45 #ifdef HAVE_SETXATTR
46 #include <sys/xattr.h>
47 #endif
48 #include <sys/file.h> /* flock(2) */
49 
50 static void *xmp_init(struct fuse_conn_info *conn,
51  struct fuse_config *cfg)
52 {
53  (void) conn;
54  cfg->use_ino = 1;
55  cfg->nullpath_ok = 1;
56 
57  /* Pick up changes from lower filesystem right away. This is
58  also necessary for better hardlink support. When the kernel
59  calls the unlink() handler, it does not know the inode of
60  the to-be-removed entry and can therefore not invalidate
61  the cache of the associated inode - resulting in an
62  incorrect st_nlink value being reported for any remaining
63  hardlinks to this inode. */
64  cfg->entry_timeout = 0;
65  cfg->attr_timeout = 0;
66  cfg->negative_timeout = 0;
67 
68  return NULL;
69 }
70 
71 static int xmp_getattr(const char *path, struct stat *stbuf,
72  struct fuse_file_info *fi)
73 {
74  int res;
75 
76  (void) path;
77 
78  if(fi)
79  res = fstat(fi->fh, stbuf);
80  else
81  res = lstat(path, stbuf);
82  if (res == -1)
83  return -errno;
84 
85  return 0;
86 }
87 
88 static int xmp_access(const char *path, int mask)
89 {
90  int res;
91 
92  res = access(path, mask);
93  if (res == -1)
94  return -errno;
95 
96  return 0;
97 }
98 
99 static int xmp_readlink(const char *path, char *buf, size_t size)
100 {
101  int res;
102 
103  res = readlink(path, buf, size - 1);
104  if (res == -1)
105  return -errno;
106 
107  buf[res] = '\0';
108  return 0;
109 }
110 
111 struct xmp_dirp {
112  DIR *dp;
113  struct dirent *entry;
114  off_t offset;
115 };
116 
117 static int xmp_opendir(const char *path, struct fuse_file_info *fi)
118 {
119  int res;
120  struct xmp_dirp *d = malloc(sizeof(struct xmp_dirp));
121  if (d == NULL)
122  return -ENOMEM;
123 
124  d->dp = opendir(path);
125  if (d->dp == NULL) {
126  res = -errno;
127  free(d);
128  return res;
129  }
130  d->offset = 0;
131  d->entry = NULL;
132 
133  fi->fh = (unsigned long) d;
134  return 0;
135 }
136 
137 static inline struct xmp_dirp *get_dirp(struct fuse_file_info *fi)
138 {
139  return (struct xmp_dirp *) (uintptr_t) fi->fh;
140 }
141 
142 static int xmp_readdir(const char *path, void *buf, fuse_fill_dir_t filler,
143  off_t offset, struct fuse_file_info *fi,
144  enum fuse_readdir_flags flags)
145 {
146  struct xmp_dirp *d = get_dirp(fi);
147 
148  (void) path;
149  if (offset != d->offset) {
150 #ifndef __FreeBSD__
151  seekdir(d->dp, offset);
152 #else
153  /* Subtract the one that we add when calling
154  telldir() below */
155  seekdir(d->dp, offset-1);
156 #endif
157  d->entry = NULL;
158  d->offset = offset;
159  }
160  while (1) {
161  struct stat st;
162  off_t nextoff;
163  enum fuse_fill_dir_flags fill_flags = 0;
164 
165  if (!d->entry) {
166  d->entry = readdir(d->dp);
167  if (!d->entry)
168  break;
169  }
170 #ifdef HAVE_FSTATAT
171  if (flags & FUSE_READDIR_PLUS) {
172  int res;
173 
174  res = fstatat(dirfd(d->dp), d->entry->d_name, &st,
175  AT_SYMLINK_NOFOLLOW);
176  if (res != -1)
177  fill_flags |= FUSE_FILL_DIR_PLUS;
178  }
179 #endif
180  if (!(fill_flags & FUSE_FILL_DIR_PLUS)) {
181  memset(&st, 0, sizeof(st));
182  st.st_ino = d->entry->d_ino;
183  st.st_mode = d->entry->d_type << 12;
184  }
185  nextoff = telldir(d->dp);
186 #ifdef __FreeBSD__
187  /* Under FreeBSD, telldir() may return 0 the first time
188  it is called. But for libfuse, an offset of zero
189  means that offsets are not supported, so we shift
190  everything by one. */
191  nextoff++;
192 #endif
193  if (filler(buf, d->entry->d_name, &st, nextoff, fill_flags))
194  break;
195 
196  d->entry = NULL;
197  d->offset = nextoff;
198  }
199 
200  return 0;
201 }
202 
203 static int xmp_releasedir(const char *path, struct fuse_file_info *fi)
204 {
205  struct xmp_dirp *d = get_dirp(fi);
206  (void) path;
207  closedir(d->dp);
208  free(d);
209  return 0;
210 }
211 
212 static int xmp_mknod(const char *path, mode_t mode, dev_t rdev)
213 {
214  int res;
215 
216  if (S_ISFIFO(mode))
217  res = mkfifo(path, mode);
218  else
219  res = mknod(path, mode, rdev);
220  if (res == -1)
221  return -errno;
222 
223  return 0;
224 }
225 
226 static int xmp_mkdir(const char *path, mode_t mode)
227 {
228  int res;
229 
230  res = mkdir(path, mode);
231  if (res == -1)
232  return -errno;
233 
234  return 0;
235 }
236 
237 static int xmp_unlink(const char *path)
238 {
239  int res;
240 
241  res = unlink(path);
242  if (res == -1)
243  return -errno;
244 
245  return 0;
246 }
247 
248 static int xmp_rmdir(const char *path)
249 {
250  int res;
251 
252  res = rmdir(path);
253  if (res == -1)
254  return -errno;
255 
256  return 0;
257 }
258 
259 static int xmp_symlink(const char *from, const char *to)
260 {
261  int res;
262 
263  res = symlink(from, to);
264  if (res == -1)
265  return -errno;
266 
267  return 0;
268 }
269 
270 static int xmp_rename(const char *from, const char *to, unsigned int flags)
271 {
272  int res;
273 
274  /* When we have renameat2() in libc, then we can implement flags */
275  if (flags)
276  return -EINVAL;
277 
278  res = rename(from, to);
279  if (res == -1)
280  return -errno;
281 
282  return 0;
283 }
284 
285 static int xmp_link(const char *from, const char *to)
286 {
287  int res;
288 
289  res = link(from, to);
290  if (res == -1)
291  return -errno;
292 
293  return 0;
294 }
295 
296 static int xmp_chmod(const char *path, mode_t mode,
297  struct fuse_file_info *fi)
298 {
299  int res;
300 
301  if(fi)
302  res = fchmod(fi->fh, mode);
303  else
304  res = chmod(path, mode);
305  if (res == -1)
306  return -errno;
307 
308  return 0;
309 }
310 
311 static int xmp_chown(const char *path, uid_t uid, gid_t gid,
312  struct fuse_file_info *fi)
313 {
314  int res;
315 
316  if (fi)
317  res = fchown(fi->fh, uid, gid);
318  else
319  res = lchown(path, uid, gid);
320  if (res == -1)
321  return -errno;
322 
323  return 0;
324 }
325 
326 static int xmp_truncate(const char *path, off_t size,
327  struct fuse_file_info *fi)
328 {
329  int res;
330 
331  if(fi)
332  res = ftruncate(fi->fh, size);
333  else
334  res = truncate(path, size);
335 
336  if (res == -1)
337  return -errno;
338 
339  return 0;
340 }
341 
342 #ifdef HAVE_UTIMENSAT
343 static int xmp_utimens(const char *path, const struct timespec ts[2],
344  struct fuse_file_info *fi)
345 {
346  int res;
347 
348  /* don't use utime/utimes since they follow symlinks */
349  if (fi)
350  res = futimens(fi->fh, ts);
351  else
352  res = utimensat(0, path, ts, AT_SYMLINK_NOFOLLOW);
353  if (res == -1)
354  return -errno;
355 
356  return 0;
357 }
358 #endif
359 
360 static int xmp_create(const char *path, mode_t mode, struct fuse_file_info *fi)
361 {
362  int fd;
363 
364  fd = open(path, fi->flags, mode);
365  if (fd == -1)
366  return -errno;
367 
368  fi->fh = fd;
369  return 0;
370 }
371 
372 static int xmp_open(const char *path, struct fuse_file_info *fi)
373 {
374  int fd;
375 
376  fd = open(path, fi->flags);
377  if (fd == -1)
378  return -errno;
379 
380  fi->fh = fd;
381  return 0;
382 }
383 
384 static int xmp_read(const char *path, char *buf, size_t size, off_t offset,
385  struct fuse_file_info *fi)
386 {
387  int res;
388 
389  (void) path;
390  res = pread(fi->fh, buf, size, offset);
391  if (res == -1)
392  res = -errno;
393 
394  return res;
395 }
396 
397 static int xmp_read_buf(const char *path, struct fuse_bufvec **bufp,
398  size_t size, off_t offset, struct fuse_file_info *fi)
399 {
400  struct fuse_bufvec *src;
401 
402  (void) path;
403 
404  src = malloc(sizeof(struct fuse_bufvec));
405  if (src == NULL)
406  return -ENOMEM;
407 
408  *src = FUSE_BUFVEC_INIT(size);
409 
411  src->buf[0].fd = fi->fh;
412  src->buf[0].pos = offset;
413 
414  *bufp = src;
415 
416  return 0;
417 }
418 
419 static int xmp_write(const char *path, const char *buf, size_t size,
420  off_t offset, struct fuse_file_info *fi)
421 {
422  int res;
423 
424  (void) path;
425  res = pwrite(fi->fh, buf, size, offset);
426  if (res == -1)
427  res = -errno;
428 
429  return res;
430 }
431 
432 static int xmp_write_buf(const char *path, struct fuse_bufvec *buf,
433  off_t offset, struct fuse_file_info *fi)
434 {
435  struct fuse_bufvec dst = FUSE_BUFVEC_INIT(fuse_buf_size(buf));
436 
437  (void) path;
438 
440  dst.buf[0].fd = fi->fh;
441  dst.buf[0].pos = offset;
442 
444 }
445 
446 static int xmp_statfs(const char *path, struct statvfs *stbuf)
447 {
448  int res;
449 
450  res = statvfs(path, stbuf);
451  if (res == -1)
452  return -errno;
453 
454  return 0;
455 }
456 
457 static int xmp_flush(const char *path, struct fuse_file_info *fi)
458 {
459  int res;
460 
461  (void) path;
462  /* This is called from every close on an open file, so call the
463  close on the underlying filesystem. But since flush may be
464  called multiple times for an open file, this must not really
465  close the file. This is important if used on a network
466  filesystem like NFS which flush the data/metadata on close() */
467  res = close(dup(fi->fh));
468  if (res == -1)
469  return -errno;
470 
471  return 0;
472 }
473 
474 static int xmp_release(const char *path, struct fuse_file_info *fi)
475 {
476  (void) path;
477  close(fi->fh);
478 
479  return 0;
480 }
481 
482 static int xmp_fsync(const char *path, int isdatasync,
483  struct fuse_file_info *fi)
484 {
485  int res;
486  (void) path;
487 
488 #ifndef HAVE_FDATASYNC
489  (void) isdatasync;
490 #else
491  if (isdatasync)
492  res = fdatasync(fi->fh);
493  else
494 #endif
495  res = fsync(fi->fh);
496  if (res == -1)
497  return -errno;
498 
499  return 0;
500 }
501 
502 #ifdef HAVE_POSIX_FALLOCATE
503 static int xmp_fallocate(const char *path, int mode,
504  off_t offset, off_t length, struct fuse_file_info *fi)
505 {
506  (void) path;
507 
508  if (mode)
509  return -EOPNOTSUPP;
510 
511  return -posix_fallocate(fi->fh, offset, length);
512 }
513 #endif
514 
515 #ifdef HAVE_SETXATTR
516 /* xattr operations are optional and can safely be left unimplemented */
517 static int xmp_setxattr(const char *path, const char *name, const char *value,
518  size_t size, int flags)
519 {
520  int res = lsetxattr(path, name, value, size, flags);
521  if (res == -1)
522  return -errno;
523  return 0;
524 }
525 
526 static int xmp_getxattr(const char *path, const char *name, char *value,
527  size_t size)
528 {
529  int res = lgetxattr(path, name, value, size);
530  if (res == -1)
531  return -errno;
532  return res;
533 }
534 
535 static int xmp_listxattr(const char *path, char *list, size_t size)
536 {
537  int res = llistxattr(path, list, size);
538  if (res == -1)
539  return -errno;
540  return res;
541 }
542 
543 static int xmp_removexattr(const char *path, const char *name)
544 {
545  int res = lremovexattr(path, name);
546  if (res == -1)
547  return -errno;
548  return 0;
549 }
550 #endif /* HAVE_SETXATTR */
551 
552 #ifdef HAVE_LIBULOCKMGR
553 static int xmp_lock(const char *path, struct fuse_file_info *fi, int cmd,
554  struct flock *lock)
555 {
556  (void) path;
557 
558  return ulockmgr_op(fi->fh, cmd, lock, &fi->lock_owner,
559  sizeof(fi->lock_owner));
560 }
561 #endif
562 
563 static int xmp_flock(const char *path, struct fuse_file_info *fi, int op)
564 {
565  int res;
566  (void) path;
567 
568  res = flock(fi->fh, op);
569  if (res == -1)
570  return -errno;
571 
572  return 0;
573 }
574 
575 #ifdef HAVE_COPY_FILE_RANGE
576 static ssize_t xmp_copy_file_range(const char *path_in,
577  struct fuse_file_info *fi_in,
578  off_t off_in, const char *path_out,
579  struct fuse_file_info *fi_out,
580  off_t off_out, size_t len, int flags)
581 {
582  ssize_t res;
583  (void) path_in;
584  (void) path_out;
585 
586  res = copy_file_range(fi_in->fh, &off_in, fi_out->fh, &off_out, len,
587  flags);
588  if (res == -1)
589  return -errno;
590 
591  return res;
592 }
593 #endif
594 
595 static off_t xmp_lseek(const char *path, off_t off, int whence, struct fuse_file_info *fi)
596 {
597  off_t res;
598  (void) path;
599 
600  res = lseek(fi->fh, off, whence);
601  if (res == -1)
602  return -errno;
603 
604  return res;
605 }
606 
607 static const struct fuse_operations xmp_oper = {
608  .init = xmp_init,
609  .getattr = xmp_getattr,
610  .access = xmp_access,
611  .readlink = xmp_readlink,
612  .opendir = xmp_opendir,
613  .readdir = xmp_readdir,
614  .releasedir = xmp_releasedir,
615  .mknod = xmp_mknod,
616  .mkdir = xmp_mkdir,
617  .symlink = xmp_symlink,
618  .unlink = xmp_unlink,
619  .rmdir = xmp_rmdir,
620  .rename = xmp_rename,
621  .link = xmp_link,
622  .chmod = xmp_chmod,
623  .chown = xmp_chown,
624  .truncate = xmp_truncate,
625 #ifdef HAVE_UTIMENSAT
626  .utimens = xmp_utimens,
627 #endif
628  .create = xmp_create,
629  .open = xmp_open,
630  .read = xmp_read,
631  .read_buf = xmp_read_buf,
632  .write = xmp_write,
633  .write_buf = xmp_write_buf,
634  .statfs = xmp_statfs,
635  .flush = xmp_flush,
636  .release = xmp_release,
637  .fsync = xmp_fsync,
638 #ifdef HAVE_POSIX_FALLOCATE
639  .fallocate = xmp_fallocate,
640 #endif
641 #ifdef HAVE_SETXATTR
642  .setxattr = xmp_setxattr,
643  .getxattr = xmp_getxattr,
644  .listxattr = xmp_listxattr,
645  .removexattr = xmp_removexattr,
646 #endif
647 #ifdef HAVE_LIBULOCKMGR
648  .lock = xmp_lock,
649 #endif
650  .flock = xmp_flock,
651 #ifdef HAVE_COPY_FILE_RANGE
652  .copy_file_range = xmp_copy_file_range,
653 #endif
654  .lseek = xmp_lseek,
655 };
656 
657 int main(int argc, char *argv[])
658 {
659  umask(0);
660  return fuse_main(argc, argv, &xmp_oper, NULL);
661 }
int(* fuse_fill_dir_t)(void *buf, const char *name, const struct stat *stbuf, off_t off, enum fuse_fill_dir_flags flags)
Definition: fuse.h:85
#define fuse_main(argc, argv, op, private_data)
Definition: fuse.h:913
fuse_fill_dir_flags
Definition: fuse.h:57
@ FUSE_FILL_DIR_PLUS
Definition: fuse.h:67
fuse_readdir_flags
Definition: fuse.h:42
@ FUSE_READDIR_PLUS
Definition: fuse.h:51
size_t fuse_buf_size(const struct fuse_bufvec *bufv)
Definition: buffer.c:22
@ FUSE_BUF_FD_SEEK
Definition: fuse_common.h:681
@ FUSE_BUF_IS_FD
Definition: fuse_common.h:672
ssize_t fuse_buf_copy(struct fuse_bufvec *dst, struct fuse_bufvec *src, enum fuse_buf_copy_flags flags)
Definition: buffer.c:284
@ FUSE_BUF_SPLICE_NONBLOCK
Definition: fuse_common.h:732
enum fuse_buf_flags flags
Definition: fuse_common.h:750
off_t pos
Definition: fuse_common.h:771
size_t off
Definition: fuse_common.h:796
struct fuse_buf buf[1]
Definition: fuse_common.h:801
double entry_timeout
Definition: fuse.h:122
double negative_timeout
Definition: fuse.h:132
int nullpath_ok
Definition: fuse.h:276
int use_ino
Definition: fuse.h:193
double attr_timeout
Definition: fuse.h:138
uint64_t lock_owner
Definition: fuse_common.h:109
void *(* init)(struct fuse_conn_info *conn, struct fuse_config *cfg)
Definition: fuse.h:616