This file system mirrors the existing file system hierarchy of the system, starting at the root file system. This is implemented by just "passing through" all requests to the corresponding user-space libc functions. This implementation is a little more sophisticated than the one in passthrough.c, so performance is not quite as bad.
#define FUSE_USE_VERSION 31
#define _GNU_SOURCE
#ifdef HAVE_LIBULOCKMGR
#include <ulockmgr.h>
#endif
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/stat.h>
#include <dirent.h>
#include <errno.h>
#include <sys/time.h>
#ifdef HAVE_SETXATTR
#include <sys/xattr.h>
#endif
#include <sys/file.h>
{
(void) conn;
return NULL;
}
static int xmp_getattr(const char *path, struct stat *stbuf,
{
int res;
(void) path;
if(fi)
res = fstat(fi->
fh, stbuf);
else
res = lstat(path, stbuf);
if (res == -1)
return -errno;
return 0;
}
static int xmp_access(const char *path, int mask)
{
int res;
res = access(path, mask);
if (res == -1)
return -errno;
return 0;
}
static int xmp_readlink(const char *path, char *buf, size_t size)
{
int res;
res = readlink(path, buf, size - 1);
if (res == -1)
return -errno;
buf[res] = '\0';
return 0;
}
struct xmp_dirp {
DIR *dp;
struct dirent *entry;
off_t offset;
};
{
int res;
struct xmp_dirp *d = malloc(sizeof(struct xmp_dirp));
if (d == NULL)
return -ENOMEM;
d->dp = opendir(path);
if (d->dp == NULL) {
res = -errno;
free(d);
return res;
}
d->offset = 0;
d->entry = NULL;
fi->
fh = (
unsigned long) d;
return 0;
}
{
return (
struct xmp_dirp *) (uintptr_t) fi->
fh;
}
static int xmp_readdir(
const char *path,
void *buf,
fuse_fill_dir_t filler,
{
struct xmp_dirp *d = get_dirp(fi);
(void) path;
if (offset != d->offset) {
#ifndef __FreeBSD__
seekdir(d->dp, offset);
#else
seekdir(d->dp, offset-1);
#endif
d->entry = NULL;
d->offset = offset;
}
while (1) {
struct stat st;
off_t nextoff;
if (!d->entry) {
d->entry = readdir(d->dp);
if (!d->entry)
break;
}
#ifdef HAVE_FSTATAT
int res;
res = fstatat(dirfd(d->dp), d->entry->d_name, &st,
AT_SYMLINK_NOFOLLOW);
if (res != -1)
}
#endif
memset(&st, 0, sizeof(st));
st.st_ino = d->entry->d_ino;
st.st_mode = d->entry->d_type << 12;
}
nextoff = telldir(d->dp);
#ifdef __FreeBSD__
nextoff++;
#endif
if (filler(buf, d->entry->d_name, &st, nextoff, fill_flags))
break;
d->entry = NULL;
d->offset = nextoff;
}
return 0;
}
static int xmp_releasedir(
const char *path,
struct fuse_file_info *fi)
{
struct xmp_dirp *d = get_dirp(fi);
(void) path;
closedir(d->dp);
free(d);
return 0;
}
static int xmp_mknod(const char *path, mode_t mode, dev_t rdev)
{
int res;
if (S_ISFIFO(mode))
res = mkfifo(path, mode);
else
res = mknod(path, mode, rdev);
if (res == -1)
return -errno;
return 0;
}
static int xmp_mkdir(const char *path, mode_t mode)
{
int res;
res = mkdir(path, mode);
if (res == -1)
return -errno;
return 0;
}
static int xmp_unlink(const char *path)
{
int res;
res = unlink(path);
if (res == -1)
return -errno;
return 0;
}
static int xmp_rmdir(const char *path)
{
int res;
res = rmdir(path);
if (res == -1)
return -errno;
return 0;
}
static int xmp_symlink(const char *from, const char *to)
{
int res;
res = symlink(from, to);
if (res == -1)
return -errno;
return 0;
}
static int xmp_rename(const char *from, const char *to, unsigned int flags)
{
int res;
if (flags)
return -EINVAL;
res = rename(from, to);
if (res == -1)
return -errno;
return 0;
}
static int xmp_link(const char *from, const char *to)
{
int res;
res = link(from, to);
if (res == -1)
return -errno;
return 0;
}
static int xmp_chmod(const char *path, mode_t mode,
{
int res;
if(fi)
res = fchmod(fi->
fh, mode);
else
res = chmod(path, mode);
if (res == -1)
return -errno;
return 0;
}
static int xmp_chown(const char *path, uid_t uid, gid_t gid,
{
int res;
if (fi)
res = fchown(fi->
fh, uid, gid);
else
res = lchown(path, uid, gid);
if (res == -1)
return -errno;
return 0;
}
static int xmp_truncate(const char *path, off_t size,
{
int res;
if(fi)
res = ftruncate(fi->
fh, size);
else
res = truncate(path, size);
if (res == -1)
return -errno;
return 0;
}
#ifdef HAVE_UTIMENSAT
static int xmp_utimens(const char *path, const struct timespec ts[2],
{
int res;
if (fi)
res = futimens(fi->
fh, ts);
else
res = utimensat(0, path, ts, AT_SYMLINK_NOFOLLOW);
if (res == -1)
return -errno;
return 0;
}
#endif
static int xmp_create(
const char *path, mode_t mode,
struct fuse_file_info *fi)
{
int fd;
fd = open(path, fi->
flags, mode);
if (fd == -1)
return -errno;
return 0;
}
{
int fd;
fd = open(path, fi->
flags);
if (fd == -1)
return -errno;
return 0;
}
static int xmp_read(const char *path, char *buf, size_t size, off_t offset,
{
int res;
(void) path;
res = pread(fi->
fh, buf, size, offset);
if (res == -1)
res = -errno;
return res;
}
static int xmp_read_buf(
const char *path,
struct fuse_bufvec **bufp,
{
(void) path;
if (src == NULL)
return -ENOMEM;
*src = FUSE_BUFVEC_INIT(size);
*bufp = src;
return 0;
}
static int xmp_write(
const char *path,
const char *
buf,
size_t size,
{
int res;
(void) path;
res = pwrite(fi->
fh,
buf, size, offset);
if (res == -1)
res = -errno;
return res;
}
{
(void) path;
}
static int xmp_statfs(const char *path, struct statvfs *stbuf)
{
int res;
res = statvfs(path, stbuf);
if (res == -1)
return -errno;
return 0;
}
{
int res;
(void) path;
res = close(dup(fi->
fh));
if (res == -1)
return -errno;
return 0;
}
{
(void) path;
return 0;
}
static int xmp_fsync(const char *path, int isdatasync,
{
int res;
(void) path;
#ifndef HAVE_FDATASYNC
(void) isdatasync;
#else
if (isdatasync)
else
#endif
if (res == -1)
return -errno;
return 0;
}
#ifdef HAVE_POSIX_FALLOCATE
static int xmp_fallocate(const char *path, int mode,
{
(void) path;
if (mode)
return -EOPNOTSUPP;
return -posix_fallocate(fi->
fh, offset, length);
}
#endif
#ifdef HAVE_SETXATTR
static int xmp_setxattr(const char *path, const char *name, const char *value,
size_t size, int flags)
{
int res = lsetxattr(path, name, value, size, flags);
if (res == -1)
return -errno;
return 0;
}
static int xmp_getxattr(const char *path, const char *name, char *value,
size_t size)
{
int res = lgetxattr(path, name, value, size);
if (res == -1)
return -errno;
return res;
}
static int xmp_listxattr(const char *path, char *list, size_t size)
{
int res = llistxattr(path, list, size);
if (res == -1)
return -errno;
return res;
}
static int xmp_removexattr(const char *path, const char *name)
{
int res = lremovexattr(path, name);
if (res == -1)
return -errno;
return 0;
}
#endif
#ifdef HAVE_LIBULOCKMGR
static int xmp_lock(
const char *path,
struct fuse_file_info *fi,
int cmd,
struct flock *lock)
{
(void) path;
}
#endif
static int xmp_flock(
const char *path,
struct fuse_file_info *fi,
int op)
{
int res;
(void) path;
if (res == -1)
return -errno;
return 0;
}
#ifdef HAVE_COPY_FILE_RANGE
static ssize_t xmp_copy_file_range(const char *path_in,
off_t off_in, const char *path_out,
off_t off_out, size_t len, int flags)
{
ssize_t res;
(void) path_in;
(void) path_out;
res = copy_file_range(fi_in->
fh, &off_in, fi_out->
fh, &off_out, len,
flags);
if (res == -1)
return -errno;
return res;
}
#endif
static off_t xmp_lseek(
const char *path, off_t
off,
int whence,
struct fuse_file_info *fi)
{
off_t res;
(void) path;
res = lseek(fi->
fh,
off, whence);
if (res == -1)
return -errno;
return res;
}
.getattr = xmp_getattr,
.access = xmp_access,
.readlink = xmp_readlink,
.opendir = xmp_opendir,
.readdir = xmp_readdir,
.releasedir = xmp_releasedir,
.mknod = xmp_mknod,
.mkdir = xmp_mkdir,
.symlink = xmp_symlink,
.unlink = xmp_unlink,
.rmdir = xmp_rmdir,
.rename = xmp_rename,
.link = xmp_link,
.chmod = xmp_chmod,
.chown = xmp_chown,
.truncate = xmp_truncate,
#ifdef HAVE_UTIMENSAT
.utimens = xmp_utimens,
#endif
.create = xmp_create,
.open = xmp_open,
.read = xmp_read,
.read_buf = xmp_read_buf,
.write = xmp_write,
.write_buf = xmp_write_buf,
.statfs = xmp_statfs,
.flush = xmp_flush,
.release = xmp_release,
.fsync = xmp_fsync,
#ifdef HAVE_POSIX_FALLOCATE
.fallocate = xmp_fallocate,
#endif
#ifdef HAVE_SETXATTR
.setxattr = xmp_setxattr,
.getxattr = xmp_getxattr,
.listxattr = xmp_listxattr,
.removexattr = xmp_removexattr,
#endif
#ifdef HAVE_LIBULOCKMGR
.lock = xmp_lock,
#endif
.flock = xmp_flock,
#ifdef HAVE_COPY_FILE_RANGE
.copy_file_range = xmp_copy_file_range,
#endif
.lseek = xmp_lseek,
};
int main(int argc, char *argv[])
{
umask(0);
return fuse_main(argc, argv, &xmp_oper, NULL);
}
int(* fuse_fill_dir_t)(void *buf, const char *name, const struct stat *stbuf, off_t off, enum fuse_fill_dir_flags flags)
#define fuse_main(argc, argv, op, private_data)
size_t fuse_buf_size(const struct fuse_bufvec *bufv)
ssize_t fuse_buf_copy(struct fuse_bufvec *dst, struct fuse_bufvec *src, enum fuse_buf_copy_flags flags)
@ FUSE_BUF_SPLICE_NONBLOCK
enum fuse_buf_flags flags
void *(* init)(struct fuse_conn_info *conn, struct fuse_config *cfg)