summary | shortlog | log | commit | commitdiff | tree
raw | patch | inline | side by side (parent: 5a4bf7b)
raw | patch | inline | side by side (parent: 5a4bf7b)
author | Lennart Poettering <lennart@poettering.net> | |
Wed, 1 Mar 2006 00:46:23 +0000 (00:46 +0000) | ||
committer | Lennart Poettering <lennart@poettering.net> | |
Wed, 1 Mar 2006 00:46:23 +0000 (00:46 +0000) |
* assorted other updates
git-svn-id: file:///home/lennart/svn/public/fusedav/trunk@10 e35a362c-bbd6-0310-a59f-a4efcb1729c4
git-svn-id: file:///home/lennart/svn/public/fusedav/trunk@10 e35a362c-bbd6-0310-a59f-a4efcb1729c4
bootstrap.sh | patch | blob | history | |
configure.ac | patch | blob | history | |
src/Makefile.am | patch | blob | history | |
src/filecache.c | patch | blob | history | |
src/filecache.h | patch | blob | history | |
src/fusedav.c | patch | blob | history | |
src/fusedav.h | patch | blob | history | |
src/openssl-thread.c | patch | blob | history | |
src/session.c | patch | blob | history | |
src/session.h | patch | blob | history | |
src/statcache.c | patch | blob | history |
diff --git a/bootstrap.sh b/bootstrap.sh
index 2ff93b4119003b0eaa11021256fbe97534c175b2..173b9fb0a7a39fb212aa27af5805b52d41364e64 100755 (executable)
--- a/bootstrap.sh
+++ b/bootstrap.sh
run_versioned automake 1.7 -a -c
autoconf -Wall
- ./configure --sysconfdir=/etc "$@"
+ CFLAGS="-g -O0" ./configure --sysconfdir=/etc "$@"
make clean
fi
diff --git a/configure.ac b/configure.ac
index 1aa56946493b62caf02010d8f9a0746418d5b184..2a67b1e7cc294b77bd8fc4d6d269077c02a51552 100644 (file)
--- a/configure.ac
+++ b/configure.ac
ac_default_prefix="/usr/local/stow/${PACKAGE_NAME}-${PACKAGE_VERSION}"
fi
+AC_GNU_SOURCE
+
# Checks for programs.
AC_PROG_CC
AC_PROG_CPP
AC_PROG_LN_S
AC_PROG_MAKE_SET
-# If using GCC specifiy some additional parameters
+test_gcc_flag() {
+ AC_LANG_CONFTEST([int main() {}])
+ $CC -c conftest.c $CFLAGS $@ > /dev/null 2> /dev/null
+ ret=$?
+ rm -f conftest.o
+ return $ret
+}
+
+# If using GCC specify some additional parameters
if test "x$GCC" = "xyes" ; then
- CFLAGS="$CFLAGS -pipe -Wall -ansi"
+
+ DESIRED_FLAGS="-Wall -W -Wextra -pedantic -pipe -Wformat -Wold-style-definition -Wdeclaration-after-statement -Wfloat-equal -Wmissing-declarations -Wmissing-prototypes -Wstrict-prototypes -Wredundant-decls -Wmissing-noreturn -Wshadow -Wendif-labels -Wpointer-arith -Wbad-function-cast -Wcast-qual -Wcast-align -Wwrite-strings -Winline"
+
+ if test "x$HAVE_NETLINK" = "xyes" ; then
+ # Test whether rtnetlink.h can be included when compiled with -std=c99
+ # some distributions (e.g. archlinux) have broken headers that dont
+ # define __u64 with -std=c99
+ AC_MSG_CHECKING([checking whether rtnetlink.h can be included with -std=c99])
+ OLDCFLAGS="$CFLAGS"
+ CFLAGS="-std=c99"
+ AC_TRY_COMPILE([#include <linux/rtnetlink.h>], [],
+ use_stdc99=yes, use_stdc99=no)
+
+ if test x"$use_stdc99" = xyes; then
+ DESIRED_FLAGS="-std=c99 $DESIRED_FLAGS"
+ AC_MSG_RESULT([yes])
+ else
+ AC_MSG_RESULT([no])
+ fi
+
+ CFLAGS="$OLDCFLAGS"
+ else
+ DESIRED_FLAGS="-std=c99 $DESIRED_FLAGS"
+ fi
+
+ for flag in $DESIRED_FLAGS ; do
+ AC_MSG_CHECKING([whether $CC accepts $flag])
+ if test_gcc_flag $flag ; then
+ CFLAGS="$CFLAGS $flag"
+ AC_MSG_RESULT([yes])
+ else
+ AC_MSG_RESULT([no])
+ fi
+ done
fi
# 64 Bit LFS support
AC_CHECK_LIB([pthread], [pthread_create])
-NEON_REQUIRE(0,24)
-NEON_LIBRARY
-NEON_WARNINGS
-
-# FUSE
-AC_CHECK_HEADER(fuse.h,, [AC_MSG_ERROR([ *** fuse.h not found *** ])])
-AC_CHECK_LIB(fuse,fuse_main, [FUSE_LIBS="-lfuse"], [AC_MSG_ERROR([ *** libfuse.a not found *** ])], -lpthread)
-AC_SUBST(FUSE_LIBS)
+PKG_CHECK_MODULES(NEON, [ neon >= 0.25 ])
+PKG_CHECK_MODULES(FUSE, [ fuse >= 2.5 ])
# LYNX documentation generation
AC_ARG_ENABLE(lynx,
diff --git a/src/Makefile.am b/src/Makefile.am
index 0221fc5eea0d9d19d5b76463ec5a5954e12ee3a4..b74d7c0bb20d99a0c64ab6927c5fc482adf31aa5 100644 (file)
--- a/src/Makefile.am
+++ b/src/Makefile.am
session.c session.h \
openssl-thread.c openssl-thread.h
-fusedav_CFLAGS = $(AM_CFLAGS) -D_GNU_SOURCE $
+fusedav_CFLAGS = $(AM_CFLAGS) $(NEON_CFLAGS) $(FUSE_CFLAGS) -DFUSE_USE_VERSION=25
fusedav_LDADD = -lpthread $(NEON_LIBS) $(FUSE_LIBS)
diff --git a/src/filecache.c b/src/filecache.c
index 985d575ac1cbfc8867104c146ad94bce3e3c00b0..e3f9b6b1e79a052a3be47cd24b197e862e45251b 100644 (file)
--- a/src/filecache.c
+++ b/src/filecache.c
#include <ne_basic.h>
#include "filecache.h"
+#include "statcache.h"
#include "fusedav.h"
#include "session.h"
-#include "statcache.h"
struct file_info {
char *filename;
static struct file_info *files = NULL;
static pthread_mutex_t files_mutex = PTHREAD_MUTEX_INITIALIZER;
-int file_cache_sync_unlocked(struct file_info *fi);
+static int file_cache_sync_unlocked(struct file_info *fi);
void* file_cache_get(const char *path) {
struct file_info *f, *r = NULL;
void* file_cache_open(const char *path, int flags) {
struct file_info *fi;
char tempfile[PATH_MAX];
- char *length = NULL;
+ const char *length = NULL;
ne_request *req = NULL;
ne_session *session;
+ if (!(session = session_get(1))) {
+ errno = EIO;
+ goto fail;
+ }
+
if ((fi = file_cache_get(path))) {
if (flags & O_RDONLY || flags & O_RDWR) fi->readable = 1;
if (flags & O_WRONLY || flags & O_RDWR) fi->writable = 1;
return fi;
}
- if (!(session = session_get())) {
- errno = -EIO;
- return NULL;
- }
-
fi = malloc(sizeof(struct file_info));
memset(fi, 0, sizeof(struct file_info));
fi->fd = -1;
req = ne_request_create(session, "HEAD", path);
assert(req);
- ne_add_response_header_handler(req, "Content-Length", ne_duplicate_header, &length);
-
if (ne_request_dispatch(req) != NE_OK) {
fprintf(stderr, "HEAD failed: %s\n", ne_get_error(session));
errno = ENOENT;
goto fail;
}
- if (!length) {
- fprintf(stderr, "HEAD did not return content length.\n");
- errno = EPROTO;
- goto fail;
- }
-
- fi->server_length = fi->length = atoi(length);
+ if (!(length = ne_get_response_header(req, "Content-Length")))
+ /* dirty hack, since Apache doesn't send the file size if the file is empty */
+ fi->server_length = fi->length = 0;
+ else
+ fi->server_length = fi->length = atoi(length);
ne_request_destroy(req);
- free(length);
if (flags & O_RDONLY || flags & O_RDWR) fi->readable = 1;
if (flags & O_WRONLY || flags & O_RDWR) fi->writable = 1;
if (req)
ne_request_destroy(req);
- if (length)
- free(length);
-
if (fi) {
if (fi->fd >= 0)
close(fi->fd);
static int load_up_to_unlocked(struct file_info *fi, off_t l) {
ne_content_range range;
- assert(fi);
ne_session *session;
- if (!(session = session_get())) {
+ assert(fi);
+
+ if (!(session = session_get(1))) {
errno = EIO;
return -1;
}
range.start = fi->present;
range.end = l-1;
+ range.total = 0;
- if (ne_get_range(session, fi->filename, &range, fi->fd)) {
+ if (ne_get_range(session, fi->filename, &range, fi->fd) != NE_OK) {
fprintf(stderr, "GET failed: %s\n", ne_get_error(session));
errno = ENOENT;
return -1;
fi->modified = 1;
- r = 0;
-
finish:
pthread_mutex_unlock(&fi->mutex);
int file_cache_truncate(void *f, off_t s) {
struct file_info *fi = f;
- assert(fi);
int r;
+ assert(fi);
+
pthread_mutex_lock(&fi->mutex);
fi->length = s;
int file_cache_sync_unlocked(struct file_info *fi) {
int r = -1;
ne_session *session;
- assert(fi);
-
- if (!(session = session_get())) {
- errno = EIO;
- goto finish;
- }
+ assert(fi);
+
if (!fi->writable) {
errno = EBADF;
goto finish;
if (lseek(fi->fd, 0, SEEK_SET) == (off_t)-1)
goto finish;
+ if (!(session = session_get(1))) {
+ errno = EIO;
+ goto finish;
+ }
if (ne_put(session, fi->filename, fi->fd)) {
fprintf(stderr, "PUT failed: %s\n", ne_get_error(session));
return r;
}
+
+off_t file_cache_get_size(void *f) {
+ struct file_info *fi = f;
+
+ assert(fi);
+
+ return fi->length;
+}
diff --git a/src/filecache.h b/src/filecache.h
index f4b50b4e7668e42c0115db6fe2b4e4b4ef022eec..c3845ca1171a69df0440931a45883cf326f5cae0 100644 (file)
--- a/src/filecache.h
+++ b/src/filecache.h
#include <sys/types.h>
+#include <ne_session.h>
+
void* file_cache_open(const char *path, int flags);
void* file_cache_get(const char *path);
void file_cache_unref(void *f);
int file_cache_sync(void *f);
int file_cache_close_all(void);
+off_t file_cache_get_size(void *f);
#endif
diff --git a/src/fusedav.c b/src/fusedav.c
index 92fceb1487d96bf8ac23865ddaa4263d4459db82..ed990e6d6289c362c8a52a96c78045bc9d4bcdc5 100644 (file)
--- a/src/fusedav.c
+++ b/src/fusedav.c
#include <errno.h>
#include <sys/statfs.h>
#include <getopt.h>
+#include <attr/xattr.h>
#include <ne_request.h>
#include <ne_basic.h>
#include <ne_socket.h>
#include <ne_auth.h>
#include <ne_dates.h>
+#include <ne_redirect.h>
+#include <ne_uri.h>
#include <fuse.h>
#include "filecache.h"
#include "session.h"
#include "openssl-thread.h"
+#include "fusedav.h"
const ne_propname query_properties[] = {
{ "DAV:", "resourcetype" },
mode_t mask = 0;
int debug = 0;
struct fuse* fuse = NULL;
+ne_lock_store *lock_store = NULL;
+struct ne_lock *lock = NULL;
+int lock_thread_exit = 0;
+
+#define MIME_XATTR "user.mime_type"
+
+#define MAX_REDIRECTS 10
+#define LOCK_TIMEOUT 8
struct fill_info {
- fuse_dirh_t h;
- fuse_dirfil_t filler;
+ void *buf;
+ fuse_fill_dir_t filler;
const char *root;
};
return r;
}
+static int simple_propfind_with_redirect(
+ ne_session *session,
+ const char *path,
+ int depth,
+ const ne_propname *props,
+ ne_props_result results,
+ void *userdata) {
+
+ int i, ret;
+
+ for (i = 0; i < MAX_REDIRECTS; i++) {
+ const ne_uri *u;
+
+ if ((ret = ne_simple_propfind(session, path, depth, props, results, userdata)) != NE_REDIRECT)
+ return ret;
+
+ if (!(u = ne_redirect_location(session)))
+ break;
+
+ if (!session_is_local(u))
+ break;
+
+ if (debug)
+ fprintf(stderr, "REDIRECT FROM '%s' to '%s'\n", path, u->path);
+
+ path = u->path;
+ }
+
+ return ret;
+}
+
+static int proppatch_with_redirect(
+ ne_session *session,
+ const char *path,
+ const ne_proppatch_operation *ops) {
+
+ int i, ret;
+
+ for (i = 0; i < MAX_REDIRECTS; i++) {
+ const ne_uri *u;
+
+ if ((ret = ne_proppatch(session, path, ops)) != NE_REDIRECT)
+ return ret;
+
+ if (!(u = ne_redirect_location(session)))
+ break;
+
+ if (!session_is_local(u))
+ break;
+
+ if (debug)
+ fprintf(stderr, "REDIRECT FROM '%s' to '%s'\n", path, u->path);
+
+ path = u->path;
+ }
+
+ return ret;
+}
+
+
static void fill_stat(struct stat* st, const ne_prop_result_set *results, int is_dir) {
const char *rt, *e, *gcl, *glm, *cd;
const ne_propname resourcetype = { "DAV:", "resourcetype" };
@@ -134,8 +206,7 @@ static void fill_stat(struct stat* st, const ne_prop_result_set *results, int is
st->st_atime = time(NULL);
st->st_mtime = glm ? ne_rfc1123_parse(glm) : 0;
st->st_ctime = cd ? ne_iso8601_parse(cd) : 0;
-
-
+
st->st_blocks = (st->st_size+511)/512;
/*fprintf(stderr, "a: %u; m: %u; c: %u\n", st->st_atime, st->st_mtime, st->st_ctime);*/
@@ -147,7 +218,9 @@ static void fill_stat(struct stat* st, const ne_prop_result_set *results, int is
static char *strip_trailing_slash(char *fn, int *is_dir) {
size_t l = strlen(fn);
- assert(fn && is_dir);
+ assert(fn);
+ assert(is_dir);
+ assert(l > 0);
if ((*is_dir = (fn[l-1] == '/')))
fn[l-1] = 0;
@@ -176,7 +249,7 @@ static void getdir_propfind_callback(void *userdata, const char *href, const ne_
t = fn;
dir_cache_add(f->root, t, is_dir);
- f->filler(f->h, h = ne_path_unescape(t), is_dir ? DT_DIR : DT_REG);
+ f->filler(f->buf, h = ne_path_unescape(t), NULL, 0);
free(h);
}
@@ -184,23 +257,31 @@ static void getdir_propfind_callback(void *userdata, const char *href, const ne_
stat_cache_set(fn, &st);
}
-static void getdir_cache_callback(const char *root, const char *fn, int is_dir, void *user) {
+static void getdir_cache_callback(
+ const char *root,
+ const char *fn,
+ int is_dir,
+ void *user) {
+
struct fill_info *f = user;
- assert(f);
char path[PATH_MAX];
- struct stat st;
char *h;
- snprintf(path, sizeof(path), "%s/%s", !strcmp(root, "/") ? "" : root, fn);
+ assert(f);
- if (get_stat(path, &st) < 0)
- return;
+ snprintf(path, sizeof(path), "%s/%s", !strcmp(root, "/") ? "" : root, fn);
- f->filler(f->h, h = ne_path_unescape(fn), is_dir ? DT_DIR : DT_REG);
+ f->filler(f->buf, h = ne_path_unescape(fn), NULL, 0);
free(h);
}
-static int dav_getdir(const char *path, fuse_dirh_t h, fuse_dirfil_t filler) {
+static int dav_readdir(
+ const char *path,
+ void *buf,
+ fuse_fill_dir_t filler,
+ off_t offset,
+ struct fuse_file_info *fi) {
+
struct fill_info f;
ne_session *session;
@@ -209,21 +290,24 @@ static int dav_getdir(const char *path, fuse_dirh_t h, fuse_dirfil_t filler) {
if (debug)
fprintf(stderr, "getdir(%s)\n", path);
- f.h = h;
+ f.buf = buf;
f.filler = filler;
f.root = path;
+ filler(buf, ".", NULL, 0);
+ filler(buf, "..", NULL, 0);
+
if (dir_cache_enumerate(path, getdir_cache_callback, &f) < 0) {
if (debug)
fprintf(stderr, "DIR-CACHE-MISS\n");
- if (!(session = session_get()))
+ if (!(session = session_get(1)))
return -EIO;
dir_cache_begin(path);
- if (ne_simple_propfind(session, path, NE_DEPTH_ONE, query_properties, getdir_propfind_callback, &f) != NE_OK) {
+ if (simple_propfind_with_redirect(session, path, NE_DEPTH_ONE, query_properties, getdir_propfind_callback, &f) != NE_OK) {
dir_cache_finish(path, 2);
fprintf(stderr, "PROPFIND failed: %s\n", ne_get_error(session));
return -ENOENT;
dir_cache_finish(path, 1);
}
- filler(h, ".", DT_DIR);
- filler(h, "..", DT_DIR);
-
return 0;
}
@@ -256,7 +337,7 @@ static void getattr_propfind_callback(void *userdata, const char *href, const ne
static int get_stat(const char *path, struct stat *stbuf) {
ne_session *session;
- if (!(session = session_get()))
+ if (!(session = session_get(1)))
return -EIO;
if (stat_cache_get(path, stbuf) == 0) {
} else {
if (debug)
fprintf(stderr, "STAT-CACHE-MISS\n");
-
- if (ne_simple_propfind(session, path, NE_DEPTH_ZERO, query_properties, getattr_propfind_callback, stbuf) != NE_OK) {
+
+ if (simple_propfind_with_redirect(session, path, NE_DEPTH_ZERO, query_properties, getattr_propfind_callback, stbuf) != NE_OK) {
stat_cache_invalidate(path);
fprintf(stderr, "PROPFIND failed: %s\n", ne_get_error(session));
return -ENOENT;
if (debug)
fprintf(stderr, "unlink(%s)\n", path);
- if (!(session = session_get()))
+ if (!(session = session_get(1)))
return -EIO;
if ((r = get_stat(path, &st)) < 0)
}
static int dav_rmdir(const char *path) {
+ char fn[PATH_MAX];
int r;
struct stat st;
ne_session *session;
if (debug)
fprintf(stderr, "rmdir(%s)\n", path);
- if (!(session = session_get()))
+ if (!(session = session_get(1)))
return -EIO;
if ((r = get_stat(path, &st)) < 0)
if (!S_ISDIR(st.st_mode))
return -ENOTDIR;
+
+ snprintf(fn, sizeof(fn), "%s/", path);
- if (ne_delete(session, path)) {
+ if (ne_delete(session, fn)) {
fprintf(stderr, "DELETE failed: %s\n", ne_get_error(session));
return -ENOENT;
}
if (debug)
fprintf(stderr, "mkdir(%s)\n", path);
- if (!(session = session_get()))
+ if (!(session = session_get(1)))
return -EIO;
snprintf(fn, sizeof(fn), "%s/", path);
static int dav_rename(const char *from, const char *to) {
ne_session *session;
int r = 0;
+ struct stat st;
+ char fn[PATH_MAX], *_from;
- from = strdup(path_cvt(from));
+ from = _from = strdup(path_cvt(from));
+ assert(from);
to = path_cvt(to);
if (debug)
fprintf(stderr, "rename(%s, %s)\n", from, to);
- if (!(session = session_get())) {
+ if (!(session = session_get(1))) {
r = -EIO;
goto finish;
}
+ if ((r = get_stat(from, &st)) < 0)
+ goto finish;
+
+ if (S_ISDIR(st.st_mode)) {
+ snprintf(fn, sizeof(fn), "%s/", from);
+ from = fn;
+ }
+
if (ne_move(session, 1, from, to)) {
fprintf(stderr, "MOVE failed: %s\n", ne_get_error(session));
r = -ENOENT;
finish:
- free((char*) from);
+ free(_from);
return r;
}
-static int dav_release(const char *path, int flags) {
+static int dav_release(const char *path, struct fuse_file_info *info) {
void *f = NULL;
int r = 0;
ne_session *session;
if (debug)
fprintf(stderr, "release(%s)\n", path);
- if (!(session = session_get())) {
+ if (!(session = session_get(1))) {
r = -EIO;
goto finish;
}
return r;
}
-static int dav_fsync(const char *path, int isdatasync) {
+static int dav_fsync(const char *path, int isdatasync, struct fuse_file_info *info) {
void *f = NULL;
int r = 0;
ne_session *session;
if (debug)
fprintf(stderr, "fsync(%s)\n", path);
- if (!(session = session_get())) {
+ if (!(session = session_get(1))) {
r = -EIO;
goto finish;
}
if (debug)
fprintf(stderr, "mknod(%s)\n", path);
- if (!(session = session_get()))
+ if (!(session = session_get(1)))
return -EIO;
if (!S_ISREG(mode))
return 0;
}
-static int dav_open(const char *path, int flags) {
+static int dav_open(const char *path, struct fuse_file_info *info) {
void *f;
if (debug)
fprintf(stderr, "open(%s)\n", path);
path = path_cvt(path);
- if (!(f = file_cache_open(path, flags)))
+
+ if (!(f = file_cache_open(path, info->flags)))
return -errno;
file_cache_unref(f);
return 0;
}
-static int dav_read(const char *path, char *buf, size_t size, off_t offset) {
+static int dav_read(const char *path, char *buf, size_t size, off_t offset, struct fuse_file_info *info) {
void *f = NULL;
ssize_t r;
path = path_cvt(path);
+
if (debug)
fprintf(stderr, "read(%s, %lu+%lu)\n", path, (unsigned long) offset, (unsigned long) size);
goto finish;
}
+ fprintf(stderr, "read: %i\n", r);
+
finish:
if (f)
file_cache_unref(f);
return r;
}
-static int dav_write(const char *path, const char *buf, size_t size, off_t offset) {
+static int dav_write(const char *path, const char *buf, size_t size, off_t offset, struct fuse_file_info *info) {
void *f = NULL;
ssize_t r;
path = path_cvt(path);
+
if (debug)
fprintf(stderr, "write(%s, %lu+%lu)\n", path, (unsigned long) offset, (unsigned long) size);
ne_session *session;
path = path_cvt(path);
+
if (debug)
fprintf(stderr, "truncate(%s, %lu)\n", path, (unsigned long) size);
- if (!(session = session_get()))
+ if (!(session = session_get(1)))
r = -EIO;
goto finish;
return r;
}
+static int dav_utime(const char *path, struct utimbuf *buf) {
+ ne_session *session;
+ const ne_propname getlastmodified = { "DAV:", "getlastmodified" };
+ ne_proppatch_operation ops[2];
+ int r = 0;
+ char *date;
+
+ assert(path);
+ assert(buf);
+
+ path = path_cvt(path);
+
+ if (debug)
+ fprintf(stderr, "utime(%s, %lu, %lu)\n", path, (unsigned long) buf->actime, (unsigned long) buf->modtime);
+
+ ops[0].name = &getlastmodified;
+ ops[0].type = ne_propset;
+ ops[0].value = date = ne_rfc1123_date(buf->modtime);
+ ops[1].name = NULL;
+
+ if (!(session = session_get(1))) {
+ r = -EIO;
+ goto finish;
+ }
+
+ if (proppatch_with_redirect(session, path, ops)) {
+ fprintf(stderr, "PROPPATCH failed: %s\n", ne_get_error(session));
+ r = -ENOTSUP;
+ goto finish;
+ }
+
+ stat_cache_invalidate(path);
+
+finish:
+ free(date);
+
+ return r;
+}
+
+static const char *fix_xattr(const char *name) {
+ assert(name);
+
+ if (!strcmp(name, MIME_XATTR))
+ return "user.webdav(DAV:;getcontenttype)";
+
+ return name;
+}
+
+struct listxattr_info {
+ char *list;
+ size_t space, size;
+};
+
+static int listxattr_iterator(
+ void *userdata,
+ const ne_propname *pname,
+ const char *value,
+ const ne_status *status) {
+
+ struct listxattr_info *l = userdata;
+ int n;
+
+ assert(l);
+
+ if (!value || !pname)
+ return -1;
+
+ if (l->list) {
+ n = snprintf(l->list, l->space, "user.webdav(%s;%s)", pname->nspace, pname->name) + 1;
+
+ if (n >= (int) l->space) {
+ l->size += l->space;
+ l->space = 0;
+ return 1;
+
+ } else {
+ l->size += n;
+ l->space -= n;
+
+ if (l->list)
+ l->list += n;
+
+ return 0;
+ }
+ } else {
+ /* Calculate space */
+
+ l->size += strlen(pname->nspace) + strlen(pname->name) + 15;
+ return 0;
+ }
+}
+
+static void listxattr_propfind_callback(void *userdata, const char *href, const ne_prop_result_set *results) {
+ struct listxattr_info *l = userdata;
+ ne_propset_iterate(results, listxattr_iterator, l);
+}
+
+static int dav_listxattr(
+ const char *path,
+ char *list,
+ size_t size) {
+
+ ne_session *session;
+ struct listxattr_info l;
+
+
+ assert(path);
+
+ path = path_cvt(path);
+
+ if (debug)
+ fprintf(stderr, "listxattr(%s, .., %lu)\n", path, (unsigned long) size);
+
+ if (list) {
+ l.list = list;
+ l.space = size-1;
+ l.size = 0;
+
+ if (l.space >= sizeof(MIME_XATTR)) {
+ memcpy(l.list, MIME_XATTR, sizeof(MIME_XATTR));
+ l.list += sizeof(MIME_XATTR);
+ l.space -= sizeof(MIME_XATTR);
+ l.size += sizeof(MIME_XATTR);
+ }
+
+ } else {
+ l.list = NULL;
+ l.space = 0;
+ l.size = sizeof(MIME_XATTR);
+ }
+
+ if (!(session = session_get(1)))
+ return -EIO;
+
+ if (simple_propfind_with_redirect(session, path, NE_DEPTH_ZERO, NULL, listxattr_propfind_callback, &l) != NE_OK) {
+ fprintf(stderr, "PROPFIND failed: %s\n", ne_get_error(session));
+ return -EIO;
+ }
+
+ if (l.list) {
+ assert(l.space > 0);
+ *l.list = 0;
+ }
+
+ return l.size+1;
+}
+
+struct getxattr_info {
+ ne_propname propname;
+ char *value;
+ size_t space, size;
+};
+
+static int getxattr_iterator(
+ void *userdata,
+ const ne_propname *pname,
+ const char *value,
+ const ne_status *status) {
+
+ struct getxattr_info *g = userdata;
+
+ assert(g);
+
+ if (!value || !pname)
+ return -1;
+
+ if (strcmp(pname->nspace, g->propname.nspace) ||
+ strcmp(pname->name, g->propname.name))
+ return 0;
+
+ if (g->value) {
+ size_t l;
+
+ l = strlen(value);
+
+ if (l > g->space)
+ l = g->space;
+
+ memcpy(g->value, value, l);
+ g->size = l;
+ } else {
+ /* Calculate space */
+
+ g->size = strlen(value);
+ return 0;
+ }
+
+ return 0;
+}
+
+static void getxattr_propfind_callback(void *userdata, const char *href, const ne_prop_result_set *results) {
+ struct getxattr_info *g = userdata;
+ ne_propset_iterate(results, getxattr_iterator, g);
+}
+
+static int parse_xattr(const char *name, char *dnspace, size_t dnspace_length, char *dname, size_t dname_length) {
+ char *e;
+ size_t k;
+
+ assert(name);
+ assert(dnspace);
+ assert(dnspace_length);
+ assert(dname);
+ assert(dname_length);
+
+ if (strncmp(name, "user.webdav(", 12) ||
+ name[strlen(name)-1] != ')' ||
+ !(e = strchr(name+12, ';')))
+ return -1;
+
+ if ((k = strcspn(name+12, ";")) > dnspace_length-1)
+ return -1;
+
+ memcpy(dnspace, name+12, k);
+ dnspace[k] = 0;
+
+ e++;
+
+ if ((k = strlen(e)) > dname_length-1)
+ return -1;
+
+ assert(k > 0);
+ k--;
+
+ memcpy(dname, e, k);
+ dname[k] = 0;
+
+ return 0;
+}
+
+static int dav_getxattr(
+ const char *path,
+ const char *name,
+ char *value,
+ size_t size) {
+
+ ne_session *session;
+ struct getxattr_info g;
+ ne_propname props[2];
+ char dnspace[128], dname[128];
+
+ assert(path);
+
+ path = path_cvt(path);
+ name = fix_xattr(name);
+
+ if (debug)
+ fprintf(stderr, "getxattr(%s, %s, .., %lu)\n", path, name, (unsigned long) size);
+
+ if (parse_xattr(name, dnspace, sizeof(dnspace), dname, sizeof(dname)) < 0)
+ return -ENOATTR;
+
+ props[0].nspace = dnspace;
+ props[0].name = dname;
+ props[1].nspace = NULL;
+ props[1].name = NULL;
+
+ if (value) {
+ g.value = value;
+ g.space = size;
+ g.size = (size_t) -1;
+ } else {
+ g.value = NULL;
+ g.space = 0;
+ g.size = (size_t) -1;
+ }
+
+ g.propname = props[0];
+
+ if (!(session = session_get(1)))
+ return -EIO;
+
+ if (simple_propfind_with_redirect(session, path, NE_DEPTH_ZERO, props, getxattr_propfind_callback, &g) != NE_OK) {
+ fprintf(stderr, "PROPFIND failed: %s\n", ne_get_error(session));
+ return -EIO;
+ }
+
+ if (g.size == (size_t) -1)
+ return -ENOATTR;
+
+ return g.size;
+}
+
+static int dav_setxattr(
+ const char *path,
+ const char *name,
+ const char *value,
+ size_t size,
+ int flags) {
+
+ ne_session *session;
+ ne_propname propname;
+ ne_proppatch_operation ops[2];
+ int r = 0;
+ char dnspace[128], dname[128];
+ char *value_fixed = NULL;
+
+ assert(path);
+ assert(name);
+ assert(value);
+
+ path = path_cvt(path);
+ name = fix_xattr(name);
+
+ if (debug)
+ fprintf(stderr, "setxattr(%s, %s)\n", path, name);
+
+ if (flags) {
+ r = ENOTSUP;
+ goto finish;
+ }
+
+ if (parse_xattr(name, dnspace, sizeof(dnspace), dname, sizeof(dname)) < 0) {
+ r = -ENOATTR;
+ goto finish;
+ }
+
+ propname.nspace = dnspace;
+ propname.name = dname;
+
+ /* Add trailing NUL byte if required */
+ if (!memchr(value, 0, size)) {
+ value_fixed = malloc(size+1);
+ assert(value_fixed);
+
+ memcpy(value_fixed, value, size);
+ value_fixed[size] = 0;
+
+ value = value_fixed;
+ }
+
+ ops[0].name = &propname;
+ ops[0].type = ne_propset;
+ ops[0].value = value;
+
+ ops[1].name = NULL;
+
+ if (!(session = session_get(1))) {
+ r = -EIO;
+ goto finish;
+ }
+
+ if (proppatch_with_redirect(session, path, ops)) {
+ fprintf(stderr, "PROPPATCH failed: %s\n", ne_get_error(session));
+ r = -ENOTSUP;
+ goto finish;
+ }
+
+ stat_cache_invalidate(path);
+
+finish:
+ free(value_fixed);
+
+ return r;
+}
+
+static int dav_removexattr(const char *path, const char *name) {
+ ne_session *session;
+ ne_propname propname;
+ ne_proppatch_operation ops[2];
+ int r = 0;
+ char dnspace[128], dname[128];
+
+ assert(path);
+ assert(name);
+
+ path = path_cvt(path);
+ name = fix_xattr(name);
+
+ if (debug)
+ fprintf(stderr, "removexattr(%s, %s)\n", path, name);
+
+ if (parse_xattr(name, dnspace, sizeof(dnspace), dname, sizeof(dname)) < 0) {
+ r = -ENOATTR;
+ goto finish;
+ }
+
+ propname.nspace = dnspace;
+ propname.name = dname;
+
+ ops[0].name = &propname;
+ ops[0].type = ne_propremove;
+ ops[0].value = NULL;
+
+ ops[1].name = NULL;
+
+ if (!(session = session_get(1))) {
+ r = -EIO;
+ goto finish;
+ }
+
+ if (proppatch_with_redirect(session, path, ops)) {
+ fprintf(stderr, "PROPPATCH failed: %s\n", ne_get_error(session));
+ r = -ENOTSUP;
+ goto finish;
+ }
+
+ stat_cache_invalidate(path);
+
+finish:
+
+ return r;
+}
+
+static int dav_chmod(const char *path, mode_t mode) {
+ ne_session *session;
+ const ne_propname executable = { "http://apache.org/dav/props/", "executable" };
+ ne_proppatch_operation ops[2];
+ int r = 0;
+
+ assert(path);
+
+ path = path_cvt(path);
+
+ if (debug)
+ fprintf(stderr, "chmod(%s, %04o)\n", path, mode);
+
+ ops[0].name = &executable;
+ ops[0].type = ne_propset;
+ ops[0].value = mode & 0111 ? "T" : "F";
+ ops[1].name = NULL;
+
+ if (!(session = session_get(1))) {
+ r = -EIO;
+ goto finish;
+ }
+
+ if (proppatch_with_redirect(session, path, ops)) {
+ fprintf(stderr, "PROPPATCH failed: %s\n", ne_get_error(session));
+ r = -ENOTSUP;
+ goto finish;
+ }
+
+ stat_cache_invalidate(path);
+
+finish:
+
+ return r;
+}
static struct fuse_operations dav_oper = {
- .getattr = dav_getattr,
- .getdir = dav_getdir,
- .mknod = dav_mknod,
- .mkdir = dav_mkdir,
- .unlink = dav_unlink,
- .rmdir = dav_rmdir,
- .rename = dav_rename,
-/* .chmod = dav_chmod,*/
- .truncate = dav_truncate,
-/* .utime = dav_utime,*/
- .open = dav_open,
- .read = dav_read,
- .write = dav_write,
- .release = dav_release,
- .fsync = dav_fsync
+ .getattr = dav_getattr,
+ .readdir = dav_readdir,
+ .mknod = dav_mknod,
+ .mkdir = dav_mkdir,
+ .unlink = dav_unlink,
+ .rmdir = dav_rmdir,
+ .rename = dav_rename,
+ .chmod = dav_chmod,
+ .truncate = dav_truncate,
+ .utime = dav_utime,
+ .open = dav_open,
+ .read = dav_read,
+ .write = dav_write,
+ .release = dav_release,
+ .fsync = dav_fsync,
+ .setxattr = dav_setxattr,
+ .getxattr = dav_getxattr,
+ .listxattr = dav_listxattr,
+ .removexattr = dav_removexattr,
};
static void usage(char *argv0) {
e = argv0;
fprintf(stderr,
- "%s [-h] [-D] [-u USERNAME] [-p PASSWORD] URL MOUNTPOINT\n"
+ "%s [-h] [-D] [-u USERNAME] [-p PASSWORD] [-o OPTIONS] URL MOUNTPOINT\n"
"\t-h Show this help\n"
"\t-D Enable debug mode\n"
"\t-u Username if required\n"
- "\t-p Password if required\n",
+ "\t-p Password if required\n"
+ "\t-o Additional FUSE mount options\n",
e);
}
static void exit_handler(int s) {
static const char m[] = "*** Caught signal ***\n";
- write(2, m, strlen(m));
if(fuse != NULL)
fuse_exit(fuse);
+ write(2, m, strlen(m));
}
static int setup_signal_handlers(void) {
return 0;
}
+static int create_lock(void) {
+ ne_session *session;
+ char token[64], _owner[64], *owner;
+ char hn[32];
+ int i;
+ int ret;
+
+ lock = ne_lock_create();
+ assert(lock);
+
+ if (!(session = session_get(0)))
+ return -1;
+
+ if (!(owner = getenv("USER")))
+ if (!(owner = getenv("LOGNAME"))) {
+ snprintf(_owner, sizeof(_owner), "%lu", (unsigned long) getuid());
+ owner = owner;
+ }
+
+ gethostname(hn, sizeof(hn)-1);
+ hn[sizeof(hn)-1] = 0;
+
+ snprintf(token, sizeof(token), "%s.%lu.%lu", hn, (unsigned long) getpid(), (unsigned long) time(NULL));
+
+ ne_fill_server_uri(session, &lock->uri);
+
+ lock->uri.path = strdup(base_directory);
+ lock->depth = NE_DEPTH_INFINITE;
+ lock->timeout = LOCK_TIMEOUT+2;
+ lock->owner = strdup(owner);
+/* lock->token = strdup(token); */
+
+ for (i = 0; i < MAX_REDIRECTS; i++) {
+ const ne_uri *u;
+
+ if ((ret = ne_lock(session, lock)) != NE_REDIRECT)
+ break;
+
+ if (!(u = ne_redirect_location(session)))
+ break;
+
+ if (!session_is_local(u))
+ break;
+
+ if (debug)
+ fprintf(stderr, "REDIRECT FROM '%s' to '%s'\n", lock->uri.path, u->path);
+
+ free(lock->uri.path);
+ lock->uri.path = strdup(u->path);
+ }
+
+ if (ret) {
+ fprintf(stderr, "LOCK failed: %s\n", ne_get_error(session));
+ ne_lock_destroy(lock);
+ lock = NULL;
+ return -1;
+ }
+
+ lock_store = ne_lockstore_create();
+ assert(lock_store);
+
+ ne_lockstore_add(lock_store, lock);
+
+ return 0;
+}
+
+static void *lock_thread_func(__unused void *p) {
+ ne_session *session;
+
+ if (debug)
+ fprintf(stderr, "lock_thread entering\n");
+
+ if (!(session = session_get(1)))
+ return NULL;
+
+ assert(lock);
+
+ while (!lock_thread_exit) {
+ lock->timeout = LOCK_TIMEOUT;
+
+
+
+ if (ne_lock_refresh(session, lock)) {
+ fprintf(stderr, "LOCK refresh failed: %s\n", ne_get_error(session));
+ break;
+ }
+
+ if (lock_thread_exit)
+ break;
+
+ sleep(LOCK_TIMEOUT);
+ }
+
+ if (debug)
+ fprintf(stderr, "lock_thread exiting\n");
+
+ return NULL;
+}
+
int main(int argc, char *argv[]) {
int c;
- char *u=NULL, *p = NULL;
+ char *u = NULL, *p = NULL, *o = NULL;
int fuse_fd = -1;
int ret = 1;
char mountpoint[PATH_MAX];
- static const char *mount_args[] = { "-n", NULL, "-l", "-c", NULL };
-
+ pthread_t lock_thread;
+ int lock_thread_running = 0;
+ int enable_locking = 0;
+
+ static char *mount_args_strings[] = {
+ NULL, /* path*/
+ NULL, /* -o */
+ NULL,
+ NULL};
+
+ struct fuse_args mount_args = {
+ .argc = 1,
+ .argv = mount_args_strings,
+ .allocated = 0
+ };
+
if (ne_sock_init()) {
fprintf(stderr, "Failed to initialize libneon.\n");
goto finish;
if (setup_signal_handlers() < 0)
goto finish;
- while ((c = getopt(argc, argv, "hu:p:D")) != -1) {
+ while ((c = getopt(argc, argv, "hu:p:Do:L")) != -1) {
switch(c) {
case 'u':
case 'D':
debug = !debug;
break;
-
+
+ case 'o':
+ o = optarg;
+ break;
+
+ case 'L':
+ enable_locking = 1;
+ break;
+
case 'h':
default:
usage(argv[0]);
free(pwd);
}
- mount_args[1] = argv[optind];
+ mount_args_strings[0] = argv[optind];
+
+ if (o) {
+ mount_args_strings[1] = "-o";
+ mount_args_strings[2] = o;
+ mount_args.argc += 2;
+ }
- if ((fuse_fd = fuse_mount(mountpoint, mount_args)) < 0) {
+ if ((fuse_fd = fuse_mount(mountpoint, &mount_args)) < 0) {
fprintf(stderr, "Failed to mount FUSE file system.\n");
goto finish;
}
- if (!(fuse = fuse_new(fuse_fd, 0, &dav_oper))) {
+ if (!(fuse = fuse_new(fuse_fd, &mount_args, &dav_oper, sizeof(dav_oper)))) {
fprintf(stderr, "Failed to create FUSE object.\n");
goto finish;
}
- fuse_loop_mt(fuse);
+ if (enable_locking && create_lock() >= 0) {
+ if (pthread_create(&lock_thread, NULL, lock_thread_func, NULL) < 0) {
+ fprintf(stderr, "pthread_create(): %s\n", strerror(errno));
+ goto finish;
+ }
+
+ lock_thread_running = 1;
+ }
+
+ fuse_loop(fuse);
+
+ if (debug)
+ fprintf(stderr, "Exiting cleanly.\n");
ret = 0;
finish:
+
+ if (lock_thread_running) {
+ lock_thread_exit = 1;
+ pthread_kill(lock_thread, SIGPIPE);
+ pthread_join(lock_thread, NULL);
+ ne_lockstore_destroy(lock_store);
+ }
if (fuse)
fuse_destroy(fuse);
diff --git a/src/fusedav.h b/src/fusedav.h
index 35598ae6e264fb88b0d2ef3cb0823ecfa3745f83..e164abb2123b8a7d2d492a4accbac6783d00d0ab 100644 (file)
--- a/src/fusedav.h
+++ b/src/fusedav.h
extern int debug;
+#ifdef __GNUC__
+#define __unused __attribute__ ((unused))
+#else
+#define __unused
+#endif
+
#endif
diff --git a/src/openssl-thread.c b/src/openssl-thread.c
index c28ebfecb2f20fc8b6203ea3c7ca70950c0fef57..e7affe870a1e1f1b6585cc30d3db3c5c833303e5 100644 (file)
--- a/src/openssl-thread.c
+++ b/src/openssl-thread.c
#include <pthread.h>
#include <openssl/crypto.h>
+#include "fusedav.h"
+#include "openssl-thread.h"
+
static pthread_mutex_t *mutexes;
-static void pthreads_locking_callback(int mode, int n, const char *file, int line) {
+static void pthreads_locking_callback(int mode, int n, __unused const char *file, __unused int line) {
if (mode & CRYPTO_LOCK)
pthread_mutex_lock(mutexes+n);
else
diff --git a/src/session.c b/src/session.c
index 75c37c86e654c449b3db5e146c82e74ea5a2e46d..60b1fd4e4431ef41f1615a15c1b01468475f3923 100644 (file)
--- a/src/session.c
+++ b/src/session.c
#include <ne_socket.h>
#include <ne_auth.h>
#include <ne_dates.h>
+#include <ne_redirect.h>
#include "session.h"
-
+#include "fusedav.h"
static pthread_once_t session_once = PTHREAD_ONCE_INIT;
static pthread_key_t session_tsd_key;
-static ne_uri uri;
+ne_uri uri;
static int b_uri = 0;
-static const char *username = NULL, *password = NULL;
-const char *base_directory = NULL;
+static char *username = NULL, *password = NULL;
+char *base_directory = NULL;
static pthread_mutex_t credential_mutex = PTHREAD_MUTEX_INITIALIZER;
-
-static char* ask_user(char *p, int hidden) {
+static char* ask_user(const char *p, int hidden) {
char q[256], *r;
struct termios t;
int c = 0, l;
return r ? strdup(r) : NULL;
}
-static int ssl_verify_cb(void *userdata, int failures, const ne_ssl_certificate *cert) {
+static int ssl_verify_cb(__unused void *userdata, __unused int failures, __unused const ne_ssl_certificate *cert) {
return 0;
}
-static int ne_auth_creds_cb(void *userdata, const char *realm, int attempt, char *u, char *p) {
+static int ne_auth_creds_cb(__unused void *userdata, const char *realm, int attempt, char *u, char *p) {
int r = -1;
-
pthread_mutex_lock(&credential_mutex);
if (attempt) {
- fprintf(stderr, "Authenication failure!\n");
+ fprintf(stderr, "Authentication failure!\n");
free((void*) username);
free((void*) password);
username = password = NULL;
}
+
+ fprintf(stderr, "Realm '%s' requires authentication.\n", realm);
if (!username)
username = ask_user("Username", 0);
@@ -122,10 +123,12 @@ static int ne_auth_creds_cb(void *userdata, const char *realm, int attempt, char
return r;
}
-static ne_session *session_open(void) {
- char *scheme = NULL;
+static ne_session *session_open(int with_lock) {
+ const char *scheme = NULL;
ne_session *session;
+ extern ne_lock_store *lock_store;
+
if (!b_uri)
return NULL;
ne_ssl_set_verify(session, ssl_verify_cb, NULL);
ne_set_server_auth(session, ne_auth_creds_cb, NULL);
+ ne_redirect_register(session);
+
+ if (with_lock && lock_store)
+ ne_lockstore_register(lock_store, session);
+
return session;
}
pthread_key_create(&session_tsd_key, session_destroy);
}
-ne_session *session_get(void) {
+ne_session *session_get(int with_lock) {
ne_session *session;
pthread_once(&session_once, session_tsd_key_init);
if ((session = pthread_getspecific(session_tsd_key)))
return session;
- session = session_open();
+ session = session_open(with_lock);
pthread_setspecific(session_tsd_key, session);
return session;
}
int session_set_uri(const char *s, const char *u, const char *p) {
- assert(!b_uri && !username && !password);
int l;
+ assert(!b_uri);
+ assert(!username);
+ assert(!password);
+
if (ne_uri_parse(s, &uri)) {
fprintf(stderr, "Invalid URI <%s>\n", s);
goto finish;
username = password = base_directory = NULL;
}
+int session_is_local(const ne_uri *u) {
+ assert(u);
+ assert(b_uri);
+
+ return
+ strcmp(u->scheme, uri.scheme) == 0 &&
+ strcmp(u->host, uri.host) == 0 &&
+ u->port == uri.port;
+}
+
diff --git a/src/session.h b/src/session.h
index 7a4678207a96e0574377b31f0222b3c43450689c..2f6a1ad70e03d5f0e5f346e53076329e39c87420 100644 (file)
--- a/src/session.h
+++ b/src/session.h
***/
#include <ne_session.h>
+#include <ne_locks.h>
-ne_session *session_get(void);
+ne_session *session_get(int with_lock);
int session_set_uri(const char *s, const char*u, const char*p);
void session_free(void);
-extern const char *base_directory;
+int session_is_local(const ne_uri *u);
+
+extern char *base_directory;
+extern ne_uri uri;
#endif
diff --git a/src/statcache.c b/src/statcache.c
index f71c1a6b4088ff07e559c07d5d5247789cdec26a..22737f7fc9de97103fd1a9c1f1975b61e5026465 100644 (file)
--- a/src/statcache.c
+++ b/src/statcache.c
#include <assert.h>
#include "statcache.h"
+#include "filecache.h"
#include "fusedav.h"
#include <ne_uri.h>
uint32_t h = 0;
for (; *s; s++) {
- h ^= * (uint8_t*) s;
+ h ^= * (const uint8_t*) s;
h = (h << 8) | (h >> 24);
}
uint32_t h;
struct cache_entry *ce;
int r = -1;
+ void *f;
if (debug)
fprintf(stderr, "CGET: %s\n", fn);
time(NULL) <= ce->stat_info.dead) {
*st = ce->stat_info.st;
+
+ if ((f = file_cache_get(fn))) {
+ st->st_size = file_cache_get_size(f);
+ file_cache_unref(f);
+ }
+
r = 0;
}
@@ -275,8 +283,9 @@ int dir_cache_enumerate(const char *fn, void (*f) (const char*fn, const char *su
uint32_t h;
struct cache_entry *ce;
struct dir_entry *de = NULL;
- assert(cache && f);
int r = -1;
+
+ assert(cache && f);
h = calc_hash(fn);
ce = cache + (h % CACHE_SIZE);
return;
cache = malloc(sizeof(struct cache_entry)*CACHE_SIZE);
+ assert(cache);
memset(cache, 0, sizeof(struct cache_entry)*CACHE_SIZE);
}