diff options
Diffstat (limited to 'ldap/servers/slapd/attrsyntax.c')
-rw-r--r-- | ldap/servers/slapd/attrsyntax.c | 906 |
1 files changed, 906 insertions, 0 deletions
diff --git a/ldap/servers/slapd/attrsyntax.c b/ldap/servers/slapd/attrsyntax.c new file mode 100644 index 00000000..845e9666 --- /dev/null +++ b/ldap/servers/slapd/attrsyntax.c @@ -0,0 +1,906 @@ +/** BEGIN COPYRIGHT BLOCK + * Copyright 2001 Sun Microsystems, Inc. + * Portions copyright 1999, 2001-2003 Netscape Communications Corporation. + * All rights reserved. + * END COPYRIGHT BLOCK **/ +/* attrsyntax.c */ + +#include "slap.h" +#include <plhash.h> + +/* + * Note: if both the oid2asi and name2asi locks are acquired at the + * same time, the old2asi one should be acquired first, + */ + +/* + * This hashtable maps the oid to the struct asyntaxinfo for that oid. + */ +static PLHashTable *oid2asi = NULL; +/* read/write lock to protect table */ +static PRRWLock *oid2asi_lock = NULL; + +/* + * This hashtable maps the name or alias of the attribute to the + * syntax info structure for that attribute. An attribute type has as + * many entries in the name2asi table as it has names and aliases, but + * all entries point to the same struct asyntaxinfo. + */ +static PLHashTable *name2asi = NULL; +/* read/write lock to protect table */ +static PRRWLock *name2asi_lock = NULL; + +#define AS_LOCK_READ(l) PR_RWLock_Rlock(l) +#define AS_LOCK_WRITE(l) PR_RWLock_Wlock(l) +#define AS_UNLOCK_READ(l) PR_RWLock_Unlock(l) +#define AS_UNLOCK_WRITE(l) PR_RWLock_Unlock(l) + + + +static void *attr_syntax_get_plugin_by_name_with_default( const char *type ); +static void attr_syntax_delete_no_lock( struct asyntaxinfo *asip, + PRBool remove_from_oid_table ); +static struct asyntaxinfo *attr_syntax_get_by_oid_locking_optional( const + char *oid, PRBool use_lock, PRBool ref_count); + +#ifdef ATTR_LDAP_DEBUG +static void attr_syntax_print(); +#endif +static int attr_syntax_init(void); + +void +attr_syntax_read_lock(void) +{ + if (0 != attr_syntax_init()) return; + + AS_LOCK_READ(oid2asi_lock); + AS_LOCK_READ(name2asi_lock); +} + +void +attr_syntax_unlock_read(void) +{ + if(name2asi_lock) AS_UNLOCK_READ(name2asi_lock); + if(oid2asi_lock) AS_UNLOCK_READ(oid2asi_lock); +} + + + +#if 0 +static int +check_oid( const char *oid ) { + + int i = 0, length_oid = 0, rc = 0; + + if ( oid == NULL) { + /* this is bad */ + LDAPDebug (LDAP_DEBUG_ANY, "NULL passed to check_oid\n",0,0,0); + return 0; + } + + length_oid = strlen(oid); + if (length_oid < 4) { + /* this is probably bad */ + LDAPDebug (LDAP_DEBUG_ANY, "Bad oid %s passed to check_oid\n",oid,0,0); + return 0; + } + + rc = strcasecmp(oid+(length_oid-4), "-oid"); + + if ( 0 == rc ) { + return 1; + } + + /* If not, the OID must begin and end with a digit, and contain only + digits and dots */ + + if ( !isdigit(oid[0]) || + !isdigit(oid[length_oid-1]) ) { + LDAPDebug (LDAP_DEBUG_ANY, "Non numeric oid %s passed to check_oid\n",oid,0,0); + return 0; + } + + /* check to see that it contains only digits and dots */ + for ( i = 0; i < length_oid; i++ ) { + if ( !isdigit(oid[i]) && oid[i] != '.' ){ + LDAPDebug (LDAP_DEBUG_ANY, "Non numeric oid %s passed to check_oid\n",oid,0,0); + return 0; + } + } + + /* The oid is OK if we're here */ + return 1; + + +} +#endif + +#define NBUCKETS(ht) (1 << (PL_HASH_BITS - (ht)->shift)) + +#if 0 +static int +attr_syntax_check_oids() +{ + int ii = 0; + int nbad = 0; + AS_LOCK_READ(oid2asi_lock); + ii = NBUCKETS(oid2asi); + for (;ii;--ii) { + PLHashEntry *he = oid2asi->buckets[ii-1]; + for (; he; he = he->next) { + if (!check_oid(he->key)) { + LDAPDebug(LDAP_DEBUG_ANY, "Error: bad oid %s in bucket %d\n", + he->key, ii-1, 0); + nbad++; + } + } + } + + AS_UNLOCK_READ(oid2asi_lock); + return nbad; +} +#endif + +void +attr_syntax_free( struct asyntaxinfo *a ) +{ + PR_ASSERT( a->asi_refcnt == 0 ); + + cool_charray_free( a->asi_aliases ); + slapi_ch_free( (void**)&a->asi_name ); + slapi_ch_free( (void **)&a->asi_desc ); + slapi_ch_free( (void **)&a->asi_oid ); + slapi_ch_free( (void **)&a->asi_superior ); + slapi_ch_free( (void **)&a->asi_mr_equality ); + slapi_ch_free( (void **)&a->asi_mr_ordering ); + slapi_ch_free( (void **)&a->asi_mr_substring ); + cool_charray_free( a->asi_origin ); + slapi_ch_free( (void **) &a ); +} + +static struct asyntaxinfo * +attr_syntax_new() +{ + return (struct asyntaxinfo *)slapi_ch_calloc(1, sizeof(struct asyntaxinfo)); +} + +/* + * hashNocaseString - used for case insensitive hash lookups + */ +static PLHashNumber +hashNocaseString(const void *key) +{ + PLHashNumber h = 0; + const unsigned char *s; + + for (s = key; *s; s++) + h = (h >> 28) ^ (h << 4) ^ (tolower(*s)); + return h; +} + +/* + * hashNocaseCompare - used for case insensitive hash key comparisons + */ +static PRIntn +hashNocaseCompare(const void *v1, const void *v2) +{ + return (strcasecmp((char *)v1, (char *)v2) == 0); +} + +/* + * Given an OID, return the syntax info. If there is more than one + * attribute syntax with the same OID (i.e. aliases), the first one + * will be returned. This is usually the "canonical" one, but it may + * not be. + * + * Note: once the caller is finished using it, the structure returned must + * be returned by calling to attr_syntax_return(). + */ +struct asyntaxinfo * +attr_syntax_get_by_oid(const char *oid) +{ + return attr_syntax_get_by_oid_locking_optional( oid, PR_TRUE, PR_TRUE); +} + + +static struct asyntaxinfo * +attr_syntax_get_by_oid_locking_optional( const char *oid, PRBool use_lock, PRBool ref_count ) +{ + struct asyntaxinfo *asi = 0; + if (oid2asi) + { + if ( use_lock ) AS_LOCK_READ(oid2asi_lock); + asi = (struct asyntaxinfo *)PL_HashTableLookup_const(oid2asi, oid); + if (asi) + { + if(ref_count) PR_AtomicIncrement( &asi->asi_refcnt ); + } + if ( use_lock ) AS_UNLOCK_READ(oid2asi_lock); + } + + return asi; +} + +/* + * Add the syntax info pointer to the look-up-by-oid table. + * The lock parameter is used by the initialization code. Normally, we want + * to acquire a write lock before we modify the table, but during + * initialization, we are running in single threaded mode, so we don't have + * to worry about resource contention. + */ +static void +attr_syntax_add_by_oid(const char *oid, struct asyntaxinfo *a, int lock) +{ + if (0 != attr_syntax_init()) return; + + if (lock) + AS_LOCK_WRITE(oid2asi_lock); + + PL_HashTableAdd(oid2asi, oid, a); + + if (lock) + AS_UNLOCK_WRITE(oid2asi_lock); +} + +/* + * Return the syntax info given an attribute name. The name may be the + * "canonical" name, an alias, or an OID. The given name need not be + * normalized since the look up is done case insensitively. + * + * Note: once the caller is finished using it, the structure returned must + * be returned by calling to attr_syntax_return(). + */ +struct asyntaxinfo * +attr_syntax_get_by_name(const char *name) +{ + return attr_syntax_get_by_name_locking_optional(name, PR_TRUE, PR_TRUE); +} + + +struct asyntaxinfo * +attr_syntax_get_by_name_locking_optional(const char *name, PRBool use_lock, PRBool ref_count) +{ + struct asyntaxinfo *asi = 0; + if (name2asi) + { + if ( use_lock ) AS_LOCK_READ(name2asi_lock); + asi = (struct asyntaxinfo *)PL_HashTableLookup_const(name2asi, name); + if ( NULL != asi ) { + if(ref_count) PR_AtomicIncrement( &asi->asi_refcnt ); + } + if ( use_lock ) AS_UNLOCK_READ(name2asi_lock); + } + if (!asi) /* given name may be an OID */ + asi = attr_syntax_get_by_oid_locking_optional(name, use_lock, ref_count); + + return asi; +} + + +/* + * Give up a reference to an asi. + * If the asi has been marked for delete, free it. This would be a bit + * easier if we could upgrade a read lock to a write one... but NSPR does + * not support that paradigm. + */ +void +attr_syntax_return( struct asyntaxinfo *asi ) +{ + attr_syntax_return_locking_optional( asi, PR_TRUE ); +} + +void +attr_syntax_return_locking_optional( struct asyntaxinfo *asi, PRBool use_lock ) +{ + if ( NULL != asi ) { + if ( 0 == PR_AtomicDecrement( &asi->asi_refcnt )) + { + PRBool delete_it; + + if(use_lock) AS_LOCK_READ(name2asi_lock); + delete_it = asi->asi_marked_for_delete; + if(use_lock) AS_UNLOCK_READ(name2asi_lock); + + if ( delete_it ) + { + AS_LOCK_WRITE(name2asi_lock); /* get a write lock */ + if ( asi->asi_marked_for_delete ) /* one final check */ + { + attr_syntax_free(asi); + } + AS_UNLOCK_WRITE(name2asi_lock); + } + } + } +} + +/* + * Add the syntax info to the look-up-by-name table. The asi_name and + * elements of the asi_aliasses field of the syntax info are the keys. + * These need not be normalized since the look up table is case insensitive. + * The lock parameter is used by the initialization code. Normally, we want + * to acquire a write lock before we modify the table, but during + * initialization, we are running in single threaded mode, so we don't have + * to worry about resource contention. + */ +static void +attr_syntax_add_by_name(struct asyntaxinfo *a, int lock) +{ + if (0 != attr_syntax_init()) return; + + if (lock) + AS_LOCK_WRITE(name2asi_lock); + + PL_HashTableAdd(name2asi, a->asi_name, a); + if ( a->asi_aliases != NULL ) { + int i; + + for ( i = 0; a->asi_aliases[i] != NULL; ++i ) { + PL_HashTableAdd(name2asi, a->asi_aliases[i], a); + } + } + + if (lock) + AS_UNLOCK_WRITE(name2asi_lock); +} + + +/* + * Delete the attribute syntax and all entries corresponding to aliases + * and oids. + */ +void +attr_syntax_delete( struct asyntaxinfo *asi ) +{ + PR_ASSERT( asi ); + + if (oid2asi && name2asi) { + AS_LOCK_WRITE(oid2asi_lock); + AS_LOCK_WRITE(name2asi_lock); + + attr_syntax_delete_no_lock( asi, PR_TRUE ); + + AS_UNLOCK_WRITE(name2asi_lock); + AS_UNLOCK_WRITE(oid2asi_lock); + } +} + + +/* + * Dispose of a node. The caller is responsible for locking. See + * attr_syntax_delete() for an example. + */ +static void +attr_syntax_delete_no_lock( struct asyntaxinfo *asi, + PRBool remove_from_oidtable ) +{ + int i; + + if (oid2asi && remove_from_oidtable ) { + PL_HashTableRemove(oid2asi, asi->asi_oid); + } + + if(name2asi) { + PL_HashTableRemove(name2asi, asi->asi_name); + if ( asi->asi_aliases != NULL ) { + for ( i = 0; asi->asi_aliases[i] != NULL; ++i ) { + PL_HashTableRemove(name2asi, asi->asi_aliases[i]); + } + } + if ( asi->asi_refcnt > 0 ) { + asi->asi_marked_for_delete = PR_TRUE; + } else { + attr_syntax_free(asi); + } + } +} + + +/* + * Look up the attribute type in the syntaxes and return a copy of the + * normalised attribute type. If it's not there then return a normalised + * copy of what the caller gave us. + * + * Warning: The caller must free the returned string. + */ + + + +char * +slapi_attr_syntax_normalize( const char *s ) +{ + struct asyntaxinfo *asi = NULL; + char *r; + + + if((asi=attr_syntax_get_by_name_locking_optional(s, PR_TRUE, PR_FALSE)) != NULL ) { + r = slapi_ch_strdup(asi->asi_name); + } + if ( NULL == asi ) { + r = attr_syntax_normalize_no_lookup( s ); + } + return r; +} + + +/* + * attr_syntax_exists: return 1 if attr_name exists, 0 otherwise + * + */ +int +attr_syntax_exists(const char *attr_name) +{ + struct asyntaxinfo *asi; + + asi = attr_syntax_get_by_name(attr_name); + attr_syntax_return( asi ); + + if ( asi != NULL ) + { + return 1; + } + return 0; +} + +/* check syntax without incrementing refcount -- handles locking itself */ + +static void * +attr_syntax_get_plugin_by_name_with_default( const char *type ) +{ + struct asyntaxinfo *asi; + void *plugin = NULL; + + /* + * first we look for this attribute type explictly + */ + if ( (asi = attr_syntax_get_by_name_locking_optional(type, PR_TRUE, PR_FALSE)) == NULL ) { + /* + * no syntax for this type... return DirectoryString + * syntax. we accomplish this by looking up a well known + * attribute type that has that syntax. + */ + asi = attr_syntax_get_by_name_locking_optional( + ATTR_WITH_DIRSTRING_SYNTAX, PR_TRUE, PR_FALSE); + } + if ( NULL != asi ) { + plugin = asi->asi_plugin; + } + return( plugin ); +} + + +static struct asyntaxinfo * +attr_syntax_dup( struct asyntaxinfo *a ) +{ + struct asyntaxinfo *newas = attr_syntax_new(); + + newas->asi_aliases = cool_charray_dup( a->asi_aliases ); + newas->asi_name = slapi_ch_strdup( a->asi_name ); + newas->asi_desc = slapi_ch_strdup( a->asi_desc ); + newas->asi_superior = slapi_ch_strdup( a->asi_superior ); + newas->asi_mr_equality = slapi_ch_strdup( a->asi_mr_equality ); + newas->asi_mr_ordering = slapi_ch_strdup( a->asi_mr_ordering ); + newas->asi_mr_substring = slapi_ch_strdup( a->asi_mr_substring ); + newas->asi_origin = cool_charray_dup( a->asi_origin ); + newas->asi_plugin = a->asi_plugin; + newas->asi_flags = a->asi_flags; + newas->asi_oid = slapi_ch_strdup( a->asi_oid); + newas->asi_syntaxlength = a->asi_syntaxlength; + + return( newas ); +} + + +/* + * Add a new attribute type to the schema. + * + * Returns an LDAP error code (LDAP_SUCCESS if all goes well). + */ +int +attr_syntax_add( struct asyntaxinfo *asip ) +{ + int i, rc = LDAP_SUCCESS; + int nolock = asip->asi_flags & SLAPI_ATTR_FLAG_NOLOCKING; + struct asyntaxinfo *oldas_from_oid = NULL, *oldas_from_name = NULL; + /* attr names may have subtypes in them, and we may not want this + if strip_subtypes is true, the ; and anything after it in the + attr name or alias will be stripped */ + /*int strip_subtypes = 1;*/ + + /* make sure the oid is unique */ + if ( NULL != ( oldas_from_oid = attr_syntax_get_by_oid_locking_optional( + asip->asi_oid, !nolock, PR_TRUE))) { + if ( 0 == (asip->asi_flags & SLAPI_ATTR_FLAG_OVERRIDE)) { + /* failure - OID is in use; no override flag */ + rc = LDAP_TYPE_OR_VALUE_EXISTS; + goto cleanup_and_return; + } + } + + /* make sure the primary name is unique OR, if override is allowed, that + * the primary name and OID point to the same schema definition. + */ + if ( NULL != ( oldas_from_name = attr_syntax_get_by_name_locking_optional( + asip->asi_name, !nolock, PR_TRUE))) { + if ( 0 == (asip->asi_flags & SLAPI_ATTR_FLAG_OVERRIDE) + || ( oldas_from_oid != oldas_from_name )) { + /* failure; no override flag OR OID and name don't match */ + rc = LDAP_TYPE_OR_VALUE_EXISTS; + goto cleanup_and_return; + } + attr_syntax_delete(oldas_from_name); + } else if ( NULL != oldas_from_oid ) { + /* failure - OID is in use but name does not exist */ + rc = LDAP_TYPE_OR_VALUE_EXISTS; + goto cleanup_and_return; + } + + if ( NULL != asip->asi_aliases ) { + /* make sure the aliases are unique */ + for (i = 0; asip->asi_aliases[i] != NULL; ++i) { + struct asyntaxinfo *tmpasi; + + if ( NULL != ( tmpasi = + attr_syntax_get_by_name_locking_optional( + asip->asi_aliases[i], !nolock,PR_TRUE))) { + if (asip->asi_flags & SLAPI_ATTR_FLAG_OVERRIDE) { + attr_syntax_delete(tmpasi); + } else { + /* failure - one of the aliases is already in use */ + rc = LDAP_TYPE_OR_VALUE_EXISTS; + } + + attr_syntax_return( tmpasi ); + if ( LDAP_SUCCESS != rc ) { + goto cleanup_and_return; + } + } + } + } + + /* the no lock flag is not worth keeping around */ + asip->asi_flags &= ~SLAPI_ATTR_FLAG_NOLOCKING; + /* ditto for the override one */ + asip->asi_flags &= ~SLAPI_ATTR_FLAG_OVERRIDE; + + attr_syntax_add_by_oid( asip->asi_oid, asip, !nolock); + attr_syntax_add_by_name( asip, !nolock); + +cleanup_and_return: + attr_syntax_return( oldas_from_oid ); + attr_syntax_return( oldas_from_name ); + return rc; +} + + +/* + * Returns an LDAP result code. + */ +int +attr_syntax_create( + const char *attr_oid, + char *const *attr_names, + int num_names, + const char *attr_desc, + const char *attr_superior, + const char *mr_equality, + const char *mr_ordering, + const char *mr_substring, + char *const *attr_origins, + const char *attr_syntax, + int syntaxlength, + unsigned long flags, + struct asyntaxinfo **asip +) +{ + char *s; + struct asyntaxinfo a; + + /* XXXmcs: had to cast away const in many places below */ + memset(&a, 0, sizeof(a)); + a.asi_name = slapi_ch_strdup(attr_names[0]); + if ( NULL != attr_names[1] ) { + a.asi_aliases = (char **)&attr_names[1]; /* all but the zero'th element */ + } + a.asi_desc = (char*)attr_desc; + a.asi_oid = (char*)attr_oid; + a.asi_superior = (char*)attr_superior; + a.asi_mr_equality = (char*)mr_equality; + a.asi_mr_ordering = (char*)mr_ordering; + a.asi_mr_substring = (char*)mr_substring; + a.asi_origin = (char **)attr_origins; + a.asi_plugin = plugin_syntax_find( attr_syntax ); + a.asi_syntaxlength = syntaxlength; + a.asi_flags = flags; + + /* + * If the 'return exact case' option is on (the default), we store the + * first name (the canonical one) unchanged so that attribute names are + * returned exactly as they appear in the schema configuration files. + * But if 'return exact case' has been turned off, we convert the name + * to lowercase. In Netscape Directory Server 4.x and earlier versions, + * the default was to convert to lowercase. + */ + if (!config_get_return_exact_case()) { + for (s = a.asi_name; *s; ++s) { + *s = TOLOWER(*s); + } + } + + *asip = attr_syntax_dup(&a); + slapi_ch_free((void **)&a.asi_name); + + return LDAP_SUCCESS; +} + + +/* + * slapi_attr_type2plugin - return the plugin handling the attribute type + * if type is unknown, we return the caseIgnoreString plugin used by the + * objectClass attribute type. + */ + +int +slapi_attr_type2plugin( const char *type, void **pi ) +{ + char buf[SLAPD_TYPICAL_ATTRIBUTE_NAME_MAX_LENGTH]; + char *tmp, *basetype; + int rc; + + basetype = buf; + if ( (tmp = slapi_attr_basetype( type, buf, sizeof(buf) )) != NULL ) { + basetype = tmp; + } + rc = -1; + *pi = attr_syntax_get_plugin_by_name_with_default( basetype ); + if ( NULL != *pi ) { + rc = 0; + } + if ( tmp != NULL ) { + free( tmp ); + } + + return( rc ); +} + +/* deprecated -- not MT safe (pointer into asi is returned!) */ +int +slapi_attr_get_oid( const Slapi_Attr *a, char **oid ) +{ + struct asyntaxinfo *asi = attr_syntax_get_by_name(a->a_type); + if (asi) { + *oid = asi->asi_oid; + attr_syntax_return(asi); + return( 0 ); + } else { + *oid = NULL; + return( -1 ); + } +} + + +/* The caller must dispose of oid by calling slapi_ch_free(). */ +int +slapi_attr_get_oid_copy( const Slapi_Attr *a, char **oidp ) +{ + struct asyntaxinfo *asi = attr_syntax_get_by_name(a->a_type); + if (asi) { + *oidp = slapi_ch_strdup( asi->asi_oid ); + attr_syntax_return(asi); + return( 0 ); + } else { + *oidp = NULL; + return( -1 ); + } +} + +#ifdef ATTR_LDAP_DEBUG + +PRIntn +attr_syntax_printnode(PLHashEntry *he, PRIntn i, void *arg) +{ + char *alias = (char *)he->key; + struct asyntaxinfo *a = (struct asyntaxinfo *)he->value; + printf( " name: %s\n", a->asi_name ); + printf( "\t flags : 0x%x\n", a->asi_flags ); + printf( "\t alias : %s\n", alias ); + printf( "\t desc : %s\n", a->asi_desc ); + printf( "\t oid : %s\n", a->asi_oid ); + printf( "\t superior : %s\n", a->asi_superior ); + printf( "\t mr_equality : %s\n", a->asi_mr_equality ); + printf( "\t mr_ordering : %s\n", a->asi_mr_ordering ); + printf( "\t mr_substring: %s\n", a->asi_mr_substring ); + if ( NULL != a->asi_origin ) { + for ( i = 0; NULL != a->asi_origin[i]; ++i ) { + printf( "\t origin : %s\n", a->asi_origin[i] ); + } + } + printf( "\tplugin: %p\n", a->asi_plugin ); + printf( "--------------\n" ); + + return HT_ENUMERATE_NEXT; +} + +void +attr_syntax_print() +{ + printf( "*** attr_syntax_print ***\n" ); + PL_HashTableEnumerateEntries(name2asi, attr_syntax_printnode, 0); +} + +#endif + + +/* lowercase the attr name and chop trailing spaces */ +/* note that s may contain options also, e.g., userCertificate;binary */ +char * +attr_syntax_normalize_no_lookup( const char *s ) +{ + char *save, *tmps; + + tmps = slapi_ch_strdup(s); + for ( save = tmps; (*tmps != '\0') && (*tmps != ' '); tmps++ ) + { + *tmps = TOLOWER( *tmps ); + } + *tmps = '\0'; + + return save; +} + +struct enum_arg_wrapper { + AttrEnumFunc aef; + void *arg; +}; + +PRIntn +attr_syntax_enumerate_internal(PLHashEntry *he, PRIntn i, void *arg) +{ + struct enum_arg_wrapper *eaw = (struct enum_arg_wrapper *)arg; + int rc; + + rc = (eaw->aef)((struct asyntaxinfo *)he->value, eaw->arg); + if ( ATTR_SYNTAX_ENUM_STOP == rc ) { + rc = HT_ENUMERATE_STOP; + } else if ( ATTR_SYNTAX_ENUM_REMOVE == rc ) { + rc = HT_ENUMERATE_REMOVE; + } else { + rc = HT_ENUMERATE_NEXT; + } + + return rc; +} + +void +attr_syntax_enumerate_attrs(AttrEnumFunc aef, void *arg, PRBool writelock ) +{ + struct enum_arg_wrapper eaw; + eaw.aef = aef; + eaw.arg = arg; + + if (!oid2asi) + return; + + if ( writelock ) { + AS_LOCK_WRITE(oid2asi_lock); + AS_LOCK_WRITE(name2asi_lock); + } else { + AS_LOCK_READ(oid2asi_lock); + AS_LOCK_READ(name2asi_lock); + } + + PL_HashTableEnumerateEntries(oid2asi, attr_syntax_enumerate_internal, &eaw); + + if ( writelock ) { + AS_UNLOCK_WRITE(oid2asi_lock); + AS_UNLOCK_WRITE(name2asi_lock); + } else { + AS_UNLOCK_READ(oid2asi_lock); + AS_UNLOCK_READ(name2asi_lock); + } +} + + +struct attr_syntax_enum_flaginfo { + unsigned long asef_flag; +}; + +static int +attr_syntax_clear_flag_callback(struct asyntaxinfo *asip, void *arg) +{ + struct attr_syntax_enum_flaginfo *fi; + + PR_ASSERT( asip != NULL ); + fi = (struct attr_syntax_enum_flaginfo *)arg; + PR_ASSERT( fi != NULL ); + + asip->asi_flags &= ~(fi->asef_flag); + + return ATTR_SYNTAX_ENUM_NEXT; +} + + +static int +attr_syntax_delete_if_not_flagged(struct asyntaxinfo *asip, void *arg) +{ + struct attr_syntax_enum_flaginfo *fi; + + PR_ASSERT( asip != NULL ); + fi = (struct attr_syntax_enum_flaginfo *)arg; + PR_ASSERT( fi != NULL ); + + if ( 0 == ( asip->asi_flags & fi->asef_flag )) { + attr_syntax_delete_no_lock( asip, PR_FALSE ); + return ATTR_SYNTAX_ENUM_REMOVE; + } else { + return ATTR_SYNTAX_ENUM_NEXT; + } +} + + +/* + * Clear 'flag' within all attribute definitions. + */ +void +attr_syntax_all_clear_flag( unsigned long flag ) +{ + struct attr_syntax_enum_flaginfo fi; + + memset( &fi, 0, sizeof(fi)); + fi.asef_flag = flag; + attr_syntax_enumerate_attrs( attr_syntax_clear_flag_callback, + (void *)&fi, PR_TRUE ); +} + + +/* + * Delete all attribute definitions that do not contain any bits of 'flag' + * in their flags. + */ +void +attr_syntax_delete_all_not_flagged( unsigned long flag ) +{ + struct attr_syntax_enum_flaginfo fi; + + memset( &fi, 0, sizeof(fi)); + fi.asef_flag = flag; + attr_syntax_enumerate_attrs( attr_syntax_delete_if_not_flagged, + (void *)&fi, PR_TRUE ); +} + +static int +attr_syntax_init(void) +{ + if (!oid2asi) + { + oid2asi = PL_NewHashTable(2047, hashNocaseString, + hashNocaseCompare, + PL_CompareValues, 0, 0); + if ( NULL == ( oid2asi_lock = PR_NewRWLock( PR_RWLOCK_RANK_NONE, + "attrsyntax oid rwlock" ))) { + if(oid2asi) PL_HashTableDestroy(oid2asi); + oid2asi = NULL; + + slapi_log_error( SLAPI_LOG_FATAL, "attr_syntax_init", + "PR_NewRWLock() for oid2asi lock failed\n" ); + return 1; + } + } + + if (!name2asi) + { + name2asi = PL_NewHashTable(2047, hashNocaseString, + hashNocaseCompare, + PL_CompareValues, 0, 0); + if ( NULL == ( name2asi_lock = PR_NewRWLock( PR_RWLOCK_RANK_NONE, + "attrsyntax name2asi rwlock"))) { + if(name2asi) PL_HashTableDestroy(name2asi); + name2asi = NULL; + + slapi_log_error( SLAPI_LOG_FATAL, "attr_syntax_init", + "PR_NewRWLock() for oid2asi lock failed\n" ); + return 1; + } + } + return 0; +} |