support USERINF, div bug fixes

This commit is contained in:
wbaumann 2009-06-04 18:57:48 +00:00
parent 15455d6130
commit 317e8a19df
8 changed files with 226 additions and 88 deletions

View File

@ -1,6 +1,36 @@
ChangeLog for davfs2 ChangeLog for davfs2
-------------------- --------------------


2009-05-31 Werner Baumann (werner.baumann@onlinehome.de)
* cache.c, cache.h, dav_coda.c, dav_fuse.c:
Cache quota in global variable fs_stat.
Update with dir_refresh and when closing or
deleting files.
Function dav_stafs now returns a pointer.

2009-05-30 Werner Baumann (werner.baumann@onlinehome.de)
* webdav.c, webdav.h, dav_quota:
Return total webspace instead of available.
Rember support for quota in static flag use_rfc.
Add support for method USERINFO.
* webdav.c:
Rename block_writer into file_reader for consistency
with neon naming conventions.
* cache.c, dav_open, dav_write:
Open directories O_RDWR again, but prevent writing
by applications.

2009-05-29 Werner Baumann (werner.baumann@onlinehome.de)
* mount_davfs.c, check_double_mounts:
Free temporary string mp.
* cache.c, parse_index:
Free index.
* webdav.c, dav_init_webdav:
Make custom_header a global variable to not disturb
code test tools.
* webdav.c, dav_quota:
Initialize ctx to 0; add ctx.error, use strtoull.

2009-05-25 Werner Baumann (werner.baumann@onlinehome.de) 2009-05-25 Werner Baumann (werner.baumann@onlinehome.de)
* cache.c, mount_davfs.c: * cache.c, mount_davfs.c:
Add missing includes. Add missing includes.

View File

@ -128,8 +128,8 @@ static const char* const type[] = {
/* Private global variables */ /* Private global variables */
/*==========================*/ /*==========================*/


/* Number of nodes. */ /* File system statistics. */
static int nnodes; static dav_stat *fs_stat;


/* Root node of the directory cache. */ /* Root node of the directory cache. */
static dav_node *root; static dav_node *root;
@ -316,6 +316,15 @@ update_node(dav_node *node, dav_props *props);
static void static void
update_path(dav_node *node, const char *src_path, const char *dst_path); update_path(dav_node *node, const char *src_path, const char *dst_path);


static inline void
update_stat(off_t size, int sign)
{
if (!fs_stat->utime) return;
fs_stat->bfree += sign * (size / fs_stat->bsize);
fs_stat->bavail = fs_stat->bfree;
fs_stat->ffree = fs_stat->bfree;
}

/* Get information about node. */ /* Get information about node. */


static int static int
@ -580,6 +589,9 @@ dav_init_cache(const dav_args *args, const char *mpoint)
max_retry = args->max_retry; max_retry = args->max_retry;
lock_refresh = args->lock_refresh; lock_refresh = args->lock_refresh;


fs_stat = (dav_stat *) malloc(sizeof(dav_stat));
if (!fs_stat) abort();

if (debug) if (debug)
syslog(LOG_MAKEPRI(LOG_DAEMON, LOG_DEBUG), "Checking cache directory"); syslog(LOG_MAKEPRI(LOG_DAEMON, LOG_DEBUG), "Checking cache directory");
max_cache_size = args->cache_size * 0x100000; max_cache_size = args->cache_size * 0x100000;
@ -602,6 +614,19 @@ dav_init_cache(const dav_args *args, const char *mpoint)


clean_cache(); clean_cache();


fs_stat->blocks = 0x65B9AA;
fs_stat->bfree = 0x32DCD5;
fs_stat->bavail = 0x32DCD5;
fs_stat->ffree = 666666;
struct stat cache_st;
if (stat(cache_dir, &cache_st) == 0) {
fs_stat->bsize = cache_st.st_blksize;
} else {
fs_stat->bsize = 4096;
}
fs_stat->namelen = 256;
fs_stat->utime = 0;

int ret = update_directory(root, 0); int ret = update_directory(root, 0);
if (ret == EAGAIN) { if (ret == EAGAIN) {
root->utime = 0; root->utime = 0;
@ -621,6 +646,8 @@ dav_init_cache(const dav_args *args, const char *mpoint)
} else if (ret) { } else if (ret) {
error(EXIT_FAILURE, 0, _("Mounting failed.\n%s"), error(EXIT_FAILURE, 0, _("Mounting failed.\n%s"),
dav_get_webdav_error()); dav_get_webdav_error());
} else {
dav_statfs();
} }
} }


