aboutsummaryrefslogtreecommitdiff
path: root/src/windows/identity/util
diff options
context:
space:
mode:
authorJeffrey Altman <jaltman@secure-endpoints.com>2005-11-02 01:14:30 +0000
committerJeffrey Altman <jaltman@secure-endpoints.com>2005-11-02 01:14:30 +0000
commit5c27b523150384dd8655e739d68f01be2e4ff5d4 (patch)
tree649928f66dba979d1a84a9317b83a678e8321889 /src/windows/identity/util
parent5aa72f089113f917694a20144dca42049951c4da (diff)
downloadkrb5-5c27b523150384dd8655e739d68f01be2e4ff5d4.zip
krb5-5c27b523150384dd8655e739d68f01be2e4ff5d4.tar.gz
krb5-5c27b523150384dd8655e739d68f01be2e4ff5d4.tar.bz2
Initial Commit Network Identity Manager for Windows
Initial commit of Network Identity Manager for KFW 3.0 Beta 1 ticket: new tags: pullup component: windows git-svn-id: svn://anonsvn.mit.edu/krb5/trunk@17476 dc483132-0cff-0310-8789-dd5450dbe970
Diffstat (limited to 'src/windows/identity/util')
-rw-r--r--src/windows/identity/util/Makefile46
-rw-r--r--src/windows/identity/util/hashtable.c167
-rw-r--r--src/windows/identity/util/hashtable.h223
-rw-r--r--src/windows/identity/util/mstring.c516
-rw-r--r--src/windows/identity/util/mstring.h361
-rw-r--r--src/windows/identity/util/sync.c121
-rw-r--r--src/windows/identity/util/sync.h128
-rw-r--r--src/windows/identity/util/utils.h36
8 files changed, 1598 insertions, 0 deletions
diff --git a/src/windows/identity/util/Makefile b/src/windows/identity/util/Makefile
new file mode 100644
index 0000000..b9fc80e
--- /dev/null
+++ b/src/windows/identity/util/Makefile
@@ -0,0 +1,46 @@
+#
+# Copyright (c) 2004 Massachusetts Institute of Technology
+#
+# Permission is hereby granted, free of charge, to any person
+# obtaining a copy of this software and associated documentation files
+# (the "Software"), to deal in the Software without restriction,
+# including without limitation the rights to use, copy, modify, merge,
+# publish, distribute, sublicense, and/or sell copies of the Software,
+# and to permit persons to whom the Software is furnished to do so,
+# subject to the following conditions:
+#
+# The above copyright notice and this permission notice shall be
+# included in all copies or substantial portions of the Software.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+# BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+# ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+# SOFTWARE.
+
+
+MODULE=util
+!include <../config/Makefile.w32>
+
+INCFILES= \
+ $(INCDIR)\utils.h \
+ $(INCDIR)\hashtable.h \
+ $(INCDIR)\mstring.h \
+ $(INCDIR)\sync.h
+
+OBJFILES= \
+ $(OBJ)\hashtable.obj \
+ $(OBJ)\mstring.obj \
+ $(OBJ)\sync.obj
+
+LIBFILES=
+
+SDKLIBFILES=
+
+all: mkdirs $(INCFILES) $(OBJFILES)
+
+clean::
+ $(RM) $(INCFILES)
diff --git a/src/windows/identity/util/hashtable.c b/src/windows/identity/util/hashtable.c
new file mode 100644
index 0000000..41f785a
--- /dev/null
+++ b/src/windows/identity/util/hashtable.c
@@ -0,0 +1,167 @@
+/*
+ * Copyright (c) 2004 Massachusetts Institute of Technology
+ *
+ * Permission is hereby granted, free of charge, to any person
+ * obtaining a copy of this software and associated documentation
+ * files (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use, copy,
+ * modify, merge, publish, distribute, sublicense, and/or sell copies
+ * of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+/* $Id$ */
+
+#include<hashtable.h>
+#include<stdlib.h>
+
+KHMEXP hashtable * KHMAPI hash_new_hashtable(khm_int32 n,
+ hash_function_t hash,
+ comp_function_t comp,
+ add_ref_function_t addr,
+ del_ref_function_t delr)
+{
+ hashtable * h;
+
+ h = malloc(sizeof(hashtable));
+
+ h->n = n;
+ h->addr = addr;
+ h->comp = comp;
+ h->delr = delr;
+ h->hash = hash;
+
+ h->bins = calloc(sizeof(hash_bin *), n);
+
+ return h;
+}
+
+KHMEXP void KHMAPI hash_del_hashtable(hashtable * h) {
+ hash_bin * b;
+ int i;
+
+ for(i=0;i<h->n;i++) {
+ LPOP(&h->bins[i], &b);
+ while(b) {
+ if(h->delr)
+ h->delr(b->key, b->data);
+ free(b);
+ LPOP(&h->bins[i], &b);
+ }
+ }
+
+ free(h);
+}
+
+KHMEXP void KHMAPI hash_add(hashtable * h, void * key, void * data) {
+ int hv;
+ hash_bin * b;
+
+ hv = h->hash(key) % h->n;
+ b = h->bins[hv];
+ while(b) {
+ if(!h->comp(b->key, key)) {
+ /* found an existing value */
+ if(h->delr)
+ h->delr(b->key, b->data);
+ b->key = key;
+ b->data = data;
+ if(h->addr)
+ h->addr(b->key, b->data);
+ break;
+ }
+ b = LNEXT(b);
+ }
+
+ if(!b) {
+ b = malloc(sizeof(hash_bin));
+ b->data = data;
+ b->key = key;
+ LINIT(b);
+ LPUSH(&h->bins[hv], b);
+ if(h->addr)
+ h->addr(b->key, b->data);
+ }
+}
+
+KHMEXP void KHMAPI hash_del(hashtable * h, void * key) {
+ hash_bin * b;
+ int hv;
+
+ hv = h->hash(key) % h->n;
+
+ b = h->bins[hv];
+ while(b) {
+ if(!h->comp(b->key, key)) {
+ /* found it */
+ LDELETE(&h->bins[hv], b);
+ if(h->delr)
+ h->delr(b->key, b->data);
+ free(b);
+ break;
+ }
+ b = LNEXT(b);
+ }
+}
+
+KHMEXP void * KHMAPI hash_lookup(hashtable * h, void * key) {
+ hash_bin * b;
+ int hv;
+
+ hv = h->hash(key) % h->n;
+
+ b = h->bins[hv];
+
+ while(b) {
+ if(!h->comp(b->key, key)) {
+ return b->data;
+ }
+ b = LNEXT(b);
+ }
+
+ return NULL;
+}
+
+KHMEXP khm_boolean KHMAPI hash_exist(hashtable * h, void * key) {
+ hash_bin * b;
+ int hv;
+
+ hv = h->hash(key) % h->n;
+ b = h->bins[hv];
+ while(b) {
+ if(!h->comp(b->key, key))
+ return 1;
+ b = LNEXT(b);
+ }
+
+ return 0;
+}
+
+KHMEXP khm_int32 hash_string(const void *vs) {
+ /* DJB algorithm */
+
+ khm_int32 hv = 13331;
+ wchar_t * c;
+
+ for(c = (wchar_t *) vs; *c; c++) {
+ hv = ((hv<<5) + hv) + (khm_int32) *c;
+ }
+
+ return (hv & KHM_INT32_MAX);
+}
+
+KHMEXP khm_int32 hash_string_comp(const void *vs1, const void *vs2) {
+ return wcscmp((const wchar_t *) vs1, (const wchar_t *) vs2);
+}
diff --git a/src/windows/identity/util/hashtable.h b/src/windows/identity/util/hashtable.h
new file mode 100644
index 0000000..179d311
--- /dev/null
+++ b/src/windows/identity/util/hashtable.h
@@ -0,0 +1,223 @@
+/*
+ * Copyright (c) 2004 Massachusetts Institute of Technology
+ *
+ * Permission is hereby granted, free of charge, to any person
+ * obtaining a copy of this software and associated documentation
+ * files (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use, copy,
+ * modify, merge, publish, distribute, sublicense, and/or sell copies
+ * of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+/* $Id$ */
+
+#ifndef __KHIMAIRA_HASHTABLE_H
+#define __KHIMAIRA_HASHTABLE_H
+
+/*! \addtogroup util
+ @{ */
+
+/*! \defgroup util_ht Hashtable
+ @{*/
+
+#include<khdefs.h>
+#include<khlist.h>
+
+/*! \brief A hash function
+
+ The function should take a key as a parameter and return an
+ khm_int32 that serves as the hash of the key.
+ */
+typedef khm_int32 (*hash_function_t)(const void *key);
+
+/*! \brief A comparison function
+
+ The function takes two keys and returns a value indicating the
+ relative ordering of the two keys.
+
+ The return value should be:
+ - \b Zero if \a key1 == \a key2
+ - \b Negative if \a key1 &lt; \a key2
+ - \b Positive if \a key1 &gt; \a key2
+ */
+typedef khm_int32 (*comp_function_t)(const void *key1, const void *key2);
+
+/*! \brief Add-reference function
+
+ When an object is successfully added to a hashtable, this function
+ will be called with the \a key and \a data used to add the object.
+ The function is allowed to modify \a data, however, the
+ modification should not alter the \a key or the relationship
+ between \a key and \a data.
+ */
+typedef void (*add_ref_function_t)(const void *key, void *data);
+
+/*! \brief Delete-reference function
+
+ When an object is successfully removed from the hashtable, this
+ function will be called. As with the add-ref function, the object
+ can be modified, but the \a key and the relationship between \a
+ key and \a data should remain intact.
+
+ An object is removed if it is explicitly removed from the
+ hashtable or another object with the same \a key is added to the
+ hashtable. There should be a 1-1 correspondence with keys and
+ objects in the hashtable. The delete-reference function will be
+ called on all the remaining objects in the hashtable when the
+ hashtable is deleted.
+ */
+typedef void (*del_ref_function_t)(const void *key, void *data);
+
+typedef struct tag_hash_bin {
+ void * data;
+ void * key;
+
+ LDCL(struct tag_hash_bin);
+} hash_bin;
+
+typedef struct hashtable_t {
+ khm_int32 n;
+ hash_function_t hash;
+ comp_function_t comp;
+ add_ref_function_t addr;
+ del_ref_function_t delr;
+ hash_bin ** bins;
+} hashtable;
+
+/*! \brief Create a new hashtable
+
+ \param[in] n Number of bins in hashtable.
+ \param[in] hash A hash function. Required.
+ \param[in] comp A comparator. Required.
+ \param[in] addr An add-ref function. Optional; can be NULL.
+ \param[in] delr A del-ref function. Optional; can be NULL.
+
+ */
+KHMEXP hashtable * KHMAPI hash_new_hashtable(khm_int32 n,
+ hash_function_t hash,
+ comp_function_t comp,
+ add_ref_function_t addr,
+ del_ref_function_t delr);
+
+/*! \brief Delete a hashtable
+
+ \note Not thread-safe. Applications must serialize calls that
+ reference the same hashtable.
+ */
+KHMEXP void KHMAPI hash_del_hashtable(hashtable * h);
+
+/*! \brief Add an object to a hashtable
+
+ Creates an association between the \a key and \a data in the
+ hashtable \a h. If there is an add-ref function defined for the
+ hashtable, it will be called with \a key and \data after the
+ object is added. If there is already an object with the same key
+ in the hashtable, that object will be removed (and the del-ref
+ function called, if appilcable) before adding the new object and
+ before the add-ref function is called for the new object.
+
+ Note that two keys \a key1 and \a key2 are equal (or same) in a
+ hashtable if the comparator returns zero when called with \a key1
+ and \a key2.
+
+ Also note that all additions and removals to the hashtable are
+ done by reference. No data is copied. Any objects pointed to are
+ expected to exist for the duration that the object and key are
+ contained in the hashtable.
+
+ \param[in] h Hashtable
+ \param[in] key A key. If \a key points to a location in memory,
+ it should be within the object pointed to by \a data, or be a
+ constant. Can be NULL.
+ \param[in] data Data. Cannot be NULL.
+
+ \note Not thread-safe. Applications must serialize calls that
+ reference the same hashtable.
+ */
+KHMEXP void KHMAPI hash_add(hashtable * h, void * key, void * data);
+
+/*! \brief Delete an object from a hashtable
+
+ Deletes the object in the hashtable \a h that is associated with
+ key \a key. An object is associated with key \a key if the key \a
+ key_o that the object is associated with is the same as \a key as
+ determined by the comparator. If the del-ref function is defined
+ for the hash-table, it will be called with the \a key_o and \a
+ data that was used to add the object.
+
+ \note Not thread-safe. Applications must serialize calls that
+ reference the same hashtable.
+ */
+KHMEXP void KHMAPI hash_del(hashtable * h, void * key);
+
+/*! \brief Resolve and association
+
+ Return the object that is associated with key \a key in hashtable
+ \a h. An object \a data is associated with key \a key in \a h if
+ the key \a key_o that was used to add \a data to \a h is equal to
+ \a key as determined by the comparator.
+
+ Returns NULL if no association is found.
+
+ \note Not thread-safe. Applications must serialize calls that
+ reference the same hashtable.
+ */
+KHMEXP void * KHMAPI hash_lookup(hashtable * h, void * key);
+
+/*! \brief Check for the presence of an association
+
+ Returns non-zero if there exists an association between key \a key
+ and some object in hashtable \a h. See hash_lookup() for
+ definition of "association".
+
+ Returns zero if there is no association.
+
+ \note (hash_lookup(h,key) == NULL) iff (hash_exist(h,key)==0)
+
+ \note Not thead-safe. Application must serialize calls that
+ reference the same hashtable.
+ */
+KHMEXP khm_boolean KHMAPI hash_exist(hashtable * h, void * key);
+
+/*! \brief Compute a hashvalue for a unicode string
+
+ The hash value is computed using DJB with parameter 13331.
+
+ This function is suitable for use as the hash function for a
+ hashtable if the keys are NULL terminated safe unicode strings
+ that are either part of the data objects or are constants.
+
+ \param[in] str A pointer to a NULL terminated wchar_t string cast
+ as (void *).
+ */
+KHMEXP khm_int32 hash_string(const void *str);
+
+/*! \brief Compare two strings
+
+ Compares two strings are returns a value that is in accordance
+ with the comparator for a hashtable.
+
+ \param[in] vs1 A pointer to a NULL terminated wchar_t string cast
+ as (void *).
+ \param[in] vs2 A pointer to a NULL terminated wchar_t string cast
+ as (void *).
+ */
+KHMEXP khm_int32 hash_string_comp(const void *vs1, const void *vs2);
+
+/*@}*/
+/*@}*/
+
+#endif
diff --git a/src/windows/identity/util/mstring.c b/src/windows/identity/util/mstring.c
new file mode 100644
index 0000000..e9120d6
--- /dev/null
+++ b/src/windows/identity/util/mstring.c
@@ -0,0 +1,516 @@
+/*
+* Copyright (c) 2004 Massachusetts Institute of Technology
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use, copy,
+* modify, merge, publish, distribute, sublicense, and/or sell copies
+* of the Software, and to permit persons to whom the Software is
+* furnished to do so, subject to the following conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+* SOFTWARE.
+*/
+
+/* $Id$ */
+
+#include<mstring.h>
+#include<kherror.h>
+#include<strsafe.h>
+#include<stdlib.h>
+
+#define TRUE 1
+#define FALSE 0
+
+KHMEXP khm_int32 KHMAPI
+multi_string_init(wchar_t * ms,
+ khm_size cb_ms) {
+ if (!ms || cb_ms < sizeof(wchar_t) * 2)
+ return KHM_ERROR_INVALID_PARM;
+
+ memset(ms, 0, cb_ms);
+
+ return KHM_ERROR_SUCCESS;
+}
+
+KHMEXP khm_int32 KHMAPI
+multi_string_append(
+ wchar_t * ms,
+ khm_size * pcb_ms,
+ const wchar_t * str)
+{
+ wchar_t * s;
+ size_t cch_s;
+ size_t cch_t;
+ size_t cch_r;
+
+ if(!ms || !pcb_ms || !str)
+ return KHM_ERROR_INVALID_PARM;
+
+ if(FAILED(StringCchLength(str, KHM_MAXCCH_STRING, &cch_s)) || cch_s == 0)
+ return KHM_ERROR_INVALID_PARM;
+ cch_s++;
+
+ s = ms;
+
+ while(*s && ((s - ms) < KHM_MAXCCH_STRING)) {
+ if(FAILED(StringCchLength(s, KHM_MAXCB_STRING, &cch_t)))
+ return KHM_ERROR_INVALID_PARM;
+ s += cch_t + 1;
+ }
+
+ if(*s || (s - ms) >= KHM_MAXCCH_STRING) {
+ return KHM_ERROR_INVALID_PARM;
+ }
+
+ /* now s points to the second NULL of the terminating double NULL */
+
+ cch_r = ((s - ms) + cch_s + 1) * sizeof(wchar_t);
+ if(*pcb_ms < cch_r) {
+ *pcb_ms = cch_r;
+ return KHM_ERROR_TOO_LONG;
+ }
+
+ *pcb_ms = cch_r;
+
+ StringCchCopy(s, cch_s, str);
+ s += cch_s;
+ *s = 0;
+
+ return KHM_ERROR_SUCCESS;
+}
+
+KHMEXP khm_int32 KHMAPI
+multi_string_prepend(
+ wchar_t * ms,
+ khm_size * pcb_ms,
+ const wchar_t * str)
+{
+ size_t cch_s;
+ size_t cch_t;
+ size_t cch_r;
+ khm_size cb_r;
+
+ if(!ms || !pcb_ms || !str)
+ return KHM_ERROR_INVALID_PARM;
+
+ if(FAILED(StringCchLength(str, KHM_MAXCCH_STRING, &cch_s)) || cch_s == 0)
+ return KHM_ERROR_INVALID_PARM;
+ cch_s++;
+
+ if(KHM_FAILED(multi_string_length_cch(ms,
+ KHM_MAXCCH_STRING,
+ &cch_r)))
+ return KHM_ERROR_INVALID_PARM;
+
+ cch_t = cch_s + cch_r;
+ cb_r = cch_t * sizeof(wchar_t);
+
+ if (*pcb_ms < cb_r) {
+ *pcb_ms = cb_r;
+ return KHM_ERROR_TOO_LONG;
+ }
+
+ memmove(ms + cch_s, ms, cch_r * sizeof(wchar_t));
+ memcpy(ms, str, cch_s * sizeof(wchar_t));
+
+ *pcb_ms = cb_r;
+
+ return KHM_ERROR_SUCCESS;
+}
+
+KHMEXP khm_int32 KHMAPI
+multi_string_delete(
+ wchar_t * ms,
+ const wchar_t * str,
+ const khm_int32 flags)
+{
+ wchar_t * s;
+ wchar_t * n;
+ wchar_t * e;
+ size_t cch;
+
+ if(!ms || !str)
+ return KHM_ERROR_INVALID_PARM;
+
+ s = multi_string_find(ms, str, flags);
+ if(!s)
+ return KHM_ERROR_NOT_FOUND;
+
+ e = s;
+ n = NULL;
+ while(*e && (e - s) < KHM_MAXCCH_STRING) {
+ if(FAILED(StringCchLength(e, KHM_MAXCCH_STRING, &cch)))
+ return KHM_ERROR_INVALID_PARM;
+ e += cch + 1;
+
+ if(!n)
+ n = e;
+ }
+
+ if(*e || (e - s) >= KHM_MAXCCH_STRING)
+ return KHM_ERROR_INVALID_PARM;
+
+ if(e == s)
+ return KHM_ERROR_SUCCESS;
+
+ memmove((void *) s, (void *) n, ((e - n) + 1) * sizeof(wchar_t));
+
+ return KHM_ERROR_SUCCESS;
+}
+
+KHMEXP wchar_t * KHMAPI
+multi_string_find(
+ const wchar_t * ms,
+ const wchar_t * str,
+ const khm_int32 flags)
+{
+ const wchar_t *s;
+ size_t cch;
+ size_t cch_s;
+
+ if(!ms || !str)
+ return NULL;
+
+ if(FAILED(StringCchLength(str, KHM_MAXCCH_STRING, &cch_s)))
+ return NULL;
+
+ s = ms;
+
+ while(*s && (s - ms) < KHM_MAXCCH_STRING) {
+ if(FAILED(StringCchLength(s, KHM_MAXCCH_STRING, &cch)))
+ return NULL;
+ /* cch++ at end */
+
+ if(flags & KHM_PREFIX) {
+ if(((flags & KHM_CASE_SENSITIVE) && !wcsncmp(s, str, cch_s)) ||
+ (!(flags & KHM_CASE_SENSITIVE) && !wcsnicmp(s, str, cch_s)))
+ return (wchar_t *) s;
+ } else {
+ if((cch == cch_s) &&
+ ((flags & KHM_CASE_SENSITIVE) && !wcsncmp(s, str, cch)) ||
+ (!(flags & KHM_CASE_SENSITIVE) && !wcsnicmp(s, str, cch)))
+ return (wchar_t *) s;
+ }
+
+ s += cch + 1;
+ }
+
+ return NULL;
+}
+
+KHMEXP khm_int32 KHMAPI
+multi_string_to_csv(
+ wchar_t * csvbuf,
+ khm_size * pcb_csvbuf,
+ const wchar_t * ms)
+{
+ size_t cb;
+ size_t cbt;
+ const wchar_t * t;
+ wchar_t * d;
+
+ if(!pcb_csvbuf || !ms)
+ return KHM_ERROR_INVALID_PARM;
+
+ /* dry run */
+ cbt = 0;
+ t = ms;
+ while(*t && cbt <= KHM_MAXCB_STRING) {
+ khm_boolean quotes = FALSE;
+
+ if(FAILED(StringCbLength(t, KHM_MAXCB_STRING, &cb)))
+ return KHM_ERROR_INVALID_PARM;
+ cb += sizeof(wchar_t);
+
+ cbt += cb;
+
+ if(wcschr(t, L','))
+ quotes = TRUE;
+
+ d = (wchar_t *) t;
+ while(d = wcschr(d, L'"')) {
+ cbt += sizeof(wchar_t); /* '"'-> '""' */
+ d++;
+ quotes = TRUE;
+ }
+
+ if(quotes)
+ cbt += 2*sizeof(wchar_t); /* make room for quotes */
+
+ t += cb / sizeof(wchar_t);
+ }
+
+ if(cbt > KHM_MAXCB_STRING)
+ return KHM_ERROR_INVALID_PARM;
+
+ /* happens if the multi string contained no strings */
+ if(cbt == 0)
+ cbt = sizeof(wchar_t);
+
+ if(!csvbuf || *pcb_csvbuf < cbt)
+ {
+ *pcb_csvbuf = cbt;
+ return KHM_ERROR_TOO_LONG;
+ }
+
+ *pcb_csvbuf = cbt;
+
+ /* wet run */
+ t = ms;
+ d = csvbuf;
+ *csvbuf = 0;
+ while(*t) {
+ const wchar_t * s;
+
+ StringCbLength(t, KHM_MAXCB_STRING, &cb);
+ cb += sizeof(wchar_t);
+
+ if(d != csvbuf)
+ *d++ = L',';
+ if(wcschr(t, L',') || wcschr(t, L'"')) {
+ *d++ = L'"';
+ s = t;
+ while(*s) {
+ if(*s == L'"') {
+ *d++ = L'"';
+ *d++ = L'"';
+ } else
+ *d++ = *s;
+ s++;
+ }
+ *d++ = L'"';
+ *d = 0;
+ } else {
+ StringCbCopy(d, cbt - ((d - csvbuf) * sizeof(wchar_t)), t);
+ d += cb / sizeof(wchar_t) - 1;
+ }
+ t += cb / sizeof(wchar_t);
+ }
+
+ return KHM_ERROR_SUCCESS;
+}
+
+KHMEXP khm_int32 KHMAPI
+csv_to_multi_string(
+ wchar_t * ms,
+ khm_size * pcb_ms,
+ const wchar_t * csv)
+{
+ const wchar_t * t;
+ wchar_t * p;
+ size_t cchr;
+ int field = 1;
+
+
+ if(!pcb_ms || !csv)
+ return KHM_ERROR_INVALID_PARM;
+
+ cchr = 0;
+
+ /* dry run */
+ t = csv;
+ while(*t && (t - csv) < KHM_MAXCCH_STRING) {
+ if(field && *t == L'"') {
+ t++;
+ while(*t && (t - csv) < KHM_MAXCCH_STRING) {
+ if(*t == L'"') {
+ t++;
+ if(*t != L'"')
+ break;
+ }
+ cchr++;
+ t++;
+ }
+ }
+
+ if(*t) {
+ cchr++;
+ if(*t == L',')
+ field = 1;
+ else
+ field = 0;
+
+ t++;
+ }
+ }
+
+ if((t - csv) >= KHM_MAXCCH_STRING)
+ return KHM_ERROR_INVALID_PARM;
+
+ cchr++; /* last string ends */
+ cchr++; /* double NULL */
+
+ if(!ms || *pcb_ms < (cchr * sizeof(wchar_t))) {
+ *pcb_ms = cchr * sizeof(wchar_t);
+ return KHM_ERROR_TOO_LONG;
+ }
+
+ /* wet run */
+ t = csv;
+ p = ms;
+ field = 1;
+ while(*t) {
+ if(field && *t == L'"') {
+ t++;
+ while(*t) {
+ if(*t == L'"') {
+ t++;
+ if(*t != L'"')
+ break;
+ }
+ *p++ = *t;
+ t++;
+ }
+ }
+
+ if(*t == L',') {
+ *p++ = 0;
+ field = 1;
+ t++;
+ } else if(*t) {
+ *p++ = *t;
+ field = 0;
+ t++;
+ }
+ }
+
+ *p++ = 0; /* last string ends */
+ *p++ = 0; /* double NULL */
+
+ *pcb_ms = (p - ms) * sizeof(wchar_t);
+
+ return KHM_ERROR_SUCCESS;
+}
+
+KHMEXP wchar_t * KHMAPI
+multi_string_next(const wchar_t * str)
+{
+ size_t cch;
+
+ if(*str) {
+ if(FAILED(StringCchLength(str, KHM_MAXCCH_STRING, &cch)))
+ return NULL;
+ str += cch + 1;
+ if(*str)
+ return (wchar_t *) str;
+ else
+ return NULL;
+ } else {
+ return NULL;
+ }
+}
+
+KHMEXP khm_size KHMAPI
+multi_string_length_n(const wchar_t * str)
+{
+ size_t n = 0;
+ const wchar_t * c = str;
+
+ while(c) {
+ n++;
+ c = multi_string_next(c);
+ }
+
+ return n;
+}
+
+KHMEXP khm_int32 KHMAPI
+multi_string_length_cb(const wchar_t * str,
+ khm_size max_cb,
+ khm_size * len_cb)
+{
+ khm_size cch;
+ khm_int32 rv;
+
+ rv = multi_string_length_cch(str, max_cb / sizeof(wchar_t), &cch);
+
+ if(KHM_FAILED(rv))
+ return rv;
+
+ if(len_cb)
+ *len_cb = cch * sizeof(wchar_t);
+
+ return rv;
+}
+
+KHMEXP khm_int32 KHMAPI
+multi_string_length_cch(const wchar_t * str,
+ khm_size max_cch,
+ khm_size * len_cch)
+{
+ const wchar_t * s;
+ khm_size cch;
+ size_t tcch;
+
+ if(!str)
+ return KHM_ERROR_INVALID_PARM;
+
+ s = str;
+ cch = 0;
+ while(*s && (cch < max_cch)) {
+ if(FAILED(StringCchLength(s, max_cch, &tcch)))
+ return KHM_ERROR_TOO_LONG;
+ cch += ++tcch;
+ s += tcch;
+ }
+
+ if(cch >= max_cch)
+ return KHM_ERROR_TOO_LONG;
+
+ if(len_cch) {
+ *len_cch = ++cch;
+ }
+
+ return KHM_ERROR_SUCCESS;
+}
+
+KHMEXP khm_int32 KHMAPI
+multi_string_copy_cb(wchar_t * s_dest,
+ khm_size max_cb_dest,
+ const wchar_t * src)
+{
+ khm_size cb_dest;
+ khm_int32 rv = KHM_ERROR_SUCCESS;
+
+ if(!s_dest)
+ return KHM_ERROR_INVALID_PARM;
+
+ rv = multi_string_length_cb(src, max_cb_dest, &cb_dest);
+ if(KHM_FAILED(rv))
+ return rv;
+
+ memmove(s_dest, src, cb_dest);
+
+ return rv;
+}
+
+KHMEXP khm_int32 KHMAPI
+multi_string_copy_cch(wchar_t * s_dest,
+ khm_size max_cch_dest,
+ const wchar_t * src)
+{
+ khm_size cch_dest;
+ khm_int32 rv = KHM_ERROR_SUCCESS;
+
+ if(!s_dest)
+ return KHM_ERROR_INVALID_PARM;
+
+ rv = multi_string_length_cch(src, max_cch_dest, &cch_dest);
+ if(KHM_FAILED(rv))
+ return rv;
+
+ memmove(s_dest, src, cch_dest * sizeof(wchar_t));
+
+ return rv;
+}
diff --git a/src/windows/identity/util/mstring.h b/src/windows/identity/util/mstring.h
new file mode 100644
index 0000000..9b4e380
--- /dev/null
+++ b/src/windows/identity/util/mstring.h
@@ -0,0 +1,361 @@
+/*
+ * Copyright (c) 2004 Massachusetts Institute of Technology
+ *
+ * Permission is hereby granted, free of charge, to any person
+ * obtaining a copy of this software and associated documentation
+ * files (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use, copy,
+ * modify, merge, publish, distribute, sublicense, and/or sell copies
+ * of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+/* $Id$ */
+
+#ifndef __KHIMAIRA_MSTRING_H
+#define __KHIMAIRA_MSTRING_H
+
+#include<khdefs.h>
+
+/*! \addtogroup util
+ @{ */
+
+/*! \defgroup util_mstring Multi String and CSV functions
+ @{*/
+
+#define KHM_PREFIX 8
+
+#define KHM_CASE_SENSITIVE 16
+
+#define KHM_MAXCCH_STRING 16384
+
+#define KHM_MAXCB_STRING (KHM_MAXCCH_STRING * sizeof(wchar_t))
+
+/*! \brief Initialize a multi-string
+ */
+KHMEXP khm_int32 KHMAPI
+multi_string_init(wchar_t * ms,
+ khm_size cb_ms);
+
+/*! \brief Prepend a string to a multi string
+
+ Adds the string \a str to the beginning of multi-string \a ms.
+
+ \param[in,out] ms The multi-string to be modified.
+
+ \param[in,out] pcb_ms A pointer to the size of the multistring.
+ On entry this specifies the size of the buffer pointed to by
+ \a ms. If the call is successful, on exit this will receive
+ the new size of the multi string in bytes. If the buffer is
+ insufficient, the function will return KHM_ERROR_TOO_LONG and
+ set this to the required size of the buffer in bytes.
+
+ \param[in] str The string to prepend to \a ms. This cannot be
+ longer than KHM_MAXCCH_STRING in characters including the
+ terminating NULL.
+ */
+KHMEXP khm_int32 KHMAPI
+multi_string_prepend(wchar_t * ms,
+ khm_size * pcb_ms,
+ const wchar_t * str);
+
+/*! \brief Append a string to a multi-string
+
+ Appends the string specified by \a str to the multi string
+ specified by \a ms. The size of the multi string in characters
+ including terminating NULLs after appending \a str can not exceed
+ KHM_MAXCCH_STRING.
+
+ \param[in] ms The buffer containing the multi string
+
+ \param[in,out] pcb_ms Points to a khm_int32 indicating the size of
+ the buffer pointed to by \a ms. On entry this contains the
+ size (in bytes) of the buffer pointed to by \a ms. On exit,
+ contains the new size of the multi string in bytes.
+
+ \param[in] str The string to append to the multi string. This
+ string cannot be NULL or an empty (zero length) string. The
+ length of \a str cannot exceed KHM_MAXCCH_STRING in
+ characters including terminating NULL.
+
+ \retval KHM_ERROR_SUCCESS The string was appended to the multi string
+
+ \retval KHM_ERROR_TOO_LONG The buffer pointed to by \a ms was
+ insufficient. The required size of the buffer is in \a pcb_ms
+
+ \retval KHM_ERROR_INVALID_PARM One of more of the parameters were invalid.
+ */
+KHMEXP khm_int32 KHMAPI
+multi_string_append(wchar_t * ms,
+ khm_size * pcb_ms,
+ const wchar_t * str);
+
+/*! \brief Deletes a string from a multi string
+
+ Deletes the string specified by \a str from the multi string
+ specified by \a ms. How the string is matched to the strings in
+ \a ms is determined by \a flags. If more than one match is found,
+ then only the first match is deleted.
+
+ \param[in] ms The multi string to modify. The length of the multi
+ string in characters cannot exceed KHM_MAXCCH_STRING.
+
+ \param[in] str The string to search for
+
+ \param[in] flags How \a str is to be matched to existing strings
+ in \a ms. This could be a combination of KHM_PREFIX and
+ KHM_CASE_SENSITIVE. If KHM_PREFIX is used, then \a ms is
+ searched for a string that begins with \a str. Otherwise, \a
+ str must match the an entire string in the multi string. If
+ KHM_CASE_SENSITIVE is specified, then a case sensitive match
+ is performed. The defualt is to use a case insensitive
+ search.
+
+ \retval KHM_ERROR_SUCCESS A string was matched and deleted from \a ms
+
+ \retval KHM_ERROR_NOT_FOUND No matches were found
+
+ \retval KHM_ERROR_INVALID_PARM One or more parameters were incorrect.
+
+ \note The search for the existing string is done with
+ multi_string_find()
+ */
+KHMEXP khm_int32 KHMAPI
+multi_string_delete(wchar_t * ms,
+ const wchar_t * str,
+ const khm_int32 flags);
+
+/*! \brief Search a multi string for a string
+
+ Searches the string specified by \a ms for a string that matches
+ \a str. How the match is performed is determined by \a flags.
+ Returns a poitner to the start of the matched string in \a ms. If
+ more than one string in \a ms matches \a str, then only the first
+ match is returned.
+
+ \param[in] ms The multi string to search in. The length of the
+ multi string cannot exceed KHM_MAXCCH_STRING in characters.
+
+ \param[in] str The string to search for
+
+ \param[in] flags How \a str is to be matched to existing strings
+ in \a ms. This could be a combination of KHM_PREFIX and
+ KHM_CASE_SENSITIVE. If KHM_PREFIX is used, then \a ms is
+ searched for a string that begins with \a str. Otherwise, \a
+ str must match the an entire string in the multi string. If
+ KHM_CASE_SENSITIVE is specified, then a case sensitive match
+ is performed. The defualt is to use a case insensitive
+ search.
+
+ \return A pointer to the start of the first matched string or
+ NULL if no matches were found.
+
+ */
+KHMEXP wchar_t * KHMAPI
+multi_string_find(const wchar_t * ms,
+ const wchar_t * str,
+ const khm_int32 flags);
+
+/*! \brief Convert a multi string to CSV
+
+ Converts a multi string to a comma separated value string based on
+ the following rules.
+
+ - Each string in the multi string is treated an individual field
+
+ - A field is quoted if it has double quotes or commas
+
+ - Double quotes within quoted fields are escaped by two
+ consecutive double quotes.
+
+ For example:
+
+ \code
+ multi_string = L"foo\0bar\0baz,quux\0ab\"cd\0";
+ csv_string = L"foo,bar,\"baz,quux\",\"ab\"\"cd\"";
+ \endcode
+
+ If multi_string_to_csv() is called on \a multi_string above,
+ you would obtain \a csv_string.
+
+ \param[out] csvbuf The buffer to place the CSV string in. Can be
+ NULL if only teh size of the needed buffer is required.
+
+ \param[in,out] pcb_csvbuf On entry, points to a khm_int32 that
+ holds the size of the buffer pointed to by \a csvbuf. On
+ exit, gets the number of bytes writted to \a csvbuf or the
+ required size of \a csvbuf if the buffer is too small or \a
+ csvbuf is NULL.
+
+ \param[in] ms The mutli string to convert to a CSV.
+
+ \retval KHM_ERROR_SUCCESS The multi string was successfully
+ converted to a CSV string. The number of bytes written is in
+ \a pcb_csvbuf. The count includes the terminating NULL.
+
+ \retval KHM_ERROR_TOO_LONG The buffer was too small or \a csvbuf
+ was NULL. The required number of bytes in the buffer is in \a
+ pcb_csvbuf.
+
+ \retval KHM_ERROR_INVALID_PARM One or more parameters were ivnalid.
+
+ \see csv_to_multi_string()
+*/
+KHMEXP khm_int32 KHMAPI
+multi_string_to_csv(wchar_t * csvbuf,
+ khm_size * pcb_csvbuf,
+ const wchar_t * ms);
+
+/*! \brief Converts a CSV to a multi string
+
+ Undoes what multi_string_to_csv() does.
+
+ \param[out] ms The buffer that recieves the multi string. This
+ can be NULL if only the size of the buffer is requried.
+
+ \param[in,out] pcb_ms On entry contains the number of bytes ni the
+ buffer poitned to by \a ms. On exit contains the number of
+ bytes that were copied to \a ms including terminating NULLs,
+ or if the buffer was too small or \a ms was NULL, holds the
+ size in bytes of the requied buffer.
+
+ \param[in] csv The CSV string.
+
+ \retval KHM_ERROR_SUCCESS The CSV string was successfully
+ converted. The number of bytes written is in \a pcb_ms.
+
+ \retval KHM_ERROR_TOO_LONG The provided buffer was too small or \a
+ ms was NULL. The required size of the buffer in bytes is in \a
+ pcb_ms.
+
+ \retval KHM_ERROR_INVALID_PARM One or more parameters were invalid.
+
+ */
+KHMEXP khm_int32 KHMAPI
+csv_to_multi_string(wchar_t * ms,
+ khm_size * pcb_ms,
+ const wchar_t * csv);
+
+/*! \brief Get the next string in a multi string
+
+ When \a str is pointing to a string that is in a multi string,
+ this function returns a pointer to the next string in the multi
+ string.
+
+ Typically, one would start by having \a str point to the start of
+ the multi string (which is the first string in the multi string),
+ and then call this function repeatedly, until it returns NULL, at
+ which point the end of the multi string has been reached.
+
+ \param[in] str Pointer to a string in a multi string. Each string
+ in a multi string cannot exceed KHM_MAXCCH_STRING in charaters
+ including the terminating NULL.
+
+ \return A pointer to the start of the next string in the multi
+ string or NULL if there is no more strings.
+ */
+KHMEXP wchar_t * KHMAPI
+multi_string_next(const wchar_t * str);
+
+/*! \brief Get the length of a multi string in bytes
+
+ The returned length includes the trailing double \a NULL and any
+ other \a NULL inbetween.
+
+ \param[in] str Pointer to a multi string.
+ \param[in] max_cb Maximum size that the str can be. This can not
+ be larger than KHM_MAXCB_STRING.
+ \param[out] len_cb The length of the string in bytes if the call
+ is successful.
+
+ \retval KHM_ERROR_SUCCESS The length of the string is in \a len_cb
+ \retval KHM_ERROR_INVALID_PARM One or more parameters were invalid
+ \retval KHM_ERROR_TOO_LONG The multi string is longer than \a
+ max_cb bytes.
+ */
+KHMEXP khm_int32 KHMAPI
+multi_string_length_cb(const wchar_t * str,
+ khm_size max_cb,
+ khm_size * len_cb);
+
+/*! \brief Get the length of a multi string in characters
+
+ The returned length includes the trailing double \a NULL and any
+ other \a NULL inbetween.
+
+ \param[in] str Pointer to a multi string.
+ \param[in] max_cch Maximum size that the str can be. This can not
+ be larger than KHM_MAXCCH_STRING.
+ \param[out] len_cch The length of the string in characters if the call
+ is successful.
+
+ \retval KHM_ERROR_SUCCESS The length of the string is in \a len_cch
+ \retval KHM_ERROR_INVALID_PARM One or more parameters were invalid
+ \retval KHM_ERROR_TOO_LONG The multi string is longer than \a
+ max_cch characters.
+ */
+KHMEXP khm_int32 KHMAPI
+multi_string_length_cch(const wchar_t * str,
+ khm_size max_cch,
+ khm_size * len_cch);
+
+/*! \brief Get the number of strings in a multi string
+ */
+KHMEXP khm_size KHMAPI
+multi_string_length_n(const wchar_t * str);
+
+/*! \brief Copy a multi string with byte counts
+
+ Copy a multi string from one location to another.
+
+ \param[out] s_dest Receives a copy of the multi string
+ \param[in] max_cb_dest Number of bytes in the buffer pointed to by
+ \a s_dest.
+ \param[in] src The source multi string
+
+ \retval KHM_ERROR_SUCCESS The multi string was copied successfully
+ \retval KHM_ERROR_INVALID_PARM One or more parameters were
+ invalid.
+ \retval KHM_ERROR_TOO_LONG The size of the destination buffer was
+ insufficient.
+ */
+KHMEXP khm_int32 KHMAPI
+multi_string_copy_cb(wchar_t * s_dest,
+ khm_size max_cb_dest,
+ const wchar_t * src);
+
+/*! \brief Copy a multi string with character count
+
+ Copy a multi string from one location to another.
+
+ \param[out] s_dest Receives a copy of the multi string
+ \param[in] max_cb_dest Number of characters in the buffer pointed
+ to by \a s_dest.
+ \param[in] src The source multi string
+
+ \retval KHM_ERROR_SUCCESS The multi string was copied successfully
+ \retval KHM_ERROR_INVALID_PARM One or more parameters were
+ invalid.
+ \retval KHM_ERROR_TOO_LONG The size of the destination buffer was
+ insufficient.
+ */
+KHMEXP khm_int32 KHMAPI
+multi_string_copy_cch(wchar_t * s_dest,
+ khm_size max_cch_dest,
+ const wchar_t * src);
+
+/*@}*/
+
+#endif
diff --git a/src/windows/identity/util/sync.c b/src/windows/identity/util/sync.c
new file mode 100644
index 0000000..b50d484
--- /dev/null
+++ b/src/windows/identity/util/sync.c
@@ -0,0 +1,121 @@
+/*
+ * Copyright (c) 2004 Massachusetts Institute of Technology
+ *
+ * Permission is hereby granted, free of charge, to any person
+ * obtaining a copy of this software and associated documentation
+ * files (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use, copy,
+ * modify, merge, publish, distribute, sublicense, and/or sell copies
+ * of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+/* $Id$ */
+
+#include<windows.h>
+#include<sync.h>
+#include<assert.h>
+
+#define LOCK_OPEN 0
+#define LOCK_READING 1
+#define LOCK_WRITING 2
+
+KHMEXP void KHMAPI InitializeRwLock(PRWLOCK pLock)
+{
+ pLock->locks = 0;
+ pLock->status = LOCK_OPEN;
+ InitializeCriticalSection(&(pLock->cs));
+ pLock->writewx = CreateEvent(NULL,
+ FALSE, /* Manual reset */
+ TRUE, /* Initial state */
+ NULL);
+ pLock->readwx = CreateEvent(NULL,
+ TRUE, /* Manual reset */
+ TRUE, /* Initial state */
+ NULL);
+}
+
+KHMEXP void KHMAPI DeleteRwLock(PRWLOCK pLock)
+{
+ DeleteCriticalSection(&(pLock->cs));
+ CloseHandle(pLock->readwx);
+ CloseHandle(pLock->writewx);
+}
+
+KHMEXP void KHMAPI LockObtainRead(PRWLOCK pLock)
+{
+ while(1) {
+ WaitForSingleObject(pLock->readwx, INFINITE);
+ EnterCriticalSection(&pLock->cs);
+ if(pLock->status == LOCK_WRITING) {
+ LeaveCriticalSection(&(pLock->cs));
+ continue;
+ } else
+ break;
+ }
+ pLock->locks ++;
+ pLock->status = LOCK_READING;
+ ResetEvent(pLock->writewx);
+ LeaveCriticalSection(&(pLock->cs));
+}
+
+KHMEXP void KHMAPI LockReleaseRead(PRWLOCK pLock)
+{
+ EnterCriticalSection(&(pLock->cs));
+ assert(pLock->status == LOCK_READING);
+ pLock->locks--;
+ if(!pLock->locks) {
+ pLock->status = LOCK_OPEN;
+ SetEvent(pLock->readwx);
+ SetEvent(pLock->writewx);
+ }
+ LeaveCriticalSection(&(pLock->cs));
+}
+
+KHMEXP void KHMAPI LockObtainWrite(PRWLOCK pLock)
+{
+ EnterCriticalSection(&(pLock->cs));
+ if(pLock->status == LOCK_WRITING &&
+ pLock->writer == GetCurrentThreadId()) {
+ pLock->locks++;
+ LeaveCriticalSection(&(pLock->cs));
+ return;
+ }
+ LeaveCriticalSection(&(pLock->cs));
+ while(1) {
+ WaitForSingleObject(pLock->writewx, INFINITE);
+ EnterCriticalSection(&(pLock->cs));
+ if(pLock->status == LOCK_OPEN)
+ break;
+ LeaveCriticalSection(&(pLock->cs));
+ }
+ pLock->status = LOCK_WRITING;
+ pLock->locks++;
+ ResetEvent(pLock->readwx);
+ LeaveCriticalSection(&(pLock->cs));
+}
+
+KHMEXP void KHMAPI LockReleaseWrite(PRWLOCK pLock)
+{
+ EnterCriticalSection(&(pLock->cs));
+ assert(pLock->status == LOCK_WRITING);
+ pLock->locks--;
+ if(!pLock->locks) {
+ pLock->status = LOCK_OPEN;
+ SetEvent(pLock->readwx);
+ SetEvent(pLock->writewx);
+ }
+ LeaveCriticalSection(&(pLock->cs));
+}
diff --git a/src/windows/identity/util/sync.h b/src/windows/identity/util/sync.h
new file mode 100644
index 0000000..5410d0e
--- /dev/null
+++ b/src/windows/identity/util/sync.h
@@ -0,0 +1,128 @@
+/*
+ * Copyright (c) 2004 Massachusetts Institute of Technology
+ *
+ * Permission is hereby granted, free of charge, to any person
+ * obtaining a copy of this software and associated documentation
+ * files (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use, copy,
+ * modify, merge, publish, distribute, sublicense, and/or sell copies
+ * of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+/* $Id$ */
+
+#ifndef __KHIMAIRA_SYNC_H
+#define __KHIMAIRA_SYNC_H
+
+#include<khdefs.h>
+
+/*! \addtogroup util
+ @{ */
+
+/*! \defgroup util_sync Synchronization
+ @{*/
+
+/*! \brief A read/write lock
+
+ A classic read/write lock. Allows multiple readers or a single
+ writer to access a protected object. Readers will wait for any
+ pending writer to release the lock, while a writer will wait for
+ any pending readers to release the lock.
+*/
+typedef struct tag_rwlock {
+ int locks;
+ int status;
+ CRITICAL_SECTION cs;
+ HANDLE readwx;
+ HANDLE writewx;
+
+ DWORD writer; /* TID of writer thread */
+} rw_lock_t;
+
+typedef rw_lock_t RWLOCK, *PRWLOCK;
+
+/*! \brief Initialize a read/write lock.
+
+ A lock <b>must</b> be initialized before it can be used.
+ Initializing the lock does not grant the caller any locks on the
+ object.
+*/
+KHMEXP void KHMAPI InitializeRwLock(PRWLOCK pLock);
+
+/*! \brief Delete a read/write lock
+
+ Once the application is done using the read/write lock, it must be
+ deleted with a call to DeleteRwLock()
+*/
+KHMEXP void KHMAPI DeleteRwLock(PRWLOCK pLock);
+
+/*! \brief Obtains a read lock on the read/write lock
+
+ Multiple readers can obtain read locks on the same r/w lock.
+ However, if any thread attempts to obtain a write lock on the
+ object, it will wait until all readers have released the read
+ locks.
+
+ Call LockReleaseRead() to release the read lock. While the same
+ thread may obtain multiple read locks on the same object, each
+ call to LockObtainRead() must have a corresponding call to
+ LockReleaseRead() to properly relinquish the lock.
+
+ \see LockReleaseRead()
+*/
+KHMEXP void KHMAPI LockObtainRead(PRWLOCK pLock);
+
+/*! \brief Relase a read lock obtained on a read/write lock
+
+ Each call to LockObtainRead() must have a corresponding call to
+ LockReleaseRead(). Once all read locks are released, any threads
+ waiting on write locks on the object will be woken and assigned a
+ write lock.
+
+ \see LockObtainRead()
+*/
+KHMEXP void KHMAPI LockReleaseRead(PRWLOCK pLock);
+
+/*! \brief Obtains a write lock on the read/write lock
+
+ Only a single writer is allowed to lock a single r/w lock.
+ However, if any thread attempts to obtain a read lock on the
+ object, it will wait until the writer has released the lock.
+
+ Call LockReleaseWrite() to release the write lock. While the same
+ thread may obtain multiple write locks on the same object, each
+ call to LockObtainWrite() must have a corresponding call to
+ LockReleaseWrite() to properly relinquish the lock.
+
+ \see LockReleaseWrite()
+*/
+KHMEXP void KHMAPI LockObtainWrite(PRWLOCK pLock);
+
+/*! \brief Relase a write lock obtained on a read/write lock
+
+ Each call to LockObtainWrite() must have a corresponding call to
+ LockReleaseWrite(). Once the write lock is released, any threads
+ waiting for read or write locks on the object will be woken and
+ assigned the proper lock.
+
+ \see LockObtainWrite()
+*/
+KHMEXP void KHMAPI LockReleaseWrite(PRWLOCK pLock);
+
+/*@}*/
+/*@}*/
+
+#endif
diff --git a/src/windows/identity/util/utils.h b/src/windows/identity/util/utils.h
new file mode 100644
index 0000000..2e3b6b7
--- /dev/null
+++ b/src/windows/identity/util/utils.h
@@ -0,0 +1,36 @@
+/*
+ * Copyright (c) 2004 Massachusetts Institute of Technology
+ *
+ * Permission is hereby granted, free of charge, to any person
+ * obtaining a copy of this software and associated documentation
+ * files (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use, copy,
+ * modify, merge, publish, distribute, sublicense, and/or sell copies
+ * of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+/* $Id$ */
+
+#ifndef __KHIMAIRA_UTIL_H
+#define __KHIMAIRA_UTIL_H
+
+/*! \defgroup util Utilities
+ */
+#include<hashtable.h>
+#include<sync.h>
+#include<mstring.h>
+
+#endif