libperfuse(3) is a PUFFS relay to FUSE. In order to use it,

FUSE filesystem must be patched to #include <perfuse.h> in the source
files that open /dev/fuse and perform the mount(2) system call. The
FUSE filesystem must be linked with -lperfuse.

libperfuse(3) implements the FUSE kernel interface, on which libfuse or
any FUSE filesystem that opens /dev/fuse directly can be used.

For now, an external daemon called perfused(8) is used. This may change
in the future.
This commit is contained in:
manu 2010-08-25 07:16:00 +00:00
parent 3a12eae410
commit 7b1d1ee680
11 changed files with 3895 additions and 0 deletions

14
lib/libperfuse/Makefile Normal file
View File

@ -0,0 +1,14 @@
LIB= perfuse
LIBDPLIBS+= puffs /usr/src/lib/libpuffs
PERFUSE_OPT_DEBUG_FLAGS= -g -DPERFUSE_DEBUG
CFLAGS+= ${PERFUSE_OPT_DEBUG_FLAGS}
SRCS= perfuse.c ops.c subr.c debug.c
MAN= libperfuse.3
WARNS= 4
INCS= perfuse.h
INCSDIR= /usr/include
.include <bsd.lib.mk>

94
lib/libperfuse/debug.c Normal file
View File

@ -0,0 +1,94 @@
/* $NetBSD: debug.c,v 1.1 2010/08/25 07:16:00 manu Exp $ */
/*-
* Copyright (c) 2010 Emmanuel Dreyfus. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
* ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
#include <puffs.h>
#include <sys/types.h>
#include "perfuse_if.h"
#include "fuse.h"
struct perfuse_opcode {
int opcode;
const char *opname;
};
const struct perfuse_opcode perfuse_opcode[] = {
{ FUSE_LOOKUP, "LOOKUP" },
{ FUSE_FORGET, "FORGET" },
{ FUSE_GETATTR, "GETATTR" },
{ FUSE_SETATTR, "SETATTR" },
{ FUSE_READLINK, "READLINK" },
{ FUSE_SYMLINK, "SYMLINK" },
{ FUSE_MKNOD, "MKNOD" },
{ FUSE_MKDIR, "MKDIR" },
{ FUSE_UNLINK, "UNLINK" },
{ FUSE_RMDIR, "RMDIR" },
{ FUSE_RENAME, "RENAME" },
{ FUSE_LINK, "LINK" },
{ FUSE_OPEN, "OPEN" },
{ FUSE_READ, "READ" },
{ FUSE_WRITE, "WRITE" },
{ FUSE_STATFS, "STATFS" },
{ FUSE_RELEASE, "RELEASE" },
{ FUSE_FSYNC, "FSYNC" },
{ FUSE_SETXATTR, "SETXATTR" },
{ FUSE_GETXATTR, "GETXATTR" },
{ FUSE_LISTXATTR, "LISTXATTR" },
{ FUSE_REMOVEXATTR, "REMOVEXATTR" },
{ FUSE_FLUSH, "FLUSH" },
{ FUSE_INIT, "INIT" },
{ FUSE_OPENDIR, "OPENDIR" },
{ FUSE_READDIR, "READDIR" },
{ FUSE_RELEASEDIR, "RELEASEDIR" },
{ FUSE_FSYNCDIR, "FSYNCDIR" },
{ FUSE_GETLK, "GETLK" },
{ FUSE_SETLK, "SETLK" },
{ FUSE_SETLKW, "SETLKW" },
{ FUSE_ACCESS, "ACCESS" },
{ FUSE_CREATE, "CREATE" },
{ FUSE_INTERRUPT, "INTERRUPT" },
{ FUSE_BMAP, "BMAP" },
{ FUSE_DESTROY, "DESTROY" },
{ FUSE_IOCTL, "IOCTL" },
{ FUSE_POLL, "POLL" },
{ FUSE_CUSE_INIT, "CUSE_INIT" },
{ 0, "UNKNOWN" },
};
const char *
perfuse_opname(opcode)
int opcode;
{
const struct perfuse_opcode *po;
for (po = perfuse_opcode; po->opcode; po++) {
if (po->opcode == opcode)
return po->opname;
}
return po->opname; /* "UNKNOWN" */
}

496
lib/libperfuse/fuse.h Normal file
View File

