Blame src/rofiles-fuse/main.c

rpm-build 0fba15
/*
rpm-build 0fba15
 * Copyright (C) 2015,2016 Colin Walters <walters@verbum.org>
rpm-build 0fba15
 *
rpm-build 0fba15
 * SPDX-License-Identifier: LGPL-2.0+
rpm-build 0fba15
 *
rpm-build 0fba15
 * This library is free software; you can redistribute it and/or
rpm-build 0fba15
 * modify it under the terms of the GNU Lesser General Public
rpm-build 0fba15
 * License as published by the Free Software Foundation; either
rpm-build 0fba15
 * version 2 of the License, or (at your option) any later version.
rpm-build 0fba15
 *
rpm-build 0fba15
 * This library is distributed in the hope that it will be useful,
rpm-build 0fba15
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
rpm-build 0fba15
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
rpm-build 0fba15
 * Lesser General Public License for more details.
rpm-build 0fba15
 *
rpm-build 0fba15
 * You should have received a copy of the GNU Lesser General Public
rpm-build 0fba15
 * License along with this library; if not, write to the
rpm-build 0fba15
 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
rpm-build 0fba15
 * Boston, MA 02111-1307, USA.
rpm-build 0fba15
 */
rpm-build 0fba15
rpm-build 0fba15
#define FUSE_USE_VERSION 26
rpm-build 0fba15
rpm-build 0fba15
#include <sys/types.h>
rpm-build 0fba15
#include <sys/stat.h>
rpm-build 0fba15
#include <sys/statvfs.h>
rpm-build 0fba15
#include <stdio.h>
rpm-build 0fba15
#include <err.h>
rpm-build 0fba15
#include <stdlib.h>
rpm-build 0fba15
#include <string.h>
rpm-build 0fba15
#include <errno.h>
rpm-build 0fba15
#include <fcntl.h>
rpm-build 0fba15
#include <sys/xattr.h>
rpm-build 0fba15
#include <dirent.h>
rpm-build 0fba15
#include <unistd.h>
rpm-build 0fba15
#include <fuse.h>
rpm-build 0fba15
rpm-build 0fba15
#include <glib.h>
rpm-build 0fba15
rpm-build 0fba15
#include "libglnx.h"
rpm-build 0fba15
#include "ostree.h"
rpm-build 0fba15
rpm-build 0fba15
// Global to store our read-write path
rpm-build 0fba15
static int basefd = -1;
rpm-build 0fba15
/* Whether or not to automatically "copyup" (in overlayfs terms).
rpm-build 0fba15
 * What we're really doing is breaking hardlinks.
rpm-build 0fba15
 */
rpm-build 0fba15
static gboolean opt_copyup;
rpm-build 0fba15
rpm-build 0fba15
static inline const char *
rpm-build 0fba15
ENSURE_RELPATH (const char *path)
rpm-build 0fba15
{
rpm-build 0fba15
  path = path + strspn (path, "/");
rpm-build 0fba15
  if (*path == 0)
rpm-build 0fba15
    return ".";
rpm-build 0fba15
  return path;
rpm-build 0fba15
}
rpm-build 0fba15
rpm-build 0fba15
static int
rpm-build 0fba15
callback_getattr (const char *path, struct stat *st_data)
rpm-build 0fba15
{
rpm-build 0fba15
  path = ENSURE_RELPATH (path);
rpm-build 0fba15
  if (!*path)
rpm-build 0fba15
    {
rpm-build 0fba15
      if (fstat (basefd, st_data) == -1)
rpm-build 0fba15
        return -errno;
rpm-build 0fba15
    }
rpm-build 0fba15
  else
rpm-build 0fba15
    {
rpm-build 0fba15
      if (fstatat (basefd, path, st_data, AT_SYMLINK_NOFOLLOW) == -1)
rpm-build 0fba15
        return -errno;
rpm-build 0fba15
    }
rpm-build 0fba15
  return 0;
rpm-build 0fba15
}
rpm-build 0fba15
rpm-build 0fba15
static int
rpm-build 0fba15
callback_readlink (const char *path, char *buf, size_t size)
rpm-build 0fba15
{
rpm-build 0fba15
  int r;
rpm-build 0fba15
rpm-build 0fba15
  path = ENSURE_RELPATH (path);
rpm-build 0fba15
rpm-build 0fba15
  /* Note FUSE wants the string to be always nul-terminated, even if
rpm-build 0fba15
   * truncated.
rpm-build 0fba15
   */
rpm-build 0fba15
  r = readlinkat (basefd, path, buf, size - 1);
rpm-build 0fba15
  if (r == -1)
rpm-build 0fba15
    return -errno;
rpm-build 0fba15
  buf[r] = '\0';
rpm-build 0fba15
  return 0;
rpm-build 0fba15
}
rpm-build 0fba15
rpm-build 0fba15
static int
rpm-build 0fba15
callback_readdir (const char *path, void *buf, fuse_fill_dir_t filler,
rpm-build 0fba15
                  off_t offset, struct fuse_file_info *fi)