@ -681,14 +708,8 @@ dav_register_kernel_interface(dav_write_dir_entry_fn write_fn, int *flush_flag,
if (flush_flag) if (flush_flag)
flush = flush_flag; flush = flush_flag;


if (blksize) { if (blksize)
struct stat st; *blksize = fs_stat->bsize;
if (stat(cache_dir, &st) == 0) {
*blksize = st.st_blksize;
} else {
*blksize = 4096;
}
}


return alignment; return alignment;
} }
@ -699,7 +720,7 @@ dav_tidy_cache(void)
{ {
if (debug) { if (debug) {
syslog(LOG_MAKEPRI(LOG_DAEMON, LOG_DEBUG), syslog(LOG_MAKEPRI(LOG_DAEMON, LOG_DEBUG),
"tidy: %i of %i nodes changed", nchanged, nnodes); "tidy: %i of %llu nodes changed", nchanged, fs_stat->files);
syslog(LOG_MAKEPRI(LOG_DAEMON, LOG_DEBUG), "cache-size: %llu MiBytes.", syslog(LOG_MAKEPRI(LOG_DAEMON, LOG_DEBUG), "cache-size: %llu MiBytes.",
(cache_size + 0x80000) / 0x100000); (cache_size + 0x80000) / 0x100000);
} }
@ -812,8 +833,10 @@ dav_close(dav_node *node, int fd, int flags, pid_t pid, pid_t pgid)
return 0; return 0;
} }


update_stat(node->size, 1);
attr_from_cache_file(node); attr_from_cache_file(node);
set_upload_time(node); set_upload_time(node);
update_stat(node->size, -1);


if (delay_upload == 0 && (is_dirty(node) || is_created(node)) if (delay_upload == 0 && (is_dirty(node) || is_created(node))
&& !is_open_write(node) && !is_backup(node)) { && !is_open_write(node) && !is_backup(node)) {
@ -1095,7 +1118,7 @@ dav_open(int *fd, dav_node *node, int flags, pid_t pid, pid_t pgid, uid_t uid,
if (create_dir_cache_file(node) != 0) if (create_dir_cache_file(node) != 0)
return EIO; return EIO;
node->atime = time(NULL); node->atime = time(NULL);
return open_file(fd, node, O_RDONLY, pid, pgid, uid); return open_file(fd, node, O_RDWR, pid, pgid, uid);
} }


int ret = 0; int ret = 0;
@ -1202,6 +1225,7 @@ dav_remove(dav_node *parent, const char *name, uid_t uid)
if (ret) if (ret)
return ret; return ret;


update_stat(node->size, 1);
remove_from_tree(node); remove_from_tree(node);
remove_from_changed(node); remove_from_changed(node);
if (is_open(node)) { if (is_open(node)) {
@ -1486,32 +1510,22 @@ dav_setattr(dav_node *node, uid_t uid, int sm, mode_t mode, int so,
} }




dav_stat dav_stat *
dav_statfs(void) dav_statfs(void)
{ {
dav_stat st; if (time(NULL) > (fs_stat->utime + dir_refresh)) {
st.blocks = 0x65B9AA; off64_t total = 0;
st.bfree = 0x32DCD5; off64_t used = 0;
st.bavail = 0x32DCD5; if (dav_quota(root->path, &total, &used) == 0) {
st.files = nnodes; fs_stat->blocks = total / fs_stat->bsize;
st.ffree = 666666; fs_stat->bfree = fs_stat->blocks - (used / fs_stat->bsize) - 1;
struct stat cache_st; fs_stat->bavail = fs_stat->bfree;
if (stat(cache_dir, &cache_st) == 0) { fs_stat->ffree = fs_stat->bfree;
st.bsize = cache_st.st_blksize; fs_stat->utime = time(NULL);
} else { }
st.bsize = 4096;
}
st.namelen = 256;

off_t used = 0;
if (dav_quota(root->path, &st.blocks, &used) == 0) {
st.blocks /= st.bsize;
st.bfree = st.blocks - (used / st.bsize) - 1;
st.bavail = st.bfree;
st.ffree = st.bfree;
} }


return st; return fs_stat;
} }




@ -1538,6 +1552,8 @@ dav_write(size_t *written, dav_node * node, int fd, char *buf, size_t size,
{ {
if (!exists(node)) if (!exists(node))
return ENOENT; return ENOENT;
if (is_dir(node))
return EBADF;


dav_handle *fh = get_file_handle(node, fd, 0, 0, 0); dav_handle *fh = get_file_handle(node, fd, 0, 0, 0);
if (!fh) if (!fh)
@ -1770,7 +1786,7 @@ delete_node(dav_node *node)
free(tofree); free(tofree);
} }
free(node); free(node);
nnodes--; fs_stat->files--;
} }




@ -2016,7 +2032,7 @@ new_node(dav_node *parent, mode_t mode)
if (debug) if (debug)
syslog(LOG_MAKEPRI(LOG_DAEMON, LOG_DEBUG), "new node: %p->%p", syslog(LOG_MAKEPRI(LOG_DAEMON, LOG_DEBUG), "new node: %p->%p",
node->parent, node); node->parent, node);
nnodes++; fs_stat->files++;
return node; return node;
} }


