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
414 src->buf[0].flags = FUSE_BUF_IS_FD | FUSE_BUF_FD_SEEK;
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
443 dst.buf[0].flags = FUSE_BUF_IS_FD | FUSE_BUF_FD_SEEK;
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 #ifdef HAVE_COPY_FILE_RANGE
580 static ssize_t xmp_copy_file_range(const char *path_in,
581 struct fuse_file_info *fi_in,
582 off_t off_in, const char *path_out,
583 struct fuse_file_info *fi_out,
584 off_t off_out, size_t len, int flags)
585 {
586 ssize_t res;
587 (void) path_in;
588 (void) path_out;
589
590 res = copy_file_range(fi_in->fh, &off_in, fi_out->fh, &off_out, len,
591 flags);
592 if (res == -1)
593 return -errno;
594
595 return res;
596 }
597 #endif
598
599 static off_t xmp_lseek(const char *path, off_t off, int whence, struct fuse_file_info *fi)
600 {
601 off_t res;
602 (void) path;
603
604 res = lseek(fi->fh, off, whence);
605 if (res == -1)
606 return -errno;
607
608 return res;
609 }
610
611 static struct fuse_operations xmp_oper = {
612 .init = xmp_init,
613 .getattr = xmp_getattr,
614 .access = xmp_access,
615 .readlink = xmp_readlink,
616 .opendir = xmp_opendir,
617 .readdir = xmp_readdir,
618 .releasedir = xmp_releasedir,
619 .mknod = xmp_mknod,
620 .mkdir = xmp_mkdir,
621 .symlink = xmp_symlink,
622 .unlink = xmp_unlink,
623 .rmdir = xmp_rmdir,
624 .rename = xmp_rename,
625 .link = xmp_link,
626 .chmod = xmp_chmod,
627 .chown = xmp_chown,
628 .truncate = xmp_truncate,
629 #ifdef HAVE_UTIMENSAT
630 .utimens = xmp_utimens,
631 #endif
632 .create = xmp_create,
633 .open = xmp_open,
634 .read = xmp_read,
635 .read_buf = xmp_read_buf,
636 .write = xmp_write,
637 .write_buf = xmp_write_buf,
638 .statfs = xmp_statfs,
639 .flush = xmp_flush,
640 .release = xmp_release,
641 .fsync = xmp_fsync,
642 #ifdef HAVE_POSIX_FALLOCATE
643 .fallocate = xmp_fallocate,
644 #endif
645 #ifdef HAVE_SETXATTR
646 .setxattr = xmp_setxattr,
647 .getxattr = xmp_getxattr,
648 .listxattr = xmp_listxattr,
649 .removexattr = xmp_removexattr,
650 #endif
651 #ifdef HAVE_LIBULOCKMGR
652 .lock = xmp_lock,
653 #endif
654 .flock = xmp_flock,
655 #ifdef HAVE_COPY_FILE_RANGE
656 .copy_file_range = xmp_copy_file_range,
657 #endif
658 .lseek = xmp_lseek,
659 };
660
661 int main(int argc, char *argv[])
662 {
663 umask(0);
664 return fuse_main(argc, argv, &xmp_oper, NULL);
665 }
fuse_bufvec::off
size_t off
Definition: fuse_common.h:721
fuse_file_info::fh
uint64_t fh
Definition: fuse_common.h:93
fuse_conn_info
Definition: fuse_common.h:385
fuse_operations::init
void *(* init)(struct fuse_conn_info *conn, struct fuse_config *cfg)
Definition: fuse.h:578
fuse_fill_dir_flags
fuse_fill_dir_flags
Definition: fuse.h:54
fuse_file_info::lock_owner
uint64_t lock_owner
Definition: fuse_common.h:96
FUSE_READDIR_PLUS
Definition: fuse.h:51
fuse_config::nullpath_ok
int nullpath_ok
Definition: fuse.h:265
fuse_config::negative_timeout
double negative_timeout
Definition: fuse.h:129
fuse_operations::readlink
int(* readlink)(const char *, char *, size_t)
Definition: fuse.h:321
fuse_buf::pos
off_t pos
Definition: fuse_common.h:696
fuse_file_info
Definition: fuse_common.h:44
FUSE_FILL_DIR_PLUS
Definition: fuse.h:64
fuse_config::use_ino
int use_ino
Definition: fuse.h:190
fuse_operations
Definition: fuse.h:299
fuse_file_info::flags
int flags
Definition: fuse_common.h:46
fuse_bufvec
Definition: fuse_common.h:707
fuse_buf::flags
enum fuse_buf_flags flags
Definition: fuse_common.h:675
FUSE_BUF_SPLICE_NONBLOCK
Definition: fuse_common.h:657
fuse_buf_copy
ssize_t fuse_buf_copy(struct fuse_bufvec *dst, struct fuse_bufvec *src, enum fuse_buf_copy_flags flags)
Definition: buffer.c:281
FUSE_BUF_FD_SEEK
Definition: fuse_common.h:606
fuse_config::attr_timeout
double attr_timeout
Definition: fuse.h:135
fuse_buf_size
size_t fuse_buf_size(const struct fuse_bufvec *bufv)
Definition: buffer.c:22
fuse_main
#define fuse_main(argc, argv, op, private_data)
Definition: fuse.h:869
fuse_readdir_flags
fuse_readdir_flags
Definition: fuse.h:42
fuse_config
Definition: fuse.h:93
fuse_fill_dir_t
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_bufvec::buf
struct fuse_buf buf[1]
Definition: fuse_common.h:726
fuse_operations::access
int(* access)(const char *, int)
Definition: fuse.h:597
fuse_buf::fd
int fd
Definition: fuse_common.h:689
fuse_config::entry_timeout
double entry_timeout
Definition: fuse.h:119
FUSE_BUF_IS_FD
Definition: fuse_common.h:597