rpm-build 0fba15
{
rpm-build 0fba15
  DIR *dp;
rpm-build 0fba15
  struct dirent *de;
rpm-build 0fba15
  int dfd;
rpm-build 0fba15
rpm-build 0fba15
  path = ENSURE_RELPATH (path);
rpm-build 0fba15
rpm-build 0fba15
  if (!*path)
rpm-build 0fba15
    {
rpm-build 0fba15
      dfd = fcntl (basefd, F_DUPFD_CLOEXEC, 3);
rpm-build 0fba15
      if (dfd < 0)
rpm-build 0fba15
        return -errno;
rpm-build 0fba15
      lseek (dfd, 0, SEEK_SET);
rpm-build 0fba15
    }
rpm-build 0fba15
  else
rpm-build 0fba15
    {
rpm-build 0fba15
      dfd = openat (basefd, path, O_RDONLY | O_NONBLOCK | O_DIRECTORY | O_CLOEXEC | O_NOCTTY);
rpm-build 0fba15
      if (dfd == -1)
rpm-build 0fba15
        return -errno;
rpm-build 0fba15
    }
rpm-build 0fba15
rpm-build 0fba15
  /* Transfers ownership of fd */
rpm-build 0fba15
  dp = fdopendir (dfd);
rpm-build 0fba15
  if (dp == NULL)
rpm-build 0fba15
    return -errno;
rpm-build 0fba15
rpm-build 0fba15
  while ((de = readdir (dp)) != NULL)
rpm-build 0fba15
    {
rpm-build 0fba15
      struct stat st;
rpm-build 0fba15
      memset (&st, 0, sizeof (st));
rpm-build 0fba15
      st.st_ino = de->d_ino;
rpm-build 0fba15
      st.st_mode = de->d_type << 12;
rpm-build 0fba15
      if (filler (buf, de->d_name, &st, 0))
rpm-build 0fba15
        break;
rpm-build 0fba15
    }
rpm-build 0fba15
rpm-build 0fba15
  (void) closedir (dp);
rpm-build 0fba15
  return 0;
rpm-build 0fba15
}
rpm-build 0fba15
rpm-build 0fba15
static int
rpm-build 0fba15
callback_mknod (const char *path, mode_t mode, dev_t rdev)
rpm-build 0fba15
{
rpm-build 0fba15
  return -EROFS;
rpm-build 0fba15
}
rpm-build 0fba15
rpm-build 0fba15
static int
rpm-build 0fba15
callback_mkdir (const char *path, mode_t mode)
rpm-build 0fba15
{
rpm-build 0fba15
  path = ENSURE_RELPATH (path);
rpm-build 0fba15
  if (mkdirat (basefd, path, mode) == -1)
rpm-build 0fba15
    return -errno;
rpm-build 0fba15
  return 0;
rpm-build 0fba15
}
rpm-build 0fba15
rpm-build 0fba15
static int
rpm-build 0fba15
callback_unlink (const char *path)
rpm-build 0fba15
{
rpm-build 0fba15
  path = ENSURE_RELPATH (path);
rpm-build 0fba15
  if (unlinkat (basefd, path, 0) == -1)
rpm-build 0fba15
    return -errno;
rpm-build 0fba15
  return 0;
rpm-build 0fba15
}
rpm-build 0fba15
rpm-build 0fba15
static int
rpm-build 0fba15
callback_rmdir (const char *path)
rpm-build 0fba15
{
rpm-build 0fba15
  path = ENSURE_RELPATH (path);
rpm-build 0fba15
  if (unlinkat (basefd, path, AT_REMOVEDIR) == -1)
rpm-build 0fba15
    return -errno;
rpm-build 0fba15
  return 0;
rpm-build 0fba15
}
rpm-build 0fba15
rpm-build 0fba15
static int
rpm-build 0fba15
callback_symlink (const char *from, const char *to)
rpm-build 0fba15
{
rpm-build 0fba15
  struct stat stbuf;
rpm-build 0fba15
rpm-build 0fba15
  to = ENSURE_RELPATH (to);
rpm-build 0fba15
rpm-build 0fba15
  if (symlinkat (from, basefd, to) == -1)
rpm-build 0fba15
    return -errno;
rpm-build 0fba15
rpm-build 0fba15
  if (fstatat (basefd, to, &stbuf, AT_SYMLINK_NOFOLLOW) == -1)
rpm-build 0fba15
    {
rpm-build 0fba15
      fprintf (stderr, "Failed to find newly created symlink '%s': %s\n",
rpm-build 0fba15
               to, g_strerror (errno));
rpm-build 0fba15
      exit (EXIT_FAILURE);
rpm-build 0fba15
    }
rpm-build 0fba15
  return 0;
rpm-build 0fba15
}
rpm-build 0fba15
rpm-build 0fba15
static int
rpm-build 0fba15
callback_rename (const char *from, const char *to)
rpm-build 0fba15
{
rpm-build 0fba15
  from = ENSURE_RELPATH (from);
rpm-build 0fba15
  to = ENSURE_RELPATH (to);
rpm-build 0fba15
  if (renameat (basefd, from, basefd, to) == -1)
rpm-build 0fba15
    return -errno;
rpm-build 0fba15
  return 0;
rpm-build 0fba15
}
rpm-build 0fba15
rpm-build 0fba15
static int
rpm-build 0fba15
callback_link (const char *from, const char *to)
rpm-build 0fba15
{
rpm-build 0fba15
  from = ENSURE_RELPATH (from);
rpm-build 0fba15
  to = ENSURE_RELPATH (to);
rpm-build 0fba15
  if (linkat (basefd, from, basefd, to, 0) == -1)
rpm-build 0fba15
    return -errno;
rpm-build 0fba15
  return 0;
rpm-build 0fba15
}
rpm-build 0fba15
rpm-build 0fba15
/* Check whether @stbuf refers to a hardlinked regfile or symlink, and if so
rpm-build 0fba15
 * return -EROFS. Otherwise return 0.
rpm-build 0fba15
 */
