📄 ne_locks.c
字号:
/* WebDAV Class 2 locking operations Copyright (C) 1999-2004, Joe Orton <joe@manyfish.co.uk> This library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public License for more details. You should have received a copy of the GNU Library General Public License along with this library; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA*/#include "config.h"#ifdef HAVE_STDLIB_H#include <stdlib.h>#endif#ifdef HAVE_STRING_H#include <string.h>#endif#ifdef HAVE_LIMITS_H#include <limits.h>#endif#include <ctype.h> /* for isdigit() */#include "ne_alloc.h"#include "ne_request.h"#include "ne_xml.h"#include "ne_locks.h"#include "ne_uri.h"#include "ne_basic.h"#include "ne_props.h"#include "ne_207.h"#include "ne_i18n.h"#define HOOK_ID "http://webdav.org/neon/hooks/webdav-locking"/* A list of lock objects. */struct lock_list { struct ne_lock *lock; struct lock_list *next, *prev;};struct ne_lock_store_s { struct lock_list *locks; struct lock_list *cursor; /* current position in 'locks' */};struct lh_req_cookie { const ne_lock_store *store; struct lock_list *submit;};/* Context for PROPFIND/lockdiscovery callbacks */struct discover_ctx { ne_session *session; ne_lock_result results; void *userdata; ne_buffer *cdata;};/* Context for handling LOCK response */struct lock_ctx { struct ne_lock active; /* activelock */ char *token; /* the token we're after. */ int found; ne_buffer *cdata;};/* use the "application" state space. */#define ELM_LOCK_FIRST (NE_PROPS_STATE_TOP + 66)#define ELM_lockdiscovery (ELM_LOCK_FIRST)#define ELM_activelock (ELM_LOCK_FIRST + 1)#define ELM_lockscope (ELM_LOCK_FIRST + 2)#define ELM_locktype (ELM_LOCK_FIRST + 3)#define ELM_depth (ELM_LOCK_FIRST + 4)#define ELM_owner (ELM_LOCK_FIRST + 5)#define ELM_timeout (ELM_LOCK_FIRST + 6)#define ELM_locktoken (ELM_LOCK_FIRST + 7)#define ELM_lockinfo (ELM_LOCK_FIRST + 8)#define ELM_write (ELM_LOCK_FIRST + 9)#define ELM_exclusive (ELM_LOCK_FIRST + 10)#define ELM_shared (ELM_LOCK_FIRST + 11)#define ELM_href (ELM_LOCK_FIRST + 12)#define ELM_prop (NE_207_STATE_PROP)static const struct ne_xml_idmap element_map[] = {#define ELM(x) { "DAV:", #x, ELM_ ## x } ELM(lockdiscovery), ELM(activelock), ELM(prop), ELM(lockscope), ELM(locktype), ELM(depth), ELM(owner), ELM(timeout), ELM(locktoken), ELM(lockinfo), ELM(lockscope), ELM(locktype), ELM(write), ELM(exclusive), ELM(shared), ELM(href) /* no "lockentry" */#undef ELM};static const ne_propname lock_props[] = { { "DAV:", "lockdiscovery" }, { NULL }};/* this simply registers the accessor for the function. */static void lk_create(ne_request *req, void *session, const char *method, const char *uri){ struct lh_req_cookie *lrc = ne_malloc(sizeof *lrc); lrc->store = session; lrc->submit = NULL; ne_set_request_private(req, HOOK_ID, lrc);}static void lk_pre_send(ne_request *r, void *userdata, ne_buffer *req){ struct lh_req_cookie *lrc = ne_get_request_private(r, HOOK_ID); if (lrc->submit != NULL) { struct lock_list *item; /* Add in the If header */ ne_buffer_zappend(req, "If:"); for (item = lrc->submit; item != NULL; item = item->next) { char *uri = ne_uri_unparse(&item->lock->uri); ne_buffer_concat(req, " <", uri, "> (<", item->lock->token, ">)", NULL); ne_free(uri); } ne_buffer_zappend(req, EOL); }}/* Insert 'lock' into lock list *list. */static void insert_lock(struct lock_list **list, struct ne_lock *lock){ struct lock_list *item = ne_malloc(sizeof *item); if (*list != NULL) { (*list)->prev = item; } item->prev = NULL; item->next = *list; item->lock = lock; *list = item;}static void free_list(struct lock_list *list, int destroy){ struct lock_list *next; while (list != NULL) { next = list->next; if (destroy) ne_lock_destroy(list->lock); ne_free(list); list = next; }}static void lk_destroy(ne_request *req, void *userdata){ struct lh_req_cookie *lrc = ne_get_request_private(req, HOOK_ID); free_list(lrc->submit, 0); ne_free(lrc);}void ne_lockstore_destroy(ne_lock_store *store){ free_list(store->locks, 1); ne_free(store);}ne_lock_store *ne_lockstore_create(void){ return ne_calloc(sizeof(ne_lock_store));}#define CURSOR_RET(s) ((s)->cursor?(s)->cursor->lock:NULL)struct ne_lock *ne_lockstore_first(ne_lock_store *store){ store->cursor = store->locks; return CURSOR_RET(store);}struct ne_lock *ne_lockstore_next(ne_lock_store *store){ store->cursor = store->cursor->next; return CURSOR_RET(store);}void ne_lockstore_register(ne_lock_store *store, ne_session *sess){ /* Register the hooks */ ne_hook_create_request(sess, lk_create, store); ne_hook_pre_send(sess, lk_pre_send, store); ne_hook_destroy_request(sess, lk_destroy, store);}/* Submit the given lock for the given URI */static void submit_lock(struct lh_req_cookie *lrc, struct ne_lock *lock){ struct lock_list *item; /* Check for dups */ for (item = lrc->submit; item != NULL; item = item->next) { if (strcasecmp(item->lock->token, lock->token) == 0) return; } insert_lock(&lrc->submit, lock);}struct ne_lock *ne_lockstore_findbyuri(ne_lock_store *store, const ne_uri *uri){ struct lock_list *cur; for (cur = store->locks; cur != NULL; cur = cur->next) { if (ne_uri_cmp(&cur->lock->uri, uri) == 0) { return cur->lock; } } return NULL;}void ne_lock_using_parent(ne_request *req, const char *path){ struct lh_req_cookie *lrc = ne_get_request_private(req, HOOK_ID); ne_uri u; struct lock_list *item; char *parent; if (lrc == NULL) return; parent = ne_path_parent(path); if (parent == NULL) return; u.authinfo = NULL; ne_fill_server_uri(ne_get_session(req), &u); for (item = lrc->store->locks; item != NULL; item = item->next) { /* Only care about locks which are on this server. */ u.path = item->lock->uri.path; if (ne_uri_cmp(&u, &item->lock->uri)) continue; /* This lock is needed if it is an infinite depth lock which * covers the parent, or a lock on the parent itself. */ if ((item->lock->depth == NE_DEPTH_INFINITE && ne_path_childof(item->lock->uri.path, parent)) || ne_path_compare(item->lock->uri.path, parent) == 0) { NE_DEBUG(NE_DBG_LOCKS, "Locked parent, %s on %s\n", item->lock->token, item->lock->uri.path); submit_lock(lrc, item->lock); } } u.path = parent; /* handy: makes u.path valid and ne_free(parent). */ ne_uri_free(&u);}void ne_lock_using_resource(ne_request *req, const char *uri, int depth){ struct lh_req_cookie *lrc = ne_get_request_private(req, HOOK_ID); struct lock_list *item; int match; if (lrc == NULL) return; /* Iterate over the list of stored locks to see if any of them * apply to this resource */ for (item = lrc->store->locks; item != NULL; item = item->next) { match = 0; if (depth == NE_DEPTH_INFINITE && ne_path_childof(uri, item->lock->uri.path)) { /* Case 1: this is a depth-infinity request which will * modify a lock somewhere inside the collection. */ NE_DEBUG(NE_DBG_LOCKS, "Has child: %s\n", item->lock->token); match = 1; } else if (ne_path_compare(uri, item->lock->uri.path) == 0) { /* Case 2: this request is directly on a locked resource */ NE_DEBUG(NE_DBG_LOCKS, "Has direct lock: %s\n", item->lock->token); match = 1; } else if (item->lock->depth == NE_DEPTH_INFINITE && ne_path_childof(item->lock->uri.path, uri)) { /* Case 3: there is a higher-up infinite-depth lock which * covers the resource that this request will modify. */ NE_DEBUG(NE_DBG_LOCKS, "Is child of: %s\n", item->lock->token); match = 1; } if (match) { submit_lock(lrc, item->lock); } }}void ne_lockstore_add(ne_lock_store *store, struct ne_lock *lock){ insert_lock(&store->locks, lock);}void ne_lockstore_remove(ne_lock_store *store, struct ne_lock *lock){ struct lock_list *item; /* Find the lock */ for (item = store->locks; item != NULL; item = item->next) if (item->lock == lock) break; if (item->prev != NULL) { item->prev->next = item->next; } else { store->locks = item->next; } if (item->next != NULL) { item->next->prev = item->prev; } ne_free(item);}struct ne_lock *ne_lock_copy(const struct ne_lock *lock){ struct ne_lock *ret = ne_calloc(sizeof *ret); ret->uri.path = ne_strdup(lock->uri.path); ret->uri.host = ne_strdup(lock->uri.host); ret->uri.scheme = ne_strdup(lock->uri.scheme); ret->uri.port = lock->uri.port; ret->token = ne_strdup(lock->token); ret->depth = lock->depth; ret->type = lock->type; ret->scope = lock->scope; if (lock->owner) ret->owner = ne_strdup(lock->owner); ret->timeout = lock->timeout; return ret;}struct ne_lock *ne_lock_create(void){ struct ne_lock *lock = ne_calloc(sizeof *lock); lock->depth = NE_DEPTH_ZERO; lock->type = ne_locktype_write; lock->scope = ne_lockscope_exclusive; lock->timeout = NE_TIMEOUT_INVALID; return lock;}void ne_lock_free(struct ne_lock *lock){ ne_uri_free(&lock->uri); NE_FREE(lock->owner); NE_FREE(lock->token);}void ne_lock_destroy(struct ne_lock *lock){ ne_lock_free(lock); ne_free(lock);}int ne_unlock(ne_session *sess, const struct ne_lock *lock){ ne_request *req = ne_request_create(sess, "UNLOCK", lock->uri.path); int ret; ne_print_request_header(req, "Lock-Token", "<%s>", lock->token); /* UNLOCK of a lock-null resource removes the resource from the * parent collection; so an UNLOCK may modify the parent * collection. (somewhat counter-intuitive, and not easily derived * from 2518.) */ ne_lock_using_parent(req, lock->uri.path); ret = ne_request_dispatch(req); if (ret == NE_OK && ne_get_status(req)->klass == 2) { ret = NE_OK; } else { ret = NE_ERROR; } ne_request_destroy(req); return ret;}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -