~ubuntu-branches/ubuntu/feisty/apache2/feisty

« back to all changes in this revision

Viewing changes to modules/dav/lock/locks.c

  • Committer: Bazaar Package Importer
  • Author(s): Andreas Barth
  • Date: 2006-12-09 21:05:45 UTC
  • mfrom: (0.6.1 upstream)
  • Revision ID: james.westby@ubuntu.com-20061209210545-h70s0xaqc2v8vqr2
Tags: 2.2.3-3.2
* Non-maintainer upload.
* 043_ajp_connection_reuse: Patch from upstream Bugzilla, fixing a critical
  issue with regard to connection reuse in mod_proxy_ajp.
  Closes: #396265

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
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
 * Generic DAV lock implementation that a DAV provider can use.
 
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
 
 
34
#include "locks.h"
 
35
 
 
36
 
 
37
/* ---------------------------------------------------------------
 
38
 *
 
39
 * Lock database primitives
 
40
 *
 
41
 */
 
42
 
 
43
/*
 
44
 * LOCK DATABASES
 
45
 *
 
46
 * Lockdiscovery information is stored in the single lock database specified
 
47
 * by the DAVGenericLockDB directive.  Information about this db is stored in
 
48
 * the per-dir configuration.
 
49
 *
 
50
 * KEY
 
51
 *
 
52
 * The database is keyed by a key_type unsigned char (DAV_TYPE_FNAME)
 
53
 * followed by full path.
 
54
 *
 
55
 * VALUE
 
56
 *
 
57
 * The value consists of a list of elements.
 
58
 *    DIRECT LOCK:     [char      (DAV_LOCK_DIRECT),
 
59
 *                      char      (dav_lock_scope),
 
60
 *                      char      (dav_lock_type),
 
61
 *                      int        depth,
 
62
 *                      time_t     expires,
 
63
 *                      apr_uuid_t locktoken,
 
64
 *                      char[]     owner,
 
65
 *                      char[]     auth_user]
 
66
 *
 
67
 *    INDIRECT LOCK:   [char      (DAV_LOCK_INDIRECT),
 
68
 *                      apr_uuid_t locktoken,
 
69
 *                      time_t     expires,
 
70
 *                      int        key_size,
 
71
 *                      char[]     key]
 
72
 *       The key is to the collection lock that resulted in this indirect lock
 
73
 */
 
74
 
 
75
#define DAV_TRUE                    1
 
76
#define DAV_FALSE                   0
 
77
 
 
78
#define DAV_CREATE_LIST            23
 
79
#define DAV_APPEND_LIST            24
 
80
 
 
81
/* Stored lock_discovery prefix */
 
82
#define DAV_LOCK_DIRECT             1
 
83
#define DAV_LOCK_INDIRECT           2
 
84
 
 
85
#define DAV_TYPE_FNAME             11
 
86
 
 
87
/* Use the opaquelock scheme for locktokens */
 
88
struct dav_locktoken {
 
89
    apr_uuid_t uuid;
 
90
};
 
91
#define dav_compare_locktoken(plt1, plt2) \
 
92
                memcmp(&(plt1)->uuid, &(plt2)->uuid, sizeof((plt1)->uuid))
 
93
 
 
94
 
 
95
/* #################################################################
 
96
 * ### keep these structures (internal) or move fully to dav_lock?
 
97
 */
 
98
 
 
99
/*
 
100
 * We need to reliably size the fixed-length portion of
 
101
 * dav_lock_discovery; best to separate it into another
 
102
 * struct for a convenient sizeof, unless we pack lock_discovery.
 
103
 */
 
104
typedef struct dav_lock_discovery_fixed
 
105
{
 
106
    char scope;
 
107
    char type;
 
108
    int depth;
 
109
    time_t timeout;
 
110
} dav_lock_discovery_fixed;
 
111
 
 
112
typedef struct dav_lock_discovery
 
113
{
 
114
    struct dav_lock_discovery_fixed f;
 
115
 
 
116
    dav_locktoken *locktoken;
 
117
    const char *owner;     /* owner field from activelock */
 
118
    const char *auth_user; /* authenticated user who created the lock */
 
119
    struct dav_lock_discovery *next;
 
120
} dav_lock_discovery;
 
121
 
 
122
/* Indirect locks represent locks inherited from containing collections.
 
123
 * They reference the lock token for the collection the lock is
 
124
 * inherited from. A lock provider may also define a key to the
 
125
 * inherited lock, for fast datbase lookup. The key is opaque outside
 
126
 * the lock provider.
 
127
 */
 
128
typedef struct dav_lock_indirect
 
129
{
 
130
    dav_locktoken *locktoken;
 
131
    apr_datum_t key;
 
132
    struct dav_lock_indirect *next;
 
133
    time_t timeout;
 
134
} dav_lock_indirect;
 
135
 
 
136
/* ################################################################# */
 
137
 
 
138
/*
 
139
 * Stored direct lock info - full lock_discovery length:
 
140
 * prefix + Fixed length + lock token + 2 strings + 2 nulls (one for each
 
141
 * string)
 
142
 */
 
143
#define dav_size_direct(a)  (1 + sizeof(dav_lock_discovery_fixed) \
 
144
                               + sizeof(apr_uuid_t) \
 
145
                               + ((a)->owner ? strlen((a)->owner) : 0) \
 
146
                               + ((a)->auth_user ? strlen((a)->auth_user) : 0) \
 
147
                               + 2)
 
148
 
 
149
/* Stored indirect lock info - lock token and apr_datum_t */
 
150
#define dav_size_indirect(a) (1 + sizeof(apr_uuid_t) \
 
151
                                + sizeof(time_t) \
 
152
                                + sizeof(int) + (a)->key.dsize)
 
153
 
 
154
/*
 
155
 * The lockdb structure.
 
156
 *
 
157
 * The <db> field may be NULL, meaning one of two things:
 
158
 * 1) That we have not actually opened the underlying database (yet). The
 
159
 *    <opened> field should be false.
 
160
 * 2) We opened it readonly and it wasn't present.
 
161
 *
 
162
 * The delayed opening (determined by <opened>) makes creating a lockdb
 
163
 * quick, while deferring the underlying I/O until it is actually required.
 
164
 *
 
165
 * We export the notion of a lockdb, but hide the details of it. Most
 
166
 * implementations will use a database of some kind, but it is certainly
 
167
 * possible that alternatives could be used.
 
168
 */
 
169
struct dav_lockdb_private
 
