#patch -p2 < [this file] see http://www.geocities.jp/t_sat7/webdav/webdav.html satake@goodcrew.ne.jp English page at http://www.needful.de/docs/projekte/webdav-quota/ Thanks to Mr.Marco Gobenich --- work/httpd-2.2.3/modules/dav/main/mod_dav.c 2006-07-12 12:38:44.000000000 +0900 +++ work/httpd-2.2.3-new/modules/dav/main/mod_dav.c 2010-11-11 10:01:40.000000000 +0900 @@ -58,6 +58,7 @@ #include "util_script.h" #include "mod_dav.h" +#include "quotachk.h" // add by satake@goodcrew.ne.jp /* ### what is the best way to set this? */ @@ -79,6 +80,8 @@ const char *dir; int locktimeout; int allow_depthinfinity; + apr_off_t area_size; // add by satake@goodcrew.ne.jp + const char *area_path; // add by satake@goodcrew.ne.jp } dav_dir_conf; @@ -163,6 +166,8 @@ conf->dir = d; } + conf->area_path = NULL; // add by satake@goodcrew.ne.jp + return conf; } @@ -195,6 +200,9 @@ newconf->dir = DAV_INHERIT_VALUE(parent, child, dir); newconf->allow_depthinfinity = DAV_INHERIT_VALUE(parent, child, allow_depthinfinity); + /* add by satake@goodcrew.ne.jp */ + newconf->area_size = DAV_INHERIT_VALUE( parent , child , area_size ); + newconf->area_path = DAV_INHERIT_VALUE( parent , child , area_path ); return newconf; } @@ -212,6 +220,22 @@ return conf->provider; } +/** add by satake@goodcrew.ne.jp */ +const apr_off_t dav_get_area_size( request_rec *r ) { + + dav_dir_conf *conf = ap_get_module_config( r->per_dir_config , &dav_module ); + return conf->area_size; + +} + +/** add by satake@goodcrew.ne.jp */ +const char *dav_get_dir( request_rec *r ) { + + dav_dir_conf *conf = ap_get_module_config( r->per_dir_config , &dav_module ); + return conf->area_path; + +} + DAV_DECLARE(const dav_hooks_locks *) dav_get_lock_hooks(request_rec *r) { return dav_get_provider(r)->locks; @@ -302,6 +326,23 @@ } /* + * Command handler for DAVSATMaxAreaSize directive, which is TAKE1 + * add by satake@goodcrew.ne.jp + */ +static const char *dav_cmd_davareasize( cmd_parms *cmd , void *config , const char *arg1 ) { + + dav_dir_conf *conf = ( dav_dir_conf * )config; + + conf->area_size = ( apr_off_t )atoll( arg1 ); + if ( conf->area_size < 0 ) + return "DAVSATMaxAreaSize requires a non-negative number."; + + conf->area_path = cmd->path; + return NULL; + +} + +/* ** dav_error_response() ** ** Send a nice response back to the user. In most cases, Apache doesn't @@ -939,6 +980,15 @@ return dav_handle_err(r, err, multi_response); } +/** + check for disk space is enough + add by satake@goodcrew.ne.jp +*/ + if ( dav_qchk_checksize( r )==DAV_QCHK_NG ) + return dav_error_response(r, HTTP_INSUFFICIENT_STORAGE, + "There is not enough storage to write to " + "this resource."); + /* make sure the resource can be modified (if versioning repository) */ if ((err = dav_auto_checkout(r, resource, 0 /* not parent_only */, @@ -2494,6 +2544,15 @@ return dav_handle_err(r, err, NULL); } +/** + check for disk space is enough + add by satake@goodcrew.ne.jp +*/ + if ( dav_qchk_checksize( r )==DAV_QCHK_NG ) + return dav_error_response(r, HTTP_INSUFFICIENT_STORAGE, + "There is not enough storage to write to " + "this resource."); + /* try to create the collection */ resource->collection = 1; err = (*resource->hooks->create_collection)(resource); @@ -2779,6 +2838,15 @@ return result; } +/** + check for disk space is enough + add by satake@goodcrew.ne.jp +*/ + if ( dav_qchk_checksize( r )==DAV_QCHK_NG ) + return dav_error_response(r, HTTP_INSUFFICIENT_STORAGE, + "There is not enough storage to write to " + "this resource."); + if ((err = dav_open_lockdb(r, 0, &lockdb)) != NULL) { /* ### add a higher-level description? */ return dav_handle_err(r, err, NULL); @@ -4803,7 +4871,7 @@ static const command_rec dav_cmds[] = { /* per directory/location */ - AP_INIT_TAKE1("DAV", dav_cmd_dav, NULL, ACCESS_CONF, + AP_INIT_TAKE1("DAV", dav_cmd_dav, NULL, ACCESS_CONF|OR_ALL, "specify the DAV provider for a directory or location"), /* per directory/location, or per server */ @@ -4811,6 +4879,12 @@ ACCESS_CONF|RSRC_CONF, "specify minimum allowed timeout"), + /* per directory/location */ + /* add by satake@goodcrew.ne.jp */ + AP_INIT_TAKE1("DAVSATMaxAreaSize", dav_cmd_davareasize, NULL, + ACCESS_CONF|OR_ALL, + "max size of user storage area, per KByte"), + /* per directory/location, or per server */ AP_INIT_FLAG("DAVDepthInfinity", dav_cmd_davdepthinfinity, NULL, ACCESS_CONF|RSRC_CONF, --- work/httpd-2.2.3/modules/dav/main/quotachk.h 1970-01-01 09:00:00.000000000 +0900 +++ work/httpd-2.2.3-new/modules/dav/main/quotachk.h 2010-11-11 10:01:40.000000000 +0900 @@ -0,0 +1,15 @@ +/** + disk quota check modules for WebDAV service + author: satake@goodcrew.ne.jp +*/ +#define DAV_QCHK_OK 0 +#define DAV_QCHK_NG -1 + +/** set your storage cluster size */ +#ifndef DAV_CLUSTER_SIZE + #define DAV_CLUSTER_SIZE 4096 +#endif + +int dav_qchk_checksize( request_rec * ); +const apr_off_t dav_get_area_size( request_rec * ); +const char * dav_get_dir( request_rec * ); --- work/httpd-2.2.3/modules/dav/main/quotachk.c 1970-01-01 09:00:00.000000000 +0900 +++ work/httpd-2.2.3-new/modules/dav/main/quotachk.c 2010-11-11 10:01:40.000000000 +0900 @@ -0,0 +1,254 @@ +/** + disk quota check modules for WebDAV service + author: satake@goodcrew.ne.jp +*/ +#include "apr_lib.h" /* for apr_is* */ +#include "apr_tables.h" /* for apr_is* */ +#include "apr_file_info.h" +#include "apr_strings.h" +#include "httpd.h" +#include "http_log.h" + +#include +#include + +#include "mod_dav.h" +#include "quotachk.h" + +/** + get slash block number + @param dirname string + @return block number +*/ +static int getSlashBlockNum( const char *dirname ) { + + int retnum = 0; + while ( *dirname ) { + + if ( *dirname=='/' ) + retnum++; + + dirname++; + + } + return retnum; + +} + +/** + get real dirname + @param pool apr_pool_t + @param dirname extend dirname + @param filepath filepath + @return real dirname +*/ +static const char *dav_getreal_path( apr_pool_t *pool , const char *dirname , const char *filepath ) { + + if ( strstr( dirname , "*" )==NULL ) + return dirname; + + int blknum = getSlashBlockNum( dirname ); + char *retnum = apr_palloc( pool , strlen( filepath ) ); + *retnum = 0; + + char *moto = ( char * )filepath; + char *saki = retnum; + int bn = 0; + while ( *moto ) { + + *saki = *moto; + if ( *saki=='/' ) { + + bn++; + if ( bn==blknum ) { + + saki++; + break; + + } + + } + moto++; + saki++; + + } + *saki = 0; + + return retnum; + +} + +/** + get (dirname) total size ( per 512byte ) + @param dirname directory name + @return block size +*/ +static apr_off_t get_dir_size( const char *dirname , apr_pool_t *pool ) { + + DIR *dir; + struct dirent *ent; + struct stat status; + char *buffer; + apr_off_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 += ( ( apr_off_t )( status.st_size + status.st_blksize - 1 ) )/512; + 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_off_t dav_qchk_du( const char *dirname , apr_pool_t *pool ) { + + struct stat status; + apr_off_t size; + + if ( lstat( dirname , &status ) ) { + + return 0; + + } + size = ( ( apr_off_t )( status.st_size + status.st_blksize - 1 ) )/512; + return ( size + ( ( status.st_mode & S_IFDIR ) ? get_dir_size( dirname , pool ) : 0 ) ) / 2; + +} + +/** + check size + return 0: OK , else: NG +*/ +int dav_qchk_checksize( request_rec *request ) { + + long long int maxsize; + long long int nowsize; + long long int putsize; + int retnum; + const char *conlen; + const char *dirname; + dav_lookup_result res; + const char *dirnameex; + int errflag1; + + /** set default return */ + retnum = DAV_QCHK_OK; + + /** get max area size */ + if ( ! ( maxsize = dav_get_area_size( request ) ) ) { + + return retnum; + + } + + /** get directive's parameter */ + if ( ( dirname = dav_get_dir( request ) )==NULL ) { + + ap_log_error(APLOG_MARK, APLOG_NOTICE, 0, NULL, "WebDAV-Quota: Directory not detect" ); + return retnum; + + } + + /** if directive without DAVSATAreaPath, then no function */ + dirnameex = apr_pstrcat( request->pool , dirname , "*" , NULL ); + if ( ap_strcmp_match( request->filename , dirnameex )!=0 ) { + + /** try uri->filename convert */ + res = dav_lookup_uri( dirname , request , 0 ); + if ( ( res.err.status )||( res.rnew==NULL ) ) { + + if ( res.err.desc!=NULL ) + ap_log_error(APLOG_MARK, APLOG_NOTICE, 0, NULL, + apr_psprintf( request->pool , "WebDAV-Quota: [%d]: %s\n" , res.err.status, res.err.desc ) + ); + return retnum; + + } + + dirname = res.rnew->filename; + errflag1 = ( dirname==NULL ); + if ( !errflag1 ) { + + dirnameex = apr_pstrcat( request->pool , dirname , "*" , NULL ); + errflag1 = ( ap_strcmp_match( request->filename , dirnameex )!=0 ); + + } + if ( errflag1 ) { + ap_log_error(APLOG_MARK, APLOG_NOTICE, 0, NULL, + "WebDAV-Quota: Quota directory not match request file path." + ); + return retnum; + + } + + } + + dirname = dav_getreal_path( request->pool , dirname , request->filename ); + + /** get now user used size */ + nowsize = dav_qchk_du( dirname , request->pool ); + + /** get put size */ + conlen = NULL; + putsize = 0; + if ( request->headers_in != NULL ) { + + conlen = apr_table_get( request->headers_in , "content-length" ); + + } + if ( conlen!=NULL ) { + + putsize = ( ( atoll( conlen ) + DAV_CLUSTER_SIZE - 1 ) / 1024 ); + + } + + /** check size */ + retnum = ( nowsize + putsize >= maxsize ) ? DAV_QCHK_NG : DAV_QCHK_OK; + if ( retnum==DAV_QCHK_NG ) { + + ap_log_error(APLOG_MARK, APLOG_ERR, 0, NULL, + apr_psprintf( + request->pool , + "WebDAV-Quota: Directory `%s' size `%sKB' is over `%sKB'!" , + dirname , + apr_off_t_toa( request->pool , nowsize + putsize ) , + apr_off_t_toa( request->pool , maxsize ) + ) + ); + + } + return retnum; + +} --- work/httpd-2.2.3/modules/dav/main/config5.m4 2004-11-22 03:50:36.000000000 +0900 +++ work/httpd-2.2.3-new/modules/dav/main/config5.m4 2010-11-11 10:01:40.000000000 +0900 @@ -2,7 +2,7 @@ APACHE_MODPATH_INIT(dav/main) -dav_objects="mod_dav.lo props.lo util.lo util_lock.lo liveprop.lo providers.lo std_liveprop.lo" +dav_objects="mod_dav.lo props.lo util.lo util_lock.lo liveprop.lo providers.lo std_liveprop.lo quotachk.lo" if test "$enable_http" = "no"; then dav_enable=no --- work/httpd-2.2.3/configure 2006-07-28 02:34:51.000000000 +0900 +++ work/httpd-2.2.3-new/configure 2010-11-11 10:01:40.000000000 +0900 @@ -17258,7 +17258,7 @@ > $modpath_current/modules.mk -dav_objects="mod_dav.lo props.lo util.lo util_lock.lo liveprop.lo providers.lo std_liveprop.lo" +dav_objects="mod_dav.lo props.lo util.lo util_lock.lo liveprop.lo providers.lo std_liveprop.lo quotachk.lo" if test "$enable_http" = "no"; then dav_enable=no