00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021 #include "apr.h"
00022 #include "apr_strings.h"
00023 #include "apr_file_io.h"
00024 #include "apr_uuid.h"
00025
00026 #define APR_WANT_MEMFUNC
00027 #include "apr_want.h"
00028
00029 #include "httpd.h"
00030 #include "http_log.h"
00031
00032 #include "mod_dav.h"
00033 #include "repos.h"
00034
00035
00036
00037
00038
00039
00040
00041
00042
00043
00044
00045
00046
00047
00048
00049
00050
00051
00052
00053
00054
00055
00056
00057
00058
00059
00060
00061
00062
00063
00064
00065
00066
00067
00068
00069
00070
00071
00072
00073
00074
00075 #define DAV_TRUE 1
00076 #define DAV_FALSE 0
00077
00078 #define DAV_CREATE_LIST 23
00079 #define DAV_APPEND_LIST 24
00080
00081
00082 #define DAV_LOCK_DIRECT 1
00083 #define DAV_LOCK_INDIRECT 2
00084
00085 #define DAV_TYPE_INODE 10
00086 #define DAV_TYPE_FNAME 11
00087
00088
00089
00090 static dav_error * dav_fs_remove_locknull_member(apr_pool_t *p,
00091 const char *filename,
00092 dav_buffer *pbuf);
00093
00094
00095
00096
00097 struct dav_locktoken {
00098 apr_uuid_t uuid;
00099 };
00100 #define dav_compare_locktoken(plt1, plt2) \
00101 memcmp(&(plt1)->uuid, &(plt2)->uuid, sizeof((plt1)->uuid))
00102
00103
00104
00105
00106
00107
00108
00109
00110
00111
00112
00113 typedef struct dav_lock_discovery_fixed
00114 {
00115 char scope;
00116 char type;
00117 int depth;
00118 time_t timeout;
00119 } dav_lock_discovery_fixed;
00120
00121 typedef struct dav_lock_discovery
00122 {
00123 struct dav_lock_discovery_fixed f;
00124
00125 dav_locktoken *locktoken;
00126 const char *owner;
00127 const char *auth_user;
00128 struct dav_lock_discovery *next;
00129 } dav_lock_discovery;
00130
00131
00132
00133
00134
00135
00136
00137 typedef struct dav_lock_indirect
00138 {
00139 dav_locktoken *locktoken;
00140 apr_datum_t key;
00141 struct dav_lock_indirect *next;
00142 time_t timeout;
00143 } dav_lock_indirect;
00144
00145
00146
00147
00148
00149
00150
00151
00152 #define dav_size_direct(a) (1 + sizeof(dav_lock_discovery_fixed) \
00153 + sizeof(apr_uuid_t) \
00154 + ((a)->owner ? strlen((a)->owner) : 0) \
00155 + ((a)->auth_user ? strlen((a)->auth_user) : 0) \
00156 + 2)
00157
00158
00159 #define dav_size_indirect(a) (1 + sizeof(apr_uuid_t) \
00160 + sizeof(time_t) \
00161 + sizeof((a)->key.dsize) + (a)->key.dsize)
00162
00163
00164
00165
00166
00167
00168
00169
00170
00171
00172
00173
00174
00175
00176
00177
00178 struct dav_lockdb_private
00179 {
00180 request_rec *r;
00181 apr_pool_t *pool;
00182 const char *lockdb_path;
00183
00184 int opened;
00185 dav_db *db;
00186 };
00187 typedef struct
00188 {
00189 dav_lockdb pub;
00190 dav_lockdb_private priv;
00191 } dav_lockdb_combined;
00192
00193
00194
00195
00196 struct dav_lock_private
00197 {
00198 apr_datum_t key;
00199 };
00200 typedef struct
00201 {
00202 dav_lock pub;
00203 dav_lock_private priv;
00204 dav_locktoken token;
00205 } dav_lock_combined;
00206
00207
00208
00209
00210 extern const dav_hooks_locks dav_hooks_locks_fs;
00211
00212
00213
00214 static dav_lock *dav_fs_alloc_lock(dav_lockdb *lockdb, apr_datum_t key,
00215 const dav_locktoken *locktoken)
00216 {
00217 dav_lock_combined *comb;
00218
00219 comb = apr_pcalloc(lockdb->info->pool, sizeof(*comb));
00220 comb->pub.rectype = DAV_LOCKREC_DIRECT;
00221 comb->pub.info = &comb->priv;
00222 comb->priv.key = key;
00223
00224 if (locktoken == NULL) {
00225 comb->pub.locktoken = &comb->token;
00226 apr_uuid_get(&comb->token.uuid);
00227 }
00228 else {
00229 comb->pub.locktoken = locktoken;
00230 }
00231
00232 return &comb->pub;
00233 }
00234
00235
00236
00237
00238
00239
00240 static dav_error * dav_fs_parse_locktoken(
00241 apr_pool_t *p,
00242 const char *char_token,
00243 dav_locktoken **locktoken_p)
00244 {
00245 dav_locktoken *locktoken;
00246
00247 if (ap_strstr_c(char_token, "opaquelocktoken:") != char_token) {
00248 return dav_new_error(p,
00249 HTTP_BAD_REQUEST, DAV_ERR_LOCK_UNK_STATE_TOKEN,
00250 "The lock token uses an unknown State-token "
00251 "format and could not be parsed.");
00252 }
00253 char_token += 16;
00254
00255 locktoken = apr_pcalloc(p, sizeof(*locktoken));
00256 if (apr_uuid_parse(&locktoken->uuid, char_token)) {
00257 return dav_new_error(p, HTTP_BAD_REQUEST, DAV_ERR_LOCK_PARSE_TOKEN,
00258 "The opaquelocktoken has an incorrect format "
00259 "and could not be parsed.");
00260 }
00261
00262 *locktoken_p = locktoken;
00263 return NULL;
00264 }
00265
00266
00267
00268
00269
00270
00271 static const char *dav_fs_format_locktoken(
00272 apr_pool_t *p,
00273 const dav_locktoken *locktoken)
00274 {
00275 char buf[APR_UUID_FORMATTED_LENGTH + 1];
00276
00277 apr_uuid_format(buf, &locktoken->uuid);
00278 return apr_pstrcat(p, "opaquelocktoken:", buf, NULL);
00279 }
00280
00281
00282
00283
00284
00285
00286 static int dav_fs_compare_locktoken(
00287 const dav_locktoken *lt1,
00288 const dav_locktoken *lt2)
00289 {
00290 return dav_compare_locktoken(lt1, lt2);
00291 }
00292
00293
00294
00295
00296
00297
00298 static dav_error * dav_fs_really_open_lockdb(dav_lockdb *lockdb)
00299 {
00300 dav_error *err;
00301
00302 if (lockdb->info->opened)
00303 return NULL;
00304
00305 err = dav_dbm_open_direct(lockdb->info->pool,
00306 lockdb->info->lockdb_path,
00307 lockdb->ro,
00308 &lockdb->info->db);
00309 if (err != NULL) {
00310 return dav_push_error(lockdb->info->pool,
00311 HTTP_INTERNAL_SERVER_ERROR,
00312 DAV_ERR_LOCK_OPENDB,
00313 "Could not open the lock database.",
00314 err);
00315 }
00316
00317
00318 lockdb->info->opened = 1;
00319
00320 return NULL;
00321 }
00322
00323
00324
00325
00326
00327
00328
00329
00330
00331 static dav_error * dav_fs_open_lockdb(request_rec *r, int ro, int force,
00332 dav_lockdb **lockdb)
00333 {
00334 dav_lockdb_combined *comb;
00335
00336 comb = apr_pcalloc(r->pool, sizeof(*comb));
00337 comb->pub.hooks = &dav_hooks_locks_fs;
00338 comb->pub.ro = ro;
00339 comb->pub.info = &comb->priv;
00340 comb->priv.r = r;
00341 comb->priv.pool = r->pool;
00342
00343 comb->priv.lockdb_path = dav_get_lockdb_path(r);
00344 if (comb->priv.lockdb_path == NULL) {
00345 return dav_new_error(r->pool, HTTP_INTERNAL_SERVER_ERROR,
00346 DAV_ERR_LOCK_NO_DB,
00347 "A lock database was not specified with the "
00348 "DAVLockDB directive. One must be specified "
00349 "to use the locking functionality.");
00350 }
00351
00352
00353 *lockdb = &comb->pub;
00354
00355 if (force) {
00356
00357 return dav_fs_really_open_lockdb(*lockdb);
00358 }
00359
00360 return NULL;
00361 }
00362
00363
00364
00365
00366
00367
00368 static void dav_fs_close_lockdb(dav_lockdb *lockdb)
00369 {
00370 if (lockdb->info->db != NULL)
00371 dav_dbm_close(lockdb->info->db);
00372 }
00373
00374
00375
00376
00377
00378
00379 static apr_datum_t dav_fs_build_fname_key(apr_pool_t *p, const char *pathname)
00380 {
00381 apr_datum_t key;
00382
00383
00384
00385
00386
00387 key.dsize = strlen(pathname) + 2;
00388 key.dptr = apr_palloc(p, key.dsize);
00389 *key.dptr = DAV_TYPE_FNAME;
00390 memcpy(key.dptr + 1, pathname, key.dsize - 1);
00391 if (key.dptr[key.dsize - 2] == '/')
00392 key.dptr[--key.dsize - 1] = '\0';
00393 return key;
00394 }
00395
00396
00397
00398
00399
00400
00401
00402
00403
00404
00405
00406 static apr_datum_t dav_fs_build_key(apr_pool_t *p,
00407 const dav_resource *resource)
00408 {
00409 const char *file = dav_fs_pathname(resource);
00410 apr_datum_t key;
00411 apr_finfo_t finfo;
00412 apr_status_t rv;
00413
00414
00415
00416
00417
00418 rv = apr_stat(&finfo, file, APR_FINFO_IDENT, p);
00419 if ((rv == APR_SUCCESS || rv == APR_INCOMPLETE)
00420 && ((finfo.valid & APR_FINFO_IDENT) == APR_FINFO_IDENT))
00421 {
00422
00423 key.dsize = 1 + sizeof(finfo.inode) + sizeof(finfo.device);
00424 key.dptr = apr_palloc(p, key.dsize);
00425 *key.dptr = DAV_TYPE_INODE;
00426 memcpy(key.dptr + 1, &finfo.inode, sizeof(finfo.inode));
00427 memcpy(key.dptr + 1 + sizeof(finfo.inode), &finfo.device,
00428 sizeof(finfo.device));
00429
00430 return key;
00431 }
00432
00433 return dav_fs_build_fname_key(p, file);
00434 }
00435
00436
00437
00438
00439
00440
00441 static int dav_fs_lock_expired(time_t expires)
00442 {
00443 return expires != DAV_TIMEOUT_INFINITE && time(NULL) >= expires;
00444 }
00445
00446
00447
00448
00449
00450
00451 static dav_error * dav_fs_save_lock_record(dav_lockdb *lockdb, apr_datum_t key,
00452 dav_lock_discovery *direct,
00453 dav_lock_indirect *indirect)
00454 {
00455 dav_error *err;
00456 apr_datum_t val = { 0 };
00457 char *ptr;
00458 dav_lock_discovery *dp = direct;
00459 dav_lock_indirect *ip = indirect;
00460
00461 #if DAV_DEBUG
00462 if (lockdb->ro) {
00463 return dav_new_error(lockdb->info->pool,
00464 HTTP_INTERNAL_SERVER_ERROR, 0,
00465 "INTERNAL DESIGN ERROR: the lockdb was opened "
00466 "readonly, but an attempt to save locks was "
00467 "performed.");
00468 }
00469 #endif
00470
00471 if ((err = dav_fs_really_open_lockdb(lockdb)) != NULL) {
00472
00473 return err;
00474 }
00475
00476
00477 if (dp == NULL && ip == NULL) {
00478
00479
00480 (void) dav_dbm_delete(lockdb->info->db, key);
00481 return NULL;
00482 }
00483
00484 while(dp) {
00485 val.dsize += dav_size_direct(dp);
00486 dp = dp->next;
00487 }
00488 while(ip) {
00489 val.dsize += dav_size_indirect(ip);
00490 ip = ip->next;
00491 }
00492
00493
00494
00495 ptr = val.dptr = apr_pcalloc(lockdb->info->pool, val.dsize);
00496 dp = direct;
00497 ip = indirect;
00498
00499 while(dp) {
00500 *ptr++ = DAV_LOCK_DIRECT;
00501 memcpy(ptr, dp, sizeof(dp->f));
00502 ptr += sizeof(dp->f);
00503 memcpy(ptr, dp->locktoken, sizeof(*dp->locktoken));
00504 ptr += sizeof(*dp->locktoken);
00505 if (dp->owner == NULL) {
00506 *ptr++ = '\0';
00507 }
00508 else {
00509 memcpy(ptr, dp->owner, strlen(dp->owner) + 1);
00510 ptr += strlen(dp->owner) + 1;
00511 }
00512 if (dp->auth_user == NULL) {
00513 *ptr++ = '\0';
00514 }
00515 else {
00516 memcpy(ptr, dp->auth_user, strlen(dp->auth_user) + 1);
00517 ptr += strlen(dp->auth_user) + 1;
00518 }
00519
00520 dp = dp->next;
00521 }
00522
00523 while(ip) {
00524 *ptr++ = DAV_LOCK_INDIRECT;
00525 memcpy(ptr, ip->locktoken, sizeof(*ip->locktoken));
00526 ptr += sizeof(*ip->locktoken);
00527 memcpy(ptr, &ip->timeout, sizeof(ip->timeout));
00528 ptr += sizeof(ip->timeout);
00529 memcpy(ptr, &ip->key.dsize, sizeof(ip->key.dsize));
00530 ptr += sizeof(ip->key.dsize);
00531 memcpy(ptr, ip->key.dptr, ip->key.dsize);
00532 ptr += ip->key.dsize;
00533 ip = ip->next;
00534 }
00535
00536 if ((err = dav_dbm_store(lockdb->info->db, key, val)) != NULL) {
00537
00538 return dav_push_error(lockdb->info->pool,
00539 HTTP_INTERNAL_SERVER_ERROR,
00540 DAV_ERR_LOCK_SAVE_LOCK,
00541 "Could not save lock information.",
00542 err);
00543 }
00544
00545 return NULL;
00546 }
00547
00548
00549
00550
00551
00552
00553
00554
00555
00556
00557
00558 static dav_error * dav_fs_load_lock_record(dav_lockdb *lockdb, apr_datum_t key,
00559 int add_method,
00560 dav_lock_discovery **direct,
00561 dav_lock_indirect **indirect)
00562 {
00563 apr_pool_t *p = lockdb->info->pool;
00564 dav_error *err;
00565 apr_size_t offset = 0;
00566 int need_save = DAV_FALSE;
00567 apr_datum_t val = { 0 };
00568 dav_lock_discovery *dp;
00569 dav_lock_indirect *ip;
00570 dav_buffer buf = { 0 };
00571
00572 if (add_method != DAV_APPEND_LIST) {
00573 *direct = NULL;
00574 *indirect = NULL;
00575 }
00576
00577 if ((err = dav_fs_really_open_lockdb(lockdb)) != NULL) {
00578
00579 return err;
00580 }
00581
00582
00583
00584
00585
00586 if (lockdb->info->db == NULL)
00587 return NULL;
00588
00589 if ((err = dav_dbm_fetch(lockdb->info->db, key, &val)) != NULL)
00590 return err;
00591
00592 if (!val.dsize)
00593 return NULL;
00594
00595 while (offset < val.dsize) {
00596 switch (*(val.dptr + offset++)) {
00597 case DAV_LOCK_DIRECT:
00598
00599
00600 dp = apr_pcalloc(p, sizeof(*dp));
00601 memcpy(dp, val.dptr + offset, sizeof(dp->f));
00602 offset += sizeof(dp->f);
00603 dp->locktoken = apr_palloc(p, sizeof(*dp->locktoken));
00604 memcpy(dp->locktoken, val.dptr + offset, sizeof(*dp->locktoken));
00605 offset += sizeof(*dp->locktoken);
00606 if (*(val.dptr + offset) == '\0') {
00607 ++offset;
00608 }
00609 else {
00610 dp->owner = apr_pstrdup(p, val.dptr + offset);
00611 offset += strlen(dp->owner) + 1;
00612 }
00613
00614 if (*(val.dptr + offset) == '\0') {
00615 ++offset;
00616 }
00617 else {
00618 dp->auth_user = apr_pstrdup(p, val.dptr + offset);
00619 offset += strlen(dp->auth_user) + 1;
00620 }
00621
00622 if (!dav_fs_lock_expired(dp->f.timeout)) {
00623 dp->next = *direct;
00624 *direct = dp;
00625 }
00626 else {
00627 need_save = DAV_TRUE;
00628
00629
00630 if (*key.dptr == DAV_TYPE_FNAME) {
00631 const char *fname = key.dptr + 1;
00632 apr_finfo_t finfo;
00633 apr_status_t rv;
00634
00635
00636 rv = apr_lstat(&finfo, fname, APR_FINFO_MIN, p);
00637 if (rv != APR_SUCCESS && rv != APR_INCOMPLETE) {
00638 if ((err = dav_fs_remove_locknull_member(p, fname, &buf)) != NULL) {
00639
00640 return err;
00641 }
00642 }
00643 }
00644 }
00645 break;
00646
00647 case DAV_LOCK_INDIRECT:
00648
00649
00650 ip = apr_pcalloc(p, sizeof(*ip));
00651 ip->locktoken = apr_palloc(p, sizeof(*ip->locktoken));
00652 memcpy(ip->locktoken, val.dptr + offset, sizeof(*ip->locktoken));
00653 offset += sizeof(*ip->locktoken);
00654 memcpy(&ip->timeout, val.dptr + offset, sizeof(ip->timeout));
00655 offset += sizeof(ip->timeout);
00656 memcpy(&ip->key.dsize, val.dptr + offset, sizeof(ip->key.dsize));
00657 offset += sizeof(ip->key.dsize);
00658 ip->key.dptr = apr_palloc(p, ip->key.dsize);
00659 memcpy(ip->key.dptr, val.dptr + offset, ip->key.dsize);
00660 offset += ip->key.dsize;
00661
00662 if (!dav_fs_lock_expired(ip->timeout)) {
00663 ip->next = *indirect;
00664 *indirect = ip;
00665 }
00666 else {
00667 need_save = DAV_TRUE;
00668
00669 }
00670
00671 break;
00672
00673 default:
00674 dav_dbm_freedatum(lockdb->info->db, val);
00675
00676
00677 --offset;
00678 return dav_new_error(p,
00679 HTTP_INTERNAL_SERVER_ERROR,
00680 DAV_ERR_LOCK_CORRUPT_DB,
00681 apr_psprintf(p,
00682 "The lock database was found to "
00683 "be corrupt. offset %"
00684 APR_SIZE_T_FMT ", c=%02x",
00685 offset, val.dptr[offset]));
00686 }
00687 }
00688
00689 dav_dbm_freedatum(lockdb->info->db, val);
00690
00691
00692
00693
00694
00695
00696 if (need_save == DAV_TRUE) {
00697 return dav_fs_save_lock_record(lockdb, key, *direct, *indirect);
00698 }
00699
00700 return NULL;
00701 }
00702
00703
00704 static dav_error * dav_fs_resolve(dav_lockdb *lockdb,
00705 dav_lock_indirect *indirect,
00706 dav_lock_discovery **direct,
00707 dav_lock_discovery **ref_dp,
00708 dav_lock_indirect **ref_ip)
00709 {
00710 dav_error *err;
00711 dav_lock_discovery *dir;
00712 dav_lock_indirect *ind;
00713
00714 if ((err = dav_fs_load_lock_record(lockdb, indirect->key,
00715 DAV_CREATE_LIST,
00716 &dir, &ind)) != NULL) {
00717
00718 return err;
00719 }
00720 if (ref_dp != NULL) {
00721 *ref_dp = dir;
00722 *ref_ip = ind;
00723 }
00724
00725 for (; dir != NULL; dir = dir->next) {
00726 if (!dav_compare_locktoken(indirect->locktoken, dir->locktoken)) {
00727 *direct = dir;
00728 return NULL;
00729 }
00730 }
00731
00732
00733
00734
00735 return dav_new_error(lockdb->info->pool,
00736 HTTP_INTERNAL_SERVER_ERROR,
00737 DAV_ERR_LOCK_CORRUPT_DB,
00738 "The lock database was found to be corrupt. "
00739 "An indirect lock's direct lock could not "
00740 "be found.");
00741 }
00742
00743
00744
00745
00746
00747
00748
00749
00750
00751
00752
00753
00754 static const char *dav_fs_get_supportedlock(const dav_resource *resource)
00755 {
00756 static const char supported[] = DEBUG_CR
00757 "<D:lockentry>" DEBUG_CR
00758 "<D:lockscope><D:exclusive/></D:lockscope>" DEBUG_CR
00759 "<D:locktype><D:write/></D:locktype>" DEBUG_CR
00760 "</D:lockentry>" DEBUG_CR
00761 "<D:lockentry>" DEBUG_CR
00762 "<D:lockscope><D:shared/></D:lockscope>" DEBUG_CR
00763 "<D:locktype><D:write/></D:locktype>" DEBUG_CR
00764 "</D:lockentry>" DEBUG_CR;
00765
00766 return supported;
00767 }
00768
00769
00770
00771
00772
00773
00774
00775
00776
00777
00778
00779
00780
00781
00782
00783
00784
00785 static dav_error * dav_fs_load_locknull_list(apr_pool_t *p, const char *dirpath,
00786 dav_buffer *pbuf)
00787 {
00788 apr_finfo_t finfo;
00789 apr_file_t *file = NULL;
00790 dav_error *err = NULL;
00791 apr_size_t amt;
00792 apr_status_t rv;
00793
00794 dav_buffer_init(p, pbuf, dirpath);
00795
00796 if (pbuf->buf[pbuf->cur_len - 1] == '/')
00797 pbuf->buf[--pbuf->cur_len] = '\0';
00798
00799 dav_buffer_place(p, pbuf, "/" DAV_FS_STATE_DIR "/" DAV_FS_LOCK_NULL_FILE);
00800
00801
00802 pbuf->cur_len = 0;
00803
00804 if (apr_file_open(&file, pbuf->buf, APR_READ | APR_BINARY, APR_OS_DEFAULT,
00805 p) != APR_SUCCESS) {
00806 return NULL;
00807 }
00808
00809 rv = apr_file_info_get(&finfo, APR_FINFO_SIZE, file);
00810 if (rv != APR_SUCCESS) {
00811 err = dav_new_error(p, HTTP_INTERNAL_SERVER_ERROR, 0,
00812 apr_psprintf(p,
00813 "Opened but could not stat file %s",
00814 pbuf->buf));
00815 goto loaderror;
00816 }
00817
00818 if (finfo.size != (apr_size_t)finfo.size) {
00819 err = dav_new_error(p, HTTP_INTERNAL_SERVER_ERROR, 0,
00820 apr_psprintf(p,
00821 "Opened but rejected huge file %s",
00822 pbuf->buf));
00823 goto loaderror;
00824 }
00825
00826 amt = (apr_size_t)finfo.size;
00827 dav_set_bufsize(p, pbuf, amt);
00828 if (apr_file_read(file, pbuf->buf, &amt) != APR_SUCCESS
00829 || amt != finfo.size) {
00830 err = dav_new_error(p, HTTP_INTERNAL_SERVER_ERROR, 0,
00831 apr_psprintf(p,
00832 "Failure reading locknull file "
00833 "for %s", dirpath));
00834
00835
00836 pbuf->cur_len = 0;
00837 goto loaderror;
00838 }
00839
00840 loaderror:
00841 apr_file_close(file);
00842 return err;
00843 }
00844
00845
00846
00847
00848
00849 static dav_error * dav_fs_save_locknull_list(apr_pool_t *p, const char *dirpath,
00850 dav_buffer *pbuf)
00851 {
00852 const char *pathname;
00853 apr_file_t *file = NULL;
00854 dav_error *err = NULL;
00855 apr_size_t amt;
00856
00857 if (pbuf->buf == NULL)
00858 return NULL;
00859
00860 dav_fs_ensure_state_dir(p, dirpath);
00861 pathname = apr_pstrcat(p,
00862 dirpath,
00863 dirpath[strlen(dirpath) - 1] == '/' ? "" : "/",
00864 DAV_FS_STATE_DIR "/" DAV_FS_LOCK_NULL_FILE,
00865 NULL);
00866
00867 if (pbuf->cur_len == 0) {
00868
00869 if (apr_file_remove(pathname, p) != 0) {
00870 return dav_new_error(p, HTTP_INTERNAL_SERVER_ERROR, 0,
00871 apr_psprintf(p,
00872 "Error removing %s", pathname));
00873 }
00874 return NULL;
00875 }
00876
00877 if (apr_file_open(&file, pathname,
00878 APR_WRITE | APR_CREATE | APR_TRUNCATE | APR_BINARY,
00879 APR_OS_DEFAULT, p) != APR_SUCCESS) {
00880 return dav_new_error(p, HTTP_INTERNAL_SERVER_ERROR, 0,
00881 apr_psprintf(p,
00882 "Error opening %s for writing",
00883 pathname));
00884 }
00885
00886 amt = pbuf->cur_len;
00887 if (apr_file_write(file, pbuf->buf, &amt) != APR_SUCCESS
00888 || amt != pbuf->cur_len) {
00889 err = dav_new_error(p, HTTP_INTERNAL_SERVER_ERROR, 0,
00890 apr_psprintf(p,
00891 "Error writing %" APR_SIZE_T_FMT
00892 " bytes to %s",
00893 pbuf->cur_len, pathname));
00894 }
00895
00896 apr_file_close(file);
00897 return err;
00898 }
00899
00900
00901
00902
00903
00904 static dav_error * dav_fs_remove_locknull_member(apr_pool_t *p,
00905 const char *filename,
00906 dav_buffer *pbuf)
00907 {
00908 dav_error *err;
00909 apr_size_t len;
00910 apr_size_t scanlen;
00911 char *scan;
00912 const char *scanend;
00913 char *dirpath = apr_pstrdup(p, filename);
00914 char *fname = strrchr(dirpath, '/');
00915 int dirty = 0;
00916
00917 if (fname != NULL)
00918 *fname++ = '\0';
00919 else
00920 fname = dirpath;
00921 len = strlen(fname) + 1;
00922
00923 if ((err = dav_fs_load_locknull_list(p, dirpath, pbuf)) != NULL) {
00924
00925 return err;
00926 }
00927
00928 for (scan = pbuf->buf, scanend = scan + pbuf->cur_len;
00929 scan < scanend;
00930 scan += scanlen) {
00931 scanlen = strlen(scan) + 1;
00932 if (len == scanlen && memcmp(fname, scan, scanlen) == 0) {
00933 pbuf->cur_len -= scanlen;
00934 memmove(scan, scan + scanlen, scanend - (scan + scanlen));
00935 dirty = 1;
00936 break;
00937 }
00938 }
00939
00940 if (dirty) {
00941 if ((err = dav_fs_save_locknull_list(p, dirpath, pbuf)) != NULL) {
00942
00943 return err;
00944 }
00945 }
00946
00947 return NULL;
00948 }
00949
00950
00951 dav_error * dav_fs_get_locknull_members(
00952 const dav_resource *resource,
00953 dav_buffer *pbuf)
00954 {
00955 const char *dirpath;
00956
00957
00958 (void) dav_fs_dir_file_name(resource, &dirpath, NULL);
00959 return dav_fs_load_locknull_list(dav_fs_pool(resource), dirpath, pbuf);
00960 }
00961
00962
00963
00964 static dav_error * dav_fs_add_locknull_state(
00965 dav_lockdb *lockdb,
00966 const dav_resource *resource)
00967 {
00968 dav_buffer buf = { 0 };
00969 apr_pool_t *p = lockdb->info->pool;
00970 const char *dirpath;
00971 const char *fname;
00972 dav_error *err;
00973
00974
00975 (void) dav_fs_dir_file_name(resource, &dirpath, &fname);
00976
00977 if ((err = dav_fs_load_locknull_list(p, dirpath, &buf)) != NULL) {
00978 return dav_push_error(p, HTTP_INTERNAL_SERVER_ERROR, 0,
00979 "Could not load .locknull file.", err);
00980 }
00981
00982 dav_buffer_append(p, &buf, fname);
00983 buf.cur_len++;
00984
00985 if ((err = dav_fs_save_locknull_list(p, dirpath, &buf)) != NULL) {
00986 return dav_push_error(p, HTTP_INTERNAL_SERVER_ERROR, 0,
00987 "Could not save .locknull file.", err);
00988 }
00989
00990 return NULL;
00991 }
00992
00993
00994
00995
00996
00997
00998
00999
01000
01001
01002
01003 static dav_error * dav_fs_remove_locknull_state(
01004 dav_lockdb *lockdb,
01005 const dav_resource *resource)
01006 {
01007 dav_buffer buf = { 0 };
01008 dav_error *err;
01009 apr_pool_t *p = lockdb->info->pool;
01010 const char *pathname = dav_fs_pathname(resource);
01011
01012 if ((err = dav_fs_remove_locknull_member(p, pathname, &buf)) != NULL) {
01013
01014 return err;
01015 }
01016
01017 {
01018 dav_lock_discovery *ld;
01019 dav_lock_indirect *id;
01020 apr_datum_t key;
01021
01022
01023
01024
01025
01026
01027 key = dav_fs_build_fname_key(p, pathname);
01028 if ((err = dav_fs_load_lock_record(lockdb, key, DAV_CREATE_LIST,
01029 &ld, &id)) != NULL) {
01030
01031 return err;
01032 }
01033
01034 if ((err = dav_fs_save_lock_record(lockdb, key, NULL, NULL)) != NULL) {
01035
01036 return err;
01037 }
01038
01039 key = dav_fs_build_key(p, resource);
01040 if ((err = dav_fs_save_lock_record(lockdb, key, ld, id)) != NULL) {
01041
01042 return err;
01043 }
01044 }
01045
01046 return NULL;
01047 }
01048
01049 static dav_error * dav_fs_create_lock(dav_lockdb *lockdb,
01050 const dav_resource *resource,
01051 dav_lock **lock)
01052 {
01053 apr_datum_t key;
01054
01055 key = dav_fs_build_key(lockdb->info->pool, resource);
01056
01057 *lock = dav_fs_alloc_lock(lockdb,
01058 key,
01059 NULL);
01060
01061 (*lock)->is_locknull = !resource->exists;
01062
01063 return NULL;
01064 }
01065
01066 static dav_error * dav_fs_get_locks(dav_lockdb *lockdb,
01067 const dav_resource *resource,
01068 int calltype,
01069 dav_lock **locks)
01070 {
01071 apr_pool_t *p = lockdb->info->pool;
01072 apr_datum_t key;
01073 dav_error *err;
01074 dav_lock *lock = NULL;
01075 dav_lock *newlock;
01076 dav_lock_discovery *dp;
01077 dav_lock_indirect *ip;
01078
01079 #if DAV_DEBUG
01080 if (calltype == DAV_GETLOCKS_COMPLETE) {
01081 return dav_new_error(lockdb->info->pool,
01082 HTTP_INTERNAL_SERVER_ERROR, 0,
01083 "INTERNAL DESIGN ERROR: DAV_GETLOCKS_COMPLETE "
01084 "is not yet supported");
01085 }
01086 #endif
01087
01088 key = dav_fs_build_key(p, resource);
01089 if ((err = dav_fs_load_lock_record(lockdb, key, DAV_CREATE_LIST,
01090 &dp, &ip)) != NULL) {
01091
01092 return err;
01093 }
01094
01095
01096 for (; dp != NULL; dp = dp->next) {
01097 newlock = dav_fs_alloc_lock(lockdb, key, dp->locktoken);
01098 newlock->is_locknull = !resource->exists;
01099 newlock->scope = dp->f.scope;
01100 newlock->type = dp->f.type;
01101 newlock->depth = dp->f.depth;
01102 newlock->timeout = dp->f.timeout;
01103 newlock->owner = dp->owner;
01104 newlock->auth_user = dp->auth_user;
01105
01106
01107 newlock->next = lock;
01108 lock = newlock;
01109 }
01110
01111
01112 for (; ip != NULL; ip = ip->next) {
01113 newlock = dav_fs_alloc_lock(lockdb, ip->key, ip->locktoken);
01114 newlock->is_locknull = !resource->exists;
01115
01116 if (calltype == DAV_GETLOCKS_RESOLVED) {
01117 if ((err = dav_fs_resolve(lockdb, ip, &dp, NULL, NULL)) != NULL) {
01118
01119 return err;
01120 }
01121
01122 newlock->scope = dp->f.scope;
01123 newlock->type = dp->f.type;
01124 newlock->depth = dp->f.depth;
01125 newlock->timeout = dp->f.timeout;
01126 newlock->owner = dp->owner;
01127 newlock->auth_user = dp->auth_user;
01128 }
01129 else {
01130
01131 newlock->rectype = DAV_LOCKREC_INDIRECT_PARTIAL;
01132 }
01133
01134
01135 newlock->next = lock;
01136 lock = newlock;
01137 }
01138
01139 *locks = lock;
01140 return NULL;
01141 }
01142
01143 static dav_error * dav_fs_find_lock(dav_lockdb *lockdb,
01144 const dav_resource *resource,
01145 const dav_locktoken *locktoken,
01146 int partial_ok,
01147 dav_lock **lock)
01148 {
01149 dav_error *err;
01150 apr_datum_t key;
01151 dav_lock_discovery *dp;
01152 dav_lock_indirect *ip;
01153
01154 *lock = NULL;
01155
01156 key = dav_fs_build_key(lockdb->info->pool, resource);
01157 if ((err = dav_fs_load_lock_record(lockdb, key, DAV_CREATE_LIST,
01158 &dp, &ip)) != NULL) {
01159
01160 return err;
01161 }
01162
01163 for (; dp != NULL; dp = dp->next) {
01164 if (!dav_compare_locktoken(locktoken, dp->locktoken)) {
01165 *lock = dav_fs_alloc_lock(lockdb, key, locktoken);
01166 (*lock)->is_locknull = !resource->exists;
01167 (*lock)->scope = dp->f.scope;
01168 (*lock)->type = dp->f.type;
01169 (*lock)->depth = dp->f.depth;
01170 (*lock)->timeout = dp->f.timeout;
01171 (*lock)->owner = dp->owner;
01172 (*lock)->auth_user = dp->auth_user;
01173 return NULL;
01174 }
01175 }
01176
01177 for (; ip != NULL; ip = ip->next) {
01178 if (!dav_compare_locktoken(locktoken, ip->locktoken)) {
01179 *lock = dav_fs_alloc_lock(lockdb, ip->key, locktoken);
01180 (*lock)->is_locknull = !resource->exists;
01181
01182
01183 if (partial_ok) {
01184 (*lock)->rectype = DAV_LOCKREC_INDIRECT_PARTIAL;
01185 }
01186 else {
01187 (*lock)->rectype = DAV_LOCKREC_INDIRECT;
01188 if ((err = dav_fs_resolve(lockdb, ip, &dp,
01189 NULL, NULL)) != NULL) {
01190
01191 return err;
01192 }
01193 (*lock)->scope = dp->f.scope;
01194 (*lock)->type = dp->f.type;
01195 (*lock)->depth = dp->f.depth;
01196 (*lock)->timeout = dp->f.timeout;
01197 (*lock)->owner = dp->owner;
01198 (*lock)->auth_user = dp->auth_user;
01199 }
01200 return NULL;
01201 }
01202 }
01203
01204 return NULL;
01205 }
01206
01207 static dav_error * dav_fs_has_locks(dav_lockdb *lockdb,
01208 const dav_resource *resource,
01209 int *locks_present)
01210 {
01211 dav_error *err;
01212 apr_datum_t key;
01213
01214 *locks_present = 0;
01215
01216 if ((err = dav_fs_really_open_lockdb(lockdb)) != NULL) {
01217
01218 return err;
01219 }
01220
01221
01222
01223
01224
01225 if (lockdb->info->db == NULL)
01226 return NULL;
01227
01228 key = dav_fs_build_key(lockdb->info->pool, resource);
01229
01230 *locks_present = dav_dbm_exists(lockdb->info->db, key);
01231
01232 return NULL;
01233 }
01234
01235 static dav_error * dav_fs_append_locks(dav_lockdb *lockdb,
01236 const dav_resource *resource,
01237 int make_indirect,
01238 const dav_lock *lock)
01239 {
01240 apr_pool_t *p = lockdb->info->pool;
01241 dav_error *err;
01242 dav_lock_indirect *ip;
01243 dav_lock_discovery *dp;
01244 apr_datum_t key;
01245
01246 key = dav_fs_build_key(lockdb->info->pool, resource);
01247 if ((err = dav_fs_load_lock_record(lockdb, key, 0, &dp, &ip)) != NULL) {
01248
01249 return err;
01250 }
01251
01252
01253
01254
01255
01256
01257 if (make_indirect) {
01258 for (; lock != NULL; lock = lock->next) {
01259
01260
01261 dav_lock_indirect *newi = apr_pcalloc(p, sizeof(*newi));
01262
01263
01264 newi->locktoken = (dav_locktoken *)lock->locktoken;
01265 newi->timeout = lock->timeout;
01266 newi->key = lock->info->key;
01267 newi->next = ip;
01268 ip = newi;
01269 }
01270 }
01271 else {
01272 for (; lock != NULL; lock = lock->next) {
01273
01274
01275 if (lock->rectype == DAV_LOCKREC_DIRECT) {
01276 dav_lock_discovery *newd = apr_pcalloc(p, sizeof(*newd));
01277
01278 newd->f.scope = lock->scope;
01279 newd->f.type = lock->type;
01280 newd->f.depth = lock->depth;
01281 newd->f.timeout = lock->timeout;
01282
01283 newd->locktoken = (dav_locktoken *)lock->locktoken;
01284 newd->owner = lock->owner;
01285 newd->auth_user = lock->auth_user;
01286 newd->next = dp;
01287 dp = newd;
01288 }
01289 else {
01290
01291
01292 dav_lock_indirect *newi = apr_pcalloc(p, sizeof(*newi));
01293
01294
01295 newi->locktoken = (dav_locktoken *)lock->locktoken;
01296 newi->key = lock->info->key;
01297 newi->next = ip;
01298 ip = newi;
01299 }
01300 }
01301 }
01302
01303 if ((err = dav_fs_save_lock_record(lockdb, key, dp, ip)) != NULL) {
01304
01305 return err;
01306 }
01307
01308
01309
01310 if (!resource->exists
01311 && (err = dav_fs_add_locknull_state(lockdb, resource)) != NULL) {
01312
01313 return err;
01314 }
01315
01316 return NULL;
01317 }
01318
01319 static dav_error * dav_fs_remove_lock(dav_lockdb *lockdb,
01320 const dav_resource *resource,
01321 const dav_locktoken *locktoken)
01322 {
01323 dav_error *err;
01324 dav_buffer buf = { 0 };
01325 dav_lock_discovery *dh = NULL;
01326 dav_lock_indirect *ih =