@ -2824,8 +2840,10 @@ parse_index(void)
{ {
char *index = ne_concat(cache_dir, "/", DAV_INDEX, NULL); char *index = ne_concat(cache_dir, "/", DAV_INDEX, NULL);
FILE *idx = fopen(index, "r"); FILE *idx = fopen(index, "r");
if (!idx) if (!idx) {
free(index);
return; return;
}


char *buf = ne_malloc(DAV_XML_BUF_SIZE); char *buf = ne_malloc(DAV_XML_BUF_SIZE);
size_t len = fread(buf, 1, DAV_XML_BUF_SIZE, idx); size_t len = fread(buf, 1, DAV_XML_BUF_SIZE, idx);

View File

@ -147,13 +147,17 @@ struct dav_node_item {
/* Returned by dav_statfs(). */ /* Returned by dav_statfs(). */
typedef struct dav_stat dav_stat; typedef struct dav_stat dav_stat;
struct dav_stat { struct dav_stat {
off_t blocks; off64_t blocks;
off_t bfree; off64_t bfree;
off_t bavail; off64_t bavail;
off_t files; off64_t files;
off_t ffree; off64_t ffree;
off_t bsize; off_t bsize;
off_t namelen; off_t namelen;
time_t utime; /* Time when last updated with data from the server.
must When 0 this structure contains fake data,
that not be changed when a file is changed or
deleted. */
}; };




@ -409,9 +413,12 @@ dav_setattr(dav_node *node, uid_t uid, int sm, mode_t mode, int so,
uid_t owner, int sg, gid_t gid, int sat, time_t atime, int smt, uid_t owner, int sg, gid_t gid, int sat, time_t atime, int smt,
time_t mtime, int ssz, off_t size); time_t mtime, int ssz, off_t size);


/* Returns struct dav_stat which currently is mainly fake.
/* Returns struct dav_stat. If the server does not provide theinformation
it will contain fake data.
No permissions necessary. */ No permissions necessary. */
dav_stat dav_statfs(void); dav_stat *
dav_statfs(void);




/* Calls fsync() for all filedescriptors of node, that are not read only. /* Calls fsync() for all filedescriptors of node, that are not read only.
@ -424,7 +431,6 @@ dav_sync(dav_node *node);
offset. offset.
The number of bytes written is returned in len. The number of bytes written is returned in len.
The file must be opened writeonly or readwrite. */ The file must be opened writeonly or readwrite. */
/* TODO: Remove pid; check flags. */
int int
dav_write(size_t *written, dav_node * node, int fd, char *buf, size_t size, dav_write(size_t *written, dav_node * node, int fd, char *buf, size_t size,
off_t offset); off_t offset);

View File

@ -684,13 +684,17 @@ coda_statfs(void)
if (debug) if (debug)
syslog(LOG_MAKEPRI(LOG_DAEMON, LOG_DEBUG), "CODA_STATFS:"); syslog(LOG_MAKEPRI(LOG_DAEMON, LOG_DEBUG), "CODA_STATFS:");


dav_stat st = dav_statfs(); dav_stat *st = dav_statfs();
if (!st) {
oh->result = EIO;
return sizeof(struct coda_out_hdr);
}


out->stat.f_blocks = st.blocks; out->stat.f_blocks = st->blocks;
out->stat.f_bfree = st.bfree; out->stat.f_bfree = st->bfree;
out->stat.f_bavail = st.bavail; out->stat.f_bavail = st->bavail;
out->stat.f_files = st.files; out->stat.f_files = st->files;
out->stat.f_ffree = st.ffree; out->stat.f_ffree = st->ffree;


oh->result = 0; oh->result = 0;
return sizeof(struct coda_statfs_out); return sizeof(struct coda_statfs_out);

View File

@ -972,16 +972,20 @@ fuse_stat(void)
if (debug) if (debug)
syslog(LOG_MAKEPRI(LOG_DAEMON, LOG_DEBUG), "FUSE_STATFS:"); syslog(LOG_MAKEPRI(LOG_DAEMON, LOG_DEBUG), "FUSE_STATFS:");


dav_stat st = dav_statfs(); dav_stat *st = dav_statfs();
if (!st) {
oh->error = -EIO;
return sizeof(struct fuse_out_header);
}


out->st.blocks = st.blocks; out->st.blocks = st->blocks;
out->st.bfree = st.bfree; out->st.bfree = st->bfree;
out->st.bavail = st.bavail; out->st.bavail = st->bavail;
out->st.files = st.files; out->st.files = st->files;
out->st.ffree = st.ffree; out->st.ffree = st->ffree;
out->st.bsize = (buf_size - sizeof(struct fuse_in_header) out->st.bsize = (buf_size - sizeof(struct fuse_in_header)
- sizeof(struct fuse_write_in) - 4095) & ~4095; - sizeof(struct fuse_write_in) - 4095) & ~4095;
out->st.namelen = st.namelen; out->st.namelen = st->namelen;
out->st.frsize = 0; out->st.frsize = 0;
out->st.padding = 0; out->st.padding = 0;
int i; int i;

View File

@ -654,8 +654,8 @@ check_double_mounts(dav_args *args)
m = strchr(mp, '/'); m = strchr(mp, '/');
} }
char *pidf = NULL; char *pidf = NULL;
if (asprintf(&pidf, "%s/%s.pid", DAV_SYS_RUN, mp) < 0) if (asprintf(&pidf, "%s/%s.pid", DAV_SYS_RUN, mp) < 0) abort();
abort(); free(mp);
if (args->debug & DAV_DBG_CONFIG) if (args->debug & DAV_DBG_CONFIG)
syslog(LOG_MAKEPRI(LOG_DAEMON, LOG_DEBUG), "PID file: %s", pidf); syslog(LOG_MAKEPRI(LOG_DAEMON, LOG_DEBUG), "PID file: %s", pidf);



