CARLA
Loading...
Searching...
No Matches
FileTransfer.cpp
Go to the documentation of this file.
1// Copyright (c) 2026 Computer Vision Center (CVC) at the Universitat Autonoma
2// de Barcelona (UAB).
3//
4// This work is licensed under the terms of the MIT license.
5// For a copy, see <https://opensource.org/licenses/MIT>.
6
7#include "FileTransfer.h"
8#include "carla/Version.h"
9
10#include <fstream>
11#include <cstdlib>
12
13namespace fs = std::filesystem;
14
15namespace carla::client {
16
17 static fs::path CachePath = [] {
18 constexpr char OverridePathEV[] = "CARLA_CACHE_DIR";
19 constexpr char HomePathEV[] =
20#ifdef _WIN32
21 "USERPROFILE";
22#else
23 "HOME";
24#endif
25 const char* override_path = std::getenv(OverridePathEV);
26 if (override_path != NULL)
27 return fs::path(override_path);
28 fs::path path = std::getenv(HomePathEV);
29 path /= "carlaCache";
30 return fs::absolute(path);
31 }();
32
33 // The path arriving here comes from the server, so it must never be trusted
34 // to stay inside the cache. Normalize it and drop any root, drive or leading
35 // ".." components: a hostile or buggy server (e.g. one sending
36 // "../../../CarlaUnreal/Content/...") can then neither write nor read
37 // outside the cache root, while legitimate nested paths such as
38 // "Config/Town10HD_Opt/Vehicles.xml" resolve unchanged. Escaping paths are
39 // remapped instead of rejected so that both WriteFile and ReadFile agree on
40 // the same in-cache location.
41 static fs::path SanitizeRelativePath(std::string_view file) {
42 auto normalized = fs::path(file).lexically_normal().relative_path();
43 fs::path clean;
44 for (const auto &part : normalized)
45 if (part != ".." && part != ".")
46 clean /= part;
47 return clean;
48 }
49
50 bool FileTransfer::SetFilesBaseFolder(std::string_view path) {
51 if (path.empty())
52 return false;
53 CachePath = path;
54 return true;
55 }
56
58 return CachePath.string();
59 }
60
61 bool FileTransfer::FileExists(std::string_view file) {
62 auto fullpath = CachePath;
63 fullpath /= carla::version();
64 fullpath /= SanitizeRelativePath(file);
65 return fs::is_regular_file(fullpath);
66 }
67
68 bool FileTransfer::WriteFile(std::string_view path, std::vector<uint8_t> content) {
69 auto writePath = CachePath;
70 writePath /= carla::version();
71 writePath /= SanitizeRelativePath(path);
72
73 // Validate and create the file path
74 {
75 auto parent = writePath.parent_path();
76 if (fs::exists(parent))
77 {
78 if (!fs::is_directory(parent))
79 return false;
80 }
81 else
82 {
83 if (!fs::create_directories(parent))
84 return false;
85 }
86 }
87
88 // Open the file to truncate it in binary mode
89 std::ofstream out(
90 writePath,
91 std::ios::trunc | std::ios::binary);
92
93 if (!out.good())
94 return false;
95
96 // Write the content on and close it
97 for (auto file : content) {
98 out << file;
99 }
100 out.close();
101
102 return true;
103 }
104
105 std::vector<uint8_t> FileTransfer::ReadFile(std::string_view path) {
106 auto fullpath = CachePath;
107 fullpath /= carla::version();
108 fullpath /= SanitizeRelativePath(path);
109 std::ifstream file(fullpath, std::ios::binary);
110 std::vector<uint8_t> content(std::istreambuf_iterator<char>(file), {});
111 return content;
112 }
113} // namespace carla::client
static std::vector< uint8_t > ReadFile(std::string_view path)
static bool FileExists(std::string_view file)
static bool SetFilesBaseFolder(std::string_view path)
static std::string GetFilesBaseFolder()
static bool WriteFile(std::string_view path, std::vector< uint8_t > content)
static fs::path SanitizeRelativePath(std::string_view file)
static fs::path CachePath