Fix missing config.h in buffer.c
[fuse.git] / example / fusexmp_fh.c
blob1ba9dbc85e1cf796a0198e03e866c659590c78d4
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.
9 gcc -Wall fusexmp_fh.c `pkg-config fuse --cflags --libs` -lulockmgr -o fusexmp_fh
12 #define FUSE_USE_VERSION 26
14 #ifdef HAVE_CONFIG_H
15 #include <config.h>
16 #endif
18 #define _GNU_SOURCE
20 #include <fuse.h>
21 #include <ulockmgr.h>
22 #include <stdio.h>
23 #include <stdlib.h>
24 #include <string.h>
25 #include <unistd.h>
26 #include <fcntl.h>
27 #include <sys/stat.h>
28 #include <dirent.h>
29 #include <errno.h>
30 #include <sys/time.h>
31 #ifdef HAVE_SETXATTR
32 #include <sys/xattr.h>
33 #endif
34 #include <sys/file.h> /* flock(2) */
36 static int xmp_getattr(const char *path, struct stat *stbuf)
38 int res;
40 res = lstat(path, stbuf);
41 if (res == -1)
42 return -errno;
44 return 0;
47 static int xmp_fgetattr(const char *path, struct stat *stbuf,
48 struct fuse_file_info *fi)
50 int res;
52 (void) path;
54 res = fstat(fi->fh, stbuf);
55 if (res == -1)
56 return -errno;
58 return 0;
61 static int xmp_access(const char *path, int mask)
63 int res;
65 res = access(path, mask);
66 if (res == -1)
67 return -errno;
69 return 0;
72 static int xmp_readlink(const char *path, char *buf, size_t size)
74 int res;
76 res = readlink(path, buf, size - 1);
77 if (res == -1)
78 return -errno;
80 buf[res] = '\0';
81 return 0;
84 struct xmp_dirp {
85 DIR *dp;
86 struct dirent *entry;
87 off_t offset;
90 static int xmp_opendir(const char *path, struct fuse_file_info *fi)
92 int res;
93 struct xmp_dirp *d = malloc(sizeof(struct xmp_dirp));
94 if (d == NULL)
95 return -ENOMEM;
97 d->dp = opendir(path);
98 if (d->dp == NULL) {
99 res = -errno;
100 free(d);
101 return res;
103 d->offset = 0;
104 d->entry = NULL;
106 fi->fh = (unsigned long) d;
107 return 0;
110 static inline struct xmp_dirp *get_dirp(struct fuse_file_info *fi)
112 return (struct xmp_dirp *) (uintptr_t) fi->fh;
115 static int xmp_readdir(const char *path, void *buf, fuse_fill_dir_t filler,
116 off_t offset, struct fuse_file_info *fi)
118 struct xmp_dirp *d = get_dirp(fi);
120 (void) path;
121 if (offset != d->offset) {
122 seekdir(d->dp, offset);
123 d->entry = NULL;
124 d->offset = offset;
126 while (1) {
127 struct stat st;
128 off_t nextoff;
130 if (!d->entry) {
131 d->entry = readdir(d->dp);
132 if (!d->entry)
133 break;
136 memset(&st, 0, sizeof(st));
137 st.st_ino = d->entry->d_ino;
138 st.st_mode = d->entry->d_type << 12;
139 nextoff = telldir(d->dp);
140 if (filler(buf, d->entry->d_name, &st, nextoff))
141 break;
143 d->entry = NULL;
144 d->offset = nextoff;
147 return 0;
150 static int xmp_releasedir(const char *path, struct fuse_file_info *fi)
152 struct xmp_dirp *d = get_dirp(fi);
153 (void) path;
154 closedir(d->dp);
155 free(d);
156 return 0;
159 static int xmp_mknod(const char *path, mode_t mode, dev_t rdev)
161 int res;
163 if (S_ISFIFO(mode))
164 res = mkfifo(path, mode);
165 else
166 res = mknod(path, mode, rdev);
167 if (res == -1)
168 return -errno;
170 return 0;
173 static int xmp_mkdir(const char *path, mode_t mode)
175 int res;
177 res = mkdir(path, mode);
178 if (res == -1)
179 return -errno;
181 return 0;
184 static int xmp_unlink(const char *path)
186 int res;
188 res = unlink(path);
189 if (res == -1)
190 return -errno;
192 return 0;
195 static int xmp_rmdir(const char *path)
197 int res;
199 res = rmdir(path);
200 if (res == -1)
201 return -errno;
203 return 0;
206 static int xmp_symlink(const char *from, const char *to)
208 int res;
210 res = symlink(from, to);
211 if (res == -1)
212 return -errno;
214 return 0;
217 static int xmp_rename(const char *from, const char *to)
219 int res;
221 res = rename(from, to);
222 if (res == -1)
223 return -errno;
225 return 0;
228 static int xmp_link(const char *from, const char *to)
230 int res;
232 res = link(from, to);
233 if (res == -1)
234 return -errno;
236 return 0;
239 static int xmp_chmod(const char *path, mode_t mode)
241 int res;
243 res = chmod(path, mode);
244 if (res == -1)
245 return -errno;
247 return 0;
250 static int xmp_chown(const char *path, uid_t uid, gid_t gid)
252 int res;
254 res = lchown(path, uid, gid);
255 if (res == -1)
256 return -errno;
258 return 0;
261 static int xmp_truncate(const char *path, off_t size)
263 int res;
265 res = truncate(path, size);
266 if (res == -1)
267 return -errno;
269 return 0;
272 static int xmp_ftruncate(const char *path, off_t size,
273 struct fuse_file_info *fi)
275 int res;
277 (void) path;
279 res = ftruncate(fi->fh, size);
280 if (res == -1)
281 return -errno;
283 return 0;
286 #ifdef HAVE_UTIMENSAT
287 static int xmp_utimens(const char *path, const struct timespec ts[2])
289 int res;
291 /* don't use utime/utimes since they follow symlinks */
292 res = utimensat(0, path, ts, AT_SYMLINK_NOFOLLOW);
293 if (res == -1)
294 return -errno;
296 return 0;
298 #endif
300 static int xmp_create(const char *path, mode_t mode, struct fuse_file_info *fi)
302 int fd;
304 fd = open(path, fi->flags, mode);
305 if (fd == -1)
306 return -errno;
308 fi->fh = fd;
309 return 0;
312 static int xmp_open(const char *path, struct fuse_file_info *fi)
314 int fd;
316 fd = open(path, fi->flags);
317 if (fd == -1)
318 return -errno;
320 fi->fh = fd;
321 return 0;
324 static int xmp_read(const char *path, char *buf, size_t size, off_t offset,
325 struct fuse_file_info *fi)
327 int res;
329 (void) path;
330 res = pread(fi->fh, buf, size, offset);
331 if (res == -1)
332 res = -errno;
334 return res;
337 static int xmp_read_buf(const char *path, struct fuse_bufvec **bufp,
338 size_t size, off_t offset, struct fuse_file_info *fi)
340 struct fuse_bufvec *src;
342 (void) path;
344 src = malloc(sizeof(struct fuse_bufvec));
345 if (src == NULL)
346 return -ENOMEM;
348 *src = FUSE_BUFVEC_INIT(size);
350 src->buf[0].flags = FUSE_BUF_IS_FD | FUSE_BUF_FD_SEEK;
351 src->buf[0].fd = fi->fh;
352 src->buf[0].pos = offset;
354 *bufp = src;
356 return 0;
359 static int xmp_write(const char *path, const char *buf, size_t size,
360 off_t offset, struct fuse_file_info *fi)
362 int res;
364 (void) path;
365 res = pwrite(fi->fh, buf, size, offset);
366 if (res == -1)
367 res = -errno;
369 return res;
372 static int xmp_write_buf(const char *path, struct fuse_bufvec *buf,
373 off_t offset, struct fuse_file_info *fi)
375 struct fuse_bufvec dst = FUSE_BUFVEC_INIT(fuse_buf_size(buf));
377 (void) path;
379 dst.buf[0].flags = FUSE_BUF_IS_FD | FUSE_BUF_FD_SEEK;
380 dst.buf[0].fd = fi->fh;
381 dst.buf[0].pos = offset;
383 return fuse_buf_copy(&dst, buf, FUSE_BUF_SPLICE_NONBLOCK);
386 static int xmp_statfs(const char *path, struct statvfs *stbuf)
388 int res;
390 res = statvfs(path, stbuf);
391 if (res == -1)
392 return -errno;
394 return 0;
397 static int xmp_flush(const char *path, struct fuse_file_info *fi)
399 int res;
401 (void) path;
402 /* This is called from every close on an open file, so call the
403 close on the underlying filesystem. But since flush may be
404 called multiple times for an open file, this must not really
405 close the file. This is important if used on a network
406 filesystem like NFS which flush the data/metadata on close() */
407 res = close(dup(fi->fh));
408 if (res == -1)
409 return -errno;
411 return 0;
414 static int xmp_release(const char *path, struct fuse_file_info *fi)
416 (void) path;
417 close(fi->fh);
419 return 0;
422 static int xmp_fsync(const char *path, int isdatasync,
423 struct fuse_file_info *fi)
425 int res;
426 (void) path;
428 #ifndef HAVE_FDATASYNC
429 (void) isdatasync;
430 #else
431 if (isdatasync)
432 res = fdatasync(fi->fh);
433 else
434 #endif
435 res = fsync(fi->fh);
436 if (res == -1)
437 return -errno;
439 return 0;
442 #ifdef HAVE_POSIX_FALLOCATE
443 static int xmp_fallocate(const char *path, int mode,
444 off_t offset, off_t length, struct fuse_file_info *fi)
446 (void) path;
448 if (mode)
449 return -EOPNOTSUPP;
451 return -posix_fallocate(fi->fh, offset, length);
453 #endif
455 #ifdef HAVE_SETXATTR
456 /* xattr operations are optional and can safely be left unimplemented */
457 static int xmp_setxattr(const char *path, const char *name, const char *value,
458 size_t size, int flags)
460 int res = lsetxattr(path, name, value, size, flags);
461 if (res == -1)
462 return -errno;
463 return 0;
466 static int xmp_getxattr(const char *path, const char *name, char *value,
467 size_t size)
469 int res = lgetxattr(path, name, value, size);
470 if (res == -1)
471 return -errno;
472 return res;
475 static int xmp_listxattr(const char *path, char *list, size_t size)
477 int res = llistxattr(path, list, size);
478 if (res == -1)
479 return -errno;
480 return res;
483 static int xmp_removexattr(const char *path, const char *name)
485 int res = lremovexattr(path, name);
486 if (res == -1)
487 return -errno;
488 return 0;
490 #endif /* HAVE_SETXATTR */
492 static int xmp_lock(const char *path, struct fuse_file_info *fi, int cmd,
493 struct flock *lock)
495 (void) path;
497 return ulockmgr_op(fi->fh, cmd, lock, &fi->lock_owner,
498 sizeof(fi->lock_owner));
501 static int xmp_flock(const char *path, struct fuse_file_info *fi, int op)
503 int res;
504 (void) path;
506 res = flock(fi->fh, op);
507 if (res == -1)
508 return -errno;
510 return 0;
513 static struct fuse_operations xmp_oper = {
514 .getattr = xmp_getattr,
515 .fgetattr = xmp_fgetattr,
516 .access = xmp_access,
517 .readlink = xmp_readlink,
518 .opendir = xmp_opendir,
519 .readdir = xmp_readdir,
520 .releasedir = xmp_releasedir,
521 .mknod = xmp_mknod,
522 .mkdir = xmp_mkdir,
523 .symlink = xmp_symlink,
524 .unlink = xmp_unlink,
525 .rmdir = xmp_rmdir,
526 .rename = xmp_rename,
527 .link = xmp_link,
528 .chmod = xmp_chmod,
529 .chown = xmp_chown,
530 .truncate = xmp_truncate,
531 .ftruncate = xmp_ftruncate,
532 #ifdef HAVE_UTIMENSAT
533 .utimens = xmp_utimens,
534 #endif
535 .create = xmp_create,
536 .open = xmp_open,
537 .read = xmp_read,
538 .read_buf = xmp_read_buf,
539 .write = xmp_write,
540 .write_buf = xmp_write_buf,
541 .statfs = xmp_statfs,
542 .flush = xmp_flush,
543 .release = xmp_release,
544 .fsync = xmp_fsync,
545 #ifdef HAVE_POSIX_FALLOCATE
546 .fallocate = xmp_fallocate,
547 #endif
548 #ifdef HAVE_SETXATTR
549 .setxattr = xmp_setxattr,
550 .getxattr = xmp_getxattr,
551 .listxattr = xmp_listxattr,
552 .removexattr = xmp_removexattr,
553 #endif
554 .lock = xmp_lock,
555 .flock = xmp_flock,
557 .flag_nullpath_ok = 1,
558 #if HAVE_UTIMENSAT
559 .flag_utime_omit_ok = 1,
560 #endif
563 int main(int argc, char *argv[])
565 umask(0);
566 return fuse_main(argc, argv, &xmp_oper, NULL);