libfuse: add FUSE_CAP_NO_OPEN_SUPPORT flag to ->init()
[fuse.git] / example / fusexmp_fh.c
blob84fce3f4b84bacf99959634c5d84a0065e30109e
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>
6 This program can be distributed under the terms of the GNU GPL.
7 See the file COPYING.
8 */
10 /** @file
11 * @tableofcontents
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
25 #ifdef HAVE_CONFIG_H
26 #include <config.h>
27 #endif
29 #define _GNU_SOURCE
31 #include <fuse.h>
33 #ifdef HAVE_LIBULOCKMGR
34 #include <ulockmgr.h>
35 #endif
37 #include <stdio.h>
38 #include <stdlib.h>
39 #include <string.h>
40 #include <unistd.h>
41 #include <fcntl.h>
42 #include <sys/stat.h>
43 #include <dirent.h>
44 #include <errno.h>
45 #include <sys/time.h>
46 #ifdef HAVE_SETXATTR
47 #include <sys/xattr.h>
48 #endif
49 #include <sys/file.h> /* flock(2) */
51 static int xmp_getattr(const char *path, struct stat *stbuf)
53 int res;
55 res = lstat(path, stbuf);
56 if (res == -1)
57 return -errno;
59 return 0;
62 static int xmp_fgetattr(const char *path, struct stat *stbuf,
63 struct fuse_file_info *fi)
65 int res;
67 (void) path;
69 res = fstat(fi->fh, stbuf);
70 if (res == -1)
71 return -errno;
73 return 0;
76 static int xmp_access(const char *path, int mask)
78 int res;
80 res = access(path, mask);
81 if (res == -1)
82 return -errno;
84 return 0;
87 static int xmp_readlink(const char *path, char *buf, size_t size)
89 int res;
91 res = readlink(path, buf, size - 1);
92 if (res == -1)
93 return -errno;
95 buf[res] = '\0';
96 return 0;
99 struct xmp_dirp {
100 DIR *dp;
101 struct dirent *entry;
102 off_t offset;
105 static int xmp_opendir(const char *path, struct fuse_file_info *fi)
107 int res;
108 struct xmp_dirp *d = malloc(sizeof(struct xmp_dirp));
109 if (d == NULL)
110 return -ENOMEM;
112 d->dp = opendir(path);
113 if (d->dp == NULL) {
114 res = -errno;
115 free(d);
116 return res;
118 d->offset = 0;
119 d->entry = NULL;
121 fi->fh = (unsigned long) d;
122 return 0;
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);
136 (void) path;
137 if (offset != d->offset) {
138 seekdir(d->dp, offset);
139 d->entry = NULL;
140 d->offset = offset;
142 while (1) {
143 struct stat st;
144 off_t nextoff;
145 enum fuse_fill_dir_flags fill_flags = 0;
147 if (!d->entry) {
148 d->entry = readdir(d->dp);
149 if (!d->entry)
150 break;
152 #ifdef HAVE_FSTATAT
153 if (flags & FUSE_READDIR_PLUS) {
154 int res;
156 res = fstatat(dirfd(d->dp), d->entry->d_name, &st,
157 AT_SYMLINK_NOFOLLOW);
158 if (res != -1)
159 fill_flags |= FUSE_FILL_DIR_PLUS;
161 #endif
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))
169 break;
171 d->entry = NULL;
172 d->offset = nextoff;
175 return 0;
178 static int xmp_releasedir(const char *path, struct fuse_file_info *fi)
180 struct xmp_dirp *d = get_dirp(fi);
181 (void) path;
182 closedir(d->dp);
183 free(d);
184 return 0;
187 static int xmp_mknod(const char *path, mode_t mode, dev_t rdev)
189 int res;
191 if (S_ISFIFO(mode))
192 res = mkfifo(path, mode);
193 else
194 res = mknod(path, mode, rdev);
195 if (res == -1)
196 return -errno;
198 return 0;
201 static int xmp_mkdir(const char *path, mode_t mode)
203 int res;
205 res = mkdir(path, mode);
206 if (res == -1)
207 return -errno;
209 return 0;
212 static int xmp_unlink(const char *path)
214 int res;
216 res = unlink(path);
217 if (res == -1)
218 return -errno;
220 return 0;
223 static int xmp_rmdir(const char *path)
225 int res;
227 res = rmdir(path);
228 if (res == -1)
229 return -errno;
231 return 0;
234 static int xmp_symlink(const char *from, const char *to)
236 int res;
238 res = symlink(from, to);
239 if (res == -1)
240 return -errno;
242 return 0;
245 static int xmp_rename(const char *from, const char *to, unsigned int flags)
247 int res;
249 /* When we have renameat2() in libc, then we can implement flags */
250 if (flags)
251 return -EINVAL;
253 res = rename(from, to);
254 if (res == -1)
255 return -errno;
257 return 0;
260 static int xmp_link(const char *from, const char *to)
262 int res;
264 res = link(from, to);
265 if (res == -1)
266 return -errno;
268 return 0;
271 static int xmp_chmod(const char *path, mode_t mode)
273 int res;
275 res = chmod(path, mode);
276 if (res == -1)
277 return -errno;
279 return 0;
282 static int xmp_chown(const char *path, uid_t uid, gid_t gid)
284 int res;
286 res = lchown(path, uid, gid);
287 if (res == -1)
288 return -errno;
290 return 0;
293 static int xmp_truncate(const char *path, off_t size)
295 int res;
297 res = truncate(path, size);
298 if (res == -1)
299 return -errno;
301 return 0;
304 static int xmp_ftruncate(const char *path, off_t size,
305 struct fuse_file_info *fi)
307 int res;
309 (void) path;
311 res = ftruncate(fi->fh, size);
312 if (res == -1)
313 return -errno;
315 return 0;
318 #ifdef HAVE_UTIMENSAT
319 static int xmp_utimens(const char *path, const struct timespec ts[2])
321 int res;
323 /* don't use utime/utimes since they follow symlinks */
324 res = utimensat(0, path, ts, AT_SYMLINK_NOFOLLOW);
325 if (res == -1)
326 return -errno;
328 return 0;
330 #endif
332 static int xmp_create(const char *path, mode_t mode, struct fuse_file_info *fi)
334 int fd;
336 fd = open(path, fi->flags, mode);
337 if (fd == -1)
338 return -errno;
340 fi->fh = fd;
341 return 0;
344 static int xmp_open(const char *path, struct fuse_file_info *fi)
346 int fd;
348 fd = open(path, fi->flags);
349 if (fd == -1)
350 return -errno;
352 fi->fh = fd;
353 return 0;
356 static int xmp_read(const char *path, char *buf, size_t size, off_t offset,
357 struct fuse_file_info *fi)
359 int res;
361 (void) path;
362 res = pread(fi->fh, buf, size, offset);
363 if (res == -1)
364 res = -errno;
366 return res;
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;
374 (void) path;
376 src = malloc(sizeof(struct fuse_bufvec));
377 if (src == NULL)
378 return -ENOMEM;
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;
386 *bufp = src;
388 return 0;
391 static int xmp_write(const char *path, const char *buf, size_t size,
392 off_t offset, struct fuse_file_info *fi)
394 int res;
396 (void) path;
397 res = pwrite(fi->fh, buf, size, offset);
398 if (res == -1)
399 res = -errno;
401 return res;
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));
409 (void) path;
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)
420 int res;
422 res = statvfs(path, stbuf);
423 if (res == -1)
424 return -errno;
426 return 0;
429 static int xmp_flush(const char *path, struct fuse_file_info *fi)
431 int res;
433 (void) path;
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));
440 if (res == -1)
441 return -errno;
443 return 0;
446 static int xmp_release(const char *path, struct fuse_file_info *fi)
448 (void) path;
449 close(fi->fh);
451 return 0;
454 static int xmp_fsync(const char *path, int isdatasync,
455 struct fuse_file_info *fi)
457 int res;
458 (void) path;
460 #ifndef HAVE_FDATASYNC
461 (void) isdatasync;
462 #else
463 if (isdatasync)
464 res = fdatasync(fi->fh);
465 else
466 #endif
467 res = fsync(fi->fh);
468 if (res == -1)
469 return -errno;
471 return 0;
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)
478 (void) path;
480 if (mode)
481 return -EOPNOTSUPP;
483 return -posix_fallocate(fi->fh, offset, length);
485 #endif
487 #ifdef HAVE_SETXATTR
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);
493 if (res == -1)
494 return -errno;
495 return 0;
498 static int xmp_getxattr(const char *path, const char *name, char *value,
499 size_t size)
501 int res = lgetxattr(path, name, value, size);
502 if (res == -1)
503 return -errno;
504 return res;
507 static int xmp_listxattr(const char *path, char *list, size_t size)
509 int res = llistxattr(path, list, size);
510 if (res == -1)
511 return -errno;
512 return res;
515 static int xmp_removexattr(const char *path, const char *name)
517 int res = lremovexattr(path, name);
518 if (res == -1)
519 return -errno;
520 return 0;
522 #endif /* HAVE_SETXATTR */
524 #ifdef HAVE_LIBULOCKMGR
525 static int xmp_lock(const char *path, struct fuse_file_info *fi, int cmd,
526 struct flock *lock)
528 (void) path;
530 return ulockmgr_op(fi->fh, cmd, lock, &fi->lock_owner,
531 sizeof(fi->lock_owner));
533 #endif
535 static int xmp_flock(const char *path, struct fuse_file_info *fi, int op)
537 int res;
538 (void) path;
540 res = flock(fi->fh, op);
541 if (res == -1)
542 return -errno;
544 return 0;
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,
555 .mknod = xmp_mknod,
556 .mkdir = xmp_mkdir,
557 .symlink = xmp_symlink,
558 .unlink = xmp_unlink,
559 .rmdir = xmp_rmdir,
560 .rename = xmp_rename,
561 .link = xmp_link,
562 .chmod = xmp_chmod,
563 .chown = xmp_chown,
564 .truncate = xmp_truncate,
565 .ftruncate = xmp_ftruncate,
566 #ifdef HAVE_UTIMENSAT
567 .utimens = xmp_utimens,
568 #endif
569 .create = xmp_create,
570 .open = xmp_open,
571 .read = xmp_read,
572 .read_buf = xmp_read_buf,
573 .write = xmp_write,
574 .write_buf = xmp_write_buf,
575 .statfs = xmp_statfs,
576 .flush = xmp_flush,
577 .release = xmp_release,
578 .fsync = xmp_fsync,
579 #ifdef HAVE_POSIX_FALLOCATE
580 .fallocate = xmp_fallocate,
581 #endif
582 #ifdef HAVE_SETXATTR
583 .setxattr = xmp_setxattr,
584 .getxattr = xmp_getxattr,
585 .listxattr = xmp_listxattr,
586 .removexattr = xmp_removexattr,
587 #endif
588 #ifdef HAVE_LIBULOCKMGR
589 .lock = xmp_lock,
590 #endif
591 .flock = xmp_flock,
594 int main(int argc, char *argv[])
596 umask(0);
597 return fuse_main(argc, argv, &xmp_oper, NULL);