View File

@ -90,8 +90,9 @@ typedef struct {
} get_context; } get_context;


typedef struct { typedef struct {
off_t available; /* Available bytes. */ int error;
off_t used; /* Used bytes. */ off64_t total; /* Total amount of available bytes. */
off64_t used; /* Used bytes. */
} quota_context; } quota_context;




@ -203,6 +204,9 @@ static iconv_t to_server_enc;
/* A GNU custom stream, used to redirect neon debug messages to syslog. */ /* A GNU custom stream, used to redirect neon debug messages to syslog. */
static FILE *log_stream; static FILE *log_stream;


/* A user defined header that is added to all requests. */
char *custom_header;

#if NE_VERSION_MINOR > 25 #if NE_VERSION_MINOR > 25
/* Session cookie. */ /* Session cookie. */
static char *cookie; static char *cookie;
@ -248,7 +252,7 @@ static int
auth(void *userdata, const char *realm, int attempt, char *user, char *pwd); auth(void *userdata, const char *realm, int attempt, char *user, char *pwd);


static int static int
block_writer(void *userdata, const char *block, size_t length); file_reader(void *userdata, const char *block, size_t length);


#if NE_VERSION_MINOR < 26 #if NE_VERSION_MINOR < 26


@ -276,6 +280,9 @@ quota_result(void *userdata, const ne_uri *uri, const ne_prop_result_set *set);


