Skip to content

Commit b11544a

Browse files
author
Martin Krulis
committed
Modifying copy_dir to ignore symlinks when copying sandbox data (fixes #31).
1 parent 218f9b5 commit b11544a

6 files changed

Lines changed: 81 additions & 17 deletions

File tree

CMakeLists.txt

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -95,12 +95,12 @@ else()
9595
include_directories(AFTER, vendor/libarchive/libarchive)
9696
endif()
9797

98-
# Use C++11
98+
# Use C++17
9999
if(UNIX)
100100
#-Wno-deprecated-declarations hides warning in yaml-cpp (using std::auto_ptr)
101-
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11 -Wall -Wno-deprecated-declarations")
101+
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++17 -Wall -Wno-deprecated-declarations")
102102
elseif(MSVC)
103-
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /EHsc /MP /D NOMINMAX")
103+
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /std:c++17 /EHsc /MP /D NOMINMAX")
104104
endif()
105105

106106

appveyor.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -81,7 +81,7 @@ before_build:
8181
8282
echo Running cmake...
8383
84-
cmake -G "Visual Studio 14 2015" -DBOOST_ROOT=C:\deps\boost -DCURL_LIBRARY=C:\deps\curl\lib\libcurl.lib -DCURL_INCLUDE_DIR=C:\deps\curl\include -DZMQ_LIBRARY_DIR=C:\deps\libzmq\lib -DZMQ_INCLUDE_DIR=C:\deps\libzmq\include .
84+
cmake -G "Visual Studio 15 2017" -DBOOST_ROOT=C:\deps\boost -DCURL_LIBRARY=C:\deps\curl\lib\libcurl.lib -DCURL_INCLUDE_DIR=C:\deps\curl\include -DZMQ_LIBRARY_DIR=C:\deps\libzmq\lib -DZMQ_INCLUDE_DIR=C:\deps\libzmq\include .
8585
build:
8686
project: ./ALL_BUILD.vcxproj
8787
parallel: true

recodex-worker.spec

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
11
%define name recodex-worker
22
%define short_name worker
33
%define version 1.7.1
4-
%define unmangled_version 45f6b839084c1793a5092f9d035c482ea259fa80
5-
%define release 1
4+
%define unmangled_version 483a474e5c2098588958e7c7e48eff4f25516aca
5+
%define release 2
66

77
%define spdlog_name spdlog
88
%define spdlog_version 0.13.0

src/helpers/filesystem.cpp

Lines changed: 71 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,35 +1,97 @@
11
#include "filesystem.h"
22
#include <iostream>
3+
#include <map>
34

4-
void helpers::copy_directory(const fs::path &src, const fs::path &dest)
5+
/**
6+
* Try to find matching hardlink in hardlinks map. If src is found in the map, dest is filled with corresponding file.
7+
* @param hardlinks the hardlinks map (src -> dst)
8+
* @param src source path being looked up in hardlinks using equvalent func
9+
* @param dest output arg which is filled in case of success
10+
* @return true if the hardlink match is found
11+
*/
12+
bool find_matching_hadlink(std::map<fs::path, fs::path> &hardlinks, const fs::path &src, fs::path &dest)
13+
{
14+
for (auto& [s, d] : hardlinks) {
15+
if (fs::equivalent(s, src)) { // both paths point to the same data on the disk (same hardlinks)
16+
dest = d;
17+
return true;
18+
}
19+
}
20+
return false;
21+
}
22+
23+
void copy_diretory_internal(const fs::path &src, const fs::path &dest, bool skip_symlinks, std::map<fs::path, fs::path> &hardlinks)
524
{
625
try {
26+
// routine checks
727
if (!fs::exists(src)) {
8-
throw filesystem_exception(
28+
throw helpers::filesystem_exception(
929
"helpers::copy_directory: Source directory does not exist '" + src.string() + "'");
10-
} else if (!fs::is_directory(fs::symlink_status(src))) {
11-
throw filesystem_exception(
30+
}
31+
32+
if (skip_symlinks && fs::is_symlink(src)) {
33+
return;
34+
}
35+
36+
if (!fs::is_directory(fs::symlink_status(src))) {
37+
throw helpers::filesystem_exception(
1238
"helpers::copy_directory: Source directory is not a directory '" + src.string() + "'");
13-
} else if (!fs::exists(dest) && !fs::create_directories(dest)) {
14-
throw filesystem_exception(
39+
}
40+
41+
if (!fs::exists(dest) && !fs::create_directories(dest)) {
42+
throw helpers::filesystem_exception(
1543
"helpers::copy_directory: Destination directory cannot be created '" + dest.string() + "'");
1644
}
1745

46+
// proceed with copying
1847
fs::directory_iterator endit;
1948
for (fs::directory_iterator it(src); it != endit; ++it) {
49+
auto srcPath = it->path();
50+
auto destPath = dest / it->path().filename();
51+
52+
if (skip_symlinks && fs::is_symlink(srcPath)) {
53+
continue;
54+
}
55+
2056
if (fs::is_directory(it->symlink_status())) {
21-
helpers::copy_directory(it->path(), dest / it->path().filename());
57+
copy_diretory_internal(srcPath, destPath, skip_symlinks, hardlinks);
2258
} else {
23-
fs::copy(it->path(), dest / it->path().filename());
59+
// a file may be either copied or hardlinked
60+
if (!fs::is_symlink(srcPath) && fs::hard_link_count(srcPath) > 1) {
61+
fs::path destPathHardlink;
62+
if (find_matching_hadlink(hardlinks, it->path(), destPathHardlink)) {
63+
// another file refering to the same data already exists in dest directory
64+
fs::create_hard_link(destPathHardlink, destPath);
65+
continue; // move to next file, hardlink replaced copying
66+
} else {
67+
// this is the first time we encoutered this data, lets register them in hardlinks map
68+
hardlinks.emplace(std::make_pair(it->path(), destPath));
69+
}
70+
}
71+
72+
// no hardlink created, lets proceed with copying
73+
fs::copy(it->path(), destPath);
2474
}
2575
}
2676
} catch (fs::filesystem_error &e) {
27-
throw filesystem_exception("helpers::copy_directory: Error in copying directories: " + std::string(e.what()));
77+
throw helpers::filesystem_exception("helpers::copy_directory: Error in copying directories: " + std::string(e.what()));
2878
}
2979

3080
return;
3181
}
3282

83+
void helpers::copy_directory(const fs::path &src, const fs::path &dest, bool skip_symlinks)
84+
{
85+
/*
86+
* Hardlinks map provide mapping between files in src and dest which have been harlinked.
87+
* Everytime a file with > 1 hadlink count is copied from src to dest, it is registered here.
88+
* When files with > 1 hardlinks are encountered, this map is searched and if match is found
89+
* the new file is hadlinked inside dest instead of coping it from src.
90+
*/
91+
std::map<fs::path, fs::path> hardlinks;
92+
::copy_diretory_internal(src, dest, skip_symlinks, hardlinks);
93+
}
94+
3395
fs::path helpers::normalize_path(const fs::path &path)
3496
{
3597
// prepare root and path chunks

src/helpers/filesystem.h

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,9 +14,11 @@ namespace helpers
1414
* Recursively copy directory from source to destination.
1515
* @param src source directory which content will be copied into @a dest
1616
* @param dest destination path which should not exist
17+
* @param skip_symlinks if true, all symlinks in src will be ignored
18+
* (security feature when dealing with sandboxed data)
1719
* @throws filesystem_exception with approprite description
1820
*/
19-
void copy_directory(const fs::path &src, const fs::path &dest);
21+
void copy_directory(const fs::path &src, const fs::path &dest, bool skip_symlinks = false);
2022

2123
/**
2224
* Normalize dots and double dots from given path.

src/sandbox/isolate_sandbox.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ namespace
2525
void move_or_throw(std::shared_ptr<spdlog::logger> logger, const std::string &from, const std::string &to)
2626
{
2727
try {
28-
helpers::copy_directory(from, to);
28+
helpers::copy_directory(from, to, true); // true = skip symlinks for security reasons
2929
} catch (fs::filesystem_error &e) {
3030
log_and_throw(logger, "Failed moving ", from, " to ", to, ", error: ", e.what());
3131
}

0 commit comments

Comments
 (0)