rpm-build 0fba15
static gboolean
rpm-build 0fba15
can_write_stbuf (const struct stat *stbuf)
rpm-build 0fba15
{
rpm-build 0fba15
  /* If it's not a regular file or symlink, ostree won't hardlink it, so allow
rpm-build 0fba15
   * writes - it might be a FIFO or device that somehow
rpm-build 0fba15
   * ended up underneath our mount.
rpm-build 0fba15
   */
rpm-build 0fba15
  if (!(S_ISREG (stbuf->st_mode) || S_ISLNK (stbuf->st_mode)))
rpm-build 0fba15
    return TRUE;
rpm-build 0fba15
  /* If the object isn't hardlinked, it's OK to write */
rpm-build 0fba15
  if (stbuf->st_nlink <= 1)
rpm-build 0fba15
    return TRUE;
rpm-build 0fba15
  /* Otherwise, it's a hardlinked file or symlink; it must be
rpm-build 0fba15
   * immutable.
rpm-build 0fba15
   */
rpm-build 0fba15
  return FALSE;
rpm-build 0fba15
}
rpm-build 0fba15
rpm-build 0fba15
static int
rpm-build 0fba15
gioerror_to_errno (GIOErrorEnum e)
rpm-build 0fba15
{
rpm-build 0fba15
  /* It's obviously crappy to have to do this but
rpm-build 0fba15
   * we also don't want to try to have "raw errno" versions
rpm-build 0fba15
   * of everything down in ostree_break_hardlink() so...
rpm-build 0fba15
   * let's just reverse map a few ones I think are going to be common.
rpm-build 0fba15
   */
rpm-build 0fba15
  switch (e)
rpm-build 0fba15
    {
rpm-build 0fba15
    case G_IO_ERROR_NOT_FOUND:
rpm-build 0fba15
      return ENOENT;
rpm-build 0fba15
    case G_IO_ERROR_IS_DIRECTORY:
rpm-build 0fba15
      return EISDIR;
rpm-build 0fba15
    case G_IO_ERROR_PERMISSION_DENIED:
rpm-build 0fba15
      return EPERM;
rpm-build 0fba15
    case G_IO_ERROR_NO_SPACE:
rpm-build 0fba15
      return ENOSPC;
rpm-build 0fba15
    default:
rpm-build 0fba15
      return EIO;
rpm-build 0fba15
    }
rpm-build 0fba15
}
rpm-build 0fba15
rpm-build 0fba15
static int
rpm-build 0fba15
verify_write_or_copyup (const char *path, const struct stat *stbuf,
rpm-build 0fba15
                        gboolean *out_did_copyup)
