Skip to content

Commit 00b2b52

Browse files
author
Brian Olsen
committed
parent_select plugin: refactor to use std::filesystem and std::string_view for loadConfigFile (coverity issue #10209)
1 parent 3a11dfe commit 00b2b52

File tree

1 file changed

+50
-61
lines changed

1 file changed

+50
-61
lines changed

plugins/experimental/parent_select/consistenthash_config.cc

Lines changed: 50 additions & 61 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@
2828
#include <mutex>
2929
#include <unordered_map>
3030
#include <unordered_set>
31+
#include <filesystem>
3132
#include <fstream>
3233
#include <cstring>
3334

@@ -176,85 +177,73 @@ createStrategiesFromFile(const char *file)
176177
* 'strategy' yaml file would then normally have the '#include hosts.yml' in it's beginning.
177178
*/
178179
void
179-
loadConfigFile(const std::string &fileName, std::stringstream &doc, std::unordered_set<std::string> &include_once)
180+
loadConfigFile(std::string const &pathnamein, std::stringstream &doc, std::unordered_set<std::string> &include_once)
180181
{
181-
const char *sep = " \t";
182-
char *tok, *last;
183-
struct stat buf;
184-
std::string line;
182+
constexpr std::string_view sep = " \t";
185183

186-
if (stat(fileName.c_str(), &buf) == -1) {
187-
std::string err_msg = strerror(errno);
188-
throw std::invalid_argument("Unable to stat '" + fileName + "': " + err_msg);
189-
}
184+
namespace fs = std::filesystem;
185+
fs::path const pathin(pathnamein);
186+
std::error_code ec;
190187

191188
// if fileName is a directory, concatenate all '.yaml' files alphanumerically
192189
// into a single document stream. No #include is supported.
193-
if (S_ISDIR(buf.st_mode)) {
194-
DIR *dir = nullptr;
195-
struct dirent *dir_ent = nullptr;
196-
std::vector<std::string_view> files;
197-
198-
TSDebug(PLUGIN_NAME, "loading strategy YAML files from the directory %s", fileName.c_str());
199-
if ((dir = opendir(fileName.c_str())) == nullptr) {
200-
std::string err_msg = strerror(errno);
201-
throw std::invalid_argument("Unable to open the directory '" + fileName + "': " + err_msg);
202-
} else {
203-
while ((dir_ent = readdir(dir)) != nullptr) {
204-
// filename should be greater that 6 characters to have a '.yaml' suffix.
205-
if (strlen(dir_ent->d_name) < 6) {
206-
continue;
207-
}
208-
std::string_view sv = dir_ent->d_name;
209-
if (sv.find(".yaml", sv.size() - 5) == sv.size() - 5) {
210-
files.push_back(sv);
190+
if (fs::is_directory(pathin, ec)) {
191+
TSDebug(PLUGIN_NAME, "loading strategy YAML files from the directory %s", pathnamein.c_str());
192+
193+
std::vector<fs::path> subpaths;
194+
for (auto const &dirent : fs::directory_iterator(pathin)) {
195+
fs::path const subpath = dirent.path();
196+
if (fs::is_regular_file(subpath, ec) && !fs::is_empty(subpath, ec)) {
197+
if (".yaml" == subpath.extension()) {
198+
subpaths.push_back(subpath);
199+
} else {
200+
TSDebug(PLUGIN_NAME, "Skipping dirent (not yaml): '%s'", subpath.c_str());
211201
}
202+
} else {
203+
TSDebug(PLUGIN_NAME, "Skipping dirent (not file/empty): '%s'", subpath.c_str());
212204
}
213-
// sort the files alphanumerically
214-
std::sort(files.begin(), files.end(),
215-
[](const std::string_view lhs, const std::string_view rhs) { return lhs.compare(rhs) < 0; });
205+
}
216206

217-
for (auto &f : files) {
218-
std::ifstream file(fileName + "/" + f.data());
219-
if (file.is_open()) {
220-
while (std::getline(file, line)) {
221-
if (line[0] == '#') {
222-
// continue;
223-
}
224-
doc << line << "\n";
225-
}
226-
file.close();
227-
} else {
228-
throw std::invalid_argument("Unable to open and read '" + fileName + "/" + f.data() + "'");
207+
// sort the files alphanumerically
208+
std::sort(subpaths.begin(), subpaths.end());
209+
210+
for (fs::path const &fpath : subpaths) {
211+
std::ifstream ifs(fpath);
212+
if (ifs.is_open()) {
213+
std::string line;
214+
while (std::getline(ifs, line)) {
215+
doc << line << "\n";
229216
}
217+
ifs.close();
218+
} else {
219+
throw std::invalid_argument("Unable to open and read: '" + fpath.string() + "'");
230220
}
231221
}
232-
closedir(dir);
233-
} else {
234-
std::ifstream file(fileName);
235-
if (file.is_open()) {
236-
while (std::getline(file, line)) {
237-
if (line[0] == '#') {
238-
tok = strtok_r(const_cast<char *>(line.c_str()), sep, &last);
239-
if (tok != nullptr && strcmp(tok, "#include") == 0) {
240-
std::string f = strtok_r(nullptr, sep, &last);
241-
if (include_once.find(f) == include_once.end()) {
242-
include_once.insert(f);
243-
// try to load included file.
244-
try {
245-
loadConfigFile(f, doc, include_once);
246-
} catch (std::exception &ex) {
247-
throw std::invalid_argument("Unable to open included file '" + f + "' from '" + fileName + "'");
248-
}
222+
} else if (fs::is_regular_file(pathin, ec) && !fs::is_empty(pathin, ec)) {
223+
std::ifstream ifs(pathin);
224+
if (ifs.is_open()) {
225+
std::string line;
226+
while (std::getline(ifs, line)) {
227+
// include directive ??
228+
if (0 == line.rfind("#include", 0)) { // starts_with
229+
std::string_view const sv(line.substr(line.find_first_of(sep)));
230+
std::string const pathinc(sv.substr(0, sv.find_first_of(sep)));
231+
if (include_once.end() == include_once.find(pathinc)) {
232+
TSDebug(PLUGIN_NAME, "Include directive: '%s'", pathinc.c_str());
233+
include_once.insert(pathinc);
234+
try {
235+
loadConfigFile(pathinc, doc, include_once);
236+
} catch (std::exception &ex) {
237+
throw std::invalid_argument("Unable to open included file '" + pathinc + "' from '" + pathnamein + "'");
249238
}
250239
}
251240
} else {
252241
doc << line << "\n";
253242
}
254243
}
255-
file.close();
244+
ifs.close();
256245
} else {
257-
throw std::invalid_argument("Unable to open and read '" + fileName + "'");
246+
throw std::invalid_argument("Unable to open and read '" + pathnamein + "'");
258247
}
259248
}
260249
}

0 commit comments

Comments
 (0)