170
{
 
171
    request_rec *r; /* for accessing the uuid state */
 
172
    apr_pool_t *pool; /* a pool to use */
 
173
    const char *lockdb_path; /* where is the lock database? */
 
174
 
 
175
    int opened; /* we opened the database */
 
176
    apr_dbm_t *db; /* if non-NULL, the lock database */
 
177
};
 
178
 
 
179
typedef struct
 
180
{
 
181
    dav_lockdb pub;
 
182
    dav_lockdb_private priv;
 
183
} dav_lockdb_combined;
 
184
 
 
185
/*
 
186
 * The private part of the lock structure.
 
187
 */
 
188
struct dav_lock_private
 
189
{
 
190
    apr_datum_t key;        /* key into the lock database */
 
191
};
 
192
typedef struct
 
193
{
 
194
    dav_lock pub;
 
195
    dav_lock_private priv;
 
196
    dav_locktoken token;
 
197
} dav_lock_combined;
 
198
 
 
199
/*
 
200
 * This must be forward-declared so the open_lockdb function can use it.
 
201
 */
 
202
extern const dav_hooks_locks dav_hooks_locks_generic;
 
203
 
 
204
static dav_error * dav_generic_dbm_new_error(apr_dbm_t *db, apr_pool_t *p,
 
205
                                             apr_status_t status)
 
206
{
 
207
    int save_errno = errno;
 
208
    int errcode;
 
209
    const char *errstr;
 
210
    dav_error *err;
 
211
    char errbuf[200];
 
212
 
 
213
    if (status == APR_SUCCESS) {
 
214
        return NULL;
 
215
    }
 
216
 
 
217
    /* There might not be a <db> if we had problems creating it. */
 
218
    if (db == NULL) {
 
219
        errcode = 1;
 
220
        errstr = "Could not open property database.";
 
221
    }
 
222
    else {
 
223
        (void) apr_dbm_geterror(db, &errcode, errbuf, sizeof(errbuf));
 
224
        errstr = apr_pstrdup(p, errbuf);
 
225
    }
 
226
 
 
227
    err = dav_new_error(p, HTTP_INTERNAL_SERVER_ERROR, errcode, errstr);
 
228
    err->save_errno = save_errno;
 
229
    return err;
 
230
}
 
231
 
 
232
/* internal function for creating locks */
 
233
static dav_lock *dav_generic_alloc_lock(dav_lockdb *lockdb, apr_datum_t key,
 
234
                                        const dav_locktoken *locktoken)
 
235
{
 
236
    dav_lock_combined *comb;
 
237
 
 
238
    comb = apr_pcalloc(lockdb->info->pool, sizeof(*comb));
 
239
    comb->pub.rectype = DAV_LOCKREC_DIRECT;
 
240
    comb->pub.info = &comb->priv;
 
241
    comb->priv.key = key;
 
242
 
 
243
    if (locktoken == NULL) {
 
244
        comb->pub.locktoken = &comb->token;
 
245
        apr_uuid_get(&comb->token.uuid);
 
246
    }
 
247
    else {
 
248
        comb->pub.locktoken = locktoken;
 
249
    }
 
250
 
 
251
    return &comb->pub;
 
252
}
 
253
 
 
254
/*
 
255
 * dav_generic_parse_locktoken
 
256
 *
 
257
 * Parse an opaquelocktoken URI into a locktoken.
 
258
 */
 
259
static dav_error * dav_generic_parse_locktoken(apr_pool_t *p,
 
260
                                               const char *char_token,
 
261
                                               dav_locktoken **locktoken_p)
 
262
{
 
263
    dav_locktoken *locktoken;
 
264
 
 
265
    if (ap_strstr_c(char_token, "opaquelocktoken:") != char_token) {
 
266
        return dav_new_error(p,
 
267
                             HTTP_BAD_REQUEST, DAV_ERR_LOCK_UNK_STATE_TOKEN,
 
268
                             "The lock token uses an unknown State-token "
 
269
                             "format and could not be parsed.");
 
270
    }
 
271
    char_token += 16;
 
272
 
 
273
    locktoken = apr_pcalloc(p, sizeof(*locktoken));
 
274
    if (apr_uuid_parse(&locktoken->uuid, char_token)) {
 
275
        return dav_new_error(p, HTTP_BAD_REQUEST, DAV_ERR_LOCK_PARSE_TOKEN,
 
276
                             "The opaquelocktoken has an incorrect format "
 
277
                             "and could not be parsed.");
 
278
    }
 
279
 
 
280
    *locktoken_p = locktoken;
 
281
    return NULL;
 
282
}
 
283
 
 
284
/*
 
285
 * dav_generic_format_locktoken
 
286
 *
 
287
 * Generate the URI for a locktoken
 
288
 */
 
289
static const char *dav_generic_format_locktoken(apr_pool_t *p,
 
290
                                                const dav_locktoken *locktoken)
 
291
{
 
292
    char buf[APR_UUID_FORMATTED_LENGTH + 1];
 
293
 
 
294
    apr_uuid_format(buf, &locktoken->uuid);
 
295
    return apr_pstrcat(p, "opaquelocktoken:", buf, NULL);
 
296
}
 
297
 
 
298
/*
 
299
 * dav_generic_compare_locktoken
 
300
 *
 
301
 * Determine whether two locktokens are the same
 
302
 */
 
303
static int dav_generic_compare_locktoken(const dav_locktoken *lt1,
 
304
                                         const dav_locktoken *lt2)
 
305
{
 
306
    return dav_compare_locktoken(lt1, lt2);
 
307
}
 
308
 
 
309
/*
 
310
 * dav_generic_really_open_lockdb:
 
311
 *
 
312
 * If the database hasn't been opened yet, then open the thing.
 
313
 */
 
314
static dav_error * dav_generic_really_open_lockdb(dav_lockdb *lockdb)
 
315
{
 
316
    dav_error *err;
 
317
    apr_status_t status;
 
318
 
 
319
    if (lockdb->info->opened) {
 
320
        return NULL;
 
321
    }
 
322
 
 
323
    status = apr_dbm_open(&lockdb->info->db, lockdb->info->lockdb_path,
 
324
                          lockdb->ro ? APR_DBM_READONLY : APR_DBM_RWCREATE,
 
325
                          APR_OS_DEFAULT, lockdb->info->pool);
 
326
 
 
327
    if (status) {
 
328
        err = dav_generic_dbm_new_error(lockdb->info->db, lockdb->info->pool,
 
329
                                        status);
 
330
        return dav_push_error(lockdb->info->pool,
 
331
                              HTTP_INTERNAL_SERVER_ERROR,
 
332
                              DAV_ERR_LOCK_OPENDB,
 
333
                              "Could not open the lock database.",
 
334
                              err);
 
335
    }
 
336
 
 
337
    /* all right. it is opened now. */
 
338
    lockdb->info->opened = 1;
 
339
 
 
340
    return NULL;
 
341
}
 
