diff options
| author | Apollon Oikonomopoulos <apoikos@debian.org> | 2016-01-14 00:10:06 +0200 |
|---|---|---|
| committer | Apollon Oikonomopoulos <apollon@skroutz.gr> | 2016-01-14 00:10:06 +0200 |
| commit | 374e1947abcd3e127a2a613aff73ecffdb9199ea (patch) | |
| tree | d83973c3c9802450acd5b5e86fe0d4e8e60a3a1b /src/mongo/db/ops/insert.cpp | |
| parent | 65585c90b12d6523bea75a2aebaae2a2fdf9e641 (diff) | |
Imported Upstream version 2.6.11upstream/2.6.11
Diffstat (limited to 'src/mongo/db/ops/insert.cpp')
| -rw-r--r-- | src/mongo/db/ops/insert.cpp | 206 |
1 files changed, 206 insertions, 0 deletions
diff --git a/src/mongo/db/ops/insert.cpp b/src/mongo/db/ops/insert.cpp new file mode 100644 index 00000000000..04f43d3a3a6 --- /dev/null +++ b/src/mongo/db/ops/insert.cpp @@ -0,0 +1,206 @@ +// insert.cpp + +/** + * Copyright (C) 2008 10gen Inc. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License, version 3, + * as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + * + * As a special exception, the copyright holders give permission to link the + * code of portions of this program with the OpenSSL library under certain + * conditions as described in each individual source file and distribute + * linked combinations including the program with the OpenSSL library. You + * must comply with the GNU Affero General Public License in all respects for + * all of the code used other than as permitted herein. If you modify file(s) + * with this exception, you may extend this exception to your version of the + * file(s), but you are not obligated to do so. If you do not wish to do so, + * delete this exception statement from your version. If you delete this + * exception statement from all source files in the program, then also delete + * it in the license file. + */ + +#include "mongo/db/ops/insert.h" +#include "mongo/db/structure/catalog/namespace.h" +#include "mongo/util/mongoutils/str.h" + +namespace mongo { + + using namespace mongoutils; + + StatusWith<BSONObj> fixDocumentForInsert( const BSONObj& doc ) { + if ( doc.objsize() > BSONObjMaxUserSize ) + return StatusWith<BSONObj>( ErrorCodes::BadValue, + str::stream() + << "object to insert too large" + << ". size in bytes: " << doc.objsize() + << ", max size: " << BSONObjMaxUserSize ); + + bool firstElementIsId = doc.firstElement().fieldNameStringData() == "_id"; + bool hasTimestampToFix = false; + { + BSONObjIterator i( doc ); + while ( i.more() ) { + BSONElement e = i.next(); + + if ( e.type() == Timestamp && e.timestampValue() == 0 ) { + // we replace Timestamp(0,0) at the top level with a correct value + // in the fast pass, we just mark that we want to swap + hasTimestampToFix = true; + } + + const char* fieldName = e.fieldName(); + + if ( fieldName[0] == '$' ) { + return StatusWith<BSONObj>( ErrorCodes::BadValue, + str::stream() + << "Document can't have $ prefixed field names: " + << e.fieldName() ); + } + + // check no regexp for _id (SERVER-9502) + // also, disallow undefined and arrays + if ( str::equals( fieldName, "_id") ) { + if ( e.type() == RegEx ) { + return StatusWith<BSONObj>( ErrorCodes::BadValue, + "can't use a regex for _id" ); + } + if ( e.type() == Undefined ) { + return StatusWith<BSONObj>( ErrorCodes::BadValue, + "can't use a undefined for _id" ); + } + if ( e.type() == Array ) { + return StatusWith<BSONObj>( ErrorCodes::BadValue, + "can't use an array for _id" ); + } + if ( e.type() == Object ) { + BSONObj o = e.Obj(); + Status s = o.storageValidEmbedded(); + if ( !s.isOK() ) + return StatusWith<BSONObj>( s ); + } + } + + } + } + + if ( firstElementIsId && !hasTimestampToFix ) + return StatusWith<BSONObj>( BSONObj() ); + + bool hadId = firstElementIsId; + + BSONObjIterator i( doc ); + + BSONObjBuilder b( doc.objsize() + 16 ); + if ( firstElementIsId ) { + b.append( doc.firstElement() ); + i.next(); + } + else { + BSONElement e = doc["_id"]; + if ( e.type() ) { + b.append( e ); + hadId = true; + } + else { + b.appendOID( "_id", NULL, true ); + } + } + + while ( i.more() ) { + BSONElement e = i.next(); + if ( hadId && e.fieldNameStringData() == "_id" ) { + // no-op + } + else if ( e.type() == Timestamp && e.timestampValue() == 0 ) { + mutex::scoped_lock lk(OpTime::m); + b.append( e.fieldName(), OpTime::now(lk) ); + } + else { + b.append( e ); + } + } + return StatusWith<BSONObj>( b.obj() ); + } + + Status userAllowedWriteNS( const StringData& ns ) { + return userAllowedWriteNS( nsToDatabaseSubstring( ns ), nsToCollectionSubstring( ns ) ); + } + + Status userAllowedWriteNS( const NamespaceString& ns ) { + return userAllowedWriteNS( ns.db(), ns.coll() ); + } + + Status userAllowedWriteNS( const StringData& db, const StringData& coll ) { + if ( coll == "system.profile" ) { + return Status( ErrorCodes::BadValue, + str::stream() << "cannot write to '" << db << ".system.profile'" ); + } + return userAllowedCreateNS( db, coll ); + } + + Status userAllowedCreateNS( const StringData& db, const StringData& coll ) { + // validity checking + + if ( db.size() == 0 ) + return Status( ErrorCodes::BadValue, "db cannot be blank" ); + + if ( !NamespaceString::validDBName( db ) ) + return Status( ErrorCodes::BadValue, "invalid db name" ); + + if ( coll.size() == 0 ) + return Status( ErrorCodes::BadValue, "collection cannot be blank" ); + + if ( !NamespaceString::validCollectionName( coll ) ) + return Status( ErrorCodes::BadValue, "invalid collection name" ); + + if ( db.size() + 1 /* dot */ + coll.size() > Namespace::MaxNsColletionLen ) + return Status( ErrorCodes::BadValue, + str::stream() + << "fully qualified namespace " << db << '.' << coll << " is too long " + << "(max is " << Namespace::MaxNsColletionLen << " bytes)" ); + + // check spceial areas + + if ( db == "system" ) + return Status( ErrorCodes::BadValue, "cannot use 'system' database" ); + + + if ( coll.startsWith( "system." ) ) { + if ( coll == "system.indexes" ) return Status::OK(); + if ( coll == "system.js" ) return Status::OK(); + if ( coll == "system.profile" ) return Status::OK(); + if ( coll == "system.users" ) return Status::OK(); + if ( db == "admin" ) { + if ( coll == "system.version" ) return Status::OK(); + if ( coll == "system.roles" ) return Status::OK(); + if ( coll == "system.new_users" ) return Status::OK(); + if ( coll == "system.backup_users" ) return Status::OK(); + } + if ( db == "local" ) { + if ( coll == "system.replset" ) return Status::OK(); + } + return Status( ErrorCodes::BadValue, + str::stream() << "cannot write to '" << db << "." << coll << "'" ); + } + + // some special rules + + if ( coll.find( ".system." ) != string::npos ) { + // this matches old (2.4 and older) behavior, but I'm not sure its a good idea + return Status( ErrorCodes::BadValue, + str::stream() << "cannot write to '" << db << "." << coll << "'" ); + } + + return Status::OK(); + } + +} |