rpm-build 0fba15
{
rpm-build 0fba15
  struct stat stbuf_local;
rpm-build 0fba15
rpm-build 0fba15
  if (out_did_copyup)
rpm-build 0fba15
    *out_did_copyup = FALSE;
rpm-build 0fba15
rpm-build 0fba15
  /* If a stbuf wasn't provided, gather it now */
rpm-build 0fba15
  if (!stbuf)
rpm-build 0fba15
    {
rpm-build 0fba15
      if (fstatat (basefd, path, &stbuf_local, AT_SYMLINK_NOFOLLOW) == -1)
rpm-build 0fba15
        {
rpm-build 0fba15
          if (errno == ENOENT)
rpm-build 0fba15
            return 0;
rpm-build 0fba15
          else
rpm-build 0fba15
            return -errno;
rpm-build 0fba15
        }
rpm-build 0fba15
      stbuf = &stbuf_local;
rpm-build 0fba15
    }
rpm-build 0fba15
rpm-build 0fba15
  /* Verify writability, if that fails, perform copy-up if enabled */
rpm-build 0fba15
  if (!can_write_stbuf (stbuf))
rpm-build 0fba15
    {
rpm-build 0fba15
      if (opt_copyup)
rpm-build 0fba15
        {
rpm-build 0fba15
          g_autoptr(GError) tmp_error = NULL;
rpm-build 0fba15
          if (!ostree_break_hardlink (basefd, path, FALSE, NULL, &tmp_error))
rpm-build 0fba15
            return -gioerror_to_errno ((GIOErrorEnum)tmp_error->code);
rpm-build 0fba15
          if (out_did_copyup)
rpm-build 0fba15
            *out_did_copyup = TRUE;
rpm-build 0fba15
        }
rpm-build 0fba15
      else
rpm-build 0fba15
        return -EROFS;
rpm-build 0fba15
    }
rpm-build 0fba15
rpm-build 0fba15
  return 0;
rpm-build 0fba15
}
rpm-build 0fba15
rpm-build 0fba15
/* Given a path (which is absolute), convert it
rpm-build 0fba15
 * to a relative path (even for the caller) and
rpm-build 0fba15
 * perform either write verification or copy-up.
rpm-build 0fba15
 */
rpm-build 0fba15
#define PATH_WRITE_ENTRYPOINT(path) do {                     \
rpm-build 0fba15
    path = ENSURE_RELPATH (path);                            \
rpm-build 0fba15
    int r = verify_write_or_copyup (path, NULL, NULL);       \
rpm-build 0fba15
    if (r != 0)                                              \
rpm-build 0fba15
      return r;                                              \
rpm-build 0fba15
  } while (0)