342
 
 
343
/*
 
344
 * dav_generic_open_lockdb:
 
345
 *
 
346
 * "open" the lock database, as specified in the global server configuration.
 
347
 * If force is TRUE, then the database is opened now, rather than lazily.
 
348
 *
 
349
 * Note that only one can be open read/write.
 
350
 */
 
351
static dav_error * dav_generic_open_lockdb(request_rec *r, int ro, int force,
 
352
                                           dav_lockdb **lockdb)
 
353
{
 
354
    dav_lockdb_combined *comb;
 
355
 
 
356
    comb = apr_pcalloc(r->pool, sizeof(*comb));
 
357
    comb->pub.hooks = &dav_hooks_locks_generic;
 
358
    comb->pub.ro = ro;
 
359
    comb->pub.info = &comb->priv;
 
360
    comb->priv.r = r;
 
361
    comb->priv.pool = r->pool;
 
362
 
 
363
    comb->priv.lockdb_path = dav_generic_get_lockdb_path(r);
 
364
    if (comb->priv.lockdb_path == NULL) {
 
365
        return dav_new_error(r->pool, HTTP_INTERNAL_SERVER_ERROR,
 
366
                             DAV_ERR_LOCK_NO_DB,
 
367
                             "A lock database was not specified with the "
 
368
                             "DAVGenericLockDB directive. One must be "
 
369
                             "specified to use the locking functionality.");
 
370
    }
 
371
 
 
372
    /* done initializing. return it. */
 
373
    *lockdb = &comb->pub;
 
374
 
 
375
    if (force) {
 
376
        /* ### add a higher-level comment? */
 
377
        return dav_generic_really_open_lockdb(*lockdb);
 
378
    }
 
379
 
 
380
    return NULL;
 
381
}
 
382
 
 
383
/*
 
384
 * dav_generic_close_lockdb:
 
385
 *
 
386
 * Close it. Duh.
 
387
 */
 
388
static void dav_generic_close_lockdb(dav_lockdb *lockdb)
 
389
{
 
390
    if (lockdb->info->db != NULL) {
 
391
        apr_dbm_close(lockdb->info->db);
 
392
    }
 
393
    lockdb->info->opened = 0;
 
394
}
 
395
 
 
396
/*
 
397
 * dav_generic_build_key
 
398
 *
 
399
 * Given a pathname, build a DAV_TYPE_FNAME lock database key.
 
400
 */
 
401
static apr_datum_t dav_generic_build_key(apr_pool_t *p,
 
402
                                         const dav_resource *resource)
 
403
{
 
404
    apr_datum_t key;
 
405
    const char *pathname = resource->uri;
 
406
 
 
407
    /* ### does this allocation have a proper lifetime? need to check */
 
408
    /* ### can we use a buffer for this? */
 
409
 
 
410
    /* size is TYPE + pathname + null */
 
411
    key.dsize = strlen(pathname) + 2;
 
412
    key.dptr = apr_palloc(p, key.dsize);
 
413
    *key.dptr = DAV_TYPE_FNAME;
 
414
    memcpy(key.dptr + 1, pathname, key.dsize - 1);
 
415
    if (key.dptr[key.dsize - 2] == '/')
 
416
        key.dptr[--key.dsize - 1] = '\0';
 
417
    return key;
 
418
}
 
419
 
 
420
/*
 
421
 * dav_generic_lock_expired:  return 1 (true) if the given timeout is in the
 
422
 *    past or present (the lock has expired), or 0 (false) if in the future
 
423
 *    (the lock has not yet expired).
 
424
 */
 
425
static int dav_generic_lock_expired(time_t expires)
 
426
{
 
427
    return expires != DAV_TIMEOUT_INFINITE && time(NULL) >= expires;
 
428
}
 
429
 
 
430
/*
 
431
 * dav_generic_save_lock_record:  Saves the lock information specified in the
 
432
 *    direct and indirect lock lists about path into the lock database.
 
433
 *    If direct and indirect == NULL, the key is removed.
 
434
 */
 
435
static dav_error * dav_generic_save_lock_record(dav_lockdb *lockdb,
 
436
                                                apr_datum_t key,
 
437
                                                dav_lock_discovery *direct,
 
438
                                                dav_lock_indirect *indirect)
 
