2 FUSE: Filesystem in Userspace
3 Copyright (C) 2001-2007 Miklos Szeredi <miklos@szeredi.hu>
4 Copyright (C) 2011 Sebastian Pipping <sebastian@pipping.org>
6 This program can be distributed under the terms of the GNU GPL.
13 * fusexmp_fh.c - FUSE: Filesystem in Userspace
15 * \section section_compile compiling this example
17 * gcc -Wall fusexmp_fh.c `pkg-config fuse3 --cflags --libs` -lulockmgr -o fusexmp_fh
19 * \section section_source the complete source
20 * \include fusexmp_fh.c
23 #define FUSE_USE_VERSION 30
33 #ifdef HAVE_LIBULOCKMGR
47 #include <sys/xattr.h>
49 #include <sys/file.h> /* flock(2) */
51 static int xmp_getattr(const char *path
, struct stat
*stbuf
)
55 res
= lstat(path
, stbuf
);
62 static int xmp_fgetattr(const char *path
, struct stat
*stbuf
,
63 struct fuse_file_info
*fi
)
69 res
= fstat(fi
->fh
, stbuf
);
76 static int xmp_access(const char *path
, int mask
)
80 res
= access(path
, mask
);
87 static int xmp_readlink(const char *path
, char *buf
, size_t size
)
91 res
= readlink(path
, buf
, size
- 1);
101 struct dirent
*entry
;
105 static int xmp_opendir(const char *path
, struct fuse_file_info
*fi
)
108 struct xmp_dirp
*d
= malloc(sizeof(struct xmp_dirp
));
112 d
->dp
= opendir(path
);
121 fi
->fh
= (unsigned long) d
;
125 static inline struct xmp_dirp
*get_dirp(struct fuse_file_info
*fi
)
127 return (struct xmp_dirp
*) (uintptr_t) fi
->fh
;
130 static int xmp_readdir(const char *path
, void *buf
, fuse_fill_dir_t filler
,
131 off_t offset
, struct fuse_file_info
*fi
,
132 enum fuse_readdir_flags flags
)
134 struct xmp_dirp
*d
= get_dirp(fi
);
137 if (offset
!= d
->offset
) {
138 seekdir(d
->dp
, offset
);
145 enum fuse_fill_dir_flags fill_flags
= 0;
148 d
->entry
= readdir(d
->dp
);
153 if (flags
& FUSE_READDIR_PLUS
) {
156 res
= fstatat(dirfd(d
->dp
), d
->entry
->d_name
, &st
,
157 AT_SYMLINK_NOFOLLOW
);
159 fill_flags
|= FUSE_FILL_DIR_PLUS
;
162 if (!(fill_flags
& FUSE_FILL_DIR_PLUS
)) {
163 memset(&st
, 0, sizeof(st
));
164 st
.st_ino
= d
->entry
->d_ino
;
165 st
.st_mode
= d
->entry
->d_type
<< 12;
167 nextoff
= telldir(d
->dp
);
168 if (filler(buf
, d
->entry
->d_name
, &st
, nextoff
, fill_flags
))
178 static int xmp_releasedir(const char *path
, struct fuse_file_info
*fi
)
180 struct xmp_dirp
*d
= get_dirp(fi
);
187 static int xmp_mknod(const char *path
, mode_t mode
, dev_t rdev
)
192 res
= mkfifo(path
, mode
);
194 res
= mknod(path
, mode
, rdev
);
201 static int xmp_mkdir(const char *path
, mode_t mode
)
205 res
= mkdir(path
, mode
);
212 static int xmp_unlink(const char *path
)
223 static int xmp_rmdir(const char *path
)
234 static int xmp_symlink(const char *from
, const char *to
)
238 res
= symlink(from
, to
);
245 static int xmp_rename(const char *from
, const char *to
, unsigned int flags
)
249 /* When we have renameat2() in libc, then we can implement flags */
253 res
= rename(from
, to
);
260 static int xmp_link(const char *from
, const char *to
)
264 res
= link(from
, to
);
271 static int xmp_chmod(const char *path
, mode_t mode
)
275 res
= chmod(path
, mode
);
282 static int xmp_chown(const char *path
, uid_t uid
, gid_t gid
)
286 res
= lchown(path
, uid
, gid
);
293 static int xmp_truncate(const char *path
, off_t size
)
297 res
= truncate(path
, size
);
304 static int xmp_ftruncate(const char *path
, off_t size
,
305 struct fuse_file_info
*fi
)
311 res
= ftruncate(fi
->fh
, size
);
318 #ifdef HAVE_UTIMENSAT
319 static int xmp_utimens(const char *path
, const struct timespec ts
[2])
323 /* don't use utime/utimes since they follow symlinks */
324 res
= utimensat(0, path
, ts
, AT_SYMLINK_NOFOLLOW
);
332 static int xmp_create(const char *path
, mode_t mode
, struct fuse_file_info
*fi
)
336 fd
= open(path
, fi
->flags
, mode
);
344 static int xmp_open(const char *path
, struct fuse_file_info
*fi
)
348 fd
= open(path
, fi
->flags
);
356 static int xmp_read(const char *path
, char *buf
, size_t size
, off_t offset
,
357 struct fuse_file_info
*fi
)
362 res
= pread(fi
->fh
, buf
, size
, offset
);
369 static int xmp_read_buf(const char *path
, struct fuse_bufvec
**bufp
,
370 size_t size
, off_t offset
, struct fuse_file_info
*fi
)
372 struct fuse_bufvec
*src
;
376 src
= malloc(sizeof(struct fuse_bufvec
));
380 *src
= FUSE_BUFVEC_INIT(size
);
382 src
->buf
[0].flags
= FUSE_BUF_IS_FD
| FUSE_BUF_FD_SEEK
;
383 src
->buf
[0].fd
= fi
->fh
;
384 src
->buf
[0].pos
= offset
;
391 static int xmp_write(const char *path
, const char *buf
, size_t size
,
392 off_t offset
, struct fuse_file_info
*fi
)
397 res
= pwrite(fi
->fh
, buf
, size
, offset
);
404 static int xmp_write_buf(const char *path
, struct fuse_bufvec
*buf
,
405 off_t offset
, struct fuse_file_info
*fi
)
407 struct fuse_bufvec dst
= FUSE_BUFVEC_INIT(fuse_buf_size(buf
));
411 dst
.buf
[0].flags
= FUSE_BUF_IS_FD
| FUSE_BUF_FD_SEEK
;
412 dst
.buf
[0].fd
= fi
->fh
;
413 dst
.buf
[0].pos
= offset
;
415 return fuse_buf_copy(&dst
, buf
, FUSE_BUF_SPLICE_NONBLOCK
);
418 static int xmp_statfs(const char *path
, struct statvfs
*stbuf
)
422 res
= statvfs(path
, stbuf
);
429 static int xmp_flush(const char *path
, struct fuse_file_info
*fi
)
434 /* This is called from every close on an open file, so call the
435 close on the underlying filesystem. But since flush may be
436 called multiple times for an open file, this must not really
437 close the file. This is important if used on a network
438 filesystem like NFS which flush the data/metadata on close() */
439 res
= close(dup(fi
->fh
));
446 static int xmp_release(const char *path
, struct fuse_file_info
*fi
)
454 static int xmp_fsync(const char *path
, int isdatasync
,
455 struct fuse_file_info
*fi
)
460 #ifndef HAVE_FDATASYNC
464 res
= fdatasync(fi
->fh
);
474 #ifdef HAVE_POSIX_FALLOCATE
475 static int xmp_fallocate(const char *path
, int mode
,
476 off_t offset
, off_t length
, struct fuse_file_info
*fi
)
483 return -posix_fallocate(fi
->fh
, offset
, length
);
488 /* xattr operations are optional and can safely be left unimplemented */
489 static int xmp_setxattr(const char *path
, const char *name
, const char *value
,
490 size_t size
, int flags
)
492 int res
= lsetxattr(path
, name
, value
, size
, flags
);
498 static int xmp_getxattr(const char *path
, const char *name
, char *value
,
501 int res
= lgetxattr(path
, name
, value
, size
);
507 static int xmp_listxattr(const char *path
, char *list
, size_t size
)
509 int res
= llistxattr(path
, list
, size
);
515 static int xmp_removexattr(const char *path
, const char *name
)
517 int res
= lremovexattr(path
, name
);
522 #endif /* HAVE_SETXATTR */
524 #ifdef HAVE_LIBULOCKMGR
525 static int xmp_lock(const char *path
, struct fuse_file_info
*fi
, int cmd
,
530 return ulockmgr_op(fi
->fh
, cmd
, lock
, &fi
->lock_owner
,
531 sizeof(fi
->lock_owner
));
535 static int xmp_flock(const char *path
, struct fuse_file_info
*fi
, int op
)
540 res
= flock(fi
->fh
, op
);
547 static struct fuse_operations xmp_oper
= {
548 .getattr
= xmp_getattr
,
549 .fgetattr
= xmp_fgetattr
,
550 .access
= xmp_access
,
551 .readlink
= xmp_readlink
,
552 .opendir
= xmp_opendir
,
553 .readdir
= xmp_readdir
,
554 .releasedir
= xmp_releasedir
,
557 .symlink
= xmp_symlink
,
558 .unlink
= xmp_unlink
,
560 .rename
= xmp_rename
,
564 .truncate
= xmp_truncate
,
565 .ftruncate
= xmp_ftruncate
,
566 #ifdef HAVE_UTIMENSAT
567 .utimens
= xmp_utimens
,
569 .create
= xmp_create
,
572 .read_buf
= xmp_read_buf
,
574 .write_buf
= xmp_write_buf
,
575 .statfs
= xmp_statfs
,
577 .release
= xmp_release
,
579 #ifdef HAVE_POSIX_FALLOCATE
580 .fallocate
= xmp_fallocate
,
583 .setxattr
= xmp_setxattr
,
584 .getxattr
= xmp_getxattr
,
585 .listxattr
= xmp_listxattr
,
586 .removexattr
= xmp_removexattr
,
588 #ifdef HAVE_LIBULOCKMGR
594 int main(int argc
, char *argv
[])
597 return fuse_main(argc
, argv
, &xmp_oper
, NULL
);