summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--Help/command/configure_file.rst9
-rw-r--r--Help/release/dev/configure_file-user-permissions.rst6
-rw-r--r--Source/CPack/cmCPackGenerator.cxx2
-rw-r--r--Source/cmConfigureFileCommand.cxx109
-rw-r--r--Source/cmCreateTestSourceList.cxx2
-rw-r--r--Source/cmLocalGenerator.cxx4
-rw-r--r--Source/cmMakefile.cxx20
-rw-r--r--Source/cmMakefile.h5
-rw-r--r--Source/cmVisualStudio10TargetGenerator.cxx2
-rw-r--r--Tests/RunCMake/configure_file/RunCMakeTest.cmake7
-rw-r--r--Tests/RunCMake/configure_file/SourcePermissions-result.txt0
-rw-r--r--Tests/RunCMake/configure_file/SourcePermissions-stderr.txt0
-rw-r--r--Tests/RunCMake/configure_file/SourcePermissions.cmake34
-rw-r--r--Tests/RunCMake/configure_file/SourcePermissionsInvalidArg-1-result.txt1
-rw-r--r--Tests/RunCMake/configure_file/SourcePermissionsInvalidArg-1-stderr.txt5
-rw-r--r--Tests/RunCMake/configure_file/SourcePermissionsInvalidArg-1.cmake5
-rw-r--r--Tests/RunCMake/configure_file/SourcePermissionsInvalidArg-2-result.txt1
-rw-r--r--Tests/RunCMake/configure_file/SourcePermissionsInvalidArg-2-stderr.txt5
-rw-r--r--Tests/RunCMake/configure_file/SourcePermissionsInvalidArg-2.cmake5
-rw-r--r--Tests/RunCMake/configure_file/SourcePermissionsInvalidArg-3-result.txt1
-rw-r--r--Tests/RunCMake/configure_file/SourcePermissionsInvalidArg-3-stderr.txt5
-rw-r--r--Tests/RunCMake/configure_file/SourcePermissionsInvalidArg-3.cmake5
-rw-r--r--Tests/RunCMake/configure_file/SourcePermissionsInvalidArg-4-result.txt1
-rw-r--r--Tests/RunCMake/configure_file/SourcePermissionsInvalidArg-4-stderr.txt4
-rw-r--r--Tests/RunCMake/configure_file/SourcePermissionsInvalidArg-4.cmake4
-rw-r--r--Tests/RunCMake/configure_file/SourcePermissionsInvalidArg-5-result.txt1
-rw-r--r--Tests/RunCMake/configure_file/SourcePermissionsInvalidArg-5-stderr.txt4
-rw-r--r--Tests/RunCMake/configure_file/SourcePermissionsInvalidArg-5.cmake6
-rw-r--r--Tests/RunCMake/configure_file/UseSourcePermissions.cmake40
-rw-r--r--Tests/RunCMake/configure_file/sourcefile.txt1
30 files changed, 266 insertions, 28 deletions
diff --git a/Help/command/configure_file.rst b/Help/command/configure_file.rst
index 46d1a05..5d55626 100644
--- a/Help/command/configure_file.rst
+++ b/Help/command/configure_file.rst
@@ -6,8 +6,9 @@ Copy a file to another location and modify its contents.
.. code-block:: cmake
configure_file(<input> <output>
+ [FILE_PERMISSIONS <permissions>...]
[COPYONLY] [ESCAPE_QUOTES] [@ONLY]
- [NO_SOURCE_PERMISSIONS]
+ [NO_SOURCE_PERMISSIONS] [USE_SOURCE_PERMISSIONS]
[NEWLINE_STYLE [UNIX|DOS|WIN32|LF|CRLF] ])
Copies an ``<input>`` file to an ``<output>`` file and substitutes
@@ -72,6 +73,9 @@ The arguments are:
If the path names an existing directory the output file is placed
in that directory with the same file name as the input file.
+``FILE_PERMISSIONS <permissions>...``
+ Use user provided permissions for the output file.
+
``COPYONLY``
Copy the file without replacing any variable references or other
content. This option may not be used with ``NEWLINE_STYLE``.
@@ -88,6 +92,9 @@ The arguments are:
The copied file permissions default to the standard 644 value
(-rw-r--r--).
+``USE_SOURCE_PERMISSIONS``
+ Transfer the file permissions of the original file to the output file.
+
``NEWLINE_STYLE <style>``
Specify the newline style for the output file. Specify
``UNIX`` or ``LF`` for ``\n`` newlines, or specify
diff --git a/Help/release/dev/configure_file-user-permissions.rst b/Help/release/dev/configure_file-user-permissions.rst
new file mode 100644
index 0000000..b757fb1
--- /dev/null
+++ b/Help/release/dev/configure_file-user-permissions.rst
@@ -0,0 +1,6 @@
+configure_file-user-permissions
+-------------------------------
+
+* The :command:`configure_file` command gained a ``USE_SOURCE_PERMISSIONS``
+ and ``FILE_PERMISSIONS`` option to support copying of permissions of source
+ file and specifying user defined permissions.
diff --git a/Source/CPack/cmCPackGenerator.cxx b/Source/CPack/cmCPackGenerator.cxx
index a9fe91c..8b544b4 100644
--- a/Source/CPack/cmCPackGenerator.cxx
+++ b/Source/CPack/cmCPackGenerator.cxx
@@ -1329,7 +1329,7 @@ bool cmCPackGenerator::ConfigureFile(const std::string& inName,
bool copyOnly /* = false */)
{
return this->MakefileMap->ConfigureFile(inName, outName, copyOnly, true,
- false, true) == 1;
+ false) == 1;
}
int cmCPackGenerator::CleanTemporaryDirectory()
diff --git a/Source/cmConfigureFileCommand.cxx b/Source/cmConfigureFileCommand.cxx
index 68322cc..edd261d 100644
--- a/Source/cmConfigureFileCommand.cxx
+++ b/Source/cmConfigureFileCommand.cxx
@@ -3,11 +3,15 @@
#include "cmConfigureFileCommand.h"
#include <set>
+#include <sstream>
#include <cm/string_view>
#include <cmext/string_view>
+#include <sys/types.h>
+
#include "cmExecutionStatus.h"
+#include "cmFSPermissions.h"
#include "cmMakefile.h"
#include "cmMessageType.h"
#include "cmNewLineStyle.h"
@@ -60,7 +64,19 @@ bool cmConfigureFileCommand(std::vector<std::string> const& args,
}
bool copyOnly = false;
bool escapeQuotes = false;
- bool use_source_permissions = true;
+ bool useSourcePermissions = false;
+ bool noSourcePermissions = false;
+ bool filePermissions = false;
+ std::vector<std::string> filePermissionOptions;
+
+ enum class Doing
+ {
+ DoingNone,
+ DoingFilePermissions,
+ DoneFilePermissions
+ };
+
+ Doing doing = Doing::DoingNone;
static std::set<cm::string_view> noopOptions = {
/* Legacy. */
@@ -78,6 +94,9 @@ bool cmConfigureFileCommand(std::vector<std::string> const& args,
bool atOnly = false;
for (unsigned int i = 2; i < args.size(); ++i) {
if (args[i] == "COPYONLY") {
+ if (doing == Doing::DoingFilePermissions) {
+ doing = Doing::DoneFilePermissions;
+ }
copyOnly = true;
if (newLineStyle.IsValid()) {
status.SetError("COPYONLY could not be used in combination "
@@ -85,13 +104,49 @@ bool cmConfigureFileCommand(std::vector<std::string> const& args,
return false;
}
} else if (args[i] == "ESCAPE_QUOTES") {
+ if (doing == Doing::DoingFilePermissions) {
+ doing = Doing::DoneFilePermissions;
+ }
escapeQuotes = true;
} else if (args[i] == "@ONLY") {
+ if (doing == Doing::DoingFilePermissions) {
+ doing = Doing::DoneFilePermissions;
+ }
atOnly = true;
} else if (args[i] == "NO_SOURCE_PERMISSIONS") {
- use_source_permissions = false;
+ if (doing == Doing::DoingFilePermissions) {
+ status.SetError(" given both FILE_PERMISSIONS and "
+ "NO_SOURCE_PERMISSIONS. Only one option allowed.");
+ return false;
+ }
+ noSourcePermissions = true;
+ } else if (args[i] == "USE_SOURCE_PERMISSIONS") {
+ if (doing == Doing::DoingFilePermissions) {
+ status.SetError(" given both FILE_PERMISSIONS and "
+ "USE_SOURCE_PERMISSIONS. Only one option allowed.");
+ return false;
+ }
+ useSourcePermissions = true;
+ } else if (args[i] == "FILE_PERMISSIONS") {
+ if (useSourcePermissions) {
+ status.SetError(" given both FILE_PERMISSIONS and "
+ "USE_SOURCE_PERMISSIONS. Only one option allowed.");
+ return false;
+ }
+ if (noSourcePermissions) {
+ status.SetError(" given both FILE_PERMISSIONS and "
+ "NO_SOURCE_PERMISSIONS. Only one option allowed.");
+ return false;
+ }
+
+ if (doing == Doing::DoingNone) {
+ doing = Doing::DoingFilePermissions;
+ filePermissions = true;
+ }
} else if (noopOptions.find(args[i]) != noopOptions.end()) {
/* Ignore no-op options. */
+ } else if (doing == Doing::DoingFilePermissions) {
+ filePermissionOptions.push_back(args[i]);
} else {
unknown_args += " ";
unknown_args += args[i];
@@ -104,9 +159,53 @@ bool cmConfigureFileCommand(std::vector<std::string> const& args,
status.GetMakefile().IssueMessage(MessageType::AUTHOR_WARNING, msg);
}
- if (!status.GetMakefile().ConfigureFile(
- inputFile, outputFile, copyOnly, atOnly, escapeQuotes,
- use_source_permissions, newLineStyle)) {
+ if (useSourcePermissions && noSourcePermissions) {
+ status.SetError(" given both USE_SOURCE_PERMISSIONS and "
+ "NO_SOURCE_PERMISSIONS. Only one option allowed.");
+ return false;
+ }
+
+ mode_t permisiions = 0;
+
+ if (filePermissions) {
+ if (filePermissionOptions.empty()) {
+ status.SetError(" given FILE_PERMISSIONS without any options.");
+ return false;
+ }
+
+ std::vector<std::string> invalidOptions;
+ for (auto const& e : filePermissionOptions) {
+ if (!cmFSPermissions::stringToModeT(e, permisiions)) {
+ invalidOptions.push_back(e);
+ }
+ }
+
+ if (!invalidOptions.empty()) {
+ std::ostringstream oss;
+ oss << " given invalid permission ";
+ for (auto i = 0u; i < invalidOptions.size(); i++) {
+ if (i == 0u) {
+ oss << "\"" << invalidOptions[i] << "\"";
+ } else {
+ oss << ",\"" << invalidOptions[i] << "\"";
+ }
+ }
+ oss << ".";
+ status.SetError(oss.str());
+ return false;
+ }
+ }
+
+ if (noSourcePermissions) {
+ permisiions |= cmFSPermissions::mode_owner_read;
+ permisiions |= cmFSPermissions::mode_owner_write;
+ permisiions |= cmFSPermissions::mode_group_read;
+ permisiions |= cmFSPermissions::mode_world_read;
+ }
+
+ if (!status.GetMakefile().ConfigureFile(inputFile, outputFile, copyOnly,
+ atOnly, escapeQuotes, permisiions,
+ newLineStyle)) {
status.SetError("Problem configuring file");
return false;
}
diff --git a/Source/cmCreateTestSourceList.cxx b/Source/cmCreateTestSourceList.cxx
index 9c4deea..9d492ba 100644
--- a/Source/cmCreateTestSourceList.cxx
+++ b/Source/cmCreateTestSourceList.cxx
@@ -127,7 +127,7 @@ bool cmCreateTestSourceList(std::vector<std::string> const& args,
mf.AddDefinition("CMAKE_FORWARD_DECLARE_TESTS", forwardDeclareCode);
mf.AddDefinition("CMAKE_FUNCTION_TABLE_ENTIRES", functionMapCode);
bool res = true;
- if (!mf.ConfigureFile(configFile, driver, false, true, false, true)) {
+ if (!mf.ConfigureFile(configFile, driver, false, true, false)) {
res = false;
}
diff --git a/Source/cmLocalGenerator.cxx b/Source/cmLocalGenerator.cxx
index 47e10e0..288172e 100644
--- a/Source/cmLocalGenerator.cxx
+++ b/Source/cmLocalGenerator.cxx
@@ -3768,7 +3768,7 @@ void cmLocalGenerator::GenerateAppleInfoPList(cmGeneratorTarget* target,
cmLGInfoProp(mf, target, "MACOSX_BUNDLE_SHORT_VERSION_STRING");
cmLGInfoProp(mf, target, "MACOSX_BUNDLE_BUNDLE_VERSION");
cmLGInfoProp(mf, target, "MACOSX_BUNDLE_COPYRIGHT");
- mf->ConfigureFile(inFile, fname, false, false, false, true);
+ mf->ConfigureFile(inFile, fname, false, false, false);
}
void cmLocalGenerator::GenerateFrameworkInfoPList(
@@ -3803,7 +3803,7 @@ void cmLocalGenerator::GenerateFrameworkInfoPList(
cmLGInfoProp(mf, target, "MACOSX_FRAMEWORK_IDENTIFIER");
cmLGInfoProp(mf, target, "MACOSX_FRAMEWORK_SHORT_VERSION_STRING");
cmLGInfoProp(mf, target, "MACOSX_FRAMEWORK_BUNDLE_VERSION");
- mf->ConfigureFile(inFile, fname, false, false, false, true);
+ mf->ConfigureFile(inFile, fname, false, false, false);
}
namespace {
diff --git a/Source/cmMakefile.cxx b/Source/cmMakefile.cxx
index 6d1868c..56b7ae1 100644
--- a/Source/cmMakefile.cxx
+++ b/Source/cmMakefile.cxx
@@ -29,15 +29,12 @@
#include "cmsys/FStream.hxx"
#include "cmsys/RegularExpression.hxx"
-#include "cm_sys_stat.h"
-
#include "cmCommandArgumentParserHelper.h"
#include "cmCustomCommand.h"
#include "cmCustomCommandLines.h"
#include "cmExecutionStatus.h"
#include "cmExpandedCommandArgument.h" // IWYU pragma: keep
#include "cmExportBuildFileGenerator.h"
-#include "cmFSPermissions.h"
#include "cmFileLockPool.h"
#include "cmFunctionBlocker.h"
#include "cmGeneratedFileStream.h"
@@ -72,8 +69,6 @@
class cmMessenger;
-using namespace cmFSPermissions;
-
cmDirectoryId::cmDirectoryId(std::string s)
: String(std::move(s))
{
@@ -3850,8 +3845,7 @@ void cmMakefile::ConfigureString(const std::string& input, std::string& output,
int cmMakefile::ConfigureFile(const std::string& infile,
const std::string& outfile, bool copyonly,
bool atOnly, bool escapeQuotes,
- bool use_source_permissions,
- cmNewLineStyle newLine)
+ mode_t permissions, cmNewLineStyle newLine)
{
int res = 1;
if (!this->CanIWriteThisFile(outfile)) {
@@ -3873,12 +3867,8 @@ int cmMakefile::ConfigureFile(const std::string& infile,
// output files that now don't exist.
this->AddCMakeOutputFile(soutfile);
- mode_t perm = 0;
- if (!use_source_permissions) {
- perm = perm | mode_owner_read | mode_owner_write | mode_group_read |
- mode_world_read;
- } else {
- cmSystemTools::GetPermissions(sinfile, perm);
+ if (permissions == 0) {
+ cmSystemTools::GetPermissions(sinfile, permissions);
}
std::string::size_type pos = soutfile.rfind('/');
@@ -3893,7 +3883,7 @@ int cmMakefile::ConfigureFile(const std::string& infile,
cmSystemTools::GetLastSystemError());
return 0;
}
- if (!cmSystemTools::SetPermissions(soutfile, perm)) {
+ if (!cmSystemTools::SetPermissions(soutfile, permissions)) {
this->IssueMessage(MessageType::FATAL_ERROR,
cmSystemTools::GetLastSystemError());
return 0;
@@ -3950,7 +3940,7 @@ int cmMakefile::ConfigureFile(const std::string& infile,
cmSystemTools::GetLastSystemError());
res = 0;
} else {
- if (!cmSystemTools::SetPermissions(soutfile, perm)) {
+ if (!cmSystemTools::SetPermissions(soutfile, permissions)) {
this->IssueMessage(MessageType::FATAL_ERROR,
cmSystemTools::GetLastSystemError());
res = 0;
diff --git a/Source/cmMakefile.h b/Source/cmMakefile.h
index 26ed737..edee02b 100644
--- a/Source/cmMakefile.h
+++ b/Source/cmMakefile.h
@@ -20,6 +20,8 @@
#include "cmsys/RegularExpression.hxx"
+#include "cm_sys_stat.h"
+
#include "cmAlgorithms.h"
#include "cmCustomCommandTypes.h"
#include "cmListFileCache.h"
@@ -659,8 +661,7 @@ public:
*/
int ConfigureFile(const std::string& infile, const std::string& outfile,
bool copyonly, bool atOnly, bool escapeQuotes,
- bool use_source_permissions,
- cmNewLineStyle = cmNewLineStyle());
+ mode_t permissions = 0, cmNewLineStyle = cmNewLineStyle());
/**
* Print a command's invocation
diff --git a/Source/cmVisualStudio10TargetGenerator.cxx b/Source/cmVisualStudio10TargetGenerator.cxx
index 1ca7de8..0d31c5e 100644
--- a/Source/cmVisualStudio10TargetGenerator.cxx
+++ b/Source/cmVisualStudio10TargetGenerator.cxx
@@ -676,7 +676,7 @@ void cmVisualStudio10TargetGenerator::Generate()
cmStrCat(this->DefaultArtifactDir, "\\nasm.props");
ConvertToWindowsSlash(propsLocal);
this->Makefile->ConfigureFile(propsTemplate, propsLocal, false, true,
- true, true);
+ true);
Elem(e1, "Import").Attribute("Project", propsLocal);
}
}
diff --git a/Tests/RunCMake/configure_file/RunCMakeTest.cmake b/Tests/RunCMake/configure_file/RunCMakeTest.cmake
index 71694fb..0a2e3f9 100644
--- a/Tests/RunCMake/configure_file/RunCMakeTest.cmake
+++ b/Tests/RunCMake/configure_file/RunCMakeTest.cmake
@@ -16,6 +16,13 @@ run_cmake(NewLineStyle-WrongArg)
run_cmake(NewLineStyle-ValidArg)
run_cmake(NewLineStyle-COPYONLY)
run_cmake(NoSourcePermissions)
+run_cmake(SourcePermissionsInvalidArg-1)
+run_cmake(SourcePermissionsInvalidArg-2)
+run_cmake(SourcePermissionsInvalidArg-3)
+run_cmake(SourcePermissionsInvalidArg-4)
+run_cmake(SourcePermissionsInvalidArg-5)
+run_cmake(UseSourcePermissions)
+run_cmake(SourcePermissions)
if(RunCMake_GENERATOR MATCHES "Make")
# Use a single build tree for a few tests without cleaning.
diff --git a/Tests/RunCMake/configure_file/SourcePermissions-result.txt b/Tests/RunCMake/configure_file/SourcePermissions-result.txt
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/Tests/RunCMake/configure_file/SourcePermissions-result.txt
diff --git a/Tests/RunCMake/configure_file/SourcePermissions-stderr.txt b/Tests/RunCMake/configure_file/SourcePermissions-stderr.txt
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/Tests/RunCMake/configure_file/SourcePermissions-stderr.txt
diff --git a/Tests/RunCMake/configure_file/SourcePermissions.cmake b/Tests/RunCMake/configure_file/SourcePermissions.cmake
new file mode 100644
index 0000000..50330fc
--- /dev/null
+++ b/Tests/RunCMake/configure_file/SourcePermissions.cmake
@@ -0,0 +1,34 @@
+configure_file(${CMAKE_CURRENT_SOURCE_DIR}/sourcefile.txt
+ ${CMAKE_CURRENT_BINARY_DIR}/sourcefile-source-permissions.txt
+ FILE_PERMISSIONS
+ OWNER_READ OWNER_EXECUTE
+ GROUP_READ GROUP_EXECUTE
+ WORLD_READ
+)
+
+if (UNIX)
+ find_program(STAT_EXECUTABLE NAMES stat)
+ if(NOT STAT_EXECUTABLE)
+ return()
+ endif()
+
+ if (CMAKE_SYSTEM_NAME MATCHES "FreeBSD")
+ execute_process(COMMAND "${STAT_EXECUTABLE}" -f %Lp "${CMAKE_CURRENT_BINARY_DIR}/sourcefile-source-permissions.txt"
+ OUTPUT_VARIABLE output
+ )
+ elseif(CMAKE_SYSTEM_NAME MATCHES "Darwin")
+ execute_process(COMMAND "${STAT_EXECUTABLE}" -f %A "${CMAKE_CURRENT_BINARY_DIR}/sourcefile-source-permissions.txt"
+ OUTPUT_VARIABLE output
+ )
+ else()
+ execute_process(COMMAND "${STAT_EXECUTABLE}" -c %a "${CMAKE_CURRENT_BINARY_DIR}/sourcefile-source-permissions.txt"
+ OUTPUT_VARIABLE output
+ )
+ endif()
+
+ if (NOT output EQUAL "554")
+ message(FATAL_ERROR "configure file has different permissions than "
+ "desired, generated permissions: ${output}")
+ endif()
+
+endif()
diff --git a/Tests/RunCMake/configure_file/SourcePermissionsInvalidArg-1-result.txt b/Tests/RunCMake/configure_file/SourcePermissionsInvalidArg-1-result.txt
new file mode 100644
index 0000000..d00491f
--- /dev/null
+++ b/Tests/RunCMake/configure_file/SourcePermissionsInvalidArg-1-result.txt
@@ -0,0 +1 @@
+1
diff --git a/Tests/RunCMake/configure_file/SourcePermissionsInvalidArg-1-stderr.txt b/Tests/RunCMake/configure_file/SourcePermissionsInvalidArg-1-stderr.txt
new file mode 100644
index 0000000..d483d34
--- /dev/null
+++ b/Tests/RunCMake/configure_file/SourcePermissionsInvalidArg-1-stderr.txt
@@ -0,0 +1,5 @@
+CMake Error at SourcePermissionsInvalidArg-1.cmake:1 \(configure_file\):
+ configure_file given both USE_SOURCE_PERMISSIONS and NO_SOURCE_PERMISSIONS.
+ Only one option allowed.
+Call Stack \(most recent call first\):
+ CMakeLists.txt:3 \(include\)
diff --git a/Tests/RunCMake/configure_file/SourcePermissionsInvalidArg-1.cmake b/Tests/RunCMake/configure_file/SourcePermissionsInvalidArg-1.cmake
new file mode 100644
index 0000000..4969880
--- /dev/null
+++ b/Tests/RunCMake/configure_file/SourcePermissionsInvalidArg-1.cmake
@@ -0,0 +1,5 @@
+configure_file(sourcefile.txt
+ ${CMAKE_CURRENT_BINARY_DIR}/sourcefile.txt
+ NO_SOURCE_PERMISSIONS
+ USE_SOURCE_PERMISSIONS
+)
diff --git a/Tests/RunCMake/configure_file/SourcePermissionsInvalidArg-2-result.txt b/Tests/RunCMake/configure_file/SourcePermissionsInvalidArg-2-result.txt
new file mode 100644
index 0000000..d00491f
--- /dev/null
+++ b/Tests/RunCMake/configure_file/SourcePermissionsInvalidArg-2-result.txt
@@ -0,0 +1 @@
+1
diff --git a/Tests/RunCMake/configure_file/SourcePermissionsInvalidArg-2-stderr.txt b/Tests/RunCMake/configure_file/SourcePermissionsInvalidArg-2-stderr.txt
new file mode 100644
index 0000000..2fcfe58
--- /dev/null
+++ b/Tests/RunCMake/configure_file/SourcePermissionsInvalidArg-2-stderr.txt
@@ -0,0 +1,5 @@
+CMake Error at SourcePermissionsInvalidArg-2.cmake:1 \(configure_file\):
+ configure_file given both FILE_PERMISSIONS and NO_SOURCE_PERMISSIONS. Only
+ one option allowed.
+Call Stack \(most recent call first\):
+ CMakeLists.txt:3 \(include\)
diff --git a/Tests/RunCMake/configure_file/SourcePermissionsInvalidArg-2.cmake b/Tests/RunCMake/configure_file/SourcePermissionsInvalidArg-2.cmake
new file mode 100644
index 0000000..8a3fb87
--- /dev/null
+++ b/Tests/RunCMake/configure_file/SourcePermissionsInvalidArg-2.cmake
@@ -0,0 +1,5 @@
+configure_file(sourcefile.txt
+ ${CMAKE_CURRENT_BINARY_DIR}/sourcefile.txt
+ NO_SOURCE_PERMISSIONS
+ FILE_PERMISSIONS OWNER_READ
+)
diff --git a/Tests/RunCMake/configure_file/SourcePermissionsInvalidArg-3-result.txt b/Tests/RunCMake/configure_file/SourcePermissionsInvalidArg-3-result.txt
new file mode 100644
index 0000000..d00491f
--- /dev/null
+++ b/Tests/RunCMake/configure_file/SourcePermissionsInvalidArg-3-result.txt
@@ -0,0 +1 @@
+1
diff --git a/Tests/RunCMake/configure_file/SourcePermissionsInvalidArg-3-stderr.txt b/Tests/RunCMake/configure_file/SourcePermissionsInvalidArg-3-stderr.txt
new file mode 100644
index 0000000..29fae1b
--- /dev/null
+++ b/Tests/RunCMake/configure_file/SourcePermissionsInvalidArg-3-stderr.txt
@@ -0,0 +1,5 @@
+CMake Error at SourcePermissionsInvalidArg-3.cmake:1 \(configure_file\):
+ configure_file given both FILE_PERMISSIONS and USE_SOURCE_PERMISSIONS.
+ Only one option allowed.
+Call Stack \(most recent call first\):
+ CMakeLists.txt:3 \(include\)
diff --git a/Tests/RunCMake/configure_file/SourcePermissionsInvalidArg-3.cmake b/Tests/RunCMake/configure_file/SourcePermissionsInvalidArg-3.cmake
new file mode 100644
index 0000000..78ecb0f
--- /dev/null
+++ b/Tests/RunCMake/configure_file/SourcePermissionsInvalidArg-3.cmake
@@ -0,0 +1,5 @@
+configure_file(sourcefile.txt
+ ${CMAKE_CURRENT_BINARY_DIR}/sourcefile.txt
+ USE_SOURCE_PERMISSIONS
+ FILE_PERMISSIONS OWNER_READ
+)
diff --git a/Tests/RunCMake/configure_file/SourcePermissionsInvalidArg-4-result.txt b/Tests/RunCMake/configure_file/SourcePermissionsInvalidArg-4-result.txt
new file mode 100644
index 0000000..d00491f
--- /dev/null
+++ b/Tests/RunCMake/configure_file/SourcePermissionsInvalidArg-4-result.txt
@@ -0,0 +1 @@
+1
diff --git a/Tests/RunCMake/configure_file/SourcePermissionsInvalidArg-4-stderr.txt b/Tests/RunCMake/configure_file/SourcePermissionsInvalidArg-4-stderr.txt
new file mode 100644
index 0000000..7d477cb
--- /dev/null
+++ b/Tests/RunCMake/configure_file/SourcePermissionsInvalidArg-4-stderr.txt
@@ -0,0 +1,4 @@
+CMake Error at SourcePermissionsInvalidArg-4.cmake:1 \(configure_file\):
+ configure_file given FILE_PERMISSIONS without any options.
+Call Stack \(most recent call first\):
+ CMakeLists.txt:3 \(include\)
diff --git a/Tests/RunCMake/configure_file/SourcePermissionsInvalidArg-4.cmake b/Tests/RunCMake/configure_file/SourcePermissionsInvalidArg-4.cmake
new file mode 100644
index 0000000..308b455
--- /dev/null
+++ b/Tests/RunCMake/configure_file/SourcePermissionsInvalidArg-4.cmake
@@ -0,0 +1,4 @@
+configure_file(sourcefile.txt
+ ${CMAKE_CURRENT_BINARY_DIR}/sourcefile.txt
+ FILE_PERMISSIONS
+)
diff --git a/Tests/RunCMake/configure_file/SourcePermissionsInvalidArg-5-result.txt b/Tests/RunCMake/configure_file/SourcePermissionsInvalidArg-5-result.txt
new file mode 100644
index 0000000..d00491f
--- /dev/null
+++ b/Tests/RunCMake/configure_file/SourcePermissionsInvalidArg-5-result.txt
@@ -0,0 +1 @@
+1
diff --git a/Tests/RunCMake/configure_file/SourcePermissionsInvalidArg-5-stderr.txt b/Tests/RunCMake/configure_file/SourcePermissionsInvalidArg-5-stderr.txt
new file mode 100644
index 0000000..7cab120
--- /dev/null
+++ b/Tests/RunCMake/configure_file/SourcePermissionsInvalidArg-5-stderr.txt
@@ -0,0 +1,4 @@
+CMake Error at SourcePermissionsInvalidArg-5.cmake:1 \(configure_file\):
+ configure_file given invalid permission "OWNER_RX","GROUP_RWX".
+Call Stack \(most recent call first\):
+ CMakeLists.txt:3 \(include\)
diff --git a/Tests/RunCMake/configure_file/SourcePermissionsInvalidArg-5.cmake b/Tests/RunCMake/configure_file/SourcePermissionsInvalidArg-5.cmake
new file mode 100644
index 0000000..15c6f9a
--- /dev/null
+++ b/Tests/RunCMake/configure_file/SourcePermissionsInvalidArg-5.cmake
@@ -0,0 +1,6 @@
+configure_file(${CMAKE_CURRENT_SOURCE_DIR}/sourcefile.txt
+ ${CMAKE_CURRENT_BINARY_DIR}/sourcefile-source-permissions.txt
+ FILE_PERMISSIONS
+ OWNER_READ OWNER_RX
+ GROUP_RWX
+)
diff --git a/Tests/RunCMake/configure_file/UseSourcePermissions.cmake b/Tests/RunCMake/configure_file/UseSourcePermissions.cmake
new file mode 100644
index 0000000..f7aedd1
--- /dev/null
+++ b/Tests/RunCMake/configure_file/UseSourcePermissions.cmake
@@ -0,0 +1,40 @@
+configure_file(${CMAKE_CURRENT_SOURCE_DIR}/sourcefile.txt
+ ${CMAKE_CURRENT_BINARY_DIR}/sourcefile-use-source-permissions.txt
+ USE_SOURCE_PERMISSIONS
+)
+
+if (UNIX)
+ find_program(STAT_EXECUTABLE NAMES stat)
+ if(NOT STAT_EXECUTABLE)
+ return()
+ endif()
+
+ if (CMAKE_SYSTEM_NAME MATCHES "FreeBSD")
+ execute_process(COMMAND "${STAT_EXECUTABLE}" -f %Lp "${CMAKE_CURRENT_SOURCE_DIR}/sourcefile.txt"
+ OUTPUT_VARIABLE output1
+ )
+ execute_process(COMMAND "${STAT_EXECUTABLE}" -f %Lp "${CMAKE_CURRENT_BINARY_DIR}/sourcefile-use-source-permissions.txt"
+ OUTPUT_VARIABLE output2
+ )
+ elseif (CMAKE_SYSTEM_NAME MATCHES "Darwin")
+ execute_process(COMMAND "${STAT_EXECUTABLE}" -f %A "${CMAKE_CURRENT_SOURCE_DIR}/sourcefile.txt"
+ OUTPUT_VARIABLE output1
+ )
+ execute_process(COMMAND "${STAT_EXECUTABLE}" -f %A "${CMAKE_CURRENT_BINARY_DIR}/sourcefile-use-source-permissions.txt"
+ OUTPUT_VARIABLE output2
+ )
+ else()
+ execute_process(COMMAND "${STAT_EXECUTABLE}" -c %a "${CMAKE_CURRENT_SOURCE_DIR}/sourcefile.txt"
+ OUTPUT_VARIABLE output1
+ )
+ execute_process(COMMAND "${STAT_EXECUTABLE}" -c %a "${CMAKE_CURRENT_BINARY_DIR}/sourcefile-use-source-permissions.txt"
+ OUTPUT_VARIABLE output2
+ )
+ endif()
+
+ if (NOT output1 EQUAL output2)
+ message(FATAL_ERROR "configure file has different permissions source "
+ "permissions: ${output1} generated permissions: ${output2}")
+ endif()
+
+endif()
diff --git a/Tests/RunCMake/configure_file/sourcefile.txt b/Tests/RunCMake/configure_file/sourcefile.txt
new file mode 100644
index 0000000..2296808
--- /dev/null
+++ b/Tests/RunCMake/configure_file/sourcefile.txt
@@ -0,0 +1 @@
+an empty file