439
{
 
440
    dav_error *err;
 
441
    apr_status_t status;
 
442
    apr_datum_t val = { 0 };
 
443
    char *ptr;
 
444
    dav_lock_discovery *dp = direct;
 
445
    dav_lock_indirect *ip = indirect;
 
446
 
 
447
#if DAV_DEBUG
 
448
    if (lockdb->ro) {
 
449
        return dav_new_error(lockdb->info->pool,
 
450
                             HTTP_INTERNAL_SERVER_ERROR, 0,
 
451
                             "INTERNAL DESIGN ERROR: the lockdb was opened "
 
452
                             "readonly, but an attempt to save locks was "
 
453
                             "performed.");
 
454
    }
 
455
#endif
 
456
 
 
457
    if ((err = dav_generic_really_open_lockdb(lockdb)) != NULL) {
 
458
        /* ### add a higher-level error? */
 
459
        return err;
 
460
    }
 
461
 
 
462
    /* If nothing to save, delete key */
 
463
    if (dp == NULL && ip == NULL) {
 
464
        /* don't fail if the key is not present */
 
465
        /* ### but what about other errors? */
 
466
        apr_dbm_delete(lockdb->info->db, key);
 
467
        return NULL;
 
468
    }
 
469
 
 
470
    while(dp) {
 
471
        val.dsize += dav_size_direct(dp);
 
472
        dp = dp->next;
 
473
    }
 
474
    while(ip) {
 
475
        val.dsize += dav_size_indirect(ip);
 
476
        ip = ip->next;
 
477
    }
 
478
 
 
479
    /* ### can this be apr_palloc() ? */
 
480
    /* ### hmmm.... investigate the use of a buffer here */
 
481
    ptr = val.dptr = apr_pcalloc(lockdb->info->pool, val.dsize);
 
482
    dp  = direct;
 
483
    ip  = indirect;
 
484
 
 
485
    while(dp) {
 
486
        /* Direct lock - lock_discovery struct follows */
 
487
        *ptr++ = DAV_LOCK_DIRECT;
 
488
        memcpy(ptr, dp, sizeof(dp->f));        /* Fixed portion of struct */
 
489
        ptr += sizeof(dp->f);
 
490
        memcpy(ptr, dp->locktoken, sizeof(*dp->locktoken));
 
491
        ptr += sizeof(*dp->locktoken);
 
492
        if (dp->owner == NULL) {
 
493
            *ptr++ = '\0';
 
494
        }
 
495
        else {
 
496
            memcpy(ptr, dp->owner, strlen(dp->owner) + 1);
 
497
            ptr += strlen(dp->owner) + 1;
 
498
        }
 
499
        if (dp->auth_user == NULL) {
 
500
            *ptr++ = '\0';
 
501
        }
 
502
        else {
 
503
            memcpy(ptr, dp->auth_user, strlen(dp->auth_user) + 1);
 
504
            ptr += strlen(dp->auth_user) + 1;
 
505
        }
 
506
 
 
507
        dp = dp->next;
 
508
    }
 
509
 
 
510
    while(ip) {
 
511
        /* Indirect lock prefix */
 
512
        *ptr++ = DAV_LOCK_INDIRECT;
 
513
 
 
514
        memcpy(ptr, ip->locktoken, sizeof(*ip->locktoken));
 
515
        ptr += sizeof(*ip->locktoken);
 
516
 
 
517
        memcpy(ptr, &ip->timeout, sizeof(ip->timeout));
 
518
        ptr += sizeof(ip->timeout);
 
519
 
 
520
        memcpy(ptr, &ip->key.dsize, sizeof(ip->key.dsize));
 
521
        ptr += sizeof(ip->key.dsize);
 
522
 
 
523
        memcpy(ptr, ip->key.dptr, ip->key.dsize);
 
524
        ptr += ip->key.dsize;
 
525
 
 
526
        ip = ip->next;
 
527
    }
 
528
 
 
529
    if ((status = apr_dbm_store(lockdb->info->db, key, val)) != APR_SUCCESS) {
 
530
        /* ### more details? add an error_id? */
 
531
        err = dav_generic_dbm_new_error(lockdb->info->db, lockdb->info->pool,
 
532
                                        status);
 
533
        return dav_push_error(lockdb->info->pool,
 
534
                              HTTP_INTERNAL_SERVER_ERROR,
 
535
                              DAV_ERR_LOCK_SAVE_LOCK,
 
536
                              "Could not save lock information.",
 
537
                              err);
 
538
    }
 
539
 
 
540
    return NULL;
 
541
}
 
542
 
 
543
/*
 
544
 * dav_load_lock_record:  Reads lock information about key from lock db;
 
545
 *    creates linked lists of the direct and indirect locks.
 
546
 *
 
547
 *    If add_method = DAV_APPEND_LIST, the result will be appended to the
 
548
 *    head of the direct and indirect lists supplied.
 
549
 *
 
550
 *    Passive lock removal:  If lock has timed out, it will not be returned.
 
551
 *    ### How much "logging" does RFC 2518 require?
 
552
 */
 
553
static dav_error * dav_generic_load_lock_record(dav_lockdb *lockdb,
 
554
                                                apr_datum_t key,
 
555
                                                int add_method,
 
556
                                                dav_lock_discovery **direct,
 
557
                                                dav_lock_indirect **indirect)
 
558
{
 
559
    apr_pool_t *p = lockdb->info->pool;
 
560
    dav_error *err;
 
561
    apr_status_t status;
 
562
    apr_size_t offset = 0;
 
563
    int need_save = DAV_FALSE;
 
564
    apr_datum_t val = { 0 };
 
565
    dav_lock_discovery *dp;
 
566
    dav_lock_indirect *ip;
 
567
 
 
568
    if (add_method != DAV_APPEND_LIST) {
 
569
        *direct = NULL;
 
570
        *indirect = NULL;
 
571
    }
 
572
 
 
573
    if ((err = dav_generic_really_open_lockdb(lockdb)) != NULL) {
 
574
        /* ### add a higher-level error? */
 
575
        return err;
 
576
    }
 
577
 
 
578
    /*
 
579
     * If we opened readonly and the db wasn't there, then there are no
 
580
     * locks for this resource. Just exit.
 
581
     */
 
582
    if (lockdb->info->db == NULL) {
 
583
        return NULL;
 
584
    }
 
585
 
 
586
    if ((status = apr_dbm_fetch(lockdb->info->db, key, &val)) != APR_SUCCESS) {
 
587
        return dav_generic_dbm_new_error(lockdb->info->db, p, status);
 
588
    }
 
589
 
 
590
    if (!val.dsize) {
 
591
        return NULL;
 
592
    }
 
593
 
 
594
    while (offset < val.dsize) {
 
595
        switch (*(val.dptr + offset++)) {
 
596
        case DAV_LOCK_DIRECT:
 
597
            /* Create and fill a dav_lock_discovery structure */
 
598
 
 
599
            dp = apr_pcalloc(p, sizeof(*dp));
 
600
 
 
601
            /* Copy the dav_lock_discovery_fixed portion */
 
602
            memcpy(dp, val.dptr + offset, sizeof(dp->f));
 
603
            offset += sizeof(dp->f);
 
604
 
 
605
            /* Copy the lock token. */
 
606
            dp->locktoken = apr_palloc(p, sizeof(*dp->locktoken));
 
607
            memcpy(dp->locktoken, val.dptr + offset, sizeof(*dp->locktoken));
 
608
            offset += sizeof(*dp->locktoken);
 
609
 
 
610
            /* Do we have an owner field? */
 
611
            if (*(val.dptr + offset) == '\0') {
 
612
                ++offset;
 
613
            }
 
614
            else {
 
615
                apr_size_t len = strlen(val.dptr + offset);
 
616
                dp->owner = apr_pstrmemdup(p, val.dptr + offset, len);
 
617
                offset += len + 1;
 
618
            }
 
619
 
 
620
            if (*(val.dptr + offset) == '\0') {
 
621
                ++offset;
 
622
            }
 
623
            else {
 
624
                apr_size_t len = strlen(val.dptr + offset);
 
625
                dp->auth_user = apr_pstrmemdup(p, val.dptr + offset, len);
 
626
                offset += len + 1;
 
627
            }
 
628
 
 
629
            if (!dav_generic_lock_expired(dp->f.timeout)) {
 
630
                dp->next = *direct;
 
631
                *direct = dp;
 
632
            }
 
633
            else {
 
634
                need_save = DAV_TRUE;
 
635
            }
 
636
            break;
 
637
 
 
638
        case DAV_LOCK_INDIRECT:
 
639
            /* Create and fill a dav_lock_indirect structure */
 
640
 
 
641
            ip = apr_pcalloc(p, sizeof(*ip));
 
642
            ip->locktoken = apr_palloc(p, sizeof(*ip->locktoken));
 
643
            memcpy(ip->locktoken, val.dptr + offset, sizeof(*ip->locktoken));
 
644
            offset += sizeof(*ip->locktoken);
 
645
            memcpy(&ip->timeout, val.dptr + offset, sizeof(ip->timeout));
 
646
            offset += sizeof(ip->timeout);
 
647
            /* length of datum */
 
648
            ip->key.dsize = *((int *) (val.dptr + offset));
 
649
            offset += sizeof(ip->key.dsize);
 
650
            ip->key.dptr = apr_palloc(p, ip->key.dsize);
 
651
            memcpy(ip->key.dptr, val.dptr + offset, ip->key.dsize);
 
652
            offset += ip->key.dsize;
 
653
 
 
654
            if (!dav_generic_lock_expired(ip->timeout)) {
 
655
                ip->next = *indirect;
 
656
                *indirect = ip;
 
657
            }
 
658
            else {
 
659
                need_save = DAV_TRUE;
 
660
            }
 
661
 
 
662
            break;
 
663
 
 
664
        default:
 
665
            apr_dbm_freedatum(lockdb->info->db, val);
 
666
 
 
667
            /* ### should use a computed_desc and insert corrupt token data */
 
668
            --offset;
 
669
            return dav_new_error(p,
 
670
                                 HTTP_INTERNAL_SERVER_ERROR,
 
671
                                 DAV_ERR_LOCK_CORRUPT_DB,
 
672
                                 apr_psprintf(p,
 
673
                                             "The lock database was found to "
 
674
                                             "be corrupt. offset %"
 
675
                                             APR_SIZE_T_FMT ", c=%02x",
 
676
                                             offset, val.dptr[offset]));
 
677
        }
 
678
    }
 
679
 
 
680
    apr_dbm_freedatum(lockdb->info->db, val);
 
681
 
 
682
    /* Clean up this record if we found expired locks */
 
683
    /*
 
684
     * ### shouldn't do this if we've been opened READONLY. elide the
 
685
     * ### timed-out locks from the response, but don't save that info back
 
686
     */
 
687
    if (need_save == DAV_TRUE) {
 
688
        return dav_generic_save_lock_record(lockdb, key, *direct, *indirect);
 
689
    }
 
690
 
 
691
    return NULL;
 
692
}
 
