📄 ne_locks.c
字号:
static int parse_depth(const char *depth){ if (strcasecmp(depth, "infinity") == 0) { return NE_DEPTH_INFINITE; } else if (isdigit(depth[0])) { return atoi(depth); } else { return -1; }}static long parse_timeout(const char *timeout){ if (strcasecmp(timeout, "infinite") == 0) { return NE_TIMEOUT_INFINITE; } else if (strncasecmp(timeout, "Second-", 7) == 0) { long to = strtol(timeout+7, NULL, 10); if (to == LONG_MIN || to == LONG_MAX) return NE_TIMEOUT_INVALID; return to; } else { return NE_TIMEOUT_INVALID; }}static void discover_results(void *userdata, const char *href, const ne_prop_result_set *set){ struct discover_ctx *ctx = userdata; struct ne_lock *lock = ne_propset_private(set); const ne_status *status = ne_propset_status(set, &lock_props[0]); /* Require at least that the lock has a token. */ if (lock->token) { if (status && status->klass != 2) { ctx->results(ctx->userdata, NULL, lock->uri.path, status); } else { ctx->results(ctx->userdata, lock, lock->uri.path, NULL); } } else if (status) { ctx->results(ctx->userdata, NULL, href, status); } ne_lock_destroy(lock); NE_DEBUG(NE_DBG_LOCKS, "End of response for %s\n", href);}static int end_element_common(struct ne_lock *l, int state, const char *cdata){ switch (state) { case ELM_write: l->type = ne_locktype_write; break; case ELM_exclusive: l->scope = ne_lockscope_exclusive; break; case ELM_shared: l->scope = ne_lockscope_shared; break; case ELM_depth: NE_DEBUG(NE_DBG_LOCKS, "Got depth: %s\n", cdata); l->depth = parse_depth(cdata); if (l->depth == -1) { return -1; } break; case ELM_timeout: NE_DEBUG(NE_DBG_LOCKS, "Got timeout: %s\n", cdata); l->timeout = parse_timeout(cdata); if (l->timeout == NE_TIMEOUT_INVALID) { return -1; } break; case ELM_owner: l->owner = strdup(cdata); break; case ELM_href: l->token = strdup(cdata); break; } return 0;}/* End-element handler for lock discovery PROPFIND response */static int end_element_ldisc(void *userdata, int state, const char *nspace, const char *name){ struct ne_lock *lock = ne_propfind_current_private(userdata); struct discover_ctx *ctx = userdata; return end_element_common(lock, state, ctx->cdata->data);}static inline int can_accept(int parent, int id){ return (parent == NE_XML_STATEROOT && id == ELM_prop) || (parent == ELM_prop && id == ELM_lockdiscovery) || (parent == ELM_lockdiscovery && id == ELM_activelock) || (parent == ELM_activelock && (id == ELM_lockscope || id == ELM_locktype || id == ELM_depth || id == ELM_owner || id == ELM_timeout || id == ELM_locktoken)) || (parent == ELM_lockscope && (id == ELM_exclusive || id == ELM_shared)) || (parent == ELM_locktype && id == ELM_write) || (parent == ELM_locktoken && id == ELM_href);}static int ld_startelm(void *userdata, int parent, const char *nspace, const char *name, const char **atts){ struct discover_ctx *ctx = userdata; int id = ne_xml_mapid(element_map, NE_XML_MAPLEN(element_map), nspace, name); ne_buffer_clear(ctx->cdata); if (can_accept(parent, id)) return id; else return NE_XML_DECLINE;} #define MAX_CDATA (256)static int lk_cdata(void *userdata, int state, const char *cdata, size_t len){ struct lock_ctx *ctx = userdata; if (ctx->cdata->used + len < MAX_CDATA) ne_buffer_append(ctx->cdata, cdata, len); return 0;}static int ld_cdata(void *userdata, int state, const char *cdata, size_t len){ struct discover_ctx *ctx = userdata; if (ctx->cdata->used + len < MAX_CDATA) ne_buffer_append(ctx->cdata, cdata, len); return 0;}static int lk_startelm(void *userdata, int parent, const char *nspace, const char *name, const char **atts){ struct lock_ctx *ctx = userdata; int id; id = ne_xml_mapid(element_map, NE_XML_MAPLEN(element_map), nspace, name); NE_DEBUG(NE_DBG_LOCKS, "lk_startelm: %s => %d\n", name, id); /* Lock-Token header is a MUST requirement: if the token * is not known, bail out. */ if (id == 0 || ctx->token == NULL) return NE_XML_DECLINE; /* TODO: only accept 'prop' as root for LOCK response */ if (!can_accept(parent, id)) return NE_XML_DECLINE; if (id == ELM_activelock && !ctx->found) { /* a new activelock */ ne_lock_free(&ctx->active); memset(&ctx->active, 0, sizeof ctx->active); } ne_buffer_clear(ctx->cdata); return id;}/* End-element handler for LOCK response */static int lk_endelm(void *userdata, int state, const char *nspace, const char *name){ struct lock_ctx *ctx = userdata; if (ctx->found) return 0; if (end_element_common(&ctx->active, state, ctx->cdata->data)) return -1; if (state == ELM_activelock) { if (ctx->active.token && strcmp(ctx->active.token, ctx->token) == 0) { ctx->found = 1; } } return 0;}static void *ld_create(void *userdata, const char *href){ struct discover_ctx *ctx = userdata; struct ne_lock *lk = ne_lock_create(); if (ne_uri_parse(href, &lk->uri) != 0) { ne_lock_destroy(lk); return NULL; } if (!lk->uri.host) ne_fill_server_uri(ctx->session, &lk->uri); return lk;}/* Discover all locks on URI */int ne_lock_discover(ne_session *sess, const char *uri, ne_lock_result callback, void *userdata){ ne_propfind_handler *handler; struct discover_ctx ctx = {0}; int ret; ctx.results = callback; ctx.userdata = userdata; ctx.session = sess; ctx.cdata = ne_buffer_create(); handler = ne_propfind_create(sess, uri, NE_DEPTH_ZERO); ne_propfind_set_private(handler, ld_create, &ctx); ne_xml_push_handler(ne_propfind_get_parser(handler), ld_startelm, ld_cdata, end_element_ldisc, handler); ret = ne_propfind_named(handler, lock_props, discover_results, &ctx); ne_buffer_destroy(ctx.cdata); ne_propfind_destroy(handler); return ret;}static void add_timeout_header(ne_request *req, long timeout){ if (timeout == NE_TIMEOUT_INFINITE) { ne_add_request_header(req, "Timeout", "Infinite"); } else if (timeout != NE_TIMEOUT_INVALID && timeout > 0) { ne_print_request_header(req, "Timeout", "Second-%ld", timeout); } /* just ignore it if timeout == 0 or invalid. */}/* Parse a Lock-Token response header. */static void get_ltoken_hdr(void *ud, const char *value){ struct lock_ctx *ctx = ud; if (value[0] == '<') value++; ctx->token = ne_strdup(value); ne_shave(ctx->token, ">");}int ne_lock(ne_session *sess, struct ne_lock *lock) { ne_request *req = ne_request_create(sess, "LOCK", lock->uri.path); ne_buffer *body = ne_buffer_create(); ne_xml_parser *parser = ne_xml_create(); int ret, parse_failed; struct lock_ctx ctx; memset(&ctx, 0, sizeof ctx); ctx.cdata = ne_buffer_create(); ne_xml_push_handler(parser, lk_startelm, lk_cdata, lk_endelm, &ctx); /* Create the body */ ne_buffer_concat(body, "<?xml version=\"1.0\" encoding=\"utf-8\"?>" EOL "<lockinfo xmlns='DAV:'>" EOL " <lockscope>", lock->scope==ne_lockscope_exclusive? "<exclusive/>":"<shared/>", "</lockscope>" EOL "<locktype><write/></locktype>", NULL); if (lock->owner) { ne_buffer_concat(body, "<owner>", lock->owner, "</owner>" EOL, NULL); } ne_buffer_zappend(body, "</lockinfo>" EOL); ne_set_request_body_buffer(req, body->data, ne_buffer_size(body)); ne_add_response_body_reader(req, ne_accept_2xx, ne_xml_parse_v, parser); ne_add_request_header(req, "Content-Type", NE_XML_MEDIA_TYPE); ne_add_depth_header(req, lock->depth); add_timeout_header(req, lock->timeout); ne_add_response_header_handler(req, "Lock-Token", get_ltoken_hdr, &ctx); /* TODO: * By 2518, we need this only if we are creating a lock-null resource. * Since we don't KNOW whether the lock we're given is a lock-null * or not, we cover our bases. */ ne_lock_using_parent(req, lock->uri.path); /* This one is clearer from 2518 sec 8.10.4. */ ne_lock_using_resource(req, lock->uri.path, lock->depth); ret = ne_request_dispatch(req); ne_buffer_destroy(body); ne_buffer_destroy(ctx.cdata); parse_failed = !ne_xml_valid(parser); if (ret == NE_OK && ne_get_status(req)->klass == 2) { if (ctx.token == NULL) { ret = NE_ERROR; ne_set_error(sess, _("No Lock-Token header given")); } else if (parse_failed) { ret = NE_ERROR; ne_set_error(sess, "%s", ne_xml_get_error(parser)); } else if (ne_get_status(req)->code == 207) { ret = NE_ERROR; /* TODO: set the error string appropriately */ } else if (ctx.found) { /* it worked: copy over real lock details if given. */ NE_FREE(lock->token); lock->token = ctx.token; ctx.token = NULL; if (ctx.active.timeout != NE_TIMEOUT_INVALID) lock->timeout = ctx.active.timeout; lock->scope = ctx.active.scope; lock->type = ctx.active.type; if (ctx.active.depth >= 0) lock->depth = ctx.active.depth; if (ctx.active.owner) { NE_FREE(lock->owner); lock->owner = ctx.active.owner; ctx.active.owner = NULL; } } else { ret = NE_ERROR; ne_set_error(sess, _("Response missing activelock for %s"), ctx.token); } } else { ret = NE_ERROR; } if (ctx.token) ne_free(ctx.token); ne_lock_free(&ctx.active); ne_request_destroy(req); ne_xml_destroy(parser); return ret;}int ne_lock_refresh(ne_session *sess, struct ne_lock *lock){ ne_request *req = ne_request_create(sess, "LOCK", lock->uri.path); ne_xml_parser *parser = ne_xml_create(); int ret, parse_failed; /* Handle the response and update *lock appropriately. */ ne_xml_push_handler(parser, lk_startelm, NULL, lk_endelm, lock); ne_add_response_body_reader(req, ne_accept_2xx, ne_xml_parse_v, parser); /* Probably don't need to submit any other lock-tokens for this * resource? If it's an exclusive lock, then there can be no other * locks covering the resource. If it's a shared lock, then this * lock (which is being refreshed) is sufficient to modify the * resource state? */ ne_print_request_header(req, "If", "(<%s>)", lock->token); add_timeout_header(req, lock->timeout); ret = ne_request_dispatch(req); parse_failed = !ne_xml_valid(parser); if (ret == NE_OK && ne_get_status(req)->klass == 2) { if (parse_failed) { ret = NE_ERROR; ne_set_error(sess, "%s", ne_xml_get_error(parser)); } else if (ne_get_status(req)->code == 207) { ret = NE_ERROR; /* TODO: set the error string appropriately */ } } else { ret = NE_ERROR; } ne_request_destroy(req); ne_xml_destroy(parser); return ret;}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -