Add ->flock() operation to low and high level interfaces
[fuse.git] / example / fusexmp_fh.c
blob046185c92a34ec4f67d04edf8ced93bffc924dc4
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 `pkg-config fuse --cflags --libs` -lulockmgr fusexmp_fh.c -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 static int xmp_utimens(const char *path, const struct timespec ts[2])
288 int res;
290 res = utimensat(0, path, ts, AT_SYMLINK_NOFOLLOW);
291 if (res == -1)
292 return -errno;
294 return 0;
297 static int xmp_create(const char *path, mode_t mode, struct fuse_file_info *fi)
299 int fd;
301 fd = open(path, fi->flags, mode);
302 if (fd == -1)
303 return -errno;
305 fi->fh = fd;
306 return 0;
309 static int xmp_open(const char *path, struct fuse_file_info *fi)
311 int fd;
313 fd = open(path, fi->flags);
314 if (fd == -1)
315 return -errno;
317 fi->fh = fd;
318 return 0;
321 static int xmp_read(const char *path, char *buf, size_t size, off_t offset,
322 struct fuse_file_info *fi)
324 int res;
326 (void) path;
327 res = pread(fi->fh, buf, size, offset);
328 if (res == -1)
329 res = -errno;
331 return res;
334 static int xmp_read_buf(const char *path, struct fuse_bufvec **bufp,
335 size_t size, off_t offset, struct fuse_file_info *fi)
337 struct fuse_bufvec *src;
339 (void) path;
341 src = malloc(sizeof(struct fuse_bufvec));
342 if (src == NULL)
343 return -ENOMEM;
345 *src = FUSE_BUFVEC_INIT(size);
347 src->buf[0].flags = FUSE_BUF_IS_FD | FUSE_BUF_FD_SEEK;
348 src->buf[0].fd = fi->fh;
349 src->buf[0].pos = offset;
351 *bufp = src;
353 return 0;
356 static int xmp_write(const char *path, const char *buf, size_t size,
357 off_t offset, struct fuse_file_info *fi)
359 int res;
361 (void) path;
362 res = pwrite(fi->fh, buf, size, offset);
363 if (res == -1)
364 res = -errno;
366 return res;
369 static int xmp_write_buf(const char *path, struct fuse_bufvec *buf,
370 off_t offset, struct fuse_file_info *fi)
372 struct fuse_bufvec dst = FUSE_BUFVEC_INIT(fuse_buf_size(buf));
374 (void) path;
376 dst.buf[0].flags = FUSE_BUF_IS_FD | FUSE_BUF_FD_SEEK;
377 dst.buf[0].fd = fi->fh;
378 dst.buf[0].pos = offset;
380 return fuse_buf_copy(&dst, buf, FUSE_BUF_SPLICE_NONBLOCK);
383 static int xmp_statfs(const char *path, struct statvfs *stbuf)
385 int res;
387 res = statvfs(path, stbuf);
388 if (res == -1)
389 return -errno;
391 return 0;
394 static int xmp_flush(const char *path, struct fuse_file_info *fi)
396 int res;
398 (void) path;
399 /* This is called from every close on an open file, so call the
400 close on the underlying filesystem. But since flush may be
401 called multiple times for an open file, this must not really
402 close the file. This is important if used on a network
403 filesystem like NFS which flush the data/metadata on close() */
404 res = close(dup(fi->fh));
405 if (res == -1)
406 return -errno;
408 return 0;
411 static int xmp_release(const char *path, struct fuse_file_info *fi)
413 (void) path;
414 close(fi->fh);
416 return 0;
419 static int xmp_fsync(const char *path, int isdatasync,
420 struct fuse_file_info *fi)
422 int res;
423 (void) path;
425 #ifndef HAVE_FDATASYNC
426 (void) isdatasync;
427 #else
428 if (isdatasync)
429 res = fdatasync(fi->fh);
430 else
431 #endif
432 res = fsync(fi->fh);
433 if (res == -1)
434 return -errno;
436 return 0;
439 #ifdef HAVE_SETXATTR
440 /* xattr operations are optional and can safely be left unimplemented */
441 static int xmp_setxattr(const char *path, const char *name, const char *value,
442 size_t size, int flags)
444 int res = lsetxattr(path, name, value, size, flags);
445 if (res == -1)
446 return -errno;
447 return 0;
450 static int xmp_getxattr(const char *path, const char *name, char *value,
451 size_t size)
453 int res = lgetxattr(path, name, value, size);
454 if (res == -1)
455 return -errno;
456 return res;
459 static int xmp_listxattr(const char *path, char *list, size_t size)
461 int res = llistxattr(path, list, size);
462 if (res == -1)
463 return -errno;
464 return res;
467 static int xmp_removexattr(const char *path, const char *name)
469 int res = lremovexattr(path, name);
470 if (res == -1)
471 return -errno;
472 return 0;
474 #endif /* HAVE_SETXATTR */
476 static int xmp_lock(const char *path, struct fuse_file_info *fi, int cmd,
477 struct flock *lock)
479 (void) path;
481 return ulockmgr_op(fi->fh, cmd, lock, &fi->lock_owner,
482 sizeof(fi->lock_owner));
485 static int xmp_flock(const char *path, struct fuse_file_info *fi, int op)
487 int res;
488 (void) path;
490 res = flock(fi->fh, op);
491 if (res == -1)
492 return -errno;
494 return 0;
497 static struct fuse_operations xmp_oper = {
498 .getattr = xmp_getattr,
499 .fgetattr = xmp_fgetattr,
500 .access = xmp_access,
501 .readlink = xmp_readlink,
502 .opendir = xmp_opendir,
503 .readdir = xmp_readdir,
504 .releasedir = xmp_releasedir,
505 .mknod = xmp_mknod,
506 .mkdir = xmp_mkdir,
507 .symlink = xmp_symlink,
508 .unlink = xmp_unlink,
509 .rmdir = xmp_rmdir,
510 .rename = xmp_rename,
511 .link = xmp_link,
512 .chmod = xmp_chmod,
513 .chown = xmp_chown,
514 .truncate = xmp_truncate,
515 .ftruncate = xmp_ftruncate,
516 .utimens = xmp_utimens,
517 .create = xmp_create,
518 .open = xmp_open,
519 .read = xmp_read,
520 .read_buf = xmp_read_buf,
521 .write = xmp_write,
522 .write_buf = xmp_write_buf,
523 .statfs = xmp_statfs,
524 .flush = xmp_flush,
525 .release = xmp_release,
526 .fsync = xmp_fsync,
527 #ifdef HAVE_SETXATTR
528 .setxattr = xmp_setxattr,
529 .getxattr = xmp_getxattr,
530 .listxattr = xmp_listxattr,
531 .removexattr = xmp_removexattr,
532 #endif
533 .lock = xmp_lock,
534 .flock = xmp_flock,
536 .flag_nullpath_ok = 1,
539 int main(int argc, char *argv[])
541 umask(0);
542 return fuse_main(argc, argv, &xmp_oper, NULL);