693
 
 
694
/* resolve <indirect>, returning <*direct> */
 
695
static dav_error * dav_generic_resolve(dav_lockdb *lockdb,
 
696
                                       dav_lock_indirect *indirect,
 
697
                                       dav_lock_discovery **direct,
 
698
                                       dav_lock_discovery **ref_dp,
 
699
                                       dav_lock_indirect **ref_ip)
 
700
{
 
701
    dav_error *err;
 
702
    dav_lock_discovery *dir;
 
703
    dav_lock_indirect *ind;
 
704
 
 
705
    if ((err = dav_generic_load_lock_record(lockdb, indirect->key,
 
706
                                       DAV_CREATE_LIST,
 
707
                                       &dir, &ind)) != NULL) {
 
708
        /* ### insert a higher-level description? */
 
709
        return err;
 
710
    }
 
711
    if (ref_dp != NULL) {
 
712
        *ref_dp = dir;
 
713
        *ref_ip = ind;
 
714
    }
 
715
 
 
716
    for (; dir != NULL; dir = dir->next) {
 
717
        if (!dav_compare_locktoken(indirect->locktoken, dir->locktoken)) {
 
718
            *direct = dir;
 
719
            return NULL;
 
720
        }
 
721
    }
 
722
 
 
723
    /* No match found (but we should have found one!) */
 
724
 
 
725
    /* ### use a different description and/or error ID? */
 
726
    return dav_new_error(lockdb->info->pool,
 
727
                         HTTP_INTERNAL_SERVER_ERROR,
 
728
                         DAV_ERR_LOCK_CORRUPT_DB,
 
729
                         "The lock database was found to be corrupt. "
 
730
                         "An indirect lock's direct lock could not "
 
731
                         "be found.");
 
732
}
 
733
 
 
734
/* ---------------------------------------------------------------
 
735
 *
 
736
 * Property-related lock functions
 
737
 *
 
738
 */
 
739
 
 
740
/*
 
741
 * dav_generic_get_supportedlock:  Returns a static string for all
 
742
 *    supportedlock properties. I think we save more returning a static string
 
743
 *    than constructing it every time, though it might look cleaner.
 
744
 */
 
745
static const char *dav_generic_get_supportedlock(const dav_resource *resource)
 
746
{
 
747
    static const char supported[] = DEBUG_CR
 
748
        "<D:lockentry>" DEBUG_CR
 
749
        "<D:lockscope><D:exclusive/></D:lockscope>" DEBUG_CR
 
750
        "<D:locktype><D:write/></D:locktype>" DEBUG_CR
 
751
        "</D:lockentry>" DEBUG_CR
 
752
        "<D:lockentry>" DEBUG_CR
 
753
        "<D:lockscope><D:shared/></D:lockscope>" DEBUG_CR
 
754
        "<D:locktype><D:write/></D:locktype>" DEBUG_CR
 
755
        "</D:lockentry>" DEBUG_CR;
 
756
 
 
757
    return supported;
 
758
}
 
759
 
 
760
/* ---------------------------------------------------------------
 
761
 *
 
762
 * General lock functions
 
763
 *
 
764
 */
 
765
 
 
766
static dav_error * dav_generic_remove_locknull_state(dav_lockdb *lockdb,
 
767
                                                 const dav_resource *resource)
 
768
{
 
769
    /* We don't need to do anything. */
 
770
    return NULL;
 
771
}
 
772
 
 
773
static dav_error * dav_generic_create_lock(dav_lockdb *lockdb,
 
774
                                      const dav_resource *resource,
 
775
                                      dav_lock **lock)
 