rpm-build 0fba15
rpm-build 0fba15
static int
rpm-build 0fba15
callback_chmod (const char *path, mode_t mode)
rpm-build 0fba15
{
rpm-build 0fba15
  PATH_WRITE_ENTRYPOINT (path);
rpm-build 0fba15
rpm-build 0fba15
  /* Note we can't use AT_SYMLINK_NOFOLLOW yet;
rpm-build 0fba15
   * https://marc.info/?l=linux-kernel&m=148830147803162&w=2
rpm-build 0fba15
   * https://marc.info/?l=linux-fsdevel&m=149193779929561&w=2
rpm-build 0fba15
   */
rpm-build 0fba15
  if (fchmodat (basefd, path, mode, 0) != 0)
rpm-build 0fba15
    return -errno;
rpm-build 0fba15
  return 0;
rpm-build 0fba15
}
rpm-build 0fba15
rpm-build 0fba15
static int
rpm-build 0fba15
callback_chown (const char *path, uid_t uid, gid_t gid)
rpm-build 0fba15
{
rpm-build 0fba15
  PATH_WRITE_ENTRYPOINT (path);
rpm-build 0fba15
rpm-build 0fba15
  if (fchownat (basefd, path, uid, gid, AT_SYMLINK_NOFOLLOW) != 0)
rpm-build 0fba15
    return -errno;
rpm-build 0fba15
  return 0;
rpm-build 0fba15
}
rpm-build 0fba15
rpm-build 0fba15
static int
rpm-build 0fba15
callback_truncate (const char *path, off_t size)
rpm-build 0fba15
{
rpm-build 0fba15
  PATH_WRITE_ENTRYPOINT (path);
rpm-build 0fba15
rpm-build 0fba15
  glnx_autofd int fd = openat (basefd, path, O_NOFOLLOW|O_WRONLY);
rpm-build 0fba15
  if (fd == -1)
rpm-build 0fba15
    return -errno;
rpm-build 0fba15
rpm-build 0fba15
  if (ftruncate (fd, size) == -1)
rpm-build 0fba15
    return -errno;
rpm-build 0fba15
rpm-build 0fba15
  return 0;
rpm-build 0fba15
}
rpm-build 0fba15
rpm-build 0fba15
static int
rpm-build 0fba15
callback_utimens (const char *path, const struct timespec tv[2])
rpm-build 0fba15
{
rpm-build 0fba15
  /* This one isn't write-verified, we support changing times
rpm-build 0fba15
   * even for hardlinked files.
rpm-build 0fba15
   */
rpm-build 0fba15
  path = ENSURE_RELPATH (path);
rpm-build 0fba15
rpm-build 0fba15
  if (utimensat (basefd, path, tv, AT_SYMLINK_NOFOLLOW) == -1)
rpm-build 0fba15
    return -errno;
rpm-build 0fba15
rpm-build 0fba15
  return 0;
rpm-build 0fba15
}
rpm-build 0fba15
rpm-build 0fba15
static int
rpm-build 0fba15
do_open (const char *path, mode_t mode, struct fuse_file_info *finfo)
rpm-build 0fba15
{
rpm-build 0fba15
  int fd;
rpm-build 0fba15
  struct stat stbuf;
rpm-build 0fba15
rpm-build 0fba15
  path = ENSURE_RELPATH (path);
rpm-build 0fba15
rpm-build 0fba15
  if ((finfo->flags & O_ACCMODE) == O_RDONLY)
rpm-build 0fba15
    {
rpm-build 0fba15
      /* Read */
rpm-build 0fba15
      fd = openat (basefd, path, finfo->flags, mode);
rpm-build 0fba15
      if (fd == -1)
rpm-build 0fba15
        return -errno;
rpm-build 0fba15
    }
rpm-build 0fba15
  else
rpm-build 0fba15
    {
rpm-build 0fba15
      /* Write */
rpm-build 0fba15
rpm-build 0fba15
      /* We need to specially handle O_TRUNC */
rpm-build 0fba15
      fd = openat (basefd, path, finfo->flags & ~O_TRUNC, mode);
rpm-build 0fba15
      if (fd == -1)
rpm-build 0fba15
        return -errno;
rpm-build 0fba15
rpm-build 0fba15
      if (fstat (fd, &stbuf) == -1)
rpm-build 0fba15
        {
rpm-build 0fba15
          (void) close (fd);
rpm-build 0fba15
          return -errno;
rpm-build 0fba15
        }
rpm-build 0fba15
rpm-build 0fba15
      gboolean did_copyup;
rpm-build 0fba15
      int r = verify_write_or_copyup (path, &stbuf, &did_copyup);
rpm-build 0fba15
      if (r != 0)
rpm-build 0fba15
        {
rpm-build 0fba15
          (void) close (fd);
rpm-build 0fba15
          return r;
rpm-build 0fba15
        }
rpm-build 0fba15
rpm-build 0fba15
      /* In the copyup case, we need to re-open */
rpm-build 0fba15
      if (did_copyup)
rpm-build 0fba15
        {
rpm-build 0fba15
          (void) close (fd);
rpm-build 0fba15
          /* Note that unlike the initial open, we will pass through
rpm-build 0fba15
           * O_TRUNC.  More ideally in this copyup case we'd avoid copying
rpm-build 0fba15
           * the whole file in the first place, but eh.  It's not like we're
rpm-build 0fba15
           * high performance anyways.
rpm-build 0fba15
           */
rpm-build 0fba15
          fd = openat (basefd, path, finfo->flags & ~(O_EXCL|O_CREAT), mode);
rpm-build 0fba15
          if (fd == -1)
rpm-build 0fba15
            return -errno;
rpm-build 0fba15
        }
rpm-build 0fba15
      else
rpm-build 0fba15
        {
rpm-build 0fba15
          /* In the non-copyup case we handle O_TRUNC here, after we've verified
rpm-build 0fba15
           * the hardlink state above with verify_write_or_copyup().
rpm-build 0fba15
           */
rpm-build 0fba15
          if (finfo->flags & O_TRUNC)
rpm-build 0fba15
            {
rpm-build 0fba15
              if (ftruncate (fd, 0) == -1)
rpm-build 0fba15
                {
rpm-build 0fba15
                  (void) close (fd);
rpm-build 0fba15
                  return -errno;
rpm-build 0fba15
                }
rpm-build 0fba15
            }
rpm-build 0fba15
        }
rpm-build 0fba15
    }
rpm-build 0fba15
rpm-build 0fba15
  finfo->fh = fd;
rpm-build 0fba15
rpm-build 0fba15
  return 0;
rpm-build 0fba15
}
rpm-build 0fba15
rpm-build 0fba15
static int
rpm-build 0fba15
callback_open (const char *path, struct fuse_file_info *finfo)
rpm-build 0fba15
{
rpm-build 0fba15
  return do_open (path, 0, finfo);
rpm-build 0fba15
}
rpm-build 0fba15
rpm-build 0fba15
static int
rpm-build 0fba15
callback_create(const char *path, mode_t mode, struct fuse_file_info *finfo)
rpm-build 0fba15
{
rpm-build 0fba15
  return do_open (path, mode, finfo);
rpm-build 0fba15
}
rpm-build 0fba15
rpm-build 0fba15
static int
rpm-build 0fba15
callback_read_buf (const char *path, struct fuse_bufvec **bufp,
rpm-build 0fba15
                   size_t size, off_t offset, struct fuse_file_info *finfo)
