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