diff options
-rw-r--r-- | db/namespace.cpp | 14 | ||||
-rw-r--r-- | db/namespace.h | 7 | ||||
-rw-r--r-- | db/pdfile.cpp | 2 | ||||
-rw-r--r-- | db/query.cpp | 6 | ||||
-rw-r--r-- | jstests/storefunc.js | 31 | ||||
-rw-r--r-- | scripting/engine.cpp | 43 | ||||
-rw-r--r-- | scripting/engine.h | 14 | ||||
-rw-r--r-- | scripting/engine_spidermonkey.cpp | 12 |
8 files changed, 119 insertions, 10 deletions
diff --git a/db/namespace.cpp b/db/namespace.cpp index b37eb8c6727..c3fe9485402 100644 --- a/db/namespace.cpp +++ b/db/namespace.cpp @@ -21,6 +21,7 @@ #include "db.h" #include "../util/mmap.h" #include "../util/hashtab.h" +#include "../scripting/engine.h" #include "btree.h" #include <algorithm> #include <list> @@ -692,5 +693,18 @@ namespace mongo { deleteObjects( s.c_str(), oldIndexSpec.getOwned(), true, false, true ); } } + + bool legalClientSystemNS( const string& ns , bool write ){ + if ( ns.find( ".system.users" ) != string::npos ) + return true; + + if ( ns.find( ".system.js" ) != string::npos ){ + if ( write ) + Scope::storedFuncMod(); + return true; + } + + return false; + } } // namespace mongo diff --git a/db/namespace.h b/db/namespace.h index 58e66bac17d..dca7e685a05 100644 --- a/db/namespace.h +++ b/db/namespace.h @@ -126,6 +126,13 @@ namespace mongo { char buf[MaxNsLen]; }; + /** + @return true if a client can modify this namespace + things like *.system.users + */ + bool legalClientSystemNS( const string& ns , bool write ); + + /* deleted lists -- linked lists of deleted records -- are placed in 'buckets' of various sizes so you can look for a deleterecord about the right size. */ diff --git a/db/pdfile.cpp b/db/pdfile.cpp index 599bc5736dc..04bec88ba0e 100644 --- a/db/pdfile.cpp +++ b/db/pdfile.cpp @@ -1302,7 +1302,7 @@ assert( !eloc.isNull() ); // later:check for dba-type permissions here if have that at some point separate if ( strstr(ns, ".system.indexes" ) ) wouldAddIndex = true; - else if ( strstr(ns, ".system.users") ) + else if ( legalClientSystemNS( ns , true ) ) ; else if ( !god ) { out() << "ERROR: attempt to insert in system namespace " << ns << endl; diff --git a/db/query.cpp b/db/query.cpp index c6d40b6fd67..d2890422365 100644 --- a/db/query.cpp +++ b/db/query.cpp @@ -112,9 +112,7 @@ namespace mongo { if done here, as there are pointers into those objects in NamespaceDetails. */ - if( strstr(ns, ".system.users") ) - ; - else { + if( ! legalClientSystemNS( ns , true ) ){ uasserted("cannot delete from system namespace"); return -1; } @@ -752,7 +750,7 @@ namespace mongo { uassert("cannot update reserved $ collection", strchr(ns, '$') == 0 ); if ( strstr(ns, ".system.") ) { - uassert("cannot update system collection", strstr(ns, ".system.users")); + uassert("cannot update system collection", legalClientSystemNS( ns , true ) ); } QueryPlanSet qps( ns, pattern, BSONObj() ); diff --git a/jstests/storefunc.js b/jstests/storefunc.js new file mode 100644 index 00000000000..bae109035fe --- /dev/null +++ b/jstests/storefunc.js @@ -0,0 +1,31 @@ + +s = db.system.js; +s.remove({}); +assert.eq( 0 , s.count() , "setup - A" ); + +s.save( { _id : "x" , value : "3" } ); +assert.isnull( db.getLastError() , "setup - B" ); +assert.eq( 1 , s.count() , "setup - C" ); + +s.remove( { _id : "x" } ); +assert.eq( 0 , s.count() , "setup - D" ); +s.save( { _id : "x" , value : "4" } ); +assert.eq( 1 , s.count() , "setup - E" ); + +assert.eq( 4 , s.findOne().value , "setup - F" ); +s.update( { _id : "x" } , { $set : { value : 5 } } ); +assert.eq( 1 , s.count() , "setup - G" ); +assert.eq( 5 , s.findOne().value , "setup - H" ); + +assert.eq( 5 , db.eval( "return x" ) , "exec - 1 " ); + +s.update( { _id : "x" } , { $set : { value : 6 } } ); +assert.eq( 1 , s.count() , "setup2 - A" ); +assert.eq( 6 , s.findOne().value , "setup - B" ); + +assert.eq( 6 , db.eval( "return x" ) , "exec - 2 " ); + + + +s.insert( { _id : "bar" , value : function( z ){ return 17 + z; } } ); +assert.eq( 22 , db.eval( "return bar(5);" ) , "exec - 3 " ); diff --git a/scripting/engine.cpp b/scripting/engine.cpp index 5c53cdd1f65..c82f5961563 100644 --- a/scripting/engine.cpp +++ b/scripting/engine.cpp @@ -3,10 +3,13 @@ #include "stdafx.h" #include "engine.h" #include "../util/file.h" +#include "../client/dbclient.h" namespace mongo { + + long long Scope::_lastVersion = 1; - Scope::Scope(){ + Scope::Scope() : _localDBName("") , _loadedVersion(0){ } Scope::~Scope(){ @@ -88,6 +91,37 @@ namespace mongo { return exec( data , filename , printResult , reportError , assertOnError, timeoutMs ); } + + void Scope::storedFuncMod(){ + _lastVersion++; + } + + void Scope::loadStored( bool ignoreNotConnected ){ + if ( _localDBName.size() == 0 ){ + if ( ignoreNotConnected ) + return; + uassert( "need to have locallyConnected already" , _localDBName.size() ); + } + if ( _loadedVersion == _lastVersion ) + return; + + _loadedVersion = _lastVersion; + + static DBClientBase * db = createDirectClient(); + + auto_ptr<DBClientCursor> c = db->query( _localDBName + ".system.js" , Query() ); + while ( c->more() ){ + BSONObj o = c->next(); + + BSONElement n = o["_id"]; + BSONElement v = o["value"]; + + uassert( "name has to be a string" , n.type() == String ); + uassert( "value has to be set" , v.type() != EOO ); + + setElement( n.valuestr() , v ); + } + } typedef map< string , list<Scope*> > PoolToScopes; @@ -157,7 +191,9 @@ namespace mongo { class PooledScope : public Scope { public: - PooledScope( const string pool , Scope * real ) : _pool( pool ) , _real( real ){}; + PooledScope( const string pool , Scope * real ) : _pool( pool ) , _real( real ){ + _real->loadStored( true ); + }; virtual ~PooledScope(){ ScopeCache * sc = scopeCache.get(); if ( sc ){ @@ -202,6 +238,9 @@ namespace mongo { return _real->type( field ); } + void setElement( const char *field , const BSONElement& val ){ + _real->setElement( field , val ); + } void setNumber( const char *field , double val ){ _real->setNumber( field , val ); } diff --git a/scripting/engine.h b/scripting/engine.h index 50b0dee6dea..fb9aa48dbc2 100644 --- a/scripting/engine.h +++ b/scripting/engine.h @@ -36,6 +36,7 @@ namespace mongo { void append( BSONObjBuilder & builder , const char * fieldName , const char * scopeName ); + virtual void setElement( const char *field , const BSONElement& e ) = 0; virtual void setNumber( const char *field , double val ) = 0; virtual void setString( const char *field , const char * val ) = 0; virtual void setObject( const char *field , const BSONObj& obj , bool readOnly=true ) = 0; @@ -67,6 +68,19 @@ namespace mongo { virtual void injectNative( const char *field, NativeFunction func ) = 0; virtual void gc() = 0; + + void loadStored( bool ignoreNotConnected = false ); + + /** + if any changes are made to .system.js, call this + right now its just global - slightly inefficient, but a lot simpler + */ + static void storedFuncMod(); + + protected: + string _localDBName; + long long _loadedVersion; + static long long _lastVersion; }; class ScriptEngine : boost::noncopyable { diff --git a/scripting/engine_spidermonkey.cpp b/scripting/engine_spidermonkey.cpp index 0fbeb0bb3db..88a410544a1 100644 --- a/scripting/engine_spidermonkey.cpp +++ b/scripting/engine_spidermonkey.cpp @@ -1008,7 +1008,7 @@ namespace mongo { smlock; uassert( "already setup for external db" , ! _externalSetup ); if ( _localConnect ){ - uassert( "connected to different db" , _dbName == dbName ); + uassert( "connected to different db" , _localDBName == dbName ); return; } @@ -1018,7 +1018,8 @@ namespace mongo { exec( ((string)"db = _mongo.getDB( \"" + dbName + "\" ); ").c_str() ); _localConnect = true; - _dbName = dbName; + _localDBName = dbName; + loadStored(); } // ----- getters ------ @@ -1082,6 +1083,12 @@ namespace mongo { // ----- setters ------ + void setElement( const char *field , const BSONElement& val ){ + smlock; + jsval v = _convertor->toval( val ); + assert( JS_SetProperty( _context , _global , field , &v ) ); + } + void setNumber( const char *field , double val ){ smlock; jsval v = _convertor->toval( val ); @@ -1301,7 +1308,6 @@ namespace mongo { bool _externalSetup; bool _localConnect; - string _dbName; set<string> _initFieldNames; |