diff --git a/code/nel/src/misc/common.cpp b/code/nel/src/misc/common.cpp index 119323331..6888dd24f 100644 --- a/code/nel/src/misc/common.cpp +++ b/code/nel/src/misc/common.cpp @@ -732,8 +732,7 @@ bool launchProgram(const std::string &programName, const std::string &arguments, SetEnvironmentVariable( SE_TRANSLATOR_IN_MAIN_MODULE, NULL ); } - string arg = " " + arguments; - BOOL res = CreateProcessA(programName.c_str(), (char*)arg.c_str(), NULL, NULL, FALSE, CREATE_DEFAULT_ERROR_MODE | CREATE_NO_WINDOW, NULL, NULL, &si, &pi); + BOOL res = CreateProcessA(programName.empty() ? NULL:programName.c_str(), (char*)arguments.c_str(), NULL, NULL, FALSE, CREATE_DEFAULT_ERROR_MODE | CREATE_NO_WINDOW, NULL, NULL, &si, &pi); if (res) { @@ -754,25 +753,13 @@ bool launchProgram(const std::string &programName, const std::string &arguments, } #elif defined(NL_OS_MAC) - std::string command; + // we need to open bundles with "open" command + std::string command = NLMISC::toString("open \"%s\"", programName.c_str()); - if (CFile::getExtension(programName) == "app") + // append arguments if any + if (!arguments.empty()) { - // we need to open bundles with "open" command - command = NLMISC::toString("open \"%s\"", programName.c_str()); - - // append arguments if any - if (!arguments.empty()) - { - command += NLMISC::toString(" --args %s", arguments.c_str()); - } - } - else - { - command = programName; - - // append arguments if any - if (!arguments.empty()) command += " " + arguments; + command += NLMISC::toString(" --args %s", arguments.c_str()); } int res = system(command.c_str()); diff --git a/code/ryzom/client/src/login_patch.cpp b/code/ryzom/client/src/login_patch.cpp index 37cbddcbd..68b29b687 100644 --- a/code/ryzom/client/src/login_patch.cpp +++ b/code/ryzom/client/src/login_patch.cpp @@ -47,6 +47,7 @@ #include "nel/misc/sha1.h" #include "nel/misc/big_file.h" #include "nel/misc/i18n.h" +#include "nel/misc/cmd_args.h" #include "game_share/bg_downloader_msg.h" @@ -89,6 +90,8 @@ extern string R2ServerVersion; std::string TheTmpInstallDirectory = "patch/client_install"; #endif +extern NLMISC::CCmdArgs Args; + // **************************************************************************** // **************************************************************************** // **************************************************************************** @@ -120,8 +123,16 @@ CPatchManager::CPatchManager() : State("t_state"), DataScanState("t_data_scan_st UpdateBatchFilename = "updt_nl.sh"; #endif - // use current directory by default - setClientRootPath("./"); + // use application directory by default + std::string rootPath = Args.getProgramPath(); + + if (!CFile::fileExists(rootPath + "client_default.cfg")) + { + // use current directory + rootPath = CPath::getCurrentPath(); + } + + setClientRootPath(rootPath); VerboseLog = true; @@ -716,29 +727,12 @@ void CPatchManager::createBatchFile(CProductDescriptionForClient &descFile, bool { uint nblab = 0; - FILE *fp = NULL; - - if (useBatchFile) - { - deleteBatchFile(); - fp = fopen (UpdateBatchFilename.c_str(), "wt"); - if (fp == 0) - { - string err = toString("Can't open file '%s' for writing: code=%d %s (error code 29)", UpdateBatchFilename.c_str(), errno, strerror(errno)); - throw Exception (err); - } - - //use bat if windows if not use sh -#ifdef NL_OS_WINDOWS - fprintf(fp, "@echo off\n"); -#else - fprintf(fp, "#!/bin/sh\n"); -#endif - } + std::string content; // Unpack files with category ExtractPath non empty const CBNPCategorySet &rDescCats = descFile.getCategories(); OptionalCat.clear(); + for (uint32 i = 0; i < rDescCats.categoryCount(); ++i) { // For all optional categories check if there is a 'file to patch' in it @@ -758,11 +752,6 @@ void CPatchManager::createBatchFile(CProductDescriptionForClient &descFile, bool } catch(...) { - if (useBatchFile) - { - fclose(fp); - } - throw; } @@ -771,11 +760,6 @@ void CPatchManager::createBatchFile(CProductDescriptionForClient &descFile, bool // TODO: handle exception? string err = toString("Error unpacking %s", rFilename.c_str()); - if (useBatchFile) - { - fclose(fp); - } - throw Exception (err); } else @@ -787,39 +771,41 @@ void CPatchManager::createBatchFile(CProductDescriptionForClient &descFile, bool NLMISC::CFile::createDirectoryTree(DstPath); // this file must be moved - if (useBatchFile) - { #ifdef NL_OS_WINDOWS - SrcPath = CPath::standardizeDosPath(SrcPath); - DstPath = CPath::standardizeDosPath(DstPath); -#else - SrcPath = CPath::standardizePath(SrcPath); - DstPath = CPath::standardizePath(DstPath); + SrcPath = CPath::standardizeDosPath(SrcPath); + DstPath = CPath::standardizeDosPath(DstPath); #endif - } std::string SrcName = SrcPath + vFilenames[fff]; std::string DstName = DstPath + vFilenames[fff]; - if (useBatchFile) + bool succeeded = false; + + if (!useBatchFile) + { + // don't check result, because it's possible the olk file doesn't exist + CFile::deleteFile(DstName); + + // try to move it, if fails move it later in a script + if (CFile::moveFile(DstName, SrcName)) + succeeded = true; + } + + // if we didn't succeed to delete or move the file, create a batch file anyway + if (!succeeded) { // write windows .bat format else write sh format #ifdef NL_OS_WINDOWS - fprintf(fp, ":loop%u\n", nblab); - fprintf(fp, "attrib -r -a -s -h %s\n", DstName.c_str()); - fprintf(fp, "del %s\n", DstName.c_str()); - fprintf(fp, "if exist %s goto loop%u\n", DstName.c_str(), nblab); - fprintf(fp, "move %s %s\n", SrcName.c_str(), DstPath.c_str()); + content += toString(":loop%u\n", nblab); + content += toString("attrib -r -a -s -h \"%s\"\n", DstName.c_str()); + content += toString("del \"%s\"\n", DstName.c_str()); + content += toString("if exist \"%s\" goto loop%u\n", DstName.c_str(), nblab); + content += toString("move \"%s\" \"%s\"\n", SrcName.c_str(), DstPath.c_str()); #else - fprintf(fp, "rm -rf %s\n", DstName.c_str()); - fprintf(fp, "mv %s %s\n", SrcName.c_str(), DstPath.c_str()); + content += toString("rm -rf \"%s\"\n", DstName.c_str()); + content += toString("mv %s \"%s\"\n", SrcName.c_str(), DstPath.c_str()); #endif } - else - { - deleteFile(DstName); - CFile::moveFile(DstName, SrcName); - } nblab++; } @@ -827,58 +813,86 @@ void CPatchManager::createBatchFile(CProductDescriptionForClient &descFile, bool } } + std::string patchDirectory = CPath::standardizeDosPath(ClientRootPath + "patch"); + // Finalize batch file - if (NLMISC::CFile::isExists("patch") && NLMISC::CFile::isDirectory("patch")) + if (NLMISC::CFile::isExists(patchDirectory) && NLMISC::CFile::isDirectory(patchDirectory)) { -#ifdef NL_OS_WINDOWS - if (useBatchFile) - { - fprintf(fp, ":looppatch\n"); - } -#endif + std::string patchContent; vector vFileList; - CPath::getPathContent ("patch", false, false, true, vFileList, NULL, false); + CPath::getPathContent (patchDirectory, false, false, true, vFileList, NULL, false); for(uint32 i = 0; i < vFileList.size(); ++i) { - if (useBatchFile) + bool succeeded = false; + + if (!useBatchFile) + { + if (CFile::deleteFile(vFileList[i])) + succeeded = true; + } + + // if we didn't succeed to delete, create a batch file anyway + if (!succeeded) { #ifdef NL_OS_WINDOWS - fprintf(fp, "del %s\n", CPath::standardizeDosPath(vFileList[i]).c_str()); + patchContent += toString("del \"%s\"\n", CPath::standardizeDosPath(vFileList[i]).c_str()); #else - fprintf(fp, "rm -f %s\n", CPath::standardizePath(vFileList[i]).c_str()); + patchContent += toString("rm -f \"%s\"\n", CPath::standardizePath(vFileList[i]).c_str()); #endif } - else - { - CFile::deleteFile(vFileList[i]); - } } - if (useBatchFile) + if (!patchContent.empty()) { #ifdef NL_OS_WINDOWS - fprintf(fp, "rd /Q /S patch\n"); - fprintf(fp, "if exist patch goto looppatch\n"); + content += toString(":looppatch\n"); + + content += patchContent; + + content += toString("rd /Q /S \"" + patchDirectory + "\"\n"); + content += toString("if exist \"" + patchDirectory + "\" goto looppatch\n"); #else - fprintf(fp, "rm -rf patch\n"); + content += toString("rm -rf \"" + patchDirectory + "\"\n"); #endif } else { - CFile::deleteDirectory("patch"); + CFile::deleteDirectory(patchDirectory); } } - if (useBatchFile) + if (!content.empty()) { + deleteBatchFile(); + + std::string batchFilename = ClientRootPath + UpdateBatchFilename; + + FILE *fp = fopen (batchFilename.c_str(), "wt"); + + if (fp == NULL) + { + string err = toString("Can't open file '%s' for writing: code=%d %s (error code 29)", batchFilename.c_str(), errno, strerror(errno)); + throw Exception (err); + } + + //use bat if windows if not use sh +#ifdef NL_OS_WINDOWS + fprintf(fp, "@echo off\n"); +#else + fprintf(fp, "#!/bin/sh\n"); +#endif + + // append content of script + fprintf(fp, content.c_str()); + if (wantRyzomRestart) { #ifdef NL_OS_WINDOWS - fprintf(fp, "start %s %%1 %%2 %%3\n", RyzomFilename.c_str()); + fprintf(fp, "start \"\" \"%s\" %%1 %%2 %%3\n", CPath::standardizeDosPath(RyzomFilename).c_str()); #else - fprintf(fp, "%s $1 $2 $3\n", RyzomFilename.c_str()); + fprintf(fp, "\"%s\" $1 $2 $3\n", RyzomFilename.c_str()); #endif } @@ -887,11 +901,11 @@ void CPatchManager::createBatchFile(CProductDescriptionForClient &descFile, bool fclose(fp); if (diskFull) { - throw NLMISC::EDiskFullError(UpdateBatchFilename.c_str()); + throw NLMISC::EDiskFullError(batchFilename.c_str()); } if (writeError) { - throw NLMISC::EWriteError(UpdateBatchFilename.c_str()); + throw NLMISC::EWriteError(batchFilename.c_str()); } } } @@ -903,93 +917,44 @@ void CPatchManager::executeBatchFile() extern void quitCrashReport (); quitCrashReport (); -#ifdef NL_OS_WINDOWS - // Launch the batch file - STARTUPINFO si; - PROCESS_INFORMATION pi; - - ZeroMemory( &si, sizeof(si) ); - si.dwFlags = STARTF_USESHOWWINDOW; - si.wShowWindow = SW_HIDE; // SW_SHOW - - si.cb = sizeof(si); - - ZeroMemory( &pi, sizeof(pi) ); - - // Start the child process. - string strCmdLine; - bool r2Mode = false; - #ifndef RY_BG_DOWNLOADER - r2Mode = ClientCfg.R2Mode; - #endif - if (r2Mode) - { - strCmdLine = UpdateBatchFilename + " " + LoginLogin + " " + LoginPassword; - } - else - { - strCmdLine = UpdateBatchFilename + " " + LoginLogin + " " + LoginPassword + " " + toString(LoginShardId); - } - if( !CreateProcess( NULL, // No module name (use command line). - (char*)strCmdLine.c_str(), // Command line. - NULL, // Process handle not inheritable. - NULL, // Thread handle not inheritable. - FALSE, // Set handle inheritance to FALSE. - 0, // No creation flags. - NULL, // Use parent's environment block. - NULL, // Use parent's starting directory. - &si, // Pointer to STARTUPINFO structure. - &pi ) // Pointer to PROCESS_INFORMATION structure. - ) - { - // error occurs during the launch - string str = toString("Can't execute '%s': code=%d %s (error code 30)", UpdateBatchFilename.c_str(), errno, strerror(errno)); - throw Exception (str); - } - // Close process and thread handles. -// CloseHandle( pi.hProcess ); -// CloseHandle( pi.hThread ); - -#else - // Start the child process. bool r2Mode = false; #ifndef RY_BG_DOWNLOADER r2Mode = ClientCfg.R2Mode; #endif - string strCmdLine; + std::string batchFilename; - strCmdLine = "./" + UpdateBatchFilename; +#ifdef NL_OS_WINDOWS + batchFilename = CPath::standardizeDosPath(ClientRootPath); +#else + batchFilename = ClientRootPath; +#endif - chmod(strCmdLine.c_str(), S_IRWXU); - if (r2Mode) + batchFilename += UpdateBatchFilename; + +#ifdef NL_OS_UNIX + // make script executable under UNIX + chmod(batchFilename.c_str(), S_IRWXU); +#endif + + std::string cmdLine = "\"" + batchFilename + "\" " + LoginLogin + " " + LoginPassword; + + if (!r2Mode) { - if (execl(strCmdLine.c_str(), strCmdLine.c_str(), LoginLogin.c_str(), LoginPassword.c_str(), (char *) NULL) == -1) - { - int errsv = errno; - nlerror("Execl Error: %d %s", errsv, strCmdLine.c_str()); - } - else - { - nlinfo("Ran batch file r2Mode Success"); - } + cmdLine += " " + toString(LoginShardId); + } + + if (launchProgram("", cmdLine, false)) + { + exit(0); } else { - if (execl(strCmdLine.c_str(), strCmdLine.c_str(), LoginLogin.c_str(), LoginPassword.c_str(), toString(LoginShardId).c_str(), (char *) NULL) == -1) - { - int errsv = errno; - nlerror("Execl r2mode Error: %d %s", errsv, strCmdLine.c_str()); - } - else - { - nlinfo("Ran batch file Success"); - } + // error occurs during the launch + string str = toString("Can't execute '%s': code=%d %s (error code 30)", UpdateBatchFilename.c_str(), errno, strerror(errno)); + throw Exception (str); } -#endif - -// exit(0); } // **************************************************************************** @@ -1156,9 +1121,9 @@ void CPatchManager::readDescFile(sint32 nVersion) std::string unpackTo = category.getUnpackTo(); - if (unpackTo.substr(0, 2) == "./") + if (unpackTo.substr(0, 1) == ".") { - unpackTo = ClientRootPath + unpackTo.substr(2); + unpackTo = CPath::makePathAbsolute(unpackTo, ClientRootPath, true); category.setUnpackTo(unpackTo); } } @@ -2356,7 +2321,6 @@ void CPatchThread::run() ucstring sTranslate; try { - // First do all ref files // ---------------------- @@ -2429,7 +2393,6 @@ void CPatchThread::run() pPM->deleteFile(pPM->UpdateBatchFilename, false, false); } - if (!bErr) { sTranslate = CI18N::get("uiPatchEndNoErr"); @@ -2439,6 +2402,7 @@ void CPatchThread::run() // Set a more explicit error message pPM->setErrorMessage(sTranslate); } + PatchOk = !bErr; Ended = true; } diff --git a/code/ryzom/tools/client/client_patcher/CMakeLists.txt b/code/ryzom/tools/client/client_patcher/CMakeLists.txt index 0b32a9867..8cfb5c452 100644 --- a/code/ryzom/tools/client/client_patcher/CMakeLists.txt +++ b/code/ryzom/tools/client/client_patcher/CMakeLists.txt @@ -3,7 +3,6 @@ FILE(GLOB SRC main.cpp ${CMAKE_SOURCE_DIR}/ryzom/client/src/user_agent.cpp ${CMAKE_SOURCE_DIR}/ryzom/client/src/client_cfg.cpp ${CMAKE_SOURCE_DIR}/ryzom/client/src/login_patch.cpp - ${CMAKE_SOURCE_DIR}/ryzom/client/src/login_patch_seven_zip.cpp ${CMAKE_SOURCE_DIR}/ryzom/client/src/login_xdelta.cpp ${CMAKE_SOURCE_DIR}/ryzom/client/src/stdpch.cpp ${CMAKE_SOURCE_DIR}/ryzom/client/src/stdpch.h diff --git a/code/ryzom/tools/client/client_patcher/main.cpp b/code/ryzom/tools/client/client_patcher/main.cpp index 004e3d861..4402da8a9 100644 --- a/code/ryzom/tools/client/client_patcher/main.cpp +++ b/code/ryzom/tools/client/client_patcher/main.cpp @@ -1,6 +1,10 @@ #include "stdpch.h" #include "login_patch.h" #include "client_cfg.h" +#include "user_agent.h" + +#include "nel/misc/cmd_args.h" + #include #ifdef NL_OS_WINDOWS @@ -28,6 +32,8 @@ string VersionName; string LoginLogin, LoginPassword; uint32 LoginShardId = 0xFFFFFFFF; +CCmdArgs Args; + bool useUtf8 = false; bool useEsc = false; @@ -147,6 +153,12 @@ int main(int argc, char *argv[]) // init the Nel context CApplicationContext appContext; + Args.setVersion(getDisplayVersion()); + Args.setDescription("Ryzom client"); + Args.addArg("c", "config", "id", "Use this configuration to determine what directory to use by default"); + + if (!Args.parse(argc, argv)) return 1; + // create logs in temporary directory createDebug(CPath::getTemporaryDirectory().c_str(), true, true); @@ -209,59 +221,6 @@ int main(int argc, char *argv[]) return 1; } - // set default paths - std::string dataPath = "./data/"; - std::string rootPath = "./"; - - // use custom data path if specified - if (!ClientCfg.DataPath.empty()) - { - dataPath = CPath::standardizePath(ClientCfg.DataPath.front()); - string::size_type pos = dataPath.rfind('/', dataPath.length()-2); - if (pos != string::npos) - rootPath = dataPath.substr(0, pos+1); - } - - std::string unpackPath = CPath::standardizePath(rootPath + "unpack"); - - // check if user can write in data directory - if (!CFile::isExists(unpackPath)) - { - if (!CFile::createDirectoryTree(unpackPath)) - { - printError("You don't have permission to create " + unpackPath); - return 1; - } - } - else - { - if (!CFile::createEmptyFile(unpackPath + "empty")) - { - printError("You don't have write permission in " + unpackPath); - return 1; - } - - CFile::deleteFile(unpackPath + "empty"); - } - - // only use PreDataPath for looking paths - if (!ClientCfg.PreDataPath.empty()) - { - for(uint i = 0; i < ClientCfg.PreDataPath.size(); ++i) - { - CPath::addSearchPath(NLMISC::expandEnvironmentVariables(ClientCfg.PreDataPath[i]), true, false); - } - } - - // add more search paths if translation is not found - if (!CPath::exists(lang + ".uxt")) - { - CPath::addSearchPath("patcher", true, false); -#ifdef RYZOM_SHARE_PREFIX - CPath::addSearchPath(RYZOM_SHARE_PREFIX"/patcher", true, false); -#endif - } - // load translation CI18N::load(lang); @@ -270,9 +229,6 @@ int main(int argc, char *argv[]) // initialize patch manager and set the ryzom full path, before it's used CPatchManager *pPM = CPatchManager::getInstance(); - // set the correct root path - pPM->setClientRootPath(rootPath); - // use PatchUrl vector patchURLs; pPM->init(patchURLs, ClientCfg.PatchUrl, ClientCfg.PatchVersion); @@ -385,6 +341,8 @@ int main(int argc, char *argv[]) printError(convert(CI18N::get("uiErrPatchApply")) + " " + error); return 1; } + + pPM->executeBatchFile(); } /*