mirror of
https://github.com/isar/libmdbx.git
synced 2025-01-06 18:44:13 +08:00
lmdb: ITS#8181 Verify that records are/aren't DBs.
Except we don't catch the user passing F_SUBDATA to mdb_cursor_<put/del>, like an internal LMDB call. Change-Id: I5ebce36694045279702c74490a5a634217d4f95d
This commit is contained in:
parent
91a6b6de57
commit
be27186f76
14
lmdb.h
14
lmdb.h
@ -412,7 +412,14 @@ typedef enum MDB_cursor_op {
|
|||||||
#define MDB_PAGE_FULL (-30786)
|
#define MDB_PAGE_FULL (-30786)
|
||||||
/** Database contents grew beyond environment mapsize */
|
/** Database contents grew beyond environment mapsize */
|
||||||
#define MDB_MAP_RESIZED (-30785)
|
#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)
|
#define MDB_INCOMPATIBLE (-30784)
|
||||||
/** Invalid reuse of reader locktable slot */
|
/** Invalid reuse of reader locktable slot */
|
||||||
#define MDB_BAD_RSLOT (-30783)
|
#define MDB_BAD_RSLOT (-30783)
|
||||||
@ -1078,8 +1085,9 @@ int mdb_txn_renew(MDB_txn *txn);
|
|||||||
* any other transaction in the process may use this function.
|
* any other transaction in the process may use this function.
|
||||||
*
|
*
|
||||||
* To use named databases (with name != NULL), #mdb_env_set_maxdbs()
|
* To use named databases (with name != NULL), #mdb_env_set_maxdbs()
|
||||||
* must be called before opening the environment. Database names
|
* must be called before opening the environment. Database names are
|
||||||
* are kept as keys in the unnamed database.
|
* 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] txn A transaction handle returned by #mdb_txn_begin()
|
||||||
* @param[in] name The name of the database to open. If only a single
|
* @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.
|
* database is needed in the environment, this value may be NULL.
|
||||||
|
19
mdb.c
19
mdb.c
@ -3754,7 +3754,8 @@ mdb_txn_commit(MDB_txn *txn)
|
|||||||
goto fail;
|
goto fail;
|
||||||
}
|
}
|
||||||
data.mv_data = &txn->mt_dbs[i];
|
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 (unlikely(rc != MDB_SUCCESS))
|
if (unlikely(rc != MDB_SUCCESS))
|
||||||
goto fail;
|
goto fail;
|
||||||
}
|
}
|
||||||
@ -5236,6 +5237,8 @@ mdb_page_search(MDB_cursor *mc, MDB_val *key, int flags)
|
|||||||
&mc->mc_dbx->md_name, &exact);
|
&mc->mc_dbx->md_name, &exact);
|
||||||
if (!exact)
|
if (!exact)
|
||||||
return MDB_NOTFOUND;
|
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);
|
rc = mdb_node_read(mc->mc_txn, leaf, &data);
|
||||||
if (rc)
|
if (rc)
|
||||||
return rc;
|
return rc;
|
||||||
@ -6437,6 +6440,9 @@ prep_subDB:
|
|||||||
goto new_sub;
|
goto new_sub;
|
||||||
}
|
}
|
||||||
current:
|
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 */
|
/* overflow page overwrites need special handling */
|
||||||
if (F_ISSET(leaf->mn_flags, F_BIGDATA)) {
|
if (F_ISSET(leaf->mn_flags, F_BIGDATA)) {
|
||||||
MDB_page *omp;
|
MDB_page *omp;
|
||||||
@ -6707,6 +6713,11 @@ mdb_cursor_del(MDB_cursor *mc, unsigned flags)
|
|||||||
goto fail;
|
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 */
|
/* add overflow pages to free list */
|
||||||
if (F_ISSET(leaf->mn_flags, F_BIGDATA)) {
|
if (F_ISSET(leaf->mn_flags, F_BIGDATA)) {
|
||||||
@ -9174,8 +9185,8 @@ int mdb_dbi_open(MDB_txn *txn, const char *name, unsigned flags, MDB_dbi *dbi)
|
|||||||
if (rc == MDB_SUCCESS) {
|
if (rc == MDB_SUCCESS) {
|
||||||
/* make sure this is actually a DB */
|
/* make sure this is actually a DB */
|
||||||
MDB_node *node = NODEPTR(mc.mc_pg[mc.mc_top], mc.mc_ki[mc.mc_top]);
|
MDB_node *node = NODEPTR(mc.mc_pg[mc.mc_top], mc.mc_ki[mc.mc_top]);
|
||||||
if (!(node->mn_flags & F_SUBDATA))
|
if (unlikely((node->mn_flags & (F_DUPDATA|F_SUBDATA)) != F_SUBDATA))
|
||||||
return MDB_BAD_DBI;
|
return MDB_INCOMPATIBLE;
|
||||||
} else if (rc == MDB_NOTFOUND && (flags & MDB_CREATE)) {
|
} else if (rc == MDB_NOTFOUND && (flags & MDB_CREATE)) {
|
||||||
/* Create if requested */
|
/* Create if requested */
|
||||||
data.mv_size = sizeof(MDB_db);
|
data.mv_size = sizeof(MDB_db);
|
||||||
@ -9369,7 +9380,7 @@ int mdb_drop(MDB_txn *txn, MDB_dbi dbi, int del)
|
|||||||
|
|
||||||
/* Can't delete the main DB */
|
/* Can't delete the main DB */
|
||||||
if (del && dbi > MAIN_DBI) {
|
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) {
|
if (!rc) {
|
||||||
txn->mt_dbflags[dbi] = DB_STALE;
|
txn->mt_dbflags[dbi] = DB_STALE;
|
||||||
mdb_dbi_close(txn->mt_env, dbi);
|
mdb_dbi_close(txn->mt_env, dbi);
|
||||||
|
Loading…
x
Reference in New Issue
Block a user