776
{
 
777
    apr_datum_t key;
 
778
 
 
779
    key = dav_generic_build_key(lockdb->info->pool, resource);
 
780
 
 
781
    *lock = dav_generic_alloc_lock(lockdb, key, NULL);
 
782
 
 
783
    (*lock)->is_locknull = !resource->exists;
 
784
 
 
785
    return NULL;
 
786
}
 
787
 
 
788
static dav_error * dav_generic_get_locks(dav_lockdb *lockdb,
 
789
                                         const dav_resource *resource,
 
790
                                         int calltype,
 
791
                                         dav_lock **locks)
 
792
{
 
793
    apr_pool_t *p = lockdb->info->pool;
 
794
    apr_datum_t key;
 
795
    dav_error *err;
 
796
    dav_lock *lock = NULL;
 
797
    dav_lock *newlock;
 
798
    dav_lock_discovery *dp;
 
799
    dav_lock_indirect *ip;
 
800
 
 
801
#if DAV_DEBUG
 
802
    if (calltype == DAV_GETLOCKS_COMPLETE) {
 
803
        return dav_new_error(lockdb->info->pool,
 
804
                             HTTP_INTERNAL_SERVER_ERROR, 0,
 
805
                             "INTERNAL DESIGN ERROR: DAV_GETLOCKS_COMPLETE "
 
806
                             "is not yet supported");
 
807
    }
 
808
#endif
 
809
 
 
810
    key = dav_generic_build_key(p, resource);
 
811
    if ((err = dav_generic_load_lock_record(lockdb, key, DAV_CREATE_LIST,
 
812
                                            &dp, &ip)) != NULL) {
 
813
        /* ### push a higher-level desc? */
 
814
        return err;
 
815
    }
 
816
 
 
817
    /* copy all direct locks to the result list */
 
818
    for (; dp != NULL; dp = dp->next) {
 
819
        newlock = dav_generic_alloc_lock(lockdb, key, dp->locktoken);
 
820
        newlock->is_locknull = !resource->exists;
 
821
        newlock->scope = dp->f.scope;
 
822
        newlock->type = dp->f.type;
 
823
        newlock->depth = dp->f.depth;
 
824
        newlock->timeout = dp->f.timeout;
 
825
        newlock->owner = dp->owner;
 
826
        newlock->auth_user = dp->auth_user;
 
827
 
 
828
        /* hook into the result list */
 
829
        newlock->next = lock;
 
830
        lock = newlock;
 
831
    }
 
832
 
 
833
    /* copy all the indirect locks to the result list. resolve as needed. */
 
834
    for (; ip != NULL; ip = ip->next) {
 
835
        newlock = dav_generic_alloc_lock(lockdb, ip->key, ip->locktoken);
 
836
        newlock->is_locknull = !resource->exists;
 
837
 
 
838
        if (calltype == DAV_GETLOCKS_RESOLVED) {
 
839
            err = dav_generic_resolve(lockdb, ip, &dp, NULL, NULL);
 
840
            if (err != NULL) {
 
841
                /* ### push a higher-level desc? */
 
842
                return err;
 
843
            }
 
844
 
 
845
            newlock->scope = dp->f.scope;
 
846
            newlock->type = dp->f.type;
 
847
            newlock->depth = dp->f.depth;
 
848
            newlock->timeout = dp->f.timeout;
 
849
            newlock->owner = dp->owner;
 
850
            newlock->auth_user = dp->auth_user;
 
851
        }
 
852
        else {
 
853
            /* DAV_GETLOCKS_PARTIAL */
 
854
            newlock->rectype = DAV_LOCKREC_INDIRECT_PARTIAL;
 
855
        }
 
856
 
 
857
        /* hook into the result list */
 
858
        newlock->next = lock;
 
859
        lock = newlock;
 
860
    }
 
861
 
 
862
    *locks = lock;
 
863
    return NULL;
 
864
}
 
865
 
 
866
static dav_error * dav_generic_find_lock(dav_lockdb *lockdb,
 
867
                                         const dav_resource *resource,
 
868
                                         const dav_locktoken *locktoken,
 
869
                                         int partial_ok,
 
870
                                         dav_lock **lock)
 
871
{
 
872
    dav_error *err;
 
873
    apr_datum_t key;
 
874
    dav_lock_discovery *dp;
 
875
    dav_lock_indirect *ip;
 
876
 
 
877
    *lock = NULL;
 
878
 
 
879
    key = dav_generic_build_key(lockdb->info->pool, resource);
 
880
    if ((err = dav_generic_load_lock_record(lockdb, key, DAV_CREATE_LIST,
 
881
                                       &dp, &ip)) != NULL) {
 
882
        /* ### push a higher-level desc? */
 
883
        return err;
 
884
    }
 
885
 
 
886
    for (; dp != NULL; dp = dp->next) {
 
887
        if (!dav_compare_locktoken(locktoken, dp->locktoken)) {
 
888
            *lock = dav_generic_alloc_lock(lockdb, key, locktoken);
 
889
            (*lock)->is_locknull = !resource->exists;
 
890
            (*lock)->scope = dp->f.scope;
 
891
            (*lock)->type = dp->f.type;
 
892
            (*lock)->depth = dp->f.depth;
 
893
            (*lock)->timeout = dp->f.timeout;
 
894
            (*lock)->owner = dp->owner;
 
895
            (*lock)->auth_user = dp->auth_user;
 
896
            return NULL;
 
897
        }
 
898
    }
 
899
 
 
900
    for (; ip != NULL; ip = ip->next) {
 
901
        if (!dav_compare_locktoken(locktoken, ip->locktoken)) {
 
902
            *lock = dav_generic_alloc_lock(lockdb, ip->key, locktoken);
 
903
            (*lock)->is_locknull = !resource->exists;
 
904
 
 
905
            /* ### nobody uses the resolving right now! */
 
906
            if (partial_ok) {
 
907
                (*lock)->rectype = DAV_LOCKREC_INDIRECT_PARTIAL;
 
908
            }
 
909
            else {
 
910
                (*lock)->rectype = DAV_LOCKREC_INDIRECT;
 
911
                if ((err = dav_generic_resolve(lockdb, ip, &dp,
 
912
                                          NULL, NULL)) != NULL) {
 
913
                    /* ### push a higher-level desc? */
 
914
                    return err;
 
915
                }
 
916
                (*lock)->scope = dp->f.scope;
 
917
                (*lock)->type = dp->f.type;
 
918
                (*lock)->depth = dp->f.depth;
 
919
                (*lock)->timeout = dp->f.timeout;
 
920
                (*lock)->owner = dp->owner;
 
921
                (*lock)->auth_user = dp->auth_user;
 
922
            }
 
923
            return NULL;
 
924
        }
 
925
    }
 
926
 
 
927
    return NULL;
 
928
}
 