@ -0,0 +1,496 @@
/* $NetBSD: fuse.h,v 1.1 2010/08/25 07:16:00 manu Exp $ */
/*-
* Copyright (c) 2010 Emmanuel Dreyfus. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
* ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef _FUSE_H
#define _FUSE_H
#define FUSE_KERNEL_VERSION 7
#define FUSE_KERNEL_MINOR_VERSION 12
#define FUSE_ROOT_ID 1
#define FUSE_UNKNOWN_FH (uint64_t)0
#define FUSE_MIN_BUFSIZE 0x21000
#define FUSE_PREF_BUFSIZE (PAGE_SIZE + 0x1000)
#define FUSE_BUFSIZE MAX(FUSE_PREF_BUFSIZE, FUSE_MIN_BUFSIZE)
struct fuse_attr {
uint64_t ino;
uint64_t size;
uint64_t blocks;
uint64_t atime;
uint64_t mtime;
uint64_t ctime;
uint32_t atimensec;
uint32_t mtimensec;
uint32_t ctimensec;
uint32_t mode;
uint32_t nlink;
uint32_t uid;
uint32_t gid;
uint32_t rdev;
uint32_t blksize;
uint32_t padding;
};
struct fuse_kstatfs {
uint64_t blocks;
uint64_t bfree;
uint64_t bavail;
uint64_t files;
uint64_t ffree;
uint32_t bsize;
uint32_t namelen;
uint32_t frsize;
uint32_t padding;
uint32_t spare[6];
};
struct fuse_file_lock {
uint64_t start;
uint64_t end;
uint32_t type;
uint32_t pid;
};
/*
* Various flags
*/
#define FUSE_FATTR_MODE 0x0001
#define FUSE_FATTR_UID 0x0002
#define FUSE_FATTR_GID 0x0004
#define FUSE_FATTR_SIZE 0x0008
#define FUSE_FATTR_ATIME 0x0010
#define FUSE_FATTR_MTIME 0x0020
#define FUSE_FATTR_FH 0x0040
#define FUSE_FATTR_ATIME_NOW 0x0080
#define FUSE_FATTR_MTIME_NOW 0x0100
#define FUSE_FATTR_LOCKOWNER 0x0200
#define FUSE_FOPEN_DIRECT_IO 0x0001
#define FUSE_FOPEN_KEEP_CACHE 0x0002
#define FUSE_FOPEN_NONSEEKABLE 0x0004
#define FUSE_ASYNC_READ 0x0001
#define FUSE_POSIX_LOCKS 0x0002
#define FUSE_FILE_OPS 0x0004
#define FUSE_ATOMIC_O_TRUNC 0x0008
#define FUSE_EXPORT_SUPPORT 0x0010
#define FUSE_BIG_WRITES 0x0020
#define FUSE_DONT_MASK 0x0040
#define FUSE_CUSE_UNRESTRICTED_IOCTL 0x0001
#define FUSE_RELEASE_FLUSH 0x0001
#define FUSE_GETATTR_FH 0x0001
#define FUSE_LK_FLOCK 0x0001
#define FUSE_WRITE_CACHE 0x0001
#define FUSE_WRITE_LOCKOWNER 0x0002
#define FUSE_READ_LOCKOWNER 0x0002
#define FUSE_IOCTL_COMPAT 0x0001
#define FUSE_IOCTL_UNRESTRICTED 0x0002
#define FUSE_IOCTL_RETRY 0x0004
#define FUSE_IOCTL_MAX_IOV 256
#define FUSE_POLL_SCHEDULE_NOTIFY 0x0001
enum fuse_opcode {
FUSE_LOOKUP = 1,
FUSE_FORGET = 2,
FUSE_GETATTR = 3,
FUSE_SETATTR = 4,
FUSE_READLINK = 5,
FUSE_SYMLINK = 6,
FUSE_MKNOD = 8,
FUSE_MKDIR = 9,
FUSE_UNLINK = 10,
FUSE_RMDIR = 11,
FUSE_RENAME = 12,
FUSE_LINK = 13,
FUSE_OPEN = 14,
FUSE_READ = 15,
FUSE_WRITE = 16,
FUSE_STATFS = 17,
FUSE_RELEASE = 18,
FUSE_FSYNC = 20,
FUSE_SETXATTR = 21,
FUSE_GETXATTR = 22,
FUSE_LISTXATTR = 23,
FUSE_REMOVEXATTR = 24,
FUSE_FLUSH = 25,
FUSE_INIT = 26,
FUSE_OPENDIR = 27,
FUSE_READDIR = 28,
FUSE_RELEASEDIR = 29,
FUSE_FSYNCDIR = 30,
FUSE_GETLK = 31,
FUSE_SETLK = 32,
FUSE_SETLKW = 33,
FUSE_ACCESS = 34,
FUSE_CREATE = 35,
FUSE_INTERRUPT = 36,
FUSE_BMAP = 37,
FUSE_DESTROY = 38,
FUSE_IOCTL = 39,
FUSE_POLL = 40,
FUSE_CUSE_INIT = 4096
};
enum fuse_notify_code {
FUSE_NOTIFY_POLL = 1,
FUSE_NOTIFY_INVAL_INODE = 2,
FUSE_NOTIFY_INVAL_ENTRY = 3,
FUSE_NOTIFY_CODE_MAX
};
#define FUSE_MIN_READ_BUFFER 8192
#define FUSE_COMPAT_ENTRY_OUT_SIZE 120
struct fuse_entry_out {
uint64_t nodeid;
uint64_t generation;
uint64_t entry_valid;
uint64_t attr_valid;
uint32_t entry_valid_nsec;
uint32_t attr_valid_nsec;
struct fuse_attr attr;
};
struct fuse_forget_in {
uint64_t nlookup;
};
struct fuse_getattr_in {
uint32_t getattr_flags;
uint32_t dummy;
uint64_t fh;
};
#define FUSE_COMPAT_ATTR_OUT_SIZE 96
struct fuse_attr_out {
uint64_t attr_valid;
uint32_t attr_valid_nsec;
uint32_t dummy;
struct fuse_attr attr;
};
#define FUSE_COMPAT_MKNOD_IN_SIZE 8
struct fuse_mknod_in {
uint32_t mode;
uint32_t rdev;
uint32_t umask;
uint32_t padding;
};
struct fuse_mkdir_in {
uint32_t mode;
uint32_t umask;
};
struct fuse_rename_in {
uint64_t newdir;
};
struct fuse_link_in {
uint64_t oldnodeid;
};
struct fuse_setattr_in {
uint32_t valid;
uint32_t padding;
uint64_t fh;
uint64_t size;
uint64_t lock_owner;
uint64_t atime;
uint64_t mtime;
uint64_t unused2;
uint32_t atimensec;
uint32_t mtimensec;
uint32_t unused3;
uint32_t mode;
uint32_t unused4;
uint32_t uid;
uint32_t gid;
uint32_t unused5;
};
struct fuse_open_in {
uint32_t flags;
uint32_t unused;
};
struct fuse_create_in {
uint32_t flags;
uint32_t mode;
uint32_t umask;
uint32_t padding;
};
struct fuse_open_out {
uint64_t fh;
uint32_t open_flags; /* FUSE_FOPEN_ */
uint32_t padding;
};
struct fuse_release_in {
uint64_t fh;
uint32_t flags;
uint32_t release_flags;
uint64_t lock_owner;
};
struct fuse_flush_in {
uint64_t fh;
uint32_t unused;
uint32_t padding;
uint64_t lock_owner;
};
struct fuse_read_in {
uint64_t fh;
uint64_t offset;
uint32_t size;
uint32_t read_flags;
uint64_t lock_owner;
uint32_t flags;
uint32_t padding;
};
#define FUSE_COMPAT_WRITE_IN_SIZE 24
struct fuse_write_in {
uint64_t fh;
uint64_t offset;
uint32_t size;
uint32_t write_flags;
uint64_t lock_owner;
uint32_t flags;
uint32_t padding;
};
struct fuse_write_out {
uint32_t size;
uint32_t padding;
};
#define FUSE_COMPAT_STATFS_SIZE 48
struct fuse_statfs_out {
struct fuse_kstatfs st;
};
struct fuse_fsync_in {
uint64_t fh;
uint32_t fsync_flags;
uint32_t padding;
};
struct fuse_setxattr_in {
uint32_t size;
uint32_t flags;
};
struct fuse_getxattr_in {
uint32_t size;
uint32_t padding;
};
struct fuse_getxattr_out {
uint32_t size;
uint32_t padding;
};
struct fuse_lk_in {
uint64_t fh;
uint64_t owner;
struct fuse_file_lock lk;
uint32_t lk_flags;
uint32_t padding;
};
struct fuse_lk_out {
struct fuse_file_lock lk;
};
struct fuse_access_in {
uint32_t mask;
uint32_t padding;
};
struct fuse_init_in {
uint32_t major;
uint32_t minor;
uint32_t max_readahead;
uint32_t flags;
};
struct fuse_init_out {
uint32_t major;
uint32_t minor;
uint32_t max_readahead;
uint32_t flags;
uint32_t unused;
uint32_t max_write;
};
#define FUSE_CUSE_INIT_INFO_MAX 4096
struct fuse_cuse_init_in {
uint32_t major;
uint32_t minor;
uint32_t unused;
uint32_t flags;
};
struct fuse_cuse_init_out {
uint32_t major;
uint32_t minor;
uint32_t unused;
uint32_t flags;
uint32_t max_read;
uint32_t max_write;
uint32_t dev_major; /* chardev major */
uint32_t dev_minor; /* chardev minor */
uint32_t spare[10];
};
struct fuse_interrupt_in {
uint64_t unique;
};
struct fuse_bmap_in {
uint64_t block;
uint32_t blocksize;
uint32_t padding;
};
struct fuse_bmap_out {
uint64_t block;
};
struct fuse_ioctl_in {
uint64_t fh;
uint32_t flags;
uint32_t cmd;
uint64_t arg;
uint32_t in_size;
uint32_t out_size;
};
struct fuse_ioctl_out {
int32_t result;
uint32_t flags;
uint32_t in_iovs;
uint32_t out_iovs;
};
struct fuse_poll_in {
uint64_t fh;
uint64_t kh;
uint32_t flags;
uint32_t padding;
};
struct fuse_poll_out {
uint32_t revents;
uint32_t padding;
};
struct fuse_notify_poll_wakeup_out {
uint64_t kh;
};
#if 0 /* Duplicated in perfuse.h to avoid making fuse.h public */
/* Send from kernel to proces */
struct fuse_in_header {
uint32_t len;
uint32_t opcode;
uint64_t unique;
uint64_t nodeid;
uint32_t uid;
uint32_t gid;
uint32_t pid;
uint32_t padding;
};
struct fuse_in_arg {
uint32_t size;
const void *value;
};
struct fuse_in {
struct fuse_in_header h;
uint32_t argpages:1; /* Req fits in a page? Always 1 */
uint32_t numargs;
struct fuse_in_arg args[3]; /* args copied to userspace */
};
/* From process to kernel */
struct fuse_out_header {
uint32_t len;
int32_t error;
uint64_t unique;
};
#endif
struct fuse_dirent {
uint64_t ino;
uint64_t off; /* offset of next field from after foh */
uint32_t namelen;
uint32_t type;
char name[0];
};
#define FUSE_NAME_OFFSET offsetof(struct fuse_dirent, name)
#define FUSE_DIRENT_ALIGN(x) \
(((x) + sizeof(uint64_t) - 1) & ~(sizeof(uint64_t) - 1))
#define FUSE_DIRENT_SIZE(d) \
FUSE_DIRENT_ALIGN(FUSE_NAME_OFFSET + (d)->namelen)
struct fuse_notify_inval_inode_out {
uint64_t ino;
int64_t off;
int64_t len;
};
struct fuse_notify_inval_entry_out {
uint64_t parent;
uint32_t namelen;
uint32_t padding;
};
#endif /* _FUSE_H */

