diff options
| author | 2023-07-03 17:26:40 +0100 | |
|---|---|---|
| committer | 2023-07-03 18:43:58 +0100 | |
| commit | 386f0dafd55897723356c75299cd02ed0b882f5b (patch) | |
| tree | be31de75870a0e1da815cf5f4203fed793eb66ba /src | |
| parent | Fix a minor Doxygen comment issue. (diff) | |
Replace FileReader with something more sensible.
Diffstat (limited to 'src')
| -rw-r--r-- | src/configparser.cpp | 25 | ||||
| -rw-r--r-- | src/configreader.cpp | 45 | ||||
| -rw-r--r-- | src/coremods/core_info/cmd_motd.cpp | 2 | ||||
| -rw-r--r-- | src/coremods/core_info/core_info.cpp | 19 | ||||
| -rw-r--r-- | src/coremods/core_info/core_info.h | 3 | ||||
| -rw-r--r-- | src/fileutils.cpp | 66 | ||||
| -rw-r--r-- | src/modules/extra/m_ssl_gnutls.cpp | 10 | ||||
| -rw-r--r-- | src/modules/m_opermotd.cpp | 15 | ||||
| -rw-r--r-- | src/modules/m_randquote.cpp | 14 | ||||
| -rw-r--r-- | src/modules/m_showfile.cpp | 16 |
10 files changed, 89 insertions, 126 deletions
diff --git a/src/configparser.cpp b/src/configparser.cpp index 985996fda..044897023 100644 --- a/src/configparser.cpp +++ b/src/configparser.cpp @@ -452,33 +452,16 @@ void ParseStack::DoReadFile(const std::string& key, const std::string& name, int if (exec && (flags & FLAG_NO_EXEC)) throw CoreException("Invalid <execfiles> tag in file included with noexec=\"yes\""); - std::string path = name; - if (!exec) - path = ServerInstance->Config->Paths.PrependConfig(name); - - auto file = DoOpenFile(path, exec); - if (!file) - throw CoreException(INSP_FORMAT("Could not read \"{}\" for {}: {}", path, key, strerror(errno))); - - file_cache& cache = FilesOutput[key]; - cache.clear(); - - char linebuf[5120]; - while (fgets(linebuf, sizeof(linebuf), file.get())) + if (FilesOutput.emplace(key, std::make_pair(name, exec)).second) { - size_t len = strlen(linebuf); - if (len) - { - if (linebuf[len-1] == '\n') - len--; - cache.push_back(std::string(linebuf, len)); - } + ServerInstance->Logs.Debug("CONFIG", "Stored config key: {} => {} (executable: {}).", + key, name, exec ? "yes" : "no"); } } ParseStack::ParseStack(ServerConfig* conf) : output(conf->config_data) - , FilesOutput(conf->Files) + , FilesOutput(conf->filesources) , errstr(conf->errstr) { vars = { diff --git a/src/configreader.cpp b/src/configreader.cpp index 363bc16c4..1c418eae7 100644 --- a/src/configreader.cpp +++ b/src/configreader.cpp @@ -40,6 +40,12 @@ #include "configparser.h" #include "exitcodes.h" +ServerConfig::ReadResult::ReadResult(const std::string& c, const std::string& e) + : contents(c) + , error(e) +{ +} + ServerConfig::ServerLimits::ServerLimits(const std::shared_ptr<ConfigTag>& tag) : MaxLine(tag->getNum<size_t>("maxline", 512, 512)) , MaxNick(tag->getNum<size_t>("maxnick", 30, 1, MaxLine)) @@ -88,6 +94,45 @@ ServerConfig::ServerConfig() { } +ServerConfig::ReadResult ServerConfig::ReadFile(const std::string& file, bool invalidate) +{ + auto contents = filecontents.find(file); + if (invalidate) + filecontents.erase(contents); + else if (contents != filecontents.end()) + return ReadResult(contents->second, {}); + + bool executable = false; + std::string name = file; + std::string path = file; + + // If the caller specified a short name (e.g. <file motd="motd.txt">) then look it up. + auto source = filesources.find(file); + if (source != filesources.end()) + { + name = source->first; + path = source->second.second; + executable = source->second.second; + } + + // Try to open the file and error out if it fails. + auto fh = ParseStack::DoOpenFile(path, executable); + if (!fh) + return ReadResult({}, strerror(errno)); + + std::stringstream datastream; + char databuf[4096]; + while (fgets(databuf, sizeof(databuf), fh.get())) + { + size_t len = strlen(databuf); + if (len) + datastream.write(databuf, len); + } + + filecontents[name] = datastream.str(); + return ReadResult(filecontents[name], {}); +} + void ServerConfig::CrossCheckOperBlocks() { std::unordered_map<std::string, std::shared_ptr<ConfigTag>> operclass; diff --git a/src/coremods/core_info/cmd_motd.cpp b/src/coremods/core_info/cmd_motd.cpp index 1f7bf75f8..424912524 100644 --- a/src/coremods/core_info/cmd_motd.cpp +++ b/src/coremods/core_info/cmd_motd.cpp @@ -57,7 +57,7 @@ CmdResult CommandMotd::Handle(User* user, const Params& parameters) tag = localuser->GetClass()->config; const std::string motd_name = tag->getString("motd", "motd", 1); - ConfigFileCache::iterator motd = motds.find(motd_name); + auto motd = motds.find(motd_name); if (motd == motds.end()) { user->WriteRemoteNumeric(ERR_NOMOTD, "There is no message of the day."); diff --git a/src/coremods/core_info/core_info.cpp b/src/coremods/core_info/core_info.cpp index da69cddf7..8c2752c65 100644 --- a/src/coremods/core_info/core_info.cpp +++ b/src/coremods/core_info/core_info.cpp @@ -21,7 +21,6 @@ #include "inspircd.h" #include "clientprotocolmsg.h" -#include "fileutils.h" #include "timeutils.h" #include "core_info.h" @@ -128,7 +127,7 @@ public: void ReadConfig(ConfigStatus& status) override { // Process the escape codes in the MOTDs. - ConfigFileCache newmotds; + CommandMotd::MessageCache newmotds; for (const auto& klass : ServerInstance->Config->Classes) { // Don't process the file if it has already been processed. @@ -136,23 +135,19 @@ public: if (newmotds.find(motd) != newmotds.end()) continue; - FileReader reader; - try - { - reader.Load(motd); - } - catch (const CoreException& ce) + auto file = ServerInstance->Config->ReadFile(motd); + if (!file) { // We can't process the file if it doesn't exist. ServerInstance->Logs.Warning(MODNAME, "Unable to read motd for connect class \"{}\" at {}: {}", - klass->GetName(), klass->config->source.str(), ce.GetReason()); + klass->GetName(), klass->config->source.str(), file.error); continue; } // Process the MOTD entry. - file_cache& newmotd = newmotds[motd]; - newmotd.reserve(reader.GetVector().size()); - for (const auto& line : reader.GetVector()) + auto& newmotd = newmotds[motd]; + irc::sepstream linestream(file.contents, '\n'); + for (std::string line; linestream.GetToken(line); ) { // Some clients can not handle receiving RPL_MOTD with an empty // trailing parameter so if a line is empty we replace it with diff --git a/src/coremods/core_info/core_info.h b/src/coremods/core_info/core_info.h index db4614098..f68a66434 100644 --- a/src/coremods/core_info/core_info.h +++ b/src/coremods/core_info/core_info.h @@ -118,7 +118,8 @@ class CommandMotd final : public ServerTargetCommand { public: - ConfigFileCache motds; + typedef insp::flat_map<std::string, std::vector<std::string>> MessageCache; + MessageCache motds; CommandMotd(Module* parent); CmdResult Handle(User* user, const Params& parameters) override; diff --git a/src/fileutils.cpp b/src/fileutils.cpp deleted file mode 100644 index 7084d8576..000000000 --- a/src/fileutils.cpp +++ /dev/null @@ -1,66 +0,0 @@ -/* - * InspIRCd -- Internet Relay Chat Daemon - * - * Copyright (C) 2013, 2019-2020 Sadie Powell <sadie@witchery.services> - * Copyright (C) 2013 Attila Molnar <attilamolnar@hush.com> - * - * This file is part of InspIRCd. InspIRCd is free software: you can - * redistribute it and/or modify it under the terms of the GNU General Public - * License as published by the Free Software Foundation, version 2. - * - * 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 General Public License for more - * details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see <http://www.gnu.org/licenses/>. - */ - - -#include "inspircd.h" -#include "fileutils.h" - -#include <fstream> - -FileReader::FileReader(const std::string& filename) -{ - Load(filename); -} - -void FileReader::Load(const std::string& filename) -{ - // If the file is stored in the file cache then we used that version instead. - ConfigFileCache::const_iterator it = ServerInstance->Config->Files.find(filename); - if (it != ServerInstance->Config->Files.end()) - { - this->lines = it->second; - } - else - { - std::ifstream stream(ServerInstance->Config->Paths.PrependConfig(filename)); - if (!stream.is_open()) - throw CoreException(filename + " does not exist or is not readable!"); - - lines.clear(); - std::string line; - while (std::getline(stream, line)) - { - lines.push_back(line); - totalSize += line.size() + 2; - } - - stream.close(); - } -} - -std::string FileReader::GetString() const -{ - std::string buffer; - for (const auto& line : lines) - { - buffer.append(line); - buffer.append("\r\n"); - } - return buffer; -} diff --git a/src/modules/extra/m_ssl_gnutls.cpp b/src/modules/extra/m_ssl_gnutls.cpp index 5ee85d3e1..4ac29186d 100644 --- a/src/modules/extra/m_ssl_gnutls.cpp +++ b/src/modules/extra/m_ssl_gnutls.cpp @@ -40,7 +40,6 @@ /// $PackageInfo: require_system("ubuntu") gnutls-bin libgnutls28-dev pkg-config #include "inspircd.h" -#include "fileutils.h" #include "modules/ssl.h" #include "timeutils.h" @@ -486,11 +485,10 @@ namespace GnuTLS static std::string ReadFile(const std::string& filename) { - FileReader reader(filename); - std::string ret = reader.GetString(); - if (ret.empty()) - throw Exception("Cannot read file " + filename); - return ret; + auto file = ServerInstance->Config->ReadFile(filename); + if (!file) + throw Exception("Cannot read file " + filename + ": " + file.error); + return file.contents; } static std::string GetPrioStr(const std::string& profilename, const std::shared_ptr<ConfigTag>& tag) diff --git a/src/modules/m_opermotd.cpp b/src/modules/m_opermotd.cpp index 7a844d8cd..c61d979ff 100644 --- a/src/modules/m_opermotd.cpp +++ b/src/modules/m_opermotd.cpp @@ -25,7 +25,6 @@ #include "inspircd.h" -#include "fileutils.h" enum { @@ -104,23 +103,19 @@ private: if (motd.empty() || newmotds.find(motd) != newmotds.end()) return; - FileReader reader; - try - { - reader.Load(motd); - } - catch (const CoreException& ce) + auto file = ServerInstance->Config->ReadFile(motd); + if (!file) { // We can't process the file if it doesn't exist. ServerInstance->Logs.Normal(MODNAME, "Unable to read server operator motd for oper {} \"{}\" at {}: {}", - type, oper->GetName(), oper->GetConfig()->source.str(), ce.GetReason()); + type, oper->GetName(), oper->GetConfig()->source.str(), file.error); return; } // Process the MOTD entry. auto& newmotd = newmotds[motd]; - newmotd.reserve(reader.GetVector().size()); - for (const auto& line : reader.GetVector()) + irc::sepstream linestream(file.contents, '\n'); + for (std::string line; linestream.GetToken(line); ) { // Some clients can not handle receiving RPL_OMOTD with an empty // trailing parameter so if a line is empty we replace it with diff --git a/src/modules/m_randquote.cpp b/src/modules/m_randquote.cpp index ceb2b1982..beecd2680 100644 --- a/src/modules/m_randquote.cpp +++ b/src/modules/m_randquote.cpp @@ -22,7 +22,6 @@ #include "inspircd.h" -#include "fileutils.h" class ModuleRandQuote final : public Module @@ -43,8 +42,17 @@ public: const auto& conf = ServerInstance->Config->ConfValue("randquote"); prefix = conf->getString("prefix"); suffix = conf->getString("suffix"); - FileReader reader(conf->getString("file", "quotes", 1)); - quotes = reader.GetVector(); + + const std::string filestr = conf->getString("file", "quotes", 1); + auto file = ServerInstance->Config->ReadFile(filestr); + if (!file) + throw ModuleException(this, "Unable to read quotes from " + filestr + ": " + file.error); + + std::vector<std::string> newquotes; + irc::sepstream linestream(file.contents, '\n'); + for (std::string line; linestream.GetToken(line); ) + newquotes.push_back(line); + std::swap(quotes, newquotes); } void OnUserConnect(LocalUser* user) override diff --git a/src/modules/m_showfile.cpp b/src/modules/m_showfile.cpp index 8273885a2..60a3f4a92 100644 --- a/src/modules/m_showfile.cpp +++ b/src/modules/m_showfile.cpp @@ -20,7 +20,6 @@ #include "inspircd.h" #include "clientprotocolmsg.h" -#include "fileutils.h" enum { @@ -80,7 +79,7 @@ public: return CmdResult::SUCCESS; } - void UpdateSettings(const std::shared_ptr<ConfigTag>& tag, const std::vector<std::string>& filecontents) + void UpdateSettings(const std::shared_ptr<ConfigTag>& tag, const std::string& filecontents) { introtext = tag->getString("introtext", "Showing " + name); endtext = tag->getString("endtext", "End of " + name); @@ -97,8 +96,9 @@ public: // Process the entry. contents.clear(); - contents.reserve(filecontents.size()); - for (const auto& line : filecontents) + + irc::sepstream linestream(filecontents, '\n'); + for (std::string line; linestream.GetToken(line); ) { // Some clients can not handle receiving NOTICE/PRIVMSG/RPL_RULES // with an empty trailing parameter so if a line is empty we @@ -106,6 +106,7 @@ public: contents.push_back(line.empty() ? " " : line); } InspIRCd::ProcessColors(contents); + contents.shrink_to_fit(); } }; @@ -126,7 +127,10 @@ private: const std::string file = tag->getString("file", cmdname); if (file.empty()) throw ModuleException(this, "Empty value for 'file'"); - FileReader reader(file); + + auto reader = ServerInstance->Config->ReadFile(file); + if (!reader) + throw ModuleException(this, "Unable to read " + file + ": " + reader.error); CommandShowFile* sfcmd; Command* handler = ServerInstance->Parser.GetHandler(cmdname); @@ -148,7 +152,7 @@ private: ServerInstance->Modules.AddService(*sfcmd); } - sfcmd->UpdateSettings(tag, reader.GetVector()); + sfcmd->UpdateSettings(tag, reader.contents); newcmds.push_back(sfcmd); } |
