summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--CMakeLists.txt2
-rw-r--r--modules/dav/fs/config6.m42
-rw-r--r--modules/dav/fs/mod_dav_fs.c121
-rw-r--r--modules/dav/fs/mod_dav_fs.dsp4
-rw-r--r--modules/dav/fs/repos.c85
-rw-r--r--modules/dav/fs/repos.h25
-rw-r--r--modules/dav/main/mod_dav.h4
7 files changed, 234 insertions, 9 deletions
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 95c95eb2c2..3ed34c7e10 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -455,7 +455,7 @@ SET(mod_dav_extra_sources
SET(mod_dav_install_lib 1)
SET(mod_dav_fs_extra_sources
modules/dav/fs/dbm.c modules/dav/fs/lock.c
- modules/dav/fs/repos.c
+ modules/dav/fs/quota.c modules/dav/fs/repos.c
)
SET(mod_dav_fs_extra_libs mod_dav)
SET(mod_dav_lock_extra_sources modules/dav/lock/locks.c)
diff --git a/modules/dav/fs/config6.m4 b/modules/dav/fs/config6.m4
index dd26ec8bab..ee0b382f15 100644
--- a/modules/dav/fs/config6.m4
+++ b/modules/dav/fs/config6.m4
@@ -2,7 +2,7 @@ dnl modules enabled in this directory by default
APACHE_MODPATH_INIT(dav/fs)
-dav_fs_objects="mod_dav_fs.lo dbm.lo lock.lo repos.lo"
+dav_fs_objects="mod_dav_fs.lo dbm.lo lock.lo quota.lo repos.lo"
if test "x$enable_dav" != "x"; then
dav_fs_enable=$enable_dav
diff --git a/modules/dav/fs/mod_dav_fs.c b/modules/dav/fs/mod_dav_fs.c
index 985823d36f..49986fc747 100644
--- a/modules/dav/fs/mod_dav_fs.c
+++ b/modules/dav/fs/mod_dav_fs.c
@@ -16,6 +16,7 @@
#include "httpd.h"
#include "http_config.h"
+#include "http_request.h"
#include "apr_strings.h"
#if !defined(_MSC_VER) && !defined(NETWARE)
#include "ap_config_auto.h"
@@ -24,6 +25,12 @@
#include "mod_dav.h"
#include "repos.h"
+/* per-dir configuration */
+typedef struct {
+ const char *dir;
+ apr_off_t quota;
+} dav_fs_dir_conf;
+
/* per-server configuration */
typedef struct {
const char *lockdb_path;
@@ -44,6 +51,60 @@ const char *dav_get_lockdb_path(const request_rec *r)
return conf->lockdb_path;
}
+static const command_rec dav_fs_cmds[];
+
+dav_error *dav_fs_get_quota(const request_rec *r, const char *path,
+ apr_off_t *quota_bytes)
+{
+ dav_fs_dir_conf *conf = NULL;
+ dav_error *err = NULL;
+ const char *request_path;
+ request_rec *rr;
+ int status;
+
+ request_path = ap_make_dirstr_parent(r->pool, r->filename);
+
+ /*
+ * Uses's request's per directry configuration if possible, for
+ * efficiency sake.
+ */
+ if (!strcmp(path, request_path)) {
+ conf = ap_get_module_config(r->per_dir_config, &dav_fs_module);
+ *quota_bytes = conf->quota;
+ goto out;
+ }
+
+ /*
+ * We need for a per directory configuration from a random path
+ * not tied to current request, for e.g. COPY or MOVE destination.
+ * This is done through a subrequest, with just rr->filename
+ * changed to target path.
+ */
+ rr = ap_sub_req_method_uri(r->method, r->uri, r, r->output_filters);
+ if (!rr || rr->status != HTTP_OK) {
+ err = dav_new_error(r->pool,
+ rr ? rr->status : HTTP_INTERNAL_SERVER_ERROR,
+ 0, 0,
+ "quota configuration subrequest failed");
+ *quota_bytes = DAV_FS_BYTES_ERROR;
+ goto out;
+ }
+
+ rr->filename = apr_pstrdup(r->pool, path);
+ if ((status = ap_directory_walk(rr)) != OK) {
+ err = dav_new_error(r->pool, status, 0, 0,
+ "quota configuration tree walk failed");
+ *quota_bytes = DAV_FS_BYTES_ERROR;
+ goto out;
+ }
+
+ conf = ap_get_module_config(rr->per_dir_config, &dav_fs_module);
+ *quota_bytes = conf->quota;
+
+out:
+ return err;
+}
+
static void *dav_fs_create_server_config(apr_pool_t *p, server_rec *s)
{
return apr_pcalloc(p, sizeof(dav_fs_server_conf));
@@ -64,6 +125,37 @@ static void *dav_fs_merge_server_config(apr_pool_t *p,
return newconf;
}
+static void *dav_fs_create_dir_config(apr_pool_t *p, char *dir)
+{
+ /* NOTE: dir==NULL creates the default per-dir config */
+
+ dav_fs_dir_conf *conf;
+
+ conf = (dav_fs_dir_conf *)apr_pcalloc(p, sizeof(*conf));
+ conf->dir = apr_pstrdup(p, dir);
+ conf->quota = DAV_FS_QUOTA_UNSET;
+
+ return conf;
+}
+
+static void *dav_fs_merge_dir_config(apr_pool_t *p, void *base, void *overrides)
+{
+ dav_fs_dir_conf *parent = base;
+ dav_fs_dir_conf *child = overrides;
+ dav_fs_dir_conf *newconf =
+ (dav_fs_dir_conf *)apr_pcalloc(p, sizeof(*newconf));
+
+ newconf->dir = child->dir;
+
+ if (child->quota != DAV_FS_QUOTA_UNSET)
+ newconf->quota = child->quota;
+ else
+ newconf->quota = parent->quota;
+
+ return newconf;
+}
+
+
static apr_status_t dav_fs_post_config(apr_pool_t *p, apr_pool_t *plog,
apr_pool_t *ptemp, server_rec *base_server)
{
@@ -101,12 +193,35 @@ static const char *dav_fs_cmd_davlockdb(cmd_parms *cmd, void *config,
return NULL;
}
+/*
+ * Command handler for the DAVquota directive, which is TAKE1
+ */
+static const char *dav_fs_cmd_quota(cmd_parms *cmd, void *config,
+ const char *bytes)
+{
+ dav_fs_dir_conf *conf = (dav_fs_dir_conf *)config;
+
+ if (!strcasecmp(bytes, "Off"))
+ conf->quota = DAV_FS_QUOTA_OFF;
+ else if (!strcasecmp(bytes, "None"))
+ conf->quota = DAV_FS_QUOTA_NONE;
+ else
+ conf->quota = atol(bytes);
+
+ return NULL;
+}
+
+
static const command_rec dav_fs_cmds[] =
{
/* per server */
AP_INIT_TAKE1("DAVLockDB", dav_fs_cmd_davlockdb, NULL, RSRC_CONF,
"specify a lock database"),
+ /* per directory */
+ AP_INIT_TAKE1("DAVquota", dav_fs_cmd_quota, NULL, ACCESS_CONF|RSRC_CONF,
+ "specify a directory quota"),
+
{ NULL }
};
@@ -119,6 +234,8 @@ static void register_hooks(apr_pool_t *p)
dav_hook_find_liveprop(dav_fs_find_liveprop, NULL, NULL, APR_HOOK_MIDDLE);
dav_hook_insert_all_liveprops(dav_fs_insert_all_liveprops, NULL, NULL,
APR_HOOK_MIDDLE);
+ dav_hook_method_precondition(dav_fs_method_precondition, NULL, NULL,
+ APR_HOOK_MIDDLE);
dav_fs_register(p);
}
@@ -126,8 +243,8 @@ static void register_hooks(apr_pool_t *p)
AP_DECLARE_MODULE(dav_fs) =
{
STANDARD20_MODULE_STUFF,
- NULL, /* dir config creater */
- NULL, /* dir merger --- default is to override */
+ dav_fs_create_dir_config, /* dir config */
+ dav_fs_merge_dir_config, /* merger dir config */
dav_fs_create_server_config, /* server config */
dav_fs_merge_server_config, /* merge server config */
dav_fs_cmds, /* command table */
diff --git a/modules/dav/fs/mod_dav_fs.dsp b/modules/dav/fs/mod_dav_fs.dsp
index fbfc1e4378..e4b873066e 100644
--- a/modules/dav/fs/mod_dav_fs.dsp
+++ b/modules/dav/fs/mod_dav_fs.dsp
@@ -116,6 +116,10 @@ SOURCE=.\mod_dav_fs.c
# End Source File
# Begin Source File
+SOURCE=.\quota.c
+# End Source File
+# Begin Source File
+
SOURCE=.\repos.c
# End Source File
# End Group
diff --git a/modules/dav/fs/repos.c b/modules/dav/fs/repos.c
index d38868c70a..889d728a1b 100644
--- a/modules/dav/fs/repos.c
+++ b/modules/dav/fs/repos.c
@@ -140,11 +140,6 @@ enum {
*/
#define DAV_PROPID_FS_executable 1
-/*
- * prefix for temporary files
- */
-#define DAV_FS_TMP_PREFIX ".davfs.tmp"
-
static const dav_liveprop_spec dav_fs_props[] =
{
/* standard DAV properties */
@@ -173,6 +168,20 @@ static const dav_liveprop_spec dav_fs_props[] =
0
},
+ /* RFC 4331 quotas */
+ {
+ DAV_FS_URI_DAV,
+ "quota-available-bytes",
+ DAV_PROPID_quota_available_bytes,
+ 0,
+ },
+ {
+ DAV_FS_URI_DAV,
+ "quota-used-bytes",
+ DAV_PROPID_quota_used_bytes,
+ 0,
+ },
+
/* our custom properties */
{
DAV_FS_URI_MYPROPS,
@@ -234,6 +243,24 @@ const char *dav_fs_pathname(const dav_resource *resource)
return resource->info->pathname;
}
+const char *dav_fs_fname(const dav_resource *resource)
+{
+ return resource->info->finfo.fname;
+}
+
+apr_off_t dav_fs_size(const dav_resource *resource)
+{
+ apr_off_t size;
+
+ if ((resource->info->finfo.valid & APR_FINFO_SIZE))
+ size = resource->info->finfo.size;
+ else
+ size = DAV_FS_BYTES_ERROR;
+
+ return size;
+}
+
+
dav_error * dav_fs_dir_file_name(
const dav_resource *resource,
const char **dirpath_p,
@@ -1927,6 +1954,7 @@ static dav_prop_insert dav_fs_insert_prop(const dav_resource *resource,
apr_pool_t *p = resource->info->pool;
const dav_liveprop_spec *info;
long global_ns;
+ apr_off_t bytes;
/* an HTTP-date can be 29 chars plus a null term */
/* a 64-bit size can be 20 chars plus a null term */
@@ -1992,6 +2020,26 @@ static dav_prop_insert dav_fs_insert_prop(const dav_resource *resource,
value = "F";
break;
+ case DAV_PROPID_quota_available_bytes:
+ bytes = dav_fs_get_available_bytes(dav_fs_get_request_rec(resource),
+ dav_fs_fname(resource), NULL);
+ if (bytes == DAV_FS_BYTES_ERROR)
+ return DAV_PROP_INSERT_NOTDEF;
+
+ apr_snprintf(buf, sizeof(buf), "%" APR_OFF_T_FMT, bytes);
+ value = buf;
+ break;
+
+ case DAV_PROPID_quota_used_bytes:
+ bytes = dav_fs_get_used_bytes(dav_fs_get_request_rec(resource),
+ dav_fs_fname(resource));
+ if (bytes == DAV_FS_BYTES_ERROR)
+ return DAV_PROP_INSERT_NOTDEF;
+
+ apr_snprintf(buf, sizeof(buf), "%" APR_OFF_T_FMT, bytes);
+ value = buf;
+ break;
+
default:
/* ### what the heck was this property? */
return DAV_PROP_INSERT_NOTDEF;
@@ -2256,9 +2304,36 @@ void dav_fs_insert_all_liveprops(request_rec *r, const dav_resource *resource,
what, phdr);
#endif
+ /*
+ * RFC 4331 section 2 says quota live properties should not
+ * be returned by <DAV:allprop> PROPFIND, hence we skip
+ " DAV_PROPID_quota_available_bytes and DAV_PROPID_quota_used_bytes.
+ */
+
/* ### we know the others aren't defined as liveprops */
}
+int dav_fs_method_precondition(request_rec *r,
+ dav_resource *src, const dav_resource *dst,
+ const apr_xml_doc *doc, dav_error **err)
+{
+ int ret = DECLINED;
+
+ switch (r->method_number) {
+ case M_COPY: /* FALLTHROUGH */
+ case M_MOVE: /* FALLTHROUGH */
+ case M_MKCOL: /* FALLTHROUGH */
+ case M_PROPPATCH: /* FALLTHROUGH */
+ case M_PUT:
+ ret = dav_fs_quota_precondition(r, src, dst, doc, err);
+ break;
+ default:
+ break;
+ }
+
+ return ret;
+}
+
void dav_fs_register(apr_pool_t *p)
{
/* register the namespace URIs */
diff --git a/modules/dav/fs/repos.h b/modules/dav/fs/repos.h
index b164611888..fa3b138ea3 100644
--- a/modules/dav/fs/repos.h
+++ b/modules/dav/fs/repos.h
@@ -29,7 +29,13 @@
#define DAV_FS_STATE_DIR ".DAV"
#define DAV_FS_STATE_FILE_FOR_DIR ".state_for_dir"
#define DAV_FS_LOCK_NULL_FILE ".locknull"
+#define DAV_FS_TMP_PREFIX ".davfs.tmp" /* prefix for tmp files */
+#define DAV_FS_QUOTA_UNSET 0
+#define DAV_FS_QUOTA_OFF -1
+#define DAV_FS_QUOTA_NONE -2
+
+#define DAV_FS_BYTES_ERROR -1
/* ensure that our state subdirectory is present */
void dav_fs_ensure_state_dir(apr_pool_t *p, const char *dirname);
@@ -40,6 +46,13 @@ apr_pool_t *dav_fs_pool(const dav_resource *resource);
/* return the full pathname for a resource */
const char *dav_fs_pathname(const dav_resource *resource);
+/* same as dav_fs_pathname() with directories' trailing slash */
+const char *dav_fs_fname(const dav_resource *resource);
+
+/* return the size for a resource, -1 if unknown */
+apr_off_t dav_fs_size(const dav_resource *resource);
+
+
/* return the directory and filename for a resource */
dav_error * dav_fs_dir_file_name(const dav_resource *resource,
const char **dirpath,
@@ -67,6 +80,12 @@ void dav_dbm_close(dav_db *db);
/* where is the lock database located? */
const char *dav_get_lockdb_path(const request_rec *r);
+dav_error *dav_fs_get_quota(const request_rec *r, const char *path,
+ apr_off_t *quota_bytes);
+apr_off_t dav_fs_get_used_bytes(request_rec *r, const char *path);
+apr_off_t dav_fs_get_available_bytes(request_rec *r,
+ const char *path, int *fs_low);
+
const dav_hooks_locks *dav_fs_get_lock_hooks(request_rec *r);
const dav_hooks_propdb *dav_fs_get_propdb_hooks(request_rec *r);
@@ -76,6 +95,12 @@ int dav_fs_find_liveprop(const dav_resource *resource,
const dav_hooks_liveprop **hooks);
void dav_fs_insert_all_liveprops(request_rec *r, const dav_resource *resource,
dav_prop_insert what, apr_text_header *phdr);
+int dav_fs_quota_precondition(request_rec *r,
+ dav_resource *src, const dav_resource *dst,
+ const apr_xml_doc *doc, dav_error **err);
+int dav_fs_method_precondition(request_rec *r,
+ dav_resource *src, const dav_resource *dst,
+ const apr_xml_doc *doc, dav_error **err);
void dav_fs_register(apr_pool_t *p);
diff --git a/modules/dav/main/mod_dav.h b/modules/dav/main/mod_dav.h
index b0c6f526bd..fcf146c694 100644
--- a/modules/dav/main/mod_dav.h
+++ b/modules/dav/main/mod_dav.h
@@ -1172,6 +1172,10 @@ enum {
DAV_PROPID_workspace,
DAV_PROPID_workspace_checkout_set,
+ /* RFC 4331 quotas */
+ DAV_PROPID_quota_available_bytes,
+ DAV_PROPID_quota_used_bytes,
+
DAV_PROPID_END
};