117
lib/libperfuse/libperfuse.3 Normal file
View File

@ -0,0 +1,117 @@
.\" $NetBSD: libperfuse.3,v 1.1 2010/08/25 07:16:00 manu Exp $
.\"
.\" Copyright (c) 2010 Emmanuel Dreyfus. All rights reserved.
.\"
.\" Redistribution and use in source and binary forms, with or without
.\" modification, are permitted provided that the following conditions
.\" are met:
.\" 1. Redistributions of source code must retain the above copyright
.\" notice, this list of conditions and the following disclaimer.
.\" 2. Redistributions in binary form must reproduce the above copyright
.\" notice, this list of conditions and the following disclaimer in the
.\" documentation and/or other materials provided with the distribution.
.\"
.\" THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
.\" ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
.\" TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
.\" PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
.\" BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
.\" CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
.\" SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
.\" INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
.\" CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
.\" ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
.\" POSSIBILITY OF SUCH DAMAGE.
.\"
.ds str-Lb-libperfuse PUFFS enabled relay to FUSE Library (libperfuse, \-lperfuse)
.Dd August 12, 2010
.Dt LIBPERFUSE 2
.Os
.Sh NAME
.Nm perfuse_mount ,
.Nm perfuse_open
.Nd Request a
.Xr puffs 3 mount from
.Xr perfused 8 .
.Sh LIBRARY
.Lb libperfuse
.Sh SYNOPSIS
.In perfuse.h
.Ft int
.Fn perfuse_mount "const char *source" "const char *dir" "const char *filesystemtype" "long int mountflags" "void *data"
.Ft int
.Fn perfuse_open "const char *path" "int flags"
.Sh DESCRIPTION
.Fn perfuse_mount
sends a mount request to
.Xr perfused 8 .
It is intended as a drop-in replacement for
.Xr mount 2
for FUSE filesystems daemons and libraries, so that they can work with
.Xr perfused 8 .
.Pp
The function prototype mimics Linux's
.Xr mount 2 ,
with the following arguments:
.Bl -tag -width indent
.It Ar source
The source fileystem that will appear in
.Xr df 1 ,
and
.Xr mount 8
listings. Defaults to
.Pa /dev/fuse
if NULL.
.It Ar dir
The filesystem mount point.
.It Ar filesystemtype
The gileystem type, as displayed by
.Xr df 1 ,
and
.Xr mount 8 .
Defaults to "fuse"
if NULL.
.It Ar mountflags
This contains the same value as in
.Xr mount 2
.Ar flags
argument.
.It Ar data
This contains the same value as in
.Xr mount 2
.Ar data
argument.
.El
.Pp
.Fn perfuse_open
is a drop-in replacement for the
.Xr open 2
system call where
.Pa /dev/fuse
is used. If
.Ar path
is different than
.Pa /dev/fuse ,
.Fn perfuse_open
handles control to the regular
.Xr open 2 .
.Sh RETURN VALUES
.Fn perfuse_mount
returns a file descriptor to the
.Pa /dev/fuse
socket on success, and cause exit on failure.
.Sh ERRORS
.Fn perfuse_mount
will fail when one of the following occurs:
.Bl -tag -width Er
.El
.Sh SEE ALSO
.Xd df 1 ,
.Xr mount 2 ,
.Xr open 2 ,
.Xr mount 8 ,
.Xr perfused 8
.Sh AUTHORS
The program was written by
.An Emmanuel Dreyfus
.Aq manu@NetBSD.org .

2133
lib/libperfuse/ops.c Normal file

File diff suppressed because it is too large Load Diff

416
lib/libperfuse/perfuse.c Normal file
View File

