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