Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 7 additions & 0 deletions src/parser.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1142,6 +1142,13 @@ bool is_safe_patch_path(const std::string& path)
if (filesystem::is_absolute(path))
return false;

#ifdef _WIN32
// A colon never appears in a Windows file name. "C:foo" names foo relative to the current
// directory of drive C, and "file:stream" names an alternate data stream of "file".
if (path.find(':') != std::string::npos)
return false;
#endif

// Reject any '..' component, including one which would resolve back inside the working directory
for (std::size_t begin = 0; begin < path.size();) {
std::size_t end = begin;
Expand Down
5 changes: 2 additions & 3 deletions src/patch.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -456,9 +456,8 @@ class DeferredWriter {
std::vector<StagedReplacement> m_deferred_writes;
};

static bool refuse_read_only_file(std::ostream& out, const Options& options, const std::string& output_file)
static bool refuse_read_only_file(std::ostream& out, const Options& options, const std::string& output_file, filesystem::perms permissions)
{
const auto permissions = filesystem::get_permissions(output_file);
const auto write_perm_mask = filesystem::perms::group_write | filesystem::perms::owner_write | filesystem::perms::others_write;
const bool is_read_only = permissions != filesystem::perms::unknown
&& (permissions & write_perm_mask) == filesystem::perms::none;
Expand Down Expand Up @@ -569,7 +568,7 @@ static bool process_parsed_patch(const Options& options, DeferredWriter& deferre
return true;
}

if (refuse_read_only_file(out, options, output_file)) {
if (refuse_read_only_file(out, options, output_file, filesystem::get_permissions(output_file))) {
parse_body_if_needed();
refuse_to_patch(out, mode, output_file, patch, options);
return true;
Expand Down
4 changes: 2 additions & 2 deletions src/system.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -298,8 +298,8 @@ bool is_absolute(const std::string& path)
return true;

#ifdef _WIN32
// A drive letter, with or without a following separator.
return path.size() >= 2 && path[1] == ':';
// A drive letter, with a following separator.
return path.size() >= 3 && path[1] == ':' && is_seperator(path[2]);
#else
return false;
#endif
Expand Down
4 changes: 4 additions & 0 deletions tests/lib/include/patch/test.h
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,10 @@

namespace Patch {

bool file_exists(const std::string& path);

bool create_directory(const std::string& path);

void unset_env(const char* name);

void set_env(const char* name, const char* value);
Expand Down
15 changes: 13 additions & 2 deletions tests/lib/src/test.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,16 @@

namespace Patch {

bool file_exists(const std::string& path)
{
return filesystem::exists(path);
}

bool create_directory(const std::string& path)
{
return filesystem::create_directory(path);
}

enum class Outcome {
Passed,
Failed,
Expand All @@ -32,8 +42,9 @@ static std::string make_temp_directory()
{
#ifdef _WIN32
std::wstring path = L"patch-XXXXXX";
if (_wmktemp_s(&path[0], path.size() + 1) < 0)
throw std::system_error(errno, std::generic_category(), "Unable to create temporary file name");
const auto error = _wmktemp_s(&path[0], path.size() + 1);
if (error != 0)
throw std::system_error(error, std::generic_category(), "Unable to create temporary file name");
if (_wmkdir(path.c_str()) < 0)
throw std::system_error(errno, std::generic_category(), "Unable to make temporary directory");
return to_narrow(path);
Expand Down
Loading
Loading