rpm-build 0fba15
{
rpm-build 0fba15
  struct fuse_bufvec *src;
rpm-build 0fba15
rpm-build 0fba15
  src = malloc (sizeof (struct fuse_bufvec));
rpm-build 0fba15
  if (src == NULL)
rpm-build 0fba15
    return -ENOMEM;
rpm-build 0fba15
rpm-build 0fba15
  *src = FUSE_BUFVEC_INIT (size);
rpm-build 0fba15
rpm-build 0fba15
  src->buf[0].flags = FUSE_BUF_IS_FD | FUSE_BUF_FD_SEEK;
rpm-build 0fba15
  src->buf[0].fd = finfo->fh;
rpm-build 0fba15
  src->buf[0].pos = offset;
rpm-build 0fba15
  *bufp = src;
rpm-build 0fba15
rpm-build 0fba15
  return 0;
rpm-build 0fba15
}
rpm-build 0fba15
rpm-build 0fba15
static int
rpm-build 0fba15
callback_read (const char *path, char *buf, size_t size, off_t offset,
rpm-build 0fba15
               struct fuse_file_info *finfo)
rpm-build 0fba15
{
rpm-build 0fba15
  int r;
rpm-build 0fba15
  r = pread (finfo->fh, buf, size, offset);
rpm-build 0fba15
  if (r == -1)
rpm-build 0fba15
    return -errno;
rpm-build 0fba15
  return r;
rpm-build 0fba15
}
rpm-build 0fba15
rpm-build 0fba15
static int
rpm-build 0fba15
callback_write_buf (const char *path, struct fuse_bufvec *buf, off_t offset,
rpm-build 0fba15
                    struct fuse_file_info *finfo)
rpm-build 0fba15
{
rpm-build 0fba15
  struct fuse_bufvec dst = FUSE_BUFVEC_INIT (fuse_buf_size (buf));
rpm-build 0fba15
rpm-build 0fba15
  dst.buf[0].flags = FUSE_BUF_IS_FD | FUSE_BUF_FD_SEEK;
rpm-build 0fba15
  dst.buf[0].fd = finfo->fh;
rpm-build 0fba15
  dst.buf[0].pos = offset;
rpm-build 0fba15
rpm-build 0fba15
  return fuse_buf_copy (&dst, buf, FUSE_BUF_SPLICE_NONBLOCK);
rpm-build 0fba15
}
rpm-build 0fba15
rpm-build 0fba15
static int
rpm-build 0fba15
callback_write (const char *path, const char *buf, size_t size, off_t offset,
rpm-build 0fba15
                struct fuse_file_info *finfo)
rpm-build 0fba15
{
rpm-build 0fba15
  int r;
rpm-build 0fba15
  r = pwrite (finfo->fh, buf, size, offset);
rpm-build 0fba15
  if (r == -1)
rpm-build 0fba15
    return -errno;
rpm-build 0fba15
  return r;
rpm-build 0fba15
}
rpm-build 0fba15
rpm-build 0fba15
static int
rpm-build 0fba15
callback_statfs (const char *path, struct statvfs *st_buf)
rpm-build 0fba15
{
rpm-build 0fba15
  if (fstatvfs (basefd, st_buf) == -1)
rpm-build 0fba15
    return -errno;
rpm-build 0fba15
  return 0;
rpm-build 0fba15
}
rpm-build 0fba15
rpm-build 0fba15
static int
rpm-build 0fba15
callback_release (const char *path, struct fuse_file_info *finfo)
rpm-build 0fba15
{
rpm-build 0fba15
  (void) close (finfo->fh);
rpm-build 0fba15
  return 0;
rpm-build 0fba15
}
rpm-build 0fba15
rpm-build 0fba15
static int
rpm-build 0fba15
callback_fsync (const char *path, int crap, struct fuse_file_info *finfo)
rpm-build 0fba15
{
rpm-build 0fba15
  if (fsync (finfo->fh) == -1)
rpm-build 0fba15
    return -errno;
rpm-build 0fba15
  return 0;
rpm-build 0fba15
}
rpm-build 0fba15
rpm-build 0fba15
static int
rpm-build 0fba15
callback_access (const char *path, int mode)
rpm-build 0fba15
{
rpm-build 0fba15
  path = ENSURE_RELPATH (path);
rpm-build 0fba15
rpm-build 0fba15
  /* Apparently at least GNU coreutils rm calls `faccessat(W_OK)`
rpm-build 0fba15
   * before trying to do an unlink.  So...we'll just lie about
rpm-build 0fba15
   * writable access here.
rpm-build 0fba15
   */
rpm-build 0fba15
  if (faccessat (basefd, path, mode, AT_SYMLINK_NOFOLLOW) == -1)
rpm-build 0fba15
    return -errno;
rpm-build 0fba15
  return 0;
rpm-build 0fba15
}
rpm-build 0fba15
rpm-build 0fba15
static int
rpm-build 0fba15
callback_setxattr (const char *path, const char *name, const char *value,
rpm-build 0fba15
                   size_t size, int flags)
