|
1 Index: modules/dav/fs/mod_dav_fs.c |
|
2 diff -Nau modules/dav/fs/mod_dav_fs.c.orig modules/dav/fs/mod_dav_fs.c |
|
3 --- modules/dav/fs/mod_dav_fs.c.orig 2006-07-12 05:38:44.000000000 +0200 |
|
4 +++ modules/dav/fs/mod_dav_fs.c 2012-09-17 14:16:06.937987679 +0200 |
|
5 @@ -15,6 +15,7 @@ |
|
6 */ |
|
7 |
|
8 #include "httpd.h" |
|
9 +#include "http_log.h" |
|
10 #include "http_config.h" |
|
11 #include "apr_strings.h" |
|
12 |
|
13 @@ -24,9 +25,19 @@ |
|
14 /* per-server configuration */ |
|
15 typedef struct { |
|
16 const char *lockdb_path; |
|
17 + const char *diskusagedb_path; |
|
18 |
|
19 } dav_fs_server_conf; |
|
20 |
|
21 +/* per-dir configuration */ |
|
22 +typedef struct { |
|
23 + apr_size_t quota; |
|
24 + const char *area_path; |
|
25 + int hiddenfiles; |
|
26 + ap_regex_t *mask; |
|
27 + |
|
28 +} dav_fs_dir_conf; |
|
29 + |
|
30 extern module AP_MODULE_DECLARE_DATA dav_fs_module; |
|
31 |
|
32 const char *dav_get_lockdb_path(const request_rec *r) |
|
33 @@ -37,9 +48,20 @@ |
|
34 return conf->lockdb_path; |
|
35 } |
|
36 |
|
37 +const char *dav_get_diskusagedb_path(const request_rec *r) |
|
38 +{ |
|
39 + dav_fs_server_conf *conf; |
|
40 + |
|
41 + conf = ap_get_module_config(r->server->module_config, &dav_fs_module); |
|
42 + return conf->diskusagedb_path; |
|
43 +} |
|
44 + |
|
45 static void *dav_fs_create_server_config(apr_pool_t *p, server_rec *s) |
|
46 { |
|
47 - return apr_pcalloc(p, sizeof(dav_fs_server_conf)); |
|
48 + dav_fs_server_conf *conf; |
|
49 + conf = apr_pcalloc(p, sizeof(dav_fs_server_conf)); |
|
50 + conf->diskusagedb_path = NULL; |
|
51 + return conf; |
|
52 } |
|
53 |
|
54 static void *dav_fs_merge_server_config(apr_pool_t *p, |
|
55 @@ -53,6 +75,35 @@ |
|
56 |
|
57 newconf->lockdb_path = |
|
58 child->lockdb_path ? child->lockdb_path : parent->lockdb_path; |
|
59 + newconf->diskusagedb_path = |
|
60 + child->diskusagedb_path ? child->diskusagedb_path : parent->diskusagedb_path; |
|
61 + |
|
62 + return newconf; |
|
63 +} |
|
64 + |
|
65 +static void *dav_fs_create_dir_config(apr_pool_t *p, char *dir) |
|
66 +{ |
|
67 + dav_fs_dir_conf *conf=apr_pcalloc(p, sizeof(dav_fs_dir_conf)); |
|
68 + conf->area_path = NULL; |
|
69 + conf->mask = NULL; |
|
70 + conf->quota = 0; |
|
71 + conf->hiddenfiles = -1; |
|
72 + return conf; |
|
73 +} |
|
74 + |
|
75 +static void *dav_fs_merge_dir_config(apr_pool_t *p, |
|
76 + void *base, void *overrides) |
|
77 +{ |
|
78 + dav_fs_dir_conf *parent = base; |
|
79 + dav_fs_dir_conf *child = overrides; |
|
80 + dav_fs_dir_conf *newconf; |
|
81 + |
|
82 + newconf = apr_pcalloc(p, sizeof(*newconf)); |
|
83 + |
|
84 + newconf->quota = child->quota ? child->quota : parent->quota; |
|
85 + newconf->area_path = child->area_path ? child->area_path : parent->area_path; |
|
86 + newconf->hiddenfiles = child->hiddenfiles!=-1 ? child->hiddenfiles : parent->hiddenfiles; |
|
87 + newconf->mask = child->mask ? child->mask : parent->mask; |
|
88 |
|
89 return newconf; |
|
90 } |
|
91 @@ -76,12 +127,83 @@ |
|
92 return NULL; |
|
93 } |
|
94 |
|
95 +/* |
|
96 + * Command handler for the DAVLockDB directive, which is TAKE1 |
|
97 + */ |
|
98 +static const char *dav_fs_cmd_diskusagedb(cmd_parms *cmd, void *config, |
|
99 + const char *arg1) |
|
100 +{ |
|
101 + dav_fs_server_conf *conf; |
|
102 + conf = ap_get_module_config(cmd->server->module_config, |
|
103 + &dav_fs_module); |
|
104 + conf->diskusagedb_path = ap_server_root_relative(cmd->pool, arg1); |
|
105 + |
|
106 + if (!conf->diskusagedb_path) { |
|
107 + return apr_pstrcat(cmd->pool, "Invalid DAVDiskUsageDB path ", |
|
108 + arg1, NULL); |
|
109 + } |
|
110 + |
|
111 + return NULL; |
|
112 +} |
|
113 + |
|
114 +/* |
|
115 + * Command handler for the DAVFSQuota directive, which is TAKE1 |
|
116 + */ |
|
117 + |
|
118 +static const char *dav_fs_cmd_davareasize( cmd_parms *cmd , void *config , const char *arg1 ) { |
|
119 + |
|
120 + dav_fs_dir_conf *conf = ( dav_fs_dir_conf * )config; |
|
121 + |
|
122 + conf->quota = (apr_size_t)atoi( arg1 ); |
|
123 + if ( conf->quota < 0 ) |
|
124 + return "DAVFSQuota requires a nonnegative integer."; |
|
125 + |
|
126 + conf->area_path = cmd->path; |
|
127 + return NULL; |
|
128 + |
|
129 +} |
|
130 + |
|
131 +static const char *dav_fs_cmd_hidefiles( cmd_parms *cmd , void *config , const char *type , const char *arg1 ) { |
|
132 + |
|
133 + dav_fs_dir_conf *conf = ( dav_fs_dir_conf * )config; |
|
134 + |
|
135 +//ap_log_error(APLOG_MARK, APLOG_ERR, 0, NULL,"arg1 %s, type %s",arg1, type); |
|
136 + |
|
137 + if (!strcasecmp(type, "None")) |
|
138 + conf->hiddenfiles = DAV_FS_HIDE_NONE; |
|
139 + else if (!strcasecmp(type, "Hidden")) |
|
140 + conf->hiddenfiles = DAV_FS_HIDE_HIDDEN; |
|
141 + else if (!strcasecmp(type, "Deny")) |
|
142 + conf->hiddenfiles = DAV_FS_HIDE_DENY; |
|
143 + else if (!strcasecmp(type, "Htaccess")) |
|
144 + conf->hiddenfiles = DAV_FS_HIDE_HTACCESS; |
|
145 + else if (!strcasecmp(type, "Mask")) { |
|
146 + conf->hiddenfiles = DAV_FS_HIDE_MASK; |
|
147 + conf->mask = ap_pregcomp(cmd->pool, arg1, AP_REG_EXTENDED|AP_REG_ICASE); |
|
148 + if (!conf->mask) { |
|
149 + return apr_psprintf(cmd->pool, "Regex '%s' in DAVFSHideFiles Mask could not be compiled", arg1); |
|
150 + } |
|
151 + } else { |
|
152 + return "DAVFSHideFiles must be one of: " |
|
153 + "None | Hidden | Deny | Htaccess | Mask <regexp>"; |
|
154 + } |
|
155 + return NULL; |
|
156 +} |
|
157 + |
|
158 static const command_rec dav_fs_cmds[] = |
|
159 { |
|
160 /* per server */ |
|
161 AP_INIT_TAKE1("DAVLockDB", dav_fs_cmd_davlockdb, NULL, RSRC_CONF, |
|
162 "specify a lock database"), |
|
163 - |
|
164 + AP_INIT_TAKE1("DAVDiskUsageDB", dav_fs_cmd_diskusagedb, NULL, RSRC_CONF, |
|
165 + "specify a disk usage database"), |
|
166 + /* per directory/location */ |
|
167 + AP_INIT_TAKE1("DAVFSQuota", dav_fs_cmd_davareasize, NULL, |
|
168 + OR_LIMIT|ACCESS_CONF, |
|
169 + "max size of user storage area, per KByte"), |
|
170 + AP_INIT_TAKE12("DAVFSHideFiles", dav_fs_cmd_hidefiles, NULL, |
|
171 + OR_LIMIT|ACCESS_CONF, |
|
172 + "how files need for hide in collection: None | Hidden | Deny | Htaccess | Mask <regexp>"), |
|
173 { NULL } |
|
174 }; |
|
175 |
|
176 @@ -99,10 +221,38 @@ |
|
177 module AP_MODULE_DECLARE_DATA dav_fs_module = |
|
178 { |
|
179 STANDARD20_MODULE_STUFF, |
|
180 - NULL, /* dir config creater */ |
|
181 - NULL, /* dir merger --- default is to override */ |
|
182 + dav_fs_create_dir_config, /* dir config creater */ |
|
183 + dav_fs_merge_dir_config, /* dir merger --- default is to override */ |
|
184 dav_fs_create_server_config, /* server config */ |
|
185 dav_fs_merge_server_config, /* merge server config */ |
|
186 dav_fs_cmds, /* command table */ |
|
187 register_hooks, /* register hooks */ |
|
188 }; |
|
189 + |
|
190 +const apr_size_t dav_fs_get_quota( request_rec *r ) { |
|
191 + |
|
192 + dav_fs_dir_conf *conf = ap_get_module_config( r->per_dir_config , &dav_fs_module ); |
|
193 + return conf->quota; |
|
194 + |
|
195 +} |
|
196 + |
|
197 +const char *dav_fs_get_dir( request_rec *r ) { |
|
198 + |
|
199 + dav_fs_dir_conf *conf = ap_get_module_config( r->per_dir_config , &dav_fs_module ); |
|
200 + return conf->area_path; |
|
201 + |
|
202 +} |
|
203 + |
|
204 +const int dav_fs_get_hidefiles( request_rec *r ) { |
|
205 + |
|
206 + dav_fs_dir_conf *conf = ap_get_module_config( r->per_dir_config , &dav_fs_module ); |
|
207 + return conf->hiddenfiles; |
|
208 + |
|
209 +} |
|
210 + |
|
211 +const ap_regex_t *dav_fs_get_mask( request_rec *r ) { |
|
212 + |
|
213 + dav_fs_dir_conf *conf = ap_get_module_config( r->per_dir_config , &dav_fs_module ); |
|
214 + return conf->mask; |
|
215 + |
|
216 +} |
|
217 Index: modules/dav/fs/quota.h |
|
218 diff -Nau modules/dav/fs/quota.h.orig modules/dav/fs/quota.h |
|
219 --- modules/dav/fs/quota.h.orig 1970-01-01 01:00:00.000000000 +0100 |
|
220 +++ modules/dav/fs/quota.h 2012-09-17 14:16:06.938238230 +0200 |
|
221 @@ -0,0 +1,13 @@ |
|
222 +/** |
|
223 + disk quota check modules for WebDAV service |
|
224 + author: satake@goodcrew.ne.jp, changed by bjaka.max@gmail.com |
|
225 +*/ |
|
226 + |
|
227 +/** set your storage cluster size */ |
|
228 +#ifndef DAV_CLUSTER_SIZE |
|
229 + #define DAV_CLUSTER_SIZE 4096 |
|
230 +#endif |
|
231 + |
|
232 +static apr_size_t dav_qchk_du(const char *dirname, apr_pool_t *pool); |
|
233 +static apr_size_t dav_cached_du(char *dirname, const request_rec *r); |
|
234 +static apr_status_t dav_change_cached_du(const char *dirname, const request_rec *r, int add_size, apr_size_t delta); |
|
235 Index: modules/dav/fs/repos.c |
|
236 diff -Nau modules/dav/fs/repos.c.orig modules/dav/fs/repos.c |
|
237 --- modules/dav/fs/repos.c.orig 2011-09-08 17:59:38.000000000 +0200 |
|
238 +++ modules/dav/fs/repos.c 2012-09-17 14:18:07.509160501 +0200 |
|
239 @@ -27,6 +27,8 @@ |
|
240 #include <stdio.h> /* for sprintf() */ |
|
241 #endif |
|
242 |
|
243 +#include "util_filter.h" |
|
244 +#include "apr_sdbm.h" |
|
245 #include "httpd.h" |
|
246 #include "http_log.h" |
|
247 #include "http_protocol.h" /* for ap_set_* (in dav_fs_set_headers) */ |
|
248 @@ -34,6 +36,7 @@ |
|
249 |
|
250 #include "mod_dav.h" |
|
251 #include "repos.h" |
|
252 +#include "quota.h" |
|
253 |
|
254 |
|
255 /* to assist in debugging mod_dav's GET handling */ |
|
256 @@ -46,6 +49,10 @@ |
|
257 apr_pool_t *pool; /* memory storage pool associated with request */ |
|
258 const char *pathname; /* full pathname to resource */ |
|
259 apr_finfo_t finfo; /* filesystem info */ |
|
260 + request_rec *r; /* request of this resource*/ |
|
261 + apr_size_t quota; /* config data for quota check */ |
|
262 + const char *area_path; |
|
263 + int hiddenfiles; |
|
264 }; |
|
265 |
|
266 /* private context for doing a filesystem walk */ |
|
267 @@ -137,7 +144,12 @@ |
|
268 /* |
|
269 ** The single property that we define (in the DAV_FS_URI_MYPROPS namespace) |
|
270 */ |
|
271 -#define DAV_PROPID_FS_executable 1 |
|
272 +#define DAV_PROPID_FS_executable 1 |
|
273 +/* |
|
274 +**Quota property in DAV:namespace |
|
275 +*/ |
|
276 +#define DAV_PROPID_quota_available_bytes 2 |
|
277 +#define DAV_PROPID_quota_used_bytes 3 |
|
278 |
|
279 static const dav_liveprop_spec dav_fs_props[] = |
|
280 { |
|
281 @@ -166,8 +178,20 @@ |
|
282 DAV_PROPID_getlastmodified, |
|
283 0 |
|
284 }, |
|
285 - |
|
286 + { |
|
287 + DAV_FS_URI_DAV, |
|
288 + "quota-available-bytes", |
|
289 + DAV_PROPID_quota_available_bytes, |
|
290 + 0 |
|
291 + }, |
|
292 + { |
|
293 + DAV_FS_URI_DAV, |
|
294 + "quota-used-bytes", |
|
295 + DAV_PROPID_quota_used_bytes, |
|
296 + 0 |
|
297 + }, |
|
298 /* our custom properties */ |
|
299 + |
|
300 { |
|
301 DAV_FS_URI_MYPROPS, |
|
302 "executable", |
|
303 @@ -191,6 +215,9 @@ |
|
304 apr_pool_t *p; |
|
305 apr_file_t *f; |
|
306 const char *pathname; /* we may need to remove it at close time */ |
|
307 + apr_size_t quota; /* config data for quota check */ |
|
308 + const char *area_path; |
|
309 + request_rec *r; /* request of this resource*/ |
|
310 }; |
|
311 |
|
312 /* returns an appropriate HTTP status code given an APR status code for a |
|
313 @@ -641,6 +668,8 @@ |
|
314 dav_resource *resource; |
|
315 char *s; |
|
316 char *filename; |
|
317 + apr_size_t nowsize, putsize; |
|
318 + const char *conlen; |
|
319 apr_size_t len; |
|
320 |
|
321 /* ### optimize this into a single allocation! */ |
|
322 @@ -652,6 +681,37 @@ |
|
323 /* ### this should go away */ |
|
324 ctx->pool = r->pool; |
|
325 |
|
326 + ctx->r = r; |
|
327 + ctx->quota = dav_fs_get_quota(r); |
|
328 + ctx->area_path = dav_fs_get_dir(r); |
|
329 + |
|
330 + ctx->hiddenfiles = dav_fs_get_hidefiles(r); |
|
331 + |
|
332 +// ap_log_error(APLOG_MARK, APLOG_ERR, 0, NULL,"Pathname is %s, quota is %d",ctx->area_path,ctx->quota); |
|
333 + /** Check quota limit*/ |
|
334 + if (ctx->quota && r->method_number==M_PUT) { |
|
335 + |
|
336 + /** get now user used size */ |
|
337 + nowsize = dav_cached_du(ctx->area_path, r); |
|
338 + |
|
339 + /** get put size */ |
|
340 + conlen = NULL; |
|
341 + putsize = 0; |
|
342 + if ( r->headers_in!=NULL ) { |
|
343 + conlen = apr_table_get( r->headers_in , "content-length" ); |
|
344 + } |
|
345 + if ( conlen!=NULL ) { |
|
346 + putsize = ((atoi(conlen)+DAV_CLUSTER_SIZE-1)/DAV_CLUSTER_SIZE)*(DAV_CLUSTER_SIZE/1024); |
|
347 + } |
|
348 + |
|
349 + /** check size */ |
|
350 +// 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); |
|
351 + if ( nowsize+putsize>=ctx->quota ) { |
|
352 + return dav_new_error(r->pool, HTTP_INSUFFICIENT_STORAGE, 0, |
|
353 + apr_psprintf(r->pool,"WebDAV-Quota: Directory `%s' size %dKB+%dKB(%s) is over %dKB!",ctx->area_path, nowsize,putsize,conlen, ctx->quota)); |
|
354 + } |
|
355 + } |
|
356 + |
|
357 /* Preserve case on OSes which fold canonical filenames */ |
|
358 #if 0 |
|
359 /* ### not available in Apache 2.0 yet */ |
|
360 @@ -865,6 +925,12 @@ |
|
361 |
|
362 ds->p = p; |
|
363 ds->pathname = resource->info->pathname; |
|
364 + |
|
365 + ds->quota=resource->info->quota; |
|
366 + ds->area_path=resource->info->area_path; |
|
367 + |
|
368 + ds->r = resource->info->r; |
|
369 + |
|
370 rv = apr_file_open(&ds->f, ds->pathname, flags, APR_OS_DEFAULT, ds->p); |
|
371 if (rv != APR_SUCCESS) { |
|
372 return dav_new_error(p, MAP_IO2HTTP(rv), 0, |
|
373 @@ -889,6 +955,23 @@ |
|
374 "back) the resource " |
|
375 "when it was being closed."); |
|
376 } |
|
377 + } else { |
|
378 + |
|
379 + if(stream->area_path && stream->r->method_number==M_PUT) { |
|
380 + const char *conlen = NULL; |
|
381 + apr_size_t putsize = 0; |
|
382 + /** get put size */ |
|
383 + |
|
384 + if ( stream->r->headers_in!=NULL ) { |
|
385 + conlen = apr_table_get( stream->r->headers_in , "content-length" ); |
|
386 + } |
|
387 + if ( conlen!=NULL ) { |
|
388 + putsize = ((atoi(conlen)+DAV_CLUSTER_SIZE-1)/DAV_CLUSTER_SIZE)*(DAV_CLUSTER_SIZE/1024); |
|
389 + } |
|
390 + |
|
391 + dav_change_cached_du(stream->area_path, stream->r, 1, putsize); |
|
392 + } |
|
393 + |
|
394 } |
|
395 |
|
396 return NULL; |
|
397 @@ -926,8 +1009,145 @@ |
|
398 } |
|
399 return NULL; |
|
400 } |
|
401 +/** |
|
402 + get (dirname) total size ( per 512byte ) |
|
403 + @param dirname directory name |
|
404 + @return block size |
|
405 +*/ |
|
406 +static apr_size_t get_dir_size(const char *dirname, apr_pool_t *pool) { |
|
407 + |
|
408 + DIR *dir; |
|
409 + struct dirent *ent; |
|
410 + struct stat status; |
|
411 + char *buffer; |
|
412 + apr_size_t size = 0; |
|
413 + |
|
414 + dir = opendir(dirname); |
|
415 + if ( dir==NULL ) { |
|
416 + return 0; |
|
417 + } |
|
418 + |
|
419 + while ( (ent = readdir(dir))!=NULL ) { |
|
420 + if ( (!strcmp(ent->d_name, ".")) || (!strcmp(ent->d_name, "..")) ) { |
|
421 + continue; |
|
422 + } |
|
423 + |
|
424 + apr_filepath_merge(&buffer, dirname, ent->d_name, 0, pool); |
|
425 + |
|
426 + if ( !lstat(buffer, &status) ) { |
|
427 + size += status.st_blocks; |
|
428 + if ( status.st_mode & S_IFDIR ) { |
|
429 + size += get_dir_size(buffer, pool); |
|
430 + } |
|
431 + } |
|
432 + } |
|
433 + closedir(dir); |
|
434 + return size; |
|
435 +} |
|
436 |
|
437 +/** |
|
438 + return directory total disk space. |
|
439 + same as 'du -sk dirname' command. |
|
440 + @param dirname directory |
|
441 + @return total space |
|
442 +*/ |
|
443 +static apr_size_t dav_qchk_du(const char *dirname, apr_pool_t *pool) { |
|
444 + struct stat status; |
|
445 |
|
446 + if ( lstat(dirname, &status) ) { |
|
447 + return 0; |
|
448 + } |
|
449 + return (status.st_blocks+((status.st_mode & S_IFDIR)?get_dir_size(dirname, pool):0))/2; |
|
450 +} |
|
451 + |
|
452 +static apr_sdbm_datum_t dav_cached_du_prepare_key(const char *dirname, apr_pool_t *pool) { |
|
453 + apr_sdbm_datum_t key; |
|
454 + key.dsize = strlen(dirname)+1; |
|
455 + key.dptr = apr_palloc(pool, key.dsize); |
|
456 + memcpy(key.dptr, dirname, key.dsize); |
|
457 + if (key.dptr[key.dsize - 2] == '/') |
|
458 + key.dptr[--key.dsize - 1] = '\0'; |
|
459 + return key; |
|
460 +} |
|
461 + |
|
462 +static apr_size_t dav_cached_du(char *dirname, const request_rec *r) { |
|
463 + const char *pathname = dav_get_diskusagedb_path(r); |
|
464 + apr_status_t status; |
|
465 + apr_sdbm_t *db; |
|
466 + apr_sdbm_datum_t val = { 0 }; |
|
467 + apr_size_t size; |
|
468 + apr_sdbm_datum_t key; |
|
469 + if (dirname[strlen(dirname)-1] == '/') |
|
470 + dirname[strlen(dirname)-1] = '\0'; |
|
471 + |
|
472 + if(!pathname) |
|
473 + return dav_qchk_du(dirname, r->pool); |
|
474 + |
|
475 + key=dav_cached_du_prepare_key(dirname, r->pool); |
|
476 + |
|
477 + if ((status = apr_sdbm_open(&db, pathname, APR_WRITE | APR_CREATE, |
|
478 + APR_OS_DEFAULT, r->pool))!= APR_SUCCESS) { |
|
479 + ap_log_error(APLOG_MARK, APLOG_ERR, 0, NULL,"Error accessing to '%s' Disk Usage db file.", pathname); |
|
480 + return dav_qchk_du(dirname, r->pool); |
|
481 + } |
|
482 + |
|
483 + apr_sdbm_fetch(db, &val, key); |
|
484 + if(val.dptr) { |
|
485 + size = atoi(val.dptr); |
|
486 + } else { |
|
487 + size=dav_qchk_du(dirname, r->pool); |
|
488 + val.dptr = apr_psprintf(r->pool,"%" APR_OFF_T_FMT, size); |
|
489 + val.dsize = strlen(val.dptr); |
|
490 + apr_sdbm_store(db, key, val, APR_SDBM_REPLACE); |
|
491 + } |
|
492 + |
|
493 + apr_sdbm_close(db); |
|
494 + return size; |
|
495 +} |
|
496 + |
|
497 +static apr_status_t dav_change_cached_du(const char *dirname, const request_rec *r, int add_size, apr_size_t delta) { |
|
498 + const char *pathname = dav_get_diskusagedb_path(r); |
|
499 + apr_status_t status; |
|
500 + apr_sdbm_t *db; |
|
501 + apr_sdbm_datum_t val = { 0 }; |
|
502 + apr_size_t size; |
|
503 + apr_sdbm_datum_t key; |
|
504 + |
|
505 + if(!pathname) |
|
506 + return APR_SUCCESS; |
|
507 + |
|
508 + key=dav_cached_du_prepare_key(dirname, r->pool); |
|
509 + |
|
510 + if ((status = apr_sdbm_open(&db, pathname, APR_WRITE | APR_CREATE | APR_SHARELOCK, |
|
511 + APR_OS_DEFAULT, r->pool))!= APR_SUCCESS) { |
|
512 + return status; |
|
513 + } |
|
514 + |
|
515 + apr_sdbm_fetch(db, &val, key); |
|
516 + |
|
517 + if(val.dptr) { |
|
518 + apr_sdbm_lock(db, APR_FLOCK_EXCLUSIVE); |
|
519 + apr_sdbm_fetch(db, &val, key); |
|
520 + size = atoi(val.dptr); |
|
521 + if(add_size) { |
|
522 + size += delta; |
|
523 + } else { |
|
524 + size -= delta; |
|
525 + } |
|
526 + val.dptr = apr_psprintf(r->pool,"%" APR_OFF_T_FMT, size); |
|
527 + val.dsize = strlen(val.dptr); |
|
528 + apr_sdbm_store(db, key, val, APR_SDBM_REPLACE); |
|
529 + apr_sdbm_unlock(db); |
|
530 + } else { |
|
531 + size=dav_qchk_du(dirname, r->pool); |
|
532 + val.dptr = apr_psprintf(r->pool,"%" APR_OFF_T_FMT, size); |
|
533 + val.dsize = strlen(val.dptr); |
|
534 + apr_sdbm_store(db, key, val, APR_SDBM_REPLACE); |
|
535 + } |
|
536 + |
|
537 + apr_sdbm_close(db); |
|
538 + return APR_SUCCESS; |
|
539 +} |
|
540 #if DEBUG_GET_HANDLER |
|
541 |
|
542 /* only define set_headers() and deliver() for debug purposes */ |
|
543 @@ -1355,6 +1575,8 @@ |
|
544 dav_response **response) |
|
545 { |
|
546 dav_resource_private *info = resource->info; |
|
547 + struct stat status; |
|
548 + apr_size_t putsize = 0; |
|
549 |
|
550 *response = NULL; |
|
551 |
|
552 @@ -1394,6 +1616,10 @@ |
|
553 } |
|
554 |
|
555 /* not a collection; remove the file and its properties */ |
|
556 + if (info->area_path && !lstat(info->pathname, &status) ) { |
|
557 + putsize = status.st_blocks/2; |
|
558 + dav_change_cached_du(info->area_path, info->r, 0, putsize); |
|
559 + } |
|
560 if (apr_file_remove(info->pathname, info->pool) != APR_SUCCESS) { |
|
561 /* ### put a description in here */ |
|
562 return dav_new_error(info->pool, HTTP_FORBIDDEN, 0, NULL); |
|
563 @@ -1418,7 +1644,12 @@ |
|
564 int isdir = fsctx->res1.collection; |
|
565 apr_finfo_t dirent; |
|
566 apr_dir_t *dirp; |
|
567 + char *dirname; |
|
568 + const ap_regex_t *mask; |
|
569 |
|
570 + if(fsctx->info1.hiddenfiles==DAV_FS_HIDE_MASK) { |
|
571 + mask=dav_fs_get_mask(fsctx->info1.r); |
|
572 + } |
|
573 /* ensure the context is prepared properly, then call the func */ |
|
574 err = (*params->func)(&fsctx->wres, |
|
575 isdir |
|
576 @@ -1455,13 +1686,16 @@ |
|
577 fsctx->res2.collection = 0; |
|
578 |
|
579 /* open and scan the directory */ |
|
580 + dirname=apr_pstrdup(pool, fsctx->path1.buf); |
|
581 if ((apr_dir_open(&dirp, fsctx->path1.buf, pool)) != APR_SUCCESS) { |
|
582 /* ### need a better error */ |
|
583 return dav_new_error(pool, HTTP_NOT_FOUND, 0, NULL); |
|
584 } |
|
585 - while ((apr_dir_read(&dirent, APR_FINFO_DIRENT, dirp)) == APR_SUCCESS) { |
|
586 + while ((apr_dir_read(&dirent, APR_FINFO_DIRENT | APR_FINFO_NORM, dirp)) == APR_SUCCESS) { |
|
587 apr_size_t len; |
|
588 apr_status_t status; |
|
589 + apr_finfo_t finfo; |
|
590 + apr_status_t rv; |
|
591 |
|
592 len = strlen(dirent.name); |
|
593 |
|
594 @@ -1479,6 +1713,37 @@ |
|
595 if (!strcmp(dirent.name, DAV_FS_STATE_DIR)) { |
|
596 continue; |
|
597 } |
|
598 + //ap_log_error(APLOG_MARK, APLOG_ERR, 0, NULL,"Hiddenfiles %i",fsctx->info1.hiddenfiles); |
|
599 + if(fsctx->info1.hiddenfiles && fsctx->info1.hiddenfiles!=-1) { |
|
600 + if(fsctx->info1.hiddenfiles==DAV_FS_HIDE_HIDDEN) { |
|
601 + if(dirent.name[0]=='.') { |
|
602 + continue; |
|
603 + } |
|
604 + } else if(fsctx->info1.hiddenfiles==DAV_FS_HIDE_DENY) { |
|
605 + request_rec *rr; |
|
606 + const char *fullname = apr_pstrcat(pool, dirname, dirent.name, NULL); |
|
607 + if (!(rr = ap_sub_req_lookup_file(ap_os_escape_path(pool,fullname,1), fsctx->info1.r, NULL))) { |
|
608 + //ap_log_error(APLOG_MARK, APLOG_ERR, 0, NULL,"Path %s, filename %s, fullname %s, return false", dirname, dirent.name, fullname); |
|
609 + continue; |
|
610 + } |
|
611 + if (rr->status >= 400) { |
|
612 + //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); |
|
613 + ap_destroy_sub_req(rr); |
|
614 + continue; |
|
615 + } |
|
616 + //ap_log_error(APLOG_MARK, APLOG_ERR, 0, NULL,"dirname %s, subrequest filename %s",dirname, rr->filename); |
|
617 + ap_destroy_sub_req(rr); |
|
618 + } else if(fsctx->info1.hiddenfiles==DAV_FS_HIDE_HTACCESS) { |
|
619 + if(!strcmp(dirent.name, ".htaccess")) { |
|
620 + continue; |
|
621 + } |
|
622 + } else if(fsctx->info1.hiddenfiles==DAV_FS_HIDE_MASK) { |
|
623 + if(!ap_regexec(mask, dirent.name, 0, NULL, 0)) { |
|
624 + //ap_log_error(APLOG_MARK, APLOG_ERR, 0, NULL,"hide %s",dirent.name); |
|
625 + continue; |
|
626 + } |
|
627 + } |
|
628 + } |
|
629 } |
|
630 /* skip the state dir unless a HIDDEN is performed */ |
|
631 if (!(params->walk_type & DAV_WALKTYPE_HIDDEN) |
|
632 @@ -1489,14 +1754,8 @@ |
|
633 /* append this file onto the path buffer (copy null term) */ |
|
634 dav_buffer_place_mem(pool, &fsctx->path1, dirent.name, len + 1, 0); |
|
635 |
|
636 - status = apr_stat(&fsctx->info1.finfo, fsctx->path1.buf, |
|
637 - DAV_FINFO_MASK, pool); |
|
638 - if (status != APR_SUCCESS && status != APR_INCOMPLETE) { |
|
639 - /* woah! where'd it go? */ |
|
640 - /* ### should have a better error here */ |
|
641 - err = dav_new_error(pool, HTTP_NOT_FOUND, 0, NULL); |
|
642 - break; |
|
643 - } |
|
644 + //set the finfo for further process |
|
645 + fsctx->info1.finfo=dirent; |
|
646 |
|
647 /* copy the file to the URI, too. NOTE: we will pad an extra byte |
|
648 for the trailing slash later. */ |
|
649 @@ -1512,10 +1771,11 @@ |
|
650 fsctx->info2.pathname = fsctx->path2.buf; |
|
651 |
|
652 /* set up the URI for the current resource */ |
|
653 + //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); |
|
654 fsctx->res1.uri = fsctx->uri_buf.buf; |
|
655 |
|
656 /* ### for now, only process regular files (e.g. skip symlinks) */ |
|
657 - if (fsctx->info1.finfo.filetype == APR_REG) { |
|
658 + if (dirent.filetype == APR_REG) { |
|
659 /* call the function for the specified dir + file */ |
|
660 if ((err = (*params->func)(&fsctx->wres, |
|
661 DAV_CALLTYPE_MEMBER)) != NULL) { |
|
662 @@ -1523,7 +1783,7 @@ |
|
663 break; |
|
664 } |
|
665 } |
|
666 - else if (fsctx->info1.finfo.filetype == APR_DIR) { |
|
667 + else if (dirent.filetype == APR_DIR) { |
|
668 apr_size_t save_path_len = fsctx->path1.cur_len; |
|
669 apr_size_t save_uri_len = fsctx->uri_buf.cur_len; |
|
670 apr_size_t save_path2_len = fsctx->path2.cur_len; |
|
671 @@ -1690,6 +1950,7 @@ |
|
672 dav_fs_walker_context fsctx = { 0 }; |
|
673 dav_error *err; |
|
674 dav_fs_copymove_walk_ctx cm_ctx = { 0 }; |
|
675 + const char *uri,*request=params->root->info->r->the_request; |
|
676 |
|
677 #if DAV_DEBUG |
|
678 if ((params->walk_type & DAV_WALKTYPE_LOCKNULL) != 0 |
|
679 @@ -1743,7 +2004,11 @@ |
|
680 } |
|
681 |
|
682 /* prep the URI buffer */ |
|
683 - dav_buffer_init(params->pool, &fsctx.uri_buf, params->root->uri); |
|
684 + |
|
685 + uri = ap_getword(params->pool, &request, ' '); //get method |
|
686 + uri = ap_getword(params->pool, &request, ' '); //get uri |
|
687 + ap_unescape_url(uri); |
|
688 + dav_buffer_init(params->pool, &fsctx.uri_buf, uri); |
|
689 |
|
690 /* if we have a directory, then ensure the URI has a trailing "/" */ |
|
691 if (fsctx.res1.collection |
|
692 @@ -1844,8 +2109,11 @@ |
|
693 ** client cannot store dead values -- we deny that thru the is_writable |
|
694 ** hook function. |
|
695 */ |
|
696 - if (!resource->exists) |
|
697 + if (!resource->exists) { |
|
698 +//ap_log_error(APLOG_MARK, APLOG_ERR, 0, NULL,"resource not exist"); |
|
699 + |
|
700 return DAV_PROP_INSERT_NOTDEF; |
|
701 +} |
|
702 |
|
703 switch (propid) { |
|
704 case DAV_PROPID_creationdate: |
|
705 @@ -1896,15 +2164,29 @@ |
|
706 value = "F"; |
|
707 break; |
|
708 |
|
709 + case DAV_PROPID_quota_available_bytes: |
|
710 + /* Property defined only for collection with quota */ |
|
711 + if (!resource->info->quota || !resource->collection) |
|
712 + return DAV_PROP_INSERT_NOTDEF; |
|
713 + value = apr_psprintf(p, "%d", (resource->info->quota-dav_cached_du(resource->info->area_path, resource->info->r))*1024); |
|
714 + break; |
|
715 + |
|
716 + case DAV_PROPID_quota_used_bytes: |
|
717 + /* Property defined only for collection with quota */ |
|
718 + if (!resource->info->quota || !resource->collection) |
|
719 + return DAV_PROP_INSERT_NOTDEF; |
|
720 + value = apr_psprintf(p, "%d", dav_cached_du(resource->info->area_path, resource->info->r)*1024); |
|
721 + break; |
|
722 + |
|
723 default: |
|
724 /* ### what the heck was this property? */ |
|
725 return DAV_PROP_INSERT_NOTDEF; |
|
726 } |
|
727 |
|
728 /* assert: value != NULL */ |
|
729 - |
|
730 /* get the information and global NS index for the property */ |
|
731 global_ns = dav_get_liveprop_info(propid, &dav_fs_liveprop_group, &info); |
|
732 +//ap_log_error(APLOG_MARK, APLOG_ERR, 0, NULL,"ns=%d name=%s value=%s",global_ns, info->name, value); |
|
733 |
|
734 /* assert: info != NULL && info->name != NULL */ |
|
735 |
|
736 @@ -2138,7 +2420,7 @@ |
|
737 */ |
|
738 return; |
|
739 } |
|
740 - |
|
741 +//ap_log_error(APLOG_MARK, APLOG_ERR, 0, NULL,"Try show all props"); |
|
742 (void) dav_fs_insert_prop(resource, DAV_PROPID_creationdate, |
|
743 what, phdr); |
|
744 (void) dav_fs_insert_prop(resource, DAV_PROPID_getcontentlength, |
|
745 @@ -2148,6 +2430,11 @@ |
|
746 (void) dav_fs_insert_prop(resource, DAV_PROPID_getetag, |
|
747 what, phdr); |
|
748 |
|
749 + (void) dav_fs_insert_prop(resource, DAV_PROPID_quota_available_bytes, |
|
750 + what, phdr); |
|
751 + (void) dav_fs_insert_prop(resource, DAV_PROPID_quota_used_bytes, |
|
752 + what, phdr); |
|
753 + |
|
754 #ifdef DAV_FS_HAS_EXECUTABLE |
|
755 /* Only insert this property if it is defined for this platform. */ |
|
756 (void) dav_fs_insert_prop(resource, DAV_PROPID_FS_executable, |
|
757 Index: modules/dav/fs/repos.h |
|
758 diff -Nau modules/dav/fs/repos.h.orig modules/dav/fs/repos.h |
|
759 --- modules/dav/fs/repos.h.orig 2006-07-12 05:38:44.000000000 +0200 |
|
760 +++ modules/dav/fs/repos.h 2012-09-17 14:16:06.941582156 +0200 |
|
761 @@ -30,6 +30,12 @@ |
|
762 #define DAV_FS_STATE_FILE_FOR_DIR ".state_for_dir" |
|
763 #define DAV_FS_LOCK_NULL_FILE ".locknull" |
|
764 |
|
765 +#define DAV_FS_HIDE_NONE 0 |
|
766 +#define DAV_FS_HIDE_HIDDEN 1 |
|
767 +#define DAV_FS_HIDE_DENY 2 |
|
768 +#define DAV_FS_HIDE_HTACCESS 3 |
|
769 +#define DAV_FS_HIDE_MASK 4 |
|
770 + |
|
771 |
|
772 /* ensure that our state subdirectory is present */ |
|
773 void dav_fs_ensure_state_dir(apr_pool_t *p, const char *dirname); |
|
774 @@ -67,6 +73,8 @@ |
|
775 /* where is the lock database located? */ |
|
776 const char *dav_get_lockdb_path(const request_rec *r); |
|
777 |
|
778 +const char *dav_get_diskusagedb_path(const request_rec *r); |
|
779 + |
|
780 const dav_hooks_locks *dav_fs_get_lock_hooks(request_rec *r); |
|
781 const dav_hooks_propdb *dav_fs_get_propdb_hooks(request_rec *r); |
|
782 |
|
783 @@ -79,6 +87,11 @@ |
|
784 |
|
785 void dav_fs_register(apr_pool_t *p); |
|
786 |
|
787 +const apr_size_t dav_fs_get_quota( request_rec *r ); |
|
788 +const char *dav_fs_get_dir( request_rec *r ); |
|
789 +const int dav_fs_get_hidefiles( request_rec *r ); |
|
790 +const ap_regex_t *dav_fs_get_mask( request_rec *r ); |
|
791 + |
|
792 #endif /* _DAV_FS_REPOS_H_ */ |
|
793 /** @} */ |
|
794 |
|
795 Index: modules/dav/main/mod_dav.c |
|
796 diff -Nau modules/dav/main/mod_dav.c.orig modules/dav/main/mod_dav.c |
|
797 --- modules/dav/main/mod_dav.c.orig 2011-02-09 09:43:17.000000000 +0100 |
|
798 +++ modules/dav/main/mod_dav.c 2012-09-17 14:16:06.944219747 +0200 |
|
799 @@ -884,7 +884,14 @@ |
|
800 |
|
801 return DECLINED; |
|
802 } |
|
803 - |
|
804 +struct dav_stream { |
|
805 + apr_pool_t *p; |
|
806 + apr_file_t *f; |
|
807 + const char *pathname; /* we may need to remove it at close time */ |
|
808 + apr_size_t quota; /* config data for quota check */ |
|
809 + const char *area_path; |
|
810 + request_rec *r; /* request of this resource*/ |
|
811 +}; |
|
812 /* handle the PUT method */ |
|
813 static int dav_method_put(request_rec *r) |
|
814 { |
|
815 @@ -958,7 +965,6 @@ |
|
816 else { |
|
817 mode = DAV_MODE_WRITE_TRUNC; |
|
818 } |
|
819 - |
|
820 /* make sure the resource can be modified (if versioning repository) */ |
|
821 if ((err = dav_auto_checkout(r, resource, |
|
822 0 /* not parent_only */, |
|
823 @@ -1043,6 +1049,7 @@ |
|
824 /* no error during the write, but we hit one at close. use it. */ |
|
825 err = err2; |
|
826 } |
|
827 + |
|
828 } |
|
829 |
|
830 /* |
|
831 @@ -2583,7 +2590,6 @@ |
|
832 dav_lockdb *lockdb; |
|
833 int replace_dest; |
|
834 int resnew_state; |
|
835 - |
|
836 /* Ask repository module to resolve the resource */ |
|
837 err = dav_get_resource(r, !is_move /* label_allowed */, |
|
838 0 /* use_checked_in */, &resource); |
|
839 @@ -2635,6 +2641,7 @@ |
|
840 |
|
841 return dav_error_response(r, lookup.err.status, lookup.err.desc); |
|
842 } |
|
843 + |
|
844 if (lookup.rnew->status != HTTP_OK) { |
|
845 const char *auth = apr_table_get(lookup.rnew->err_headers_out, |
|
846 "WWW-Authenticate"); |
|
847 @@ -2700,6 +2707,7 @@ |
|
848 if ((depth = dav_get_depth(r, DAV_INFINITY)) < 0) { |
|
849 /* dav_get_depth() supplies additional information for the |
|
850 * default message. */ |
|
851 + |
|
852 return HTTP_BAD_REQUEST; |
|
853 } |
|
854 if (depth == 1) { |
|
855 @@ -2817,7 +2825,6 @@ |
|
856 /* ### pass lockdb! */ |
|
857 (void)dav_unlock(r, resource, NULL); |
|
858 } |
|
859 - |
|
860 /* if this is a move, then the source parent collection will be modified */ |
|
861 if (is_move) { |
|
862 if ((err = dav_auto_checkout(r, resource, 1 /* parent_only */, |
|
863 @@ -2835,7 +2842,6 @@ |
|
864 * can be notified as to how it changed. |
|
865 */ |
|
866 resnew_state = dav_get_resource_state(lookup.rnew, resnew); |
|
867 - |
|
868 /* In a MOVE operation, the destination is replaced by the source. |
|
869 * In a COPY operation, if the destination exists, is under version |
|
870 * control, and is the same resource type as the source, |
|
871 @@ -4573,7 +4579,7 @@ |
|
872 * be more destructive than the user intended. */ |
|
873 if (r->parsed_uri.fragment != NULL) { |
|
874 ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, |
|
875 - "buggy client used un-escaped hash in Request-URI"); |
|
876 + "buggy client used un-escaped hash in Request-URI uri is '%s'",r->uri); |
|
877 return dav_error_response(r, HTTP_BAD_REQUEST, |
|
878 "The request was invalid: the URI included " |
|
879 "an un-escaped hash character"); |
|
880 Index: modules/dav/main/util.c |
|
881 diff -Nau modules/dav/main/util.c.orig modules/dav/main/util.c |
|
882 --- modules/dav/main/util.c.orig 2010-07-21 20:25:49.000000000 +0200 |
|
883 +++ modules/dav/main/util.c 2012-09-17 14:16:06.945216500 +0200 |
|
884 @@ -168,6 +168,8 @@ |
|
885 apr_port_t port; |
|
886 apr_uri_t comp; |
|
887 char *new_file; |
|
888 + const char *new_filename; |
|
889 + char *redirect; |
|
890 const char *domain; |
|
891 |
|
892 /* first thing to do is parse the URI into various components */ |
|
893 @@ -278,7 +280,13 @@ |
|
894 * to apply appropriate restrictions (e.g. readonly). |
|
895 */ |
|
896 result.rnew = ap_sub_req_method_uri(r->method, new_file, r, NULL); |
|
897 - |
|
898 + //detect redirect |
|
899 + new_filename=apr_pstrdup(r->pool, result.rnew->filename); |
|
900 + redirect=ap_getword(r->pool, &new_filename, ':'); |
|
901 + //ap_unescape_url(new_filename); |
|
902 + if(!strcasecmp(redirect, "redirect")) {//subrequest for resolve redirect |
|
903 + result.rnew = ap_sub_req_method_uri(r->method, new_filename, r, NULL); |
|
904 + } |
|
905 return result; |
|
906 } |
|
907 |
|
908 @@ -1420,11 +1428,11 @@ |
|
909 |
|
910 retVal = ap_meets_conditions(r); |
|
911 |
|
912 - /* If-None-Match '*' fix. If-None-Match '*' request should succeed |
|
913 + /* If-None-Match '*' fix. If-None-Match '*' request should succeed |
|
914 * if the resource does not exist. */ |
|
915 if (retVal == HTTP_PRECONDITION_FAILED) { |
|
916 /* Note. If if_none_match != NULL, if_none_match is the culprit. |
|
917 - * Since, in presence of If-None-Match, |
|
918 + * Since, in presence of If-None-Match, |
|
919 * other If-* headers are undefined. */ |
|
920 if ((if_none_match = |
|
921 apr_table_get(r->headers_in, "If-None-Match")) != NULL) { |
|
922 Index: modules/mappers/mod_rewrite.c |
|
923 diff -Nau modules/mappers/mod_rewrite.c.orig modules/mappers/mod_rewrite.c |
|
924 --- modules/mappers/mod_rewrite.c.orig 2012-01-24 20:39:31.000000000 +0100 |
|
925 +++ modules/mappers/mod_rewrite.c 2012-09-17 14:16:06.947134500 +0200 |
|
926 @@ -2286,7 +2286,7 @@ |
|
927 current->len = span; |
|
928 current->string = bri->source + bri->regmatch[n].rm_so; |
|
929 } |
|
930 - |
|
931 + |
|
932 outlen += span; |
|
933 } |
|
934 |
|
935 @@ -3250,7 +3250,7 @@ |
|
936 case 'B': |
|
937 if (!*key || !strcasecmp(key, "ackrefescaping")) { |
|
938 cfg->flags |= RULEFLAG_ESCAPEBACKREF; |
|
939 - } |
|
940 + } |
|
941 else { |
|
942 ++error; |
|
943 } |
|
944 @@ -4026,6 +4026,7 @@ |
|
945 if (r->main != NULL && |
|
946 (p->flags & RULEFLAG_IGNOREONSUBREQ || |
|
947 p->flags & RULEFLAG_FORCEREDIRECT )) { |
|
948 +ap_log_error(APLOG_MARK, APLOG_ERR, 0, NULL,"Ignore this rule on subrequests"); |
|
949 continue; |
|
950 } |
|
951 |