Skip to content

Commit 2badb7e

Browse files
Detect unexpected directories in the cache (#1481)
Scan cache folder for the unexpected directories as their presence means that the cache was changed outside of Data SDK, or the wrong cache was used in a first place. Relates-To: OLPEDGE-2857 Signed-off-by: Andrey Kashcheev <ext-andrey.kashcheev@here.com>
1 parent ad5b230 commit 2badb7e

File tree

4 files changed

+155
-3
lines changed

4 files changed

+155
-3
lines changed

olp-cpp-sdk-core/include/olp/core/utils/Dir.h

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright (C) 2019-2023 HERE Europe B.V.
2+
* Copyright (C) 2019-2024 HERE Europe B.V.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -35,6 +35,9 @@ class CORE_API Dir {
3535
/// An alias for the filter function.
3636
using FilterFunction = std::function<bool(const std::string&)>;
3737

38+
/// An alias for the path callback function.
39+
using PathCallback = std::function<void(const std::string&)>;
40+
3841
/**
3942
* @brief Checks whether a directory exists.
4043
*
@@ -143,6 +146,15 @@ class CORE_API Dir {
143146
* path.
144147
*/
145148
static bool IsReadOnly(const std::string& path);
149+
150+
/**
151+
* @brief Iterates through all directories in the provided path and calls the
152+
* provided callback function for each directory.
153+
*
154+
* @param path The path of the root directory.
155+
* @param path_fn The callback function.
156+
*/
157+
static void ForEachDirectory(const std::string& path, PathCallback path_fn);
146158
};
147159

148160
} // namespace utils

olp-cpp-sdk-core/src/cache/DiskCache.cpp

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -204,6 +204,23 @@ OpenResult DiskCache::Open(const std::string& data_path,
204204
}
205205
}
206206

207+
// Check cache path for unexpected directories
208+
const std::vector<std::string> expected_dirs = {disk_cache_path_ +
209+
kLevelDbLostFolder};
210+
bool unexpected_dirs = false;
211+
utils::Dir::ForEachDirectory(disk_cache_path_, [&](const std::string& dir) {
212+
if (std::find(expected_dirs.begin(), expected_dirs.end(), dir) ==
213+
expected_dirs.end()) {
214+
OLP_SDK_LOG_WARNING_F(
215+
kLogTag, "Open: unexpected directory found, path='%s'", dir.c_str());
216+
unexpected_dirs = true;
217+
}
218+
});
219+
220+
if (unexpected_dirs) {
221+
return OpenResult::Fail;
222+
}
223+
207224
enforce_immediate_flush_ = settings.enforce_immediate_flush;
208225

209226
max_size_ = settings.max_disk_storage;

olp-cpp-sdk-core/src/utils/Dir.cpp

Lines changed: 75 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright (C) 2019-2023 HERE Europe B.V.
2+
* Copyright (C) 2019-2024 HERE Europe B.V.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -530,5 +530,79 @@ bool Dir::IsReadOnly(const std::string& path) {
530530
#endif
531531
}
532532