@ -0,0 +1,416 @@
/* $NetBSD: perfuse.c,v 1.1 2010/08/25 07:16:00 manu Exp $ */
/*-
* Copyright (c) 2010 Emmanuel Dreyfus. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
* ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <fcntl.h>
#include <string.h>
#include <errno.h>
#include <puffs.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/un.h>
#define LIBPERFUSE
#include "perfuse.h"
#include "perfuse_if.h"
#include "perfuse_priv.h"
int perfuse_diagflags = 0; /* global used only in DPRINTF/DERR/DWARN */
static struct perfuse_state *init_state(void);
static int get_fd(const char *);
static struct perfuse_state *
init_state(void)
{
struct perfuse_state *ps;
if ((ps = malloc(sizeof(*ps))) == NULL)
DERR(EX_OSERR, "malloc failed");
(void)memset(ps, 0, sizeof(*ps));
ps->ps_max_write = UINT_MAX;
ps->ps_max_readahead = UINT_MAX;
return ps;
}
static int
get_fd(data)
const char *data;
{
char *string;
const char fdopt[] = "fd=";
char *lastp;
char *opt;
int fd = -1;
if ((string = strdup(data)) == NULL)
return -1;
for (opt = strtok_r(string, ",", &lastp);
opt != NULL;
opt = strtok_r(NULL, ",", &lastp)) {
if (strncmp(opt, fdopt, strlen(fdopt)) == 0) {
fd = atoi(opt + strlen(fdopt));
break;
}
}
/*
* No file descriptor found
*/
if (fd == -1)
errno = EINVAL;
free(string);
return fd;
}
int
perfuse_open(path, flags, mode)
const char *path;
int flags;
mode_t mode;
{
int s;
struct sockaddr_un sun;
struct sockaddr *sa;
if (strcmp(path, _PATH_FUSE) != 0)
return open(path, flags, mode);
if ((s = socket(PF_LOCAL, SOCK_STREAM, 0)) == -1) {
#ifdef PERFUSE_DEBUG
printf("%s:%d socket failed: %s",
__func__, __LINE__, strerror(errno));
#endif
return -1;
}
sa = (struct sockaddr *)(void *)&sun;
sun.sun_len = sizeof(sun);
sun.sun_family = AF_LOCAL;
(void)strcpy(sun.sun_path, path);
if (connect(s, sa, (socklen_t)sun.sun_len) == -1) {
#ifdef PERFUSE_DEBUG
printf("%s:%d connect failed: %s",
__func__, __LINE__, strerror(errno));
#endif
close(s);
return -1;
}
return s;
}
int
perfuse_mount(source, target, filesystemtype, mountflags, data)
const char *source;
const char *target;
const char *filesystemtype;
long mountflags;
const void *data;
{
int s;
#if 0
struct sockaddr_un sun;
#endif
size_t len;
struct perfuse_mount_out pmo;
#ifdef PERFUSE_DEBUG
printf("%s(\"%s\", \"%s\", \"%s\", 0x%lx, \"%s\")\n", __func__,
source, target, filesystemtype, mountflags, (const char *)data);
#endif
#if 0
if ((s = socket(PF_LOCAL, SOCK_STREAM, 0)) == -1)
err(EX_OSERR, "socket failed");
sun.sun_len = sizeof(sun);
sun.sun_family = AF_LOCAL;
(void)strcpy(sun.sun_path, _PATH_FUSE);
if (connect(s, (struct sockaddr *)&sun, sun.sun_len) == -1)
err(EX_UNAVAILABLE, "cannot connect to \"%s\"", _PATH_FUSE);
#endif
if ((s = get_fd(data)) == -1)
return -1;
pmo.pmo_len = sizeof(pmo);
pmo.pmo_len += source ? strlen(source) : 0;
pmo.pmo_len += target ? strlen(target) : 0;
pmo.pmo_len += filesystemtype ? strlen(filesystemtype) : 0;
pmo.pmo_len += data ? strlen(data) : 0;
pmo.pmo_error = 0;
pmo.pmo_unique = (uint64_t)-1;
(void)strcpy(pmo.pmo_magic, PERFUSE_MOUNT_MAGIC);
pmo.pmo_source_len = source ? strlen(source) : 0;
pmo.pmo_target_len = target ? strlen(target) : 0;
pmo.pmo_filesystemtype_len =
filesystemtype ? strlen(filesystemtype) : 0;
pmo.pmo_mountflags = mountflags;
pmo.pmo_data_len = data ? strlen(data) : 0;
if (write(s, &pmo, sizeof(pmo)) != sizeof(pmo)) {
#ifdef PERFUSE_DEBUG
printf("%s:%d short write", __func__, __LINE__);
#endif
return -1;
}
if (source) {
len = pmo.pmo_source_len;
if (write(s, source, len) != (ssize_t)len) {
#ifdef PERFUSE_DEBUG
printf("%s:%d short write", __func__, __LINE__);
#endif
return -1;
}
}
if (target) {
len = pmo.pmo_target_len;
if (write(s, target, len) != (ssize_t)len) {
#ifdef PERFUSE_DEBUG
printf("%s:%d short write", __func__, __LINE__);
#endif
return -1;
}
}
if (filesystemtype) {
len = pmo.pmo_filesystemtype_len;
if (write(s, filesystemtype, len) != (ssize_t)len) {
#ifdef PERFUSE_DEBUG
printf("%s:%d short write", __func__, __LINE__);
#endif
return -1;
}
}
if (data) {
len = pmo.pmo_data_len;
if (write(s, data, len) != (ssize_t)len) {
#ifdef PERFUSE_DEBUG
printf("%s:%d short write", __func__, __LINE__);
#endif
return -1;
}
}
return 0;
}
uint64_t
perfuse_next_unique(pu)
struct puffs_usermount *pu;
{
struct perfuse_state *ps;
ps = puffs_getspecific(pu);
return ps->ps_unique++;
}
struct puffs_usermount *
perfuse_init(pc, pmi)
struct perfuse_callbacks *pc;
struct perfuse_mount_info *pmi;
{
struct perfuse_state *ps;
struct puffs_usermount *pu;
struct puffs_ops *pops;
char name[] = "perfuse";
unsigned int puffs_flags;
struct puffs_node *pn_root;
struct puffs_pathobj *po_root;
ps = init_state();
ps->ps_uid = pmi->pmi_uid;
if (pmi->pmi_source)
ps->ps_source = strdup(pmi->pmi_source);
if (pmi->pmi_filesystemtype)
ps->ps_filesystemtype = strdup(pmi->pmi_filesystemtype);
ps->ps_target = strdup(pmi->pmi_target);
ps->ps_mountflags = pmi->pmi_mountflags;
/*
* Some options are forbidden for non root users
*/
if (ps->ps_uid != 0)
ps->ps_mountflags |= MNT_NOSUID|MNT_NODEV;
PUFFSOP_INIT(pops);
PUFFSOP_SET(pops, perfuse, fs, unmount);
PUFFSOP_SET(pops, perfuse, fs, statvfs);
PUFFSOP_SET(pops, perfuse, fs, sync);
PUFFSOP_SET(pops, perfuse, node, lookup);
PUFFSOP_SET(pops, perfuse, node, create);
PUFFSOP_SET(pops, perfuse, node, mknod);
PUFFSOP_SET(pops, perfuse, node, open);
PUFFSOP_SET(pops, perfuse, node, close);
PUFFSOP_SET(pops, perfuse, node, access);
PUFFSOP_SET(pops, perfuse, node, getattr);
PUFFSOP_SET(pops, perfuse, node, setattr);
PUFFSOP_SET(pops, perfuse, node, poll);
#if 0
PUFFSOP_SET(pops, perfuse, node, mmap);
#endif
PUFFSOP_SET(pops, perfuse, node, fsync);
PUFFSOP_SET(pops, perfuse, node, seek);
PUFFSOP_SET(pops, perfuse, node, remove);
PUFFSOP_SET(pops, perfuse, node, link);
PUFFSOP_SET(pops, perfuse, node, rename);
PUFFSOP_SET(pops, perfuse, node, mkdir);
PUFFSOP_SET(pops, perfuse, node, rmdir);
PUFFSOP_SET(pops, perfuse, node, symlink);
PUFFSOP_SET(pops, perfuse, node, readdir);
PUFFSOP_SET(pops, perfuse, node, readlink);
PUFFSOP_SET(pops, perfuse, node, reclaim);
PUFFSOP_SET(pops, perfuse, node, inactive);
PUFFSOP_SET(pops, perfuse, node, print);
PUFFSOP_SET(pops, perfuse, node, advlock);
PUFFSOP_SET(pops, perfuse, node, read);
PUFFSOP_SET(pops, perfuse, node, write);
puffs_flags = PUFFS_FLAG_BUILDPATH | PUFFS_FLAG_HASHPATH;
if (perfuse_diagflags & PDF_PUFFS)
puffs_flags |= PUFFS_FLAG_OPDUMP;
if ((pu = puffs_init(pops, _PATH_PUFFS, name, ps, puffs_flags)) == NULL)
DERR(EX_OSERR, "puffs_init failed");
ps->ps_pu = pu;
/*
* Setup filesystem root
*/
pn_root = perfuse_new_pn(pu, NULL);
PERFUSE_NODE_DATA(pn_root)->pnd_ino = FUSE_ROOT_ID;
puffs_setroot(pu, pn_root);
ps->ps_fsid = pn_root->pn_va.va_fsid;
po_root = puffs_getrootpathobj(pu);
if ((po_root->po_path = strdup("/")) == NULL)
DERRX(EX_OSERR, "perfuse_mount_start() failed");
po_root->po_len = 1;
puffs_path_buildhash(pu, po_root);
puffs_vattr_null(&pn_root->pn_va);
pn_root->pn_va.va_type = VDIR;
pn_root->pn_va.va_mode = 0755;
ps->ps_root = pn_root;
/*
* Callbacks
*/
ps->ps_new_msg = pc->pc_new_msg;
ps->ps_xchg_msg = pc->pc_xchg_msg;
ps->ps_destroy_msg = pc->pc_destroy_msg;
ps->ps_get_inhdr = pc->pc_get_inhdr;
ps->ps_get_inpayload = pc->pc_get_inpayload;
ps->ps_get_outhdr = pc->pc_get_outhdr;
ps->ps_get_outpayload = pc->pc_get_outpayload;
return pu;
}
void
perfuse_setspecific(pu, priv)
struct puffs_usermount *pu;
void *priv;
{
struct perfuse_state *ps;
ps = puffs_getspecific(pu);
ps->ps_private = priv;
return;
}
void *
perfuse_getspecific(pu)
struct puffs_usermount *pu;
{
struct perfuse_state *ps;
ps = puffs_getspecific(pu);
return ps->ps_private;
}
int
perfuse_inloop(pu)
struct puffs_usermount *pu;
{
struct perfuse_state *ps;
ps = puffs_getspecific(pu);
return ps->ps_flags & PS_INLOOP;
}
int
perfuse_mainloop(pu)
struct puffs_usermount *pu;
{
struct perfuse_state *ps;
ps = puffs_getspecific(pu);
ps->ps_flags |= PS_INLOOP;
if (puffs_mainloop(ps->ps_pu) != 0)
DERR(EX_OSERR, "puffs_mainloop failed");
DERR(EX_OSERR, "puffs_mainloop exit");
/* NOTREACHED */
return -1;
}
/* ARGSUSED0 */
uint64_t
perfuse_get_ino(pu, opc)
struct puffs_usermount *pu;
puffs_cookie_t opc;
{
return PERFUSE_NODE_DATA(opc)->pnd_ino;
}

