📄 lock.c
字号:
} else { memcpy(ptr, dp->owner, strlen(dp->owner) + 1); ptr += strlen(dp->owner) + 1; } if (dp->auth_user == NULL) { *ptr++ = '\0'; } else { memcpy(ptr, dp->auth_user, strlen(dp->auth_user) + 1); ptr += strlen(dp->auth_user) + 1; } dp = dp->next; } while(ip) { *ptr++ = DAV_LOCK_INDIRECT; /* Indirect lock prefix */ memcpy(ptr, ip->locktoken, sizeof(*ip->locktoken)); /* Locktoken */ ptr += sizeof(*ip->locktoken); memcpy(ptr, &ip->timeout, sizeof(ip->timeout)); /* Expire time */ ptr += sizeof(ip->timeout); memcpy(ptr, &ip->key.dsize, sizeof(ip->key.dsize)); /* Size of key */ ptr += sizeof(ip->key.dsize); memcpy(ptr, ip->key.dptr, ip->key.dsize); /* Key data */ ptr += ip->key.dsize; ip = ip->next; } if ((err = dav_dbm_store(lockdb->info->db, key, val)) != NULL) { /* ### more details? add an error_id? */ return dav_push_error(lockdb->info->pool, HTTP_INTERNAL_SERVER_ERROR, DAV_ERR_LOCK_SAVE_LOCK, "Could not save lock information.", err); } return NULL;}/*** dav_load_lock_record: Reads lock information about key from lock db;** creates linked lists of the direct and indirect locks.**** If add_method = DAV_APPEND_LIST, the result will be appended to the** head of the direct and indirect lists supplied.**** Passive lock removal: If lock has timed out, it will not be returned.** ### How much "logging" does RFC 2518 require?*/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){ apr_pool_t *p = lockdb->info->pool; dav_error *err; apr_size_t offset = 0; int need_save = DAV_FALSE; apr_datum_t val = { 0 }; dav_lock_discovery *dp; dav_lock_indirect *ip; dav_buffer buf = { 0 }; if (add_method != DAV_APPEND_LIST) { *direct = NULL; *indirect = NULL; } if ((err = dav_fs_really_open_lockdb(lockdb)) != NULL) { /* ### add a higher-level error? */ return err; } /* ** If we opened readonly and the db wasn't there, then there are no ** locks for this resource. Just exit. */ if (lockdb->info->db == NULL) return NULL; if ((err = dav_dbm_fetch(lockdb->info->db, key, &val)) != NULL) return err; if (!val.dsize) return NULL; while (offset < val.dsize) { switch (*(val.dptr + offset++)) { case DAV_LOCK_DIRECT: /* Create and fill a dav_lock_discovery structure */ dp = apr_pcalloc(p, sizeof(*dp)); memcpy(dp, val.dptr + offset, sizeof(dp->f)); offset += sizeof(dp->f); dp->locktoken = apr_palloc(p, sizeof(*dp->locktoken)); memcpy(dp->locktoken, val.dptr + offset, sizeof(*dp->locktoken)); offset += sizeof(*dp->locktoken); if (*(val.dptr + offset) == '\0') { ++offset; } else { dp->owner = apr_pstrdup(p, val.dptr + offset); offset += strlen(dp->owner) + 1; } if (*(val.dptr + offset) == '\0') { ++offset; } else { dp->auth_user = apr_pstrdup(p, val.dptr + offset); offset += strlen(dp->auth_user) + 1; } if (!dav_fs_lock_expired(dp->f.timeout)) { dp->next = *direct; *direct = dp; } else { need_save = DAV_TRUE; /* Remove timed-out locknull fm .locknull list */ if (*key.dptr == DAV_TYPE_FNAME) { const char *fname = key.dptr + 1; apr_finfo_t finfo; apr_status_t rv; /* if we don't see the file, then it's a locknull */ rv = apr_lstat(&finfo, fname, APR_FINFO_MIN, p); if (rv != APR_SUCCESS && rv != APR_INCOMPLETE) { if ((err = dav_fs_remove_locknull_member(p, fname, &buf)) != NULL) { /* ### push a higher-level description? */ return err; } } } } break; case DAV_LOCK_INDIRECT: /* Create and fill a dav_lock_indirect structure */ ip = apr_pcalloc(p, sizeof(*ip)); ip->locktoken = apr_palloc(p, sizeof(*ip->locktoken)); memcpy(ip->locktoken, val.dptr + offset, sizeof(*ip->locktoken)); offset += sizeof(*ip->locktoken); memcpy(&ip->timeout, val.dptr + offset, sizeof(ip->timeout)); offset += sizeof(ip->timeout); memcpy(&ip->key.dsize, val.dptr + offset, sizeof(ip->key.dsize)); /* length of datum */ offset += sizeof(ip->key.dsize); ip->key.dptr = apr_palloc(p, ip->key.dsize); memcpy(ip->key.dptr, val.dptr + offset, ip->key.dsize); offset += ip->key.dsize; if (!dav_fs_lock_expired(ip->timeout)) { ip->next = *indirect; *indirect = ip; } else { need_save = DAV_TRUE; /* A locknull resource will never be locked indirectly */ } break; default: dav_dbm_freedatum(lockdb->info->db, val); /* ### should use a computed_desc and insert corrupt token data */ --offset; return dav_new_error(p, HTTP_INTERNAL_SERVER_ERROR, DAV_ERR_LOCK_CORRUPT_DB, apr_psprintf(p, "The lock database was found to " "be corrupt. offset %" APR_SIZE_T_FMT ", c=%02x", offset, val.dptr[offset])); } } dav_dbm_freedatum(lockdb->info->db, val); /* Clean up this record if we found expired locks */ /* ** ### shouldn't do this if we've been opened READONLY. elide the ** ### timed-out locks from the response, but don't save that info back */ if (need_save == DAV_TRUE) { return dav_fs_save_lock_record(lockdb, key, *direct, *indirect); } return NULL;}/* resolve <indirect>, returning <*direct> */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){ dav_error *err; dav_lock_discovery *dir; dav_lock_indirect *ind; if ((err = dav_fs_load_lock_record(lockdb, indirect->key, DAV_CREATE_LIST, &dir, &ind)) != NULL) { /* ### insert a higher-level description? */ return err; } if (ref_dp != NULL) { *ref_dp = dir; *ref_ip = ind; } for (; dir != NULL; dir = dir->next) { if (!dav_compare_locktoken(indirect->locktoken, dir->locktoken)) { *direct = dir; return NULL; } } /* No match found (but we should have found one!) */ /* ### use a different description and/or error ID? */ return dav_new_error(lockdb->info->pool, HTTP_INTERNAL_SERVER_ERROR, DAV_ERR_LOCK_CORRUPT_DB, "The lock database was found to be corrupt. " "An indirect lock's direct lock could not " "be found.");}/* ---------------------------------------------------------------**** Property-related lock functions***//*** dav_fs_get_supportedlock: Returns a static string for all supportedlock** properties. I think we save more returning a static string than** constructing it every time, though it might look cleaner.*/static const char *dav_fs_get_supportedlock(const dav_resource *resource){ static const char supported[] = DEBUG_CR "<D:lockentry>" DEBUG_CR "<D:lockscope><D:exclusive/></D:lockscope>" DEBUG_CR "<D:locktype><D:write/></D:locktype>" DEBUG_CR "</D:lockentry>" DEBUG_CR "<D:lockentry>" DEBUG_CR "<D:lockscope><D:shared/></D:lockscope>" DEBUG_CR "<D:locktype><D:write/></D:locktype>" DEBUG_CR "</D:lockentry>" DEBUG_CR; return supported;}/* ---------------------------------------------------------------**** General lock functions***//* ---------------------------------------------------------------**** Functions dealing with lock-null resources***//*** dav_fs_load_locknull_list: Returns a dav_buffer dump of the locknull file** for the given directory.*/static dav_error * dav_fs_load_locknull_list(apr_pool_t *p, const char *dirpath, dav_buffer *pbuf) { apr_finfo_t finfo; apr_file_t *file = NULL; dav_error *err = NULL; apr_size_t amt; apr_status_t rv; dav_buffer_init(p, pbuf, dirpath); if (pbuf->buf[pbuf->cur_len - 1] == '/') pbuf->buf[--pbuf->cur_len] = '\0'; dav_buffer_place(p, pbuf, "/" DAV_FS_STATE_DIR "/" DAV_FS_LOCK_NULL_FILE); /* reset this in case we leave w/o reading into the buffer */ pbuf->cur_len = 0; if (apr_file_open(&file, pbuf->buf, APR_READ | APR_BINARY, APR_OS_DEFAULT, p) != APR_SUCCESS) { return NULL; } rv = apr_file_info_get(&finfo, APR_FINFO_SIZE, file); if (rv != APR_SUCCESS) { err = dav_new_error(p, HTTP_INTERNAL_SERVER_ERROR, 0, apr_psprintf(p, "Opened but could not stat file %s", pbuf->buf)); goto loaderror; } if (finfo.size != (apr_size_t)finfo.size) { err = dav_new_error(p, HTTP_INTERNAL_SERVER_ERROR, 0, apr_psprintf(p, "Opened but rejected huge file %s", pbuf->buf)); goto loaderror; } amt = (apr_size_t)finfo.size; dav_set_bufsize(p, pbuf, amt); if (apr_file_read(file, pbuf->buf, &amt) != APR_SUCCESS || amt != finfo.size) { err = dav_new_error(p, HTTP_INTERNAL_SERVER_ERROR, 0, apr_psprintf(p, "Failure reading locknull file " "for %s", dirpath)); /* just in case the caller disregards the returned error */ pbuf->cur_len = 0; goto loaderror; } loaderror: apr_file_close(file); return err;}/*** dav_fs_save_locknull_list: Saves contents of pbuf into the** locknull file for dirpath.*/static dav_error * dav_fs_save_locknull_list(apr_pool_t *p, const char *dirpath, dav_buffer *pbuf){ const char *pathname; apr_file_t *file = NULL; dav_error *err = NULL; apr_size_t amt; if (pbuf->buf == NULL) return NULL; dav_fs_ensure_state_dir(p, dirpath); pathname = apr_pstrcat(p, dirpath, dirpath[strlen(dirpath) - 1] == '/' ? "" : "/", DAV_FS_STATE_DIR "/" DAV_FS_LOCK_NULL_FILE, NULL); if (pbuf->cur_len == 0) { /* delete the file if cur_len == 0 */ if (apr_file_remove(pathname, p) != 0) { return dav_new_error(p, HTTP_INTERNAL_SERVER_ERROR, 0, apr_psprintf(p, "Error removing %s", pathname)); } return NULL; } if (apr_file_open(&file, pathname, APR_WRITE | APR_CREATE | APR_TRUNCATE | APR_BINARY, APR_OS_DEFAULT, p) != APR_SUCCESS) { return dav_new_error(p, HTTP_INTERNAL_SERVER_ERROR, 0, apr_psprintf(p, "Error opening %s for writing", pathname)); } amt = pbuf->cur_len; if (apr_file_write(file, pbuf->buf, &amt) != APR_SUCCESS || amt != pbuf->cur_len) { err = dav_new_error(p, HTTP_INTERNAL_SERVER_ERROR, 0, apr_psprintf(p, "Error writing %" APR_SIZE_T_FMT " bytes to %s", pbuf->cur_len, pathname)); } apr_file_close(file); return err;}/*** dav_fs_remove_locknull_member: Removes filename from the locknull list** for directory path.*/static dav_error * dav_fs_remove_locknull_member(apr_pool_t *p, const char *filename, dav_buffer *pbuf){ dav_error *err; apr_size_t len; apr_size_t scanlen; char *scan; const char *scanend; char *dirpath = apr_pstrdup(p, filename); char *fname = strrchr(dirpath, '/'); int dirty = 0; if (fname != NULL) *fname++ = '\0'; else fname = dirpath; len = strlen(fname) + 1; if ((err = dav_fs_load_locknull_list(p, dirpath, pbuf)) != NULL) { /* ### add a higher level description? */ return err; } for (scan = pbuf->buf, scanend = scan + pbuf->cur_len; scan < scanend; scan += scanlen) { scanlen = strlen(scan) + 1; if (len == scanlen && memcmp(fname, scan, scanlen) == 0) { pbuf->cur_len -= scanlen; memmove(scan, scan + scanlen, scanend - (scan + scanlen)); dirty = 1; break; } } if (dirty) { if ((err = dav_fs_save_locknull_list(p, dirpath, pbuf)) != NULL) { /* ### add a higher level description? */ return err; } } return NULL;}/* Note: used by dav_fs_repos.c */dav_error * dav_fs_get_locknull_members( const dav_resource *resource, dav_buffer *pbuf){ const char *dirpath; /* ### should test this result value... */ (void) dav_fs_dir_file_name(resource, &dirpath, NULL); return dav_fs_load_locknull_list(dav_fs_pool(resource), dirpath, pbuf);}/* ### fold into append_lock? *//* ### take an optional buf parameter? */static dav_error * dav_fs_add_locknull_state( dav_lockdb *lockdb, const dav_resource *resource){ dav_buffer buf = { 0 }; apr_pool_t *p = lockdb->info->pool; const char *dirpath; const char *fname; dav_error *err; /* ### should test this result value... */ (void) dav_fs_dir_file_name(resource, &dirpath, &fname); if ((err = dav_fs_load_locknull_list(p, dirpath, &buf)) != NULL) { return dav_push_error(p, HTTP_INTERNAL_SERVER_ERROR, 0, "Could not load .locknull file.", err); } dav_buffer_append(p, &buf, fname); buf.cur_len++; /* we want the null-term here */ if ((err = dav_fs_save_locknull_list(p, dirpath, &buf)) != NULL) { return dav_push_error(p, HTTP_INTERNAL_SERVER_ERROR, 0, "Could not save .locknull file.", err); } return NULL;}/*** dav_fs_remove_locknull_state: Given a request, check to see if r->filename** is/was a lock-null resource. If so, return it to an existant state.**** ### this function is broken... it doesn't check!**** In this implementation, this involves two things:** (a) remove it from the list in the appropriate .DAV/locknull file** (b) on *nix, convert the key from a filename to an inode.*/static dav_error * dav_fs_remove_locknull_state( dav_lockdb *lockdb, const dav_resource *resource){ dav_buffer buf = { 0 }; dav_error *err; apr_pool_t *p = lockdb->info->pool; const char *pathname = dav_fs_pathname(resource); if ((err = dav_fs_remove_locknull_member(p, pathname, &buf)) != NULL) {
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -