summaryrefslogtreecommitdiffstats
path: root/Source/cmFileCommand.cxx
diff options
context:
space:
mode:
Diffstat (limited to 'Source/cmFileCommand.cxx')
-rw-r--r--Source/cmFileCommand.cxx160
1 files changed, 160 insertions, 0 deletions
diff --git a/Source/cmFileCommand.cxx b/Source/cmFileCommand.cxx
index 550ad6e..f1169cc 100644
--- a/Source/cmFileCommand.cxx
+++ b/Source/cmFileCommand.cxx
@@ -30,6 +30,7 @@
#include "cmArgumentParser.h"
#include "cmCryptoHash.h"
#include "cmExecutionStatus.h"
+#include "cmFSPermissions.h"
#include "cmFileCopier.h"
#include "cmFileInstaller.h"
#include "cmFileLockPool.h"
@@ -3160,6 +3161,163 @@ bool HandleArchiveExtractCommand(std::vector<std::string> const& args,
return true;
}
+bool ValidateAndConvertPermissions(const std::vector<std::string>& permissions,
+ mode_t& perms, cmExecutionStatus& status)
+{
+ for (const auto& i : permissions) {
+ if (!cmFSPermissions::stringToModeT(i, perms)) {
+ status.SetError(i + " is an invalid permission specifier");
+ cmSystemTools::SetFatalErrorOccured();
+ return false;
+ }
+ }
+ return true;
+}
+
+bool SetPermissions(const std::string& filename, const mode_t& perms,
+ cmExecutionStatus& status)
+{
+ if (!cmSystemTools::SetPermissions(filename, perms)) {
+ status.SetError("Failed to set permissions for " + filename);
+ cmSystemTools::SetFatalErrorOccured();
+ return false;
+ }
+ return true;
+}
+
+bool HandleChmodCommandImpl(std::vector<std::string> const& args, bool recurse,
+ cmExecutionStatus& status)
+{
+ mode_t perms = 0;
+ mode_t fperms = 0;
+ mode_t dperms = 0;
+ cmsys::Glob globber;
+
+ globber.SetRecurse(recurse);
+ globber.SetRecurseListDirs(recurse);
+
+ struct Arguments
+ {
+ std::vector<std::string> Permissions;
+ std::vector<std::string> FilePermissions;
+ std::vector<std::string> DirectoryPermissions;
+ };
+
+ static auto const parser =
+ cmArgumentParser<Arguments>{}
+ .Bind("PERMISSIONS"_s, &Arguments::Permissions)
+ .Bind("FILE_PERMISSIONS"_s, &Arguments::FilePermissions)
+ .Bind("DIRECTORY_PERMISSIONS"_s, &Arguments::DirectoryPermissions);
+
+ std::vector<std::string> pathEntries;
+ std::vector<std::string> keywordsMissingValues;
+ Arguments parsedArgs = parser.Parse(cmMakeRange(args).advance(1),
+ &pathEntries, &keywordsMissingValues);
+
+ // check validity of arguments
+ if (parsedArgs.Permissions.empty() && parsedArgs.FilePermissions.empty() &&
+ parsedArgs.DirectoryPermissions.empty()) // no permissions given
+ {
+ status.SetError("No permissions given");
+ cmSystemTools::SetFatalErrorOccured();
+ return false;
+ }
+
+ if (!parsedArgs.Permissions.empty() && !parsedArgs.FilePermissions.empty() &&
+ !parsedArgs.DirectoryPermissions.empty()) // all keywords are used
+ {
+ status.SetError("Remove either PERMISSIONS or FILE_PERMISSIONS or "
+ "DIRECTORY_PERMISSIONS from the invocation");
+ cmSystemTools::SetFatalErrorOccured();
+ return false;
+ }
+
+ if (!keywordsMissingValues.empty()) {
+ for (const auto& i : keywordsMissingValues) {
+ status.SetError(i + " is not given any arguments");
+ cmSystemTools::SetFatalErrorOccured();
+ }
+ return false;
+ }
+
+ // validate permissions
+ bool validatePermissions =
+ ValidateAndConvertPermissions(parsedArgs.Permissions, perms, status) &&
+ ValidateAndConvertPermissions(parsedArgs.FilePermissions, fperms,
+ status) &&
+ ValidateAndConvertPermissions(parsedArgs.DirectoryPermissions, dperms,
+ status);
+ if (!validatePermissions) {
+ return false;
+ }
+
+ std::vector<std::string> allPathEntries;
+
+ if (recurse) {
+ std::vector<std::string> tempPathEntries;
+ for (const auto& i : pathEntries) {
+ if (cmSystemTools::FileIsDirectory(i)) {
+ globber.FindFiles(i + "/*");
+ tempPathEntries = globber.GetFiles();
+ allPathEntries.insert(allPathEntries.end(), tempPathEntries.begin(),
+ tempPathEntries.end());
+ allPathEntries.emplace_back(i);
+ } else {
+ allPathEntries.emplace_back(i); // We validate path entries below
+ }
+ }
+ } else {
+ allPathEntries = std::move(pathEntries);
+ }
+
+ // chmod
+ for (const auto& i : allPathEntries) {
+ if (!(cmSystemTools::FileExists(i) || cmSystemTools::FileIsDirectory(i))) {
+ status.SetError(cmStrCat("does not exist:\n ", i));
+ cmSystemTools::SetFatalErrorOccured();
+ return false;
+ }
+
+ if (cmSystemTools::FileExists(i, true)) {
+ bool success = true;
+ const mode_t& filePermissions =
+ parsedArgs.FilePermissions.empty() ? perms : fperms;
+ if (filePermissions) {
+ success = SetPermissions(i, filePermissions, status);
+ }
+ if (!success) {
+ return false;
+ }
+ }
+
+ else if (cmSystemTools::FileIsDirectory(i)) {
+ bool success = true;
+ const mode_t& directoryPermissions =
+ parsedArgs.DirectoryPermissions.empty() ? perms : dperms;
+ if (directoryPermissions) {
+ success = SetPermissions(i, directoryPermissions, status);
+ }
+ if (!success) {
+ return false;
+ }
+ }
+ }
+
+ return true;
+}
+
+bool HandleChmodCommand(std::vector<std::string> const& args,
+ cmExecutionStatus& status)
+{
+ return HandleChmodCommandImpl(args, false, status);
+}
+
+bool HandleChmodRecurseCommand(std::vector<std::string> const& args,
+ cmExecutionStatus& status)
+{
+ return HandleChmodCommandImpl(args, true, status);
+}
+
} // namespace
bool cmFileCommand(std::vector<std::string> const& args,
@@ -3216,6 +3374,8 @@ bool cmFileCommand(std::vector<std::string> const& args,
{ "CONFIGURE"_s, HandleConfigureCommand },
{ "ARCHIVE_CREATE"_s, HandleArchiveCreateCommand },
{ "ARCHIVE_EXTRACT"_s, HandleArchiveExtractCommand },
+ { "CHMOD"_s, HandleChmodCommand },
+ { "CHMOD_RECURSE"_s, HandleChmodRecurseCommand },
};
return subcommand(args[0], args, status);