2013-08-09 16:16:13 +00:00
|
|
|
/* dav_fuse.c: interface to the fuse kernel module FUSE_KERNEL_VERSION 7.
|
|
|
|
Copyright (C) 2006, 2007, 2008. 2009 Werner Baumann
|
2009-04-14 19:54:53 +00:00
|
|
|
|
|
|
|
This file is part of davfs2.
|
|
|
|
|
|
|
|
davfs2 is free software; you can redistribute it and/or modify
|
|
|
|
it under the terms of the GNU General Public License as published by
|
|
|
|
the Free Software Foundation; either version 3 of the License, or
|
|
|
|
(at your option) any later version.
|
|
|
|
|
|
|
|
davfs2 is distributed in the hope that it will be useful,
|
|
|
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
|
|
GNU General Public License for more details.
|
|
|
|
|
|
|
|
You should have received a copy of the GNU General Public License
|
|
|
|
along with davfs2; if not, write to the Free Software Foundation,
|
|
|
|
Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. */
|
|
|
|
|
|
|
|
|
|
|
|
#include "config.h"
|
|
|
|
|
2013-08-09 16:16:13 +00:00
|
|
|
#include <errno.h>
|
2009-04-14 19:54:53 +00:00
|
|
|
#include <error.h>
|
|
|
|
#ifdef HAVE_FCNTL_H
|
|
|
|
#include <fcntl.h>
|
|
|
|
#endif
|
|
|
|
#ifdef HAVE_LIBINTL_H
|
|
|
|
#include <libintl.h>
|
|
|
|
#endif
|
|
|
|
#ifdef HAVE_STDDEF_H
|
|
|
|
#include <stddef.h>
|
|
|
|
#endif
|
|
|
|
#ifdef HAVE_STDINT_H
|
|
|
|
#include <stdint.h>
|
|
|
|
#endif
|
|
|
|
#include <stdio.h>
|
|
|
|
#ifdef HAVE_STDLIB_H
|
|
|
|
#include <stdlib.h>
|
|
|
|
#endif
|
2011-01-02 21:26:10 +00:00
|
|
|
#ifdef HAVE_STRING_H
|
2009-04-14 19:54:53 +00:00
|
|
|
#include <string.h>
|
2011-01-02 21:26:10 +00:00
|
|
|
#endif
|
2009-04-14 19:54:53 +00:00
|
|
|
#ifdef HAVE_SYSLOG_H
|
|
|
|
#include <syslog.h>
|
|
|
|
#endif
|
2013-08-09 16:16:13 +00:00
|
|
|
#include <time.h>
|
2009-04-14 19:54:53 +00:00
|
|
|
#ifdef HAVE_UNISTD_H
|
|
|
|
#include <unistd.h>
|
|
|
|
#endif
|
|
|
|
|
|
|
|
#ifdef HAVE_SYS_MOUNT_H
|
|
|
|
#include <sys/mount.h>
|
|
|
|
#endif
|
2010-02-16 19:46:48 +00:00
|
|
|
#ifdef HAVE_SYS_STAT_H
|
|
|
|
#include <sys/stat.h>
|
|
|
|
#endif
|
2013-09-08 07:54:58 +00:00
|
|
|
#ifdef HAVE_SYS_TYPES_H
|
|
|
|
#include <sys/types.h>
|
|
|
|
#endif
|
2014-04-20 09:12:27 +00:00
|
|
|
#include <sys/wait.h>
|
2009-04-14 19:54:53 +00:00
|
|
|
|
2012-01-28 19:54:55 +00:00
|
|
|
#include "xalloc.h"
|
2012-01-28 22:38:15 +00:00
|
|
|
#include "xvasprintf.h"
|
2012-01-28 19:54:55 +00:00
|
|
|
|
2012-01-31 20:50:28 +00:00
|
|
|
#include <ne_ssl.h>
|
|
|
|
|
2009-04-14 19:54:53 +00:00
|
|
|
#include "defaults.h"
|
|
|
|
#include "mount_davfs.h"
|
|
|
|
#include "cache.h"
|
|
|
|
#include "kernel_interface.h"
|
2013-08-09 16:16:13 +00:00
|
|
|
#include "fuse_kernel.h"
|
2009-04-14 19:54:53 +00:00
|
|
|
|
|
|
|
#ifdef ENABLE_NLS
|
|
|
|
#define _(String) gettext(String)
|
|
|
|
#else
|
|
|
|
#define _(String) String
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
2013-09-08 07:54:58 +00:00
|
|
|
/* Constants from Linux headers */
|
|
|
|
/*==============================*/
|
|
|
|
|
|
|
|
#ifndef MISC_MAJOR
|
|
|
|
#define MISC_MAJOR 10
|
|
|
|
#endif
|
|
|
|
#ifndef FUSE_MINOR
|
|
|
|
#define FUSE_MINOR 229
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
2013-08-09 16:16:13 +00:00
|
|
|
/* Data Types */
|
|
|
|
/*============*/
|
|
|
|
|
|
|
|
/* There is no struct fuse_create_out in fuse_kernel.h. */
|
|
|
|
|
|
|
|
struct create_out {
|
|
|
|
struct fuse_entry_out entry;
|
|
|
|
struct fuse_open_out open;
|
|
|
|
};
|
|
|
|
|
|
|
|
|
2009-04-14 19:54:53 +00:00
|
|
|
/* Private constants */
|
|
|
|
/*===================*/
|
|
|
|
|
2013-08-09 16:16:13 +00:00
|
|
|
/* Name of the device to communicate with the
|
2009-04-14 19:54:53 +00:00
|
|
|
kernel file system. */
|
|
|
|
#define FUSE_DEV_NAME "fuse"
|
2013-08-09 16:16:13 +00:00
|
|
|
|
2013-09-08 07:54:58 +00:00
|
|
|
/* Minimum minor version of fuse. */
|
|
|
|
#define FUSE_MIN_MINOR 13
|
|
|
|
|
2013-08-09 16:16:13 +00:00
|
|
|
|
|
|
|
/* Private global variables */
|
|
|
|
/*==========================*/
|
|
|
|
|
|
|
|
/* File descriptor of the fuse device. */
|
|
|
|
static int fuse_device;
|
|
|
|
|
|
|
|
/* Buffer used for communication with the kernel module (in and out). */
|
|
|
|
static size_t buf_size;
|
|
|
|
static char *buf;
|
2013-09-08 07:54:58 +00:00
|
|
|
/* Header of incomming calls. */
|
|
|
|
static struct fuse_in_header *ih;
|
|
|
|
/* Header of outgoing replies. */
|
|
|
|
static struct fuse_out_header *oh;
|
|
|
|
/* Start of upcall specific structure. */
|
|
|
|
static char *upcall;
|
|
|
|
/* Start of upcall specific reply structure. */
|
|
|
|
static char *reply;
|
2013-08-09 16:16:13 +00:00
|
|
|
|
|
|
|
/* Time to wait for upcalls before calling dav_tidy_cache(). */
|
|
|
|
static time_t idle_time;
|
|
|
|
|
|
|
|
/* Send debug messages to syslog if dbg != 0. */
|
|
|
|
static int debug;
|
|
|
|
|
|
|
|
/* fuse wants the nodeid of the root node to be 1, so we have to translate
|
|
|
|
between the real nodeid and what fuse wants. */
|
|
|
|
static uint64_t root;
|
2009-04-14 19:54:53 +00:00
|
|
|
|
|
|
|
|
|
|
|
/* Private function prototypes */
|
|
|
|
/*=============================*/
|
|
|
|
|
2013-08-09 16:16:13 +00:00
|
|
|
/* Functions to handle upcalls fromthe kernel module. */
|
|
|
|
|
|
|
|
static uint32_t
|
|
|
|
fuse_access(void);
|
|
|
|
|
|
|
|
static uint32_t
|
|
|
|
fuse_create(void);
|
|
|
|
|
|
|
|
static uint32_t
|
|
|
|
fuse_getattr(void);
|
2009-04-14 19:54:53 +00:00
|
|
|
|
2013-08-09 16:16:13 +00:00
|
|
|
static uint32_t
|
|
|
|
fuse_init(void);
|
|
|
|
|
|
|
|
static uint32_t
|
|
|
|
fuse_lookup(void);
|
|
|
|
|
|
|
|
static uint32_t
|
|
|
|
fuse_mkdir(void);
|
|
|
|
|
|
|
|
static uint32_t
|
|
|
|
fuse_mknod(void);
|
|
|
|
|
|
|
|
static uint32_t
|
|
|
|
fuse_open(void);
|
|
|
|
|
|
|
|
static uint32_t
|
|
|
|
fuse_read(void);
|
|
|
|
|
|
|
|
static uint32_t
|
|
|
|
fuse_release(void);
|
|
|
|
|
|
|
|
static uint32_t
|
|
|
|
fuse_rename(void);
|
|
|
|
|
|
|
|
static uint32_t
|
|
|
|
fuse_setattr(void);
|
|
|
|
|
|
|
|
static uint32_t
|
|
|
|
fuse_stat(void);
|
|
|
|
|
|
|
|
static uint32_t
|
|
|
|
fuse_write(void);
|
|
|
|
|
2013-09-08 07:54:58 +00:00
|
|
|
static uint32_t
|
|
|
|
not_implemented(const char *msg);
|
|
|
|
|
|
|
|
|
2013-08-09 16:16:13 +00:00
|
|
|
/* Auxiliary functions. */
|
|
|
|
|
|
|
|
static off_t
|
|
|
|
write_dir_entry(int fd, off_t off, const dav_node *node, const char *name);
|
|
|
|
|
|
|
|
static void
|
|
|
|
set_attr(struct fuse_attr *attr, const dav_node *node);
|
2009-04-14 19:54:53 +00:00
|
|
|
|
|
|
|
|
|
|
|
/* Public functions */
|
|
|
|
/*==================*/
|
|
|
|
|
2013-08-09 16:16:13 +00:00
|
|
|
void
|
|
|
|
dav_init_kernel_interface(const char *url, const char *mpoint,
|
|
|
|
const dav_args *args)
|
2009-04-14 19:54:53 +00:00
|
|
|
{
|
2013-08-09 16:16:13 +00:00
|
|
|
debug = args->debug & DAV_DBG_KERNEL;
|
|
|
|
if (debug)
|
|
|
|
syslog(LOG_MAKEPRI(LOG_DAEMON, LOG_DEBUG),
|
|
|
|
"Initializing kernel interface");
|
|
|
|
|
2013-08-10 10:54:58 +00:00
|
|
|
buf_size = args->buf_size * 1024;
|
2013-09-08 07:54:58 +00:00
|
|
|
if (buf_size < (FUSE_MIN_READ_BUFFER + 1024))
|
|
|
|
buf_size = FUSE_MIN_READ_BUFFER + 1024;
|
2013-08-10 10:54:58 +00:00
|
|
|
buf = malloc(buf_size);
|
|
|
|
if (!buf)
|
|
|
|
error(EXIT_FAILURE, errno, _("can't allocate message buffer"));
|
|
|
|
|
2013-09-08 07:54:58 +00:00
|
|
|
ih = (struct fuse_in_header *) buf;
|
|
|
|
oh = (struct fuse_out_header *) buf;
|
|
|
|
upcall = buf + sizeof(struct fuse_in_header);
|
|
|
|
reply = buf + sizeof(struct fuse_out_header);
|
|
|
|
|
2013-08-10 10:54:58 +00:00
|
|
|
idle_time = args->delay_upload;
|
|
|
|
|
2013-08-09 16:16:13 +00:00
|
|
|
char *path = xasprintf("%s/%s", DAV_DEV_DIR, FUSE_DEV_NAME);
|
|
|
|
|
|
|
|
fuse_device = open(path, O_RDWR | O_NONBLOCK);
|
2014-04-20 09:12:27 +00:00
|
|
|
|
2013-08-09 16:16:13 +00:00
|
|
|
if (fuse_device <= 0) {
|
2014-04-20 09:12:27 +00:00
|
|
|
error(0, 0, _("loading kernel module fuse"));
|
|
|
|
int ret;
|
|
|
|
pid_t pid = fork();
|
|
|
|
if (pid == 0) {
|
|
|
|
execl("/sbin/modprobe", "modprobe", "fuse", NULL);
|
|
|
|
_exit(EXIT_FAILURE);
|
|
|
|
} else if (pid < 0) {
|
|
|
|
ret = -1;
|
|
|
|
} else {
|
|
|
|
if (waitpid(pid, &ret, 0) != pid)
|
|
|
|
ret = -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (ret) {
|
|
|
|
error(0, 0, _("loading kernel module fuse failed"));
|
|
|
|
} else {
|
|
|
|
fuse_device = open(path, O_RDWR | O_NONBLOCK);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (fuse_device <= 0) {
|
|
|
|
error(0, 0, _("waiting for %s to be created"), path);
|
|
|
|
sleep(2);
|
|
|
|
fuse_device = open(path, O_RDWR | O_NONBLOCK);
|
2013-08-09 16:16:13 +00:00
|
|
|
}
|
|
|
|
}
|
2009-04-14 19:54:53 +00:00
|
|
|
|
2013-08-09 16:16:13 +00:00
|
|
|
free(path);
|
|
|
|
if (fuse_device <= 0)
|
|
|
|
error(EXIT_FAILURE, 0, _("can't open fuse device"));
|
2009-04-14 19:54:53 +00:00
|
|
|
|
2013-08-09 16:16:13 +00:00
|
|
|
char *mdata = xasprintf("fd=%i,rootmode=%o,user_id=%i,group_id=%i,"
|
|
|
|
"allow_other,max_read=%lu", fuse_device,
|
|
|
|
args->dir_mode, args->fsuid, args->fsgid,
|
2013-09-08 07:54:58 +00:00
|
|
|
(unsigned long int) (buf_size - 1024));
|
2013-08-09 16:16:13 +00:00
|
|
|
|
|
|
|
if (mount(url, mpoint, "fuse", args->mopts, mdata) != 0)
|
|
|
|
error(EXIT_FAILURE, errno, _("mounting failed"));
|
|
|
|
|
|
|
|
free(mdata);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
dav_run_msgloop(volatile int *keep_on_running)
|
|
|
|
{
|
|
|
|
dav_register_kernel_interface(&write_dir_entry);
|
|
|
|
|
|
|
|
struct timeval tv;
|
|
|
|
tv.tv_sec = idle_time;
|
|
|
|
tv.tv_usec = 0;
|
|
|
|
time_t last_tidy_cache = time(NULL);
|
|
|
|
|
|
|
|
while (*keep_on_running) {
|
|
|
|
|
|
|
|
fd_set fds;
|
|
|
|
FD_ZERO(&fds);
|
|
|
|
FD_SET(fuse_device, &fds);
|
|
|
|
int ret = select(fuse_device + 1, &fds, NULL, NULL, &tv);
|
|
|
|
if (debug)
|
|
|
|
syslog(LOG_MAKEPRI(LOG_DAEMON, LOG_DEBUG), "SELECT: %i", ret);
|
|
|
|
|
|
|
|
if (ret > 0) {
|
|
|
|
ssize_t bytes_read = read(fuse_device, buf, buf_size);
|
|
|
|
if (bytes_read <= 0) {
|
|
|
|
if (debug)
|
|
|
|
syslog(LOG_MAKEPRI(LOG_DAEMON, LOG_DEBUG), "READ: %s",
|
|
|
|
strerror(errno));
|
|
|
|
if (bytes_read == 0 || errno == EINTR || errno == EAGAIN ||
|
|
|
|
errno == ENOENT) {
|
|
|
|
if (time(NULL) < (last_tidy_cache + idle_time)) {
|
|
|
|
tv.tv_sec = last_tidy_cache + idle_time - time(NULL);
|
|
|
|
} else {
|
|
|
|
tv.tv_sec = 0;
|
|
|
|
}
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
} else if (ret == 0) {
|
|
|
|
if (!dav_is_mounted())
|
|
|
|
break;
|
|
|
|
if (dav_tidy_cache() == 0) {
|
|
|
|
tv.tv_sec = idle_time;
|
|
|
|
last_tidy_cache = time(NULL);
|
2009-04-14 19:54:53 +00:00
|
|
|
} else {
|
2013-08-09 16:16:13 +00:00
|
|
|
tv.tv_sec = 0;
|
2009-04-14 19:54:53 +00:00
|
|
|
}
|
2013-08-09 16:16:13 +00:00
|
|
|
continue;
|
|
|
|
} else {
|
|
|
|
break;
|
2009-04-14 19:54:53 +00:00
|
|
|
}
|
|
|
|
|
2013-08-09 16:16:13 +00:00
|
|
|
if (ih->nodeid == 1)
|
|
|
|
ih->nodeid = root;
|
2009-04-14 19:54:53 +00:00
|
|
|
|
2013-08-09 16:16:13 +00:00
|
|
|
switch (ih->opcode) {
|
|
|
|
case FUSE_LOOKUP:
|
|
|
|
oh->len = fuse_lookup();
|
|
|
|
break;
|
|
|
|
case FUSE_FORGET:
|
|
|
|
if (debug)
|
|
|
|
syslog(LOG_MAKEPRI(LOG_DAEMON, LOG_DEBUG),
|
|
|
|
"FUSE_FORGET: no reply");
|
|
|
|
oh->len = 0;
|
|
|
|
break;
|
|
|
|
case FUSE_GETATTR:
|
|
|
|
oh->len = fuse_getattr();
|
|
|
|
break;
|
|
|
|
case FUSE_SETATTR:
|
|
|
|
oh->len = fuse_setattr();
|
|
|
|
break;
|
|
|
|
case FUSE_READLINK:
|
2013-09-08 07:54:58 +00:00
|
|
|
oh->len = not_implemented("FUSE_READLINK:");
|
2013-08-09 16:16:13 +00:00
|
|
|
break;
|
|
|
|
case FUSE_SYMLINK:
|
2013-09-08 07:54:58 +00:00
|
|
|
oh->len = not_implemented("FUSE_SYMLINK:");
|
2013-08-09 16:16:13 +00:00
|
|
|
break;
|
|
|
|
case FUSE_MKNOD:
|
|
|
|
oh->len = fuse_mknod();
|
|
|
|
break;
|
|
|
|
case FUSE_MKDIR:
|
|
|
|
oh->len = fuse_mkdir();
|
|
|
|
break;
|
|
|
|
case FUSE_UNLINK:
|
|
|
|
if (debug) {
|
2013-09-08 07:54:58 +00:00
|
|
|
syslog(LOG_MAKEPRI(LOG_DAEMON, LOG_DEBUG),
|
|
|
|
"FUSE_UNLINK %llu: n=0x%llx",
|
|
|
|
(unsigned long long) ih->unique,
|
|
|
|
(unsigned long long) ih->nodeid);
|
|
|
|
syslog(LOG_MAKEPRI(LOG_DAEMON, LOG_DEBUG), " u=%u g=%u p=%u",
|
|
|
|
ih->uid, ih->gid, ih->pid);
|
2013-08-09 16:16:13 +00:00
|
|
|
}
|
2013-09-08 07:54:58 +00:00
|
|
|
oh->error = dav_remove((dav_node *) ((size_t) ih->nodeid), upcall,
|
|
|
|
ih->uid);
|
2013-08-09 16:16:13 +00:00
|
|
|
if (oh->error)
|
|
|
|
oh->error *= -1;
|
|
|
|
oh->len = sizeof(struct fuse_out_header);
|
|
|
|
break;
|
|
|
|
case FUSE_RMDIR:
|
|
|
|
if (debug) {
|
2013-09-08 07:54:58 +00:00
|
|
|
syslog(LOG_MAKEPRI(LOG_DAEMON, LOG_DEBUG),
|
|
|
|
"FUSE_RMDIR %llu: n=0x%llx",
|
|
|
|
(unsigned long long) ih->unique,
|
|
|
|
(unsigned long long) ih->nodeid);
|
|
|
|
syslog(LOG_MAKEPRI(LOG_DAEMON, LOG_DEBUG), " u=%u g=%u p=%u",
|
|
|
|
ih->uid, ih->gid, ih->pid);
|
2013-08-09 16:16:13 +00:00
|
|
|
}
|
2013-09-08 07:54:58 +00:00
|
|
|
oh->error = dav_rmdir((dav_node *) ((size_t) ih->nodeid), upcall,
|
|
|
|
ih->uid);
|
2013-08-09 16:16:13 +00:00
|
|
|
if (oh->error)
|
|
|
|
oh->error *= -1;
|
|
|
|
oh->len = sizeof(struct fuse_out_header);
|
|
|
|
break;
|
|
|
|
case FUSE_RENAME:
|
|
|
|
oh->len = fuse_rename();
|
|
|
|
break;
|
|
|
|
case FUSE_LINK:
|
2013-09-08 07:54:58 +00:00
|
|
|
oh->len = not_implemented("FUSE_LINK:");
|
2013-08-09 16:16:13 +00:00
|
|
|
break;
|
|
|
|
case FUSE_OPEN:
|
|
|
|
oh->len = fuse_open();
|
|
|
|
break;
|
|
|
|
case FUSE_READ:
|
|
|
|
oh->len = fuse_read();
|
|
|
|
break;
|
|
|
|
case FUSE_WRITE:
|
|
|
|
oh->len = fuse_write();
|
|
|
|
break;
|
|
|
|
case FUSE_STATFS:
|
|
|
|
oh->len = fuse_stat();
|
|
|
|
break;
|
|
|
|
case FUSE_RELEASE:
|
|
|
|
oh->len = fuse_release();
|
|
|
|
last_tidy_cache = 0;
|
|
|
|
break;
|
|
|
|
case FUSE_FSYNC:
|
|
|
|
if (debug) {
|
2013-09-08 07:54:58 +00:00
|
|
|
syslog(LOG_MAKEPRI(LOG_DAEMON, LOG_DEBUG),
|
|
|
|
"FUSE_FSYNC %llu: n=0x%llx",
|
|
|
|
(unsigned long long) ih->unique,
|
|
|
|
(unsigned long long) ih->nodeid);
|
|
|
|
syslog(LOG_MAKEPRI(LOG_DAEMON, LOG_DEBUG), " u=%u g=%u p=%u",
|
|
|
|
ih->uid, ih->gid, ih->pid);
|
2013-08-09 16:16:13 +00:00
|
|
|
}
|
|
|
|
oh->error = dav_sync((dav_node *) ((size_t) ih->nodeid));
|
|
|
|
if (oh->error)
|
|
|
|
oh->error *= -1;
|
|
|
|
oh->len = sizeof(struct fuse_out_header);
|
|
|
|
break;
|
|
|
|
case FUSE_SETXATTR:
|
2013-09-08 07:54:58 +00:00
|
|
|
oh->len = not_implemented("FUSE_SETXATTR:");
|
2013-08-09 16:16:13 +00:00
|
|
|
break;
|
|
|
|
case FUSE_GETXATTR:
|
2013-09-08 07:54:58 +00:00
|
|
|
oh->len = not_implemented("FUSE_GETXATTR:");
|
2013-08-09 16:16:13 +00:00
|
|
|
break;
|
|
|
|
case FUSE_LISTXATTR:
|
2013-09-08 07:54:58 +00:00
|
|
|
oh->len = not_implemented("FUSE_LISTXATTR:");
|
2013-08-09 16:16:13 +00:00
|
|
|
break;
|
|
|
|
case FUSE_REMOVEXATTR:
|
2013-09-08 07:54:58 +00:00
|
|
|
oh->len = not_implemented("FUSE_REMOVEXATTR:");
|
2013-08-09 16:16:13 +00:00
|
|
|
break;
|
|
|
|
case FUSE_FLUSH:
|
|
|
|
if (debug)
|
|
|
|
syslog(LOG_MAKEPRI(LOG_DAEMON, LOG_DEBUG),
|
|
|
|
"FUSE_FLUSH: ignored");
|
|
|
|
oh->error = 0;
|
|
|
|
oh->len = sizeof(struct fuse_out_header);
|
|
|
|
break;
|
|
|
|
case FUSE_INIT:
|
|
|
|
oh->len = fuse_init();
|
|
|
|
break;
|
|
|
|
case FUSE_OPENDIR:
|
|
|
|
oh->len = fuse_open();
|
|
|
|
break;
|
|
|
|
case FUSE_READDIR:
|
|
|
|
oh->len = fuse_read();
|
|
|
|
break;
|
|
|
|
case FUSE_RELEASEDIR:
|
|
|
|
oh->len = fuse_release();
|
|
|
|
break;
|
|
|
|
case FUSE_FSYNCDIR:
|
2013-09-08 07:54:58 +00:00
|
|
|
oh->len = not_implemented("FUSE_FSYNCDIR:");
|
|
|
|
break;
|
|
|
|
case FUSE_GETLK:
|
|
|
|
oh->len = not_implemented("FUSE_GETLK:");
|
|
|
|
break;
|
|
|
|
case FUSE_SETLK:
|
|
|
|
oh->len = not_implemented("FUSE_SETLK:");
|
|
|
|
break;
|
|
|
|
case FUSE_SETLKW:
|
|
|
|
oh->len = not_implemented("FUSE_SETLKW:");
|
2013-08-09 16:16:13 +00:00
|
|
|
break;
|
|
|
|
case FUSE_ACCESS:
|
|
|
|
oh->len = fuse_access();
|
|
|
|
break;
|
|
|
|
case FUSE_CREATE:
|
|
|
|
oh->len = fuse_create();
|
|
|
|
break;
|
2013-09-08 07:54:58 +00:00
|
|
|
case FUSE_INTERRUPT:
|
|
|
|
oh->len = not_implemented("FUSE_INTERRUPT:");
|
|
|
|
break;
|
|
|
|
case FUSE_BMAP:
|
|
|
|
oh->len = not_implemented("FUSE_BMAP:");
|
|
|
|
break;
|
|
|
|
case FUSE_DESTROY:
|
|
|
|
oh->len = not_implemented("FUSE_DESTROY:");
|
|
|
|
break;
|
|
|
|
case FUSE_IOCTL:
|
|
|
|
oh->len = not_implemented("FUSE_IOCTL:");
|
|
|
|
break;
|
|
|
|
case FUSE_POLL:
|
|
|
|
oh->len = not_implemented("FUSE_POLL:");
|
|
|
|
break;
|
|
|
|
case FUSE_NOTIFY_REPLY:
|
|
|
|
oh->len = not_implemented("FUSE_NOTIFY_REPLY:");
|
|
|
|
break;
|
|
|
|
case FUSE_BATCH_FORGET:
|
|
|
|
oh->len = not_implemented("FUSE_BATCH_FORGET:");
|
|
|
|
break;
|
|
|
|
case FUSE_FALLOCATE:
|
|
|
|
oh->len = not_implemented("FUSE_FALLOCATE:");
|
|
|
|
break;
|
2013-08-09 16:16:13 +00:00
|
|
|
default:
|
|
|
|
if (debug)
|
|
|
|
syslog(LOG_MAKEPRI(LOG_DAEMON, LOG_DEBUG),
|
|
|
|
"UNKNOWN FUSE CALL %i", ih->opcode);
|
|
|
|
oh->error = -ENOSYS;
|
|
|
|
oh->len = sizeof(struct fuse_out_header);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (debug && oh->len)
|
|
|
|
syslog(LOG_MAKEPRI(LOG_DAEMON, LOG_DEBUG), "RET: %s",
|
|
|
|
strerror(-oh->error));
|
|
|
|
|
|
|
|
ssize_t n = 0;
|
|
|
|
ssize_t w = 0;
|
|
|
|
while (n < oh->len && w >= 0) {
|
|
|
|
w = write(fuse_device, buf + n, oh->len - n);
|
|
|
|
n += w;
|
|
|
|
}
|
2012-01-25 20:26:30 +00:00
|
|
|
|
2013-08-09 16:16:13 +00:00
|
|
|
if (time(NULL) < (last_tidy_cache + idle_time)) {
|
|
|
|
tv.tv_sec = last_tidy_cache + idle_time - time(NULL);
|
|
|
|
} else {
|
|
|
|
dav_tidy_cache();
|
|
|
|
tv.tv_sec = idle_time;
|
|
|
|
last_tidy_cache = time(NULL);
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
2009-04-14 19:54:53 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/* Private functions */
|
|
|
|
/*===================*/
|
|
|
|
|
2013-08-09 16:16:13 +00:00
|
|
|
/* Functions to handle upcalls fromthe kernel module.
|
|
|
|
The cache module only uses data types from the C-library. For file access,
|
|
|
|
mode and the like it only uses symbolic constants defined in the C-library.
|
|
|
|
So the main porpose of this functions is to translate from kernel specific
|
|
|
|
types and constants to types and constants from the C-library, and back.
|
|
|
|
All of this functions return the amount of data in buf that is to be
|
|
|
|
send to the kernel module. */
|
|
|
|
|
|
|
|
static uint32_t
|
|
|
|
fuse_access(void)
|
2009-04-14 19:54:53 +00:00
|
|
|
{
|
2013-09-08 07:54:58 +00:00
|
|
|
struct fuse_access_in *in = (struct fuse_access_in *) upcall;
|
|
|
|
|
2013-08-09 16:16:13 +00:00
|
|
|
if (debug) {
|
2013-09-08 07:54:58 +00:00
|
|
|
syslog(LOG_MAKEPRI(LOG_DAEMON, LOG_DEBUG), "FUSE_ACCESS %llu: n=0x%llx",
|
|
|
|
(unsigned long long) ih->unique,
|
|
|
|
(unsigned long long) ih->nodeid);
|
|
|
|
syslog(LOG_MAKEPRI(LOG_DAEMON, LOG_DEBUG), " u=%u g=%u p=%u",
|
|
|
|
ih->uid, ih->gid, ih->pid);
|
|
|
|
syslog(LOG_MAKEPRI(LOG_DAEMON, LOG_DEBUG), " m=0x%x",
|
|
|
|
in->mask);
|
2013-08-09 16:16:13 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
oh->error = dav_access((dav_node *) ((size_t) ih->nodeid), ih->uid,
|
|
|
|
in->mask);
|
|
|
|
|
|
|
|
if (oh->error)
|
|
|
|
oh->error *= -1;
|
|
|
|
|
|
|
|
return sizeof(struct fuse_out_header);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static uint32_t
|
|
|
|
fuse_create(void)
|
|
|
|
{
|
2013-09-08 07:54:58 +00:00
|
|
|
struct fuse_create_in *in = (struct fuse_create_in *) upcall;
|
|
|
|
char *name = upcall + sizeof(struct fuse_create_in);
|
|
|
|
struct create_out *out = (struct create_out *) reply;
|
|
|
|
|
2013-08-09 16:16:13 +00:00
|
|
|
if (debug) {
|
2013-09-08 07:54:58 +00:00
|
|
|
syslog(LOG_MAKEPRI(LOG_DAEMON, LOG_DEBUG), "FUSE_CREATE %llu: n=0x%llx",
|
|
|
|
(unsigned long long) ih->unique,
|
|
|
|
(unsigned long long) ih->nodeid);
|
|
|
|
syslog(LOG_MAKEPRI(LOG_DAEMON, LOG_DEBUG), " u=%u g=%u p=%u",
|
|
|
|
ih->uid, ih->gid, ih->pid);
|
|
|
|
syslog(LOG_MAKEPRI(LOG_DAEMON, LOG_DEBUG), " f=0x%x m=0%o um=0%o",
|
|
|
|
in->flags, in->mode, in->umask);
|
2013-08-09 16:16:13 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
int created = 0;
|
|
|
|
dav_node *node = NULL;
|
|
|
|
oh->error = dav_lookup(&node, (dav_node *) ((size_t) ih->nodeid), name,
|
|
|
|
ih->uid);
|
|
|
|
|
|
|
|
if (!oh->error) {
|
|
|
|
if (!node) {
|
|
|
|
oh->error = -EIO;
|
|
|
|
return sizeof(struct fuse_out_header);
|
|
|
|
} else if (in->flags & O_EXCL) {
|
|
|
|
oh->error = -EEXIST;
|
|
|
|
return sizeof(struct fuse_out_header);
|
2009-04-14 19:54:53 +00:00
|
|
|
}
|
2013-08-09 16:16:13 +00:00
|
|
|
} else if (oh->error == ENOENT) {
|
|
|
|
oh->error = dav_create(&node, (dav_node *) ((size_t) ih->nodeid), name,
|
|
|
|
ih->uid, in->mode & DAV_A_MASK);
|
|
|
|
if (oh->error || !node) {
|
|
|
|
if (!oh->error)
|
|
|
|
oh->error = EIO;
|
|
|
|
oh->error *= -1;
|
|
|
|
return sizeof(struct fuse_out_header);
|
|
|
|
}
|
|
|
|
created = 1;
|
|
|
|
} else {
|
|
|
|
oh->error *= -1;
|
|
|
|
return sizeof(struct fuse_out_header);
|
2009-04-14 19:54:53 +00:00
|
|
|
}
|
|
|
|
|
2013-08-09 16:16:13 +00:00
|
|
|
int fd = 0;
|
|
|
|
oh->error = dav_open(&fd, node, in->flags & ~(O_EXCL | O_CREAT), ih->uid, 1);
|
|
|
|
|
|
|
|
if (oh->error || !fd) {
|
|
|
|
if (created)
|
|
|
|
dav_remove((dav_node *) ((size_t) ih->nodeid), name, ih->uid);
|
|
|
|
if (!oh->error)
|
|
|
|
oh->error = EIO;
|
|
|
|
oh->error *= -1;
|
|
|
|
return sizeof(struct fuse_out_header);
|
|
|
|
}
|
|
|
|
|
|
|
|
out->entry.nodeid = (size_t) node;
|
|
|
|
out->entry.generation = out->entry.nodeid;
|
|
|
|
out->entry.entry_valid = 1;
|
|
|
|
out->entry.attr_valid = 1;
|
|
|
|
out->entry.entry_valid_nsec = 0;
|
|
|
|
out->entry.attr_valid_nsec = 0;
|
|
|
|
set_attr(&out->entry.attr, node);
|
|
|
|
|
|
|
|
out->open.open_flags = in->flags & (O_ACCMODE | O_APPEND);
|
|
|
|
out->open.fh = fd;
|
|
|
|
out->open.padding = 0;
|
|
|
|
|
|
|
|
if (debug)
|
|
|
|
syslog(LOG_MAKEPRI(LOG_DAEMON, LOG_DEBUG), " fd %i", fd);
|
2013-09-08 07:54:58 +00:00
|
|
|
|
2013-08-09 16:16:13 +00:00
|
|
|
return sizeof(struct fuse_out_header) + sizeof(struct create_out);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static uint32_t
|
|
|
|
fuse_getattr(void)
|
|
|
|
{
|
2013-09-08 07:54:58 +00:00
|
|
|
struct fuse_getattr_in *in = (struct fuse_getattr_in *) upcall;
|
|
|
|
struct fuse_attr_out *out = (struct fuse_attr_out *) reply;
|
|
|
|
|
2013-08-09 16:16:13 +00:00
|
|
|
if (debug) {
|
2013-09-08 07:54:58 +00:00
|
|
|
syslog(LOG_MAKEPRI(LOG_DAEMON, LOG_DEBUG), "FUSE_GETATTR %llu: n=0x%llx",
|
|
|
|
(unsigned long long) ih->unique,
|
2013-08-09 16:16:13 +00:00
|
|
|
(unsigned long long) ih->nodeid);
|
2013-09-08 07:54:58 +00:00
|
|
|
syslog(LOG_MAKEPRI(LOG_DAEMON, LOG_DEBUG), " u=%u g=%u p=%u",
|
|
|
|
ih->uid, ih->gid, ih->pid);
|
|
|
|
syslog(LOG_MAKEPRI(LOG_DAEMON, LOG_DEBUG), " f=0x%x fh=%llu",
|
|
|
|
in->getattr_flags, in->fh);
|
2013-08-09 16:16:13 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
oh->error = dav_getattr((dav_node *) ((size_t) ih->nodeid), ih->uid);
|
|
|
|
|
|
|
|
if (oh->error) {
|
|
|
|
oh->error *= -1;
|
|
|
|
return sizeof(struct fuse_out_header);
|
|
|
|
}
|
|
|
|
|
|
|
|
set_attr(&out->attr, (dav_node *) ((size_t) ih->nodeid));
|
|
|
|
out->attr_valid = 1;
|
|
|
|
out->attr_valid_nsec = 0;
|
|
|
|
out->dummy = 0;
|
|
|
|
|
|
|
|
return sizeof(struct fuse_out_header) + sizeof(struct fuse_attr_out);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static uint32_t
|
|
|
|
fuse_init(void)
|
|
|
|
{
|
2013-09-08 07:54:58 +00:00
|
|
|
struct fuse_init_in *in = (struct fuse_init_in *) upcall;
|
|
|
|
struct fuse_init_out *out = (struct fuse_init_out *) reply;
|
|
|
|
|
2013-08-09 16:16:13 +00:00
|
|
|
if (debug) {
|
2013-09-08 07:54:58 +00:00
|
|
|
syslog(LOG_MAKEPRI(LOG_DAEMON, LOG_DEBUG), "FUSE_INIT %llu: n=0x%llx",
|
|
|
|
(unsigned long long) ih->unique,
|
|
|
|
(unsigned long long) ih->nodeid);
|
|
|
|
syslog(LOG_MAKEPRI(LOG_DAEMON, LOG_DEBUG), " u=%u g=%u p=%u",
|
|
|
|
ih->uid, ih->gid, ih->pid);
|
|
|
|
syslog(LOG_MAKEPRI(LOG_DAEMON, LOG_DEBUG), " verson=%u.%u",
|
2013-08-09 16:16:13 +00:00
|
|
|
in->major, in->minor);
|
2013-09-08 07:54:58 +00:00
|
|
|
syslog(LOG_MAKEPRI(LOG_DAEMON, LOG_DEBUG), " ra=%u f=0x%x",
|
|
|
|
in->max_readahead, in->flags);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (in->major < FUSE_KERNEL_VERSION
|
|
|
|
|| (in->major == FUSE_KERNEL_VERSION && in->minor < FUSE_MIN_MINOR)) {
|
|
|
|
syslog(LOG_MAKEPRI(LOG_DAEMON, LOG_DEBUG),
|
|
|
|
"FATAL: Kernel-version too old.");
|
|
|
|
oh->error = -ENOSYS;
|
|
|
|
return sizeof(struct fuse_out_header);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (in->major > FUSE_KERNEL_VERSION) {
|
|
|
|
oh->error = 0;
|
|
|
|
out->major = FUSE_KERNEL_VERSION;
|
|
|
|
return sizeof(struct fuse_out_header);
|
2013-08-09 16:16:13 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
dav_node *node;
|
|
|
|
oh->error = dav_root(&node, ih->uid);
|
|
|
|
|
|
|
|
if (oh->error || !node) {
|
|
|
|
if (!oh->error)
|
|
|
|
oh->error = EIO;
|
|
|
|
oh->error *= -1;
|
|
|
|
return sizeof(struct fuse_out_header);
|
2009-04-14 19:54:53 +00:00
|
|
|
}
|
|
|
|
|
2013-08-09 16:16:13 +00:00
|
|
|
root = (size_t) node;
|
|
|
|
out->major = FUSE_KERNEL_VERSION;
|
2013-09-08 07:54:58 +00:00
|
|
|
if (in->minor > FUSE_KERNEL_MINOR_VERSION) {
|
|
|
|
out->minor = FUSE_KERNEL_MINOR_VERSION;
|
|
|
|
} else {
|
|
|
|
out->minor = in->minor;
|
|
|
|
}
|
|
|
|
out->max_readahead = 0;
|
|
|
|
out->flags = 0;
|
|
|
|
out->max_background = 0;
|
|
|
|
out->congestion_threshold = 0;
|
|
|
|
out->max_write = buf_size - 1024;
|
2009-04-14 19:54:53 +00:00
|
|
|
|
2013-08-09 16:16:13 +00:00
|
|
|
return sizeof(struct fuse_out_header) + sizeof(struct fuse_init_out);
|
2009-04-14 19:54:53 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2013-08-09 16:16:13 +00:00
|
|
|
static uint32_t
|
|
|
|
fuse_lookup(void)
|
|
|
|
{
|
2013-09-08 07:54:58 +00:00
|
|
|
char * name = upcall;
|
|
|
|
struct fuse_entry_out *out = (struct fuse_entry_out *) reply;
|
|
|
|
|
2013-08-09 16:16:13 +00:00
|
|
|
if (debug) {
|
2013-09-08 07:54:58 +00:00
|
|
|
syslog(LOG_MAKEPRI(LOG_DAEMON, LOG_DEBUG), "FUSE_LOOKUP %llu: n=0x%llx",
|
|
|
|
(unsigned long long) ih->unique,
|
|
|
|
(unsigned long long) ih->nodeid);
|
|
|
|
syslog(LOG_MAKEPRI(LOG_DAEMON, LOG_DEBUG), " u=%u g=%u p=%u",
|
|
|
|
ih->uid, ih->gid, ih->pid);
|
|
|
|
syslog(LOG_MAKEPRI(LOG_DAEMON, LOG_DEBUG), " %s", name);
|
2013-08-09 16:16:13 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
dav_node *node = NULL;
|
|
|
|
oh->error = dav_lookup(&node, (dav_node *) ((size_t) ih->nodeid), name,
|
|
|
|
ih->uid);
|
|
|
|
|
|
|
|
if (oh->error || !node) {
|
|
|
|
if (!oh->error)
|
|
|
|
oh->error = EIO;
|
|
|
|
oh->error *= -1;
|
|
|
|
return sizeof(struct fuse_out_header);
|
|
|
|
}
|
|
|
|
|
2013-09-08 07:54:58 +00:00
|
|
|
out->nodeid = (uint64_t) ((size_t) node);
|
2013-08-09 16:16:13 +00:00
|
|
|
out->generation = out->nodeid;
|
|
|
|
out->entry_valid = 1;
|
|
|
|
out->attr_valid = 1;
|
|
|
|
out->entry_valid_nsec = 0;
|
|
|
|
out->attr_valid_nsec = 0;
|
|
|
|
set_attr(&out->attr, node);
|
|
|
|
|
|
|
|
return sizeof(struct fuse_out_header) + sizeof(struct fuse_entry_out);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static uint32_t
|
|
|
|
fuse_mkdir(void)
|
|
|
|
{
|
2013-09-08 07:54:58 +00:00
|
|
|
struct fuse_mkdir_in *in = (struct fuse_mkdir_in *) upcall;
|
|
|
|
char *name = upcall + sizeof(struct fuse_mkdir_in);
|
|
|
|
struct fuse_entry_out *out = (struct fuse_entry_out *) reply;
|
|
|
|
|
2013-08-09 16:16:13 +00:00
|
|
|
if (debug) {
|
2013-09-08 07:54:58 +00:00
|
|
|
syslog(LOG_MAKEPRI(LOG_DAEMON, LOG_DEBUG), "FUSE_MKDIR %llu: n=0x%llx",
|
|
|
|
(unsigned long long) ih->unique,
|
|
|
|
(unsigned long long) ih->nodeid);
|
|
|
|
syslog(LOG_MAKEPRI(LOG_DAEMON, LOG_DEBUG), " u=%u g=%u p=%u",
|
|
|
|
ih->uid, ih->gid, ih->pid);
|
|
|
|
syslog(LOG_MAKEPRI(LOG_DAEMON, LOG_DEBUG), " m=0%o um=0%o %s",
|
|
|
|
in->mode, in->umask, name);
|
2013-08-09 16:16:13 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
dav_node *node = NULL;
|
|
|
|
oh->error = dav_mkdir(&node, (dav_node *) ((size_t) ih->nodeid), name,
|
|
|
|
ih->uid, in->mode & DAV_A_MASK);
|
|
|
|
|
|
|
|
if (oh->error || !node) {
|
|
|
|
if (!oh->error)
|
|
|
|
oh->error = EIO;
|
|
|
|
oh->error *= -1;
|
|
|
|
return sizeof(struct fuse_out_header);
|
|
|
|
}
|
|
|
|
|
|
|
|
out->nodeid = (size_t) node;
|
|
|
|
out->generation = out->nodeid;
|
|
|
|
out->entry_valid = 1;
|
|
|
|
out->attr_valid = 1;
|
|
|
|
out->entry_valid_nsec = 0;
|
|
|
|
out->attr_valid_nsec = 0;
|
|
|
|
set_attr(&out->attr, node);
|
|
|
|
|
|
|
|
return sizeof(struct fuse_out_header) + sizeof(struct fuse_entry_out);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static uint32_t
|
|
|
|
fuse_mknod(void)
|
|
|
|
{
|
2013-09-08 07:54:58 +00:00
|
|
|
struct fuse_mknod_in *in = (struct fuse_mknod_in *) upcall;
|
|
|
|
char *name = upcall + sizeof(struct fuse_mknod_in);
|
|
|
|
struct fuse_entry_out *out = (struct fuse_entry_out *) reply;
|
|
|
|
|
2013-08-09 16:16:13 +00:00
|
|
|
if (debug) {
|
2013-09-08 07:54:58 +00:00
|
|
|
syslog(LOG_MAKEPRI(LOG_DAEMON, LOG_DEBUG), "FUSE_MKNOD %llu: n=0x%llx",
|
|
|
|
(unsigned long long) ih->unique,
|
|
|
|
(unsigned long long) ih->nodeid);
|
|
|
|
syslog(LOG_MAKEPRI(LOG_DAEMON, LOG_DEBUG), " u=%u g=%u p=%u",
|
|
|
|
ih->uid, ih->gid, ih->pid);
|
|
|
|
syslog(LOG_MAKEPRI(LOG_DAEMON, LOG_DEBUG), " m=0%o r=%u um=0%o",
|
|
|
|
in->mode, in->rdev, in->umask);
|
2013-08-09 16:16:13 +00:00
|
|
|
syslog(LOG_MAKEPRI(LOG_DAEMON, LOG_DEBUG), " %s", name);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!S_ISREG(in->mode)) {
|
|
|
|
oh->error = -ENOTSUP;
|
|
|
|
return sizeof(struct fuse_out_header);
|
|
|
|
}
|
|
|
|
|
|
|
|
dav_node *node = NULL;
|
|
|
|
oh->error = dav_create(&node, (dav_node *) ((size_t) ih->nodeid), name,
|
|
|
|
ih->uid, in->mode & DAV_A_MASK);
|
|
|
|
|
|
|
|
if (oh->error || !node) {
|
|
|
|
if (!oh->error)
|
|
|
|
oh->error = EIO;
|
|
|
|
oh->error *= -1;
|
|
|
|
return sizeof(struct fuse_out_header);
|
|
|
|
}
|
|
|
|
|
|
|
|
out->nodeid = (size_t) node;
|
|
|
|
out->generation = out->nodeid;
|
|
|
|
out->entry_valid = 1;
|
|
|
|
out->attr_valid = 1;
|
|
|
|
out->entry_valid_nsec = 0;
|
|
|
|
out->attr_valid_nsec = 0;
|
|
|
|
set_attr(&out->attr, node);
|
|
|
|
|
|
|
|
return sizeof(struct fuse_out_header) + sizeof(struct fuse_entry_out);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static uint32_t
|
|
|
|
fuse_open(void)
|
|
|
|
{
|
2013-09-08 07:54:58 +00:00
|
|
|
struct fuse_open_in *in = (struct fuse_open_in *) upcall;
|
|
|
|
struct fuse_open_out *out = (struct fuse_open_out *) reply;
|
|
|
|
|
2013-08-09 16:16:13 +00:00
|
|
|
if (debug) {
|
|
|
|
if (ih->opcode == FUSE_OPENDIR) {
|
2013-09-08 07:54:58 +00:00
|
|
|
syslog(LOG_MAKEPRI(LOG_DAEMON, LOG_DEBUG),
|
|
|
|
"FUSE_OPENDIR %llu: n=0x%llx",
|
|
|
|
(unsigned long long) ih->unique,
|
|
|
|
(unsigned long long) ih->nodeid);
|
2013-08-09 16:16:13 +00:00
|
|
|
} else {
|
2013-09-08 07:54:58 +00:00
|
|
|
syslog(LOG_MAKEPRI(LOG_DAEMON, LOG_DEBUG),
|
|
|
|
"FUSE_OPEN %llu: n=0x%llx",
|
|
|
|
(unsigned long long) ih-> unique,
|
|
|
|
(unsigned long long) ih->nodeid);
|
2009-04-14 19:54:53 +00:00
|
|
|
}
|
2013-09-08 07:54:58 +00:00
|
|
|
syslog(LOG_MAKEPRI(LOG_DAEMON, LOG_DEBUG), " u=%u g=%u p=%u",
|
|
|
|
ih->uid, ih->gid, ih->pid);
|
|
|
|
syslog(LOG_MAKEPRI(LOG_DAEMON, LOG_DEBUG), " f=0x%x", in->flags);
|
2009-04-14 19:54:53 +00:00
|
|
|
}
|
|
|
|
|
2013-08-09 16:16:13 +00:00
|
|
|
int fd = 0;
|
|
|
|
oh->error = dav_open(&fd, (dav_node *) ((size_t) ih->nodeid), in->flags,
|
|
|
|
ih->uid, 0);
|
|
|
|
|
|
|
|
if (oh->error || !fd) {
|
|
|
|
if (!oh->error)
|
|
|
|
oh->error = EIO;
|
|
|
|
oh->error *= -1;
|
|
|
|
return sizeof(struct fuse_out_header);
|
|
|
|
}
|
|
|
|
|
|
|
|
out->open_flags = in->flags & (O_ACCMODE | O_APPEND);
|
|
|
|
out->fh = fd;
|
|
|
|
out->padding = 0;
|
|
|
|
|
|
|
|
if (debug)
|
|
|
|
syslog(LOG_MAKEPRI(LOG_DAEMON, LOG_DEBUG), " fd %i", fd);
|
2013-09-08 07:54:58 +00:00
|
|
|
|
2013-08-09 16:16:13 +00:00
|
|
|
return sizeof(struct fuse_out_header) + sizeof(struct fuse_open_out);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static uint32_t
|
|
|
|
fuse_read(void)
|
|
|
|
{
|
2013-09-08 07:54:58 +00:00
|
|
|
struct fuse_read_in *in = (struct fuse_read_in *) upcall;
|
|
|
|
|
2013-08-09 16:16:13 +00:00
|
|
|
if (debug) {
|
|
|
|
if (ih->opcode == FUSE_READDIR) {
|
2013-09-08 07:54:58 +00:00
|
|
|
syslog(LOG_MAKEPRI(LOG_DAEMON, LOG_DEBUG),
|
|
|
|
"FUSE_READDIR %llu: n=0x%llx",
|
|
|
|
(unsigned long long) ih->unique,
|
|
|
|
(unsigned long long) ih->nodeid);
|
2013-08-09 16:16:13 +00:00
|
|
|
} else {
|
2013-09-08 07:54:58 +00:00
|
|
|
syslog(LOG_MAKEPRI(LOG_DAEMON, LOG_DEBUG),
|
|
|
|
"FUSE_READ %llu: n=0x%llx",
|
|
|
|
(unsigned long long) ih-> unique,
|
|
|
|
(unsigned long long) ih->nodeid);
|
2013-08-09 16:16:13 +00:00
|
|
|
}
|
2013-09-08 07:54:58 +00:00
|
|
|
syslog(LOG_MAKEPRI(LOG_DAEMON, LOG_DEBUG), " u=%u g=%u p=%u",
|
|
|
|
ih->uid, ih->gid, ih->pid);
|
|
|
|
syslog(LOG_MAKEPRI(LOG_DAEMON, LOG_DEBUG), " fh=%llu, off=%llu, sz=%u",
|
|
|
|
(unsigned long long) in->fh, (unsigned long long) in->offset,
|
|
|
|
in->size);
|
|
|
|
syslog(LOG_MAKEPRI(LOG_DAEMON, LOG_DEBUG), " rf=0x%x, f=0x%x",
|
|
|
|
in->read_flags, in->flags);
|
2009-04-14 19:54:53 +00:00
|
|
|
}
|
|
|
|
|
2013-08-09 16:16:13 +00:00
|
|
|
if (in->size > (buf_size - sizeof(struct fuse_out_header))) {
|
|
|
|
oh->error = -EINVAL;
|
|
|
|
return sizeof(struct fuse_out_header);
|
2009-04-14 19:54:53 +00:00
|
|
|
}
|
|
|
|
|
2013-08-09 16:16:13 +00:00
|
|
|
ssize_t len;
|
|
|
|
oh->error = dav_read(&len, (dav_node *) ((size_t) ih->nodeid),
|
2013-09-08 07:54:58 +00:00
|
|
|
in->fh, reply, in->size, in->offset);
|
2013-08-09 16:16:13 +00:00
|
|
|
|
|
|
|
if (oh->error)
|
|
|
|
oh->error *= -1;
|
|
|
|
|
|
|
|
return len + sizeof(struct fuse_out_header);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static uint32_t
|
|
|
|
fuse_release(void)
|
|
|
|
{
|
2013-09-08 07:54:58 +00:00
|
|
|
struct fuse_release_in *in = (struct fuse_release_in *) upcall;
|
|
|
|
|
2013-08-09 16:16:13 +00:00
|
|
|
if (debug) {
|
|
|
|
if (ih->opcode == FUSE_RELEASEDIR) {
|
2013-09-08 07:54:58 +00:00
|
|
|
syslog(LOG_MAKEPRI(LOG_DAEMON, LOG_DEBUG),
|
|
|
|
"FUSE_RELEASEDIR %llu: n=0x%llx",
|
|
|
|
(unsigned long long) ih->unique,
|
|
|
|
(unsigned long long) ih->nodeid);
|
2013-08-09 16:16:13 +00:00
|
|
|
} else {
|
2013-09-08 07:54:58 +00:00
|
|
|
syslog(LOG_MAKEPRI(LOG_DAEMON, LOG_DEBUG),
|
|
|
|
"FUSE_RELEASE %llu: n=0x%llx",
|
|
|
|
(unsigned long long) ih->unique,
|
|
|
|
(unsigned long long) ih->nodeid);
|
2013-08-09 16:16:13 +00:00
|
|
|
}
|
2013-09-08 07:54:58 +00:00
|
|
|
syslog(LOG_MAKEPRI(LOG_DAEMON, LOG_DEBUG), " u=%u g=%u p=%u",
|
|
|
|
ih->uid, ih->gid, ih->pid);
|
|
|
|
syslog(LOG_MAKEPRI(LOG_DAEMON, LOG_DEBUG), " fh=%llu, f=0x%x, rf=0x%x",
|
|
|
|
(unsigned long long) in->fh, in->flags, in->release_flags);
|
2009-04-14 19:54:53 +00:00
|
|
|
}
|
|
|
|
|
2013-08-09 16:16:13 +00:00
|
|
|
oh->error = dav_close((dav_node *) ((size_t) ih->nodeid), in->fh,
|
|
|
|
in->flags, ih->pid, 0);
|
|
|
|
|
|
|
|
if (oh->error)
|
|
|
|
oh->error *= -1;
|
|
|
|
|
|
|
|
return sizeof(struct fuse_out_header);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static uint32_t
|
|
|
|
fuse_rename(void)
|
|
|
|
{
|
2013-09-08 07:54:58 +00:00
|
|
|
struct fuse_rename_in *in = (struct fuse_rename_in *) upcall;
|
|
|
|
char *old = upcall + sizeof(struct fuse_rename_in);
|
2013-08-09 16:16:13 +00:00
|
|
|
char *new = old + strlen(old) + 1;
|
2013-09-08 07:54:58 +00:00
|
|
|
|
2013-08-09 16:16:13 +00:00
|
|
|
if (debug) {
|
2013-09-08 07:54:58 +00:00
|
|
|
syslog(LOG_MAKEPRI(LOG_DAEMON, LOG_DEBUG), "FUSE_RENAME %llu: n=0x%llx",
|
|
|
|
(unsigned long long) ih->unique,
|
|
|
|
(unsigned long long) ih->nodeid);
|
|
|
|
syslog(LOG_MAKEPRI(LOG_DAEMON, LOG_DEBUG), " u=%u g=%u p=%u",
|
|
|
|
ih->uid, ih->gid, ih->pid);
|
|
|
|
syslog(LOG_MAKEPRI(LOG_DAEMON, LOG_DEBUG), " %s", old);
|
|
|
|
syslog(LOG_MAKEPRI(LOG_DAEMON, LOG_DEBUG), " n=0x%llx %s",
|
2013-08-09 16:16:13 +00:00
|
|
|
(unsigned long long) in->newdir, new);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (in->newdir == 1)
|
|
|
|
in->newdir = root;
|
|
|
|
oh->error = dav_rename((dav_node *) ((size_t) ih->nodeid), old,
|
|
|
|
(dav_node *) ((size_t) in->newdir), new, ih->uid);
|
|
|
|
|
|
|
|
if (oh->error)
|
|
|
|
oh->error *= -1;
|
|
|
|
|
|
|
|
return sizeof(struct fuse_out_header);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static uint32_t
|
|
|
|
fuse_setattr(void)
|
|
|
|
{
|
2013-09-08 07:54:58 +00:00
|
|
|
struct fuse_setattr_in *in = (struct fuse_setattr_in *) upcall;
|
|
|
|
struct fuse_attr_out *out = (struct fuse_attr_out *) reply;
|
|
|
|
|
2013-08-09 16:16:13 +00:00
|
|
|
if (debug) {
|
2013-09-08 07:54:58 +00:00
|
|
|
syslog(LOG_MAKEPRI(LOG_DAEMON, LOG_DEBUG), "FUSE_SETATTR %llu: n=0x%llx",
|
|
|
|
(unsigned long long) ih->unique,
|
|
|
|
(unsigned long long) ih->nodeid);
|
|
|
|
syslog(LOG_MAKEPRI(LOG_DAEMON, LOG_DEBUG), " u=%u g=%u p=%u",
|
|
|
|
ih->uid, ih->gid, ih->pid);
|
|
|
|
syslog(LOG_MAKEPRI(LOG_DAEMON, LOG_DEBUG), " v=0x%x sz=%llu",
|
|
|
|
in->valid, (unsigned long long) in->size);
|
|
|
|
syslog(LOG_MAKEPRI(LOG_DAEMON, LOG_DEBUG), " at=%llu mt=%llu",
|
|
|
|
(unsigned long long) in->atime, (unsigned long long) in->mtime);
|
|
|
|
syslog(LOG_MAKEPRI(LOG_DAEMON, LOG_DEBUG), " m=0%o uid=%u gid=%u",
|
|
|
|
in->mode, in->uid, in->gid);
|
2013-08-09 16:16:13 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
oh->error = dav_setattr((dav_node *) ((size_t) ih->nodeid), ih->uid,
|
|
|
|
in->valid & FATTR_MODE, in->mode,
|
|
|
|
in->valid & FATTR_UID, in->uid,
|
|
|
|
in->valid & FATTR_GID, in->gid,
|
|
|
|
in->valid & FATTR_ATIME, in->atime,
|
|
|
|
in->valid & FATTR_MTIME, in->mtime,
|
|
|
|
in->valid & FATTR_SIZE, in->size);
|
|
|
|
|
|
|
|
if (oh->error) {
|
|
|
|
oh->error *= -1;
|
|
|
|
return sizeof(struct fuse_out_header);
|
|
|
|
}
|
|
|
|
|
|
|
|
set_attr(&out->attr, (dav_node *) ((size_t) ih->nodeid));
|
|
|
|
out->attr_valid = 1;
|
|
|
|
out->attr_valid_nsec = 0;
|
|
|
|
out->dummy = 0;
|
|
|
|
|
|
|
|
return sizeof(struct fuse_out_header) + sizeof(struct fuse_attr_out);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static uint32_t
|
|
|
|
fuse_stat(void)
|
|
|
|
{
|
2013-09-08 07:54:58 +00:00
|
|
|
struct fuse_statfs_out *out = (struct fuse_statfs_out *) reply;
|
|
|
|
|
|
|
|
if (debug) {
|
|
|
|
syslog(LOG_MAKEPRI(LOG_DAEMON, LOG_DEBUG), "FUSE_STATFS %llu: n=0x%llx",
|
|
|
|
(unsigned long long) ih->unique,
|
|
|
|
(unsigned long long) ih->nodeid);
|
|
|
|
syslog(LOG_MAKEPRI(LOG_DAEMON, LOG_DEBUG), " u=%u g=%u p=%u",
|
|
|
|
ih->uid, ih->gid, ih->pid);
|
|
|
|
}
|
2013-08-09 16:16:13 +00:00
|
|
|
|
|
|
|
dav_stat *st = dav_statfs();
|
|
|
|
if (!st) {
|
|
|
|
oh->error = -ENOSYS;
|
|
|
|
return sizeof(struct fuse_out_header);
|
|
|
|
}
|
|
|
|
|
|
|
|
int nblocks = (buf_size - sizeof(struct fuse_in_header)
|
|
|
|
- sizeof(struct fuse_write_in) - 4095) / st->bsize;
|
|
|
|
if (nblocks > 1) {
|
|
|
|
out->st.blocks = st->blocks / nblocks;
|
|
|
|
out->st.bfree = st->bfree / nblocks;
|
|
|
|
out->st.bavail = st->bavail / nblocks;
|
|
|
|
out->st.bsize = st->bsize * nblocks;
|
|
|
|
} else {
|
|
|
|
out->st.blocks = st->blocks;
|
|
|
|
out->st.bfree = st->bfree;
|
|
|
|
out->st.bavail = st->bavail;
|
|
|
|
out->st.bsize = st->bsize;
|
|
|
|
}
|
|
|
|
out->st.files = st->files;
|
|
|
|
out->st.ffree = st->ffree;
|
|
|
|
out->st.namelen = st->namelen;
|
|
|
|
out->st.frsize = 0;
|
|
|
|
out->st.padding = 0;
|
|
|
|
int i;
|
|
|
|
for (i = 0; i < 6; i++)
|
|
|
|
out->st.spare[i] = 0;
|
|
|
|
|
|
|
|
oh->error = 0;
|
|
|
|
return sizeof(struct fuse_out_header) + sizeof(struct fuse_statfs_out);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static uint32_t
|
|
|
|
fuse_write(void)
|
|
|
|
{
|
2013-09-08 07:54:58 +00:00
|
|
|
struct fuse_write_in *in = (struct fuse_write_in *) upcall;
|
|
|
|
struct fuse_write_out *out = (struct fuse_write_out *) reply;
|
|
|
|
|
2013-08-09 16:16:13 +00:00
|
|
|
if (debug) {
|
2013-09-08 07:54:58 +00:00
|
|
|
syslog(LOG_MAKEPRI(LOG_DAEMON, LOG_DEBUG), "FUSE_WRITE %llu: n=0x%llx",
|
|
|
|
(unsigned long long) ih->unique,
|
|
|
|
(unsigned long long) ih->nodeid);
|
|
|
|
syslog(LOG_MAKEPRI(LOG_DAEMON, LOG_DEBUG), " u=%u g=%u p=%u",
|
|
|
|
ih->uid, ih->gid, ih->pid);
|
|
|
|
syslog(LOG_MAKEPRI(LOG_DAEMON, LOG_DEBUG), " fh=%llu, off=%llu, sz=%u",
|
|
|
|
(unsigned long long) in->fh, (unsigned long long) in->offset,
|
|
|
|
in->size);
|
|
|
|
syslog(LOG_MAKEPRI(LOG_DAEMON, LOG_DEBUG), " wf=0x%x, f=0x%x",
|
|
|
|
in->write_flags, in->flags);
|
2013-08-09 16:16:13 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
if (in->size > (buf_size - sizeof(struct fuse_in_header)
|
|
|
|
- sizeof(struct fuse_write_in))) {
|
|
|
|
oh->error = -EINVAL;
|
|
|
|
return sizeof(struct fuse_out_header);
|
|
|
|
}
|
|
|
|
|
|
|
|
size_t size;
|
|
|
|
oh->error = dav_write(&size, (dav_node *) ((size_t) ih->nodeid),
|
2013-09-08 07:54:58 +00:00
|
|
|
in->fh, upcall + sizeof(struct fuse_write_in),
|
2013-08-09 16:16:13 +00:00
|
|
|
in->size, in->offset);
|
|
|
|
|
|
|
|
if (oh->error) {
|
|
|
|
oh->error *= -1;
|
|
|
|
return sizeof(struct fuse_out_header);
|
|
|
|
}
|
|
|
|
|
|
|
|
out->size = size;
|
|
|
|
out->padding = 0;
|
|
|
|
|
|
|
|
return sizeof(struct fuse_out_header) + sizeof(struct fuse_write_out);
|
|
|
|
}
|
|
|
|
|
2013-09-08 07:54:58 +00:00
|
|
|
static uint32_t
|
|
|
|
not_implemented(const char *msg)
|
|
|
|
{
|
|
|
|
if (debug)
|
|
|
|
syslog(LOG_MAKEPRI(LOG_DAEMON, LOG_DEBUG), "%s", msg);
|
|
|
|
|
|
|
|
oh->error = -ENOSYS;
|
|
|
|
|
|
|
|
return sizeof(struct fuse_out_header);
|
|
|
|
}
|
|
|
|
|
2013-08-09 16:16:13 +00:00
|
|
|
|
|
|
|
/* Auxiliary functions. */
|
|
|
|
|
|
|
|
/* Writes a struct fuse_dirent to file with file descriptor fd.
|
|
|
|
fd : An open file descriptor to write to.
|
|
|
|
off : The current file size.
|
|
|
|
name : File name; if NULL, the last, empty entry is written.
|
|
|
|
return value : New size of the file. -1 in case of an error. */
|
|
|
|
static off_t
|
|
|
|
write_dir_entry(int fd, off_t off, const dav_node *node, const char *name)
|
|
|
|
{
|
|
|
|
if (!name)
|
|
|
|
return off;
|
|
|
|
|
|
|
|
struct fuse_dirent entry;
|
|
|
|
size_t head = offsetof(struct fuse_dirent, name);
|
|
|
|
size_t reclen = (head + strlen(name) + sizeof(uint64_t) -1)
|
|
|
|
& ~(sizeof(uint64_t) - 1);
|
|
|
|
|
|
|
|
entry.ino = (((size_t) node) == root) ? 1 : (size_t) node;
|
|
|
|
entry.off = off + reclen;
|
|
|
|
entry.namelen = strlen(name);
|
|
|
|
entry.type = (node->mode & S_IFMT) >> 12;
|
|
|
|
|
|
|
|
size_t size = 0;
|
|
|
|
ssize_t ret = 0;
|
|
|
|
while (ret >= 0 && size < head) {
|
|
|
|
ret = write(fd, (char *) &entry + size, head - size);
|
|
|
|
size += ret;
|
|
|
|
}
|
|
|
|
if (size != head)
|
|
|
|
return -1;
|
|
|
|
|
|
|
|
ret = 0;
|
|
|
|
while (ret >= 0 && size < (head + entry.namelen)) {
|
|
|
|
ret = write(fd, name + size - head, entry.namelen - size + head);
|
|
|
|
size += ret;
|
|
|
|
}
|
|
|
|
if (size != (head + entry.namelen))
|
|
|
|
return -1;
|
|
|
|
|
|
|
|
ret = 0;
|
|
|
|
while (ret >= 0 && size < reclen) {
|
|
|
|
ret = write(fd, "\0", 1);
|
|
|
|
size += ret;
|
|
|
|
}
|
|
|
|
if (size != reclen)
|
|
|
|
return -1;
|
|
|
|
|
|
|
|
return off + reclen;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
set_attr(struct fuse_attr *attr, const dav_node *node)
|
|
|
|
{
|
|
|
|
attr->ino = (((size_t) node) == root) ? 1 : (size_t) node;
|
|
|
|
attr->size = node->size;
|
|
|
|
attr->blocks = (node->size + 511) / 512;
|
|
|
|
attr->atime = node->atime;
|
|
|
|
attr->mtime = node->mtime;
|
|
|
|
attr->ctime = node->ctime;
|
|
|
|
attr->atimensec = 0;
|
|
|
|
attr->mtimensec = 0;
|
|
|
|
attr->ctimensec = 0;
|
|
|
|
attr->mode = node->mode;
|
|
|
|
if (S_ISDIR(node->mode)) {
|
|
|
|
attr->nlink = node->nref;
|
|
|
|
} else {
|
|
|
|
attr->nlink = 1;
|
|
|
|
}
|
|
|
|
attr->uid = node->uid;
|
|
|
|
attr->gid = node->gid;
|
|
|
|
attr->rdev = 0;
|
2013-09-08 07:54:58 +00:00
|
|
|
/* TODO: set blocksize */
|
|
|
|
attr->blksize = 0;
|
|
|
|
attr->padding = 0;
|
2009-04-14 19:54:53 +00:00
|
|
|
}
|