929
 
 
930
static dav_error * dav_generic_has_locks(dav_lockdb *lockdb,
 
931
                                         const dav_resource *resource,
 
932
                                         int *locks_present)
 
933
{
 
934
    dav_error *err;
 
935
    apr_datum_t key;
 
936
 
 
937
    *locks_present = 0;
 
938
 
 
939
    if ((err = dav_generic_really_open_lockdb(lockdb)) != NULL) {
 
940
        /* ### insert a higher-level error description */
 
941
        return err;
 
942
    }
 
943
 
 
944
    /*
 
945
     * If we opened readonly and the db wasn't there, then there are no
 
946
     * locks for this resource. Just exit.
 
947
     */
 
948
    if (lockdb->info->db == NULL)
 
949
        return NULL;
 
950
 
 
951
    key = dav_generic_build_key(lockdb->info->pool, resource);
 
952
 
 
953
    *locks_present = apr_dbm_exists(lockdb->info->db, key);
 
954
 
 
955
    return NULL;
 
956
}
 
957
 
 
958
static dav_error * dav_generic_append_locks(dav_lockdb *lockdb,
 
959
                                            const dav_resource *resource,
 
960
                                            int make_indirect,
 
961
                                            const dav_lock *lock)
 
962
{
 
963
    apr_pool_t *p = lockdb->info->pool;
 
964
    dav_error *err;
 
965
    dav_lock_indirect *ip;
 
966
    dav_lock_discovery *dp;
 
967
    apr_datum_t key;
 
968
 
 
969
    key = dav_generic_build_key(lockdb->info->pool, resource);
 
970
 
 
971
    err = dav_generic_load_lock_record(lockdb, key, 0, &dp, &ip);
 
972
    if (err != NULL) {
 
973
        /* ### maybe add in a higher-level description */
 
974
        return err;
 
975
    }
 
976
 
 
977
    /*
 
978
     * ### when we store the lock more directly, we need to update
 
979
     * ### lock->rectype and lock->is_locknull
 
980
     */
 
981
 
 
982
    if (make_indirect) {
 
983
        for (; lock != NULL; lock = lock->next) {
 
984
 
 
985
            /* ### this works for any <lock> rectype */
 
986
            dav_lock_indirect *newi = apr_pcalloc(p, sizeof(*newi));
 
987
 
 
988
            /* ### shut off the const warning for now */
 
989
            newi->locktoken = (dav_locktoken *)lock->locktoken;
 
990
            newi->timeout   = lock->timeout;
 
991
            newi->key       = lock->info->key;
 
992
            newi->next      = ip;
 
993
            ip              = newi;
 
994
        }
 
995
    }
 
996
    else {
 
997
        for (; lock != NULL; lock = lock->next) {
 
998
            /* create and link in the right kind of lock */
 
999
 
 
1000
            if (lock->rectype == DAV_LOCKREC_DIRECT) {
 
1001
                dav_lock_discovery *newd = apr_pcalloc(p, sizeof(*newd));
 
1002
 
 
1003
                newd->f.scope = lock->scope;
 
1004
                newd->f.type = lock->type;
 
1005
                newd->f.depth = lock->depth;
 
1006
                newd->f.timeout = lock->timeout;
 
1007
                /* ### shut off the const warning for now */
 
1008
                newd->locktoken = (dav_locktoken *)lock->locktoken;
 
1009
                newd->owner = lock->owner;
 
1010
                newd->auth_user = lock->auth_user;
 
1011
                newd->next = dp;
 
1012
                dp = newd;
 
1013
            }
 
1014
            else {
 
1015
                /* DAV_LOCKREC_INDIRECT(_PARTIAL) */
 
1016
 
 
1017
                dav_lock_indirect *newi = apr_pcalloc(p, sizeof(*newi));
 
1018
 
 
1019
                /* ### shut off the const warning for now */
 
1020
                newi->locktoken = (dav_locktoken *)lock->locktoken;
 
1021
                newi->key       = lock->info->key;
 
1022
                newi->next      = ip;
 
1023
                ip              = newi;
 
1024
            }
 
1025
        }
 
1026
    }
 
1027
 
 
1028
    if ((err = dav_generic_save_lock_record(lockdb, key, dp, ip)) != NULL) {
 
1029
        /* ### maybe add a higher-level description */
 
1030
        return err;
 
1031
    }
 
1032
 
 
1033
    return NULL;
 
1034
}
 
1035
 
 
1036
static dav_error * dav_generic_remove_lock(dav_lockdb *lockdb,
 
1037
                                           const dav_resource *resource,
 
1038
                                           const dav_locktoken *locktoken)
 
1039
{
 
1040
    dav_error *err;
 
1041
    dav_lock_discovery *dh = NULL;
 
1042
    dav_lock_indirect *ih = NULL;
 
1043
    apr_datum_t key;
 
1044
 
 
1045
    key = dav_generic_build_key(lockdb->info->pool, resource);
 
1046
 
 
1047
    if (locktoken != NULL) {
 
1048
        dav_lock_discovery *dp;
 
1049
        dav_lock_discovery *dprev = NULL;
 
1050
        dav_lock_indirect *ip;
 
1051
        dav_lock_indirect *iprev = NULL;
 
1052
 
 
1053
        if ((err = dav_generic_load_lock_record(lockdb, key, DAV_CREATE_LIST,
 
1054
                                           &dh, &ih)) != NULL) {
 
1055
            /* ### maybe add a higher-level description */
 
1056
            return err;
 
1057
        }
 
1058
 
 
1059
        for (dp = dh; dp != NULL; dp = dp->next) {
 
1060
            if (dav_compare_locktoken(locktoken, dp->locktoken) == 0) {
 
1061
                if (dprev)
 
1062
                    dprev->next = dp->next;
 
1063
                else
 
1064
                    dh = dh->next;
 
1065
            }
 
1066
            dprev = dp;
 
1067
        }
 
1068
 
 
1069
        for (ip = ih; ip != NULL; ip = ip->next) {
 
1070
            if (dav_compare_locktoken(locktoken, ip->locktoken) == 0) {
 
1071
                if (iprev)
 
1072
                    iprev->next = ip->next;
 
1073
                else
 
1074
                    ih = ih->next;
 
1075
            }
 
1076
            iprev = ip;
 
1077
        }
 
1078
 
 
1079
    }
 
1080
 
 
1081
    /* save the modified locks, or remove all locks (dh=ih=NULL). */
 
1082
    if ((err = dav_generic_save_lock_record(lockdb, key, dh, ih)) != NULL) {
 
1083
        /* ### maybe add a higher-level description */
 
1084
        return err;
 
1085
    }
 
1086
 
 
1087
    return NULL;
 
1088
}
 