533+
void Dir::ForEachDirectory(const std::string& path, PathCallback path_fn) {
534+
#if defined(_WIN32) && !defined(__MINGW32__)
535+
536+
WIN32_FIND_DATAA find_data;
537+
std::string current_path = path + "\\*.*";
538+
539+
HANDLE handle = FindFirstFileA(current_path.c_str(), &find_data);
540+
541+
if (handle != INVALID_HANDLE_VALUE) {
542+
do {
543+
if (strcmp(find_data.cFileName, ".") == 0 ||
544+
strcmp(find_data.cFileName, "..") == 0) {
545+
continue;
546+
}
547+
548+
if (find_data.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) {
549+
current_path = path + "\\" + find_data.cFileName;
550+
path_fn(current_path);
551+
ForEachDirectory(current_path, path_fn);
552+
}
553+
} while (FindNextFileA(handle, &find_data) != 0);
554+
555+
FindClose(handle);
556+
}
557+
558+
#else
559+
560+
std::queue<std::string> recursive_queue;
561+
recursive_queue.push(path);
562+
563+
auto iterate_directory = [&](const std::string& path) {
564+
auto* dir = ::opendir(path.c_str());
565+
if (dir == nullptr) {
566+
return;
567+
}
568+
569+
struct ::dirent* entry = nullptr;
570+
while ((entry = ::readdir(dir)) != nullptr) {
571+
const char* entry_name = entry->d_name;
572+
573+
if (strcmp(entry_name, ".") == 0 || strcmp(entry_name, "..") == 0) {
574+
continue;
575+
}
576+
577+
std::string full_path = path + "/" + entry_name;
578+
579+
#ifdef __APPLE__
580+
struct ::stat path_stat;
581+
if (::lstat(full_path.c_str(), &path_stat) == 0) {
582+
#else
583+
struct ::stat64 path_stat;
584+
if (::lstat64(full_path.c_str(), &path_stat) == 0) {
585+
#endif
586+
if (S_ISDIR(path_stat.st_mode)) {
587+
path_fn(full_path);
588+
recursive_queue.push(std::move(full_path));
589+
}
590+
} else if (errno != ENOENT) {
591+
// Ignore ENOENT errors as its a common case, e.g. cache compaction.
592+
break;
593+
}
594+
}
595+
596+
::closedir(dir);
597+
};
598+
599+
while (!recursive_queue.empty()) {
600+
iterate_directory(recursive_queue.front());
601+
recursive_queue.pop();
602+
}
603+
604+
#endif
605+
}
606+
533607
} // namespace utils
534608
} // namespace olp

olp-cpp-sdk-core/tests/cache/DefaultCacheTest.cpp

Lines changed: 50 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright (C) 2019-2021 HERE Europe B.V.
2+
* Copyright (C) 2019-2024 HERE Europe B.V.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -21,6 +21,7 @@
2121
#include <fstream>
2222
#include <string>
2323
#include <thread>
24+
#include <tuple>
2425

2526
#include <gtest/gtest.h>
2627

@@ -684,6 +685,54 @@ TEST(DefaultCacheTest, OpenTypeCache) {
684685
ASSERT_FALSE(cache.Contains(key1));
685686
ASSERT_FALSE(cache.Contains(key2));
686687
}
688+
689+
{
690+
SCOPED_TRACE("Additional directories");
691+
692+
constexpr auto kExpectedDirResult =
693+
olp::cache::DefaultCache::StorageOpenResult::Success;
694+
constexpr auto kUnexpectedDirResult =
695+
olp::cache::DefaultCache::StorageOpenResult::OpenDiskPathFailure;
696+
697+
auto scenarios = {
698+
std::make_tuple("/lost", kExpectedDirResult),
699+
std::make_tuple("/lost/tmp", kUnexpectedDirResult),
700+
std::make_tuple("/found", kUnexpectedDirResult),
701+
std::make_tuple("/ARCHIVES", kUnexpectedDirResult),
702+
std::make_tuple("/ARCHIVES/removed", kUnexpectedDirResult)};
703+
704+
for (auto& scenario : scenarios) {
705+
{
706+
SCOPED_TRACE("Mutable cache");
707+
708+
std::string dir_path = mutable_path + std::get<0>(scenario);
709+
ASSERT_TRUE(olp::utils::Dir::Create(dir_path));
710+
711+
olp::cache::CacheSettings settings;
712+
settings.disk_path_mutable = mutable_path;
713+
714+
olp::cache::DefaultCache cache(settings);
715+
EXPECT_EQ(cache.Open(), std::get<1>(scenario));
716+
717+
olp::utils::Dir::Remove(dir_path);
718+
}
719+
720+
{
721+
SCOPED_TRACE("Protected cache");
722+
723+
std::string dir_path = protected_path + std::get<0>(scenario);
724+
ASSERT_TRUE(olp::utils::Dir::Create(dir_path));
725+
726+
olp::cache::CacheSettings settings;
727+
settings.disk_path_protected = protected_path;
728+
729+
olp::cache::DefaultCache cache(settings);
730+
EXPECT_EQ(cache.Open(), std::get<1>(scenario));
731+
732+
olp::utils::Dir::Remove(dir_path);
733+
}
734+
}
735+
}
687736
}
688737

689738
struct TestParameters {

0 commit comments

Comments
 (0)