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