#endif /* NE_VERSION_MINOR >= 26 */ #endif /* NE_VERSION_MINOR >= 26 */


static int
quota_reader(void *userdata, const char *block, size_t length);

static int static int
ssl_verify(void *userdata, int failures, const ne_ssl_certificate *cert); ssl_verify(void *userdata, int failures, const ne_ssl_certificate *cert);


@ -429,7 +436,7 @@ dav_init_webdav(const dav_args *args)
} }


if (args->header) { if (args->header) {
char *custom_header = ne_strdup(args->header); custom_header = ne_strdup(args->header);
ne_hook_pre_send(session, add_header, custom_header); ne_hook_pre_send(session, add_header, custom_header);
} }


@ -674,7 +681,7 @@ dav_get_file(const char *path, const char *cache_path, off_t *size,
ne_add_request_header(req, "If-Modified-Since", mod_time); ne_add_request_header(req, "If-Modified-Since", mod_time);
} }


ne_add_response_body_reader(req, ne_accept_2xx, block_writer, &ctx); ne_add_response_body_reader(req, ne_accept_2xx, file_reader, &ctx);


ret = ne_request_dispatch(req); ret = ne_request_dispatch(req);
ret = get_error(ret, "GET"); ret = get_error(ret, "GET");
@ -1063,7 +1070,7 @@ dav_put(const char *path, const char *cache_path, int *exists, time_t *expire,




int int
dav_quota(const char *path, off_t *available, off_t *used) dav_quota(const char *path, off64_t *total, off64_t *used)
{ {
int ret; int ret;
if (!initialized) { if (!initialized) {
@ -1071,26 +1078,52 @@ dav_quota(const char *path, off_t *available, off_t *used)
if (ret) return ret; if (ret) return ret;
} }


static int use_rfc = 1;
static int use_userinfo = 1;

quota_context ctx; quota_context ctx;
ctx.available = (off_t) -1; ctx.error = 0;
ctx.used = (off_t) -1; ctx.total = 0;

ctx.used = 0;
ret = EIO;
char *spath = ne_path_escape(path); char *spath = ne_path_escape(path);
ne_propfind_handler *ph = ne_propfind_create(session, spath, NE_DEPTH_ZERO);
ret = ne_propfind_named(ph, quota_names, quota_result, &ctx);
ret = get_error(ret, "PROPFIND");
ne_propfind_destroy(ph);
free(spath);


if (!ret) { if (use_rfc) {
if (ctx.available == (off_t) -1 || ctx.used == (off_t) -1) { ne_propfind_handler *ph = ne_propfind_create(session, spath,
NE_DEPTH_ZERO);
ret = ne_propfind_named(ph, quota_names, quota_result, &ctx);
ret = get_error(ret, "PROPFIND");
ne_propfind_destroy(ph);

if (!ret && ctx.error) {
ret = EIO; ret = EIO;
} else { if (ctx.error == 2)
*available = ctx.available; use_rfc = 0;
*used = ctx.used;
} }
} }


if (ret && use_userinfo) {
ctx.error = 0;
ne_request *req = ne_request_create(session, "USERINFO", spath);
ne_add_response_body_reader(req, ne_accept_2xx, quota_reader, &ctx);
ret = ne_request_dispatch(req);
ret = get_error(ret, "USERINFO");
ne_request_destroy(req);

if (!ret) {
if (ctx.error)
ret = EIO;
} else if (ret == EINVAL) {
use_userinfo = 0;
}
}

if (!ret) {
*total = ctx.total;
*used = ctx.used;
}

free(spath);
return ret; return ret;
} }


@ -1519,7 +1552,7 @@ auth(void *userdata, const char *realm, int attempt, char *user, char *pwd)
} }




