diff --git a/CHANGELOG b/CHANGELOG index a122974812..f0730ba5d6 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -1,6 +1,13 @@ v1.2.alpha (XXXX-XX-XX) ----------------------- +* unified history file locations for arangod, arangosh, and arangoirb. + - The readline history for arangod (emergency console) is now stored in file + $HOME/.arangod. It was stored in $HOME/.arangod before. + - The readline history for arangosh is still stored in $HOME/.arangosh. + - The readline history for arangoirb is now stored in $HOME/.arangoirb. It was + stored in $HOME/.arango-mrb before. + * fixed issue #381: _users user should have a unique constraint * allow negative list indexes in AQL to access elements from the end of a list, diff --git a/UnitTests/Makefile.unittests b/UnitTests/Makefile.unittests index 60ff208f79..2bad943142 100755 --- a/UnitTests/Makefile.unittests +++ b/UnitTests/Makefile.unittests @@ -434,7 +434,7 @@ unittests-import: ################################################################################ -### @brief DATAFILE DEBUGGER TESTS +### @brief DATAFILE DEBUGGER TESTS ### ### this test just checks whether the dfdb starts. ### we will send an EOT signal to the dfdb process to stop it right away. @@ -526,7 +526,7 @@ cppcheck: ## ----------------------------------------------------------------------------- ## --SECTION-- END-OF-FILE ## ----------------------------------------------------------------------------- - + ## Local Variables: ## mode: outline-minor ## outline-regexp: "^\\(### @brief\\|## --SECTION--\\|# -\\*- \\)" diff --git a/arangod/Documentation/communication.dox b/arangod/Documentation/communication.dox index 9f98e0a13f..fff1ec08ad 100644 --- a/arangod/Documentation/communication.dox +++ b/arangod/Documentation/communication.dox @@ -49,8 +49,13 @@ /// Client authentication is done by using the @LIT{Authorization} HTTP header. /// ArangoDB supports Basic authentication. /// -/// Authentication is optional if the server has been started with the option -/// @LIT{\-\-server.disable-authentication}. +/// Authentication is optional. To enforce authentication for incoming requested, the +/// server must be started with the option @LIT{\-\-server.disable-authentication}. +/// Please note that requests using the HTTP OPTIONS method will be answered by +/// ArangoDB in any case, even if no authentication data is sent by the client or if +/// the authentication data is wrong. This is required for handling CORS preflight +/// requests (see @ref CommunicationCors). The response to an HTTP OPTIONS request +/// will be generic and not expose any private data. /// /// @section CommunicationErrors Error Handling /// @@ -128,6 +133,18 @@ /// ignored by ArangoDB its value is not @LIT{true}. If a client sends a header /// value of @LIT{true}, ArangoDB will return the header /// @LIT{access-control-allow-credentials: true}, too. +/// +/// Note that CORS preflight requests will probably not send any authentication +/// data with them. One of the purposes of the preflight request is to check whether +/// the server accepts authentication or not. +/// +/// A consequence of this is that ArangoDB will allow requests using the HTTP +/// OPTIONS method without credentials, even when the server is run with +/// authentication enabled. +/// +/// The response to the HTTP OPTIONS request will however be a generic response +/// that will not expose any private data and thus can be considered "safe" +/// even without credentials. //////////////////////////////////////////////////////////////////////////////// // Local Variables: diff --git a/arangod/RestServer/ArangoServer.cpp b/arangod/RestServer/ArangoServer.cpp index 79ac409154..55029c0193 100644 --- a/arangod/RestServer/ArangoServer.cpp +++ b/arangod/RestServer/ArangoServer.cpp @@ -228,7 +228,9 @@ void ArangoServer::buildApplicationServer () { _applicationServer = new ApplicationServer("arangod", "[] ", TRIAGENS_VERSION); _applicationServer->setSystemConfigFile("arangod.conf"); - _applicationServer->setUserConfigFile(string(".arango") + string(1,TRI_DIR_SEPARATOR_CHAR) + string("arangod.conf") ); + + // arangod allows defining a user-specific configuration file. arangosh and the other binaries don't + _applicationServer->setUserConfigFile(string(".arango") + string(1, TRI_DIR_SEPARATOR_CHAR) + string("arangod.conf") ); // ............................................................................. // multi-threading scheduler @@ -457,7 +459,7 @@ void ArangoServer::buildApplicationServer () { int res = executeConsole(mode); TRI_FlushLogging(); - exit(res); + TRI_EXIT_FUNCTION(res,NULL); } #ifdef TRI_ENABLE_MRUBY else if (mode == OperationMode::MODE_RUBY_CONSOLE) { @@ -840,7 +842,7 @@ int ArangoServer::executeConsole (OperationMode::server_operation_mode_e mode) { // ............................................................................. case OperationMode::MODE_CONSOLE: { - V8LineEditor console(context->_context, ".arango"); + V8LineEditor console(context->_context, ".arangod"); console.open(true); @@ -1015,7 +1017,7 @@ int ArangoServer::executeRubyConsole () { // create a line editor printf("ArangoDB MRuby emergency console [DB version %s]\n", TRIAGENS_VERSION); - MRLineEditor console(context->_mrb, ".arango-mrb"); + MRLineEditor console(context->_mrb, ".arangod"); console.open(false); diff --git a/arangod/RestServer/arango.cpp b/arangod/RestServer/arango.cpp index 214f04e40b..eba033def8 100755 --- a/arangod/RestServer/arango.cpp +++ b/arangod/RestServer/arango.cpp @@ -26,6 +26,7 @@ //////////////////////////////////////////////////////////////////////////////// #include "Basics/Common.h" +#include "BasicsC/messages.h" #include "RestServer/ArangoServer.h" #include "ResultGenerator/InitialiseGenerator.h" @@ -43,19 +44,25 @@ using namespace triagens::arango; /// @{ //////////////////////////////////////////////////////////////////////////////// + + //////////////////////////////////////////////////////////////////////////////// -/// @brief creates an application server +/// @brief startup and exit functions //////////////////////////////////////////////////////////////////////////////// -int main (int argc, char* argv[]) { - int res; +void* arangodResourcesAllocated = NULL; +static void arangodEntryFunction (); +static void arangodExitFunction (int, void*); #ifdef _WIN32 - // ........................................................................... - // Call this function to do various initialistions for windows only - // ........................................................................... - +// ............................................................................. +// Call this function to do various initialistions for windows only +// ............................................................................. +void arangodEntryFunction() { + int maxOpenFiles = 2048; // upper hard limit for windows + int res = 0; + // ........................................................................... // Uncomment this to call this for extended debug information. // If you familiar with valgrind ... then this is not like that, however @@ -67,13 +74,56 @@ int main (int argc, char* argv[]) { if (res != 0) { _exit(1); } + + res = initialiseWindows(TRI_WIN_INITIAL_SET_MAX_STD_IO,(const char*)(&maxOpenFiles)); + if (res != 0) { + _exit(1); + } + res = initialiseWindows(TRI_WIN_INITIAL_WSASTARTUP_FUNCTION_CALL, 0); if (res != 0) { _exit(1); } + TRI_Application_Exit_SetExit(arangodExitFunction); + +} + +static void arangodExitFunction(int exitCode, void* data) { + int res = 0; + // ........................................................................... + // TODO: need a terminate function for windows to be called and cleanup + // any windows specific stuff. + // ........................................................................... + + res = finaliseWindows(TRI_WIN_FINAL_WSASTARTUP_FUNCTION_CALL, 0); + + if (res != 0) { + _exit(1); + } + + _exit(exitCode); +} +#else + +static void arangodEntryFunction() { +} + +static void arangodExitFunction(int exitCode, void* data) { +} + #endif + +//////////////////////////////////////////////////////////////////////////////// +/// @brief creates an application server +//////////////////////////////////////////////////////////////////////////////// + +int main (int argc, char* argv[]) { + int res = 0; + + arangodEntryFunction(); + TRIAGENS_RESULT_GENERATOR_INITIALISE(argc, argv); // create and start a ArangoDB server @@ -84,16 +134,7 @@ int main (int argc, char* argv[]) { // shutdown TRIAGENS_RESULT_GENERATOR_SHUTDOWN; -#ifdef _WIN32 - - // ........................................................................... - // TODO: need a terminate function for windows to be called and cleanup - // any windows specific stuff. - // ........................................................................... - - res = finaliseWindows(TRI_WIN_FINAL_WSASTARTUP_FUNCTION_CALL, 0); - -#endif + arangodExitFunction(res, NULL); return res; } diff --git a/arangod/Utils/SingleCollectionTransaction.h b/arangod/Utils/SingleCollectionTransaction.h index 9547b3c104..6e633666f3 100644 --- a/arangod/Utils/SingleCollectionTransaction.h +++ b/arangod/Utils/SingleCollectionTransaction.h @@ -28,7 +28,7 @@ #ifndef TRIAGENS_UTILS_SINGLE_COLLECTION_TRANSACTION_H #define TRIAGENS_UTILS_SINGLE_COLLECTION_TRANSACTION_H 1 -#include "common.h" +#include "BasicsC/common.h" #include "VocBase/barrier.h" #include "VocBase/primary-collection.h" diff --git a/arangod/V8Server/v8-vocbase.cpp b/arangod/V8Server/v8-vocbase.cpp index 9310ae68b5..cbc6da20b0 100644 --- a/arangod/V8Server/v8-vocbase.cpp +++ b/arangod/V8Server/v8-vocbase.cpp @@ -1877,6 +1877,11 @@ static v8::Handle JS_compare_string (v8::Arguments const& argv) { v8::String::Value left(argv[0]); v8::String::Value right(argv[1]); + // .......................................................................... + // Take note here: we are assuming that the ICU type UChar is two bytes. + // There is no guarantee that this will be the case on all platforms and + // compilers. + // .......................................................................... int result = Utf8Helper::DefaultUtf8Helper.compareUtf16(*left, left.length(), *right, right.length()); return scope.Close(v8::Integer::New(result)); @@ -2841,7 +2846,7 @@ static v8::Handle JS_UpgradeVocbaseCol (v8::Arguments const& argv) { TRI_DestroyVectorPointer(&files); TRI_ReleaseCollection(collection); - close(fd); + TRI_CLOSE(fd); return scope.Close(v8::False()); } @@ -2851,7 +2856,7 @@ static v8::Handle JS_UpgradeVocbaseCol (v8::Arguments const& argv) { while (true) { // read marker header - ssize_t bytesRead = ::read(fd, &marker, sizeof(marker)); + ssize_t bytesRead = TRI_READ(fd, &marker, sizeof(marker)); if (bytesRead == 0) { // eof @@ -2880,16 +2885,15 @@ static v8::Handle JS_UpgradeVocbaseCol (v8::Arguments const& argv) { off_t paddedSize = TRI_DF_ALIGN_BLOCK(marker._size); - char payload[paddedSize]; - char* p = (char*) &payload; + char* payload = new char[paddedSize]; // copy header - memcpy(&payload, &marker, sizeof(marker)); + memcpy(payload, &marker, sizeof(marker)); if (marker._size > sizeof(marker)) { //int r = ::read(fd, p + sizeof(marker), marker._size - sizeof(marker)); - int r = ::read(fd, p + sizeof(marker), paddedSize - sizeof(marker)); + int r = TRI_READ(fd, payload + sizeof(marker), paddedSize - sizeof(marker)); if (r < (int) (paddedSize - sizeof(marker))) { LOG_WARNING("read less than paddedSize - sizeof(marker) = %d", r); break; @@ -2903,7 +2907,7 @@ static v8::Handle JS_UpgradeVocbaseCol (v8::Arguments const& argv) { switch (marker._type) { case TRI_DOC_MARKER_DOCUMENT: { - doc_document_marker_t_deprecated* oldMarker = (doc_document_marker_t_deprecated*) &payload; + doc_document_marker_t_deprecated* oldMarker = (doc_document_marker_t_deprecated*) payload; TRI_doc_document_key_marker_t newMarker; TRI_voc_size_t newMarkerSize = sizeof(TRI_doc_document_key_marker_t); @@ -2936,12 +2940,9 @@ static v8::Handle JS_UpgradeVocbaseCol (v8::Arguments const& argv) { newMarker.base._size = newMarkerSize + keyBodySize + bodySize; TRI_FillCrcKeyMarkerDatafile(df, &newMarker.base, newMarkerSize, keyBody, keyBodySize, body, bodySize); - writeResult = write(fdout, &newMarker, sizeof(newMarker)); - (void) writeResult; - writeResult = write(fdout, keyBody, keyBodySize); - (void) writeResult; - writeResult = write(fdout, body, bodySizePadded); - (void) writeResult; + writeResult = TRI_WRITE(fdout, &newMarker, sizeof(newMarker)); + writeResult = TRI_WRITE(fdout, keyBody, keyBodySize); + writeResult = TRI_WRITE(fdout, body, bodySizePadded); //LOG_INFO("found doc marker, type: '%d', did: '%d', rid: '%d', size: '%d', crc: '%d'", marker._type, oldMarker->_did, oldMarker->_rid,newMarker.base._size,newMarker.base._crc); @@ -2952,7 +2953,7 @@ static v8::Handle JS_UpgradeVocbaseCol (v8::Arguments const& argv) { } case TRI_DOC_MARKER_EDGE: { - doc_edge_marker_t_deprecated* oldMarker = (doc_edge_marker_t_deprecated*) &payload; + doc_edge_marker_t_deprecated* oldMarker = (doc_edge_marker_t_deprecated*) payload; TRI_doc_edge_key_marker_t newMarker; TRI_voc_size_t newMarkerSize = sizeof(TRI_doc_edge_key_marker_t); @@ -3004,11 +3005,11 @@ static v8::Handle JS_UpgradeVocbaseCol (v8::Arguments const& argv) { newMarker.base.base._tick = oldMarker->base.base._tick; TRI_FillCrcKeyMarkerDatafile(df, &newMarker.base.base, newMarkerSize, keyBody, keyBodySize, body, bodySize); - writeResult = write(fdout, &newMarker, newMarkerSize); + writeResult = TRI_WRITE(fdout, &newMarker, newMarkerSize); (void) writeResult; - writeResult = write(fdout, keyBody, keyBodySize); + writeResult = TRI_WRITE(fdout, keyBody, keyBodySize); (void) writeResult; - writeResult = write(fdout, body, bodySizePadded); + writeResult = TRI_WRITE(fdout, body, bodySizePadded); (void) writeResult; //LOG_INFO("found edge marker, type: '%d', did: '%d', rid: '%d', size: '%d', crc: '%d'", marker._type, oldMarker->base._did, oldMarker->base._rid,newMarker.base.base._size,newMarker.base.base._crc); @@ -3020,7 +3021,7 @@ static v8::Handle JS_UpgradeVocbaseCol (v8::Arguments const& argv) { } case TRI_DOC_MARKER_DELETION: { - doc_deletion_marker_t_deprecated* oldMarker = (doc_deletion_marker_t_deprecated*) &payload; + doc_deletion_marker_t_deprecated* oldMarker = (doc_deletion_marker_t_deprecated*) payload; TRI_doc_deletion_key_marker_t newMarker; TRI_voc_size_t newMarkerSize = sizeof(TRI_doc_deletion_key_marker_t); @@ -3046,9 +3047,9 @@ static v8::Handle JS_UpgradeVocbaseCol (v8::Arguments const& argv) { newMarker.base._tick = oldMarker->base._tick; TRI_FillCrcKeyMarkerDatafile(df, &newMarker.base, newMarkerSize, keyBody, keyBodySize, NULL, 0); - writeResult = write(fdout, &newMarker, newMarkerSize); + writeResult = TRI_WRITE(fdout, &newMarker, newMarkerSize); (void) writeResult; - writeResult = write(fdout, (char*) keyBody, keyBodySize); + writeResult = TRI_WRITE(fdout, (char*) keyBody, keyBodySize); (void) writeResult; //LOG_INFO("found deletion marker, type: '%d', did: '%d', rid: '%d'", marker._type, oldMarker->_did, oldMarker->_rid); @@ -3061,14 +3062,15 @@ static v8::Handle JS_UpgradeVocbaseCol (v8::Arguments const& argv) { default: { // copy other types without modification - writeResult = write(fdout, &payload, sizeof(payload)); + writeResult = TRI_WRITE(fdout, payload, paddedSize); (void) writeResult; - writtenSize += sizeof(payload); + writtenSize += paddedSize; //LOG_INFO("found marker, type: '%d'", marker._type); } } + delete [] payload; } else if (bytesRead == 0) { // eof @@ -3077,8 +3079,8 @@ static v8::Handle JS_UpgradeVocbaseCol (v8::Arguments const& argv) { else { LOG_ERROR("Could not read data from file '%s' while upgrading collection '%s'.", df->_filename, name); LOG_ERROR("Remove collection manually."); - close(fd); - close(fdout); + TRI_CLOSE(fd); + TRI_CLOSE(fdout); TRI_DestroyVectorPointer(&files); TRI_ReleaseCollection(collection); @@ -3094,20 +3096,20 @@ static v8::Handle JS_UpgradeVocbaseCol (v8::Arguments const& argv) { memset(b, 0, max); while (writtenSize + max < fileSize) { - writeResult = write(fdout, b, max); + writeResult = TRI_WRITE(fdout, b, max); (void) writeResult; writtenSize += max; } if (writtenSize < fileSize) { - writeResult = write(fdout, b, fileSize - writtenSize); + writeResult = TRI_WRITE(fdout, b, fileSize - writtenSize); (void) writeResult; } } // file converted! - close(fd); - close(fdout); + TRI_CLOSE(fd); + TRI_CLOSE(fdout); } diff --git a/arangod/VocBase/key-generator.h b/arangod/VocBase/key-generator.h index 543111809a..699d2abd5a 100644 --- a/arangod/VocBase/key-generator.h +++ b/arangod/VocBase/key-generator.h @@ -118,7 +118,7 @@ int TRI_CreateKeyGenerator (const struct TRI_json_s* const, /// @brief free a key generator //////////////////////////////////////////////////////////////////////////////// -void TRI_FreeKeyGenerator (TRI_key_generator_t* const); +void TRI_FreeKeyGenerator (TRI_key_generator_t*); //////////////////////////////////////////////////////////////////////////////// /// @brief check whether a key is allowed diff --git a/arangod/VocBase/transaction.h b/arangod/VocBase/transaction.h index bd0baa689a..f734ca6ac6 100644 --- a/arangod/VocBase/transaction.h +++ b/arangod/VocBase/transaction.h @@ -221,14 +221,15 @@ TRI_transaction_collection_global_t; /// @brief create the global transaction context //////////////////////////////////////////////////////////////////////////////// -TRI_transaction_context_t* TRI_CreateTransactionContext (struct TRI_vocbase_s*, +TRI_transaction_context_t* TRI_CreateTransactionContext (struct TRI_vocbase_s* const, TRI_transaction_server_id_t); + //////////////////////////////////////////////////////////////////////////////// /// @brief free the global transaction context //////////////////////////////////////////////////////////////////////////////// -void TRI_FreeTransactionContext (TRI_transaction_context_t*); +void TRI_FreeTransactionContext (TRI_transaction_context_t* const); //////////////////////////////////////////////////////////////////////////////// /// @} diff --git a/arangoirb/MRClient/arangoirb.cpp b/arangoirb/MRClient/arangoirb.cpp index 0642de21a4..656529828f 100644 --- a/arangoirb/MRClient/arangoirb.cpp +++ b/arangoirb/MRClient/arangoirb.cpp @@ -244,7 +244,7 @@ static void InitMRClientConnection (mrb_state* mrb, MRubyClientConnection* conne //////////////////////////////////////////////////////////////////////////////// static void RunShell (mrb_state* mrb) { - MRLineEditor console(mrb, ".arango-mrb"); + MRLineEditor console(mrb, ".arangoirb"); console.open(false /*! NoAutoComplete*/); diff --git a/arangosh/V8Client/arangoimp.cpp b/arangosh/V8Client/arangoimp.cpp index 001a231358..02b1b5bbd4 100755 --- a/arangosh/V8Client/arangoimp.cpp +++ b/arangosh/V8Client/arangoimp.cpp @@ -189,6 +189,76 @@ static void ParseProgramOptions (int argc, char* argv[]) { /// @{ //////////////////////////////////////////////////////////////////////////////// + +//////////////////////////////////////////////////////////////////////////////// +/// @brief startup and exit functions +//////////////////////////////////////////////////////////////////////////////// + +void* arangoimpResourcesAllocated = NULL; +static void arangoimpEntryFunction (); +static void arangoimpExitFunction (int, void*); + +#ifdef _WIN32 + +// ............................................................................. +// Call this function to do various initialistions for windows only +// ............................................................................. +void arangoimpEntryFunction() { + int maxOpenFiles = 1024; + int res = 0; + + // ........................................................................... + // Uncomment this to call this for extended debug information. + // If you familiar with valgrind ... then this is not like that, however + // you do get some similar functionality. + // ........................................................................... + //res = initialiseWindows(TRI_WIN_INITIAL_SET_DEBUG_FLAG, 0); + + res = initialiseWindows(TRI_WIN_INITIAL_SET_INVALID_HANLE_HANDLER, 0); + if (res != 0) { + _exit(1); + } + + res = initialiseWindows(TRI_WIN_INITIAL_SET_MAX_STD_IO,(const char*)(&maxOpenFiles)); + if (res != 0) { + _exit(1); + } + + res = initialiseWindows(TRI_WIN_INITIAL_WSASTARTUP_FUNCTION_CALL, 0); + if (res != 0) { + _exit(1); + } + + TRI_Application_Exit_SetExit(arangoimpExitFunction); + +} + +static void arangoimpExitFunction(int exitCode, void* data) { + int res = 0; + // ........................................................................... + // TODO: need a terminate function for windows to be called and cleanup + // any windows specific stuff. + // ........................................................................... + + res = finaliseWindows(TRI_WIN_FINAL_WSASTARTUP_FUNCTION_CALL, 0); + + if (res != 0) { + _exit(1); + } + + _exit(exitCode); +} +#else + +static void arangoimpEntryFunction() { +} + +static void arangoimpExitFunction(int exitCode, void* data) { +} + +#endif + + //////////////////////////////////////////////////////////////////////////////// /// @brief main //////////////////////////////////////////////////////////////////////////////// @@ -197,29 +267,7 @@ int main (int argc, char* argv[]) { int ret = EXIT_SUCCESS; -#ifdef _WIN32 - - // ........................................................................... - // Call this function to do various initialistions for windows only - // ........................................................................... - - // ........................................................................... - // Uncomment this to call this for extended debug information. - // If you familiar with valgrind ... then this is not like that, however - // you do get some similar functionality. - // ........................................................................... - //res = initialiseWindows(TRI_WIN_INITIAL_SET_DEBUG_FLAG, 0); - - ret = initialiseWindows(TRI_WIN_INITIAL_SET_INVALID_HANLE_HANDLER, 0); - if (ret != 0) { - _exit(1); - } - ret = initialiseWindows(TRI_WIN_INITIAL_WSASTARTUP_FUNCTION_CALL, 0); - if (ret != 0) { - _exit(1); - } - -#endif + arangoimpEntryFunction(); TRIAGENS_C_INITIALISE(argc, argv); TRIAGENS_REST_INITIALISE(argc, argv); @@ -242,7 +290,7 @@ int main (int argc, char* argv[]) { if (BaseClient.endpointServer() == 0) { cerr << "invalid value for --server.endpoint ('" << BaseClient.endpointString() << "')" << endl; - exit(EXIT_FAILURE); + TRI_EXIT_FUNCTION(EXIT_FAILURE,NULL); } ClientConnection = new V8ClientConnection(BaseClient.endpointServer(), @@ -256,8 +304,7 @@ int main (int argc, char* argv[]) { if (! ClientConnection->isConnected() || ClientConnection->getLastHttpReturnCode() != SimpleHttpResult::HTTP_STATUS_OK) { cerr << "Could not connect to endpoint " << BaseClient.endpointServer()->getSpecification() << endl; cerr << "Error message: '" << ClientConnection->getErrorMessage() << "'" << endl; - - return EXIT_FAILURE; + TRI_EXIT_FUNCTION(EXIT_FAILURE,NULL); } // successfully connected @@ -293,7 +340,7 @@ int main (int argc, char* argv[]) { } else { cerr << "Wrong length of quote character." << endl; - return EXIT_FAILURE; + TRI_EXIT_FUNCTION(EXIT_FAILURE,NULL); } // eol @@ -302,7 +349,7 @@ int main (int argc, char* argv[]) { } else { cerr << "Wrong length of eol character." << endl; - return EXIT_FAILURE; + TRI_EXIT_FUNCTION(EXIT_FAILURE,NULL); } // separator @@ -311,24 +358,24 @@ int main (int argc, char* argv[]) { } else { cerr << "Separator must be at least one character." << endl; - return EXIT_FAILURE; + TRI_EXIT_FUNCTION(EXIT_FAILURE,NULL); } // collection name if (CollectionName == "") { cerr << "collection name is missing." << endl; - return EXIT_FAILURE; + TRI_EXIT_FUNCTION(EXIT_FAILURE,NULL); } // filename if (FileName == "") { cerr << "file name is missing." << endl; - return EXIT_FAILURE; + TRI_EXIT_FUNCTION(EXIT_FAILURE,NULL); } if (FileName != "-" && !FileUtils::isRegularFile(FileName)) { cerr << "file '" << FileName << "' is not a regular file." << endl; - return EXIT_FAILURE; + TRI_EXIT_FUNCTION(EXIT_FAILURE,NULL); } // progress @@ -337,7 +384,7 @@ int main (int argc, char* argv[]) { } // import type - bool ok; + bool ok = false; if (TypeImport == "csv") { cout << "Starting CSV import..." << endl; @@ -358,7 +405,7 @@ int main (int argc, char* argv[]) { else { cerr << "Wrong type '" << TypeImport << "'." << endl; - return EXIT_FAILURE; + TRI_EXIT_FUNCTION(EXIT_FAILURE,NULL); } cout << endl; @@ -378,16 +425,7 @@ int main (int argc, char* argv[]) { TRIAGENS_REST_SHUTDOWN; -#ifdef _WIN32 - - // ........................................................................... - // TODO: need a terminate function for windows to be called and cleanup - // any windows specific stuff. - // ........................................................................... - - ret = finaliseWindows(TRI_WIN_FINAL_WSASTARTUP_FUNCTION_CALL, 0); - -#endif + arangoimpExitFunction(ret, NULL); return ret; } diff --git a/arangosh/V8Client/arangosh.cpp b/arangosh/V8Client/arangosh.cpp index bb80b56898..00d3292fd0 100755 --- a/arangosh/V8Client/arangosh.cpp +++ b/arangosh/V8Client/arangosh.cpp @@ -1,4 +1,4 @@ -/// @brief V8 shell +/// @brief V8 shell /// /// @file /// @@ -34,6 +34,7 @@ #include "3rdParty/valgrind/valgrind.h" #include "ArangoShell/ArangoClient.h" +#include "BasicsC/messages.h" #include "Basics/FileUtils.h" #include "Basics/ProgramOptions.h" #include "Basics/ProgramOptionsDescription.h" @@ -905,6 +906,15 @@ static void RunShell (v8::Handle context, bool promptError) { // using non-printable characters in the prompt will lead to wrong prompt lengths being calculated // we will therefore disable colorful prompts for MacOS. goodPrompt = badPrompt = string("arangosh> "); + +#elif _WIN32 + // ........................................................................................ + // Windows console is not coloured by escape sequences. So the method given below will not + // work. For now we simply ignore the colours until we move the windows version into + // a GUI Window. + // ........................................................................................ + goodPrompt = string("arangosh> "); + badPrompt = string("arangosh> "); #else if (BaseClient.colors()) { goodPrompt = string(ArangoClient::PROMPT_IGNORE_START) + string(TRI_SHELL_COLOR_BOLD_GREEN) + string(ArangoClient::PROMPT_IGNORE_END) + @@ -1118,6 +1128,76 @@ static bool RunJsLint (v8::Handle context) { /// @{ //////////////////////////////////////////////////////////////////////////////// + +//////////////////////////////////////////////////////////////////////////////// +/// @brief startup and exit functions +//////////////////////////////////////////////////////////////////////////////// + +void* arangoshResourcesAllocated = NULL; +static void arangoshEntryFunction (); +static void arangoshExitFunction (int, void*); + +#ifdef _WIN32 + +// ............................................................................. +// Call this function to do various initialistions for windows only +// ............................................................................. +void arangoshEntryFunction() { + int maxOpenFiles = 1024; + int res = 0; + + // ........................................................................... + // Uncomment this to call this for extended debug information. + // If you familiar with valgrind ... then this is not like that, however + // you do get some similar functionality. + // ........................................................................... + //res = initialiseWindows(TRI_WIN_INITIAL_SET_DEBUG_FLAG, 0); + + res = initialiseWindows(TRI_WIN_INITIAL_SET_INVALID_HANLE_HANDLER, 0); + if (res != 0) { + _exit(1); + } + + res = initialiseWindows(TRI_WIN_INITIAL_SET_MAX_STD_IO,(const char*)(&maxOpenFiles)); + if (res != 0) { + _exit(1); + } + + res = initialiseWindows(TRI_WIN_INITIAL_WSASTARTUP_FUNCTION_CALL, 0); + if (res != 0) { + _exit(1); + } + + TRI_Application_Exit_SetExit(arangoshExitFunction); + +} + +static void arangoshExitFunction(int exitCode, void* data) { + int res = 0; + // ........................................................................... + // TODO: need a terminate function for windows to be called and cleanup + // any windows specific stuff. + // ........................................................................... + + res = finaliseWindows(TRI_WIN_FINAL_WSASTARTUP_FUNCTION_CALL, 0); + + if (res != 0) { + _exit(1); + } + + _exit(exitCode); +} +#else + +static void arangoshEntryFunction() { +} + +static void arangoshExitFunction(int exitCode, void* data) { +} + +#endif + + //////////////////////////////////////////////////////////////////////////////// /// @brief main //////////////////////////////////////////////////////////////////////////////// @@ -1126,29 +1206,7 @@ int main (int argc, char* argv[]) { int ret = EXIT_SUCCESS; -#ifdef _WIN32 - - // ........................................................................... - // Call this function to do various initialistions for windows only - // ........................................................................... - - // ........................................................................... - // Uncomment this to call this for extended debug information. - // If you familiar with valgrind ... then this is not like that, however - // you do get some similar functionality. - // ........................................................................... - //res = initialiseWindows(TRI_WIN_INITIAL_SET_DEBUG_FLAG, 0); - - ret = initialiseWindows(TRI_WIN_INITIAL_SET_INVALID_HANLE_HANDLER, 0); - if (ret != 0) { - _exit(1); - } - ret = initialiseWindows(TRI_WIN_INITIAL_WSASTARTUP_FUNCTION_CALL, 0); - if (ret != 0) { - _exit(1); - } - -#endif + arangoshEntryFunction(); TRIAGENS_C_INITIALISE(argc, argv); TRIAGENS_REST_INITIALISE(argc, argv); @@ -1181,7 +1239,7 @@ int main (int argc, char* argv[]) { if (BaseClient.endpointServer() == 0) { cerr << "invalid value for --server.endpoint ('" << BaseClient.endpointString() << "')" << endl; - exit(EXIT_FAILURE); + TRI_EXIT_FUNCTION(EXIT_FAILURE,NULL); } @@ -1202,7 +1260,7 @@ int main (int argc, char* argv[]) { if (context.IsEmpty()) { cerr << "cannot initialize V8 engine" << endl; - exit(EXIT_FAILURE); + TRI_EXIT_FUNCTION(EXIT_FAILURE,NULL); } context->Enter(); @@ -1317,7 +1375,8 @@ int main (int argc, char* argv[]) { defaultColour = csbiInfo.wAttributes; } - SetConsoleOutputCP(65001); + // not sure about the code page + //SetConsoleOutputCP(65001); SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE), greenColour); printf(" "); SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE), redColour); @@ -1425,7 +1484,7 @@ int main (int argc, char* argv[]) { if (StartupPath.empty()) { LOGGER_FATAL << "no 'javascript.startup-directory' has been supplied, giving up"; TRI_FlushLogging(); - exit(EXIT_FAILURE); + TRI_EXIT_FUNCTION(EXIT_FAILURE,NULL); } LOGGER_DEBUG << "using JavaScript startup files at '" << StartupPath << "'"; @@ -1458,7 +1517,7 @@ int main (int argc, char* argv[]) { } else { LOGGER_ERROR << "cannot load JavaScript file '" << files[i] << "'"; - exit(EXIT_FAILURE); + TRI_EXIT_FUNCTION(EXIT_FAILURE,NULL); } } @@ -1516,16 +1575,7 @@ int main (int argc, char* argv[]) { TRIAGENS_REST_SHUTDOWN; -#ifdef _WIN32 - - // ........................................................................... - // TODO: need a terminate function for windows to be called and cleanup - // any windows specific stuff. - // ........................................................................... - - ret = finaliseWindows(TRI_WIN_FINAL_WSASTARTUP_FUNCTION_CALL, 0); - -#endif + arangoshExitFunction(ret, NULL); return ret; } diff --git a/js/common/bootstrap/errors.js b/js/common/bootstrap/errors.js index 50f41a28a5..82aa5492c3 100644 --- a/js/common/bootstrap/errors.js +++ b/js/common/bootstrap/errors.js @@ -111,6 +111,10 @@ "ERROR_TRANSACTION_NESTED" : { "code" : 1652, "message" : "nested transactions detected" }, "ERROR_TRANSACTION_INTERNAL" : { "code" : 1653, "message" : "internal transaction error" }, "ERROR_TRANSACTION_UNREGISTERED_COLLECTION" : { "code" : 1654, "message" : "unregistered collection used in transaction" }, + "ERROR_USER_INVALID_NAME" : { "code" : 1700, "message" : "invalid user name" }, + "ERROR_USER_INVALID_PASSWORD" : { "code" : 1701, "message" : "invalid password" }, + "ERROR_USER_DUPLICATE" : { "code" : 1702, "message" : "duplicate user" }, + "ERROR_USER_NOT_FOUND" : { "code" : 1703, "message" : "user not found" }, "ERROR_KEYVALUE_INVALID_KEY" : { "code" : 1800, "message" : "invalid key declaration" }, "ERROR_KEYVALUE_KEY_EXISTS" : { "code" : 1801, "message" : "key already exists" }, "ERROR_KEYVALUE_KEY_NOT_FOUND" : { "code" : 1802, "message" : "key not found" }, diff --git a/js/common/modules/org/arangodb/graph/traversal.js b/js/common/modules/org/arangodb/graph/traversal.js index 82006f6885..eddd303404 100644 --- a/js/common/modules/org/arangodb/graph/traversal.js +++ b/js/common/modules/org/arangodb/graph/traversal.js @@ -775,6 +775,7 @@ function depthFirstSearch () { if (config.uniqueness.vertices === ArangoTraverser.UNIQUE_PATH) { visited.vertices = this.getPathItems(config.datasource.getVertexId, path.vertices); } + if (config.uniqueness.edges === ArangoTraverser.UNIQUE_PATH) { visited.edges = this.getPathItems(config.datasource.getEdgeId, path.edges); } @@ -789,6 +790,7 @@ function depthFirstSearch () { if (edge !== null) { path.edges.push(edge); } + path.vertices.push(vertex); var filterResult = parseFilterResult(config.filter(config, vertex, path)); diff --git a/js/common/modules/org/arangodb/users.js b/js/common/modules/org/arangodb/users.js index 391d138a53..5fc346f70a 100644 --- a/js/common/modules/org/arangodb/users.js +++ b/js/common/modules/org/arangodb/users.js @@ -32,10 +32,9 @@ var internal = require("internal"); // OK: encodePassword, reloadAuth var encodePassword = internal.encodePassword; var reloadAuth = internal.reloadAuth; - var arangodb = require("org/arangodb"); - var db = arangodb.db; +var ArangoError = require("org/arangodb/arango-error").ArangoError; // ----------------------------------------------------------------------------- // --SECTION-- module "org/arangodb/users" @@ -55,8 +54,12 @@ var db = arangodb.db; //////////////////////////////////////////////////////////////////////////////// var validateName = function (username) { - if (typeof username !== 'string' || ! username.match(/^[a-zA-Z0-9\-_]+$/)) { - throw "username must be a string"; + if (typeof username !== 'string' || username === '') { + var err = new ArangoError(); + err.errorNum = arangodb.errors.ERROR_USER_INVALID_NAME.code; + err.errorMessage = arangodb.errors.ERROR_USER_INVALID_NAME.message; + + throw err; } }; @@ -66,7 +69,11 @@ var validateName = function (username) { var validatePassword = function (passwd) { if (typeof passwd !== 'string') { - throw "password must be a string"; + var err = new ArangoError(); + err.errorNum = arangodb.errors.ERROR_USER_INVALID_PASSWORD.code; + err.errorMessage = arangodb.errors.ERROR_USER_INVALID_PASSWORD.message; + + throw err; } }; @@ -78,7 +85,11 @@ var getStorage = function () { var users = db._collection("_users"); if (users === null) { - throw "collection _users does not exist."; + var err = new ArangoError(); + err.errorNum = arangodb.errors.ERROR_ARANGO_COLLECTION_NOT_FOUND.code; + err.errorMessage = "collection _users not found"; + + throw err; } return users; @@ -124,6 +135,10 @@ var getStorage = function () { //////////////////////////////////////////////////////////////////////////////// exports.save = function (username, passwd) { + if (passwd === null || passwd === undefined) { + passwd = ""; + } + // validate input validateName(username); validatePassword(passwd); @@ -135,8 +150,12 @@ exports.save = function (username, passwd) { var hash = encodePassword(passwd); return users.save({ user: username, password: hash, active: true }); } + + var err = new ArangoError(); + err.errorNum = arangodb.errors.ERROR_USER_DUPLICATE.code; + err.errorMessage = arangodb.errors.ERROR_USER_DUPLICATE.message; - throw "cannot create user: user already exists."; + throw err; }; //////////////////////////////////////////////////////////////////////////////// @@ -169,6 +188,10 @@ exports.save = function (username, passwd) { exports.replace = exports.update = function (username, passwd) { + if (passwd === null || passwd === undefined) { + passwd = ""; + } + // validate input validateName(username); validatePassword(passwd); @@ -177,7 +200,11 @@ exports.update = function (username, passwd) { var user = users.firstExample({ user: username }); if (user === null) { - throw "cannot update user: user does not exist."; + var err = new ArangoError(); + err.errorNum = arangodb.errors.ERROR_USER_NOT_FOUND.code; + err.errorMessage = arangodb.errors.ERROR_USER_NOT_FOUND.message; + + throw err; } var hash = encodePassword(passwd); @@ -217,7 +244,11 @@ exports.remove = function (username) { var user = users.firstExample({ user: username }); if (user === null) { - throw "cannot delete: user does not exist."; + var err = new ArangoError(); + err.errorNum = arangodb.errors.ERROR_USER_NOT_FOUND.code; + err.errorMessage = arangodb.errors.ERROR_USER_NOT_FOUND.message; + + throw err; } return users.remove(user._id); diff --git a/js/common/tests/shell-users.js b/js/common/tests/shell-users.js index f0fa2c99f0..0fa49566c8 100644 --- a/js/common/tests/shell-users.js +++ b/js/common/tests/shell-users.js @@ -53,9 +53,15 @@ function UsersSuite () { try { users.remove(username); } - catch (err) { + catch (e1) { } } + + try { + users.remove("hackers@arangodb.org"); + } + catch (e2) { + } }; return { @@ -81,7 +87,7 @@ function UsersSuite () { //////////////////////////////////////////////////////////////////////////////// testInvalidNames : function () { - var usernames = [ " ", "", "******", "#", "'", "\"", "d d", "d " ]; + var usernames = [ null, 1, 2, 3, [ ], { }, false, true, "" ]; for (var i = 0; i < usernames.length; ++i) { var username = usernames[i]; @@ -92,6 +98,7 @@ function UsersSuite () { fail(); } catch (err) { + assertEqual(ERRORS.ERROR_USER_INVALID_NAME.code, err.errorNum); } } }, @@ -126,9 +133,45 @@ function UsersSuite () { fail(); } catch (err) { + assertEqual(ERRORS.ERROR_USER_DUPLICATE.code, err.errorNum); } }, +//////////////////////////////////////////////////////////////////////////////// +/// @brief test save no passwd +//////////////////////////////////////////////////////////////////////////////// + + testSavePasswdEmpty : function () { + var username = "users-1"; + var passwd = ""; + + users.save(username, passwd); + assertEqual(username, c.firstExample({ user: username }).user); + }, + +//////////////////////////////////////////////////////////////////////////////// +/// @brief test save no passwd +//////////////////////////////////////////////////////////////////////////////// + + testSavePasswdMissing : function () { + var username = "users-1"; + + users.save(username); + assertEqual(username, c.firstExample({ user: username }).user); + }, + +//////////////////////////////////////////////////////////////////////////////// +/// @brief test save w/ email address pattern +//////////////////////////////////////////////////////////////////////////////// + + testSaveWithEmailAddressName : function () { + var username = "hackers@arangodb.org"; + var passwd = "arangodb-loves-you"; + + users.save(username, passwd); + assertEqual(username, c.firstExample({ user: username }).user); + }, + //////////////////////////////////////////////////////////////////////////////// /// @brief test update method //////////////////////////////////////////////////////////////////////////////// @@ -156,6 +199,7 @@ function UsersSuite () { fail(); } catch (err) { + assertEqual(ERRORS.ERROR_USER_NOT_FOUND.code, err.errorNum); } }, @@ -184,6 +228,7 @@ function UsersSuite () { fail(); } catch (err) { + assertEqual(ERRORS.ERROR_USER_NOT_FOUND.code, err.errorNum); } }, diff --git a/lib/Basics/Utf8Helper.cpp b/lib/Basics/Utf8Helper.cpp index 3f6e370984..ecb0f2bf50 100644 --- a/lib/Basics/Utf8Helper.cpp +++ b/lib/Basics/Utf8Helper.cpp @@ -101,7 +101,11 @@ int Utf8Helper::compareUtf16 (const uint16_t* left, size_t leftLength, const uin return result; } - + // .......................................................................... + // Take note here: we are assuming that the ICU type UChar is two bytes. + // There is no guarantee that this will be the case on all platforms and + // compilers. + // .......................................................................... return _coll->compare((const UChar *)left, leftLength, (const UChar *)right, rightLength); } diff --git a/lib/BasicsC/application-exit.c b/lib/BasicsC/application-exit.c new file mode 100644 index 0000000000..96a79ef48c --- /dev/null +++ b/lib/BasicsC/application-exit.c @@ -0,0 +1,64 @@ +//////////////////////////////////////////////////////////////////////////////// +/// @brief High-Performance Database Framework made by triagens +/// +/// @file +/// +/// DISCLAIMER +/// +/// Copyright 2004-2013 triagens GmbH, Cologne, Germany +/// +/// Licensed under the Apache License, Version 2.0 (the "License"); +/// you may not use this file except in compliance with the License. +/// You may obtain a copy of the License at +/// +/// http://www.apache.org/licenses/LICENSE-2.0 +/// +/// Unless required by applicable law or agreed to in writing, software +/// distributed under the License is distributed on an "AS IS" BASIS, +/// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +/// See the License for the specific language governing permissions and +/// limitations under the License. +/// +/// Copyright holder is triAGENS GmbH, Cologne, Germany +/// +/// @author Dr. O +/// @author Copyright 2009-2013, triAGENS GmbH, Cologne, Germany +//////////////////////////////////////////////////////////////////////////////// + +#include "BasicsC/common.h" + +// ----------------------------------------------------------------------------- +// --SECTION-- public functions +// ----------------------------------------------------------------------------- + +//////////////////////////////////////////////////////////////////////////////// +/// @addtogroup Application Exit +/// @{ +//////////////////////////////////////////////////////////////////////////////// + +static void defaultExitFunction(int, void*); + +TRI_ExitFunction_t TRI_EXIT_FUNCTION = defaultExitFunction; + + +void defaultExitFunction (int exitCode, void* data) { + _exit(exitCode); +} + +void TRI_Application_Exit_SetExit(TRI_ExitFunction_t exitFunction) { + if (exitFunction != NULL) { + TRI_EXIT_FUNCTION = exitFunction; + } + else { + TRI_EXIT_FUNCTION = defaultExitFunction; + } +} + +//////////////////////////////////////////////////////////////////////////////// +/// @} +//////////////////////////////////////////////////////////////////////////////// + +// Local Variables: +// mode: outline-minor +// outline-regexp: "^\\(/// @brief\\|/// {@inheritDoc}\\|/// @addtogroup\\|// --SECTION--\\|/// @\\}\\)" +// End: diff --git a/lib/BasicsC/application-exit.h b/lib/BasicsC/application-exit.h new file mode 100644 index 0000000000..710057814e --- /dev/null +++ b/lib/BasicsC/application-exit.h @@ -0,0 +1,68 @@ +//////////////////////////////////////////////////////////////////////////////// +/// @brief High-Performance Database Framework made by triagens +/// +/// @file +/// +/// DISCLAIMER +/// +/// Copyright 2004-2013 triagens GmbH, Cologne, Germany +/// +/// Licensed under the Apache License, Version 2.0 (the "License"); +/// you may not use this file except in compliance with the License. +/// You may obtain a copy of the License at +/// +/// http://www.apache.org/licenses/LICENSE-2.0 +/// +/// Unless required by applicable law or agreed to in writing, software +/// distributed under the License is distributed on an "AS IS" BASIS, +/// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +/// See the License for the specific language governing permissions and +/// limitations under the License. +/// +/// Copyright holder is triAGENS GmbH, Cologne, Germany +/// +/// @author Dr. O +/// @author Copyright 2011-2012, triAGENS GmbH, Cologne, Germany +//////////////////////////////////////////////////////////////////////////////// + +#ifndef TRIAGENS_BASICSC_APPLICATION_EXIT_H +#define TRIAGENS_BASICSC_APPLICATION_EXIT_H 1 + +#ifndef TRI_WITHIN_COMMON +#error use +#endif + +#ifdef __cplusplus +extern "C" { +#endif + +// ----------------------------------------------------------------------------- +// --SECTION-- Special Application Exit +// ----------------------------------------------------------------------------- + +//////////////////////////////////////////////////////////////////////////////// +/// @addtogroup Application Exit +/// @{ +//////////////////////////////////////////////////////////////////////////////// + +typedef void (*TRI_ExitFunction_t) (int, void*); + +extern TRI_ExitFunction_t TRI_EXIT_FUNCTION; + +void TRI_Application_Exit_SetExit (TRI_ExitFunction_t); + +//////////////////////////////////////////////////////////////////////////////// +/// @} +//////////////////////////////////////////////////////////////////////////////// + +#ifdef __cplusplus +} +#endif + + +#endif + +// Local Variables: +// mode: outline-minor +// outline-regexp: "^\\(/// @brief\\|/// {@inheritDoc}\\|/// @addtogroup\\|// --SECTION--\\|/// @\\}\\)" +// End: diff --git a/lib/BasicsC/common.h b/lib/BasicsC/common.h index e011421b2c..dfcc116f14 100644 --- a/lib/BasicsC/common.h +++ b/lib/BasicsC/common.h @@ -40,6 +40,7 @@ #define TRI_WITHIN_COMMON 1 #include "BasicsC/operating-system.h" #include "BasicsC/local-configuration.h" +#include "BasicsC/application-exit.h" #undef TRI_WITHIN_COMMON //////////////////////////////////////////////////////////////////////////////// diff --git a/lib/BasicsC/errors.dat b/lib/BasicsC/errors.dat index 1ca1908b34..a27491d2a7 100755 --- a/lib/BasicsC/errors.dat +++ b/lib/BasicsC/errors.dat @@ -152,6 +152,15 @@ ERROR_TRANSACTION_NESTED,1652,"nested transactions detected","Will be raised whe ERROR_TRANSACTION_INTERNAL,1653,"internal transaction error","Will be raised when a wrong usage of transactions is detected. this is an internal error and indicates a bug in ArangoDB." ERROR_TRANSACTION_UNREGISTERED_COLLECTION,1654,"unregistered collection used in transaction","Will be raised when a collection is used in the middle of a transaction but was not registered at transaction start." +################################################################################ +## User management +################################################################################ + +ERROR_USER_INVALID_NAME,1700,"invalid user name","Will be raised when an invalid user name is used" +ERROR_USER_INVALID_PASSWORD,1701,"invalid password","Will be raised when an invalid password is used" +ERROR_USER_DUPLICATE,1702,"duplicate user","Will be raised when a user name already exists" +ERROR_USER_NOT_FOUND,1703,"user not found","Will be raised when a user name is updated that does not exist" + ################################################################################ ## Key value access ################################################################################ diff --git a/lib/BasicsC/files.c b/lib/BasicsC/files.c index e52dc229be..3e10ee25a0 100755 --- a/lib/BasicsC/files.c +++ b/lib/BasicsC/files.c @@ -277,7 +277,13 @@ int64_t TRI_SizeFile (char const* path) { #ifdef _WIN32 bool TRI_IsWritable (char const* path) { -#error "TRI_IsWritable needs to be implemented for Windows" + // .......................................................................... + // will attempt the following: + // if path is a directory, then attempt to create temporary file + // if path is a file, then attempt to open it in read/write mode + // .......................................................................... + +// #error "TRI_IsWritable needs to be implemented for Windows" // implementation for seems to be non-trivial return true; } diff --git a/lib/BasicsC/locks-win32.c b/lib/BasicsC/locks-win32.c index 0d065a8be4..e0b249d279 100644 --- a/lib/BasicsC/locks-win32.c +++ b/lib/BasicsC/locks-win32.c @@ -420,11 +420,61 @@ void TRI_ReadUnlockReadWriteLock (TRI_read_write_lock_t* lock) { //////////////////////////////////////////////////////////////////////////////// /// @brief tries to write lock a read-write lock -/// TODO: not yet implemented //////////////////////////////////////////////////////////////////////////////// bool TRI_TryWriteLockReadWriteLock (TRI_read_write_lock_t* lock) { -#error implement me! + + BOOL result; + // ........................................................................... + // Here we use TryEnterCriticalSection instead of EnterCriticalSection + // There could already be a write lock - which will actuall block from this + // point on. + // ........................................................................... + + result = TryEnterCriticalSection(&lock->_lockWriter); + + if (result == 0) { + // appears some other writer is writing + return false; + } + + + // ........................................................................... + // Wait until the lock->_writerEvent is in a 'signalled' state + // This might fail because a reader is just about to read + // ........................................................................... + + if (WaitForSingleObject(lock->_writerEvent, 0) != WAIT_OBJECT_0) { + LeaveCriticalSection(&lock->_lockWriter); + return false; + } + + // ........................................................................... + // Set _writeEvent as nonsignalled -- this will block other read/write + // lockers + // ........................................................................... + + ResetEvent(lock->_writerEvent); + + + // ........................................................................... + // If there are ANY read locks outstanding, leave + // ........................................................................... + + if (WaitForSingleObject(lock->_readersEvent, 0) != WAIT_OBJECT_0) { + LeaveCriticalSection(&lock->_lockWriter); + SetEvent(lock->_writerEvent); + return false; + } + + + // ........................................................................... + // Allow other threads to access this function + // ........................................................................... + + LeaveCriticalSection(&lock->_lockWriter); + + return true; } //////////////////////////////////////////////////////////////////////////////// diff --git a/lib/BasicsC/memory-map-win32.c b/lib/BasicsC/memory-map-win32.c index 4ec16894dd..24ec7ade60 100644 --- a/lib/BasicsC/memory-map-win32.c +++ b/lib/BasicsC/memory-map-win32.c @@ -112,12 +112,24 @@ int TRI_MMFile(void* memoryAddress, size_t numOfBytesToInitialise, int memoryPro // ........................................................................... // Whenever we talk to the memory map functions, we require a file handle - // rather than a file descriptor. However, we only store file descriptors for - // now - this may change. + // rather than a file descriptor. // ........................................................................... - if (fileDescriptor < 0) { // an invalid file descriptor of course means an invalid handle + + + if (fileDescriptor < 0) { + // ......................................................................... + // An invalid file descriptor of course means an invalid handle. + // Having an invalid handle could mean (i) an error, or more likely, + // (ii) a request for an anonymous memory mapped file. Determine this below + // ......................................................................... fileHandle = INVALID_HANDLE_VALUE; + if ((flags & MAP_ANONYMOUS) != MAP_ANONYMOUS) { + LOG_DEBUG("File descriptor is invalid however memory map flag is not anonymous"); + LOG_TRACE("File descriptor is invalid however memory map flag is not anonymous"); + return TRI_ERROR_SYS_ERROR; + } + } else { @@ -204,9 +216,8 @@ int TRI_MMFile(void* memoryAddress, size_t numOfBytesToInitialise, int memoryPro // TODO: determine the correct memory protection and then uncomment // ........................................................................... // *mmHandle = CreateFileMapping(fileHandle, NULL, objectProtection, mmLength.HighPart, mmLength.LowPart, NULL); - - *mmHandle = CreateFileMapping(fileHandle, NULL, PAGE_READWRITE, mmLength.HighPart, mmLength.LowPart, NULL); + *mmHandle = CreateFileMapping(fileHandle, NULL, PAGE_READWRITE, mmLength.HighPart, mmLength.LowPart, NULL); // ........................................................................... // If we have failed for some reason return system error for now. diff --git a/lib/BasicsC/memory-map-win32.h b/lib/BasicsC/memory-map-win32.h index d9fa47114d..6e4b59327d 100644 --- a/lib/BasicsC/memory-map-win32.h +++ b/lib/BasicsC/memory-map-win32.h @@ -41,7 +41,6 @@ /// anonymous memory mapping may or may not work on Windows //////////////////////////////////////////////////////////////////////////////// -#undef TRI_MMAP_ANONYMOUS //////////////////////////////////////////////////////////////////////////////// // Flags used when we create a memory map -- dummy flags for windows for now @@ -53,6 +52,7 @@ #define MAP_FIXED 0x10 /* Interpret addr exactly */ #define MAP_ANONYMOUS 0x20 /* don't use a file */ +#define TRI_MMAP_ANONYMOUS MAP_ANONYMOUS //////////////////////////////////////////////////////////////////////////////// // Define some dummy flags which are ignored under windows. diff --git a/lib/BasicsC/operating-system.h b/lib/BasicsC/operating-system.h index 7a23517574..cde58221cd 100755 --- a/lib/BasicsC/operating-system.h +++ b/lib/BasicsC/operating-system.h @@ -442,7 +442,7 @@ typedef int socket_t; #define TRI_ALIGNOF_VOIDP 4 #endif -#undef TRI_HAVE_ANONYMOUS_MMAP +#define TRI_HAVE_ANONYMOUS_MMAP 1 #define strcasecmp _stricmp #define strncasecmp _strnicmp @@ -541,6 +541,7 @@ typedef SOCKET socket_t; #define STDOUT_FILENO 1; #define STDERR_FILENO 2; + #endif //////////////////////////////////////////////////////////////////////////////// diff --git a/lib/BasicsC/timer.h b/lib/BasicsC/timer.h deleted file mode 100644 index 7ccadced7c..0000000000 --- a/lib/BasicsC/timer.h +++ /dev/null @@ -1,91 +0,0 @@ -//////////////////////////////////////////////////////////////////////////////// -/// @brief timing helper macros -/// -/// @file -/// -/// DISCLAIMER -/// -/// Copyright 2004-2012 triagens GmbH, Cologne, Germany -/// -/// Licensed under the Apache License, Version 2.0 (the "License"); -/// you may not use this file except in compliance with the License. -/// You may obtain a copy of the License at -/// -/// http://www.apache.org/licenses/LICENSE-2.0 -/// -/// Unless required by applicable law or agreed to in writing, software -/// distributed under the License is distributed on an "AS IS" BASIS, -/// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -/// See the License for the specific language governing permissions and -/// limitations under the License. -/// -/// Copyright holder is triAGENS GmbH, Cologne, Germany -/// -/// @author Jan Steemann -/// @author Copyright 2009-2012, triAGENS GmbH, Cologne, Germany -//////////////////////////////////////////////////////////////////////////////// - -#ifndef TRIAGENS_BASICS_C_TIMER_H -#define TRIAGENS_BASICS_C_TIMER_H 1 - -// ----------------------------------------------------------------------------- -// --SECTION-- public macros -// ----------------------------------------------------------------------------- - -//////////////////////////////////////////////////////////////////////////////// -/// @addtogroup timing -/// @{ -//////////////////////////////////////////////////////////////////////////////// - -//////////////////////////////////////////////////////////////////////////////// -/// @brief stringify the timer name -//////////////////////////////////////////////////////////////////////////////// - -#define TRI_TIMER_NAME(name) timer ## name - -//////////////////////////////////////////////////////////////////////////////// -/// @brief declare a timer -//////////////////////////////////////////////////////////////////////////////// - -#define TRI_TIMER_DECLARE(name) double TRI_TIMER_NAME(name) = 0.0 - -//////////////////////////////////////////////////////////////////////////////// -/// @brief initialise a timer -//////////////////////////////////////////////////////////////////////////////// - -#define TRI_TIMER_INIT(name) TRI_TIMER_NAME(name) = TRI_microtime() - -//////////////////////////////////////////////////////////////////////////////// -/// @brief get the current value of a timer -//////////////////////////////////////////////////////////////////////////////// - -#define TRI_TIMER_CURRENT(name) (TRI_microtime() - TRI_TIMER_NAME(name)) - -//////////////////////////////////////////////////////////////////////////////// -/// @brief stop a timer -//////////////////////////////////////////////////////////////////////////////// - -#define TRI_TIMER_STOP(name) TRI_TIMER_NAME(name) = TRI_TIMER_CURRENT(name) - -//////////////////////////////////////////////////////////////////////////////// -/// @brief dump a timer to stdout -//////////////////////////////////////////////////////////////////////////////// - -#define TRI_TIMER_DUMP(name) fprintf(stdout, "timer %s: %f\n", #name, TRI_TIMER_NAME(name)); - -//////////////////////////////////////////////////////////////////////////////// -/// @brief log a timer value to the log in debug mode -//////////////////////////////////////////////////////////////////////////////// - -#define TRI_TIMER_LOG(name) LOG_DEBUG("timer %s: %f", #name, TRI_TIMER_NAME(name)); - -//////////////////////////////////////////////////////////////////////////////// -/// @} -//////////////////////////////////////////////////////////////////////////////// - -#endif - -// Local Variables: -// mode: outline-minor -// outline-regexp: "^\\(/// @brief\\|/// {@inheritDoc}\\|/// @addtogroup\\|// --SECTION--\\|/// @\\}\\)" -// End: diff --git a/lib/BasicsC/utf8-helper.h b/lib/BasicsC/utf8-helper.h index 831790be49..ebadc00ca4 100644 --- a/lib/BasicsC/utf8-helper.h +++ b/lib/BasicsC/utf8-helper.h @@ -79,7 +79,7 @@ char* TRI_normalize_utf8_to_NFC (TRI_memory_zone_t* zone, char * TRI_normalize_utf16_to_NFC (TRI_memory_zone_t* zone, const uint16_t* utf16, - size_t inLength, + const size_t inLength, size_t* outLength); //////////////////////////////////////////////////////////////////////////////// diff --git a/lib/BasicsC/vector.c b/lib/BasicsC/vector.c index 32e93324e5..a6b43615da 100755 --- a/lib/BasicsC/vector.c +++ b/lib/BasicsC/vector.c @@ -62,7 +62,7 @@ //////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////// -/// @brief initialises a vector +/// @brief initialises a vector //////////////////////////////////////////////////////////////////////////////// void TRI_InitVector (TRI_vector_t* vector, TRI_memory_zone_t* zone, size_t elementSize) { diff --git a/lib/BasicsC/voc-errors.c b/lib/BasicsC/voc-errors.c index 19c6d4abc7..4fdda30535 100644 --- a/lib/BasicsC/voc-errors.c +++ b/lib/BasicsC/voc-errors.c @@ -107,6 +107,10 @@ void TRI_InitialiseErrorMessages (void) { REG_ERROR(ERROR_TRANSACTION_NESTED, "nested transactions detected"); REG_ERROR(ERROR_TRANSACTION_INTERNAL, "internal transaction error"); REG_ERROR(ERROR_TRANSACTION_UNREGISTERED_COLLECTION, "unregistered collection used in transaction"); + REG_ERROR(ERROR_USER_INVALID_NAME, "invalid user name"); + REG_ERROR(ERROR_USER_INVALID_PASSWORD, "invalid password"); + REG_ERROR(ERROR_USER_DUPLICATE, "duplicate user"); + REG_ERROR(ERROR_USER_NOT_FOUND, "user not found"); REG_ERROR(ERROR_KEYVALUE_INVALID_KEY, "invalid key declaration"); REG_ERROR(ERROR_KEYVALUE_KEY_EXISTS, "key already exists"); REG_ERROR(ERROR_KEYVALUE_KEY_NOT_FOUND, "key not found"); diff --git a/lib/BasicsC/voc-errors.h b/lib/BasicsC/voc-errors.h index 38635e5ca8..81a50a33cd 100644 --- a/lib/BasicsC/voc-errors.h +++ b/lib/BasicsC/voc-errors.h @@ -237,6 +237,14 @@ extern "C" { /// - 1654: @LIT{unregistered collection used in transaction} /// Will be raised when a collection is used in the middle of a transaction /// but was not registered at transaction start. +/// - 1700: @LIT{invalid user name} +/// Will be raised when an invalid user name is used +/// - 1701: @LIT{invalid password} +/// Will be raised when an invalid password is used +/// - 1702: @LIT{duplicate user} +/// Will be raised when a user name already exists +/// - 1703: @LIT{user not found} +/// Will be raised when a user name is updated that does not exist /// - 1800: @LIT{invalid key declaration} /// Will be raised when an invalid key specification is passed to the server /// - 1801: @LIT{key already exists} @@ -1342,6 +1350,46 @@ void TRI_InitialiseErrorMessages (void); #define TRI_ERROR_TRANSACTION_UNREGISTERED_COLLECTION (1654) +//////////////////////////////////////////////////////////////////////////////// +/// @brief 1700: ERROR_USER_INVALID_NAME +/// +/// invalid user name +/// +/// Will be raised when an invalid user name is used +//////////////////////////////////////////////////////////////////////////////// + +#define TRI_ERROR_USER_INVALID_NAME (1700) + +//////////////////////////////////////////////////////////////////////////////// +/// @brief 1701: ERROR_USER_INVALID_PASSWORD +/// +/// invalid password +/// +/// Will be raised when an invalid password is used +//////////////////////////////////////////////////////////////////////////////// + +#define TRI_ERROR_USER_INVALID_PASSWORD (1701) + +//////////////////////////////////////////////////////////////////////////////// +/// @brief 1702: ERROR_USER_DUPLICATE +/// +/// duplicate user +/// +/// Will be raised when a user name already exists +//////////////////////////////////////////////////////////////////////////////// + +#define TRI_ERROR_USER_DUPLICATE (1702) + +//////////////////////////////////////////////////////////////////////////////// +/// @brief 1703: ERROR_USER_NOT_FOUND +/// +/// user not found +/// +/// Will be raised when a user name is updated that does not exist +//////////////////////////////////////////////////////////////////////////////// + +#define TRI_ERROR_USER_NOT_FOUND (1703) + //////////////////////////////////////////////////////////////////////////////// /// @brief 1800: ERROR_KEYVALUE_INVALID_KEY /// diff --git a/lib/BasicsC/win-utils.c b/lib/BasicsC/win-utils.c index c6b4e4c1b8..8a47ef4acc 100755 --- a/lib/BasicsC/win-utils.c +++ b/lib/BasicsC/win-utils.c @@ -159,7 +159,7 @@ static void InvalidParameterHandler(const wchar_t* expression, // expression sen else { wprintf(L"win-utils.c:InvalidParameterHandler:FILE = NULL\n"); } - printf("oreste:%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%:win-utils.c:InvalidParameterHandler:LINE = %ud\n",line); + printf("oreste:win-utils.c:InvalidParameterHandler:LINE = %ud\n",line); /* end oreste -debug */ //abort(); // TODO: use the wcstombs_s function to convert wchar to char - since all the above @@ -234,6 +234,15 @@ int initialiseWindows(const TRI_win_initialise_e initialiseWhat, const char* dat return 0; } + case TRI_WIN_INITIAL_SET_MAX_STD_IO: { + int* newMax = (int*)(data); + int result = _setmaxstdio(*newMax); + if (result != *newMax) { + return -1; + } + return 0; + } + case TRI_WIN_INITIAL_WSASTARTUP_FUNCTION_CALL: { int errorCode; WSADATA wsaData; @@ -273,7 +282,6 @@ int TRI_createFile (const char* filename, int openFlags, int modeFlags) { HANDLE fileHandle; int fileDescriptor; - fileHandle = CreateFileA(filename, GENERIC_READ | GENERIC_WRITE, FILE_SHARE_DELETE | FILE_SHARE_READ | FILE_SHARE_WRITE, @@ -282,6 +290,7 @@ int TRI_createFile (const char* filename, int openFlags, int modeFlags) { 0, NULL); + if (fileHandle == INVALID_HANDLE_VALUE) { return -1; } diff --git a/lib/BasicsC/win-utils.h b/lib/BasicsC/win-utils.h index d7010ae185..eff77cbe48 100755 --- a/lib/BasicsC/win-utils.h +++ b/lib/BasicsC/win-utils.h @@ -69,6 +69,7 @@ TRI_win_finalise_e; typedef enum { TRI_WIN_INITIAL_SET_DEBUG_FLAG, TRI_WIN_INITIAL_SET_INVALID_HANLE_HANDLER, + TRI_WIN_INITIAL_SET_MAX_STD_IO, TRI_WIN_INITIAL_WSASTARTUP_FUNCTION_CALL } TRI_win_initialise_e; diff --git a/lib/Makefile.files b/lib/Makefile.files index 6bfe029b95..3f8d69a401 100644 --- a/lib/Makefile.files +++ b/lib/Makefile.files @@ -30,6 +30,7 @@ lib_libarango_a_SOURCES = \ lib/Basics/WriteLocker.cpp \ lib/Basics/WriteUnlocker.cpp \ lib/Basics/ssl-helper.cpp \ + lib/BasicsC/application-exit.c \ lib/BasicsC/associative-multi.c \ lib/BasicsC/associative.c \ lib/BasicsC/conversions.c \ diff --git a/lib/Rest/EndpointIp.cpp b/lib/Rest/EndpointIp.cpp index 0c897403f7..b4b25f6215 100755 --- a/lib/Rest/EndpointIp.cpp +++ b/lib/Rest/EndpointIp.cpp @@ -136,7 +136,7 @@ socket_t EndpointIp::connectSocket (const struct addrinfo* aip, double connectTi if (setsockopt(listenSocket, SOL_SOCKET, SO_REUSEADDR, reinterpret_cast (&opt), sizeof (opt)) == -1) { LOGGER_ERROR << "setsockopt failed with " << errno << " (" << strerror(errno) << ")"; - TRI_CLOSE(listenSocket); + TRI_CLOSE_SOCKET(listenSocket); return 0; } diff --git a/lib/V8/v8-utils.cpp b/lib/V8/v8-utils.cpp index 771dcef762..1965680598 100644 --- a/lib/V8/v8-utils.cpp +++ b/lib/V8/v8-utils.cpp @@ -1472,15 +1472,20 @@ v8::Handle TRI_normalize_V8_Obj (v8::Handle obj) { //LOGGER_ERROR << "error in Normalizer2::getNFCInstance(erroCode): " << u_errorName(erroCode); return scope.Close(v8::String::New(*str, str_len)); } - - UnicodeString result = normalizer->normalize(UnicodeString(*str, str_len), erroCode); + + UnicodeString result = normalizer->normalize(UnicodeString((UChar*)(*str), str_len), erroCode); if (U_FAILURE(erroCode)) { //LOGGER_ERROR << "error in normalizer->normalize(UnicodeString(*str, str_len), erroCode): " << u_errorName(erroCode); return scope.Close(v8::String::New(*str, str_len)); } - return scope.Close(v8::String::New(result.getBuffer(), result.length())); + // .......................................................................... + // Take note here: we are assuming that the ICU type UChar is two bytes. + // There is no guarantee that this will be the case on all platforms and + // compilers. v8 expects uint16_t (2 bytes) + // .......................................................................... + return scope.Close(v8::String::New( (const uint16_t*)(result.getBuffer()), result.length())); #else return scope.Close(v8::String::New(*str, str_len)); #endif