45
lib/libperfuse/perfuse.h Normal file
View File

@ -0,0 +1,45 @@
/* $NetBSD: perfuse.h,v 1.1 2010/08/25 07:16:00 manu Exp $ */
/*-
* Copyright (c) 2010 Emmanuel Dreyfus. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
* ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef _REFUSE_PERFUSE_WRAPPER_H
#define _REFUSE_PERFUSE_WRAPPER_H
__BEGIN_DECLS
int perfuse_open(const char *, int, mode_t);
int perfuse_mount(const char *, const char *, const char *, long, const void *);
__END_DECLS
#ifndef LIBPERFUSE
#define mount(source, mnt, type, flags, optbuf) \
perfuse_mount(source, mnt, type, flags, optbuf)
#define open(path, flags) \
perfuse_open(path, flags, 0)
#endif /* LIBPERFUSE */
#endif /* _REFUSE_PERFUSE_WRAPPER_H */

201
lib/libperfuse/perfuse_if.h Normal file
View File

@ -0,0 +1,201 @@
/* $NetBSD: perfuse_if.h,v 1.1 2010/08/25 07:16:00 manu Exp $ */
/*-
* Copyright (c) 2010 Emmanuel Dreyfus. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
* ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef _REFUSE_PERFUSE_H
#define _REFUSE_PERFUSE_H
#define _PATH_FUSE "/dev/fuse"
#define FUSE_COMMFD_ENV "_FUSE_COMMFD"
#define PERFUSE_MOUNT_MAGIC "noFuseRq"
#define PERFUSE_UNKNOWN_INO 0xffffffff
/*
* Diagnostic flags. This global is used only for DPRINTF/DERR/DWARN
*/
extern int perfuse_diagflags;
#define PDF_FOREGROUND 0x001 /* we run in foreground */
#define PDF_FUSE 0x002 /* Display FUSE reqeusts and reply */
#define PDF_DUMP 0x004 /* Dump FUSE frames */
#define PDF_PUFFS 0x008 /* Display PUFFS requets and reply */
#define PDF_FH 0x010 /* File handles */
#define PDF_RECLAIM 0x020 /* Reclaimed files */
#define PDF_READDIR 0x040 /* readdir operations */
#define PDF_REQUEUE 0x080 /* reueued messages */
#define PDF_MISC 0x100 /* Miscelaneous messages */
#define PDF_SYSLOG 0x200 /* use syslog */
/*
* Diagnostic functions
*/
#define DPRINTF(fmt, ...) do { \
if (perfuse_diagflags & PDF_FOREGROUND) \
(void)printf(fmt, ## __VA_ARGS__); \
} while (0 /* CONSTCOND */)
#define DERRX(status, fmt, ...) do { \
if (perfuse_diagflags & PDF_SYSLOG) \
syslog(LOG_ERR, fmt, ## __VA_ARGS__); \
\
if (perfuse_diagflags & PDF_FOREGROUND) { \
(void)fprintf(stderr, fmt, ## __VA_ARGS__); \
abort(); \
} else { \
errx(status, fmt, ## __VA_ARGS__); \
} \
} while (0 /* CONSTCOND */)
#define DERR(status, fmt, ...) do { \
char fmterr[BUFSIZ]; \
char strerrbuf[BUFSIZ]; \
\
(void)strerror_r(errno, strerrbuf, sizeof(strerrbuf)); \
(void)sprintf(fmterr, "%s: %s\n", fmt, strerrbuf); \
\
if (perfuse_diagflags & PDF_SYSLOG) \
syslog(LOG_ERR, fmterr, ## __VA_ARGS__); \
\
if (perfuse_diagflags & PDF_FOREGROUND) { \
(void)fprintf(stderr, fmterr, ## __VA_ARGS__); \
abort(); \
} else { \
errx(status, fmt, ## __VA_ARGS__); \
} \
} while (0 /* CONSTCOND */)
#define DWARNX(fmt, ...) do { \
if (perfuse_diagflags & PDF_SYSLOG) \
syslog(LOG_WARNING, fmt, ## __VA_ARGS__); \
\
warnx(fmt, ## __VA_ARGS__); \
} while (0 /* CONSTCOND */)
#define DWARN(fmt, ...) do { \
char fmterr[BUFSIZ]; \
char strerrbuf[BUFSIZ]; \
\
(void)strerror_r(errno, strerrbuf, sizeof(strerrbuf)); \
(void)sprintf(fmterr, "%s: %s\n", fmt, strerrbuf); \
\
if (perfuse_diagflags & PDF_SYSLOG) \
syslog(LOG_WARNING, fmterr, ## __VA_ARGS__); \
\
warn(fmterr, ## __VA_ARGS__); \
} while (0 /* CONSTCOND */)
/*
* frame handling callbacks
*/
#ifndef PEFUSE_MSG_T
#define PEFUSE_MSG_T struct perfuse_framebuf
#endif
typedef PEFUSE_MSG_T perfuse_msg_t;
#define PERFUSE_UNSPEC_REPLY_LEN (size_t)-1
enum perfuse_xchg_pb_reply { wait_reply, no_reply };
typedef perfuse_msg_t *(*perfuse_new_msg_fn)(struct puffs_usermount *,
puffs_cookie_t, int, size_t, const struct puffs_cred *);
typedef int (*perfuse_xchg_msg_fn)(struct puffs_usermount *,
perfuse_msg_t *, size_t, enum perfuse_xchg_pb_reply);
typedef void (*perfuse_destroy_msg_fn)(perfuse_msg_t *);
typedef struct fuse_out_header *(*perfuse_get_outhdr_fn)(perfuse_msg_t *);
typedef struct fuse_in_header *(*perfuse_get_inhdr_fn)(perfuse_msg_t *);
typedef char *(*perfuse_get_inpayload_fn)(perfuse_msg_t *);
typedef char *(*perfuse_get_outpayload_fn)(perfuse_msg_t *);
struct perfuse_callbacks {
perfuse_new_msg_fn pc_new_msg;
perfuse_xchg_msg_fn pc_xchg_msg;
perfuse_destroy_msg_fn pc_destroy_msg;
perfuse_get_inhdr_fn pc_get_inhdr;
perfuse_get_inpayload_fn pc_get_inpayload;
perfuse_get_outhdr_fn pc_get_outhdr;
perfuse_get_outpayload_fn pc_get_outpayload;
};
/*
* mount request
*/
struct perfuse_mount_out {
uint32_t pmo_len;
int32_t pmo_error;
uint64_t pmo_unique;
char pmo_magic[sizeof(PERFUSE_MOUNT_MAGIC)];
size_t pmo_source_len;
size_t pmo_target_len;
size_t pmo_filesystemtype_len;
int pmo_mountflags;
size_t pmo_data_len;
};
struct perfuse_mount_info {
const char *pmi_source;
const char *pmi_target;
const char *pmi_filesystemtype;
int pmi_mountflags;
void *pmi_data;
uid_t pmi_uid;
};
/*
* Duplicated fro fuse.h to avoid making it public
*/
#define FUSE_MIN_BUFSIZE 0x21000
#define FUSE_PREF_BUFSIZE (PAGE_SIZE + 0x1000)
#define FUSE_BUFSIZE MAX(FUSE_PREF_BUFSIZE, FUSE_MIN_BUFSIZE)
struct fuse_in_header {
uint32_t len;
uint32_t opcode;
uint64_t unique;
uint64_t nodeid;
uint32_t uid;
uint32_t gid;
uint32_t pid;
uint32_t padding;
};
struct fuse_out_header {
uint32_t len;
int32_t error;
uint64_t unique;
};
__BEGIN_DECLS
struct puffs_usermount *perfuse_init(struct perfuse_callbacks *,
struct perfuse_mount_info *);
void perfuse_setspecific(struct puffs_usermount *, void *);
void *perfuse_getspecific(struct puffs_usermount *);
uint64_t perfuse_next_unique(struct puffs_usermount *);
uint64_t perfuse_get_ino(struct puffs_usermount *, puffs_cookie_t);
int perfuse_inloop(struct puffs_usermount *);
const char *perfuse_opname(int);
void perfuse_fs_init(struct puffs_usermount *);
int perfuse_mainloop(struct puffs_usermount *);
#endif /* _REFUSE_PERFUSE_H */

View File

@ -0,0 +1,215 @@
/* $NetBSD: perfuse_priv.h,v 1.1 2010/08/25 07:16:00 manu Exp $ */
/*-
* Copyright (c) 2010 Emmanuel Dreyfus. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
* ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef _PERFUSE_PRIV_H_
#define _PERFUSE_PRIV_H_
#include <syslog.h>
#include <paths.h>
#include <err.h>
#include <sysexits.h>
#include <puffs.h>
#include "perfuse_if.h"
#include "fuse.h"
struct perfuse_state {
void *ps_private; /* Private field for libperfuse user */
struct puffs_usermount *ps_pu;
struct puffs_node *ps_root;
uid_t ps_uid;
gid_t ps_gid;
pid_t ps_pid;
int ps_flags;
#define PS_NO_ACCESS 0x0001 /* access is unimplemented; */
#define PS_NO_FSYNC 0x0002 /* fsync is unimplemented */
#define PS_NO_CREAT 0x0004 /* create is unimplemented */
#define PS_INLOOP 0x0008 /* puffs mainloop started */
long ps_fsid;
uint32_t ps_max_readahead;
uint32_t ps_max_write;
uint64_t ps_syncreads;
uint64_t ps_syncwrites;
uint64_t ps_asyncreads;
uint64_t ps_asyncwrites;
char *ps_source;
char *ps_target;
char *ps_filesystemtype;
int ps_mountflags;
uint64_t ps_unique;
uint32_t ps_readahead;
uint32_t ps_write;
perfuse_new_msg_fn ps_new_msg;
perfuse_xchg_msg_fn ps_xchg_msg;
perfuse_destroy_msg_fn ps_destroy_msg;
perfuse_get_inhdr_fn ps_get_inhdr;
perfuse_get_inpayload_fn ps_get_inpayload;
perfuse_get_outhdr_fn ps_get_outhdr;
perfuse_get_outpayload_fn ps_get_outpayload;
};
struct perfuse_file_handle {
uint64_t pfh_fh;
TAILQ_ENTRY(perfuse_file_handle) pfh_entries;
};
enum perfuse_qtype { PCQ_READDIR, PCQ_READ, PCQ_WRITE };
struct perfuse_cc_queue {
enum perfuse_qtype pcq_type;
struct puffs_cc *pcq_cc;
TAILQ_ENTRY(perfuse_cc_queue) pcq_next;
};
struct perfuse_node_data {
TAILQ_HEAD(,perfuse_file_handle) pnd_fh;
uint64_t pnd_ino; /* inode */
uint64_t pnd_nlookup; /* vnode refcount */
uint64_t pnd_offset; /* seek state */
uint64_t pnd_lock_owner;
struct dirent *pnd_dirent; /* native buffer for readdir */
size_t pnd_dirent_len;
struct fuse_dirent *pnd_all_fd; /* FUSE buffer for readdir */
size_t pnd_all_fd_len;
TAILQ_HEAD(,perfuse_cc_queue) pnd_pcq; /* queued requests */
int pnd_flags;
#define PND_RECLAIMED 0x1 /* reclaim pending */
#define PND_INREADDIR 0x2 /* readdir in progress */
puffs_cookie_t pnd_parent;
int pnd_childcount;
};
#define PERFUSE_NODE_DATA(opc) \
((struct perfuse_node_data *)puffs_pn_getpriv((struct puffs_node *)opc))
#define UNSPEC_REPLY_LEN PERFUSE_UNSPEC_REPLY_LEN /* shorter! */
#define NO_PAYLOAD_REPLY_LEN 0
#define GET_INHDR(ps, pm) ps->ps_get_inhdr(pm)
#define GET_INPAYLOAD(ps, pm, type) \
(struct type *)(void *)ps->ps_get_inpayload(pm)
#define _GET_INPAYLOAD(ps, pm, type) (type)ps->ps_get_inpayload(pm)
#define GET_OUTHDR(ps, pm) ps->ps_get_outhdr(pm)
#define GET_OUTPAYLOAD(ps, pm, type) \
(struct type *)(void *)ps->ps_get_outpayload(pm)
#define _GET_OUTPAYLOAD(ps, pm, type) (type)ps->ps_get_outpayload(pm)
#define XCHG_MSG(ps, pu, opc, len) ps->ps_xchg_msg(pu, opc, len, wait_reply)
#define XCHG_MSG_NOREPLY(ps, pu, opc, len) \
ps->ps_xchg_msg(pu, opc, len, no_reply)
__BEGIN_DECLS
struct puffs_node *perfuse_new_pn(struct puffs_usermount *,
struct puffs_node *);
void perfuse_destroy_pn(struct puffs_node *);
void perfuse_new_fh(puffs_cookie_t, uint64_t);
void perfuse_destroy_fh(puffs_cookie_t, uint64_t);
uint64_t perfuse_get_fh(puffs_cookie_t);
uint64_t perfuse_next_unique(struct puffs_usermount *);
char *perfuse_fs_mount(int, ssize_t);
/*
* opc.c - filesystem operations
*/
int perfuse_fs_unmount(struct puffs_usermount *, int);
int perfuse_fs_statvfs(struct puffs_usermount *, struct statvfs *);
int perfuse_fs_sync(struct puffs_usermount *, int,
const struct puffs_cred *);
int perfuse_fs_fhtonode(struct puffs_usermount *, void *, size_t,
struct puffs_newinfo *);
int perfuse_fs_nodetofh(struct puffs_usermount *, puffs_cookie_t,
void *, size_t *);
void perfuse_fs_suspend(struct puffs_usermount *, int);
int perfuse_node_lookup(struct puffs_usermount *,
puffs_cookie_t, struct puffs_newinfo *, const struct puffs_cn *);
int perfuse_node_create(struct puffs_usermount *,
puffs_cookie_t, struct puffs_newinfo *, const struct puffs_cn *,
const struct vattr *);
int perfuse_node_mknod(struct puffs_usermount *,
puffs_cookie_t, struct puffs_newinfo *, const struct puffs_cn *,
const struct vattr *);
int perfuse_node_open(struct puffs_usermount *,
puffs_cookie_t, int, const struct puffs_cred *);
int perfuse_node_close(struct puffs_usermount *,
puffs_cookie_t, int, const struct puffs_cred *);
int perfuse_node_access(struct puffs_usermount *,
puffs_cookie_t, int, const struct puffs_cred *);
int perfuse_node_getattr(struct puffs_usermount *,
puffs_cookie_t, struct vattr *, const struct puffs_cred *);
int perfuse_node_setattr(struct puffs_usermount *,
puffs_cookie_t, const struct vattr *, const struct puffs_cred *);
int perfuse_node_poll(struct puffs_usermount *, puffs_cookie_t, int *);
int perfuse_node_mmap(struct puffs_usermount *,
puffs_cookie_t, vm_prot_t, const struct puffs_cred *);
int perfuse_node_fsync(struct puffs_usermount *,
puffs_cookie_t, const struct puffs_cred *, int, off_t, off_t);
int perfuse_node_seek(struct puffs_usermount *,
puffs_cookie_t, off_t, off_t, const struct puffs_cred *);
int perfuse_node_remove(struct puffs_usermount *,
puffs_cookie_t, puffs_cookie_t, const struct puffs_cn *);
int perfuse_node_link(struct puffs_usermount *,
puffs_cookie_t, puffs_cookie_t, const struct puffs_cn *);
int perfuse_node_rename(struct puffs_usermount *,
puffs_cookie_t, puffs_cookie_t, const struct puffs_cn *,
puffs_cookie_t, puffs_cookie_t, const struct puffs_cn *);
int perfuse_node_mkdir(struct puffs_usermount *,
puffs_cookie_t, struct puffs_newinfo *, const struct puffs_cn *,
const struct vattr *);
int perfuse_node_rmdir(struct puffs_usermount *,
puffs_cookie_t, puffs_cookie_t, const struct puffs_cn *);
int perfuse_node_symlink(struct puffs_usermount *,
puffs_cookie_t, struct puffs_newinfo *, const struct puffs_cn *,
const struct vattr *, const char *);
int perfuse_node_readdir(struct puffs_usermount *,
puffs_cookie_t, struct dirent *, off_t *, size_t *,
const struct puffs_cred *, int *, off_t *, size_t *);
int perfuse_node_readlink(struct puffs_usermount *,
puffs_cookie_t, const struct puffs_cred *, char *, size_t *);
int perfuse_node_reclaim(struct puffs_usermount *, puffs_cookie_t);
int perfuse_node_inactive(struct puffs_usermount *, puffs_cookie_t);
int perfuse_node_print(struct puffs_usermount *, puffs_cookie_t);
int perfuse_node_pathconf(struct puffs_usermount *,
puffs_cookie_t, int, int *);
int perfuse_node_advlock(struct puffs_usermount *,
puffs_cookie_t, void *, int, struct flock *, int);
int perfuse_node_read(struct puffs_usermount *, puffs_cookie_t,
uint8_t *, off_t, size_t *, const struct puffs_cred *, int);
int perfuse_node_write(struct puffs_usermount *, puffs_cookie_t,
uint8_t *, off_t, size_t *, const struct puffs_cred *, int);
void perfuse_cache_write(struct puffs_usermount *,
puffs_cookie_t, size_t, struct puffs_cacherun *);
__END_DECLS
#endif /* _PERFUSE_PRIV_H_ */

View File

@ -0,0 +1,4 @@
# $NetBSD: shlib_version,v 1.1 2010/08/25 07:16:00 manu Exp $
#
major=0
minor=0

160
lib/libperfuse/subr.c Normal file
View File

@ -0,0 +1,160 @@
/* $NetBSD: subr.c,v 1.1 2010/08/25 07:16:00 manu Exp $ */
/*-
* Copyright (c) 2010 Emmanuel Dreyfus. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
* ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
#include <stdio.h>
#include <stdlib.h>
#include <err.h>
#include <errno.h>
#include <sysexits.h>
#include <syslog.h>
#include <puffs.h>
#include <paths.h>
#include "perfuse_priv.h"
struct puffs_node *
perfuse_new_pn(pu, parent)
struct puffs_usermount *pu;
struct puffs_node *parent;
{
struct puffs_node *pn;
struct perfuse_node_data *pnd;
if ((pnd = malloc(sizeof(*pnd))) == NULL)
DERR(EX_OSERR, "malloc failed");
if ((pn = puffs_pn_new(pu, pnd)) == NULL)
DERR(EX_SOFTWARE, "puffs_pn_new failed");
(void)memset(pnd, 0, sizeof(*pnd));
TAILQ_INIT(&pnd->pnd_fh);
pnd->pnd_ino = PERFUSE_UNKNOWN_INO;
pnd->pnd_nlookup = 1;
pnd->pnd_parent = parent;
TAILQ_INIT(&pnd->pnd_pcq);
if (parent != NULL)
PERFUSE_NODE_DATA(parent)->pnd_childcount++;
return pn;
}
void
perfuse_destroy_pn(pn)
struct puffs_node *pn;
{
struct perfuse_node_data *pnd;
if ((pnd = puffs_pn_getpriv(pn)) != NULL) {
if (pnd->pnd_parent != NULL)
PERFUSE_NODE_DATA(pnd->pnd_parent)->pnd_childcount--;
if (pnd->pnd_dirent != NULL)
free(pnd->pnd_dirent);
if (pnd->pnd_all_fd != NULL)
free(pnd->pnd_all_fd);
#ifdef PERFUSE_DEBUG
if (!TAILQ_EMPTY(&pnd->pnd_fh))
DERRX(EX_SOFTWARE, "%s: non empty pnd_fh", __func__);
if (!TAILQ_EMPTY(&pnd->pnd_pcq))
DERRX(EX_SOFTWARE, "%s: non empty pnd_pcq", __func__);
#endif /* PERFUSE_DEBUG */
free(pnd);
}
puffs_pn_remove(pn);
return;
}
void
perfuse_new_fh(opc, fh)
puffs_cookie_t opc;
uint64_t fh;
{
struct perfuse_node_data *pnd;
struct perfuse_file_handle *pfh;
if (fh == FUSE_UNKNOWN_FH)
return;
pnd = PERFUSE_NODE_DATA(opc);
if ((pfh = malloc(sizeof(*pfh))) == NULL)
DERR(EX_OSERR, "malloc failed");
pfh->pfh_fh = fh;
TAILQ_INSERT_TAIL(&pnd->pnd_fh, pfh, pfh_entries);
return;
}
void
perfuse_destroy_fh(opc, fh)
puffs_cookie_t opc;
uint64_t fh;
{
struct perfuse_node_data *pnd;
struct perfuse_file_handle *pfh;
pnd = PERFUSE_NODE_DATA(opc);
TAILQ_FOREACH(pfh, &pnd->pnd_fh, pfh_entries) {
if (pfh->pfh_fh == fh) {
TAILQ_REMOVE(&pnd->pnd_fh, pfh, pfh_entries);
free(pfh);
break;
}
}
if (pfh == NULL)
warnx("%s: unexistant fh = %lld (double close?)", __func__, fh);
return;
}
uint64_t
perfuse_get_fh(opc)
puffs_cookie_t opc;
{
struct perfuse_node_data *pnd;
struct perfuse_file_handle *pfh;
uint64_t fh = FUSE_UNKNOWN_FH;
pnd = PERFUSE_NODE_DATA(opc);
if ((pfh = TAILQ_FIRST(&pnd->pnd_fh)) != NULL)
fh = pfh->pfh_fh;;
return fh;
}