Resolved merge conflict in favor of basic-passthrough
				
					
				
			This commit is contained in:
		
							
								
								
									
										674
									
								
								sources/main.c
									
									
									
									
									
								
							
							
						
						
									
										674
									
								
								sources/main.c
									
									
									
									
									
								
							@@ -1,47 +1,671 @@
 | 
			
		||||
#include <stdlib.h>
 | 
			
		||||
/*
 | 
			
		||||
  FUSE: Filesystem in Userspace
 | 
			
		||||
  Copyright (C) 2001-2007  Miklos Szeredi <miklos@szeredi.hu>
 | 
			
		||||
  Copyright (C) 2011       Sebastian Pipping <sebastian@pipping.org>
 | 
			
		||||
 | 
			
		||||
  This program can be distributed under the terms of the GNU GPLv2.
 | 
			
		||||
  See the file COPYING.
 | 
			
		||||
*/
 | 
			
		||||
 | 
			
		||||
/** @file
 | 
			
		||||
 *
 | 
			
		||||
 * 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.
 | 
			
		||||
 *
 | 
			
		||||
 * Compile with:
 | 
			
		||||
 *
 | 
			
		||||
 *     gcc -Wall passthrough_fh.c `pkg-config fuse3 --cflags --libs` -lulockmgr
 | 
			
		||||
 * -o passthrough_fh
 | 
			
		||||
 *
 | 
			
		||||
 * ## Source code ##
 | 
			
		||||
 * \include passthrough_fh.c
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#define FUSE_USE_VERSION 31
 | 
			
		||||
 | 
			
		||||
#include "sourcefs.h"
 | 
			
		||||
#define _GNU_SOURCE
 | 
			
		||||
 | 
			
		||||
#include <fuse3/fuse.h>
 | 
			
		||||
 | 
			
		||||
const char *mountpoint;
 | 
			
		||||
#ifdef HAVE_LIBULOCKMGR
 | 
			
		||||
#include <ulockmgr.h>
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * #In this function we need to:
 | 
			
		||||
 *
 | 
			
		||||
 * * Open the folder we are mounting over (and remember it).
 | 
			
		||||
 * * Initialize the process table.
 | 
			
		||||
 */
 | 
			
		||||
