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
--------------------

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)
* cache.c, mount_davfs.c:
Add missing includes.

View File

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

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

/* Root node of the directory cache. */
static dav_node *root;
@ -316,6 +316,15 @@ update_node(dav_node *node, dav_props *props);
static void
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. */

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

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

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

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);
if (ret == EAGAIN) {
root->utime = 0;
@ -621,6 +646,8 @@ dav_init_cache(const dav_args *args, const char *mpoint)
} else if (ret) {
error(EXIT_FAILURE, 0, _("Mounting failed.\n%s"),
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)
flush = flush_flag;

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

return alignment;
}
@ -699,7 +720,7 @@ dav_tidy_cache(void)
{
if (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.",
(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;
}

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

if (delay_upload == 0 && (is_dirty(node) || is_created(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)
return EIO;
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;
@ -1202,6 +1225,7 @@ dav_remove(dav_node *parent, const char *name, uid_t uid)
if (ret)
return ret;

update_stat(node->size, 1);
remove_from_tree(node);
remove_from_changed(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_stat st;
st.blocks = 0x65B9AA;
st.bfree = 0x32DCD5;
st.bavail = 0x32DCD5;
st.files = nnodes;
st.ffree = 666666;
struct stat cache_st;
if (stat(cache_dir, &cache_st) == 0) {
st.bsize = cache_st.st_blksize;
} else {
st.bsize = 4096;
if (time(NULL) > (fs_stat->utime + dir_refresh)) {
off64_t total = 0;
off64_t used = 0;
if (dav_quota(root->path, &total, &used) == 0) {
fs_stat->blocks = total / fs_stat->bsize;
fs_stat->bfree = fs_stat->blocks - (used / fs_stat->bsize) - 1;
fs_stat->bavail = fs_stat->bfree;
fs_stat->ffree = fs_stat->bfree;
fs_stat->utime = time(NULL);
}
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))
return ENOENT;
if (is_dir(node))
return EBADF;

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


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

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

char *buf = ne_malloc(DAV_XML_BUF_SIZE);
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(). */
typedef struct dav_stat dav_stat;
struct dav_stat {
off_t blocks;
off_t bfree;
off_t bavail;
off_t files;
off_t ffree;
off64_t blocks;
off64_t bfree;
off64_t bavail;
off64_t files;
off64_t ffree;
off_t bsize;
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,
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. */
dav_stat dav_statfs(void);
dav_stat *
dav_statfs(void);


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

View File

@ -684,13 +684,17 @@ coda_statfs(void)
if (debug)
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_bfree = st.bfree;
out->stat.f_bavail = st.bavail;
out->stat.f_files = st.files;
out->stat.f_ffree = st.ffree;
out->stat.f_blocks = st->blocks;
out->stat.f_bfree = st->bfree;
out->stat.f_bavail = st->bavail;
out->stat.f_files = st->files;
out->stat.f_ffree = st->ffree;

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

View File

@ -972,16 +972,20 @@ fuse_stat(void)
if (debug)
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.bfree = st.bfree;
out->st.bavail = st.bavail;
out->st.files = st.files;
out->st.ffree = st.ffree;
out->st.blocks = st->blocks;
out->st.bfree = st->bfree;
out->st.bavail = st->bavail;
out->st.files = st->files;
out->st.ffree = st->ffree;
out->st.bsize = (buf_size - sizeof(struct fuse_in_header)
- sizeof(struct fuse_write_in) - 4095) & ~4095;
out->st.namelen = st.namelen;
out->st.namelen = st->namelen;
out->st.frsize = 0;
out->st.padding = 0;
int i;

View File

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


View File

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

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


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

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

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

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

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

#endif /* NE_VERSION_MINOR >= 26 */

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

static int
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) {
char *custom_header = ne_strdup(args->header);
custom_header = ne_strdup(args->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_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 = get_error(ret, "GET");
@ -1063,7 +1070,7 @@ dav_put(const char *path, const char *cache_path, int *exists, time_t *expire,


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;
if (!initialized) {
@ -1071,26 +1078,52 @@ dav_quota(const char *path, off_t *available, off_t *used)
if (ret) return ret;
}

quota_context ctx;
ctx.available = (off_t) -1;
ctx.used = (off_t) -1;
static int use_rfc = 1;
static int use_userinfo = 1;

quota_context ctx;
ctx.error = 0;
ctx.total = 0;
ctx.used = 0;
ret = EIO;
char *spath = ne_path_escape(path);
ne_propfind_handler *ph = ne_propfind_create(session, spath, NE_DEPTH_ZERO);

if (use_rfc) {
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 && ctx.error) {
ret = EIO;
if (ctx.error == 2)
use_rfc = 0;
}
}

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.available == (off_t) -1 || ctx.used == (off_t) -1) {
if (ctx.error)
ret = EIO;
} else {
*available = ctx.available;
*used = ctx.used;
} else if (ret == EINVAL) {
use_userinfo = 0;
}
}

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

free(spath);
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
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
@ -1530,7 +1563,7 @@ auth(void *userdata, const char *realm, int attempt, char *user, char *pwd)
length : Number of bytes in the buffer.
return value : 0 on success, EIO otherwise. */
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;
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
userdata. */
#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 */

const char *data = ne_propset_value(set, &quota_names[AVAILABLE]);
if (data)
ctx->available = strtol(data, NULL, 10);
if (data) {
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]);
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);

/* 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. */
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.