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 fuse --cflags --libs` -lulockmgr -o fusexmp_fh
19 * \section section_source the complete source
20 * \include fusexmp_fh.c
23 #define FUSE_USE_VERSION 30
43 #include <sys/xattr.h>
45 #include <sys/file.h> /* flock(2) */
47 static int xmp_getattr(const char *path
, struct stat
*stbuf
)
51 res
= lstat(path
, stbuf
);
58 static int xmp_fgetattr(const char *path
, struct stat
*stbuf
,
59 struct fuse_file_info
*fi
)
65 res
= fstat(fi
->fh
, stbuf
);
72 static int xmp_access(const char *path
, int mask
)
76 res
= access(path
, mask
);
83 static int xmp_readlink(const char *path
, char *buf
, size_t size
)
87 res
= readlink(path
, buf
, size
- 1);
101 static int xmp_opendir(const char *path
, struct fuse_file_info
*fi
)
104 struct xmp_dirp
*d
= malloc(sizeof(struct xmp_dirp
));
108 d
->dp
= opendir(path
);
117 fi
->fh
= (unsigned long) d
;
121 static inline struct xmp_dirp
*get_dirp(struct fuse_file_info
*fi
)
123 return (struct xmp_dirp
*) (uintptr_t) fi
->fh
;
126 static int xmp_readdir(const char *path
, void *buf
, fuse_fill_dir_t filler
,
127 off_t offset
, struct fuse_file_info
*fi
)
129 struct xmp_dirp
*d
= get_dirp(fi
);
132 if (offset
!= d
->offset
) {
133 seekdir(d
->dp
, offset
);
142 d
->entry
= readdir(d
->dp
);
147 memset(&st
, 0, sizeof(st
));
148 st
.st_ino
= d
->entry
->d_ino
;
149 st
.st_mode
= d
->entry
->d_type
<< 12;
150 nextoff
= telldir(d
->dp
);
151 if (filler(buf
, d
->entry
->d_name
, &st
, nextoff
))
161 static int xmp_releasedir(const char *path
, struct fuse_file_info
*fi
)
163 struct xmp_dirp
*d
= get_dirp(fi
);
170 static int xmp_mknod(const char *path
, mode_t mode
, dev_t rdev
)
175 res
= mkfifo(path
, mode
);
177 res
= mknod(path
, mode
, rdev
);
184 static int xmp_mkdir(const char *path
, mode_t mode
)
188 res
= mkdir(path
, mode
);
195 static int xmp_unlink(const char *path
)
206 static int xmp_rmdir(const char *path
)
217 static int xmp_symlink(const char *from
, const char *to
)
221 res
= symlink(from
, to
);
228 static int xmp_rename(const char *from
, const char *to
)
232 res
= rename(from
, to
);
239 static int xmp_link(const char *from
, const char *to
)
243 res
= link(from
, to
);
250 static int xmp_chmod(const char *path
, mode_t mode
)
254 res
= chmod(path
, mode
);
261 static int xmp_chown(const char *path
, uid_t uid
, gid_t gid
)
265 res
= lchown(path
, uid
, gid
);
272 static int xmp_truncate(const char *path
, off_t size
)
276 res
= truncate(path
, size
);
283 static int xmp_ftruncate(const char *path
, off_t size
,
284 struct fuse_file_info
*fi
)
290 res
= ftruncate(fi
->fh
, size
);
297 #ifdef HAVE_UTIMENSAT
298 static int xmp_utimens(const char *path
, const struct timespec ts
[2])
302 /* don't use utime/utimes since they follow symlinks */
303 res
= utimensat(0, path
, ts
, AT_SYMLINK_NOFOLLOW
);
311 static int xmp_create(const char *path
, mode_t mode
, struct fuse_file_info
*fi
)
315 fd
= open(path
, fi
->flags
, mode
);
323 static int xmp_open(const char *path
, struct fuse_file_info
*fi
)
327 fd
= open(path
, fi
->flags
);
335 static int xmp_read(const char *path
, char *buf
, size_t size
, off_t offset
,
336 struct fuse_file_info
*fi
)
341 res
= pread(fi
->fh
, buf
, size
, offset
);
348 static int xmp_read_buf(const char *path
, struct fuse_bufvec
**bufp
,
349 size_t size
, off_t offset
, struct fuse_file_info
*fi
)
351 struct fuse_bufvec
*src
;
355 src
= malloc(sizeof(struct fuse_bufvec
));
359 *src
= FUSE_BUFVEC_INIT(size
);
361 src
->buf
[0].flags
= FUSE_BUF_IS_FD
| FUSE_BUF_FD_SEEK
;
362 src
->buf
[0].fd
= fi
->fh
;
363 src
->buf
[0].pos
= offset
;
370 static int xmp_write(const char *path
, const char *buf
, size_t size
,
371 off_t offset
, struct fuse_file_info
*fi
)
376 res
= pwrite(fi
->fh
, buf
, size
, offset
);
383 static int xmp_write_buf(const char *path
, struct fuse_bufvec
*buf
,
384 off_t offset
, struct fuse_file_info
*fi
)
386 struct fuse_bufvec dst
= FUSE_BUFVEC_INIT(fuse_buf_size(buf
));
390 dst
.buf
[0].flags
= FUSE_BUF_IS_FD
| FUSE_BUF_FD_SEEK
;
391 dst
.buf
[0].fd
= fi
->fh
;
392 dst
.buf
[0].pos
= offset
;
394 return fuse_buf_copy(&dst
, buf
, FUSE_BUF_SPLICE_NONBLOCK
);
397 static int xmp_statfs(const char *path
, struct statvfs
*stbuf
)
401 res
= statvfs(path
, stbuf
);
408 static int xmp_flush(const char *path
, struct fuse_file_info
*fi
)
413 /* This is called from every close on an open file, so call the
414 close on the underlying filesystem. But since flush may be
415 called multiple times for an open file, this must not really
416 close the file. This is important if used on a network
417 filesystem like NFS which flush the data/metadata on close() */
418 res
= close(dup(fi
->fh
));
425 static int xmp_release(const char *path
, struct fuse_file_info
*fi
)
433 static int xmp_fsync(const char *path
, int isdatasync
,
434 struct fuse_file_info
*fi
)
439 #ifndef HAVE_FDATASYNC
443 res
= fdatasync(fi
->fh
);
453 #ifdef HAVE_POSIX_FALLOCATE
454 static int xmp_fallocate(const char *path
, int mode
,
455 off_t offset
, off_t length
, struct fuse_file_info
*fi
)
462 return -posix_fallocate(fi
->fh
, offset
, length
);
467 /* xattr operations are optional and can safely be left unimplemented */
468 static int xmp_setxattr(const char *path
, const char *name
, const char *value
,
469 size_t size
, int flags
)
471 int res
= lsetxattr(path
, name
, value
, size
, flags
);
477 static int xmp_getxattr(const char *path
, const char *name
, char *value
,
480 int res
= lgetxattr(path
, name
, value
, size
);
486 static int xmp_listxattr(const char *path
, char *list
, size_t size
)
488 int res
= llistxattr(path
, list
, size
);
494 static int xmp_removexattr(const char *path
, const char *name
)
496 int res
= lremovexattr(path
, name
);
501 #endif /* HAVE_SETXATTR */
503 static int xmp_lock(const char *path
, struct fuse_file_info
*fi
, int cmd
,
508 return ulockmgr_op(fi
->fh
, cmd
, lock
, &fi
->lock_owner
,
509 sizeof(fi
->lock_owner
));
512 static int xmp_flock(const char *path
, struct fuse_file_info
*fi
, int op
)
517 res
= flock(fi
->fh
, op
);
524 static struct fuse_operations xmp_oper
= {
525 .getattr
= xmp_getattr
,
526 .fgetattr
= xmp_fgetattr
,
527 .access
= xmp_access
,
528 .readlink
= xmp_readlink
,
529 .opendir
= xmp_opendir
,
530 .readdir
= xmp_readdir
,
531 .releasedir
= xmp_releasedir
,
534 .symlink
= xmp_symlink
,
535 .unlink
= xmp_unlink
,
537 .rename
= xmp_rename
,
541 .truncate
= xmp_truncate
,
542 .ftruncate
= xmp_ftruncate
,
543 #ifdef HAVE_UTIMENSAT
544 .utimens
= xmp_utimens
,
546 .create
= xmp_create
,
549 .read_buf
= xmp_read_buf
,
551 .write_buf
= xmp_write_buf
,
552 .statfs
= xmp_statfs
,
554 .release
= xmp_release
,
556 #ifdef HAVE_POSIX_FALLOCATE
557 .fallocate
= xmp_fallocate
,
560 .setxattr
= xmp_setxattr
,
561 .getxattr
= xmp_getxattr
,
562 .listxattr
= xmp_listxattr
,
563 .removexattr
= xmp_removexattr
,
569 int main(int argc
, char *argv
[])
572 return fuse_main(argc
, argv
, &xmp_oper
, NULL
);