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.
9 gcc -Wall fusexmp_fh.c `pkg-config fuse --cflags --libs` -lulockmgr -o fusexmp_fh
12 #define FUSE_USE_VERSION 26
32 #include <sys/xattr.h>
34 #include <sys/file.h> /* flock(2) */
36 static int xmp_getattr(const char *path
, struct stat
*stbuf
)
40 res
= lstat(path
, stbuf
);
47 static int xmp_fgetattr(const char *path
, struct stat
*stbuf
,
48 struct fuse_file_info
*fi
)
54 res
= fstat(fi
->fh
, stbuf
);
61 static int xmp_access(const char *path
, int mask
)
65 res
= access(path
, mask
);
72 static int xmp_readlink(const char *path
, char *buf
, size_t size
)
76 res
= readlink(path
, buf
, size
- 1);
90 static int xmp_opendir(const char *path
, struct fuse_file_info
*fi
)
93 struct xmp_dirp
*d
= malloc(sizeof(struct xmp_dirp
));
97 d
->dp
= opendir(path
);
106 fi
->fh
= (unsigned long) d
;
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
);
121 if (offset
!= d
->offset
) {
122 seekdir(d
->dp
, offset
);
131 d
->entry
= readdir(d
->dp
);
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
))
150 static int xmp_releasedir(const char *path
, struct fuse_file_info
*fi
)
152 struct xmp_dirp
*d
= get_dirp(fi
);
159 static int xmp_mknod(const char *path
, mode_t mode
, dev_t rdev
)
164 res
= mkfifo(path
, mode
);
166 res
= mknod(path
, mode
, rdev
);
173 static int xmp_mkdir(const char *path
, mode_t mode
)
177 res
= mkdir(path
, mode
);
184 static int xmp_unlink(const char *path
)
195 static int xmp_rmdir(const char *path
)
206 static int xmp_symlink(const char *from
, const char *to
)
210 res
= symlink(from
, to
);
217 static int xmp_rename(const char *from
, const char *to
)
221 res
= rename(from
, to
);
228 static int xmp_link(const char *from
, const char *to
)
232 res
= link(from
, to
);
239 static int xmp_chmod(const char *path
, mode_t mode
)
243 res
= chmod(path
, mode
);
250 static int xmp_chown(const char *path
, uid_t uid
, gid_t gid
)
254 res
= lchown(path
, uid
, gid
);
261 static int xmp_truncate(const char *path
, off_t size
)
265 res
= truncate(path
, size
);
272 static int xmp_ftruncate(const char *path
, off_t size
,
273 struct fuse_file_info
*fi
)
279 res
= ftruncate(fi
->fh
, size
);
286 #ifdef HAVE_UTIMENSAT
287 static int xmp_utimens(const char *path
, const struct timespec ts
[2])
291 /* don't use utime/utimes since they follow symlinks */
292 res
= utimensat(0, path
, ts
, AT_SYMLINK_NOFOLLOW
);
300 static int xmp_create(const char *path
, mode_t mode
, struct fuse_file_info
*fi
)
304 fd
= open(path
, fi
->flags
, mode
);
312 static int xmp_open(const char *path
, struct fuse_file_info
*fi
)
316 fd
= open(path
, fi
->flags
);
324 static int xmp_read(const char *path
, char *buf
, size_t size
, off_t offset
,
325 struct fuse_file_info
*fi
)
330 res
= pread(fi
->fh
, buf
, size
, offset
);
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
;
344 src
= malloc(sizeof(struct fuse_bufvec
));
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
;
359 static int xmp_write(const char *path
, const char *buf
, size_t size
,
360 off_t offset
, struct fuse_file_info
*fi
)
365 res
= pwrite(fi
->fh
, buf
, size
, offset
);
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
));
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
)
390 res
= statvfs(path
, stbuf
);
397 static int xmp_flush(const char *path
, struct fuse_file_info
*fi
)
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
));
414 static int xmp_release(const char *path
, struct fuse_file_info
*fi
)
422 static int xmp_fsync(const char *path
, int isdatasync
,
423 struct fuse_file_info
*fi
)
428 #ifndef HAVE_FDATASYNC
432 res
= fdatasync(fi
->fh
);
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
)
451 return -posix_fallocate(fi
->fh
, offset
, length
);
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
);
466 static int xmp_getxattr(const char *path
, const char *name
, char *value
,
469 int res
= lgetxattr(path
, name
, value
, size
);
475 static int xmp_listxattr(const char *path
, char *list
, size_t size
)
477 int res
= llistxattr(path
, list
, size
);
483 static int xmp_removexattr(const char *path
, const char *name
)
485 int res
= lremovexattr(path
, name
);
490 #endif /* HAVE_SETXATTR */
492 static int xmp_lock(const char *path
, struct fuse_file_info
*fi
, int cmd
,
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
)
506 res
= flock(fi
->fh
, op
);
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
,
523 .symlink
= xmp_symlink
,
524 .unlink
= xmp_unlink
,
526 .rename
= xmp_rename
,
530 .truncate
= xmp_truncate
,
531 .ftruncate
= xmp_ftruncate
,
532 #ifdef HAVE_UTIMENSAT
533 .utimens
= xmp_utimens
,
535 .create
= xmp_create
,
538 .read_buf
= xmp_read_buf
,
540 .write_buf
= xmp_write_buf
,
541 .statfs
= xmp_statfs
,
543 .release
= xmp_release
,
545 #ifdef HAVE_POSIX_FALLOCATE
546 .fallocate
= xmp_fallocate
,
549 .setxattr
= xmp_setxattr
,
550 .getxattr
= xmp_getxattr
,
551 .listxattr
= xmp_listxattr
,
552 .removexattr
= xmp_removexattr
,
557 .flag_nullpath_ok
= 1,
559 .flag_utime_omit_ok
= 1,
563 int main(int argc
, char *argv
[])
566 return fuse_main(argc
, argv
, &xmp_oper
, NULL
);