16881f68fSopenharmony_ci/* 26881f68fSopenharmony_ci FUSE: Filesystem in Userspace 36881f68fSopenharmony_ci Copyright (C) 2001-2007 Miklos Szeredi <miklos@szeredi.hu> 46881f68fSopenharmony_ci Copyright (C) 2011 Sebastian Pipping <sebastian@pipping.org> 56881f68fSopenharmony_ci 66881f68fSopenharmony_ci This program can be distributed under the terms of the GNU GPLv2. 76881f68fSopenharmony_ci See the file COPYING. 86881f68fSopenharmony_ci*/ 96881f68fSopenharmony_ci 106881f68fSopenharmony_ci/** @file 116881f68fSopenharmony_ci * 126881f68fSopenharmony_ci * This file system mirrors the existing file system hierarchy of the 136881f68fSopenharmony_ci * system, starting at the root file system. This is implemented by 146881f68fSopenharmony_ci * just "passing through" all requests to the corresponding user-space 156881f68fSopenharmony_ci * libc functions. This implementation is a little more sophisticated 166881f68fSopenharmony_ci * than the one in passthrough.c, so performance is not quite as bad. 176881f68fSopenharmony_ci * 186881f68fSopenharmony_ci * Compile with: 196881f68fSopenharmony_ci * 206881f68fSopenharmony_ci * gcc -Wall passthrough_fh.c `pkg-config fuse3 --cflags --libs` -lulockmgr -o passthrough_fh 216881f68fSopenharmony_ci * 226881f68fSopenharmony_ci * ## Source code ## 236881f68fSopenharmony_ci * \include passthrough_fh.c 246881f68fSopenharmony_ci */ 256881f68fSopenharmony_ci 266881f68fSopenharmony_ci#define FUSE_USE_VERSION 31 276881f68fSopenharmony_ci 286881f68fSopenharmony_ci#define _GNU_SOURCE 296881f68fSopenharmony_ci 306881f68fSopenharmony_ci#include <fuse.h> 316881f68fSopenharmony_ci 326881f68fSopenharmony_ci#ifdef HAVE_LIBULOCKMGR 336881f68fSopenharmony_ci#include <ulockmgr.h> 346881f68fSopenharmony_ci#endif 356881f68fSopenharmony_ci 366881f68fSopenharmony_ci#include <stdio.h> 376881f68fSopenharmony_ci#include <stdlib.h> 386881f68fSopenharmony_ci#include <string.h> 396881f68fSopenharmony_ci#include <unistd.h> 406881f68fSopenharmony_ci#include <fcntl.h> 416881f68fSopenharmony_ci#include <sys/stat.h> 426881f68fSopenharmony_ci#include <dirent.h> 436881f68fSopenharmony_ci#include <errno.h> 446881f68fSopenharmony_ci#include <sys/time.h> 456881f68fSopenharmony_ci#ifdef HAVE_SETXATTR 466881f68fSopenharmony_ci#include <sys/xattr.h> 476881f68fSopenharmony_ci#endif 486881f68fSopenharmony_ci#include <sys/file.h> /* flock(2) */ 496881f68fSopenharmony_ci 506881f68fSopenharmony_cistatic void *xmp_init(struct fuse_conn_info *conn, 516881f68fSopenharmony_ci struct fuse_config *cfg) 526881f68fSopenharmony_ci{ 536881f68fSopenharmony_ci (void) conn; 546881f68fSopenharmony_ci cfg->use_ino = 1; 556881f68fSopenharmony_ci cfg->nullpath_ok = 1; 566881f68fSopenharmony_ci 576881f68fSopenharmony_ci /* Pick up changes from lower filesystem right away. This is 586881f68fSopenharmony_ci also necessary for better hardlink support. When the kernel 596881f68fSopenharmony_ci calls the unlink() handler, it does not know the inode of 606881f68fSopenharmony_ci the to-be-removed entry and can therefore not invalidate 616881f68fSopenharmony_ci the cache of the associated inode - resulting in an 626881f68fSopenharmony_ci incorrect st_nlink value being reported for any remaining 636881f68fSopenharmony_ci hardlinks to this inode. */ 646881f68fSopenharmony_ci cfg->entry_timeout = 0; 656881f68fSopenharmony_ci cfg->attr_timeout = 0; 666881f68fSopenharmony_ci cfg->negative_timeout = 0; 676881f68fSopenharmony_ci 686881f68fSopenharmony_ci return NULL; 696881f68fSopenharmony_ci} 706881f68fSopenharmony_ci 716881f68fSopenharmony_cistatic int xmp_getattr(const char *path, struct stat *stbuf, 726881f68fSopenharmony_ci struct fuse_file_info *fi) 736881f68fSopenharmony_ci{ 746881f68fSopenharmony_ci int res; 756881f68fSopenharmony_ci 766881f68fSopenharmony_ci (void) path; 776881f68fSopenharmony_ci 786881f68fSopenharmony_ci if(fi) 796881f68fSopenharmony_ci res = fstat(fi->fh, stbuf); 806881f68fSopenharmony_ci else 816881f68fSopenharmony_ci res = lstat(path, stbuf); 826881f68fSopenharmony_ci if (res == -1) 836881f68fSopenharmony_ci return -errno; 846881f68fSopenharmony_ci 856881f68fSopenharmony_ci return 0; 866881f68fSopenharmony_ci} 876881f68fSopenharmony_ci 886881f68fSopenharmony_cistatic int xmp_access(const char *path, int mask) 896881f68fSopenharmony_ci{ 906881f68fSopenharmony_ci int res; 916881f68fSopenharmony_ci 926881f68fSopenharmony_ci res = access(path, mask); 936881f68fSopenharmony_ci if (res == -1) 946881f68fSopenharmony_ci return -errno; 956881f68fSopenharmony_ci 966881f68fSopenharmony_ci return 0; 976881f68fSopenharmony_ci} 986881f68fSopenharmony_ci 996881f68fSopenharmony_cistatic int xmp_readlink(const char *path, char *buf, size_t size) 1006881f68fSopenharmony_ci{ 1016881f68fSopenharmony_ci int res; 1026881f68fSopenharmony_ci 1036881f68fSopenharmony_ci res = readlink(path, buf, size - 1); 1046881f68fSopenharmony_ci if (res == -1) 1056881f68fSopenharmony_ci return -errno; 1066881f68fSopenharmony_ci 1076881f68fSopenharmony_ci buf[res] = '\0'; 1086881f68fSopenharmony_ci return 0; 1096881f68fSopenharmony_ci} 1106881f68fSopenharmony_ci 1116881f68fSopenharmony_cistruct xmp_dirp { 1126881f68fSopenharmony_ci DIR *dp; 1136881f68fSopenharmony_ci struct dirent *entry; 1146881f68fSopenharmony_ci off_t offset; 1156881f68fSopenharmony_ci}; 1166881f68fSopenharmony_ci 1176881f68fSopenharmony_cistatic int xmp_opendir(const char *path, struct fuse_file_info *fi) 1186881f68fSopenharmony_ci{ 1196881f68fSopenharmony_ci int res; 1206881f68fSopenharmony_ci struct xmp_dirp *d = malloc(sizeof(struct xmp_dirp)); 1216881f68fSopenharmony_ci if (d == NULL) 1226881f68fSopenharmony_ci return -ENOMEM; 1236881f68fSopenharmony_ci 1246881f68fSopenharmony_ci d->dp = opendir(path); 1256881f68fSopenharmony_ci if (d->dp == NULL) { 1266881f68fSopenharmony_ci res = -errno; 1276881f68fSopenharmony_ci free(d); 1286881f68fSopenharmony_ci return res; 1296881f68fSopenharmony_ci } 1306881f68fSopenharmony_ci d->offset = 0; 1316881f68fSopenharmony_ci d->entry = NULL; 1326881f68fSopenharmony_ci 1336881f68fSopenharmony_ci fi->fh = (unsigned long) d; 1346881f68fSopenharmony_ci return 0; 1356881f68fSopenharmony_ci} 1366881f68fSopenharmony_ci 1376881f68fSopenharmony_cistatic inline struct xmp_dirp *get_dirp(struct fuse_file_info *fi) 1386881f68fSopenharmony_ci{ 1396881f68fSopenharmony_ci return (struct xmp_dirp *) (uintptr_t) fi->fh; 1406881f68fSopenharmony_ci} 1416881f68fSopenharmony_ci 1426881f68fSopenharmony_cistatic int xmp_readdir(const char *path, void *buf, fuse_fill_dir_t filler, 1436881f68fSopenharmony_ci off_t offset, struct fuse_file_info *fi, 1446881f68fSopenharmony_ci enum fuse_readdir_flags flags) 1456881f68fSopenharmony_ci{ 1466881f68fSopenharmony_ci struct xmp_dirp *d = get_dirp(fi); 1476881f68fSopenharmony_ci 1486881f68fSopenharmony_ci (void) path; 1496881f68fSopenharmony_ci if (offset != d->offset) { 1506881f68fSopenharmony_ci#ifndef __FreeBSD__ 1516881f68fSopenharmony_ci seekdir(d->dp, offset); 1526881f68fSopenharmony_ci#else 1536881f68fSopenharmony_ci /* Subtract the one that we add when calling 1546881f68fSopenharmony_ci telldir() below */ 1556881f68fSopenharmony_ci seekdir(d->dp, offset-1); 1566881f68fSopenharmony_ci#endif 1576881f68fSopenharmony_ci d->entry = NULL; 1586881f68fSopenharmony_ci d->offset = offset; 1596881f68fSopenharmony_ci } 1606881f68fSopenharmony_ci while (1) { 1616881f68fSopenharmony_ci struct stat st; 1626881f68fSopenharmony_ci off_t nextoff; 1636881f68fSopenharmony_ci enum fuse_fill_dir_flags fill_flags = 0; 1646881f68fSopenharmony_ci 1656881f68fSopenharmony_ci if (!d->entry) { 1666881f68fSopenharmony_ci d->entry = readdir(d->dp); 1676881f68fSopenharmony_ci if (!d->entry) 1686881f68fSopenharmony_ci break; 1696881f68fSopenharmony_ci } 1706881f68fSopenharmony_ci#ifdef HAVE_FSTATAT 1716881f68fSopenharmony_ci if (flags & FUSE_READDIR_PLUS) { 1726881f68fSopenharmony_ci int res; 1736881f68fSopenharmony_ci 1746881f68fSopenharmony_ci res = fstatat(dirfd(d->dp), d->entry->d_name, &st, 1756881f68fSopenharmony_ci AT_SYMLINK_NOFOLLOW); 1766881f68fSopenharmony_ci if (res != -1) 1776881f68fSopenharmony_ci fill_flags |= FUSE_FILL_DIR_PLUS; 1786881f68fSopenharmony_ci } 1796881f68fSopenharmony_ci#endif 1806881f68fSopenharmony_ci if (!(fill_flags & FUSE_FILL_DIR_PLUS)) { 1816881f68fSopenharmony_ci memset(&st, 0, sizeof(st)); 1826881f68fSopenharmony_ci st.st_ino = d->entry->d_ino; 1836881f68fSopenharmony_ci st.st_mode = d->entry->d_type << 12; 1846881f68fSopenharmony_ci } 1856881f68fSopenharmony_ci nextoff = telldir(d->dp); 1866881f68fSopenharmony_ci#ifdef __FreeBSD__ 1876881f68fSopenharmony_ci /* Under FreeBSD, telldir() may return 0 the first time 1886881f68fSopenharmony_ci it is called. But for libfuse, an offset of zero 1896881f68fSopenharmony_ci means that offsets are not supported, so we shift 1906881f68fSopenharmony_ci everything by one. */ 1916881f68fSopenharmony_ci nextoff++; 1926881f68fSopenharmony_ci#endif 1936881f68fSopenharmony_ci if (filler(buf, d->entry->d_name, &st, nextoff, fill_flags)) 1946881f68fSopenharmony_ci break; 1956881f68fSopenharmony_ci 1966881f68fSopenharmony_ci d->entry = NULL; 1976881f68fSopenharmony_ci d->offset = nextoff; 1986881f68fSopenharmony_ci } 1996881f68fSopenharmony_ci 2006881f68fSopenharmony_ci return 0; 2016881f68fSopenharmony_ci} 2026881f68fSopenharmony_ci 2036881f68fSopenharmony_cistatic int xmp_releasedir(const char *path, struct fuse_file_info *fi) 2046881f68fSopenharmony_ci{ 2056881f68fSopenharmony_ci struct xmp_dirp *d = get_dirp(fi); 2066881f68fSopenharmony_ci (void) path; 2076881f68fSopenharmony_ci closedir(d->dp); 2086881f68fSopenharmony_ci free(d); 2096881f68fSopenharmony_ci return 0; 2106881f68fSopenharmony_ci} 2116881f68fSopenharmony_ci 2126881f68fSopenharmony_cistatic int xmp_mknod(const char *path, mode_t mode, dev_t rdev) 2136881f68fSopenharmony_ci{ 2146881f68fSopenharmony_ci int res; 2156881f68fSopenharmony_ci 2166881f68fSopenharmony_ci if (S_ISFIFO(mode)) 2176881f68fSopenharmony_ci res = mkfifo(path, mode); 2186881f68fSopenharmony_ci else 2196881f68fSopenharmony_ci res = mknod(path, mode, rdev); 2206881f68fSopenharmony_ci if (res == -1) 2216881f68fSopenharmony_ci return -errno; 2226881f68fSopenharmony_ci 2236881f68fSopenharmony_ci return 0; 2246881f68fSopenharmony_ci} 2256881f68fSopenharmony_ci 2266881f68fSopenharmony_cistatic int xmp_mkdir(const char *path, mode_t mode) 2276881f68fSopenharmony_ci{ 2286881f68fSopenharmony_ci int res; 2296881f68fSopenharmony_ci 2306881f68fSopenharmony_ci res = mkdir(path, mode); 2316881f68fSopenharmony_ci if (res == -1) 2326881f68fSopenharmony_ci return -errno; 2336881f68fSopenharmony_ci 2346881f68fSopenharmony_ci return 0; 2356881f68fSopenharmony_ci} 2366881f68fSopenharmony_ci 2376881f68fSopenharmony_cistatic int xmp_unlink(const char *path) 2386881f68fSopenharmony_ci{ 2396881f68fSopenharmony_ci int res; 2406881f68fSopenharmony_ci 2416881f68fSopenharmony_ci res = unlink(path); 2426881f68fSopenharmony_ci if (res == -1) 2436881f68fSopenharmony_ci return -errno; 2446881f68fSopenharmony_ci 2456881f68fSopenharmony_ci return 0; 2466881f68fSopenharmony_ci} 2476881f68fSopenharmony_ci 2486881f68fSopenharmony_cistatic int xmp_rmdir(const char *path) 2496881f68fSopenharmony_ci{ 2506881f68fSopenharmony_ci int res; 2516881f68fSopenharmony_ci 2526881f68fSopenharmony_ci res = rmdir(path); 2536881f68fSopenharmony_ci if (res == -1) 2546881f68fSopenharmony_ci return -errno; 2556881f68fSopenharmony_ci 2566881f68fSopenharmony_ci return 0; 2576881f68fSopenharmony_ci} 2586881f68fSopenharmony_ci 2596881f68fSopenharmony_cistatic int xmp_symlink(const char *from, const char *to) 2606881f68fSopenharmony_ci{ 2616881f68fSopenharmony_ci int res; 2626881f68fSopenharmony_ci 2636881f68fSopenharmony_ci res = symlink(from, to); 2646881f68fSopenharmony_ci if (res == -1) 2656881f68fSopenharmony_ci return -errno; 2666881f68fSopenharmony_ci 2676881f68fSopenharmony_ci return 0; 2686881f68fSopenharmony_ci} 2696881f68fSopenharmony_ci 2706881f68fSopenharmony_cistatic int xmp_rename(const char *from, const char *to, unsigned int flags) 2716881f68fSopenharmony_ci{ 2726881f68fSopenharmony_ci int res; 2736881f68fSopenharmony_ci 2746881f68fSopenharmony_ci /* When we have renameat2() in libc, then we can implement flags */ 2756881f68fSopenharmony_ci if (flags) 2766881f68fSopenharmony_ci return -EINVAL; 2776881f68fSopenharmony_ci 2786881f68fSopenharmony_ci res = rename(from, to); 2796881f68fSopenharmony_ci if (res == -1) 2806881f68fSopenharmony_ci return -errno; 2816881f68fSopenharmony_ci 2826881f68fSopenharmony_ci return 0; 2836881f68fSopenharmony_ci} 2846881f68fSopenharmony_ci 2856881f68fSopenharmony_cistatic int xmp_link(const char *from, const char *to) 2866881f68fSopenharmony_ci{ 2876881f68fSopenharmony_ci int res; 2886881f68fSopenharmony_ci 2896881f68fSopenharmony_ci res = link(from, to); 2906881f68fSopenharmony_ci if (res == -1) 2916881f68fSopenharmony_ci return -errno; 2926881f68fSopenharmony_ci 2936881f68fSopenharmony_ci return 0; 2946881f68fSopenharmony_ci} 2956881f68fSopenharmony_ci 2966881f68fSopenharmony_cistatic int xmp_chmod(const char *path, mode_t mode, 2976881f68fSopenharmony_ci struct fuse_file_info *fi) 2986881f68fSopenharmony_ci{ 2996881f68fSopenharmony_ci int res; 3006881f68fSopenharmony_ci 3016881f68fSopenharmony_ci if(fi) 3026881f68fSopenharmony_ci res = fchmod(fi->fh, mode); 3036881f68fSopenharmony_ci else 3046881f68fSopenharmony_ci res = chmod(path, mode); 3056881f68fSopenharmony_ci if (res == -1) 3066881f68fSopenharmony_ci return -errno; 3076881f68fSopenharmony_ci 3086881f68fSopenharmony_ci return 0; 3096881f68fSopenharmony_ci} 3106881f68fSopenharmony_ci 3116881f68fSopenharmony_cistatic int xmp_chown(const char *path, uid_t uid, gid_t gid, 3126881f68fSopenharmony_ci struct fuse_file_info *fi) 3136881f68fSopenharmony_ci{ 3146881f68fSopenharmony_ci int res; 3156881f68fSopenharmony_ci 3166881f68fSopenharmony_ci if (fi) 3176881f68fSopenharmony_ci res = fchown(fi->fh, uid, gid); 3186881f68fSopenharmony_ci else 3196881f68fSopenharmony_ci res = lchown(path, uid, gid); 3206881f68fSopenharmony_ci if (res == -1) 3216881f68fSopenharmony_ci return -errno; 3226881f68fSopenharmony_ci 3236881f68fSopenharmony_ci return 0; 3246881f68fSopenharmony_ci} 3256881f68fSopenharmony_ci 3266881f68fSopenharmony_cistatic int xmp_truncate(const char *path, off_t size, 3276881f68fSopenharmony_ci struct fuse_file_info *fi) 3286881f68fSopenharmony_ci{ 3296881f68fSopenharmony_ci int res; 3306881f68fSopenharmony_ci 3316881f68fSopenharmony_ci if(fi) 3326881f68fSopenharmony_ci res = ftruncate(fi->fh, size); 3336881f68fSopenharmony_ci else 3346881f68fSopenharmony_ci res = truncate(path, size); 3356881f68fSopenharmony_ci 3366881f68fSopenharmony_ci if (res == -1) 3376881f68fSopenharmony_ci return -errno; 3386881f68fSopenharmony_ci 3396881f68fSopenharmony_ci return 0; 3406881f68fSopenharmony_ci} 3416881f68fSopenharmony_ci 3426881f68fSopenharmony_ci#ifdef HAVE_UTIMENSAT 3436881f68fSopenharmony_cistatic int xmp_utimens(const char *path, const struct timespec ts[2], 3446881f68fSopenharmony_ci struct fuse_file_info *fi) 3456881f68fSopenharmony_ci{ 3466881f68fSopenharmony_ci int res; 3476881f68fSopenharmony_ci 3486881f68fSopenharmony_ci /* don't use utime/utimes since they follow symlinks */ 3496881f68fSopenharmony_ci if (fi) 3506881f68fSopenharmony_ci res = futimens(fi->fh, ts); 3516881f68fSopenharmony_ci else 3526881f68fSopenharmony_ci res = utimensat(0, path, ts, AT_SYMLINK_NOFOLLOW); 3536881f68fSopenharmony_ci if (res == -1) 3546881f68fSopenharmony_ci return -errno; 3556881f68fSopenharmony_ci 3566881f68fSopenharmony_ci return 0; 3576881f68fSopenharmony_ci} 3586881f68fSopenharmony_ci#endif 3596881f68fSopenharmony_ci 3606881f68fSopenharmony_cistatic int xmp_create(const char *path, mode_t mode, struct fuse_file_info *fi) 3616881f68fSopenharmony_ci{ 3626881f68fSopenharmony_ci int fd; 3636881f68fSopenharmony_ci 3646881f68fSopenharmony_ci fd = open(path, fi->flags, mode); 3656881f68fSopenharmony_ci if (fd == -1) 3666881f68fSopenharmony_ci return -errno; 3676881f68fSopenharmony_ci 3686881f68fSopenharmony_ci fi->fh = fd; 3696881f68fSopenharmony_ci return 0; 3706881f68fSopenharmony_ci} 3716881f68fSopenharmony_ci 3726881f68fSopenharmony_cistatic int xmp_open(const char *path, struct fuse_file_info *fi) 3736881f68fSopenharmony_ci{ 3746881f68fSopenharmony_ci int fd; 3756881f68fSopenharmony_ci 3766881f68fSopenharmony_ci fd = open(path, fi->flags); 3776881f68fSopenharmony_ci if (fd == -1) 3786881f68fSopenharmony_ci return -errno; 3796881f68fSopenharmony_ci 3806881f68fSopenharmony_ci fi->fh = fd; 3816881f68fSopenharmony_ci return 0; 3826881f68fSopenharmony_ci} 3836881f68fSopenharmony_ci 3846881f68fSopenharmony_cistatic int xmp_read(const char *path, char *buf, size_t size, off_t offset, 3856881f68fSopenharmony_ci struct fuse_file_info *fi) 3866881f68fSopenharmony_ci{ 3876881f68fSopenharmony_ci int res; 3886881f68fSopenharmony_ci 3896881f68fSopenharmony_ci (void) path; 3906881f68fSopenharmony_ci res = pread(fi->fh, buf, size, offset); 3916881f68fSopenharmony_ci if (res == -1) 3926881f68fSopenharmony_ci res = -errno; 3936881f68fSopenharmony_ci 3946881f68fSopenharmony_ci return res; 3956881f68fSopenharmony_ci} 3966881f68fSopenharmony_ci 3976881f68fSopenharmony_cistatic int xmp_read_buf(const char *path, struct fuse_bufvec **bufp, 3986881f68fSopenharmony_ci size_t size, off_t offset, struct fuse_file_info *fi) 3996881f68fSopenharmony_ci{ 4006881f68fSopenharmony_ci struct fuse_bufvec *src; 4016881f68fSopenharmony_ci 4026881f68fSopenharmony_ci (void) path; 4036881f68fSopenharmony_ci 4046881f68fSopenharmony_ci src = malloc(sizeof(struct fuse_bufvec)); 4056881f68fSopenharmony_ci if (src == NULL) 4066881f68fSopenharmony_ci return -ENOMEM; 4076881f68fSopenharmony_ci 4086881f68fSopenharmony_ci *src = FUSE_BUFVEC_INIT(size); 4096881f68fSopenharmony_ci 4106881f68fSopenharmony_ci src->buf[0].flags = FUSE_BUF_IS_FD | FUSE_BUF_FD_SEEK; 4116881f68fSopenharmony_ci src->buf[0].fd = fi->fh; 4126881f68fSopenharmony_ci src->buf[0].pos = offset; 4136881f68fSopenharmony_ci 4146881f68fSopenharmony_ci *bufp = src; 4156881f68fSopenharmony_ci 4166881f68fSopenharmony_ci return 0; 4176881f68fSopenharmony_ci} 4186881f68fSopenharmony_ci 4196881f68fSopenharmony_cistatic int xmp_write(const char *path, const char *buf, size_t size, 4206881f68fSopenharmony_ci off_t offset, struct fuse_file_info *fi) 4216881f68fSopenharmony_ci{ 4226881f68fSopenharmony_ci int res; 4236881f68fSopenharmony_ci 4246881f68fSopenharmony_ci (void) path; 4256881f68fSopenharmony_ci res = pwrite(fi->fh, buf, size, offset); 4266881f68fSopenharmony_ci if (res == -1) 4276881f68fSopenharmony_ci res = -errno; 4286881f68fSopenharmony_ci 4296881f68fSopenharmony_ci return res; 4306881f68fSopenharmony_ci} 4316881f68fSopenharmony_ci 4326881f68fSopenharmony_cistatic int xmp_write_buf(const char *path, struct fuse_bufvec *buf, 4336881f68fSopenharmony_ci off_t offset, struct fuse_file_info *fi) 4346881f68fSopenharmony_ci{ 4356881f68fSopenharmony_ci struct fuse_bufvec dst = FUSE_BUFVEC_INIT(fuse_buf_size(buf)); 4366881f68fSopenharmony_ci 4376881f68fSopenharmony_ci (void) path; 4386881f68fSopenharmony_ci 4396881f68fSopenharmony_ci dst.buf[0].flags = FUSE_BUF_IS_FD | FUSE_BUF_FD_SEEK; 4406881f68fSopenharmony_ci dst.buf[0].fd = fi->fh; 4416881f68fSopenharmony_ci dst.buf[0].pos = offset; 4426881f68fSopenharmony_ci 4436881f68fSopenharmony_ci return fuse_buf_copy(&dst, buf, FUSE_BUF_SPLICE_NONBLOCK); 4446881f68fSopenharmony_ci} 4456881f68fSopenharmony_ci 4466881f68fSopenharmony_cistatic int xmp_statfs(const char *path, struct statvfs *stbuf) 4476881f68fSopenharmony_ci{ 4486881f68fSopenharmony_ci int res; 4496881f68fSopenharmony_ci 4506881f68fSopenharmony_ci res = statvfs(path, stbuf); 4516881f68fSopenharmony_ci if (res == -1) 4526881f68fSopenharmony_ci return -errno; 4536881f68fSopenharmony_ci 4546881f68fSopenharmony_ci return 0; 4556881f68fSopenharmony_ci} 4566881f68fSopenharmony_ci 4576881f68fSopenharmony_cistatic int xmp_flush(const char *path, struct fuse_file_info *fi) 4586881f68fSopenharmony_ci{ 4596881f68fSopenharmony_ci int res; 4606881f68fSopenharmony_ci 4616881f68fSopenharmony_ci (void) path; 4626881f68fSopenharmony_ci /* This is called from every close on an open file, so call the 4636881f68fSopenharmony_ci close on the underlying filesystem. But since flush may be 4646881f68fSopenharmony_ci called multiple times for an open file, this must not really 4656881f68fSopenharmony_ci close the file. This is important if used on a network 4666881f68fSopenharmony_ci filesystem like NFS which flush the data/metadata on close() */ 4676881f68fSopenharmony_ci res = close(dup(fi->fh)); 4686881f68fSopenharmony_ci if (res == -1) 4696881f68fSopenharmony_ci return -errno; 4706881f68fSopenharmony_ci 4716881f68fSopenharmony_ci return 0; 4726881f68fSopenharmony_ci} 4736881f68fSopenharmony_ci 4746881f68fSopenharmony_cistatic int xmp_release(const char *path, struct fuse_file_info *fi) 4756881f68fSopenharmony_ci{ 4766881f68fSopenharmony_ci (void) path; 4776881f68fSopenharmony_ci close(fi->fh); 4786881f68fSopenharmony_ci 4796881f68fSopenharmony_ci return 0; 4806881f68fSopenharmony_ci} 4816881f68fSopenharmony_ci 4826881f68fSopenharmony_cistatic int xmp_fsync(const char *path, int isdatasync, 4836881f68fSopenharmony_ci struct fuse_file_info *fi) 4846881f68fSopenharmony_ci{ 4856881f68fSopenharmony_ci int res; 4866881f68fSopenharmony_ci (void) path; 4876881f68fSopenharmony_ci 4886881f68fSopenharmony_ci#ifndef HAVE_FDATASYNC 4896881f68fSopenharmony_ci (void) isdatasync; 4906881f68fSopenharmony_ci#else 4916881f68fSopenharmony_ci if (isdatasync) 4926881f68fSopenharmony_ci res = fdatasync(fi->fh); 4936881f68fSopenharmony_ci else 4946881f68fSopenharmony_ci#endif 4956881f68fSopenharmony_ci res = fsync(fi->fh); 4966881f68fSopenharmony_ci if (res == -1) 4976881f68fSopenharmony_ci return -errno; 4986881f68fSopenharmony_ci 4996881f68fSopenharmony_ci return 0; 5006881f68fSopenharmony_ci} 5016881f68fSopenharmony_ci 5026881f68fSopenharmony_ci#ifdef HAVE_POSIX_FALLOCATE 5036881f68fSopenharmony_cistatic int xmp_fallocate(const char *path, int mode, 5046881f68fSopenharmony_ci off_t offset, off_t length, struct fuse_file_info *fi) 5056881f68fSopenharmony_ci{ 5066881f68fSopenharmony_ci (void) path; 5076881f68fSopenharmony_ci 5086881f68fSopenharmony_ci if (mode) 5096881f68fSopenharmony_ci return -EOPNOTSUPP; 5106881f68fSopenharmony_ci 5116881f68fSopenharmony_ci return -posix_fallocate(fi->fh, offset, length); 5126881f68fSopenharmony_ci} 5136881f68fSopenharmony_ci#endif 5146881f68fSopenharmony_ci 5156881f68fSopenharmony_ci#ifdef HAVE_SETXATTR 5166881f68fSopenharmony_ci/* xattr operations are optional and can safely be left unimplemented */ 5176881f68fSopenharmony_cistatic int xmp_setxattr(const char *path, const char *name, const char *value, 5186881f68fSopenharmony_ci size_t size, int flags) 5196881f68fSopenharmony_ci{ 5206881f68fSopenharmony_ci int res = lsetxattr(path, name, value, size, flags); 5216881f68fSopenharmony_ci if (res == -1) 5226881f68fSopenharmony_ci return -errno; 5236881f68fSopenharmony_ci return 0; 5246881f68fSopenharmony_ci} 5256881f68fSopenharmony_ci 5266881f68fSopenharmony_cistatic int xmp_getxattr(const char *path, const char *name, char *value, 5276881f68fSopenharmony_ci size_t size) 5286881f68fSopenharmony_ci{ 5296881f68fSopenharmony_ci int res = lgetxattr(path, name, value, size); 5306881f68fSopenharmony_ci if (res == -1) 5316881f68fSopenharmony_ci return -errno; 5326881f68fSopenharmony_ci return res; 5336881f68fSopenharmony_ci} 5346881f68fSopenharmony_ci 5356881f68fSopenharmony_cistatic int xmp_listxattr(const char *path, char *list, size_t size) 5366881f68fSopenharmony_ci{ 5376881f68fSopenharmony_ci int res = llistxattr(path, list, size); 5386881f68fSopenharmony_ci if (res == -1) 5396881f68fSopenharmony_ci return -errno; 5406881f68fSopenharmony_ci return res; 5416881f68fSopenharmony_ci} 5426881f68fSopenharmony_ci 5436881f68fSopenharmony_cistatic int xmp_removexattr(const char *path, const char *name) 5446881f68fSopenharmony_ci{ 5456881f68fSopenharmony_ci int res = lremovexattr(path, name); 5466881f68fSopenharmony_ci if (res == -1) 5476881f68fSopenharmony_ci return -errno; 5486881f68fSopenharmony_ci return 0; 5496881f68fSopenharmony_ci} 5506881f68fSopenharmony_ci#endif /* HAVE_SETXATTR */ 5516881f68fSopenharmony_ci 5526881f68fSopenharmony_ci#ifdef HAVE_LIBULOCKMGR 5536881f68fSopenharmony_cistatic int xmp_lock(const char *path, struct fuse_file_info *fi, int cmd, 5546881f68fSopenharmony_ci struct flock *lock) 5556881f68fSopenharmony_ci{ 5566881f68fSopenharmony_ci (void) path; 5576881f68fSopenharmony_ci 5586881f68fSopenharmony_ci return ulockmgr_op(fi->fh, cmd, lock, &fi->lock_owner, 5596881f68fSopenharmony_ci sizeof(fi->lock_owner)); 5606881f68fSopenharmony_ci} 5616881f68fSopenharmony_ci#endif 5626881f68fSopenharmony_ci 5636881f68fSopenharmony_cistatic int xmp_flock(const char *path, struct fuse_file_info *fi, int op) 5646881f68fSopenharmony_ci{ 5656881f68fSopenharmony_ci int res; 5666881f68fSopenharmony_ci (void) path; 5676881f68fSopenharmony_ci 5686881f68fSopenharmony_ci res = flock(fi->fh, op); 5696881f68fSopenharmony_ci if (res == -1) 5706881f68fSopenharmony_ci return -errno; 5716881f68fSopenharmony_ci 5726881f68fSopenharmony_ci return 0; 5736881f68fSopenharmony_ci} 5746881f68fSopenharmony_ci 5756881f68fSopenharmony_ci#ifdef HAVE_COPY_FILE_RANGE 5766881f68fSopenharmony_cistatic ssize_t xmp_copy_file_range(const char *path_in, 5776881f68fSopenharmony_ci struct fuse_file_info *fi_in, 5786881f68fSopenharmony_ci off_t off_in, const char *path_out, 5796881f68fSopenharmony_ci struct fuse_file_info *fi_out, 5806881f68fSopenharmony_ci off_t off_out, size_t len, int flags) 5816881f68fSopenharmony_ci{ 5826881f68fSopenharmony_ci ssize_t res; 5836881f68fSopenharmony_ci (void) path_in; 5846881f68fSopenharmony_ci (void) path_out; 5856881f68fSopenharmony_ci 5866881f68fSopenharmony_ci res = copy_file_range(fi_in->fh, &off_in, fi_out->fh, &off_out, len, 5876881f68fSopenharmony_ci flags); 5886881f68fSopenharmony_ci if (res == -1) 5896881f68fSopenharmony_ci return -errno; 5906881f68fSopenharmony_ci 5916881f68fSopenharmony_ci return res; 5926881f68fSopenharmony_ci} 5936881f68fSopenharmony_ci#endif 5946881f68fSopenharmony_ci 5956881f68fSopenharmony_cistatic off_t xmp_lseek(const char *path, off_t off, int whence, struct fuse_file_info *fi) 5966881f68fSopenharmony_ci{ 5976881f68fSopenharmony_ci off_t res; 5986881f68fSopenharmony_ci (void) path; 5996881f68fSopenharmony_ci 6006881f68fSopenharmony_ci res = lseek(fi->fh, off, whence); 6016881f68fSopenharmony_ci if (res == -1) 6026881f68fSopenharmony_ci return -errno; 6036881f68fSopenharmony_ci 6046881f68fSopenharmony_ci return res; 6056881f68fSopenharmony_ci} 6066881f68fSopenharmony_ci 6076881f68fSopenharmony_cistatic const struct fuse_operations xmp_oper = { 6086881f68fSopenharmony_ci .init = xmp_init, 6096881f68fSopenharmony_ci .getattr = xmp_getattr, 6106881f68fSopenharmony_ci .access = xmp_access, 6116881f68fSopenharmony_ci .readlink = xmp_readlink, 6126881f68fSopenharmony_ci .opendir = xmp_opendir, 6136881f68fSopenharmony_ci .readdir = xmp_readdir, 6146881f68fSopenharmony_ci .releasedir = xmp_releasedir, 6156881f68fSopenharmony_ci .mknod = xmp_mknod, 6166881f68fSopenharmony_ci .mkdir = xmp_mkdir, 6176881f68fSopenharmony_ci .symlink = xmp_symlink, 6186881f68fSopenharmony_ci .unlink = xmp_unlink, 6196881f68fSopenharmony_ci .rmdir = xmp_rmdir, 6206881f68fSopenharmony_ci .rename = xmp_rename, 6216881f68fSopenharmony_ci .link = xmp_link, 6226881f68fSopenharmony_ci .chmod = xmp_chmod, 6236881f68fSopenharmony_ci .chown = xmp_chown, 6246881f68fSopenharmony_ci .truncate = xmp_truncate, 6256881f68fSopenharmony_ci#ifdef HAVE_UTIMENSAT 6266881f68fSopenharmony_ci .utimens = xmp_utimens, 6276881f68fSopenharmony_ci#endif 6286881f68fSopenharmony_ci .create = xmp_create, 6296881f68fSopenharmony_ci .open = xmp_open, 6306881f68fSopenharmony_ci .read = xmp_read, 6316881f68fSopenharmony_ci .read_buf = xmp_read_buf, 6326881f68fSopenharmony_ci .write = xmp_write, 6336881f68fSopenharmony_ci .write_buf = xmp_write_buf, 6346881f68fSopenharmony_ci .statfs = xmp_statfs, 6356881f68fSopenharmony_ci .flush = xmp_flush, 6366881f68fSopenharmony_ci .release = xmp_release, 6376881f68fSopenharmony_ci .fsync = xmp_fsync, 6386881f68fSopenharmony_ci#ifdef HAVE_POSIX_FALLOCATE 6396881f68fSopenharmony_ci .fallocate = xmp_fallocate, 6406881f68fSopenharmony_ci#endif 6416881f68fSopenharmony_ci#ifdef HAVE_SETXATTR 6426881f68fSopenharmony_ci .setxattr = xmp_setxattr, 6436881f68fSopenharmony_ci .getxattr = xmp_getxattr, 6446881f68fSopenharmony_ci .listxattr = xmp_listxattr, 6456881f68fSopenharmony_ci .removexattr = xmp_removexattr, 6466881f68fSopenharmony_ci#endif 6476881f68fSopenharmony_ci#ifdef HAVE_LIBULOCKMGR 6486881f68fSopenharmony_ci .lock = xmp_lock, 6496881f68fSopenharmony_ci#endif 6506881f68fSopenharmony_ci .flock = xmp_flock, 6516881f68fSopenharmony_ci#ifdef HAVE_COPY_FILE_RANGE 6526881f68fSopenharmony_ci .copy_file_range = xmp_copy_file_range, 6536881f68fSopenharmony_ci#endif 6546881f68fSopenharmony_ci .lseek = xmp_lseek, 6556881f68fSopenharmony_ci}; 6566881f68fSopenharmony_ci 6576881f68fSopenharmony_ciint main(int argc, char *argv[]) 6586881f68fSopenharmony_ci{ 6596881f68fSopenharmony_ci umask(0); 6606881f68fSopenharmony_ci return fuse_main(argc, argv, &xmp_oper, NULL); 6616881f68fSopenharmony_ci} 662