diff --git a/nel/include/nel/misc/path.h b/nel/include/nel/misc/path.h index 74e24d715..6f3bb8fe1 100644 --- a/nel/include/nel/misc/path.h +++ b/nel/include/nel/misc/path.h @@ -731,11 +731,18 @@ struct CFile static bool createDirectoryTree(const std::string &dirname); /** Try to set the file access to read/write if not already set. + * On linux/macOS also set +x on directory. * return true if the file doesn't exist or if the file already have RW access. * \return true if RW access is granted */ static bool setRWAccess(const std::string &filename); + /** Try to set +x bit on linux/macOS to make file executable. no-op on Windows + * On Windows, always returns true, even if file does not exist. + * \return true if file exists and +x was set, false if operation failed. + */ + static bool setExecutable(const std::string &filename); + /** Delete a file if possible (change the write access if possible) * \return true if the delete occurs. */ diff --git a/nel/src/misc/path.cpp b/nel/src/misc/path.cpp index 2c55ac09f..ffa27d193 100644 --- a/nel/src/misc/path.cpp +++ b/nel/src/misc/path.cpp @@ -2571,8 +2571,8 @@ bool CFile::createDirectory(const std::string &filename) #ifdef NL_OS_WINDOWS return _wmkdir(nlUtf8ToWide(filename)) == 0; #else - // Set full permissions.... - return mkdir(filename.c_str(), 0xFFFF)==0; + // set rwxrwxr-x permissions + return mkdir(filename.c_str(), S_IRUSR|S_IWUSR|S_IXUSR|S_IRGRP|S_IWGRP|S_IXGRP|S_IROTH|S_IXOTH)==0; #endif } @@ -2810,7 +2810,17 @@ bool CFile::setRWAccess(const std::string &filename) if (access (filename.c_str(), F_OK) == 0) { // try to set the read/write access - if (chmod (filename.c_str(), S_IRUSR|S_IWUSR|S_IXUSR|S_IRGRP|S_IWGRP|S_IXGRP|S_IROTH|S_IWOTH|S_IXOTH) == -1) + // rw-rw-r-- + mode_t mode = S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP|S_IROTH; + + // set +x only for directory + // rwxrwxr-x + if (CFile::isDirectory(filename)) + { + mode |= S_IXUSR|S_IXGRP|S_IXOTH; + } + + if (chmod (filename.c_str(), mode) == -1) { if (INelContext::getInstance().getAlreadyCreateSharedAmongThreads()) { @@ -2831,6 +2841,34 @@ bool CFile::setRWAccess(const std::string &filename) return true; } +bool CFile::setExecutable(const std::string &filename) +{ +#ifndef NL_OS_WINDOWS + struct stat buf; + if (stat(filename.c_str (), &buf) == 0) + { + mode_t mode = buf.st_mode | S_IXUSR | S_IXGRP | S_IXOTH; + if (chmod(filename.c_str(), mode) == -1) + { + if (INelContext::getInstance().getAlreadyCreateSharedAmongThreads()) + { + nlwarning ("PATH: Can't set +x flag on file '%s': %d %s", filename.c_str(), errno, strerror(errno)); + } + return false; + } + } + else + { + if (INelContext::getInstance().getAlreadyCreateSharedAmongThreads()) + { + nlwarning("PATH: Can't access file '%s': %d %s", filename.c_str(), errno, strerror(errno)); + } + return false; + } +#endif + return true; +} + bool CFile::deleteFile(const std::string &filename) { setRWAccess(filename); diff --git a/ryzom/client/src/login_patch.cpp b/ryzom/client/src/login_patch.cpp index d9d7e2e99..6fc6da999 100644 --- a/ryzom/client/src/login_patch.cpp +++ b/ryzom/client/src/login_patch.cpp @@ -1035,6 +1035,7 @@ void CPatchManager::executeBatchFile() // make script executable CFile::setRWAccess(batchFilename); + CFile::setExecutable(batchFilename); // append login, password and shard if (!LoginLogin.empty()) diff --git a/ryzom/tools/client/client_patcher/main.cpp b/ryzom/tools/client/client_patcher/main.cpp index 6ab6d860b..9855a6b65 100644 --- a/ryzom/tools/client/client_patcher/main.cpp +++ b/ryzom/tools/client/client_patcher/main.cpp @@ -351,6 +351,7 @@ int main(int argc, char *argv[]) try { // move downloaded files to final location + // batch file will not be created pPM->createBatchFile(pPM->getDescFile(), false, false); CFile::createEmptyFile("show_eula"); @@ -381,17 +382,20 @@ int main(int argc, char *argv[]) printError(convert(CI18N::get("uiErrPatchApply")) + " " + error); return 1; } - - pPM->executeBatchFile(); } -/* - // Start Scanning - pPM->startScanDataThread(); - - // request to stop the thread - pPM->askForStopScanDataThread(); -*/ + // upgd_nl.sh will normally take care of the permissions + // + // for linux/macOS (no-op on windows) + // Set for current executable (might be 'dev' version), + // and also 'ryzom_client_patcher' directly (from patched files) + CFile::setExecutable(Args.getProgramPath() + Args.getProgramName()); + CFile::setExecutable("ryzom_client_patcher"); + // other + CFile::setExecutable("crash_report"); + CFile::setExecutable("ryzom_client"); + CFile::setExecutable("ryzom_installer_qt"); + CFile::setExecutable("ryzom_configuration_qt"); return 0; }