static void *icfs_init(struct fuse_conn_info *conn, struct fuse_config *cfg) {
 | 
			
		||||
  (void)conn; /* Explicit way to tell we ignore these arguments. */
 | 
			
		||||
  (void)cfg;  /* This also silences the compiler warnings. */
 | 
			
		||||
#include <dirent.h>
 | 
			
		||||
#include <errno.h>
 | 
			
		||||
#include <fcntl.h>
 | 
			
		||||
#include <stdio.h>
 | 
			
		||||
#include <stdlib.h>
 | 
			
		||||
#include <string.h>
 | 
			
		||||
#include <sys/stat.h>
 | 
			
		||||
#include <sys/time.h>
 | 
			
		||||
#include <unistd.h>
 | 
			
		||||
#ifdef HAVE_SETXATTR
 | 
			
		||||
#include <sys/xattr.h>
 | 
			
		||||
#endif
 | 
			
		||||
#include <sys/file.h> /* flock(2) */
 | 
			
		||||
 | 
			
		||||
#include "sourcefs.h"
 | 
			
		||||
 | 
			
		||||
const char *mountpoint = NULL;
 | 
			
		||||
 | 
			
		||||
static void *xmp_init(struct fuse_conn_info *conn, struct fuse_config *cfg) {
 | 
			
		||||
  (void)conn;
 | 
			
		||||
  cfg->use_ino = 1;
 | 
			
		||||
  cfg->nullpath_ok = 1;
 | 
			
		||||
 | 
			
		||||
  /* parallel_direct_writes feature depends on direct_io features.
 | 
			
		||||
     To make parallel_direct_writes valid, need either set cfg->direct_io
 | 
			
		||||
     in current function (recommended in high level API) or set fi->direct_io
 | 
			
		||||
     in xmp_create() or xmp_open(). */
 | 
			
		||||
  // cfg->direct_io = 1;
 | 
			
		||||
  // cfg->parallel_direct_writes = 1;
 | 
			
		||||
 | 
			
		||||
  /* Pick up changes from lower filesystem right away. This is
 | 
			
		||||
     also necessary for better hardlink support. When the kernel
 | 
			
		||||
     calls the unlink() handler, it does not know the inode of
 | 
			
		||||
     the to-be-removed entry and can therefore not invalidate
 | 
			
		||||
     the cache of the associated inode - resulting in an
 | 
			
		||||
     incorrect st_nlink value being reported for any remaining
 | 
			
		||||
     hardlinks to this inode. */
 | 
			
		||||
  cfg->entry_timeout = 0;
 | 
			
		||||
  cfg->attr_timeout = 0;
 | 
			
		||||
  cfg->negative_timeout = 0;
 | 
			
		||||
 | 
			
		||||
  source_init(mountpoint);
 | 
			
		||||
  return NULL;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int icfs_getattr(const char *path, struct stat *stbuf,
 | 
			
		||||
                        struct fuse_file_info *fi) {
 | 
			
		||||
static int xmp_getattr(const char *path, struct stat *stbuf,
 | 
			
		||||
                       struct fuse_file_info *fi) {
 | 
			
		||||
  int res;
 | 
			
		||||
 | 
			
		||||
  int statret = source_stat(path, stbuf);
 | 
			
		||||
  (void)path;
 | 
			
		||||
 | 
			
		||||
  return statret;
 | 
			
		||||
  if (fi)
 | 
			
		||||
    res = fstat(fi->fh, stbuf);
 | 
			
		||||
  else
 | 
			
		||||
    res = source_stat(path, stbuf);
 | 
			
		||||
  if (res == -1) {
 | 
			
		||||
    perror("Stat failed");
 | 
			
		||||
    return -errno;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static const struct fuse_operations icfs_oper = {
 | 
			
		||||
    .init = icfs_init,
 | 
			
		||||
    .getattr = icfs_getattr,
 | 
			
		||||
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;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
static int xmp_opendir(const char *path, struct fuse_file_info *fi) {
 | 
			
		||||
  int res;
 | 
			
		||||
  struct xmp_dirp *d = malloc(sizeof(struct xmp_dirp));
 | 
			
		||||
  if (d == NULL)
 | 
			
		||||
    return -ENOMEM;
 | 
			
		||||
 | 
			
		||||
  d->dp = source_opendir(path);
 | 
			
		||||
  if (d->dp == NULL) {
 | 
			
		||||
    perror("Opendir failed");
 | 
			
		||||
    res = -errno;
 | 
			
		||||
    free(d);
 | 
			
		||||
    return res;
 | 
			
		||||
  }
 | 
			
		||||
  d->offset = 0;
 | 
			
		||||
  d->entry = NULL;
 | 
			
		||||
 | 
			
		||||
  fi->fh = (unsigned long)d;
 | 
			
		||||
  return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static inline struct xmp_dirp *get_dirp(struct fuse_file_info *fi) {
 | 
			
		||||
  return (struct xmp_dirp *)(uintptr_t)fi->fh;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* Complete copy of the example method(no need to modify anything so far) */
 | 
			
		||||
static int xmp_readdir(const char *path, void *buf, fuse_fill_dir_t filler,
 | 
			
		||||
                       off_t offset, struct fuse_file_info *fi,
 | 
			
		||||
                       enum fuse_readdir_flags flags) {
 | 
			
		||||
  struct xmp_dirp *d = get_dirp(fi);
 | 
			
		||||
 | 
			
		||||
  (void)path;
 | 
			
		||||
  if (offset != d->offset) {
 | 
			
		||||
#ifndef __FreeBSD__
 | 
			
		||||
    seekdir(d->dp, offset);
 | 
			
		||||
#else
 | 
			
		||||
    /* Subtract the one that we add when calling
 | 
			
		||||
       telldir() below */
 | 
			
		||||
    seekdir(d->dp, offset - 1);
 | 
			
		||||
#endif
 | 
			
		||||
    d->entry = NULL;
 | 
			
		||||
    d->offset = offset;
 | 
			
		||||
  }
 | 
			
		||||
  while (1) {
 | 
			
		||||
    struct stat st;
 | 
			
		||||
    off_t nextoff;
 | 
			
		||||
    // enum fuse_fill_dir_flags fill_flags = FUSE_FILL_DIR_DEFAULTS;
 | 
			
		||||
    enum fuse_fill_dir_flags fill_flags = 0;
 | 
			
		||||
 | 
			
		||||
    if (!d->entry) {
 | 
			
		||||
      d->entry = readdir(d->dp);
 | 
			
		||||
      if (!d->entry)
 | 
			
		||||
        break;
 | 
			
		||||
    }
 | 
			
		||||
#ifdef HAVE_FSTATAT
 | 
			
		||||
    if (flags & FUSE_READDIR_PLUS) {
 | 
			
		||||
      int res;
 | 
			
		||||
 | 
			
		||||
      res = fstatat(dirfd(d->dp), d->entry->d_name, &st, AT_SYMLINK_NOFOLLOW);
 | 
			
		||||
      if (res != -1)
 | 
			
		||||
        fill_flags |= FUSE_FILL_DIR_PLUS;
 | 
			
		||||
    }
 | 
			
		||||
#endif
 | 
			
		||||
    if (!(fill_flags & FUSE_FILL_DIR_PLUS)) {
 | 
			
		||||
      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__
 | 
			
		||||
    /* Under FreeBSD, telldir() may return 0 the first time
 | 
			
		||||
       it is called. But for libfuse, an offset of zero
 | 
			
		||||
       means that offsets are not supported, so we shift
 | 
			
		||||
       everything by one. */
 | 
			
		||||
    nextoff++;
 | 
			
		||||
#endif
 | 
			
		||||
    if (filler(buf, d->entry->d_name, &st, nextoff, fill_flags))
 | 
			
		||||
      break;
 | 
			
		||||
 | 
			
		||||
    d->entry = NULL;
 | 
			
		||||
    d->offset = nextoff;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* Complete copy of the example method(no need to modify anything so far) */
 | 
			
		||||
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;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
// TODO: make this work
 | 
			
		||||
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 = source_mkdir(path, mode);
 | 
			
		||||
  if (res == -1)
 | 
			
		||||
    return -errno;
 | 
			
		||||
 | 
			
		||||
  return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int xmp_unlink(const char *path) {
 | 
			
		||||
  int res;
 | 
			
		||||
 | 
			
		||||
  res = source_unlink(path);
 | 
			
		||||
  if (res == -1)
 | 
			
		||||
    return -errno;
 | 
			
		||||
 | 
			
		||||
  return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int xmp_rmdir(const char *path) {
 | 
			
		||||
  int res;
 | 
			
		||||
 | 
			
		||||
  res = source_rmdir(path);
 | 
			
		||||
  if (res == -1)
 | 
			
		||||
    return -errno;
 | 
			
		||||
 | 
			
		||||
  return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int xmp_symlink(const char *from, const char *to) {
 | 
			
		||||
  int res;
 | 
			
		||||
 | 
			
		||||
  res = source_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;
 | 
			
		||||
 | 
			
		||||
  /* When we have renameat2() in libc, then we can implement flags */
 | 
			
		||||
  if (flags)
 | 
			
		||||
    return -EINVAL;
 | 
			
		||||
 | 
			
		||||
  res = source_rename(from, to);
 | 
			
		||||
  if (res == -1)
 | 
			
		||||
    return -errno;
 | 
			
		||||
 | 
			
		||||
  return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int xmp_link(const char *from, const char *to) {
 | 
			
		||||
  int res;
 | 
			
		||||
 | 
			
		||||
  res = source_link(from, to);
 | 
			
		||||
  if (res == -1)
 | 
			
		||||
    return -errno;
 | 
			
		||||
 | 
			
		||||
  return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int xmp_chmod(const char *path, mode_t mode, struct fuse_file_info *fi) {
 | 
			
		||||
  int res;
 | 
			
		||||
 | 
			
		||||
  if (fi)
 | 
			
		||||
    res = fchmod(fi->fh, mode);
 | 
			
		||||
  else
 | 
			
		||||
    res = source_chmod(path, mode);
 | 
			
		||||
  if (res == -1)
 | 
			
		||||
    return -errno;
 | 
			
		||||
 | 
			
		||||
  return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int xmp_chown(const char *path, uid_t uid, gid_t gid,
 | 
			
		||||
                     struct fuse_file_info *fi) {
 | 
			
		||||
  int res;
 | 
			
		||||
 | 
			
		||||
  if (fi)
 | 
			
		||||
    res = fchown(fi->fh, uid, gid);
 | 
			
		||||
  else
 | 
			
		||||
    res = source_chown(path, uid, gid);
 | 
			
		||||
  if (res == -1)
 | 
			
		||||
    return -errno;
 | 
			
		||||
 | 
			
		||||
  return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int xmp_truncate(const char *path, off_t size,
 | 
			
		||||
                        struct fuse_file_info *fi) {
 | 
			
		||||
  int res;
 | 
			
		||||
 | 
			
		||||
  if (fi)
 | 
			
		||||
    res = ftruncate(fi->fh, size);
 | 
			
		||||
  else
 | 
			
		||||
    res = source_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],
 | 
			
		||||
                       struct fuse_file_info *fi) {
 | 
			
		||||
  int res;
 | 
			
		||||
 | 
			
		||||
  /* don't use utime/utimes since they follow symlinks */
 | 
			
		||||
  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 = source_create(path, fi->flags, mode);
 | 
			
		||||
  if (fd == -1)
 | 
			
		||||
    return -errno;
 | 
			
		||||
 | 
			
		||||
  fi->fh = fd;
 | 
			
		||||
  return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int xmp_open(const char *path, struct fuse_file_info *fi) {
 | 
			
		||||
  int fd;
 | 
			
		||||
 | 
			
		||||
  fd = source_open(path, fi->flags);
 | 
			
		||||
  if (fd == -1)
 | 
			
		||||
    return -errno;
 | 
			
		||||
 | 
			
		||||
  /* Enable direct_io when open has flags O_DIRECT to enjoy the feature
 | 
			
		||||
     parallel_direct_writes (i.e., to get a shared lock, not exclusive lock,
 | 
			
		||||
     for writes to the same file).
 | 
			
		||||
  if (fi->flags & O_DIRECT) {
 | 
			
		||||
    fi->direct_io = 1;
 | 
			
		||||
    fi->parallel_direct_writes = 1;
 | 
			
		||||
  }
 | 
			
		||||
  */
 | 
			
		||||
 | 
			
		||||
  fi->fh = fd;
 | 
			
		||||
  return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* Complete copy of the example method(no need to modify anything so far) */
 | 
			
		||||
static int xmp_read(const char *path, char *buf, size_t size, off_t offset,
 | 
			
		||||
                    struct fuse_file_info *fi) {
 | 
			
		||||
  int res;
 | 
			
		||||
 | 
			
		||||
  (void)path;
 | 
			
		||||
  res = pread(fi->fh, buf, size, offset);
 | 
			
		||||
  if (res == -1)
 | 
			
		||||
    res = -errno;
 | 
			
		||||
 | 
			
		||||
  return res;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* Complete copy of the example method(no need to modify anything so far) */
 | 
			
		||||
static int xmp_read_buf(const char *path, struct fuse_bufvec **bufp,
 | 
			
		||||
                        size_t size, off_t offset, struct fuse_file_info *fi) {
 | 
			
		||||
  struct fuse_bufvec *src;
 | 
			
		||||
 | 
			
		||||
  (void)path;
 | 
			
		||||
 | 
			
		||||
  src = malloc(sizeof(struct fuse_bufvec));
 | 
			
		||||
  if (src == NULL)
 | 
			
		||||
    return -ENOMEM;
 | 
			
		||||
 | 
			
		||||
  *src = FUSE_BUFVEC_INIT(size);
 | 
			
		||||
 | 
			
		||||
  src->buf[0].flags = FUSE_BUF_IS_FD | FUSE_BUF_FD_SEEK;
 | 
			
		||||
  src->buf[0].fd = fi->fh;
 | 
			
		||||
  src->buf[0].pos = offset;
 | 
			
		||||
 | 
			
		||||
  *bufp = src;
 | 
			
		||||
 | 
			
		||||
  return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* Complete copy of the example method(no need to modify anything so far) */
 | 
			
		||||
static int xmp_write(const char *path, const char *buf, size_t size,
 | 
			
		||||
                     off_t offset, struct fuse_file_info *fi) {
 | 
			
		||||
  int res;
 | 
			
		||||
 | 
			
		||||
  (void)path;
 | 
			
		||||
  res = pwrite(fi->fh, buf, size, offset);
 | 
			
		||||
  if (res == -1)
 | 
			
		||||
    res = -errno;
 | 
			
		||||
 | 
			
		||||
  return res;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* Complete copy of the example method(no need to modify anything so far) */
 | 
			
		||||
static int xmp_write_buf(const char *path, struct fuse_bufvec *buf,
 | 
			
		||||
                         off_t offset, struct fuse_file_info *fi) {
 | 
			
		||||
  struct fuse_bufvec dst = FUSE_BUFVEC_INIT(fuse_buf_size(buf));
 | 
			
		||||
 | 
			
		||||
  (void)path;
 | 
			
		||||
 | 
			
		||||
  dst.buf[0].flags = FUSE_BUF_IS_FD | FUSE_BUF_FD_SEEK;
 | 
			
		||||
  dst.buf[0].fd = fi->fh;
 | 
			
		||||
  dst.buf[0].pos = offset;
 | 
			
		||||
 | 
			
		||||
  return fuse_buf_copy(&dst, buf, FUSE_BUF_SPLICE_NONBLOCK);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int xmp_statfs(const char *path, struct statvfs *stbuf) {
 | 
			
		||||
  int res;
 | 
			
		||||
 | 
			
		||||
  res = statvfs(path, stbuf);
 | 
			
		||||
  if (res == -1)
 | 
			
		||||
    return -errno;
 | 
			
		||||
 | 
			
		||||
  return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* Complete copy of the example method(no need to modify anything so far) */
 | 
			
		||||
static int xmp_flush(const char *path, struct fuse_file_info *fi) {
 | 
			
		||||
  int res;
 | 
			
		||||
 | 
			
		||||
  (void)path;
 | 
			
		||||
  /* This is called from every close on an open file, so call the
 | 
			
		||||
     close on the underlying filesystem.	But since flush may be
 | 
			
		||||
     called multiple times for an open file, this must not really
 | 
			
		||||
     close the file.  This is important if used on a network
 | 
			
		||||
     filesystem like NFS which flush the data/metadata on close() */
 | 
			
		||||
  res = close(dup(fi->fh));
 | 
			
		||||
  if (res == -1)
 | 
			
		||||
    return -errno;
 | 
			
		||||
 | 
			
		||||
  return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* Complete copy of the example method(no need to modify anything so far) */
 | 
			
		||||
static int xmp_release(const char *path, struct fuse_file_info *fi) {
 | 
			
		||||
  (void)path;
 | 
			
		||||
  close(fi->fh);
 | 
			
		||||
 | 
			
		||||
  return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* Complete copy of the example method(no need to modify anything so far) */
 | 
			
		||||
static int xmp_fsync(const char *path, int isdatasync,
 | 
			
		||||
                     struct fuse_file_info *fi) {
 | 
			
		||||
  int res;
 | 
			
		||||
  (void)path;
 | 
			
		||||
 | 
			
		||||
#ifndef HAVE_FDATASYNC
 | 
			
		||||
  (void)isdatasync;
 | 
			
		||||
#else
 | 
			
		||||
  if (isdatasync)
 | 
			
		||||
    res = fdatasync(fi->fh);
 | 
			
		||||
  else
 | 
			
		||||
#endif
 | 
			
		||||
  res = fsync(fi->fh);
 | 
			
		||||
  if (res == -1)
 | 
			
		||||
    return -errno;
 | 
			
		||||
 | 
			
		||||
  return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#ifdef HAVE_POSIX_FALLOCATE
 | 
			
		||||
static int xmp_fallocate(const char *path, int mode, off_t offset, off_t length,
 | 
			
		||||
                         struct fuse_file_info *fi) {
 | 
			
		||||
  (void)path;
 | 
			
		||||
 | 
			
		||||
  if (mode)
 | 
			
		||||
    return -EOPNOTSUPP;
 | 
			
		||||
 | 
			
		||||
  return -posix_fallocate(fi->fh, offset, length);
 | 
			
		||||
}
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
#ifdef HAVE_SETXATTR
 | 
			
		||||
/* xattr operations are optional and can safely be left unimplemented */
 | 
			
		||||
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 /* HAVE_SETXATTR */
 | 
			
		||||
 | 
			
		||||
#ifdef HAVE_LIBULOCKMGR
 | 
			
		||||
static int xmp_lock(const char *path, struct fuse_file_info *fi, int cmd,
 | 
			
		||||
                    struct flock *lock) {
 | 
			
		||||
  (void)path;
 | 
			
		||||
 | 
			
		||||
  return ulockmgr_op(fi->fh, cmd, lock, &fi->lock_owner,
 | 
			
		||||
                     sizeof(fi->lock_owner));
 | 
			
		||||
}
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
/* Complete copy of the example method(no need to modify anything so far) */
 | 
			
		||||
static int xmp_flock(const char *path, struct fuse_file_info *fi, int op) {
 | 
			
		||||
  int res;
 | 
			
		||||
  (void)path;
 | 
			
		||||
 | 
			
		||||
  res = flock(fi->fh, op);
 | 
			
		||||
  if (res == -1)
 | 
			
		||||
    return -errno;
 | 
			
		||||
 | 
			
		||||
  return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#ifdef HAVE_COPY_FILE_RANGE
 | 
			
		||||
static ssize_t xmp_copy_file_range(const char *path_in,
 | 
			
		||||
                                   struct fuse_file_info *fi_in, off_t off_in,
 | 
			
		||||
                                   const char *path_out,
 | 
			
		||||
                                   struct fuse_file_info *fi_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
 | 
			
		||||
 | 
			
		||||
/* Complete copy of the example method(no need to modify anything so far) */
 | 
			
		||||
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;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// TODO: look trough "optional"(commented out) operations.
 | 
			
		||||
static const struct fuse_operations xmp_oper = {
 | 
			
		||||
    .init = xmp_init,
 | 
			
		||||
    .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[]) {
 | 
			
		||||
 | 
			
		||||
  int ret;
 | 
			
		||||
  umask(0);
 | 
			
		||||
 | 
			
		||||
  // FUSE won't tell us the mountpoint on it's own, so we need to extract it
 | 
			
		||||
  // ourselves.
 | 
			
		||||
  mountpoint = realpath(argv[argc - 2], NULL);
 | 
			
		||||
  mountpoint = realpath(argv[argc - 1], NULL);
 | 
			
		||||
 | 
			
		||||
  ret = fuse_main(argc, argv, &icfs_oper, NULL);
 | 
			
		||||
  int ret = source_init(mountpoint);
 | 
			
		||||
  if (ret != 0) {
 | 
			
		||||
    perror("Failed to initialize filesystem.");
 | 
			
		||||
    exit(EXIT_FAILURE);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  return ret;
 | 
			
		||||
  return fuse_main(argc, argv, &xmp_oper, NULL);
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -1,14 +1,26 @@
 | 
			
		||||
#define _GNU_SOURCE
 | 
			
		||||
 | 
			
		||||
#include "sourcefs.h"
 | 
			
		||||
#include <dirent.h>
 | 
			
		||||
#include <errno.h>
 | 
			
		||||
#include <fcntl.h>
 | 
			
		||||
#include <stdio.h>
 | 
			
		||||
#include <string.h>
 | 
			
		||||
#include <sys/stat.h>
 | 
			
		||||
#include <unistd.h>
 | 
			
		||||
 | 
			
		||||
static struct source_files_handle {
 | 
			
		||||
  int root_fd;
 | 
			
		||||
} handle;
 | 
			
		||||
 | 
			
		||||
const char *source_fname_translate(const char *filename) {
 | 
			
		||||
  if (strcmp("/", filename) == 0) {
 | 
			
		||||
    return ".";
 | 
			
		||||
  } else {
 | 
			
		||||
    return filename + 1;
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int source_init(const char *root_path) {
 | 
			
		||||
  int root_fd = open(root_path, O_PATH);
 | 
			
		||||
 | 
			
		||||
@@ -21,8 +33,84 @@ int source_init(const char *root_path) {
 | 
			
		||||
  return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Currently this literally is a fstatat wrapper.
 | 
			
		||||
int source_stat(const char *restrict pathname, struct stat *restrict statbuf) {
 | 
			
		||||
  int statret = fstatat(handle.root_fd, pathname, statbuf, 0);
 | 
			
		||||
  return statret;
 | 
			
		||||
int source_mkdir(const char *filename, mode_t mode) {
 | 
			
		||||
  const char *relative_filename = source_fname_translate(filename);
 | 
			
		||||
  return mkdirat(handle.root_fd, relative_filename, mode);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int source_unlink(const char *filename) {
 | 
			
		||||
  const char *relative_filename = source_fname_translate(filename);
 | 
			
		||||
  return unlinkat(handle.root_fd, relative_filename, 0);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int source_stat(const char *restrict filename, struct stat *restrict statbuf) {
 | 
			
		||||
  const char *relative_filename = source_fname_translate(filename);
 | 
			
		||||
  return fstatat(handle.root_fd, relative_filename, statbuf, 0);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int source_rmdir(const char *filename) {
 | 
			
		||||
  const char *relative_filename = source_fname_translate(filename);
 | 
			
		||||
  return unlinkat(handle.root_fd, relative_filename, AT_REMOVEDIR);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int source_symlink(const char *target, const char *linkpath) {
 | 
			
		||||
  const char *relative_linkpath = source_fname_translate(linkpath);
 | 
			
		||||
  return symlinkat(target, handle.root_fd, relative_linkpath);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
DIR *source_opendir(const char *filename) {
 | 
			
		||||
  const char *relative_filename = source_fname_translate(filename);
 | 
			
		||||
  int fd = openat(handle.root_fd, relative_filename, NULL);
 | 
			
		||||
  if (fd < 0) {
 | 
			
		||||
    perror("Openat failed");
 | 
			
		||||
    return NULL;
 | 
			
		||||
  }
 | 
			
		||||
  DIR *dir_pointer = fdopendir(fd);
 | 
			
		||||
  return dir_pointer;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int source_rename(const char *oldpath, const char *newpath) {
 | 
			
		||||
  const char *relative_oldpath = source_fname_translate(oldpath);
 | 
			
		||||
  const char *relative_newpath = source_fname_translate(newpath);
 | 
			
		||||
  return renameat(handle.root_fd, relative_oldpath, handle.root_fd,
 | 
			
		||||
                  relative_newpath);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int source_link(const char *oldpath, const char *newpath) {
 | 
			
		||||
  const char *relative_oldpath = source_fname_translate(oldpath);
 | 
			
		||||
  const char *relative_newpath = source_fname_translate(newpath);
 | 
			
		||||
  return linkat(handle.root_fd, relative_oldpath, handle.root_fd,
 | 
			
		||||
                relative_newpath, 0);
 | 
			
		||||
  // NOTE: perhaps the flags here need to be reevaluated.
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int source_chmod(const char *filename, mode_t mode) {
 | 
			
		||||
  const char *relative_filename = source_fname_translate(filename);
 | 
			
		||||
  return fchmodat(handle.root_fd, relative_filename, mode, 0);
 | 
			
		||||
  // NOTE: perhaps the flags here need to be reevaluated.
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int source_chown(const char *filename, uid_t owner, gid_t group) {
 | 
			
		||||
  const char *relative_filename = source_fname_translate(filename);
 | 
			
		||||
  return fchownat(handle.root_fd, filename, owner, group, AT_SYMLINK_NOFOLLOW);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int source_truncate(const char *filename, off_t length) {
 | 
			
		||||
  const char *relative_filename = source_fname_translate(filename);
 | 
			
		||||
  int fd = openat(handle.root_fd, relative_filename, NULL);
 | 
			
		||||
  if (fd < 0) {
 | 
			
		||||
    perror("Openat failed");
 | 
			
		||||
    return -1;
 | 
			
		||||
  }
 | 
			
		||||
  return ftruncate(fd, length);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int source_open(const char *filename, int flags) {
 | 
			
		||||
  const char *relative_filename = source_fname_translate(filename);
 | 
			
		||||
  return openat(handle.root_fd, relative_filename, flags);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int source_create(const char *filename, int flags, mode_t mode) {
 | 
			
		||||
  const char *relative_filename = source_fname_translate(filename);
 | 
			
		||||
  return openat(handle.root_fd, relative_filename, flags, mode);
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -3,21 +3,49 @@
 | 
			
		||||
#ifndef SOURCEFS_H
 | 
			
		||||
#define SOURCEFS_H
 | 
			
		||||
 | 
			
		||||
#include <dirent.h>
 | 
			
		||||
#include <sys/stat.h>
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Initializes the source file handling.
 | 
			
		||||
 *
 | 
			
		||||
 * @param root_path The root of the source files folder.
 | 
			
		||||
 * @return 0 on success, 1 on failure.
 | 
			
		||||
 * @return 0 on success, -1 on failure.
 | 
			
		||||
 */
 | 
			
		||||
int source_init(const char *root_path);
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * `stat()`, but for source files.
 | 
			
		||||
 *
 | 
			
		||||
 * @see `stat()`
 | 
			
		||||
 */
 | 
			
		||||
int source_stat(const char *restrict pathname, struct stat *restrict statbuf);
 | 
			
		||||
/* All of the functions below are designed to behave exactly as their non-source
 | 
			
		||||
 * counterparts. */
 | 
			
		||||
 | 
			
		||||
int source_stat(const char *restrict filename, struct stat *restrict statbuf);
 | 
			
		||||
 | 
			
		||||
struct dirent *source_readdir(DIR *dirp);
 | 
			
		||||
 | 
			
		||||
DIR *source_opendir(const char *filename);
 | 
			
		||||
 | 
			
		||||
int source_unlink(const char *filename);
 | 
			
		||||
 | 
			
		||||
int source_mkdir(const char *filename, mode_t mode);
 | 
			
		||||
 | 
			
		||||
int source_rmdir(const char *filename);
 | 
			
		||||
 | 
			
		||||
int source_symlink(const char *target, const char *linkpath);
 | 
			
		||||
 | 
			
		||||
int source_rename(const char *oldpath, const char *newpath);
 | 
			
		||||
 | 
			
		||||
int source_link(const char *oldpath, const char *newpath);
 | 
			
		||||
 | 
			
		||||
int source_chmod(const char *filename, mode_t mode);
 | 
			
		||||
 | 
			
		||||
int source_chown(const char *filename, uid_t owner, gid_t group);
 | 
			
		||||
 | 
			
		||||
int source_truncate(const char *filename, off_t length);
 | 
			
		||||
 | 
			
		||||
/* `open` and `create` are designed to correspond to fuse operations, not the
 | 
			
		||||
 * libc's `open(2)`. Both of them actually call `openat`. */
 | 
			
		||||
 | 
			
		||||
int source_open(const char *filename, int flags);
 | 
			
		||||
 | 
			
		||||
int source_create(const char *filename, int flags, mode_t mode);
 | 
			
		||||
 | 
			
		||||
#endif // !SOURCEFS_H
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user