Apache HTTPD
lock.c
Go to the documentation of this file.
1/* Licensed to the Apache Software Foundation (ASF) under one or more
2 * contributor license agreements. See the NOTICE file distributed with
3 * this work for additional information regarding copyright ownership.
4 * The ASF licenses this file to You under the Apache License, Version 2.0
5 * (the "License"); you may not use this file except in compliance with
6 * the License. You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17/*
18** DAV filesystem lock implementation
19*/
20
21#include "apr.h"
22#include "apr_strings.h"
23#include "apr_file_io.h"
24#include "apr_uuid.h"
25
26#define APR_WANT_MEMFUNC
27#include "apr_want.h"
28
29#include "httpd.h"
30#include "http_log.h"
31
32#include "mod_dav.h"
33#include "repos.h"
34
35
36/* ---------------------------------------------------------------
37**
38** Lock database primitives
39**
40*/
41
42/*
43** LOCK DATABASES
44**
45** Lockdiscovery information is stored in the single lock database specified
46** by the DAVLockDB directive. Information about this db is stored in the
47** global server configuration.
48**
49** KEY
50**
51** The database is keyed by a key_type unsigned char (DAV_TYPE_FNAME)
52** followed by the full path. The key_type DAV_TYPE_INODE is not used anymore.
53**
54** VALUE
55**
56** The value consists of a list of elements.
57** DIRECT LOCK: [char (DAV_LOCK_DIRECT),
58** char (dav_lock_scope),
59** char (dav_lock_type),
60** int depth,
61** time_t expires,
62** apr_uuid_t locktoken,
63** char[] owner,
64** char[] auth_user]
65**
66** INDIRECT LOCK: [char (DAV_LOCK_INDIRECT),
67** apr_uuid_t locktoken,
68** time_t expires,
69** apr_size_t key_size,
70** char[] key]
71** The key is to the collection lock that resulted in this indirect lock
72*/
73
74#define DAV_TRUE 1
75#define DAV_FALSE 0
76
77#define DAV_CREATE_LIST 23
78#define DAV_APPEND_LIST 24
79
80/* Stored lock_discovery prefix */
81#define DAV_LOCK_DIRECT 1
82#define DAV_LOCK_INDIRECT 2
83
84/*
85 * not used anymore
86 * #define DAV_TYPE_INODE 10
87 */
88#define DAV_TYPE_FNAME 11
89
90
91/* ack. forward declare. */
93 const char *filename,
95
96/*
97** Use the opaquelock scheme for locktokens
98*/
102#define dav_compare_locktoken(plt1, plt2) \
103 memcmp(&(plt1)->uuid, &(plt2)->uuid, sizeof((plt1)->uuid))
104
105
106/* #################################################################
107** ### keep these structures (internal) or move fully to dav_lock?
108*/
109
110/*
111** We need to reliably size the fixed-length portion of
112** dav_lock_discovery; best to separate it into another
113** struct for a convenient sizeof, unless we pack lock_discovery.
114*/
122
123typedef struct dav_lock_discovery
124{
126
128 const char *owner; /* owner field from activelock */
129 const char *auth_user; /* authenticated user who created the lock */
132
133/* Indirect locks represent locks inherited from containing collections.
134 * They reference the lock token for the collection the lock is
135 * inherited from. A lock provider may also define a key to the
136 * inherited lock, for fast datbase lookup. The key is opaque outside
137 * the lock provider.
138 */
146
147/* ################################################################# */
148
149
150/*
151** Stored direct lock info - full lock_discovery length:
152** prefix + Fixed length + lock token + 2 strings + 2 nulls (one for each string)
153*/
154#define dav_size_direct(a) ( 1 + sizeof(dav_lock_discovery_fixed) \
155 + sizeof(apr_uuid_t) \
156 + ((a)->owner ? strlen((a)->owner) : 0) \
157 + ((a)->auth_user ? strlen((a)->auth_user) : 0) \
158 + 2)
159
160/* Stored indirect lock info - lock token and apr_datum_t */
161#define dav_size_indirect(a) (1 + sizeof(apr_uuid_t) \
162 + sizeof(time_t) \
163 + sizeof((a)->key.dsize) + (a)->key.dsize)
164
165/*
166** The lockdb structure.
167**
168** The <db> field may be NULL, meaning one of two things:
169** 1) That we have not actually opened the underlying database (yet). The
170** <opened> field should be false.
171** 2) We opened it readonly and it wasn't present.
172**
173** The delayed opening (determined by <opened>) makes creating a lockdb
174** quick, while deferring the underlying I/O until it is actually required.
175**
176** We export the notion of a lockdb, but hide the details of it. Most
177** implementations will use a database of some kind, but it is certainly
178** possible that alternatives could be used.
179*/
181{
182 request_rec *r; /* for accessing the uuid state */
183 apr_pool_t *pool; /* a pool to use */
184 const char *lockdb_path; /* where is the lock database? */
185
186 int opened; /* we opened the database */
187 dav_db *db; /* if non-NULL, the lock database */
188};
194
195/*
196** The private part of the lock structure.
197*/
199{
200 apr_datum_t key; /* key into the lock database */
201};
208
209/*
210** This must be forward-declared so the open_lockdb function can use it.
211*/
213
214
215/* internal function for creating locks */
217 const dav_locktoken *locktoken)
218{
220
221 comb = apr_pcalloc(lockdb->info->pool, sizeof(*comb));
222 comb->pub.rectype = DAV_LOCKREC_DIRECT;
223 comb->pub.info = &comb->priv;
224 comb->priv.key = key;
225
226 if (locktoken == NULL) {
227 comb->pub.locktoken = &comb->token;
228 apr_uuid_get(&comb->token.uuid);
229 }
230 else {
231 comb->pub.locktoken = locktoken;
232 }
233
234 return &comb->pub;
235}
236
237/*
238** dav_fs_parse_locktoken
239**
240** Parse an opaquelocktoken URI into a locktoken.
241*/
243 apr_pool_t *p,
244 const char *char_token,
246{
247 dav_locktoken *locktoken;
248
249 if (ap_strstr_c(char_token, "opaquelocktoken:") != char_token) {
250 return dav_new_error(p,
252 "The lock token uses an unknown State-token "
253 "format and could not be parsed.");
254 }
255 char_token += 16;
256
257 locktoken = apr_pcalloc(p, sizeof(*locktoken));
258 if (apr_uuid_parse(&locktoken->uuid, char_token)) {
260 "The opaquelocktoken has an incorrect format "
261 "and could not be parsed.");
262 }
263
264 *locktoken_p = locktoken;
265 return NULL;
266}
267
268/*
269** dav_fs_format_locktoken
270**
271** Generate the URI for a locktoken
272*/
273static const char *dav_fs_format_locktoken(
274 apr_pool_t *p,
275 const dav_locktoken *locktoken)
276{
278
279 apr_uuid_format(buf, &locktoken->uuid);
280 return apr_pstrcat(p, "opaquelocktoken:", buf, NULL);
281}
282
283/*
284** dav_fs_compare_locktoken
285**
286** Determine whether two locktokens are the same
287*/
289 const dav_locktoken *lt1,
290 const dav_locktoken *lt2)
291{
293}
294
295/*
296** dav_fs_really_open_lockdb:
297**
298** If the database hasn't been opened yet, then open the thing.
299*/
301{
302 dav_error *err;
303
304 if (lockdb->info->opened)
305 return NULL;
306
307 err = dav_dbm_open_direct(lockdb->info->pool,
308 lockdb->info->lockdb_path,
309 lockdb->ro,
310 &lockdb->info->db);
311 if (err != NULL) {
312 return dav_push_error(lockdb->info->pool,
315 "Could not open the lock database.",
316 err);
317 }
318
319 /* all right. it is opened now. */
320 lockdb->info->opened = 1;
321
322 return NULL;
323}
324
325/*
326** dav_fs_open_lockdb:
327**
328** "open" the lock database, as specified in the global server configuration.
329** If force is TRUE, then the database is opened now, rather than lazily.
330**
331** Note that only one can be open read/write.
332*/
334 dav_lockdb **lockdb)
335{
337
338 comb = apr_pcalloc(r->pool, sizeof(*comb));
339 comb->pub.hooks = &dav_hooks_locks_fs;
340 comb->pub.ro = ro;
341 comb->pub.info = &comb->priv;
342 comb->priv.r = r;
343 comb->priv.pool = r->pool;
344
345 comb->priv.lockdb_path = dav_get_lockdb_path(r);
346 if (comb->priv.lockdb_path == NULL) {
349 "A lock database was not specified with the "
350 "DAVLockDB directive. One must be specified "
351 "to use the locking functionality.");
352 }
353
354 /* done initializing. return it. */
355 *lockdb = &comb->pub;
356
357 if (force) {
358 /* ### add a higher-level comment? */
359 return dav_fs_really_open_lockdb(*lockdb);
360 }
361
362 return NULL;
363}
364
365/*
366** dav_fs_close_lockdb:
367**
368** Close it. Duh.
369*/
370static void dav_fs_close_lockdb(dav_lockdb *lockdb)
371{
372 if (lockdb->info->db != NULL)
373 dav_dbm_close(lockdb->info->db);
374}
375
376/*
377** dav_fs_build_key: Given a resource, return a apr_datum_t key
378** to look up lock information for this file.
379*/
381 const dav_resource *resource)
382{
383 const char *pathname = dav_fs_pathname(resource);
385
386 /* ### does this allocation have a proper lifetime? need to check */
387 /* ### can we use a buffer for this? */
388
389 /* size is TYPE + pathname + null */
390 key.dsize = strlen(pathname) + 2;
391 key.dptr = apr_palloc(p, key.dsize);
392 *key.dptr = DAV_TYPE_FNAME;
393 memcpy(key.dptr + 1, pathname, key.dsize - 1);
394 if (key.dptr[key.dsize - 2] == '/')
395 key.dptr[--key.dsize - 1] = '\0';
396 return key;
397}
398
399/*
400** dav_fs_lock_expired: return 1 (true) if the given timeout is in the past
401** or present (the lock has expired), or 0 (false) if in the future
402** (the lock has not yet expired).
403*/
404static int dav_fs_lock_expired(time_t expires)
405{
406 return expires != DAV_TIMEOUT_INFINITE && time(NULL) >= expires;
407}
408
409/*
410** dav_fs_save_lock_record: Saves the lock information specified in the
411** direct and indirect lock lists about path into the lock database.
412** If direct and indirect == NULL, the key is removed.
413*/
417{
418 dav_error *err;
419 apr_datum_t val = { 0 };
420 char *ptr;
423
424#if DAV_DEBUG
425 if (lockdb->ro) {
426 return dav_new_error(lockdb->info->pool,
428 "INTERNAL DESIGN ERROR: the lockdb was opened "
429 "readonly, but an attempt to save locks was "
430 "performed.");
431 }
432#endif
433
434 if ((err = dav_fs_really_open_lockdb(lockdb)) != NULL) {
435 /* ### add a higher-level error? */
436 return err;
437 }
438
439 /* If nothing to save, delete key */
440 if (dp == NULL && ip == NULL) {
441 /* don't fail if the key is not present */
442 /* ### but what about other errors? */
443 (void) dav_dbm_delete(lockdb->info->db, key);
444 return NULL;
445 }
446
447 while(dp) {
448 val.dsize += dav_size_direct(dp);
449 dp = dp->next;
450 }
451 while(ip) {
452 val.dsize += dav_size_indirect(ip);
453 ip = ip->next;
454 }
455
456 /* ### can this be apr_palloc() ? */
457 /* ### hmmm.... investigate the use of a buffer here */
458 ptr = val.dptr = apr_pcalloc(lockdb->info->pool, val.dsize);
459 dp = direct;
460 ip = indirect;
461
462 while(dp) {
463 *ptr++ = DAV_LOCK_DIRECT; /* Direct lock - lock_discovery struct follows */
464 memcpy(ptr, dp, sizeof(dp->f)); /* Fixed portion of struct */
465 ptr += sizeof(dp->f);
466 memcpy(ptr, dp->locktoken, sizeof(*dp->locktoken));
467 ptr += sizeof(*dp->locktoken);
468 if (dp->owner == NULL) {
469 *ptr++ = '\0';
470 }
471 else {
472 memcpy(ptr, dp->owner, strlen(dp->owner) + 1);
473 ptr += strlen(dp->owner) + 1;
474 }
475 if (dp->auth_user == NULL) {
476 *ptr++ = '\0';
477 }
478 else {
479 memcpy(ptr, dp->auth_user, strlen(dp->auth_user) + 1);
480 ptr += strlen(dp->auth_user) + 1;
481 }
482
483 dp = dp->next;
484 }
485
486 while(ip) {
487 *ptr++ = DAV_LOCK_INDIRECT; /* Indirect lock prefix */
488 memcpy(ptr, ip->locktoken, sizeof(*ip->locktoken)); /* Locktoken */
489 ptr += sizeof(*ip->locktoken);
490 memcpy(ptr, &ip->timeout, sizeof(ip->timeout)); /* Expire time */
491 ptr += sizeof(ip->timeout);
492 memcpy(ptr, &ip->key.dsize, sizeof(ip->key.dsize)); /* Size of key */
493 ptr += sizeof(ip->key.dsize);
494 memcpy(ptr, ip->key.dptr, ip->key.dsize); /* Key data */
495 ptr += ip->key.dsize;
496 ip = ip->next;
497 }
498
499 if ((err = dav_dbm_store(lockdb->info->db, key, val)) != NULL) {
500 /* ### more details? add an error_id? */
501 return dav_push_error(lockdb->info->pool,
504 "Could not save lock information.",
505 err);
506 }
507
508 return NULL;
509}
510
511/*
512** dav_load_lock_record: Reads lock information about key from lock db;
513** creates linked lists of the direct and indirect locks.
514**
515** If add_method = DAV_APPEND_LIST, the result will be appended to the
516** head of the direct and indirect lists supplied.
517**
518** Passive lock removal: If lock has timed out, it will not be returned.
519** ### How much "logging" does RFC 2518 require?
520*/
522 int add_method,
525{
526 apr_pool_t *p = lockdb->info->pool;
527 dav_error *err;
528 apr_size_t offset = 0;
529 int need_save = DAV_FALSE;
530 apr_datum_t val = { 0 };
533 dav_buffer buf = { 0 };
534
536 *direct = NULL;
537 *indirect = NULL;
538 }
539
540 if ((err = dav_fs_really_open_lockdb(lockdb)) != NULL) {
541 /* ### add a higher-level error? */
542 return err;
543 }
544
545 /*
546 ** If we opened readonly and the db wasn't there, then there are no
547 ** locks for this resource. Just exit.
548 */
549 if (lockdb->info->db == NULL)
550 return NULL;
551
552 if ((err = dav_dbm_fetch(lockdb->info->db, key, &val)) != NULL)
553 return err;
554
555 if (!val.dsize)
556 return NULL;
557
558 while (offset < val.dsize) {
559 switch (*(val.dptr + offset++)) {
560 case DAV_LOCK_DIRECT:
561 /* Create and fill a dav_lock_discovery structure */
562
563 dp = apr_pcalloc(p, sizeof(*dp));
564 memcpy(dp, val.dptr + offset, sizeof(dp->f));
565 offset += sizeof(dp->f);
566 dp->locktoken = apr_pmemdup(p, val.dptr + offset, sizeof(*dp->locktoken));
567 offset += sizeof(*dp->locktoken);
568 if (*(val.dptr + offset) == '\0') {
569 ++offset;
570 }
571 else {
572 dp->owner = apr_pstrdup(p, val.dptr + offset);
573 offset += strlen(dp->owner) + 1;
574 }
575
576 if (*(val.dptr + offset) == '\0') {
577 ++offset;
578 }
579 else {
580 dp->auth_user = apr_pstrdup(p, val.dptr + offset);
581 offset += strlen(dp->auth_user) + 1;
582 }
583
584 if (!dav_fs_lock_expired(dp->f.timeout)) {
585 dp->next = *direct;
586 *direct = dp;
587 }
588 else {
590
591 /* Remove timed-out locknull fm .locknull list */
592 if (*key.dptr == DAV_TYPE_FNAME) {
593 const char *fname = key.dptr + 1;
594 apr_finfo_t finfo;
595 apr_status_t rv;
596
597 /* if we don't see the file, then it's a locknull */
598 rv = apr_stat(&finfo, fname, APR_FINFO_MIN | APR_FINFO_LINK, p);
599 if (rv != APR_SUCCESS && rv != APR_INCOMPLETE) {
601 /* ### push a higher-level description? */
602 return err;
603 }
604 }
605 }
606 }
607 break;
608
610 /* Create and fill a dav_lock_indirect structure */
611
612 ip = apr_pcalloc(p, sizeof(*ip));
613 ip->locktoken = apr_pmemdup(p, val.dptr + offset, sizeof(*ip->locktoken));
614 offset += sizeof(*ip->locktoken);
615 memcpy(&ip->timeout, val.dptr + offset, sizeof(ip->timeout));
616 offset += sizeof(ip->timeout);
617 memcpy(&ip->key.dsize, val.dptr + offset, sizeof(ip->key.dsize)); /* length of datum */
618 offset += sizeof(ip->key.dsize);
619 ip->key.dptr = apr_pmemdup(p, val.dptr + offset, ip->key.dsize);
620 offset += ip->key.dsize;
621
622 if (!dav_fs_lock_expired(ip->timeout)) {
623 ip->next = *indirect;
624 *indirect = ip;
625 }
626 else {
628 /* A locknull resource will never be locked indirectly */
629 }
630
631 break;
632
633 default:
634 dav_dbm_freedatum(lockdb->info->db, val);
635
636 /* ### should use a computed_desc and insert corrupt token data */
637 --offset;
638 return dav_new_error(p,
642 "The lock database was found to "
643 "be corrupt. offset %"
644 APR_SIZE_T_FMT ", c=%02x",
645 offset, val.dptr[offset]));
646 }
647 }
648
649 dav_dbm_freedatum(lockdb->info->db, val);
650
651 /* Clean up this record if we found expired locks */
652 /*
653 ** ### shouldn't do this if we've been opened READONLY. elide the
654 ** ### timed-out locks from the response, but don't save that info back
655 */
656 if (need_save == DAV_TRUE) {
657 return dav_fs_save_lock_record(lockdb, key, *direct, *indirect);
658 }
659
660 return NULL;
661}
662
663/* resolve <indirect>, returning <*direct> */
669{
670 dav_error *err;
673
674 if ((err = dav_fs_load_lock_record(lockdb, indirect->key,
676 &dir, &ind)) != NULL) {
677 /* ### insert a higher-level description? */
678 return err;
679 }
680 if (ref_dp != NULL) {
681 *ref_dp = dir;
682 *ref_ip = ind;
683 }
684
685 for (; dir != NULL; dir = dir->next) {
686 if (!dav_compare_locktoken(indirect->locktoken, dir->locktoken)) {
687 *direct = dir;
688 return NULL;
689 }
690 }
691
692 /* No match found (but we should have found one!) */
693
694 /* ### use a different description and/or error ID? */
695 return dav_new_error(lockdb->info->pool,
698 "The lock database was found to be corrupt. "
699 "An indirect lock's direct lock could not "
700 "be found.");
701}
702
703/* ---------------------------------------------------------------
704**
705** Property-related lock functions
706**
707*/
708
709/*
710** dav_fs_get_supportedlock: Returns a static string for all supportedlock
711** properties. I think we save more returning a static string than
712** constructing it every time, though it might look cleaner.
713*/
715{
716 static const char supported[] = DEBUG_CR
717 "<D:lockentry>" DEBUG_CR
718 "<D:lockscope><D:exclusive/></D:lockscope>" DEBUG_CR
719 "<D:locktype><D:write/></D:locktype>" DEBUG_CR
720 "</D:lockentry>" DEBUG_CR
721 "<D:lockentry>" DEBUG_CR
722 "<D:lockscope><D:shared/></D:lockscope>" DEBUG_CR
723 "<D:locktype><D:write/></D:locktype>" DEBUG_CR
724 "</D:lockentry>" DEBUG_CR;
725
726 return supported;
727}
728
729/* ---------------------------------------------------------------
730**
731** General lock functions
732**
733*/
734
735/* ---------------------------------------------------------------
736**
737** Functions dealing with lock-null resources
738**
739*/
740
741/*
742** dav_fs_load_locknull_list: Returns a dav_buffer dump of the locknull file
743** for the given directory.
744*/
747{
748 apr_finfo_t finfo;
750 dav_error *err = NULL;
752 apr_status_t rv;
753
755
756 if (pbuf->buf[pbuf->cur_len - 1] == '/')
757 pbuf->buf[--pbuf->cur_len] = '\0';
758
760
761 /* reset this in case we leave w/o reading into the buffer */
762 pbuf->cur_len = 0;
763
765 p) != APR_SUCCESS) {
766 return NULL;
767 }
768
770 if (rv != APR_SUCCESS) {
773 "Opened but could not stat file %s",
774 pbuf->buf));
775 goto loaderror;
776 }
777
778 if (finfo.size != (apr_size_t)finfo.size) {
781 "Opened but rejected huge file %s",
782 pbuf->buf));
783 goto loaderror;
784 }
785
786 amt = (apr_size_t)finfo.size;
788 if ((rv = apr_file_read(file, pbuf->buf, &amt)) != APR_SUCCESS
789 || amt != finfo.size) {
792 "Failure reading locknull file "
793 "for %s", dirpath));
794
795 /* just in case the caller disregards the returned error */
796 pbuf->cur_len = 0;
797 goto loaderror;
798 }
799
800 loaderror:
802 return err;
803}
804
805/*
806** dav_fs_save_locknull_list: Saves contents of pbuf into the
807** locknull file for dirpath.
808*/
811{
812 const char *pathname;
814 dav_error *err = NULL;
816 apr_status_t rv;
817
818 if (pbuf->buf == NULL)
819 return NULL;
820
823 dirpath,
824 dirpath[strlen(dirpath) - 1] == '/' ? "" : "/",
826 NULL);
827
828 if (pbuf->cur_len == 0) {
829 /* delete the file if cur_len == 0 */
830 if ((rv = apr_file_remove(pathname, p)) != APR_SUCCESS) {
833 "Error removing %s", pathname));
834 }
835 return NULL;
836 }
837
838 if ((rv = apr_file_open(&file, pathname,
843 "Error opening %s for writing",
844 pathname));
845 }
846
847 amt = pbuf->cur_len;
848 if ((rv = apr_file_write_full(file, pbuf->buf, amt, &amt)) != APR_SUCCESS
849 || amt != pbuf->cur_len) {
852 "Error writing %" APR_SIZE_T_FMT
853 " bytes to %s",
854 pbuf->cur_len, pathname));
855 }
856
858 return err;
859}
860
861/*
862** dav_fs_remove_locknull_member: Removes filename from the locknull list
863** for directory path.
864*/
866 const char *filename,
868{
869 dav_error *err;
872 char *scan;
873 const char *scanend;
874 char *dirpath = apr_pstrdup(p, filename);
875 char *fname = strrchr(dirpath, '/');
876 int dirty = 0;
877
878 if (fname != NULL)
879 *fname++ = '\0';
880 else
881 fname = dirpath;
882 len = strlen(fname) + 1;
883
885 /* ### add a higher level description? */
886 return err;
887 }
888
889 for (scan = pbuf->buf, scanend = scan + pbuf->cur_len;
890 scan < scanend;
891 scan += scanlen) {
892 scanlen = strlen(scan) + 1;
893 if (len == scanlen && memcmp(fname, scan, scanlen) == 0) {
894 pbuf->cur_len -= scanlen;
896 dirty = 1;
897 break;
898 }
899 }
900
901 if (dirty) {
903 /* ### add a higher level description? */
904 return err;
905 }
906 }
907
908 return NULL;
909}
910
911/* Note: used by dav_fs_repos.c */
913 const dav_resource *resource,
915{
916 const char *dirpath;
917
918 /* ### should test this result value... */
921}
922
923/* ### fold into append_lock? */
924/* ### take an optional buf parameter? */
926 dav_lockdb *lockdb,
927 const dav_resource *resource)
928{
929 dav_buffer buf = { 0 };
930 apr_pool_t *p = lockdb->info->pool;
931 const char *dirpath;
932 const char *fname;
933 dav_error *err;
934
935 /* ### should test this result value... */
937
940 "Could not load .locknull file.", err);
941 }
942
944 buf.cur_len++; /* we want the null-term here */
945
948 "Could not save .locknull file.", err);
949 }
950
951 return NULL;
952}
953
954/*
955** dav_fs_remove_locknull_state: Given a request, check to see if r->filename
956** is/was a lock-null resource. If so, return it to an existent state, i.e.
957** remove it from the list in the appropriate .DAV/locknull file.
958*/
960 dav_lockdb *lockdb,
961 const dav_resource *resource)
962{
963 dav_buffer buf = { 0 };
964 dav_error *err;
965 apr_pool_t *p = lockdb->info->pool;
966 const char *pathname = dav_fs_pathname(resource);
967
969 /* ### add a higher-level description? */
970 return err;
971 }
972
973 return NULL;
974}
975
977 const dav_resource *resource,
978 dav_lock **lock)
979{
981
983
984 *lock = dav_fs_alloc_lock(lockdb,
985 key,
986 NULL);
987
988 (*lock)->is_locknull = !resource->exists;
989
990 return NULL;
991}
992
994 const dav_resource *resource,
995 int calltype,
996 dav_lock **locks)
997{
998 apr_pool_t *p = lockdb->info->pool;
1000 dav_error *err;
1001 dav_lock *lock = NULL;
1005
1006#if DAV_DEBUG
1008 return dav_new_error(lockdb->info->pool,
1010 "INTERNAL DESIGN ERROR: DAV_GETLOCKS_COMPLETE "
1011 "is not yet supported");
1012 }
1013#endif
1014
1017 &dp, &ip)) != NULL) {
1018 /* ### push a higher-level desc? */
1019 return err;
1020 }
1021
1022 /* copy all direct locks to the result list */
1023 for (; dp != NULL; dp = dp->next) {
1024 newlock = dav_fs_alloc_lock(lockdb, key, dp->locktoken);
1025 newlock->is_locknull = !resource->exists;
1026 newlock->scope = dp->f.scope;
1027 newlock->type = dp->f.type;
1028 newlock->depth = dp->f.depth;
1029 newlock->timeout = dp->f.timeout;
1030 newlock->owner = dp->owner;
1031 newlock->auth_user = dp->auth_user;
1032
1033 /* hook into the result list */
1034 newlock->next = lock;
1035 lock = newlock;
1036 }
1037
1038 /* copy all the indirect locks to the result list. resolve as needed. */
1039 for (; ip != NULL; ip = ip->next) {
1040 newlock = dav_fs_alloc_lock(lockdb, ip->key, ip->locktoken);
1041 newlock->is_locknull = !resource->exists;
1042
1044 if ((err = dav_fs_resolve(lockdb, ip, &dp, NULL, NULL)) != NULL) {
1045 /* ### push a higher-level desc? */
1046 return err;
1047 }
1048
1049 newlock->scope = dp->f.scope;
1050 newlock->type = dp->f.type;
1051 newlock->depth = dp->f.depth;
1052 newlock->timeout = dp->f.timeout;
1053 newlock->owner = dp->owner;
1054 newlock->auth_user = dp->auth_user;
1055 }
1056 else {
1057 /* DAV_GETLOCKS_PARTIAL */
1059 }
1060
1061 /* hook into the result list */
1062 newlock->next = lock;
1063 lock = newlock;
1064 }
1065
1066 *locks = lock;
1067 return NULL;
1068}
1069
1071 const dav_resource *resource,
1072 const dav_locktoken *locktoken,
1073 int partial_ok,
1074 dav_lock **lock)
1075{
1076 dav_error *err;
1080
1081 *lock = NULL;
1082
1083 key = dav_fs_build_key(lockdb->info->pool, resource);
1085 &dp, &ip)) != NULL) {
1086 /* ### push a higher-level desc? */
1087 return err;
1088 }
1089
1090 for (; dp != NULL; dp = dp->next) {
1091 if (!dav_compare_locktoken(locktoken, dp->locktoken)) {
1092 *lock = dav_fs_alloc_lock(lockdb, key, locktoken);
1093 (*lock)->is_locknull = !resource->exists;
1094 (*lock)->scope = dp->f.scope;
1095 (*lock)->type = dp->f.type;
1096 (*lock)->depth = dp->f.depth;
1097 (*lock)->timeout = dp->f.timeout;
1098 (*lock)->owner = dp->owner;
1099 (*lock)->auth_user = dp->auth_user;
1100 return NULL;
1101 }
1102 }
1103
1104 for (; ip != NULL; ip = ip->next) {
1105 if (!dav_compare_locktoken(locktoken, ip->locktoken)) {
1106 *lock = dav_fs_alloc_lock(lockdb, ip->key, locktoken);
1107 (*lock)->is_locknull = !resource->exists;
1108
1109 /* ### nobody uses the resolving right now! */
1110 if (partial_ok) {
1111 (*lock)->rectype = DAV_LOCKREC_INDIRECT_PARTIAL;
1112 }
1113 else {
1114 (*lock)->rectype = DAV_LOCKREC_INDIRECT;
1115 if ((err = dav_fs_resolve(lockdb, ip, &dp,
1116 NULL, NULL)) != NULL) {
1117 /* ### push a higher-level desc? */
1118 return err;
1119 }
1120 (*lock)->scope = dp->f.scope;
1121 (*lock)->type = dp->f.type;
1122 (*lock)->depth = dp->f.depth;
1123 (*lock)->timeout = dp->f.timeout;
1124 (*lock)->owner = dp->owner;
1125 (*lock)->auth_user = dp->auth_user;
1126 }
1127 return NULL;
1128 }
1129 }
1130
1131 return NULL;
1132}
1133
1135 const dav_resource *resource,
1136 int *locks_present)
1137{
1138 dav_error *err;
1140
1141 *locks_present = 0;
1142
1143 if ((err = dav_fs_really_open_lockdb(lockdb)) != NULL) {
1144 /* ### insert a higher-level error description */
1145 return err;
1146 }
1147
1148 /*
1149 ** If we opened readonly and the db wasn't there, then there are no
1150 ** locks for this resource. Just exit.
1151 */
1152 if (lockdb->info->db == NULL)
1153 return NULL;
1154
1155 key = dav_fs_build_key(lockdb->info->pool, resource);
1156
1157 *locks_present = dav_dbm_exists(lockdb->info->db, key);
1158
1159 return NULL;
1160}
1161
1163 const dav_resource *resource,
1164 int make_indirect,
1165 const dav_lock *lock)
1166{
1167 apr_pool_t *p = lockdb->info->pool;
1168 dav_error *err;
1172
1173 key = dav_fs_build_key(lockdb->info->pool, resource);
1174 if ((err = dav_fs_load_lock_record(lockdb, key, 0, &dp, &ip)) != NULL) {
1175 /* ### maybe add in a higher-level description */
1176 return err;
1177 }
1178
1179 /*
1180 ** ### when we store the lock more directly, we need to update
1181 ** ### lock->rectype and lock->is_locknull
1182 */
1183
1184 if (make_indirect) {
1185 for (; lock != NULL; lock = lock->next) {
1186
1187 /* ### this works for any <lock> rectype */
1188 dav_lock_indirect *newi = apr_pcalloc(p, sizeof(*newi));
1189
1190 /* ### shut off the const warning for now */
1191 newi->locktoken = (dav_locktoken *)lock->locktoken;
1192 newi->timeout = lock->timeout;
1193 newi->key = lock->info->key;
1194 newi->next = ip;
1195 ip = newi;
1196 }
1197 }
1198 else {
1199 for (; lock != NULL; lock = lock->next) {
1200 /* create and link in the right kind of lock */
1201
1202 if (lock->rectype == DAV_LOCKREC_DIRECT) {
1204
1205 newd->f.scope = lock->scope;
1206 newd->f.type = lock->type;
1207 newd->f.depth = lock->depth;
1208 newd->f.timeout = lock->timeout;
1209 /* ### shut off the const warning for now */
1210 newd->locktoken = (dav_locktoken *)lock->locktoken;
1211 newd->owner = lock->owner;
1212 newd->auth_user = lock->auth_user;
1213 newd->next = dp;
1214 dp = newd;
1215 }
1216 else {
1217 /* DAV_LOCKREC_INDIRECT(_PARTIAL) */
1218
1219 dav_lock_indirect *newi = apr_pcalloc(p, sizeof(*newi));
1220
1221 /* ### shut off the const warning for now */
1222 newi->locktoken = (dav_locktoken *)lock->locktoken;
1223 newi->key = lock->info->key;
1224 newi->next = ip;
1225 ip = newi;
1226 }
1227 }
1228 }
1229
1230 if ((err = dav_fs_save_lock_record(lockdb, key, dp, ip)) != NULL) {
1231 /* ### maybe add a higher-level description */
1232 return err;
1233 }
1234
1235 /* we have a special list for recording locknull resources */
1236 /* ### ack! this can add two copies to the locknull list */
1237 if (!resource->exists
1238 && (err = dav_fs_add_locknull_state(lockdb, resource)) != NULL) {
1239 /* ### maybe add a higher-level description */
1240 return err;
1241 }
1242
1243 return NULL;
1244}
1245
1247 const dav_resource *resource,
1248 const dav_locktoken *locktoken)
1249{
1250 dav_error *err;
1251 dav_buffer buf = { 0 };
1253 dav_lock_indirect *ih = NULL;
1255
1256 key = dav_fs_build_key(lockdb->info->pool, resource);
1257
1258 if (locktoken != NULL) {
1263
1265 &dh, &ih)) != NULL) {
1266 /* ### maybe add a higher-level description */
1267 return err;
1268 }
1269
1270 for (dp = dh; dp != NULL; dp = dp->next) {
1271 if (dav_compare_locktoken(locktoken, dp->locktoken) == 0) {
1272 if (dprev)
1273 dprev->next = dp->next;
1274 else
1275 dh = dh->next;
1276 }
1277 dprev = dp;
1278 }
1279
1280 for (ip = ih; ip != NULL; ip = ip->next) {
1281 if (dav_compare_locktoken(locktoken, ip->locktoken) == 0) {
1282 if (iprev)
1283 iprev->next = ip->next;
1284 else
1285 ih = ih->next;
1286 }
1287 iprev = ip;
1288 }
1289
1290 }
1291
1292 /* save the modified locks, or remove all locks (dh=ih=NULL). */
1293 if ((err = dav_fs_save_lock_record(lockdb, key, dh, ih)) != NULL) {
1294 /* ### maybe add a higher-level description */
1295 return err;
1296 }
1297
1298 /*
1299 ** If this resource is a locknull resource AND no more locks exist,
1300 ** then remove the locknull member.
1301 **
1302 ** Note: remove_locknull_state() attempts to convert a locknull member
1303 ** to a real member. In this case, all locks are gone, so the
1304 ** locknull resource returns to the null state (ie. doesn't exist),
1305 ** so there is no need to update the lockdb (and it won't find
1306 ** any because a precondition is that none exist).
1307 */
1308 if (!resource->exists && dh == NULL && ih == NULL
1311 &buf)) != NULL) {
1312 /* ### maybe add a higher-level description */
1313 return err;
1314 }
1315
1316 return NULL;
1317}
1318
1320 const dav_locktoken_list *ltl,
1322{
1323 int dirty = 0;
1324
1325 for (; ltl != NULL; ltl = ltl->next) {
1326 if (dav_compare_locktoken(dp->locktoken, ltl->locktoken) == 0)
1327 {
1328 dp->f.timeout = new_time;
1329 dirty = 1;
1330 break;
1331 }
1332 }
1333
1334 return dirty;
1335}
1336
1338 const dav_resource *resource,
1339 const dav_locktoken_list *ltl,
1341 dav_lock **locks)
1342{
1343 dav_error *err;
1348 int dirty = 0;
1350
1351 *locks = NULL;
1352
1353 key = dav_fs_build_key(lockdb->info->pool, resource);
1355 &dp, &ip)) != NULL) {
1356 /* ### maybe add in a higher-level description */
1357 return err;
1358 }
1359
1360 /* ### we should be refreshing direct AND (resolved) indirect locks! */
1361
1362 /* refresh all of the direct locks on this resource */
1363 for (dp_scan = dp; dp_scan != NULL; dp_scan = dp_scan->next) {
1365 /* the lock was refreshed. return the lock. */
1366 newlock = dav_fs_alloc_lock(lockdb, key, dp_scan->locktoken);
1367 newlock->is_locknull = !resource->exists;
1368 newlock->scope = dp_scan->f.scope;
1369 newlock->type = dp_scan->f.type;
1370 newlock->depth = dp_scan->f.depth;
1371 newlock->timeout = dp_scan->f.timeout;
1372 newlock->owner = dp_scan->owner;
1373 newlock->auth_user = dp_scan->auth_user;
1374
1375 newlock->next = *locks;
1376 *locks = newlock;
1377
1378 dirty = 1;
1379 }
1380 }
1381
1382 /* if we refreshed any locks, then save them back. */
1383 if (dirty
1384 && (err = dav_fs_save_lock_record(lockdb, key, dp, ip)) != NULL) {
1385 /* ### maybe add in a higher-level description */
1386 return err;
1387 }
1388
1389 /* for each indirect lock, find its direct lock and refresh it. */
1390 for (; ip != NULL; ip = ip->next) {
1393
1394 if ((err = dav_fs_resolve(lockdb, ip, &dp_scan,
1395 &ref_dp, &ref_ip)) != NULL) {
1396 /* ### push a higher-level desc? */
1397 return err;
1398 }
1400 /* the lock was refreshed. return the lock. */
1401 newlock = dav_fs_alloc_lock(lockdb, ip->key, dp_scan->locktoken);
1402 newlock->is_locknull = !resource->exists;
1403 newlock->scope = dp_scan->f.scope;
1404 newlock->type = dp_scan->f.type;
1405 newlock->depth = dp_scan->f.depth;
1406 newlock->timeout = dp_scan->f.timeout;
1407 newlock->owner = dp_scan->owner;
1408 newlock->auth_user = dp_scan->auth_user;
1409
1410 newlock->next = *locks;
1411 *locks = newlock;
1412
1413 /* save the (resolved) direct lock back */
1414 if ((err = dav_fs_save_lock_record(lockdb, ip->key, ref_dp,
1415 ref_ip)) != NULL) {
1416 /* ### push a higher-level desc? */
1417 return err;
1418 }
1419 }
1420 }
1421
1422 return NULL;
1423}
1424
1425
const char apr_size_t len
Definition ap_regex.h:187
APR File I/O Handling.
APR Strings library.
APR UUID library.
APR Standard Headers Support.
static sem_id lock
Definition threadpriv.c:21
request_rec * r
const unsigned char * buf
Definition util_md5.h:50
#define APR_INCOMPLETE
Definition apr_errno.h:452
#define APR_UUID_FORMATTED_LENGTH
Definition apr_uuid.h:46
const char const char * pathname
Definition apr_dbm.h:201
void ** resource
const apr_xml_elem int apr_array_header_t int const char ** pbuf
Definition apr_xml.h:288
#define HTTP_BAD_REQUEST
Definition httpd.h:508
#define HTTP_INTERNAL_SERVER_ERROR
Definition httpd.h:535
dav_error * dav_dbm_store(dav_db *db, apr_datum_t key, apr_datum_t value)
Definition dbm.c:232
void dav_fs_ensure_state_dir(apr_pool_t *p, const char *dirname)
Definition dbm.c:119
#define DAV_ERR_LOCK_NO_DB
Definition mod_dav.h:230
dav_error * dav_dbm_delete(dav_db *db, apr_datum_t key)
Definition dbm.c:239
const char * dav_get_lockdb_path(const request_rec *r)
Definition mod_dav_fs.c:32
void dav_buffer_init(apr_pool_t *p, dav_buffer *pbuf, const char *str)
Definition util.c:144
apr_pool_t * dav_fs_pool(const dav_resource *resource)
Definition repos.c:228
void dav_buffer_append(apr_pool_t *p, dav_buffer *pbuf, const char *str)
Definition util.c:152
void dav_dbm_freedatum(dav_db *db, apr_datum_t data)
Definition dbm.c:265
dav_error * dav_dbm_fetch(dav_db *db, apr_datum_t key, apr_datum_t *pvalue)
Definition dbm.c:217
const char * dav_fs_pathname(const dav_resource *resource)
Definition repos.c:233
int dav_dbm_exists(dav_db *db, apr_datum_t key)
Definition dbm.c:246
#define DAV_ERR_LOCK_PARSE_TOKEN
Definition mod_dav.h:233
#define DAV_ERR_LOCK_OPENDB
Definition mod_dav.h:229
dav_error * dav_fs_dir_file_name(const dav_resource *resource, const char **dirpath_p, const char **fname_p)
Definition repos.c:238
#define DEBUG_CR
Definition mod_dav.h:65
void dav_dbm_close(dav_db *db)
Definition dbm.c:212
#define DAV_ERR_LOCK_CORRUPT_DB
Definition mod_dav.h:231
#define DAV_ERR_LOCK_SAVE_LOCK
Definition mod_dav.h:234
dav_error * dav_push_error(apr_pool_t *p, int status, int error_id, const char *desc, dav_error *prev)
Definition util.c:66
dav_error * dav_dbm_open_direct(apr_pool_t *p, const char *pathname, int ro, dav_db **pdb)
Definition dbm.c:132
#define DAV_ERR_LOCK_UNK_STATE_TOKEN
Definition mod_dav.h:232
dav_error * dav_fs_get_locknull_members(const dav_resource *resource, dav_buffer *pbuf)
Definition lock.c:912
#define DAV_TIMEOUT_INFINITE
Definition mod_dav.h:1314
#define DAV_FS_STATE_DIR
Definition repos.h:29
void dav_set_bufsize(apr_pool_t *p, dav_buffer *pbuf, apr_size_t size)
Definition util.c:122
void dav_buffer_place(apr_pool_t *p, dav_buffer *pbuf, const char *str)
Definition util.c:163
#define DAV_FS_LOCK_NULL_FILE
Definition repos.h:31
dav_error * dav_new_error(apr_pool_t *p, int status, int error_id, apr_status_t aprerr, const char *desc)
Definition util.c:36
@ DAV_LOCKREC_DIRECT
Definition mod_dav.h:1353
@ DAV_LOCKREC_INDIRECT_PARTIAL
Definition mod_dav.h:1355
@ DAV_LOCKREC_INDIRECT
Definition mod_dav.h:1354
#define ap_strstr_c(s, c)
Definition httpd.h:2361
apr_size_t size
apr_uint32_t val
Definition apr_atomic.h:66
#define APR_SUCCESS
Definition apr_errno.h:225
int apr_status_t
Definition apr_errno.h:44
const char * key
apr_seek_where_t apr_off_t * offset
const char apr_file_t * file
#define APR_READ
Definition apr_file_io.h:93
#define APR_BINARY
Definition apr_file_io.h:98
#define APR_WRITE
Definition apr_file_io.h:94
#define APR_TRUNCATE
Definition apr_file_io.h:97
#define APR_CREATE
Definition apr_file_io.h:95
#define APR_OS_DEFAULT
#define APR_FINFO_MIN
const char * fname
#define APR_FINFO_LINK
#define APR_FINFO_SIZE
#define memmove(a, b, c)
#define apr_pcalloc(p, size)
Definition apr_pools.h:465
apr_dir_t * dir
apr_size_t const char * filename
Definition apr_shm.h:72
apr_int32_t apr_int32_t apr_int32_t err
Apache Logging library.
HTTP Daemon routines.
static dav_error * dav_fs_create_lock(dav_lockdb *lockdb, const dav_resource *resource, dav_lock **lock)
Definition lock.c:976
static dav_error * dav_fs_load_locknull_list(apr_pool_t *p, const char *dirpath, dav_buffer *pbuf)
Definition lock.c:745
static const char * dav_fs_format_locktoken(apr_pool_t *p, const dav_locktoken *locktoken)
Definition lock.c:273
static dav_error * dav_fs_find_lock(dav_lockdb *lockdb, const dav_resource *resource, const dav_locktoken *locktoken, int partial_ok, dav_lock **lock)
Definition lock.c:1070
struct dav_lock_discovery dav_lock_discovery
static dav_error * dav_fs_save_lock_record(dav_lockdb *lockdb, apr_datum_t key, dav_lock_discovery *direct, dav_lock_indirect *indirect)
Definition lock.c:414
static dav_error * dav_fs_add_locknull_state(dav_lockdb *lockdb, const dav_resource *resource)
Definition lock.c:925
static dav_error * dav_fs_remove_lock(dav_lockdb *lockdb, const dav_resource *resource, const dav_locktoken *locktoken)
Definition lock.c:1246
static dav_error * dav_fs_resolve(dav_lockdb *lockdb, dav_lock_indirect *indirect, dav_lock_discovery **direct, dav_lock_discovery **ref_dp, dav_lock_indirect **ref_ip)
Definition lock.c:664
static dav_error * dav_fs_really_open_lockdb(dav_lockdb *lockdb)
Definition lock.c:300
static int dav_fs_do_refresh(dav_lock_discovery *dp, const dav_locktoken_list *ltl, time_t new_time)
Definition lock.c:1319
static const char * dav_fs_get_supportedlock(const dav_resource *resource)
Definition lock.c:714
static int dav_fs_compare_locktoken(const dav_locktoken *lt1, const dav_locktoken *lt2)
Definition lock.c:288
static dav_error * dav_fs_refresh_locks(dav_lockdb *lockdb, const dav_resource *resource, const dav_locktoken_list *ltl, time_t new_time, dav_lock **locks)
Definition lock.c:1337
static dav_error * dav_fs_load_lock_record(dav_lockdb *lockdb, apr_datum_t key, int add_method, dav_lock_discovery **direct, dav_lock_indirect **indirect)
Definition lock.c:521
static dav_lock * dav_fs_alloc_lock(dav_lockdb *lockdb, apr_datum_t key, const dav_locktoken *locktoken)
Definition lock.c:216
static int dav_fs_lock_expired(time_t expires)
Definition lock.c:404
#define DAV_APPEND_LIST
Definition lock.c:78
#define DAV_FALSE
Definition lock.c:75
struct dav_lock_indirect dav_lock_indirect
struct dav_lock_discovery_fixed dav_lock_discovery_fixed
#define DAV_LOCK_DIRECT
Definition lock.c:81
static dav_error * dav_fs_open_lockdb(request_rec *r, int ro, int force, dav_lockdb **lockdb)
Definition lock.c:333
#define DAV_CREATE_LIST
Definition lock.c:77
const dav_hooks_locks dav_hooks_locks_fs
Definition lock.c:1426
static apr_datum_t dav_fs_build_key(apr_pool_t *p, const dav_resource *resource)
Definition lock.c:380
#define dav_size_indirect(a)
Definition lock.c:161
static dav_error * dav_fs_parse_locktoken(apr_pool_t *p, const char *char_token, dav_locktoken **locktoken_p)
Definition lock.c:242
#define DAV_TRUE
Definition lock.c:74
static dav_error * dav_fs_get_locks(dav_lockdb *lockdb, const dav_resource *resource, int calltype, dav_lock **locks)
Definition lock.c:993
static dav_error * dav_fs_remove_locknull_member(apr_pool_t *p, const char *filename, dav_buffer *pbuf)
Definition lock.c:865
#define DAV_TYPE_FNAME
Definition lock.c:88
#define dav_size_direct(a)
Definition lock.c:154
static dav_error * dav_fs_append_locks(dav_lockdb *lockdb, const dav_resource *resource, int make_indirect, const dav_lock *lock)
Definition lock.c:1162
static dav_error * dav_fs_remove_locknull_state(dav_lockdb *lockdb, const dav_resource *resource)
Definition lock.c:959
static dav_error * dav_fs_save_locknull_list(apr_pool_t *p, const char *dirpath, dav_buffer *pbuf)
Definition lock.c:809
static dav_error * dav_fs_has_locks(dav_lockdb *lockdb, const dav_resource *resource, int *locks_present)
Definition lock.c:1134
#define dav_compare_locktoken(plt1, plt2)
Definition lock.c:102
static void dav_fs_close_lockdb(dav_lockdb *lockdb)
Definition lock.c:370
#define DAV_LOCK_INDIRECT
Definition lock.c:82
apr_pool_t * p
Definition md_event.c:32
DAV extension module for Apache 2.0.*.
#define DAV_GETLOCKS_COMPLETE
Definition mod_dav.h:1568
#define DAV_GETLOCKS_RESOLVED
Definition mod_dav.h:1566
return NULL
Definition mod_so.c:359
Declarations for the filesystem repository implementation.
apr_size_t dsize
Definition apr_dbm.h:52
char * dptr
Definition apr_dbm.h:50
apr_off_t size
Definition dbm.c:52
dav_lock pub
Definition lock.c:204
dav_lock_private priv
Definition lock.c:205
dav_locktoken token
Definition lock.c:206
struct dav_lock_discovery * next
Definition lock.c:130
const char * auth_user
Definition lock.c:129
const char * owner
Definition lock.c:128
struct dav_lock_discovery_fixed f
Definition lock.c:125
dav_locktoken * locktoken
Definition lock.c:127
dav_locktoken * locktoken
Definition lock.c:141
time_t timeout
Definition lock.c:144
apr_datum_t key
Definition lock.c:142
struct dav_lock_indirect * next
Definition lock.c:143
apr_datum_t key
Definition lock.c:200
dav_lockdb pub
Definition lock.c:191
dav_lockdb_private priv
Definition lock.c:192
apr_pool_t * pool
Definition lock.c:183
const char * lockdb_path
Definition lock.c:184
dav_db * db
Definition lock.c:187
request_rec * r
Definition lock.c:182
dav_lockdb_private * info
Definition mod_dav.h:1337
apr_uuid_t uuid
Definition lock.c:100
A structure that represents the current request.
Definition httpd.h:845
apr_pool_t * pool
Definition httpd.h:847