diff options
author | manu <manu@unknown> | 2023-03-02 14:36:31 +0000 |
---|---|---|
committer | manu <manu@unknown> | 2023-03-02 14:36:31 +0000 |
commit | 063e815a3c13454887733b3ac1883d7868459728 (patch) | |
tree | 848d652ae3aa69f95b29e488a8a6585b9605f10f /modules/dav | |
parent | 8e229adef7b2ecbdbf9cf602db3564062d04e007 (diff) | |
download | httpd-063e815a3c13454887733b3ac1883d7868459728.tar.gz |
Add RFC4331 quotas for mod_dav_fs
This is enabled by a new directive: DavQuota (Off|None|#bytes)
Off (default): feature disabled
None: no quota enforced, but used and available bytes are reported
#bytes: an numerical value in bytes as the quota to enforce
git-svn-id: https://svn.apache.org/repos/asf/httpd/httpd/trunk@1907974 13f79535-47bb-0310-9956-ffa450edef68
Diffstat (limited to 'modules/dav')
-rw-r--r-- | modules/dav/fs/config6.m4 | 2 | ||||
-rw-r--r-- | modules/dav/fs/mod_dav_fs.c | 121 | ||||
-rw-r--r-- | modules/dav/fs/mod_dav_fs.dsp | 4 | ||||
-rw-r--r-- | modules/dav/fs/repos.c | 85 | ||||
-rw-r--r-- | modules/dav/fs/repos.h | 25 | ||||
-rw-r--r-- | modules/dav/main/mod_dav.h | 4 |
6 files changed, 233 insertions, 8 deletions
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 }; |