michael@685: Index: modules/dav/fs/mod_dav_fs.c michael@685: diff -Nau modules/dav/fs/mod_dav_fs.c.orig modules/dav/fs/mod_dav_fs.c michael@685: --- modules/dav/fs/mod_dav_fs.c.orig 2006-07-12 05:38:44.000000000 +0200 michael@685: +++ modules/dav/fs/mod_dav_fs.c 2012-09-17 14:16:06.937987679 +0200 michael@685: @@ -15,6 +15,7 @@ michael@685: */ michael@685: michael@685: #include "httpd.h" michael@685: +#include "http_log.h" michael@685: #include "http_config.h" michael@685: #include "apr_strings.h" michael@685: michael@685: @@ -24,9 +25,19 @@ michael@685: /* per-server configuration */ michael@685: typedef struct { michael@685: const char *lockdb_path; michael@685: + const char *diskusagedb_path; michael@685: michael@685: } dav_fs_server_conf; michael@685: michael@685: +/* per-dir configuration */ michael@685: +typedef struct { michael@685: + apr_size_t quota; michael@685: + const char *area_path; michael@685: + int hiddenfiles; michael@685: + ap_regex_t *mask; michael@685: + michael@685: +} dav_fs_dir_conf; michael@685: + michael@685: extern module AP_MODULE_DECLARE_DATA dav_fs_module; michael@685: michael@685: const char *dav_get_lockdb_path(const request_rec *r) michael@685: @@ -37,9 +48,20 @@ michael@685: return conf->lockdb_path; michael@685: } michael@685: michael@685: +const char *dav_get_diskusagedb_path(const request_rec *r) michael@685: +{ michael@685: + dav_fs_server_conf *conf; michael@685: + michael@685: + conf = ap_get_module_config(r->server->module_config, &dav_fs_module); michael@685: + return conf->diskusagedb_path; michael@685: +} michael@685: + michael@685: static void *dav_fs_create_server_config(apr_pool_t *p, server_rec *s) michael@685: { michael@685: - return apr_pcalloc(p, sizeof(dav_fs_server_conf)); michael@685: + dav_fs_server_conf *conf; michael@685: + conf = apr_pcalloc(p, sizeof(dav_fs_server_conf)); michael@685: + conf->diskusagedb_path = NULL; michael@685: + return conf; michael@685: } michael@685: michael@685: static void *dav_fs_merge_server_config(apr_pool_t *p, michael@685: @@ -53,6 +75,35 @@ michael@685: michael@685: newconf->lockdb_path = michael@685: child->lockdb_path ? child->lockdb_path : parent->lockdb_path; michael@685: + newconf->diskusagedb_path = michael@685: + child->diskusagedb_path ? child->diskusagedb_path : parent->diskusagedb_path; michael@685: + michael@685: + return newconf; michael@685: +} michael@685: + michael@685: +static void *dav_fs_create_dir_config(apr_pool_t *p, char *dir) michael@685: +{ michael@685: + dav_fs_dir_conf *conf=apr_pcalloc(p, sizeof(dav_fs_dir_conf)); michael@685: + conf->area_path = NULL; michael@685: + conf->mask = NULL; michael@685: + conf->quota = 0; michael@685: + conf->hiddenfiles = -1; michael@685: + return conf; michael@685: +} michael@685: + michael@685: +static void *dav_fs_merge_dir_config(apr_pool_t *p, michael@685: + void *base, void *overrides) michael@685: +{ michael@685: + dav_fs_dir_conf *parent = base; michael@685: + dav_fs_dir_conf *child = overrides; michael@685: + dav_fs_dir_conf *newconf; michael@685: + michael@685: + newconf = apr_pcalloc(p, sizeof(*newconf)); michael@685: + michael@685: + newconf->quota = child->quota ? child->quota : parent->quota; michael@685: + newconf->area_path = child->area_path ? child->area_path : parent->area_path; michael@685: + newconf->hiddenfiles = child->hiddenfiles!=-1 ? child->hiddenfiles : parent->hiddenfiles; michael@685: + newconf->mask = child->mask ? child->mask : parent->mask; michael@685: michael@685: return newconf; michael@685: } michael@685: @@ -76,12 +127,83 @@ michael@685: return NULL; michael@685: } michael@685: michael@685: +/* michael@685: + * Command handler for the DAVLockDB directive, which is TAKE1 michael@685: + */ michael@685: +static const char *dav_fs_cmd_diskusagedb(cmd_parms *cmd, void *config, michael@685: + const char *arg1) michael@685: +{ michael@685: + dav_fs_server_conf *conf; michael@685: + conf = ap_get_module_config(cmd->server->module_config, michael@685: + &dav_fs_module); michael@685: + conf->diskusagedb_path = ap_server_root_relative(cmd->pool, arg1); michael@685: + michael@685: + if (!conf->diskusagedb_path) { michael@685: + return apr_pstrcat(cmd->pool, "Invalid DAVDiskUsageDB path ", michael@685: + arg1, NULL); michael@685: + } michael@685: + michael@685: + return NULL; michael@685: +} michael@685: + michael@685: +/* michael@685: + * Command handler for the DAVFSQuota directive, which is TAKE1 michael@685: + */ michael@685: + michael@685: +static const char *dav_fs_cmd_davareasize( cmd_parms *cmd , void *config , const char *arg1 ) { michael@685: + michael@685: + dav_fs_dir_conf *conf = ( dav_fs_dir_conf * )config; michael@685: + michael@685: + conf->quota = (apr_size_t)atoi( arg1 ); michael@685: + if ( conf->quota < 0 ) michael@685: + return "DAVFSQuota requires a nonnegative integer."; michael@685: + michael@685: + conf->area_path = cmd->path; michael@685: + return NULL; michael@685: + michael@685: +} michael@685: + michael@685: +static const char *dav_fs_cmd_hidefiles( cmd_parms *cmd , void *config , const char *type , const char *arg1 ) { michael@685: + michael@685: + dav_fs_dir_conf *conf = ( dav_fs_dir_conf * )config; michael@685: + michael@685: +//ap_log_error(APLOG_MARK, APLOG_ERR, 0, NULL,"arg1 %s, type %s",arg1, type); michael@685: + michael@685: + if (!strcasecmp(type, "None")) michael@685: + conf->hiddenfiles = DAV_FS_HIDE_NONE; michael@685: + else if (!strcasecmp(type, "Hidden")) michael@685: + conf->hiddenfiles = DAV_FS_HIDE_HIDDEN; michael@685: + else if (!strcasecmp(type, "Deny")) michael@685: + conf->hiddenfiles = DAV_FS_HIDE_DENY; michael@685: + else if (!strcasecmp(type, "Htaccess")) michael@685: + conf->hiddenfiles = DAV_FS_HIDE_HTACCESS; michael@685: + else if (!strcasecmp(type, "Mask")) { michael@685: + conf->hiddenfiles = DAV_FS_HIDE_MASK; michael@685: + conf->mask = ap_pregcomp(cmd->pool, arg1, AP_REG_EXTENDED|AP_REG_ICASE); michael@685: + if (!conf->mask) { michael@685: + return apr_psprintf(cmd->pool, "Regex '%s' in DAVFSHideFiles Mask could not be compiled", arg1); michael@685: + } michael@685: + } else { michael@685: + return "DAVFSHideFiles must be one of: " michael@685: + "None | Hidden | Deny | Htaccess | Mask "; michael@685: + } michael@685: + return NULL; michael@685: +} michael@685: + michael@685: static const command_rec dav_fs_cmds[] = michael@685: { michael@685: /* per server */ michael@685: AP_INIT_TAKE1("DAVLockDB", dav_fs_cmd_davlockdb, NULL, RSRC_CONF, michael@685: "specify a lock database"), michael@685: - michael@685: + AP_INIT_TAKE1("DAVDiskUsageDB", dav_fs_cmd_diskusagedb, NULL, RSRC_CONF, michael@685: + "specify a disk usage database"), michael@685: + /* per directory/location */ michael@685: + AP_INIT_TAKE1("DAVFSQuota", dav_fs_cmd_davareasize, NULL, michael@685: + OR_LIMIT|ACCESS_CONF, michael@685: + "max size of user storage area, per KByte"), michael@685: + AP_INIT_TAKE12("DAVFSHideFiles", dav_fs_cmd_hidefiles, NULL, michael@685: + OR_LIMIT|ACCESS_CONF, michael@685: + "how files need for hide in collection: None | Hidden | Deny | Htaccess | Mask "), michael@685: { NULL } michael@685: }; michael@685: michael@685: @@ -99,10 +221,38 @@ michael@685: module AP_MODULE_DECLARE_DATA dav_fs_module = michael@685: { michael@685: STANDARD20_MODULE_STUFF, michael@685: - NULL, /* dir config creater */ michael@685: - NULL, /* dir merger --- default is to override */ michael@685: + dav_fs_create_dir_config, /* dir config creater */ michael@685: + dav_fs_merge_dir_config, /* dir merger --- default is to override */ michael@685: dav_fs_create_server_config, /* server config */ michael@685: dav_fs_merge_server_config, /* merge server config */ michael@685: dav_fs_cmds, /* command table */ michael@685: register_hooks, /* register hooks */ michael@685: }; michael@685: + michael@685: +const apr_size_t dav_fs_get_quota( request_rec *r ) { michael@685: + michael@685: + dav_fs_dir_conf *conf = ap_get_module_config( r->per_dir_config , &dav_fs_module ); michael@685: + return conf->quota; michael@685: + michael@685: +} michael@685: + michael@685: +const char *dav_fs_get_dir( request_rec *r ) { michael@685: + michael@685: + dav_fs_dir_conf *conf = ap_get_module_config( r->per_dir_config , &dav_fs_module ); michael@685: + return conf->area_path; michael@685: + michael@685: +} michael@685: + michael@685: +const int dav_fs_get_hidefiles( request_rec *r ) { michael@685: + michael@685: + dav_fs_dir_conf *conf = ap_get_module_config( r->per_dir_config , &dav_fs_module ); michael@685: + return conf->hiddenfiles; michael@685: + michael@685: +} michael@685: + michael@685: +const ap_regex_t *dav_fs_get_mask( request_rec *r ) { michael@685: + michael@685: + dav_fs_dir_conf *conf = ap_get_module_config( r->per_dir_config , &dav_fs_module ); michael@685: + return conf->mask; michael@685: + michael@685: +} michael@685: Index: modules/dav/fs/quota.h michael@685: diff -Nau modules/dav/fs/quota.h.orig modules/dav/fs/quota.h michael@685: --- modules/dav/fs/quota.h.orig 1970-01-01 01:00:00.000000000 +0100 michael@685: +++ modules/dav/fs/quota.h 2012-09-17 14:16:06.938238230 +0200 michael@685: @@ -0,0 +1,13 @@ michael@685: +/** michael@685: + disk quota check modules for WebDAV service michael@685: + author: satake@goodcrew.ne.jp, changed by bjaka.max@gmail.com michael@685: +*/ michael@685: + michael@685: +/** set your storage cluster size */ michael@685: +#ifndef DAV_CLUSTER_SIZE michael@685: + #define DAV_CLUSTER_SIZE 4096 michael@685: +#endif michael@685: + michael@685: +static apr_size_t dav_qchk_du(const char *dirname, apr_pool_t *pool); michael@685: +static apr_size_t dav_cached_du(char *dirname, const request_rec *r); michael@685: +static apr_status_t dav_change_cached_du(const char *dirname, const request_rec *r, int add_size, apr_size_t delta); michael@685: Index: modules/dav/fs/repos.c michael@685: diff -Nau modules/dav/fs/repos.c.orig modules/dav/fs/repos.c michael@685: --- modules/dav/fs/repos.c.orig 2011-09-08 17:59:38.000000000 +0200 michael@685: +++ modules/dav/fs/repos.c 2012-09-17 14:18:07.509160501 +0200 michael@685: @@ -27,6 +27,8 @@ michael@685: #include /* for sprintf() */ michael@685: #endif michael@685: michael@685: +#include "util_filter.h" michael@685: +#include "apr_sdbm.h" michael@685: #include "httpd.h" michael@685: #include "http_log.h" michael@685: #include "http_protocol.h" /* for ap_set_* (in dav_fs_set_headers) */ michael@685: @@ -34,6 +36,7 @@ michael@685: michael@685: #include "mod_dav.h" michael@685: #include "repos.h" michael@685: +#include "quota.h" michael@685: michael@685: michael@685: /* to assist in debugging mod_dav's GET handling */ michael@685: @@ -46,6 +49,10 @@ michael@685: apr_pool_t *pool; /* memory storage pool associated with request */ michael@685: const char *pathname; /* full pathname to resource */ michael@685: apr_finfo_t finfo; /* filesystem info */ michael@685: + request_rec *r; /* request of this resource*/ michael@685: + apr_size_t quota; /* config data for quota check */ michael@685: + const char *area_path; michael@685: + int hiddenfiles; michael@685: }; michael@685: michael@685: /* private context for doing a filesystem walk */ michael@685: @@ -137,7 +144,12 @@ michael@685: /* michael@685: ** The single property that we define (in the DAV_FS_URI_MYPROPS namespace) michael@685: */ michael@685: -#define DAV_PROPID_FS_executable 1 michael@685: +#define DAV_PROPID_FS_executable 1 michael@685: +/* michael@685: +**Quota property in DAV:namespace michael@685: +*/ michael@685: +#define DAV_PROPID_quota_available_bytes 2 michael@685: +#define DAV_PROPID_quota_used_bytes 3 michael@685: michael@685: static const dav_liveprop_spec dav_fs_props[] = michael@685: { michael@685: @@ -166,8 +178,20 @@ michael@685: DAV_PROPID_getlastmodified, michael@685: 0 michael@685: }, michael@685: - michael@685: + { michael@685: + DAV_FS_URI_DAV, michael@685: + "quota-available-bytes", michael@685: + DAV_PROPID_quota_available_bytes, michael@685: + 0 michael@685: + }, michael@685: + { michael@685: + DAV_FS_URI_DAV, michael@685: + "quota-used-bytes", michael@685: + DAV_PROPID_quota_used_bytes, michael@685: + 0 michael@685: + }, michael@685: /* our custom properties */ michael@685: + michael@685: { michael@685: DAV_FS_URI_MYPROPS, michael@685: "executable", michael@685: @@ -191,6 +215,9 @@ michael@685: apr_pool_t *p; michael@685: apr_file_t *f; michael@685: const char *pathname; /* we may need to remove it at close time */ michael@685: + apr_size_t quota; /* config data for quota check */ michael@685: + const char *area_path; michael@685: + request_rec *r; /* request of this resource*/ michael@685: }; michael@685: michael@685: /* returns an appropriate HTTP status code given an APR status code for a michael@685: @@ -641,6 +668,8 @@ michael@685: dav_resource *resource; michael@685: char *s; michael@685: char *filename; michael@685: + apr_size_t nowsize, putsize; michael@685: + const char *conlen; michael@685: apr_size_t len; michael@685: michael@685: /* ### optimize this into a single allocation! */ michael@685: @@ -652,6 +681,37 @@ michael@685: /* ### this should go away */ michael@685: ctx->pool = r->pool; michael@685: michael@685: + ctx->r = r; michael@685: + ctx->quota = dav_fs_get_quota(r); michael@685: + ctx->area_path = dav_fs_get_dir(r); michael@685: + michael@685: + ctx->hiddenfiles = dav_fs_get_hidefiles(r); michael@685: + michael@685: +// ap_log_error(APLOG_MARK, APLOG_ERR, 0, NULL,"Pathname is %s, quota is %d",ctx->area_path,ctx->quota); michael@685: + /** Check quota limit*/ michael@685: + if (ctx->quota && r->method_number==M_PUT) { michael@685: + michael@685: + /** get now user used size */ michael@685: + nowsize = dav_cached_du(ctx->area_path, r); michael@685: + michael@685: + /** get put size */ michael@685: + conlen = NULL; michael@685: + putsize = 0; michael@685: + if ( r->headers_in!=NULL ) { michael@685: + conlen = apr_table_get( r->headers_in , "content-length" ); michael@685: + } michael@685: + if ( conlen!=NULL ) { michael@685: + putsize = ((atoi(conlen)+DAV_CLUSTER_SIZE-1)/DAV_CLUSTER_SIZE)*(DAV_CLUSTER_SIZE/1024); michael@685: + } michael@685: + michael@685: + /** check size */ michael@685: +// ap_log_error(APLOG_MARK, APLOG_ERR, 0, NULL,"Pathname is %s, directory size is %d, quota is %d",ctx->area_path, nowsize+putsize, ctx->quota); michael@685: + if ( nowsize+putsize>=ctx->quota ) { michael@685: + return dav_new_error(r->pool, HTTP_INSUFFICIENT_STORAGE, 0, michael@685: + apr_psprintf(r->pool,"WebDAV-Quota: Directory `%s' size %dKB+%dKB(%s) is over %dKB!",ctx->area_path, nowsize,putsize,conlen, ctx->quota)); michael@685: + } michael@685: + } michael@685: + michael@685: /* Preserve case on OSes which fold canonical filenames */ michael@685: #if 0 michael@685: /* ### not available in Apache 2.0 yet */ michael@685: @@ -865,6 +925,12 @@ michael@685: michael@685: ds->p = p; michael@685: ds->pathname = resource->info->pathname; michael@685: + michael@685: + ds->quota=resource->info->quota; michael@685: + ds->area_path=resource->info->area_path; michael@685: + michael@685: + ds->r = resource->info->r; michael@685: + michael@685: rv = apr_file_open(&ds->f, ds->pathname, flags, APR_OS_DEFAULT, ds->p); michael@685: if (rv != APR_SUCCESS) { michael@685: return dav_new_error(p, MAP_IO2HTTP(rv), 0, michael@685: @@ -889,6 +955,23 @@ michael@685: "back) the resource " michael@685: "when it was being closed."); michael@685: } michael@685: + } else { michael@685: + michael@685: + if(stream->area_path && stream->r->method_number==M_PUT) { michael@685: + const char *conlen = NULL; michael@685: + apr_size_t putsize = 0; michael@685: + /** get put size */ michael@685: + michael@685: + if ( stream->r->headers_in!=NULL ) { michael@685: + conlen = apr_table_get( stream->r->headers_in , "content-length" ); michael@685: + } michael@685: + if ( conlen!=NULL ) { michael@685: + putsize = ((atoi(conlen)+DAV_CLUSTER_SIZE-1)/DAV_CLUSTER_SIZE)*(DAV_CLUSTER_SIZE/1024); michael@685: + } michael@685: + michael@685: + dav_change_cached_du(stream->area_path, stream->r, 1, putsize); michael@685: + } michael@685: + michael@685: } michael@685: michael@685: return NULL; michael@685: @@ -926,8 +1009,145 @@ michael@685: } michael@685: return NULL; michael@685: } michael@685: +/** michael@685: + get (dirname) total size ( per 512byte ) michael@685: + @param dirname directory name michael@685: + @return block size michael@685: +*/ michael@685: +static apr_size_t get_dir_size(const char *dirname, apr_pool_t *pool) { michael@685: + michael@685: + DIR *dir; michael@685: + struct dirent *ent; michael@685: + struct stat status; michael@685: + char *buffer; michael@685: + apr_size_t size = 0; michael@685: + michael@685: + dir = opendir(dirname); michael@685: + if ( dir==NULL ) { michael@685: + return 0; michael@685: + } michael@685: + michael@685: + while ( (ent = readdir(dir))!=NULL ) { michael@685: + if ( (!strcmp(ent->d_name, ".")) || (!strcmp(ent->d_name, "..")) ) { michael@685: + continue; michael@685: + } michael@685: + michael@685: + apr_filepath_merge(&buffer, dirname, ent->d_name, 0, pool); michael@685: + michael@685: + if ( !lstat(buffer, &status) ) { michael@685: + size += status.st_blocks; michael@685: + if ( status.st_mode & S_IFDIR ) { michael@685: + size += get_dir_size(buffer, pool); michael@685: + } michael@685: + } michael@685: + } michael@685: + closedir(dir); michael@685: + return size; michael@685: +} michael@685: michael@685: +/** michael@685: + return directory total disk space. michael@685: + same as 'du -sk dirname' command. michael@685: + @param dirname directory michael@685: + @return total space michael@685: +*/ michael@685: +static apr_size_t dav_qchk_du(const char *dirname, apr_pool_t *pool) { michael@685: + struct stat status; michael@685: michael@685: + if ( lstat(dirname, &status) ) { michael@685: + return 0; michael@685: + } michael@685: + return (status.st_blocks+((status.st_mode & S_IFDIR)?get_dir_size(dirname, pool):0))/2; michael@685: +} michael@685: + michael@685: +static apr_sdbm_datum_t dav_cached_du_prepare_key(const char *dirname, apr_pool_t *pool) { michael@685: + apr_sdbm_datum_t key; michael@685: + key.dsize = strlen(dirname)+1; michael@685: + key.dptr = apr_palloc(pool, key.dsize); michael@685: + memcpy(key.dptr, dirname, key.dsize); michael@685: + if (key.dptr[key.dsize - 2] == '/') michael@685: + key.dptr[--key.dsize - 1] = '\0'; michael@685: + return key; michael@685: +} michael@685: + michael@685: +static apr_size_t dav_cached_du(char *dirname, const request_rec *r) { michael@685: + const char *pathname = dav_get_diskusagedb_path(r); michael@685: + apr_status_t status; michael@685: + apr_sdbm_t *db; michael@685: + apr_sdbm_datum_t val = { 0 }; michael@685: + apr_size_t size; michael@685: + apr_sdbm_datum_t key; michael@685: + if (dirname[strlen(dirname)-1] == '/') michael@685: + dirname[strlen(dirname)-1] = '\0'; michael@685: + michael@685: + if(!pathname) michael@685: + return dav_qchk_du(dirname, r->pool); michael@685: + michael@685: + key=dav_cached_du_prepare_key(dirname, r->pool); michael@685: + michael@685: + if ((status = apr_sdbm_open(&db, pathname, APR_WRITE | APR_CREATE, michael@685: + APR_OS_DEFAULT, r->pool))!= APR_SUCCESS) { michael@685: + ap_log_error(APLOG_MARK, APLOG_ERR, 0, NULL,"Error accessing to '%s' Disk Usage db file.", pathname); michael@685: + return dav_qchk_du(dirname, r->pool); michael@685: + } michael@685: + michael@685: + apr_sdbm_fetch(db, &val, key); michael@685: + if(val.dptr) { michael@685: + size = atoi(val.dptr); michael@685: + } else { michael@685: + size=dav_qchk_du(dirname, r->pool); michael@685: + val.dptr = apr_psprintf(r->pool,"%" APR_OFF_T_FMT, size); michael@685: + val.dsize = strlen(val.dptr); michael@685: + apr_sdbm_store(db, key, val, APR_SDBM_REPLACE); michael@685: + } michael@685: + michael@685: + apr_sdbm_close(db); michael@685: + return size; michael@685: +} michael@685: + michael@685: +static apr_status_t dav_change_cached_du(const char *dirname, const request_rec *r, int add_size, apr_size_t delta) { michael@685: + const char *pathname = dav_get_diskusagedb_path(r); michael@685: + apr_status_t status; michael@685: + apr_sdbm_t *db; michael@685: + apr_sdbm_datum_t val = { 0 }; michael@685: + apr_size_t size; michael@685: + apr_sdbm_datum_t key; michael@685: + michael@685: + if(!pathname) michael@685: + return APR_SUCCESS; michael@685: + michael@685: + key=dav_cached_du_prepare_key(dirname, r->pool); michael@685: + michael@685: + if ((status = apr_sdbm_open(&db, pathname, APR_WRITE | APR_CREATE | APR_SHARELOCK, michael@685: + APR_OS_DEFAULT, r->pool))!= APR_SUCCESS) { michael@685: + return status; michael@685: + } michael@685: + michael@685: + apr_sdbm_fetch(db, &val, key); michael@685: + michael@685: + if(val.dptr) { michael@685: + apr_sdbm_lock(db, APR_FLOCK_EXCLUSIVE); michael@685: + apr_sdbm_fetch(db, &val, key); michael@685: + size = atoi(val.dptr); michael@685: + if(add_size) { michael@685: + size += delta; michael@685: + } else { michael@685: + size -= delta; michael@685: + } michael@685: + val.dptr = apr_psprintf(r->pool,"%" APR_OFF_T_FMT, size); michael@685: + val.dsize = strlen(val.dptr); michael@685: + apr_sdbm_store(db, key, val, APR_SDBM_REPLACE); michael@685: + apr_sdbm_unlock(db); michael@685: + } else { michael@685: + size=dav_qchk_du(dirname, r->pool); michael@685: + val.dptr = apr_psprintf(r->pool,"%" APR_OFF_T_FMT, size); michael@685: + val.dsize = strlen(val.dptr); michael@685: + apr_sdbm_store(db, key, val, APR_SDBM_REPLACE); michael@685: + } michael@685: + michael@685: + apr_sdbm_close(db); michael@685: + return APR_SUCCESS; michael@685: +} michael@685: #if DEBUG_GET_HANDLER michael@685: michael@685: /* only define set_headers() and deliver() for debug purposes */ michael@685: @@ -1355,6 +1575,8 @@ michael@685: dav_response **response) michael@685: { michael@685: dav_resource_private *info = resource->info; michael@685: + struct stat status; michael@685: + apr_size_t putsize = 0; michael@685: michael@685: *response = NULL; michael@685: michael@685: @@ -1394,6 +1616,10 @@ michael@685: } michael@685: michael@685: /* not a collection; remove the file and its properties */ michael@685: + if (info->area_path && !lstat(info->pathname, &status) ) { michael@685: + putsize = status.st_blocks/2; michael@685: + dav_change_cached_du(info->area_path, info->r, 0, putsize); michael@685: + } michael@685: if (apr_file_remove(info->pathname, info->pool) != APR_SUCCESS) { michael@685: /* ### put a description in here */ michael@685: return dav_new_error(info->pool, HTTP_FORBIDDEN, 0, NULL); michael@685: @@ -1418,7 +1644,12 @@ michael@685: int isdir = fsctx->res1.collection; michael@685: apr_finfo_t dirent; michael@685: apr_dir_t *dirp; michael@685: + char *dirname; michael@685: + const ap_regex_t *mask; michael@685: michael@685: + if(fsctx->info1.hiddenfiles==DAV_FS_HIDE_MASK) { michael@685: + mask=dav_fs_get_mask(fsctx->info1.r); michael@685: + } michael@685: /* ensure the context is prepared properly, then call the func */ michael@685: err = (*params->func)(&fsctx->wres, michael@685: isdir michael@685: @@ -1455,13 +1686,16 @@ michael@685: fsctx->res2.collection = 0; michael@685: michael@685: /* open and scan the directory */ michael@685: + dirname=apr_pstrdup(pool, fsctx->path1.buf); michael@685: if ((apr_dir_open(&dirp, fsctx->path1.buf, pool)) != APR_SUCCESS) { michael@685: /* ### need a better error */ michael@685: return dav_new_error(pool, HTTP_NOT_FOUND, 0, NULL); michael@685: } michael@685: - while ((apr_dir_read(&dirent, APR_FINFO_DIRENT, dirp)) == APR_SUCCESS) { michael@685: + while ((apr_dir_read(&dirent, APR_FINFO_DIRENT | APR_FINFO_NORM, dirp)) == APR_SUCCESS) { michael@685: apr_size_t len; michael@685: apr_status_t status; michael@685: + apr_finfo_t finfo; michael@685: + apr_status_t rv; michael@685: michael@685: len = strlen(dirent.name); michael@685: michael@685: @@ -1479,6 +1713,37 @@ michael@685: if (!strcmp(dirent.name, DAV_FS_STATE_DIR)) { michael@685: continue; michael@685: } michael@685: + //ap_log_error(APLOG_MARK, APLOG_ERR, 0, NULL,"Hiddenfiles %i",fsctx->info1.hiddenfiles); michael@685: + if(fsctx->info1.hiddenfiles && fsctx->info1.hiddenfiles!=-1) { michael@685: + if(fsctx->info1.hiddenfiles==DAV_FS_HIDE_HIDDEN) { michael@685: + if(dirent.name[0]=='.') { michael@685: + continue; michael@685: + } michael@685: + } else if(fsctx->info1.hiddenfiles==DAV_FS_HIDE_DENY) { michael@685: + request_rec *rr; michael@685: + const char *fullname = apr_pstrcat(pool, dirname, dirent.name, NULL); michael@685: + if (!(rr = ap_sub_req_lookup_file(ap_os_escape_path(pool,fullname,1), fsctx->info1.r, NULL))) { michael@685: + //ap_log_error(APLOG_MARK, APLOG_ERR, 0, NULL,"Path %s, filename %s, fullname %s, return false", dirname, dirent.name, fullname); michael@685: + continue; michael@685: + } michael@685: + if (rr->status >= 400) { michael@685: + //ap_log_error(APLOG_MARK, APLOG_ERR, 0, NULL,"Path %s, filename %s, fullname(escaped) %s(%s), status %i", dirname, dirent.name, fullname, ap_os_escape_path(pool,fullname,1), rr->status); michael@685: + ap_destroy_sub_req(rr); michael@685: + continue; michael@685: + } michael@685: + //ap_log_error(APLOG_MARK, APLOG_ERR, 0, NULL,"dirname %s, subrequest filename %s",dirname, rr->filename); michael@685: + ap_destroy_sub_req(rr); michael@685: + } else if(fsctx->info1.hiddenfiles==DAV_FS_HIDE_HTACCESS) { michael@685: + if(!strcmp(dirent.name, ".htaccess")) { michael@685: + continue; michael@685: + } michael@685: + } else if(fsctx->info1.hiddenfiles==DAV_FS_HIDE_MASK) { michael@685: + if(!ap_regexec(mask, dirent.name, 0, NULL, 0)) { michael@685: + //ap_log_error(APLOG_MARK, APLOG_ERR, 0, NULL,"hide %s",dirent.name); michael@685: + continue; michael@685: + } michael@685: + } michael@685: + } michael@685: } michael@685: /* skip the state dir unless a HIDDEN is performed */ michael@685: if (!(params->walk_type & DAV_WALKTYPE_HIDDEN) michael@685: @@ -1489,14 +1754,8 @@ michael@685: /* append this file onto the path buffer (copy null term) */ michael@685: dav_buffer_place_mem(pool, &fsctx->path1, dirent.name, len + 1, 0); michael@685: michael@685: - status = apr_stat(&fsctx->info1.finfo, fsctx->path1.buf, michael@685: - DAV_FINFO_MASK, pool); michael@685: - if (status != APR_SUCCESS && status != APR_INCOMPLETE) { michael@685: - /* woah! where'd it go? */ michael@685: - /* ### should have a better error here */ michael@685: - err = dav_new_error(pool, HTTP_NOT_FOUND, 0, NULL); michael@685: - break; michael@685: - } michael@685: + //set the finfo for further process michael@685: + fsctx->info1.finfo=dirent; michael@685: michael@685: /* copy the file to the URI, too. NOTE: we will pad an extra byte michael@685: for the trailing slash later. */ michael@685: @@ -1512,10 +1771,11 @@ michael@685: fsctx->info2.pathname = fsctx->path2.buf; michael@685: michael@685: /* set up the URI for the current resource */ michael@685: + //ap_log_error(APLOG_MARK, APLOG_ERR, 0, NULL,"the_request: %s,hostname: %s,status_line: %s,method: %s,range: %s,content_type: %s,unparsed_uri: %s,uri: %s,filename: %s,canonical_filename: %s,path_info: %s,args: %s,uri: %s",fsctx->info1.r->the_request ,fsctx->info1.r->hostname ,fsctx->info1.r->status_line,fsctx->info1.r->method,fsctx->info1.r->range,fsctx->info1.r->content_type,fsctx->info1.r->unparsed_uri,fsctx->info1.r->uri,fsctx->info1.r->filename,fsctx->info1.r->canonical_filename,fsctx->info1.r->path_info,fsctx->info1.r->args,fsctx->uri_buf.buf); michael@685: fsctx->res1.uri = fsctx->uri_buf.buf; michael@685: michael@685: /* ### for now, only process regular files (e.g. skip symlinks) */ michael@685: - if (fsctx->info1.finfo.filetype == APR_REG) { michael@685: + if (dirent.filetype == APR_REG) { michael@685: /* call the function for the specified dir + file */ michael@685: if ((err = (*params->func)(&fsctx->wres, michael@685: DAV_CALLTYPE_MEMBER)) != NULL) { michael@685: @@ -1523,7 +1783,7 @@ michael@685: break; michael@685: } michael@685: } michael@685: - else if (fsctx->info1.finfo.filetype == APR_DIR) { michael@685: + else if (dirent.filetype == APR_DIR) { michael@685: apr_size_t save_path_len = fsctx->path1.cur_len; michael@685: apr_size_t save_uri_len = fsctx->uri_buf.cur_len; michael@685: apr_size_t save_path2_len = fsctx->path2.cur_len; michael@685: @@ -1690,6 +1950,7 @@ michael@685: dav_fs_walker_context fsctx = { 0 }; michael@685: dav_error *err; michael@685: dav_fs_copymove_walk_ctx cm_ctx = { 0 }; michael@685: + const char *uri,*request=params->root->info->r->the_request; michael@685: michael@685: #if DAV_DEBUG michael@685: if ((params->walk_type & DAV_WALKTYPE_LOCKNULL) != 0 michael@685: @@ -1743,7 +2004,11 @@ michael@685: } michael@685: michael@685: /* prep the URI buffer */ michael@685: - dav_buffer_init(params->pool, &fsctx.uri_buf, params->root->uri); michael@685: + michael@685: + uri = ap_getword(params->pool, &request, ' '); //get method michael@685: + uri = ap_getword(params->pool, &request, ' '); //get uri michael@685: + ap_unescape_url(uri); michael@685: + dav_buffer_init(params->pool, &fsctx.uri_buf, uri); michael@685: michael@685: /* if we have a directory, then ensure the URI has a trailing "/" */ michael@685: if (fsctx.res1.collection michael@685: @@ -1844,8 +2109,11 @@ michael@685: ** client cannot store dead values -- we deny that thru the is_writable michael@685: ** hook function. michael@685: */ michael@685: - if (!resource->exists) michael@685: + if (!resource->exists) { michael@685: +//ap_log_error(APLOG_MARK, APLOG_ERR, 0, NULL,"resource not exist"); michael@685: + michael@685: return DAV_PROP_INSERT_NOTDEF; michael@685: +} michael@685: michael@685: switch (propid) { michael@685: case DAV_PROPID_creationdate: michael@685: @@ -1896,15 +2164,29 @@ michael@685: value = "F"; michael@685: break; michael@685: michael@685: + case DAV_PROPID_quota_available_bytes: michael@685: + /* Property defined only for collection with quota */ michael@685: + if (!resource->info->quota || !resource->collection) michael@685: + return DAV_PROP_INSERT_NOTDEF; michael@685: + value = apr_psprintf(p, "%d", (resource->info->quota-dav_cached_du(resource->info->area_path, resource->info->r))*1024); michael@685: + break; michael@685: + michael@685: + case DAV_PROPID_quota_used_bytes: michael@685: + /* Property defined only for collection with quota */ michael@685: + if (!resource->info->quota || !resource->collection) michael@685: + return DAV_PROP_INSERT_NOTDEF; michael@685: + value = apr_psprintf(p, "%d", dav_cached_du(resource->info->area_path, resource->info->r)*1024); michael@685: + break; michael@685: + michael@685: default: michael@685: /* ### what the heck was this property? */ michael@685: return DAV_PROP_INSERT_NOTDEF; michael@685: } michael@685: michael@685: /* assert: value != NULL */ michael@685: - michael@685: /* get the information and global NS index for the property */ michael@685: global_ns = dav_get_liveprop_info(propid, &dav_fs_liveprop_group, &info); michael@685: +//ap_log_error(APLOG_MARK, APLOG_ERR, 0, NULL,"ns=%d name=%s value=%s",global_ns, info->name, value); michael@685: michael@685: /* assert: info != NULL && info->name != NULL */ michael@685: michael@685: @@ -2138,7 +2420,7 @@ michael@685: */ michael@685: return; michael@685: } michael@685: - michael@685: +//ap_log_error(APLOG_MARK, APLOG_ERR, 0, NULL,"Try show all props"); michael@685: (void) dav_fs_insert_prop(resource, DAV_PROPID_creationdate, michael@685: what, phdr); michael@685: (void) dav_fs_insert_prop(resource, DAV_PROPID_getcontentlength, michael@685: @@ -2148,6 +2430,11 @@ michael@685: (void) dav_fs_insert_prop(resource, DAV_PROPID_getetag, michael@685: what, phdr); michael@685: michael@685: + (void) dav_fs_insert_prop(resource, DAV_PROPID_quota_available_bytes, michael@685: + what, phdr); michael@685: + (void) dav_fs_insert_prop(resource, DAV_PROPID_quota_used_bytes, michael@685: + what, phdr); michael@685: + michael@685: #ifdef DAV_FS_HAS_EXECUTABLE michael@685: /* Only insert this property if it is defined for this platform. */ michael@685: (void) dav_fs_insert_prop(resource, DAV_PROPID_FS_executable, michael@685: Index: modules/dav/fs/repos.h michael@685: diff -Nau modules/dav/fs/repos.h.orig modules/dav/fs/repos.h michael@685: --- modules/dav/fs/repos.h.orig 2006-07-12 05:38:44.000000000 +0200 michael@685: +++ modules/dav/fs/repos.h 2012-09-17 14:16:06.941582156 +0200 michael@685: @@ -30,6 +30,12 @@ michael@685: #define DAV_FS_STATE_FILE_FOR_DIR ".state_for_dir" michael@685: #define DAV_FS_LOCK_NULL_FILE ".locknull" michael@685: michael@685: +#define DAV_FS_HIDE_NONE 0 michael@685: +#define DAV_FS_HIDE_HIDDEN 1 michael@685: +#define DAV_FS_HIDE_DENY 2 michael@685: +#define DAV_FS_HIDE_HTACCESS 3 michael@685: +#define DAV_FS_HIDE_MASK 4 michael@685: + michael@685: michael@685: /* ensure that our state subdirectory is present */ michael@685: void dav_fs_ensure_state_dir(apr_pool_t *p, const char *dirname); michael@685: @@ -67,6 +73,8 @@ michael@685: /* where is the lock database located? */ michael@685: const char *dav_get_lockdb_path(const request_rec *r); michael@685: michael@685: +const char *dav_get_diskusagedb_path(const request_rec *r); michael@685: + michael@685: const dav_hooks_locks *dav_fs_get_lock_hooks(request_rec *r); michael@685: const dav_hooks_propdb *dav_fs_get_propdb_hooks(request_rec *r); michael@685: michael@685: @@ -79,6 +87,11 @@ michael@685: michael@685: void dav_fs_register(apr_pool_t *p); michael@685: michael@685: +const apr_size_t dav_fs_get_quota( request_rec *r ); michael@685: +const char *dav_fs_get_dir( request_rec *r ); michael@685: +const int dav_fs_get_hidefiles( request_rec *r ); michael@685: +const ap_regex_t *dav_fs_get_mask( request_rec *r ); michael@685: + michael@685: #endif /* _DAV_FS_REPOS_H_ */ michael@685: /** @} */ michael@685: michael@685: Index: modules/dav/main/mod_dav.c michael@685: diff -Nau modules/dav/main/mod_dav.c.orig modules/dav/main/mod_dav.c michael@685: --- modules/dav/main/mod_dav.c.orig 2011-02-09 09:43:17.000000000 +0100 michael@685: +++ modules/dav/main/mod_dav.c 2012-09-17 14:16:06.944219747 +0200 michael@685: @@ -884,7 +884,14 @@ michael@685: michael@685: return DECLINED; michael@685: } michael@685: - michael@685: +struct dav_stream { michael@685: + apr_pool_t *p; michael@685: + apr_file_t *f; michael@685: + const char *pathname; /* we may need to remove it at close time */ michael@685: + apr_size_t quota; /* config data for quota check */ michael@685: + const char *area_path; michael@685: + request_rec *r; /* request of this resource*/ michael@685: +}; michael@685: /* handle the PUT method */ michael@685: static int dav_method_put(request_rec *r) michael@685: { michael@685: @@ -958,7 +965,6 @@ michael@685: else { michael@685: mode = DAV_MODE_WRITE_TRUNC; michael@685: } michael@685: - michael@685: /* make sure the resource can be modified (if versioning repository) */ michael@685: if ((err = dav_auto_checkout(r, resource, michael@685: 0 /* not parent_only */, michael@685: @@ -1043,6 +1049,7 @@ michael@685: /* no error during the write, but we hit one at close. use it. */ michael@685: err = err2; michael@685: } michael@685: + michael@685: } michael@685: michael@685: /* michael@685: @@ -2583,7 +2590,6 @@ michael@685: dav_lockdb *lockdb; michael@685: int replace_dest; michael@685: int resnew_state; michael@685: - michael@685: /* Ask repository module to resolve the resource */ michael@685: err = dav_get_resource(r, !is_move /* label_allowed */, michael@685: 0 /* use_checked_in */, &resource); michael@685: @@ -2635,6 +2641,7 @@ michael@685: michael@685: return dav_error_response(r, lookup.err.status, lookup.err.desc); michael@685: } michael@685: + michael@685: if (lookup.rnew->status != HTTP_OK) { michael@685: const char *auth = apr_table_get(lookup.rnew->err_headers_out, michael@685: "WWW-Authenticate"); michael@685: @@ -2700,6 +2707,7 @@ michael@685: if ((depth = dav_get_depth(r, DAV_INFINITY)) < 0) { michael@685: /* dav_get_depth() supplies additional information for the michael@685: * default message. */ michael@685: + michael@685: return HTTP_BAD_REQUEST; michael@685: } michael@685: if (depth == 1) { michael@685: @@ -2817,7 +2825,6 @@ michael@685: /* ### pass lockdb! */ michael@685: (void)dav_unlock(r, resource, NULL); michael@685: } michael@685: - michael@685: /* if this is a move, then the source parent collection will be modified */ michael@685: if (is_move) { michael@685: if ((err = dav_auto_checkout(r, resource, 1 /* parent_only */, michael@685: @@ -2835,7 +2842,6 @@ michael@685: * can be notified as to how it changed. michael@685: */ michael@685: resnew_state = dav_get_resource_state(lookup.rnew, resnew); michael@685: - michael@685: /* In a MOVE operation, the destination is replaced by the source. michael@685: * In a COPY operation, if the destination exists, is under version michael@685: * control, and is the same resource type as the source, michael@685: @@ -4573,7 +4579,7 @@ michael@685: * be more destructive than the user intended. */ michael@685: if (r->parsed_uri.fragment != NULL) { michael@685: ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, michael@685: - "buggy client used un-escaped hash in Request-URI"); michael@685: + "buggy client used un-escaped hash in Request-URI uri is '%s'",r->uri); michael@685: return dav_error_response(r, HTTP_BAD_REQUEST, michael@685: "The request was invalid: the URI included " michael@685: "an un-escaped hash character"); michael@685: Index: modules/dav/main/util.c michael@685: diff -Nau modules/dav/main/util.c.orig modules/dav/main/util.c michael@685: --- modules/dav/main/util.c.orig 2010-07-21 20:25:49.000000000 +0200 michael@685: +++ modules/dav/main/util.c 2012-09-17 14:16:06.945216500 +0200 michael@685: @@ -168,6 +168,8 @@ michael@685: apr_port_t port; michael@685: apr_uri_t comp; michael@685: char *new_file; michael@685: + const char *new_filename; michael@685: + char *redirect; michael@685: const char *domain; michael@685: michael@685: /* first thing to do is parse the URI into various components */ michael@685: @@ -278,7 +280,13 @@ michael@685: * to apply appropriate restrictions (e.g. readonly). michael@685: */ michael@685: result.rnew = ap_sub_req_method_uri(r->method, new_file, r, NULL); michael@685: - michael@685: + //detect redirect michael@685: + new_filename=apr_pstrdup(r->pool, result.rnew->filename); michael@685: + redirect=ap_getword(r->pool, &new_filename, ':'); michael@685: + //ap_unescape_url(new_filename); michael@685: + if(!strcasecmp(redirect, "redirect")) {//subrequest for resolve redirect michael@685: + result.rnew = ap_sub_req_method_uri(r->method, new_filename, r, NULL); michael@685: + } michael@685: return result; michael@685: } michael@685: michael@685: @@ -1420,11 +1428,11 @@ michael@685: michael@685: retVal = ap_meets_conditions(r); michael@685: michael@685: - /* If-None-Match '*' fix. If-None-Match '*' request should succeed michael@685: + /* If-None-Match '*' fix. If-None-Match '*' request should succeed michael@685: * if the resource does not exist. */ michael@685: if (retVal == HTTP_PRECONDITION_FAILED) { michael@685: /* Note. If if_none_match != NULL, if_none_match is the culprit. michael@685: - * Since, in presence of If-None-Match, michael@685: + * Since, in presence of If-None-Match, michael@685: * other If-* headers are undefined. */ michael@685: if ((if_none_match = michael@685: apr_table_get(r->headers_in, "If-None-Match")) != NULL) { michael@685: Index: modules/mappers/mod_rewrite.c michael@685: diff -Nau modules/mappers/mod_rewrite.c.orig modules/mappers/mod_rewrite.c michael@685: --- modules/mappers/mod_rewrite.c.orig 2012-01-24 20:39:31.000000000 +0100 michael@685: +++ modules/mappers/mod_rewrite.c 2012-09-17 14:16:06.947134500 +0200 michael@685: @@ -2286,7 +2286,7 @@ michael@685: current->len = span; michael@685: current->string = bri->source + bri->regmatch[n].rm_so; michael@685: } michael@685: - michael@685: + michael@685: outlen += span; michael@685: } michael@685: michael@685: @@ -3250,7 +3250,7 @@ michael@685: case 'B': michael@685: if (!*key || !strcasecmp(key, "ackrefescaping")) { michael@685: cfg->flags |= RULEFLAG_ESCAPEBACKREF; michael@685: - } michael@685: + } michael@685: else { michael@685: ++error; michael@685: } michael@685: @@ -4026,6 +4026,7 @@ michael@685: if (r->main != NULL && michael@685: (p->flags & RULEFLAG_IGNOREONSUBREQ || michael@685: p->flags & RULEFLAG_FORCEREDIRECT )) { michael@685: +ap_log_error(APLOG_MARK, APLOG_ERR, 0, NULL,"Ignore this rule on subrequests"); michael@685: continue; michael@685: } michael@685: