]> git.sur5r.net Git - openldap/blob - servers/slapd/back-bdb/operational.c
Merge remote-tracking branch 'origin/mdb.master'
[openldap] / servers / slapd / back-bdb / operational.c
1 /* operational.c - bdb backend operational attributes function */
2 /* $OpenLDAP$ */
3 /* This work is part of OpenLDAP Software <http://www.openldap.org/>.
4  *
5  * Copyright 2000-2013 The OpenLDAP Foundation.
6  * All rights reserved.
7  *
8  * Redistribution and use in source and binary forms, with or without
9  * modification, are permitted only as authorized by the OpenLDAP
10  * Public License.
11  *
12  * A copy of this license is available in the file LICENSE in the
13  * top-level directory of the distribution or, alternatively, at
14  * <http://www.OpenLDAP.org/license.html>.
15  */
16
17 #include "portable.h"
18
19 #include <stdio.h>
20
21 #include <ac/string.h>
22 #include <ac/socket.h>
23
24 #include "slap.h"
25 #include "back-bdb.h"
26
27 /*
28  * sets *hasSubordinates to LDAP_COMPARE_TRUE/LDAP_COMPARE_FALSE
29  * if the entry has children or not.
30  */
31 int
32 bdb_hasSubordinates(
33         Operation       *op,
34         Entry           *e,
35         int             *hasSubordinates )
36 {
37         struct bdb_info *bdb = (struct bdb_info *) op->o_bd->be_private;
38         struct bdb_op_info      *opinfo;
39         OpExtra *oex;
40         DB_TXN          *rtxn;
41         int             rc;
42         int             release = 0;
43         
44         assert( e != NULL );
45
46         /* NOTE: this should never happen, but it actually happens
47          * when using back-relay; until we find a better way to
48          * preserve entry's private information while rewriting it,
49          * let's disable the hasSubordinate feature for back-relay.
50          */
51         if ( BEI( e ) == NULL ) {
52                 Entry *ee = NULL;
53                 rc = be_entry_get_rw( op, &e->e_nname, NULL, NULL, 0, &ee );
54                 if ( rc != LDAP_SUCCESS || ee == NULL ) {
55                         rc = LDAP_OTHER;
56                         goto done;
57                 }
58                 e = ee;
59                 release = 1;
60                 if ( BEI( ee ) == NULL ) {
61                         rc = LDAP_OTHER;
62                         goto done;
63                 }
64         }
65
66         /* Check for a txn in a parent op, otherwise use reader txn */
67         LDAP_SLIST_FOREACH( oex, &op->o_extra, oe_next ) {
68                 if ( oex->oe_key == bdb )
69                         break;
70         }
71         opinfo = (struct bdb_op_info *) oex;
72         if ( opinfo && opinfo->boi_txn ) {
73                 rtxn = opinfo->boi_txn;
74         } else {
75                 rc = bdb_reader_get(op, bdb->bi_dbenv, &rtxn);
76                 if ( rc ) {
77                         rc = LDAP_OTHER;
78                         goto done;
79                 }
80         }
81
82 retry:
83         /* FIXME: we can no longer assume the entry's e_private
84          * field is correctly populated; so we need to reacquire
85          * it with reader lock */
86         rc = bdb_cache_children( op, rtxn, e );
87
88         switch( rc ) {
89         case DB_LOCK_DEADLOCK:
90         case DB_LOCK_NOTGRANTED:
91                 goto retry;
92
93         case 0:
94                 *hasSubordinates = LDAP_COMPARE_TRUE;
95                 break;
96
97         case DB_NOTFOUND:
98                 *hasSubordinates = LDAP_COMPARE_FALSE;
99                 rc = LDAP_SUCCESS;
100                 break;
101
102         default:
103                 Debug(LDAP_DEBUG_ARGS, 
104                         "<=- " LDAP_XSTRING(bdb_hasSubordinates)
105                         ": has_children failed: %s (%d)\n", 
106                         db_strerror(rc), rc, 0 );
107                 rc = LDAP_OTHER;
108         }
109
110 done:;
111         if ( release && e != NULL ) be_entry_release_r( op, e );
112         return rc;
113 }
114
115 /*
116  * sets the supported operational attributes (if required)
117  */
118 int
119 bdb_operational(
120         Operation       *op,
121         SlapReply       *rs )
122 {
123         Attribute       **ap;
124
125         assert( rs->sr_entry != NULL );
126
127         for ( ap = &rs->sr_operational_attrs; *ap; ap = &(*ap)->a_next ) {
128                 if ( (*ap)->a_desc == slap_schema.si_ad_hasSubordinates ) {
129                         break;
130                 }
131         }
132
133         if ( *ap == NULL &&
134                 attr_find( rs->sr_entry->e_attrs, slap_schema.si_ad_hasSubordinates ) == NULL &&
135                 ( SLAP_OPATTRS( rs->sr_attr_flags ) ||
136                         ad_inlist( slap_schema.si_ad_hasSubordinates, rs->sr_attrs ) ) )
137         {
138                 int     hasSubordinates, rc;
139
140                 rc = bdb_hasSubordinates( op, rs->sr_entry, &hasSubordinates );
141                 if ( rc == LDAP_SUCCESS ) {
142                         *ap = slap_operational_hasSubordinate( hasSubordinates == LDAP_COMPARE_TRUE );
143                         assert( *ap != NULL );
144
145                         ap = &(*ap)->a_next;
146                 }
147         }
148
149         return LDAP_SUCCESS;
150 }
151