/* Writes data from block to a local file. /* Reads HTTP-data from blockand writes them to a local file.
userdata must be a get_context structure that holds at least the name of userdata must be a get_context structure that holds at least the name of
the local file. If it does not contain a file descriptor, the file is the local file. If it does not contain a file descriptor, the file is
opened for writing and the file descriptor is stored in the get_context opened for writing and the file descriptor is stored in the get_context
@ -1530,7 +1563,7 @@ auth(void *userdata, const char *realm, int attempt, char *user, char *pwd)
length : Number of bytes in the buffer. length : Number of bytes in the buffer.
return value : 0 on success, EIO otherwise. */ return value : 0 on success, EIO otherwise. */
static int static int
block_writer(void *userdata, const char *block, size_t length) file_reader(void *userdata, const char *block, size_t length)
{ {
get_context *ctx = (get_context *) userdata; get_context *ctx = (get_context *) userdata;
if (!ctx->fd) if (!ctx->fd)
@ -1733,6 +1766,36 @@ prop_result(void *userdata, const ne_uri *uri, const ne_prop_result_set *set)
} }




static int
quota_reader(void *userdata, const char *block, size_t length)
{
if (length < 1) return 0;
quota_context *ctx = (quota_context *) userdata;

char *quota = strndup(block, length);
if (!quota) {
ctx->error = 1;
return 0;
}

char *number = strtok(quota, ",");
if (number) {
ctx->total = strtoull(number, NULL, 10);
} else {
ctx->error = 1;
free(quota);
return 0;
}

number = strtok(NULL, ",");
if (number)
ctx->used = strtoull(number, NULL, 10);

free(quota);
return 0;
}


/* Reads available and used bytes from set and stores them in /* Reads available and used bytes from set and stores them in
userdata. */ userdata. */
#if NE_VERSION_MINOR < 26 #if NE_VERSION_MINOR < 26
@ -1756,12 +1819,23 @@ quota_result(void *userdata, const ne_uri *uri, const ne_prop_result_set *set)
#endif /* NE_VERSION_MINOR >= 26 */ #endif /* NE_VERSION_MINOR >= 26 */


const char *data = ne_propset_value(set, &quota_names[AVAILABLE]); const char *data = ne_propset_value(set, &quota_names[AVAILABLE]);
if (data) if (data) {
ctx->available = strtol(data, NULL, 10); ctx->total = strtoull(data, NULL, 10);
} else {
const ne_status *st = ne_propset_status(set, &quota_names[AVAILABLE]);
if (st && st->klass == 4) {
ctx->error = 2;
} else {
ctx->error = 1;
}
return;
}


data = ne_propset_value(set, &quota_names[USED]); data = ne_propset_value(set, &quota_names[USED]);
if (data) if (data)
ctx->used = strtol(data, NULL, 10); ctx->used = strtoull(data, NULL, 10);

ctx->total += ctx->used;
} }





View File

@ -247,10 +247,12 @@ dav_put(const char *path, const char *cache_path, int *exists, time_t *expire,
char **etag, time_t *mtime, char **mime, int execute); char **etag, time_t *mtime, char **mime, int execute);


/* Makes a PROPFIND request for path to get quota information (RFC 4331) /* Makes a PROPFIND request for path to get quota information (RFC 4331)
and places them in available and used. If quota information is not and places them in total and used.
toatal is the sum of quota-available-bytes and quota-used-bytes.
If quota information is not
available, an error is returned and available and used are not changed. */ available, an error is returned and available and used are not changed. */
int int
dav_quota(const char *path, off_t *available, off_t *used); dav_quota(const char *path, off_t *total, off_t *used);




/* Sets or resets the execute property of file path. /* Sets or resets the execute property of file path.