rpm-build 0fba15
{
rpm-build 0fba15
  return -ENOTSUP;
rpm-build 0fba15
}
rpm-build 0fba15
rpm-build 0fba15
static int
rpm-build 0fba15
callback_getxattr (const char *path, const char *name, char *value,
rpm-build 0fba15
                   size_t size)
rpm-build 0fba15
{
rpm-build 0fba15
  return -ENOTSUP;
rpm-build 0fba15
}
rpm-build 0fba15
rpm-build 0fba15
/*
rpm-build 0fba15
 * List the supported extended attributes.
rpm-build 0fba15
 */
rpm-build 0fba15
static int
rpm-build 0fba15
callback_listxattr (const char *path, char *list, size_t size)
rpm-build 0fba15
{
rpm-build 0fba15
  return -ENOTSUP;
rpm-build 0fba15
rpm-build 0fba15
}
rpm-build 0fba15
rpm-build 0fba15
/*
rpm-build 0fba15
 * Remove an extended attribute.
rpm-build 0fba15
 */
rpm-build 0fba15
static int
rpm-build 0fba15
callback_removexattr (const char *path, const char *name)
rpm-build 0fba15
{
rpm-build 0fba15
  return -ENOTSUP;
rpm-build 0fba15
rpm-build 0fba15
}
rpm-build 0fba15
rpm-build 0fba15
struct fuse_operations callback_oper = {
rpm-build 0fba15
  .getattr = callback_getattr,
rpm-build 0fba15
  .readlink = callback_readlink,
rpm-build 0fba15
  .readdir = callback_readdir,
rpm-build 0fba15
  .mknod = callback_mknod,
rpm-build 0fba15
  .mkdir = callback_mkdir,
rpm-build 0fba15
  .symlink = callback_symlink,
rpm-build 0fba15
  .unlink = callback_unlink,
rpm-build 0fba15
  .rmdir = callback_rmdir,
rpm-build 0fba15
  .rename = callback_rename,
rpm-build 0fba15
  .link = callback_link,
rpm-build 0fba15
  .chmod = callback_chmod,
rpm-build 0fba15
  .chown = callback_chown,
rpm-build 0fba15
  .truncate = callback_truncate,
rpm-build 0fba15
  .utimens = callback_utimens,
rpm-build 0fba15
  .create = callback_create,
rpm-build 0fba15
  .open = callback_open,
rpm-build 0fba15
  .read_buf = callback_read_buf,
rpm-build 0fba15
  .read = callback_read,
rpm-build 0fba15
  .write_buf = callback_write_buf,
rpm-build 0fba15
  .write = callback_write,
rpm-build 0fba15
  .statfs = callback_statfs,
rpm-build 0fba15
  .release = callback_release,
rpm-build 0fba15
  .fsync = callback_fsync,
rpm-build 0fba15
  .access = callback_access,
rpm-build 0fba15
rpm-build 0fba15
  /* Extended attributes support for userland interaction */
rpm-build 0fba15
  .setxattr = callback_setxattr,
rpm-build 0fba15
  .getxattr = callback_getxattr,
rpm-build 0fba15
  .listxattr = callback_listxattr,
rpm-build 0fba15
  .removexattr = callback_removexattr
rpm-build 0fba15
};
rpm-build 0fba15
rpm-build 0fba15
enum {
rpm-build 0fba15
  KEY_HELP,
rpm-build 0fba15
  KEY_VERSION,
rpm-build 0fba15
  KEY_COPYUP,
rpm-build 0fba15
};
rpm-build 0fba15
rpm-build 0fba15
static void
rpm-build 0fba15
usage (const char *progname)
rpm-build 0fba15
{
rpm-build 0fba15
  fprintf (stdout,
rpm-build 0fba15
           "usage: %s basepath mountpoint [options]\n"
rpm-build 0fba15
           "\n"
rpm-build 0fba15
           "   Makes basepath visible at mountpoint such that files are read-only, directories are writable\n"
rpm-build 0fba15
           "\n"
rpm-build 0fba15
           "general options:\n"
rpm-build 0fba15
           "   -o opt,[opt...]     mount options\n"
rpm-build 0fba15
           "   -h  --help          print help\n"
rpm-build 0fba15
           "\n", progname);
rpm-build 0fba15
}
rpm-build 0fba15
rpm-build 0fba15
static int
rpm-build 0fba15
rofs_parse_opt (void *data, const char *arg, int key,
rpm-build 0fba15
                struct fuse_args *outargs)
