Skip to content

Commit cd5264a

Browse files
authored
Use absolute paths for archives and filesystems (#437)
1 parent 7f8beb1 commit cd5264a

21 files changed

Lines changed: 205 additions & 56 deletions

src/odr/exceptions.cpp

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -126,4 +126,7 @@ DecryptionFailed::DecryptionFailed()
126126
NotEncryptedError::NotEncryptedError()
127127
: std::runtime_error("not encrypted error") {}
128128

129+
InvalidPath::InvalidPath(const std::string &message)
130+
: std::runtime_error("invalid path: " + message) {}
131+
129132
} // namespace odr

src/odr/exceptions.hpp

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -215,4 +215,9 @@ struct NotEncryptedError : public std::runtime_error {
215215
explicit NotEncryptedError();
216216
};
217217

218+
/// @brief Invalid path
219+
struct InvalidPath : public std::runtime_error {
220+
explicit InvalidPath(const std::string &message);
221+
};
222+
218223
} // namespace odr

src/odr/internal/cfb/cfb_archive.cpp

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,6 @@ std::shared_ptr<abstract::Filesystem> CfbArchive::as_filesystem() const {
3434

3535
void CfbArchive::save(std::ostream &out) const {
3636
(void)out;
37-
3837
throw UnsupportedOperation();
3938
}
4039

src/odr/internal/common/filesystem.cpp

Lines changed: 100 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,11 @@ class SystemFileWalker final : public abstract::FileWalker {
1919
public:
2020
SystemFileWalker(Path root, const Path &path)
2121
: m_root{std::move(root)},
22-
m_iterator{std::filesystem::recursive_directory_iterator(path)} {}
22+
m_iterator{std::filesystem::recursive_directory_iterator(path)} {
23+
if (path.relative()) {
24+
throw InvalidPath("SystemFileWalker: path must be absolute");
25+
}
26+
}
2327

2428
[[nodiscard]] std::unique_ptr<FileWalker> clone() const final {
2529
return std::make_unique<SystemFileWalker>(*this);
@@ -69,40 +73,77 @@ Path SystemFilesystem::to_system_path_(const Path &path) const {
6973
}
7074

7175
bool SystemFilesystem::exists(const Path &path) const {
76+
if (path.relative()) {
77+
throw InvalidPath("SystemFilesystem::exists: path must be absolute");
78+
}
79+
7280
return std::filesystem::exists(to_system_path_(path));
7381
}
7482

7583
bool SystemFilesystem::is_file(const Path &path) const {
84+
if (path.relative()) {
85+
throw InvalidPath("SystemFilesystem::is_file: path must be absolute");
86+
}
87+
7688
return std::filesystem::is_regular_file(to_system_path_(path));
7789
}
7890

7991
bool SystemFilesystem::is_directory(const Path &path) const {
92+
if (path.relative()) {
93+
throw InvalidPath("SystemFilesystem::is_directory: path must be absolute");
94+
}
95+
8096
return std::filesystem::is_directory(to_system_path_(path));
8197
}
8298

8399
std::unique_ptr<abstract::FileWalker>
84100
SystemFilesystem::file_walker(const Path &path) const {
101+
if (path.relative()) {
102+
throw InvalidPath("SystemFilesystem::file_walker: path must be absolute");
103+
}
104+
85105
return std::make_unique<SystemFileWalker>(m_root, to_system_path_(path));
86106
}
87107

88108
std::shared_ptr<abstract::File> SystemFilesystem::open(const Path &path) const {
109+
if (path.relative()) {
110+
throw InvalidPath("SystemFilesystem::open: path must be absolute");
111+
}
112+
89113
return std::make_unique<DiskFile>(to_system_path_(path));
90114
}
91115

92116
std::unique_ptr<std::ostream> SystemFilesystem::create_file(const Path &path) {
117+
if (path.relative()) {
118+
throw InvalidPath("SystemFilesystem::create_file: path must be absolute");
119+
}
120+
93121
return std::make_unique<std::ofstream>(
94122
util::file::create(to_system_path_(path).string()));
95123
}
96124

97125
bool SystemFilesystem::create_directory(const Path &path) {
126+
if (path.relative()) {
127+
throw InvalidPath(
128+
"SystemFilesystem::create_directory: path must be absolute");
129+
}
130+
98131
return std::filesystem::create_directory(to_system_path_(path));
99132
}
100133

101134
bool SystemFilesystem::remove(const Path &path) {
135+
if (path.relative()) {
136+
throw InvalidPath("SystemFilesystem::remove: path must be absolute");
137+
}
138+
102139
return std::filesystem::remove(to_system_path_(path));
103140
}
104141

105142
bool SystemFilesystem::copy(const Path &from, const Path &to) {
143+
if (from.relative() || to.relative()) {
144+
throw InvalidPath("SystemFilesystem::copy: paths must be absolute");
145+
}
146+
106147
std::error_code error_code;
107148
std::filesystem::copy(to_system_path_(from), to_system_path_(to), error_code);
108149
if (error_code) {
@@ -113,6 +154,10 @@ bool SystemFilesystem::copy(const Path &from, const Path &to) {
113154

114155
std::shared_ptr<abstract::File>
115156
SystemFilesystem::copy(const abstract::File &from, const Path &to) {
157+
if (to.relative()) {
158+
throw InvalidPath("SystemFilesystem::copy: path must be absolute");
159+
}
160+
116161
auto istream = from.stream();
117162
auto ostream = create_file(to_system_path_(to));
118163

@@ -123,10 +168,18 @@ SystemFilesystem::copy(const abstract::File &from, const Path &to) {
123168

124169
std::shared_ptr<abstract::File>
125170
SystemFilesystem::copy(std::shared_ptr<abstract::File> from, const Path &to) {
171+
if (to.relative()) {
172+
throw InvalidPath("SystemFilesystem::copy: path must be absolute");
173+
}
174+
126175
return copy(*from, to_system_path_(to));
127176
}
128177

129178
bool SystemFilesystem::move(const Path &from, const Path &to) {
179+
if (from.relative() || to.relative()) {
180+
throw InvalidPath("SystemFilesystem::move: paths must be absolute");
181+
}
182+
130183
std::error_code error_code;
131184
std::filesystem::rename(to_system_path_(from), to_system_path_(to),
132185
error_code);
@@ -142,6 +195,10 @@ class VirtualFileWalker final : public abstract::FileWalker {
142195
VirtualFileWalker(
143196
const Path &root,
144197
const std::map<Path, std::shared_ptr<abstract::File>> &files) {
198+
if (root.relative()) {
199+
throw InvalidPath("VirtualFileWalker: path must be absolute");
200+
}
201+
145202
for (auto &&f : files) {
146203
if (f.first.ancestor_of(root)) {
147204
m_files[f.first] = f.second;
@@ -195,10 +252,18 @@ class VirtualFileWalker final : public abstract::FileWalker {
195252
} // namespace
196253

197254
bool VirtualFilesystem::exists(const Path &path) const {
255+
if (path.relative()) {
256+
throw InvalidPath("VirtualFilesystem::exists: path must be absolute");
257+
}
258+
198259
return m_files.find(path) != std::end(m_files);
199260
}
200261

201262
bool VirtualFilesystem::is_file(const Path &path) const {
263+
if (path.relative()) {
264+
throw InvalidPath("VirtualFilesystem::is_file: path must be absolute");
265+
}
266+
202267
auto file_it = m_files.find(path);
203268
if (file_it == std::end(m_files)) {
204269
return false;
@@ -207,6 +272,10 @@ bool VirtualFilesystem::is_file(const Path &path) const {
207272
}
208273

209274
bool VirtualFilesystem::is_directory(const Path &path) const {
275+
if (path.relative()) {
276+
throw InvalidPath("VirtualFilesystem::is_directory: path must be absolute");
277+
}
278+
210279
auto file_it = m_files.find(path);
211280
if (file_it == std::end(m_files)) {
212281
return false;
@@ -216,11 +285,19 @@ bool VirtualFilesystem::is_directory(const Path &path) const {
216285

217286
std::unique_ptr<abstract::FileWalker>
218287
VirtualFilesystem::file_walker(const Path &path) const {
219-
return std::make_unique<VirtualFileWalker>(std::move(path), m_files);
288+
if (path.relative()) {
289+
throw InvalidPath("VirtualFilesystem::file_walker: path must be absolute");
290+
}
291+
292+
return std::make_unique<VirtualFileWalker>(path, m_files);
220293
}
221294

222295
std::shared_ptr<abstract::File>
223296
VirtualFilesystem::open(const Path &path) const {
297+
if (path.relative()) {
298+
throw InvalidPath("VirtualFilesystem::open: path must be absolute");
299+
}
300+
224301
auto file_it = m_files.find(path);
225302
if (file_it == std::end(m_files)) {
226303
return {};
@@ -234,6 +311,11 @@ VirtualFilesystem::create_file(const Path & /*path*/) {
234311
}
235312

236313
bool VirtualFilesystem::create_directory(const Path &path) {
314+
if (path.relative()) {
315+
throw InvalidPath(
316+
"VirtualFilesystem::create_directory: path must be absolute");
317+
}
318+
237319
if (exists(path)) {
238320
return false;
239321
}
@@ -242,6 +324,10 @@ bool VirtualFilesystem::create_directory(const Path &path) {
242324
}
243325

244326
bool VirtualFilesystem::remove(const Path &path) {
327+
if (path.relative()) {
328+
throw InvalidPath("VirtualFilesystem::remove: path must be absolute");
329+
}
330+
245331
auto file_it = m_files.find(path);
246332
if (file_it == std::end(m_files)) {
247333
return false;
@@ -251,6 +337,10 @@ bool VirtualFilesystem::remove(const Path &path) {
251337
}
252338

253339
bool VirtualFilesystem::copy(const Path &from, const Path &to) {
340+
if (from.relative() || to.relative()) {
341+
throw InvalidPath("VirtualFilesystem::copy: paths must be absolute");
342+
}
343+
254344
// TODO what about directories?
255345

256346
auto from_it = m_files.find(from);
@@ -271,6 +361,10 @@ VirtualFilesystem::copy(const abstract::File & /*from*/, const Path & /*to*/) {
271361

272362
std::shared_ptr<abstract::File>
273363
VirtualFilesystem::copy(std::shared_ptr<abstract::File> from, const Path &to) {
364+
if (to.relative()) {
365+
throw InvalidPath("VirtualFilesystem::copy: path must be absolute");
366+
}
367+
274368
if (exists(to)) {
275369
return {};
276370
}
@@ -279,6 +373,10 @@ VirtualFilesystem::copy(std::shared_ptr<abstract::File> from, const Path &to) {
279373
}
280374

281375
bool VirtualFilesystem::move(const Path &from, const Path &to) {
376+
if (from.relative() || to.relative()) {
377+
throw InvalidPath("VirtualFilesystem::move: paths must be absolute");
378+
}
379+
282380
if (!copy(from, to)) {
283381
return false;
284382
}

src/odr/internal/common/path.cpp

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -186,7 +186,11 @@ Path Path::join(const Path &b) const {
186186
}
187187

188188
Path Path::rebase(const Path &b) const {
189-
Path result = Path(m_absolute ? "/" : "");
189+
if (m_absolute != b.m_absolute) {
190+
throw std::invalid_argument("cannot rebase absolute and relative path");
191+
}
192+
193+
Path result = Path("");
190194
auto common_root = this->common_root(b);
191195

192196
Path sub_a;
@@ -217,7 +221,7 @@ Path Path::rebase(const Path &b) const {
217221
result.join_("..");
218222
}
219223

220-
for (auto part : sub_a) {
224+
for (const auto &part : sub_a) {
221225
result.join_(part);
222226
}
223227

@@ -251,7 +255,7 @@ Path Path::common_root(const Path &b) const {
251255

252256
Path::Iterator Path::begin() const { return Iterator(*this); }
253257

254-
Path::Iterator Path::end() const { return Iterator(); }
258+
Path::Iterator Path::end() const { return {}; }
255259

256260
Path::Iterator::Iterator() : m_path{nullptr}, m_begin{std::string::npos} {}
257261

src/odr/internal/html/filesystem.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -65,7 +65,7 @@ class HtmlServiceImpl : public HtmlService {
6565
HtmlResources write_filesystem(HtmlWriter &out) const {
6666
HtmlResources resources;
6767

68-
auto file_walker = m_filesystem.file_walker("");
68+
auto file_walker = m_filesystem.file_walker("/");
6969

7070
out.write_begin();
7171

src/odr/internal/odf/odf_crypto.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -170,7 +170,7 @@ odf::decrypt(const std::shared_ptr<abstract::ReadableFilesystem> &filesystem,
170170
throw NotEncryptedError();
171171
}
172172

173-
if (auto it = manifest.entries.find(common::Path("encrypted-package"));
173+
if (auto it = manifest.entries.find(common::Path("/encrypted-package"));
174174
it != std::end(manifest.entries)) {
175175
try {
176176
const std::string start_key = odf::start_key(it->second, password);

src/odr/internal/odf/odf_document.cpp

Lines changed: 11 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -18,10 +18,10 @@ Document::Document(const FileType file_type, const DocumentType document_type,
1818
std::shared_ptr<abstract::ReadableFilesystem> filesystem)
1919
: common::TemplateDocument<Element>(file_type, document_type,
2020
std::move(filesystem)) {
21-
m_content_xml = util::xml::parse(*m_filesystem, common::Path("content.xml"));
21+
m_content_xml = util::xml::parse(*m_filesystem, common::Path("/content.xml"));
2222

23-
if (m_filesystem->exists(common::Path("styles.xml"))) {
24-
m_styles_xml = util::xml::parse(*m_filesystem, common::Path("styles.xml"));
23+
if (m_filesystem->exists(common::Path("/styles.xml"))) {
24+
m_styles_xml = util::xml::parse(*m_filesystem, common::Path("/styles.xml"));
2525
}
2626

2727
m_root_element = parse_tree(
@@ -43,33 +43,33 @@ void Document::save(const common::Path &path) const {
4343
zip::ZipArchive archive;
4444

4545
// `mimetype` has to be the first file and uncompressed
46-
if (m_filesystem->is_file(common::Path("mimetype"))) {
47-
archive.insert_file(std::end(archive), common::Path("mimetype"),
48-
m_filesystem->open(common::Path("mimetype")), 0);
46+
if (m_filesystem->is_file(common::Path("/mimetype"))) {
47+
archive.insert_file(std::end(archive), common::Path("/mimetype"),
48+
m_filesystem->open(common::Path("/mimetype")), 0);
4949
}
5050

51-
for (auto walker = m_filesystem->file_walker(common::Path(""));
51+
for (auto walker = m_filesystem->file_walker(common::Path("/"));
5252
!walker->end(); walker->next()) {
5353
auto p = walker->path();
54-
if (p == common::Path("mimetype")) {
54+
if (p == common::Path("/mimetype")) {
5555
continue;
5656
}
5757
if (m_filesystem->is_directory(p)) {
5858
archive.insert_directory(std::end(archive), p);
5959
continue;
6060
}
61-
if (p == common::Path("content.xml")) {
61+
if (p == common::Path("/content.xml")) {
6262
// TODO stream
6363
std::stringstream out;
6464
m_content_xml.print(out, "", pugi::format_raw);
6565
auto tmp = std::make_shared<common::MemoryFile>(out.str());
6666
archive.insert_file(std::end(archive), p, tmp);
6767
continue;
6868
}
69-
if (p == common::Path("META-INF/manifest.xml")) {
69+
if (p == common::Path("/META-INF/manifest.xml")) {
7070
// TODO
7171
auto manifest = util::xml::parse(*m_filesystem,
72-
common::Path("META-INF/manifest.xml"));
72+
common::Path("/META-INF/manifest.xml"));
7373

7474
for (auto &&node : manifest.select_nodes("//manifest:encryption-data")) {
7575
node.node().parent().remove_child(node.node());

src/odr/internal/odf/odf_element.cpp

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -441,7 +441,11 @@ bool Image::is_internal(const abstract::Document *document) const {
441441
return false;
442442
}
443443
try {
444-
return doc->as_filesystem()->is_file(common::Path(href(document)));
444+
common::Path path(href(document));
445+
if (path.relative()) {
446+
path = common::Path("/").join(path);
447+
}
448+
return doc->as_filesystem()->is_file(path);
445449
} catch (...) {
446450
}
447451
return false;
@@ -452,7 +456,11 @@ std::optional<odr::File> Image::file(const abstract::Document *document) const {
452456
if (!doc || !is_internal(document)) {
453457
return {};
454458
}
455-
return File(doc->as_filesystem()->open(common::Path(href(document))));
459+
common::Path path(href(document));
460+
if (path.relative()) {
461+
path = common::Path("/").join(path);
462+
}
463+
return File(doc->as_filesystem()->open(path));
456464
}
457465

458466
std::string Image::href(const abstract::Document *) const {

0 commit comments

Comments
 (0)