1089
 
 
1090
static int dav_generic_do_refresh(dav_lock_discovery *dp,
 
1091
                                  const dav_locktoken_list *ltl,
 
1092
                                  time_t new_time)
 
1093
{
 
1094
    int dirty = 0;
 
1095
 
 
1096
    for (; ltl != NULL; ltl = ltl->next) {
 
1097
        if (dav_compare_locktoken(dp->locktoken, ltl->locktoken) == 0)
 
1098
        {
 
1099
            dp->f.timeout = new_time;
 
1100
            dirty = 1;
 
1101
        }
 
1102
    }
 
1103
 
 
1104
    return dirty;
 
1105
}
 
1106
 
 
1107
static dav_error * dav_generic_refresh_locks(dav_lockdb *lockdb,
 
1108
                                             const dav_resource *resource,
 
1109
                                             const dav_locktoken_list *ltl,
 
1110
                                             time_t new_time,
 
1111
                                             dav_lock **locks)
 
1112
{
 
1113
    dav_error *err;
 
1114
    apr_datum_t key;
 
1115
    dav_lock_discovery *dp;
 
1116
    dav_lock_discovery *dp_scan;
 
1117
    dav_lock_indirect *ip;
 
1118
    int dirty = 0;
 
1119
    dav_lock *newlock;
 
1120
 
 
1121
    *locks = NULL;
 
1122
 
 
1123
    key = dav_generic_build_key(lockdb->info->pool, resource);
 
1124
    if ((err = dav_generic_load_lock_record(lockdb, key, DAV_CREATE_LIST,
 
1125
                                            &dp, &ip)) != NULL) {
 
1126
        /* ### maybe add in a higher-level description */
 
1127
        return err;
 
1128
    }
 
1129
 
 
1130
    /* ### we should be refreshing direct AND (resolved) indirect locks! */
 
1131
 
 
1132
    /* refresh all of the direct locks on this resource */
 
1133
    for (dp_scan = dp; dp_scan != NULL; dp_scan = dp_scan->next) {
 
1134
        if (dav_generic_do_refresh(dp_scan, ltl, new_time)) {
 
1135
            /* the lock was refreshed. return the lock. */
 
1136
            newlock = dav_generic_alloc_lock(lockdb, key, dp_scan->locktoken);
 
1137
            newlock->is_locknull = !resource->exists;
 
1138
            newlock->scope = dp_scan->f.scope;
 
1139
            newlock->type = dp_scan->f.type;
 
1140
            newlock->depth = dp_scan->f.depth;
 
1141
            newlock->timeout = dp_scan->f.timeout;
 
1142
            newlock->owner = dp_scan->owner;
 
1143
            newlock->auth_user = dp_scan->auth_user;
 
1144
 
 
1145
            newlock->next = *locks;
 
1146
            *locks = newlock;
 
1147
 
 
1148
            dirty = 1;
 
1149
        }
 
1150
    }
 
1151
 
 
1152
    /* if we refreshed any locks, then save them back. */
 
1153
    if (dirty
 
1154
        && (err = dav_generic_save_lock_record(lockdb, key, dp, ip)) != NULL) {
 
1155
        /* ### maybe add in a higher-level description */
 
1156
        return err;
 
1157
    }
 
1158
 
 
1159
    /* for each indirect lock, find its direct lock and refresh it. */
 
1160
    for (; ip != NULL; ip = ip->next) {
 
1161
        dav_lock_discovery *ref_dp;
 
1162
        dav_lock_indirect *ref_ip;
 
1163
 
 
1164
        if ((err = dav_generic_resolve(lockdb, ip, &dp_scan,
 
1165
                                       &ref_dp, &ref_ip)) != NULL) {
 
1166
            /* ### push a higher-level desc? */
 
1167
            return err;
 
1168
        }
 
1169
        if (dav_generic_do_refresh(dp_scan, ltl, new_time)) {
 
1170
            /* the lock was refreshed. return the lock. */
 
1171
            newlock = dav_generic_alloc_lock(lockdb, ip->key, dp->locktoken);
 
1172
            newlock->is_locknull = !resource->exists;
 
1173
            newlock->scope = dp->f.scope;
 
1174
            newlock->type = dp->f.type;
 
1175
            newlock->depth = dp->f.depth;
 
1176
            newlock->timeout = dp->f.timeout;
 
1177
            newlock->owner = dp->owner;
 
1178
            newlock->auth_user = dp_scan->auth_user;
 
1179
 
 
1180
            newlock->next = *locks;
 
1181
            *locks = newlock;
 
1182
 
 
1183
            /* save the (resolved) direct lock back */
 
1184
            if ((err = dav_generic_save_lock_record(lockdb, ip->key, ref_dp,
 
1185
                                                    ref_ip)) != NULL) {
 
1186
                /* ### push a higher-level desc? */
 
1187
                return err;
 
1188
            }
 
1189
        }
 
1190
    }
 
1191
 
 
1192
    return NULL;
 
1193
}
 
1194
 
 
1195
 
 
1196
const dav_hooks_locks dav_hooks_locks_generic =
 
1197
{
 
1198
    dav_generic_get_supportedlock,
 
1199
    dav_generic_parse_locktoken,
 
1200
    dav_generic_format_locktoken,
 
1201
    dav_generic_compare_locktoken,
 
1202
    dav_generic_open_lockdb,
 
1203
    dav_generic_close_lockdb,
 
1204
    dav_generic_remove_locknull_state,
 
1205
    dav_generic_create_lock,
 
1206
    dav_generic_get_locks,
 
1207
    dav_generic_find_lock,
 
1208
    dav_generic_has_locks,
 
1209
    dav_generic_append_locks,
 
1210
    dav_generic_remove_lock,
 
1211
    dav_generic_refresh_locks,
 
1212
    NULL, /* lookup_resource */
 
1213
 
 
1214
    NULL /* ctx */
 
1215
};