rpm-build 0fba15
{
rpm-build 0fba15
  (void) data;
rpm-build 0fba15
rpm-build 0fba15
  switch (key)
rpm-build 0fba15
    {
rpm-build 0fba15
    case FUSE_OPT_KEY_NONOPT:
rpm-build 0fba15
      if (basefd == -1)
rpm-build 0fba15
        {
rpm-build 0fba15
          basefd = openat (AT_FDCWD, arg, O_RDONLY | O_NONBLOCK | O_DIRECTORY | O_CLOEXEC | O_NOCTTY);
rpm-build 0fba15
          if (basefd == -1)
rpm-build 0fba15
            err (1, "opening rootfs %s", arg);
rpm-build 0fba15
          return 0;
rpm-build 0fba15
        }
rpm-build 0fba15
      else
rpm-build 0fba15
        {
rpm-build 0fba15
          return 1;
rpm-build 0fba15
        }
rpm-build 0fba15
    case FUSE_OPT_KEY_OPT:
rpm-build 0fba15
      return 1;
rpm-build 0fba15
    case KEY_HELP:
rpm-build 0fba15
      usage (outargs->argv[0]);
rpm-build 0fba15
      exit (EXIT_SUCCESS);
rpm-build 0fba15
    case KEY_COPYUP:
rpm-build 0fba15
      opt_copyup = TRUE;
rpm-build 0fba15
      return 0;
rpm-build 0fba15
    default:
rpm-build 0fba15
      fprintf (stderr, "see `%s -h' for usage\n", outargs->argv[0]);
rpm-build 0fba15
      exit (EXIT_FAILURE);
rpm-build 0fba15
    }
rpm-build 0fba15
  return 1;
rpm-build 0fba15
}
rpm-build 0fba15
rpm-build 0fba15
static struct fuse_opt rofs_opts[] = {
rpm-build 0fba15
  FUSE_OPT_KEY ("-h", KEY_HELP),
rpm-build 0fba15
  FUSE_OPT_KEY ("--help", KEY_HELP),
rpm-build 0fba15
  FUSE_OPT_KEY ("-V", KEY_VERSION),
rpm-build 0fba15
  FUSE_OPT_KEY ("--version", KEY_VERSION),
rpm-build 0fba15
  FUSE_OPT_KEY ("--copyup", KEY_COPYUP),
rpm-build 0fba15
  FUSE_OPT_END
rpm-build 0fba15
};
rpm-build 0fba15
rpm-build 0fba15
int
rpm-build 0fba15
main (int argc, char *argv[])
rpm-build 0fba15
{
rpm-build 0fba15
  struct fuse_args args = FUSE_ARGS_INIT (argc, argv);
rpm-build 0fba15
  int res;
rpm-build 0fba15
rpm-build 0fba15
  res = fuse_opt_parse (&args, &basefd, rofs_opts, rofs_parse_opt);
rpm-build 0fba15
  if (res != 0)
rpm-build 0fba15
    {
rpm-build 0fba15
      fprintf (stderr, "Invalid arguments\n");
rpm-build 0fba15
      fprintf (stderr, "see `%s -h' for usage\n", argv[0]);
rpm-build 0fba15
      exit (EXIT_FAILURE);
rpm-build 0fba15
    }
rpm-build 0fba15
  if (basefd == -1)
rpm-build 0fba15
    {
rpm-build 0fba15
      fprintf (stderr, "Missing basepath\n");
rpm-build 0fba15
      fprintf (stderr, "see `%s -h' for usage\n", argv[0]);
rpm-build 0fba15
      exit (EXIT_FAILURE);
rpm-build 0fba15
    }
rpm-build 0fba15
rpm-build 0fba15
  fuse_main (args.argc, args.argv, &callback_oper, NULL);
rpm-build 0fba15
rpm-build 0fba15
  return 0;
rpm-build 0fba15
}