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. Its performance is terrible.
166881f68fSopenharmony_ci *
176881f68fSopenharmony_ci * Compile with
186881f68fSopenharmony_ci *
196881f68fSopenharmony_ci *     gcc -Wall passthrough.c `pkg-config fuse3 --cflags --libs` -o passthrough
206881f68fSopenharmony_ci *
216881f68fSopenharmony_ci * ## Source code ##
226881f68fSopenharmony_ci * \include passthrough.c
236881f68fSopenharmony_ci */
246881f68fSopenharmony_ci
256881f68fSopenharmony_ci
266881f68fSopenharmony_ci#define FUSE_USE_VERSION 31
276881f68fSopenharmony_ci
286881f68fSopenharmony_ci#define _GNU_SOURCE
296881f68fSopenharmony_ci
306881f68fSopenharmony_ci#ifdef linux
316881f68fSopenharmony_ci/* For pread()/pwrite()/utimensat() */
326881f68fSopenharmony_ci#define _XOPEN_SOURCE 700
336881f68fSopenharmony_ci#endif
346881f68fSopenharmony_ci
356881f68fSopenharmony_ci#include <fuse.h>
366881f68fSopenharmony_ci#include <stdio.h>
376881f68fSopenharmony_ci#include <string.h>
386881f68fSopenharmony_ci#include <unistd.h>
396881f68fSopenharmony_ci#include <fcntl.h>
406881f68fSopenharmony_ci#include <sys/stat.h>
416881f68fSopenharmony_ci#include <dirent.h>
426881f68fSopenharmony_ci#include <errno.h>
436881f68fSopenharmony_ci#ifdef __FreeBSD__
446881f68fSopenharmony_ci#include <sys/socket.h>
456881f68fSopenharmony_ci#include <sys/un.h>
466881f68fSopenharmony_ci#endif
476881f68fSopenharmony_ci#include <sys/time.h>
486881f68fSopenharmony_ci#ifdef HAVE_SETXATTR
496881f68fSopenharmony_ci#include <sys/xattr.h>
506881f68fSopenharmony_ci#endif
516881f68fSopenharmony_ci
526881f68fSopenharmony_ci#include "passthrough_helpers.h"
536881f68fSopenharmony_ci
546881f68fSopenharmony_cistatic int fill_dir_plus = 0;
556881f68fSopenharmony_ci
566881f68fSopenharmony_cistatic void *xmp_init(struct fuse_conn_info *conn,
576881f68fSopenharmony_ci		      struct fuse_config *cfg)
586881f68fSopenharmony_ci{
596881f68fSopenharmony_ci	(void) conn;
606881f68fSopenharmony_ci	cfg->use_ino = 1;
616881f68fSopenharmony_ci
626881f68fSopenharmony_ci	/* Pick up changes from lower filesystem right away. This is
636881f68fSopenharmony_ci	   also necessary for better hardlink support. When the kernel
646881f68fSopenharmony_ci	   calls the unlink() handler, it does not know the inode of
656881f68fSopenharmony_ci	   the to-be-removed entry and can therefore not invalidate
666881f68fSopenharmony_ci	   the cache of the associated inode - resulting in an
676881f68fSopenharmony_ci	   incorrect st_nlink value being reported for any remaining
686881f68fSopenharmony_ci	   hardlinks to this inode. */
696881f68fSopenharmony_ci	cfg->entry_timeout = 0;
706881f68fSopenharmony_ci	cfg->attr_timeout = 0;
716881f68fSopenharmony_ci	cfg->negative_timeout = 0;
726881f68fSopenharmony_ci
736881f68fSopenharmony_ci	return NULL;
746881f68fSopenharmony_ci}
756881f68fSopenharmony_ci
766881f68fSopenharmony_cistatic int xmp_getattr(const char *path, struct stat *stbuf,
776881f68fSopenharmony_ci		       struct fuse_file_info *fi)
786881f68fSopenharmony_ci{
796881f68fSopenharmony_ci	(void) fi;
806881f68fSopenharmony_ci	int res;
816881f68fSopenharmony_ci
826881f68fSopenharmony_ci	res = lstat(path, stbuf);
836881f68fSopenharmony_ci	if (res == -1)
846881f68fSopenharmony_ci		return -errno;
856881f68fSopenharmony_ci
866881f68fSopenharmony_ci	return 0;
876881f68fSopenharmony_ci}
886881f68fSopenharmony_ci
896881f68fSopenharmony_cistatic int xmp_access(const char *path, int mask)
906881f68fSopenharmony_ci{
916881f68fSopenharmony_ci	int res;
926881f68fSopenharmony_ci
936881f68fSopenharmony_ci	res = access(path, mask);
946881f68fSopenharmony_ci	if (res == -1)
956881f68fSopenharmony_ci		return -errno;
966881f68fSopenharmony_ci
976881f68fSopenharmony_ci	return 0;
986881f68fSopenharmony_ci}
996881f68fSopenharmony_ci
1006881f68fSopenharmony_cistatic int xmp_readlink(const char *path, char *buf, size_t size)
1016881f68fSopenharmony_ci{
1026881f68fSopenharmony_ci	int res;
1036881f68fSopenharmony_ci
1046881f68fSopenharmony_ci	res = readlink(path, buf, size - 1);
1056881f68fSopenharmony_ci	if (res == -1)
1066881f68fSopenharmony_ci		return -errno;
1076881f68fSopenharmony_ci
1086881f68fSopenharmony_ci	buf[res] = '\0';
1096881f68fSopenharmony_ci	return 0;
1106881f68fSopenharmony_ci}
1116881f68fSopenharmony_ci
1126881f68fSopenharmony_ci
1136881f68fSopenharmony_cistatic int xmp_readdir(const char *path, void *buf, fuse_fill_dir_t filler,
1146881f68fSopenharmony_ci		       off_t offset, struct fuse_file_info *fi,
1156881f68fSopenharmony_ci		       enum fuse_readdir_flags flags)
1166881f68fSopenharmony_ci{
1176881f68fSopenharmony_ci	DIR *dp;
1186881f68fSopenharmony_ci	struct dirent *de;
1196881f68fSopenharmony_ci
1206881f68fSopenharmony_ci	(void) offset;
1216881f68fSopenharmony_ci	(void) fi;
1226881f68fSopenharmony_ci	(void) flags;
1236881f68fSopenharmony_ci
1246881f68fSopenharmony_ci	dp = opendir(path);
1256881f68fSopenharmony_ci	if (dp == NULL)
1266881f68fSopenharmony_ci		return -errno;
1276881f68fSopenharmony_ci
1286881f68fSopenharmony_ci	while ((de = readdir(dp)) != NULL) {
1296881f68fSopenharmony_ci		struct stat st;
1306881f68fSopenharmony_ci		memset(&st, 0, sizeof(st));
1316881f68fSopenharmony_ci		st.st_ino = de->d_ino;
1326881f68fSopenharmony_ci		st.st_mode = de->d_type << 12;
1336881f68fSopenharmony_ci		if (filler(buf, de->d_name, &st, 0, fill_dir_plus))
1346881f68fSopenharmony_ci			break;
1356881f68fSopenharmony_ci	}
1366881f68fSopenharmony_ci
1376881f68fSopenharmony_ci	closedir(dp);
1386881f68fSopenharmony_ci	return 0;
1396881f68fSopenharmony_ci}
1406881f68fSopenharmony_ci
1416881f68fSopenharmony_cistatic int xmp_mknod(const char *path, mode_t mode, dev_t rdev)
1426881f68fSopenharmony_ci{
1436881f68fSopenharmony_ci	int res;
1446881f68fSopenharmony_ci
1456881f68fSopenharmony_ci	res = mknod_wrapper(AT_FDCWD, path, NULL, mode, rdev);
1466881f68fSopenharmony_ci	if (res == -1)
1476881f68fSopenharmony_ci		return -errno;
1486881f68fSopenharmony_ci
1496881f68fSopenharmony_ci	return 0;
1506881f68fSopenharmony_ci}
1516881f68fSopenharmony_ci
1526881f68fSopenharmony_cistatic int xmp_mkdir(const char *path, mode_t mode)
1536881f68fSopenharmony_ci{
1546881f68fSopenharmony_ci	int res;
1556881f68fSopenharmony_ci
1566881f68fSopenharmony_ci	res = mkdir(path, mode);
1576881f68fSopenharmony_ci	if (res == -1)
1586881f68fSopenharmony_ci		return -errno;
1596881f68fSopenharmony_ci
1606881f68fSopenharmony_ci	return 0;
1616881f68fSopenharmony_ci}
1626881f68fSopenharmony_ci
1636881f68fSopenharmony_cistatic int xmp_unlink(const char *path)
1646881f68fSopenharmony_ci{
1656881f68fSopenharmony_ci	int res;
1666881f68fSopenharmony_ci
1676881f68fSopenharmony_ci	res = unlink(path);
1686881f68fSopenharmony_ci	if (res == -1)
1696881f68fSopenharmony_ci		return -errno;
1706881f68fSopenharmony_ci
1716881f68fSopenharmony_ci	return 0;
1726881f68fSopenharmony_ci}
1736881f68fSopenharmony_ci
1746881f68fSopenharmony_cistatic int xmp_rmdir(const char *path)
1756881f68fSopenharmony_ci{
1766881f68fSopenharmony_ci	int res;
1776881f68fSopenharmony_ci
1786881f68fSopenharmony_ci	res = rmdir(path);
1796881f68fSopenharmony_ci	if (res == -1)
1806881f68fSopenharmony_ci		return -errno;
1816881f68fSopenharmony_ci
1826881f68fSopenharmony_ci	return 0;
1836881f68fSopenharmony_ci}
1846881f68fSopenharmony_ci
1856881f68fSopenharmony_cistatic int xmp_symlink(const char *from, const char *to)
1866881f68fSopenharmony_ci{
1876881f68fSopenharmony_ci	int res;
1886881f68fSopenharmony_ci
1896881f68fSopenharmony_ci	res = symlink(from, to);
1906881f68fSopenharmony_ci	if (res == -1)
1916881f68fSopenharmony_ci		return -errno;
1926881f68fSopenharmony_ci
1936881f68fSopenharmony_ci	return 0;
1946881f68fSopenharmony_ci}
1956881f68fSopenharmony_ci
1966881f68fSopenharmony_cistatic int xmp_rename(const char *from, const char *to, unsigned int flags)
1976881f68fSopenharmony_ci{
1986881f68fSopenharmony_ci	int res;
1996881f68fSopenharmony_ci
2006881f68fSopenharmony_ci	if (flags)
2016881f68fSopenharmony_ci		return -EINVAL;
2026881f68fSopenharmony_ci
2036881f68fSopenharmony_ci	res = rename(from, to);
2046881f68fSopenharmony_ci	if (res == -1)
2056881f68fSopenharmony_ci		return -errno;
2066881f68fSopenharmony_ci
2076881f68fSopenharmony_ci	return 0;
2086881f68fSopenharmony_ci}
2096881f68fSopenharmony_ci
2106881f68fSopenharmony_cistatic int xmp_link(const char *from, const char *to)
2116881f68fSopenharmony_ci{
2126881f68fSopenharmony_ci	int res;
2136881f68fSopenharmony_ci
2146881f68fSopenharmony_ci	res = link(from, to);
2156881f68fSopenharmony_ci	if (res == -1)
2166881f68fSopenharmony_ci		return -errno;
2176881f68fSopenharmony_ci
2186881f68fSopenharmony_ci	return 0;
2196881f68fSopenharmony_ci}
2206881f68fSopenharmony_ci
2216881f68fSopenharmony_cistatic int xmp_chmod(const char *path, mode_t mode,
2226881f68fSopenharmony_ci		     struct fuse_file_info *fi)
2236881f68fSopenharmony_ci{
2246881f68fSopenharmony_ci	(void) fi;
2256881f68fSopenharmony_ci	int res;
2266881f68fSopenharmony_ci
2276881f68fSopenharmony_ci	res = chmod(path, mode);
2286881f68fSopenharmony_ci	if (res == -1)
2296881f68fSopenharmony_ci		return -errno;
2306881f68fSopenharmony_ci
2316881f68fSopenharmony_ci	return 0;
2326881f68fSopenharmony_ci}
2336881f68fSopenharmony_ci
2346881f68fSopenharmony_cistatic int xmp_chown(const char *path, uid_t uid, gid_t gid,
2356881f68fSopenharmony_ci		     struct fuse_file_info *fi)
2366881f68fSopenharmony_ci{
2376881f68fSopenharmony_ci	(void) fi;
2386881f68fSopenharmony_ci	int res;
2396881f68fSopenharmony_ci
2406881f68fSopenharmony_ci	res = lchown(path, uid, gid);
2416881f68fSopenharmony_ci	if (res == -1)
2426881f68fSopenharmony_ci		return -errno;
2436881f68fSopenharmony_ci
2446881f68fSopenharmony_ci	return 0;
2456881f68fSopenharmony_ci}
2466881f68fSopenharmony_ci
2476881f68fSopenharmony_cistatic int xmp_truncate(const char *path, off_t size,
2486881f68fSopenharmony_ci			struct fuse_file_info *fi)
2496881f68fSopenharmony_ci{
2506881f68fSopenharmony_ci	int res;
2516881f68fSopenharmony_ci
2526881f68fSopenharmony_ci	if (fi != NULL)
2536881f68fSopenharmony_ci		res = ftruncate(fi->fh, size);
2546881f68fSopenharmony_ci	else
2556881f68fSopenharmony_ci		res = truncate(path, size);
2566881f68fSopenharmony_ci	if (res == -1)
2576881f68fSopenharmony_ci		return -errno;
2586881f68fSopenharmony_ci
2596881f68fSopenharmony_ci	return 0;
2606881f68fSopenharmony_ci}
2616881f68fSopenharmony_ci
2626881f68fSopenharmony_ci#ifdef HAVE_UTIMENSAT
2636881f68fSopenharmony_cistatic int xmp_utimens(const char *path, const struct timespec ts[2],
2646881f68fSopenharmony_ci		       struct fuse_file_info *fi)
2656881f68fSopenharmony_ci{
2666881f68fSopenharmony_ci	(void) fi;
2676881f68fSopenharmony_ci	int res;
2686881f68fSopenharmony_ci
2696881f68fSopenharmony_ci	/* don't use utime/utimes since they follow symlinks */
2706881f68fSopenharmony_ci	res = utimensat(0, path, ts, AT_SYMLINK_NOFOLLOW);
2716881f68fSopenharmony_ci	if (res == -1)
2726881f68fSopenharmony_ci		return -errno;
2736881f68fSopenharmony_ci
2746881f68fSopenharmony_ci	return 0;
2756881f68fSopenharmony_ci}
2766881f68fSopenharmony_ci#endif
2776881f68fSopenharmony_ci
2786881f68fSopenharmony_cistatic int xmp_create(const char *path, mode_t mode,
2796881f68fSopenharmony_ci		      struct fuse_file_info *fi)
2806881f68fSopenharmony_ci{
2816881f68fSopenharmony_ci	int res;
2826881f68fSopenharmony_ci
2836881f68fSopenharmony_ci	res = open(path, fi->flags, mode);
2846881f68fSopenharmony_ci	if (res == -1)
2856881f68fSopenharmony_ci		return -errno;
2866881f68fSopenharmony_ci
2876881f68fSopenharmony_ci	fi->fh = res;
2886881f68fSopenharmony_ci	return 0;
2896881f68fSopenharmony_ci}
2906881f68fSopenharmony_ci
2916881f68fSopenharmony_cistatic int xmp_open(const char *path, struct fuse_file_info *fi)
2926881f68fSopenharmony_ci{
2936881f68fSopenharmony_ci	int res;
2946881f68fSopenharmony_ci
2956881f68fSopenharmony_ci	res = open(path, fi->flags);
2966881f68fSopenharmony_ci	if (res == -1)
2976881f68fSopenharmony_ci		return -errno;
2986881f68fSopenharmony_ci
2996881f68fSopenharmony_ci	fi->fh = res;
3006881f68fSopenharmony_ci	return 0;
3016881f68fSopenharmony_ci}
3026881f68fSopenharmony_ci
3036881f68fSopenharmony_cistatic int xmp_read(const char *path, char *buf, size_t size, off_t offset,
3046881f68fSopenharmony_ci		    struct fuse_file_info *fi)
3056881f68fSopenharmony_ci{
3066881f68fSopenharmony_ci	int fd;
3076881f68fSopenharmony_ci	int res;
3086881f68fSopenharmony_ci
3096881f68fSopenharmony_ci	if(fi == NULL)
3106881f68fSopenharmony_ci		fd = open(path, O_RDONLY);
3116881f68fSopenharmony_ci	else
3126881f68fSopenharmony_ci		fd = fi->fh;
3136881f68fSopenharmony_ci
3146881f68fSopenharmony_ci	if (fd == -1)
3156881f68fSopenharmony_ci		return -errno;
3166881f68fSopenharmony_ci
3176881f68fSopenharmony_ci	res = pread(fd, buf, size, offset);
3186881f68fSopenharmony_ci	if (res == -1)
3196881f68fSopenharmony_ci		res = -errno;
3206881f68fSopenharmony_ci
3216881f68fSopenharmony_ci	if(fi == NULL)
3226881f68fSopenharmony_ci		close(fd);
3236881f68fSopenharmony_ci	return res;
3246881f68fSopenharmony_ci}
3256881f68fSopenharmony_ci
3266881f68fSopenharmony_cistatic int xmp_write(const char *path, const char *buf, size_t size,
3276881f68fSopenharmony_ci		     off_t offset, struct fuse_file_info *fi)
3286881f68fSopenharmony_ci{
3296881f68fSopenharmony_ci	int fd;
3306881f68fSopenharmony_ci	int res;
3316881f68fSopenharmony_ci
3326881f68fSopenharmony_ci	(void) fi;
3336881f68fSopenharmony_ci	if(fi == NULL)
3346881f68fSopenharmony_ci		fd = open(path, O_WRONLY);
3356881f68fSopenharmony_ci	else
3366881f68fSopenharmony_ci		fd = fi->fh;
3376881f68fSopenharmony_ci
3386881f68fSopenharmony_ci	if (fd == -1)
3396881f68fSopenharmony_ci		return -errno;
3406881f68fSopenharmony_ci
3416881f68fSopenharmony_ci	res = pwrite(fd, buf, size, offset);
3426881f68fSopenharmony_ci	if (res == -1)
3436881f68fSopenharmony_ci		res = -errno;
3446881f68fSopenharmony_ci
3456881f68fSopenharmony_ci	if(fi == NULL)
3466881f68fSopenharmony_ci		close(fd);
3476881f68fSopenharmony_ci	return res;
3486881f68fSopenharmony_ci}
3496881f68fSopenharmony_ci
3506881f68fSopenharmony_cistatic int xmp_statfs(const char *path, struct statvfs *stbuf)
3516881f68fSopenharmony_ci{
3526881f68fSopenharmony_ci	int res;
3536881f68fSopenharmony_ci
3546881f68fSopenharmony_ci	res = statvfs(path, stbuf);
3556881f68fSopenharmony_ci	if (res == -1)
3566881f68fSopenharmony_ci		return -errno;
3576881f68fSopenharmony_ci
3586881f68fSopenharmony_ci	return 0;
3596881f68fSopenharmony_ci}
3606881f68fSopenharmony_ci
3616881f68fSopenharmony_cistatic int xmp_release(const char *path, struct fuse_file_info *fi)
3626881f68fSopenharmony_ci{
3636881f68fSopenharmony_ci	(void) path;
3646881f68fSopenharmony_ci	close(fi->fh);
3656881f68fSopenharmony_ci	return 0;
3666881f68fSopenharmony_ci}
3676881f68fSopenharmony_ci
3686881f68fSopenharmony_cistatic int xmp_fsync(const char *path, int isdatasync,
3696881f68fSopenharmony_ci		     struct fuse_file_info *fi)
3706881f68fSopenharmony_ci{
3716881f68fSopenharmony_ci	/* Just a stub.	 This method is optional and can safely be left
3726881f68fSopenharmony_ci	   unimplemented */
3736881f68fSopenharmony_ci
3746881f68fSopenharmony_ci	(void) path;
3756881f68fSopenharmony_ci	(void) isdatasync;
3766881f68fSopenharmony_ci	(void) fi;
3776881f68fSopenharmony_ci	return 0;
3786881f68fSopenharmony_ci}
3796881f68fSopenharmony_ci
3806881f68fSopenharmony_ci#ifdef HAVE_POSIX_FALLOCATE
3816881f68fSopenharmony_cistatic int xmp_fallocate(const char *path, int mode,
3826881f68fSopenharmony_ci			off_t offset, off_t length, struct fuse_file_info *fi)
3836881f68fSopenharmony_ci{
3846881f68fSopenharmony_ci	int fd;
3856881f68fSopenharmony_ci	int res;
3866881f68fSopenharmony_ci
3876881f68fSopenharmony_ci	(void) fi;
3886881f68fSopenharmony_ci
3896881f68fSopenharmony_ci	if (mode)
3906881f68fSopenharmony_ci		return -EOPNOTSUPP;
3916881f68fSopenharmony_ci
3926881f68fSopenharmony_ci	if(fi == NULL)
3936881f68fSopenharmony_ci		fd = open(path, O_WRONLY);
3946881f68fSopenharmony_ci	else
3956881f68fSopenharmony_ci		fd = fi->fh;
3966881f68fSopenharmony_ci
3976881f68fSopenharmony_ci	if (fd == -1)
3986881f68fSopenharmony_ci		return -errno;
3996881f68fSopenharmony_ci
4006881f68fSopenharmony_ci	res = -posix_fallocate(fd, offset, length);
4016881f68fSopenharmony_ci
4026881f68fSopenharmony_ci	if(fi == NULL)
4036881f68fSopenharmony_ci		close(fd);
4046881f68fSopenharmony_ci	return res;
4056881f68fSopenharmony_ci}
4066881f68fSopenharmony_ci#endif
4076881f68fSopenharmony_ci
4086881f68fSopenharmony_ci#ifdef HAVE_SETXATTR
4096881f68fSopenharmony_ci/* xattr operations are optional and can safely be left unimplemented */
4106881f68fSopenharmony_cistatic int xmp_setxattr(const char *path, const char *name, const char *value,
4116881f68fSopenharmony_ci			size_t size, int flags)
4126881f68fSopenharmony_ci{
4136881f68fSopenharmony_ci	int res = lsetxattr(path, name, value, size, flags);
4146881f68fSopenharmony_ci	if (res == -1)
4156881f68fSopenharmony_ci		return -errno;
4166881f68fSopenharmony_ci	return 0;
4176881f68fSopenharmony_ci}
4186881f68fSopenharmony_ci
4196881f68fSopenharmony_cistatic int xmp_getxattr(const char *path, const char *name, char *value,
4206881f68fSopenharmony_ci			size_t size)
4216881f68fSopenharmony_ci{
4226881f68fSopenharmony_ci	int res = lgetxattr(path, name, value, size);
4236881f68fSopenharmony_ci	if (res == -1)
4246881f68fSopenharmony_ci		return -errno;
4256881f68fSopenharmony_ci	return res;
4266881f68fSopenharmony_ci}
4276881f68fSopenharmony_ci
4286881f68fSopenharmony_cistatic int xmp_listxattr(const char *path, char *list, size_t size)
4296881f68fSopenharmony_ci{
4306881f68fSopenharmony_ci	int res = llistxattr(path, list, size);
4316881f68fSopenharmony_ci	if (res == -1)
4326881f68fSopenharmony_ci		return -errno;
4336881f68fSopenharmony_ci	return res;
4346881f68fSopenharmony_ci}
4356881f68fSopenharmony_ci
4366881f68fSopenharmony_cistatic int xmp_removexattr(const char *path, const char *name)
4376881f68fSopenharmony_ci{
4386881f68fSopenharmony_ci	int res = lremovexattr(path, name);
4396881f68fSopenharmony_ci	if (res == -1)
4406881f68fSopenharmony_ci		return -errno;
4416881f68fSopenharmony_ci	return 0;
4426881f68fSopenharmony_ci}
4436881f68fSopenharmony_ci#endif /* HAVE_SETXATTR */
4446881f68fSopenharmony_ci
4456881f68fSopenharmony_ci#ifdef HAVE_COPY_FILE_RANGE
4466881f68fSopenharmony_cistatic ssize_t xmp_copy_file_range(const char *path_in,
4476881f68fSopenharmony_ci				   struct fuse_file_info *fi_in,
4486881f68fSopenharmony_ci				   off_t offset_in, const char *path_out,
4496881f68fSopenharmony_ci				   struct fuse_file_info *fi_out,
4506881f68fSopenharmony_ci				   off_t offset_out, size_t len, int flags)
4516881f68fSopenharmony_ci{
4526881f68fSopenharmony_ci	int fd_in, fd_out;
4536881f68fSopenharmony_ci	ssize_t res;
4546881f68fSopenharmony_ci
4556881f68fSopenharmony_ci	if(fi_in == NULL)
4566881f68fSopenharmony_ci		fd_in = open(path_in, O_RDONLY);
4576881f68fSopenharmony_ci	else
4586881f68fSopenharmony_ci		fd_in = fi_in->fh;
4596881f68fSopenharmony_ci
4606881f68fSopenharmony_ci	if (fd_in == -1)
4616881f68fSopenharmony_ci		return -errno;
4626881f68fSopenharmony_ci
4636881f68fSopenharmony_ci	if(fi_out == NULL)
4646881f68fSopenharmony_ci		fd_out = open(path_out, O_WRONLY);
4656881f68fSopenharmony_ci	else
4666881f68fSopenharmony_ci		fd_out = fi_out->fh;
4676881f68fSopenharmony_ci
4686881f68fSopenharmony_ci	if (fd_out == -1) {
4696881f68fSopenharmony_ci		close(fd_in);
4706881f68fSopenharmony_ci		return -errno;
4716881f68fSopenharmony_ci	}
4726881f68fSopenharmony_ci
4736881f68fSopenharmony_ci	res = copy_file_range(fd_in, &offset_in, fd_out, &offset_out, len,
4746881f68fSopenharmony_ci			      flags);
4756881f68fSopenharmony_ci	if (res == -1)
4766881f68fSopenharmony_ci		res = -errno;
4776881f68fSopenharmony_ci
4786881f68fSopenharmony_ci	if (fi_out == NULL)
4796881f68fSopenharmony_ci		close(fd_out);
4806881f68fSopenharmony_ci	if (fi_in == NULL)
4816881f68fSopenharmony_ci		close(fd_in);
4826881f68fSopenharmony_ci
4836881f68fSopenharmony_ci	return res;
4846881f68fSopenharmony_ci}
4856881f68fSopenharmony_ci#endif
4866881f68fSopenharmony_ci
4876881f68fSopenharmony_cistatic off_t xmp_lseek(const char *path, off_t off, int whence, struct fuse_file_info *fi)
4886881f68fSopenharmony_ci{
4896881f68fSopenharmony_ci	int fd;
4906881f68fSopenharmony_ci	off_t res;
4916881f68fSopenharmony_ci
4926881f68fSopenharmony_ci	if (fi == NULL)
4936881f68fSopenharmony_ci		fd = open(path, O_RDONLY);
4946881f68fSopenharmony_ci	else
4956881f68fSopenharmony_ci		fd = fi->fh;
4966881f68fSopenharmony_ci
4976881f68fSopenharmony_ci	if (fd == -1)
4986881f68fSopenharmony_ci		return -errno;
4996881f68fSopenharmony_ci
5006881f68fSopenharmony_ci	res = lseek(fd, off, whence);
5016881f68fSopenharmony_ci	if (res == -1)
5026881f68fSopenharmony_ci		res = -errno;
5036881f68fSopenharmony_ci
5046881f68fSopenharmony_ci	if (fi == NULL)
5056881f68fSopenharmony_ci		close(fd);
5066881f68fSopenharmony_ci	return res;
5076881f68fSopenharmony_ci}
5086881f68fSopenharmony_ci
5096881f68fSopenharmony_cistatic const struct fuse_operations xmp_oper = {
5106881f68fSopenharmony_ci	.init           = xmp_init,
5116881f68fSopenharmony_ci	.getattr	= xmp_getattr,
5126881f68fSopenharmony_ci	.access		= xmp_access,
5136881f68fSopenharmony_ci	.readlink	= xmp_readlink,
5146881f68fSopenharmony_ci	.readdir	= xmp_readdir,
5156881f68fSopenharmony_ci	.mknod		= xmp_mknod,
5166881f68fSopenharmony_ci	.mkdir		= xmp_mkdir,
5176881f68fSopenharmony_ci	.symlink	= xmp_symlink,
5186881f68fSopenharmony_ci	.unlink		= xmp_unlink,
5196881f68fSopenharmony_ci	.rmdir		= xmp_rmdir,
5206881f68fSopenharmony_ci	.rename		= xmp_rename,
5216881f68fSopenharmony_ci	.link		= xmp_link,
5226881f68fSopenharmony_ci	.chmod		= xmp_chmod,
5236881f68fSopenharmony_ci	.chown		= xmp_chown,
5246881f68fSopenharmony_ci	.truncate	= xmp_truncate,
5256881f68fSopenharmony_ci#ifdef HAVE_UTIMENSAT
5266881f68fSopenharmony_ci	.utimens	= xmp_utimens,
5276881f68fSopenharmony_ci#endif
5286881f68fSopenharmony_ci	.open		= xmp_open,
5296881f68fSopenharmony_ci	.create 	= xmp_create,
5306881f68fSopenharmony_ci	.read		= xmp_read,
5316881f68fSopenharmony_ci	.write		= xmp_write,
5326881f68fSopenharmony_ci	.statfs		= xmp_statfs,
5336881f68fSopenharmony_ci	.release	= xmp_release,
5346881f68fSopenharmony_ci	.fsync		= xmp_fsync,
5356881f68fSopenharmony_ci#ifdef HAVE_POSIX_FALLOCATE
5366881f68fSopenharmony_ci	.fallocate	= xmp_fallocate,
5376881f68fSopenharmony_ci#endif
5386881f68fSopenharmony_ci#ifdef HAVE_SETXATTR
5396881f68fSopenharmony_ci	.setxattr	= xmp_setxattr,
5406881f68fSopenharmony_ci	.getxattr	= xmp_getxattr,
5416881f68fSopenharmony_ci	.listxattr	= xmp_listxattr,
5426881f68fSopenharmony_ci	.removexattr	= xmp_removexattr,
5436881f68fSopenharmony_ci#endif
5446881f68fSopenharmony_ci#ifdef HAVE_COPY_FILE_RANGE
5456881f68fSopenharmony_ci	.copy_file_range = xmp_copy_file_range,
5466881f68fSopenharmony_ci#endif
5476881f68fSopenharmony_ci	.lseek		= xmp_lseek,
5486881f68fSopenharmony_ci};
5496881f68fSopenharmony_ci
5506881f68fSopenharmony_ciint main(int argc, char *argv[])
5516881f68fSopenharmony_ci{
5526881f68fSopenharmony_ci	enum { MAX_ARGS = 10 };
5536881f68fSopenharmony_ci	int i,new_argc;
5546881f68fSopenharmony_ci	char *new_argv[MAX_ARGS];
5556881f68fSopenharmony_ci
5566881f68fSopenharmony_ci	umask(0);
5576881f68fSopenharmony_ci			/* Process the "--plus" option apart */
5586881f68fSopenharmony_ci	for (i=0, new_argc=0; (i<argc) && (new_argc<MAX_ARGS); i++) {
5596881f68fSopenharmony_ci		if (!strcmp(argv[i], "--plus")) {
5606881f68fSopenharmony_ci			fill_dir_plus = FUSE_FILL_DIR_PLUS;
5616881f68fSopenharmony_ci		} else {
5626881f68fSopenharmony_ci			new_argv[new_argc++] = argv[i];
5636881f68fSopenharmony_ci		}
5646881f68fSopenharmony_ci	}
5656881f68fSopenharmony_ci	return fuse_main(new_argc, new_argv, &xmp_oper, NULL);
5666881f68fSopenharmony_ci}
567