ITS#8181 Verify that records are/aren't DBs.
authorHallvard Furuseth <hallvard@openldap.org>
Sat, 11 Jul 2015 19:01:40 +0000 (21:01 +0200)
committerHallvard Furuseth <hallvard@openldap.org>
Sat, 11 Jul 2015 19:01:40 +0000 (21:01 +0200)
Except we don't catch the user passing F_SUBDATA to
mdb_cursor_<put/del>, like an internal LMDB call.

libraries/liblmdb/lmdb.h
libraries/liblmdb/mdb.c

index deb6812..c27f78b 100644 (file)
@@ -421,7 +421,14 @@ typedef enum MDB_cursor_op {
 #define MDB_PAGE_FULL  (-30786)
        /** Database contents grew beyond environment mapsize */
 #define MDB_MAP_RESIZED        (-30785)
-       /** MDB_INCOMPATIBLE: Operation and DB incompatible, or DB flags changed */
+       /** Operation and DB incompatible, or DB type changed. This can mean:
+        *      <ul>
+        *      <li>The operation expects an #MDB_DUPSORT / #MDB_DUPFIXED database.
+        *      <li>Opening a named DB when the unnamed DB has #MDB_DUPSORT / #MDB_INTEGERKEY.
+        *      <li>Accessing a data record as a database, or vice versa.
+        *      <li>The database was dropped and recreated with different flags.
+        *      </ul>
+        */
 #define MDB_INCOMPATIBLE       (-30784)
        /** Invalid reuse of reader locktable slot */
 #define MDB_BAD_RSLOT          (-30783)
@@ -1057,8 +1064,9 @@ int  mdb_txn_renew(MDB_txn *txn);
         * any other transaction in the process may use this function.
         *
         * To use named databases (with name != NULL), #mdb_env_set_maxdbs()
-        * must be called before opening the environment.  Database names
-        * are kept as keys in the unnamed database.
+        * must be called before opening the environment.  Database names are
+        * keys in the unnamed database, and may be read but not written.
+        *
         * @param[in] txn A transaction handle returned by #mdb_txn_begin()
         * @param[in] name The name of the database to open. If only a single
         *      database is needed in the environment, this value may be NULL.
index b576c82..9ccac2c 100644 (file)
@@ -3519,7 +3519,8 @@ mdb_txn_commit(MDB_txn *txn)
                                        goto fail;
                                }
                                data.mv_data = &txn->mt_dbs[i];
-                               rc = mdb_cursor_put(&mc, &txn->mt_dbxs[i].md_name, &data, 0);
+                               rc = mdb_cursor_put(&mc, &txn->mt_dbxs[i].md_name, &data,
+                                       F_SUBDATA);
                                if (rc)
                                        goto fail;
                        }
@@ -5413,6 +5414,8 @@ mdb_page_search(MDB_cursor *mc, MDB_val *key, int flags)
                                                &mc->mc_dbx->md_name, &exact);
                                        if (!exact)
                                                return MDB_NOTFOUND;
+                                       if ((leaf->mn_flags & (F_DUPDATA|F_SUBDATA)) != F_SUBDATA)
+                                               return MDB_INCOMPATIBLE; /* not a named DB */
                                        rc = mdb_node_read(mc->mc_txn, leaf, &data);
                                        if (rc)
                                                return rc;
@@ -6604,6 +6607,9 @@ prep_subDB:
                        goto new_sub;
                }
 current:
+               /* LMDB passes F_SUBDATA in 'flags' to write a DB record */
+               if ((leaf->mn_flags ^ flags) & F_SUBDATA)
+                       return MDB_INCOMPATIBLE;
                /* overflow page overwrites need special handling */
                if (F_ISSET(leaf->mn_flags, F_BIGDATA)) {
                        MDB_page *omp;
@@ -6874,6 +6880,11 @@ mdb_cursor_del(MDB_cursor *mc, unsigned int flags)
                                goto fail;
                }
        }
+       /* LMDB passes F_SUBDATA in 'flags' to delete a DB record */
+       else if ((leaf->mn_flags ^ flags) & F_SUBDATA) {
+               rc = MDB_INCOMPATIBLE;
+               goto fail;
+       }
 
        /* add overflow pages to free list */
        if (F_ISSET(leaf->mn_flags, F_BIGDATA)) {
@@ -9358,7 +9369,7 @@ int mdb_dbi_open(MDB_txn *txn, const char *name, unsigned int flags, MDB_dbi *db
        if (rc == MDB_SUCCESS) {
                /* make sure this is actually a DB */
                MDB_node *node = NODEPTR(mc.mc_pg[mc.mc_top], mc.mc_ki[mc.mc_top]);
-               if (!(node->mn_flags & F_SUBDATA))
+               if ((node->mn_flags & (F_DUPDATA|F_SUBDATA)) != F_SUBDATA)
                        return MDB_INCOMPATIBLE;
        } else if (rc == MDB_NOTFOUND && (flags & MDB_CREATE)) {
                /* Create if requested */
@@ -9554,7 +9565,7 @@ int mdb_drop(MDB_txn *txn, MDB_dbi dbi, int del)
 
        /* Can't delete the main DB */
        if (del && dbi > MAIN_DBI) {
-               rc = mdb_del0(txn, MAIN_DBI, &mc->mc_dbx->md_name, NULL, 0);
+               rc = mdb_del0(txn, MAIN_DBI, &mc->mc_dbx->md_name, NULL, F_SUBDATA);
                if (!rc) {
                        txn->mt_dbflags[dbi] = DB_STALE;
                        mdb_dbi_close(txn->mt_env, dbi);