summaryrefslogtreecommitdiffstats
path: root/Source/cmFileCommand.cxx
diff options
context:
space:
mode:
Diffstat (limited to 'Source/cmFileCommand.cxx')
-rw-r--r--Source/cmFileCommand.cxx1082
1 files changed, 2 insertions, 1080 deletions
diff --git a/Source/cmFileCommand.cxx b/Source/cmFileCommand.cxx
index a2018c3..d2bc851 100644
--- a/Source/cmFileCommand.cxx
+++ b/Source/cmFileCommand.cxx
@@ -3,7 +3,6 @@
#include "cmFileCommand.h"
#include "cm_kwiml.h"
-#include "cmsys/Directory.hxx"
#include "cmsys/FStream.hxx"
#include "cmsys/Glob.hxx"
#include "cmsys/RegularExpression.hxx"
@@ -16,20 +15,18 @@
#include <sstream>
#include <stdio.h>
#include <stdlib.h>
-#include <string.h>
#include <utility>
#include <vector>
#include "cmAlgorithms.h"
#include "cmCommandArgumentsHelper.h"
#include "cmCryptoHash.h"
-#include "cmFSPermissions.h"
+#include "cmFileCopier.h"
+#include "cmFileInstaller.h"
#include "cmFileLockPool.h"
-#include "cmFileTimeComparison.h"
#include "cmGeneratorExpression.h"
#include "cmGlobalGenerator.h"
#include "cmHexFileConverter.h"
-#include "cmInstallType.h"
#include "cmListFileCache.h"
#include "cmMakefile.h"
#include "cmMessageType.h"
@@ -56,8 +53,6 @@
class cmSystemToolsFileTime;
-using namespace cmFSPermissions;
-
#if defined(_WIN32)
// libcurl doesn't support file:// urls for unicode filenames on Windows.
// Convert string from UTF-8 to ACP if this is a file:// URL.
@@ -1058,1085 +1053,12 @@ bool cmFileCommand::HandleDifferentCommand(
return true;
}
-// File installation helper class.
-struct cmFileCopier
-{
- cmFileCopier(cmFileCommand* command, const char* name = "COPY")
- : FileCommand(command)
- , Makefile(command->GetMakefile())
- , Name(name)
- , Always(false)
- , MatchlessFiles(true)
- , FilePermissions(0)
- , DirPermissions(0)
- , CurrentMatchRule(nullptr)
- , UseGivenPermissionsFile(false)
- , UseGivenPermissionsDir(false)
- , UseSourcePermissions(true)
- , Doing(DoingNone)
- {
- }
- virtual ~cmFileCopier() = default;
-
- bool Run(std::vector<std::string> const& args);
-
-protected:
- cmFileCommand* FileCommand;
- cmMakefile* Makefile;
- const char* Name;
- bool Always;
- cmFileTimeComparison FileTimes;
-
- // Whether to install a file not matching any expression.
- bool MatchlessFiles;
-
- // Permissions for files and directories installed by this object.
- mode_t FilePermissions;
- mode_t DirPermissions;
-
- // Properties set by pattern and regex match rules.
- struct MatchProperties
- {
- bool Exclude = false;
- mode_t Permissions = 0;
- };
- struct MatchRule
- {
- cmsys::RegularExpression Regex;
- MatchProperties Properties;
- std::string RegexString;
- MatchRule(std::string const& regex)
- : Regex(regex)
- , RegexString(regex)
- {
- }
- };
- std::vector<MatchRule> MatchRules;
-
- // Get the properties from rules matching this input file.
- MatchProperties CollectMatchProperties(const std::string& file)
- {
-// Match rules are case-insensitive on some platforms.
-#if defined(_WIN32) || defined(__APPLE__) || defined(__CYGWIN__)
- const std::string file_to_match = cmSystemTools::LowerCase(file);
-#else
- const std::string& file_to_match = file;
-#endif
-
- // Collect properties from all matching rules.
- bool matched = false;
- MatchProperties result;
- for (MatchRule& mr : this->MatchRules) {
- if (mr.Regex.find(file_to_match)) {
- matched = true;
- result.Exclude |= mr.Properties.Exclude;
- result.Permissions |= mr.Properties.Permissions;
- }
- }
- if (!matched && !this->MatchlessFiles) {
- result.Exclude = !cmSystemTools::FileIsDirectory(file);
- }
- return result;
- }
-
- bool SetPermissions(const std::string& toFile, mode_t permissions)
- {
- if (permissions) {
-#ifdef WIN32
- if (Makefile->IsOn("CMAKE_CROSSCOMPILING")) {
- // Store the mode in an NTFS alternate stream.
- std::string mode_t_adt_filename = toFile + ":cmake_mode_t";
-
- // Writing to an NTFS alternate stream changes the modification
- // time, so we need to save and restore its original value.
- cmSystemToolsFileTime* file_time_orig = cmSystemTools::FileTimeNew();
- cmSystemTools::FileTimeGet(toFile, file_time_orig);
-
- cmsys::ofstream permissionStream(mode_t_adt_filename.c_str());
-
- if (permissionStream) {
- permissionStream << std::oct << permissions << std::endl;
- }
-
- permissionStream.close();
-
- cmSystemTools::FileTimeSet(toFile, file_time_orig);
-
- cmSystemTools::FileTimeDelete(file_time_orig);
- }
-#endif
-
- if (!cmSystemTools::SetPermissions(toFile, permissions)) {
- std::ostringstream e;
- e << this->Name << " cannot set permissions on \"" << toFile << "\"";
- this->FileCommand->SetError(e.str());
- return false;
- }
- }
- return true;
- }
-
- // Translate an argument to a permissions bit.
- bool CheckPermissions(std::string const& arg, mode_t& permissions)
- {
- if (!cmFSPermissions::stringToModeT(arg, permissions)) {
- std::ostringstream e;
- e << this->Name << " given invalid permission \"" << arg << "\".";
- this->FileCommand->SetError(e.str());
- return false;
- }
- return true;
- }
-
- bool InstallSymlink(const std::string& fromFile, const std::string& toFile);
- bool InstallFile(const std::string& fromFile, const std::string& toFile,
- MatchProperties match_properties);
- bool InstallDirectory(const std::string& source,
- const std::string& destination,
- MatchProperties match_properties);
- virtual bool Install(const std::string& fromFile, const std::string& toFile);
- virtual std::string const& ToName(std::string const& fromName)
- {
- return fromName;
- }
-
- enum Type
- {
- TypeFile,
- TypeDir,
- TypeLink
- };
- virtual void ReportCopy(const std::string&, Type, bool) {}
- virtual bool ReportMissing(const std::string& fromFile)
- {
- // The input file does not exist and installation is not optional.
- std::ostringstream e;
- e << this->Name << " cannot find \"" << fromFile << "\".";
- this->FileCommand->SetError(e.str());
- return false;
- }
-
- MatchRule* CurrentMatchRule;
- bool UseGivenPermissionsFile;
- bool UseGivenPermissionsDir;
- bool UseSourcePermissions;
- std::string Destination;
- std::string FilesFromDir;
- std::vector<std::string> Files;
- int Doing;
-
- virtual bool Parse(std::vector<std::string> const& args);
- enum
- {
- DoingNone,
- DoingError,
- DoingDestination,
- DoingFilesFromDir,
- DoingFiles,
- DoingPattern,
- DoingRegex,
- DoingPermissionsFile,
- DoingPermissionsDir,
- DoingPermissionsMatch,
- DoingLast1
- };
- virtual bool CheckKeyword(std::string const& arg);
- virtual bool CheckValue(std::string const& arg);
-
- void NotBeforeMatch(std::string const& arg)
- {
- std::ostringstream e;
- e << "option " << arg << " may not appear before PATTERN or REGEX.";
- this->FileCommand->SetError(e.str());
- this->Doing = DoingError;
- }
- void NotAfterMatch(std::string const& arg)
- {
- std::ostringstream e;
- e << "option " << arg << " may not appear after PATTERN or REGEX.";
- this->FileCommand->SetError(e.str());
- this->Doing = DoingError;
- }
- virtual void DefaultFilePermissions()
- {
- // Use read/write permissions.
- this->FilePermissions = 0;
- this->FilePermissions |= mode_owner_read;
- this->FilePermissions |= mode_owner_write;
- this->FilePermissions |= mode_group_read;
- this->FilePermissions |= mode_world_read;
- }
- virtual void DefaultDirectoryPermissions()
- {
- // Use read/write/executable permissions.
- this->DirPermissions = 0;
- this->DirPermissions |= mode_owner_read;
- this->DirPermissions |= mode_owner_write;
- this->DirPermissions |= mode_owner_execute;
- this->DirPermissions |= mode_group_read;
- this->DirPermissions |= mode_group_execute;
- this->DirPermissions |= mode_world_read;
- this->DirPermissions |= mode_world_execute;
- }
-
- bool GetDefaultDirectoryPermissions(mode_t** mode)
- {
- // check if default dir creation permissions were set
- const char* default_dir_install_permissions =
- this->Makefile->GetDefinition(
- "CMAKE_INSTALL_DEFAULT_DIRECTORY_PERMISSIONS");
- if (default_dir_install_permissions && *default_dir_install_permissions) {
- std::vector<std::string> items;
- cmSystemTools::ExpandListArgument(default_dir_install_permissions,
- items);
- for (const auto& arg : items) {
- if (!this->CheckPermissions(arg, **mode)) {
- std::ostringstream e;
- e << this->FileCommand->GetError()
- << " Set with CMAKE_INSTALL_DEFAULT_DIRECTORY_PERMISSIONS "
- "variable.";
- this->FileCommand->SetError(e.str());
- return false;
- }
- }
- } else {
- *mode = nullptr;
- }
-
- return true;
- }
-};
-
-bool cmFileCopier::Parse(std::vector<std::string> const& args)
-{
- this->Doing = DoingFiles;
- for (unsigned int i = 1; i < args.size(); ++i) {
- // Check this argument.
- if (!this->CheckKeyword(args[i]) && !this->CheckValue(args[i])) {
- std::ostringstream e;
- e << "called with unknown argument \"" << args[i] << "\".";
- this->FileCommand->SetError(e.str());
- return false;
- }
-
- // Quit if an argument is invalid.
- if (this->Doing == DoingError) {
- return false;
- }
- }
-
- // Require a destination.
- if (this->Destination.empty()) {
- std::ostringstream e;
- e << this->Name << " given no DESTINATION";
- this->FileCommand->SetError(e.str());
- return false;
- }
-
- // If file permissions were not specified set default permissions.
- if (!this->UseGivenPermissionsFile && !this->UseSourcePermissions) {
- this->DefaultFilePermissions();
- }
-
- // If directory permissions were not specified set default permissions.
- if (!this->UseGivenPermissionsDir && !this->UseSourcePermissions) {
- this->DefaultDirectoryPermissions();
- }
-
- return true;
-}
-
-bool cmFileCopier::CheckKeyword(std::string const& arg)
-{
- if (arg == "DESTINATION") {
- if (this->CurrentMatchRule) {
- this->NotAfterMatch(arg);
- } else {
- this->Doing = DoingDestination;
- }
- } else if (arg == "FILES_FROM_DIR") {
- if (this->CurrentMatchRule) {
- this->NotAfterMatch(arg);
- } else {
- this->Doing = DoingFilesFromDir;
- }
- } else if (arg == "PATTERN") {
- this->Doing = DoingPattern;
- } else if (arg == "REGEX") {
- this->Doing = DoingRegex;
- } else if (arg == "EXCLUDE") {
- // Add this property to the current match rule.
- if (this->CurrentMatchRule) {
- this->CurrentMatchRule->Properties.Exclude = true;
- this->Doing = DoingNone;
- } else {
- this->NotBeforeMatch(arg);
- }
- } else if (arg == "PERMISSIONS") {
- if (this->CurrentMatchRule) {
- this->Doing = DoingPermissionsMatch;
- } else {
- this->NotBeforeMatch(arg);
- }
- } else if (arg == "FILE_PERMISSIONS") {
- if (this->CurrentMatchRule) {
- this->NotAfterMatch(arg);
- } else {
- this->Doing = DoingPermissionsFile;
- this->UseGivenPermissionsFile = true;
- }
- } else if (arg == "DIRECTORY_PERMISSIONS") {
- if (this->CurrentMatchRule) {
- this->NotAfterMatch(arg);
- } else {
- this->Doing = DoingPermissionsDir;
- this->UseGivenPermissionsDir = true;
- }
- } else if (arg == "USE_SOURCE_PERMISSIONS") {
- if (this->CurrentMatchRule) {
- this->NotAfterMatch(arg);
- } else {
- this->Doing = DoingNone;
- this->UseSourcePermissions = true;
- }
- } else if (arg == "NO_SOURCE_PERMISSIONS") {
- if (this->CurrentMatchRule) {
- this->NotAfterMatch(arg);
- } else {
- this->Doing = DoingNone;
- this->UseSourcePermissions = false;
- }
- } else if (arg == "FILES_MATCHING") {
- if (this->CurrentMatchRule) {
- this->NotAfterMatch(arg);
- } else {
- this->Doing = DoingNone;
- this->MatchlessFiles = false;
- }
- } else {
- return false;
- }
- return true;
-}
-
-bool cmFileCopier::CheckValue(std::string const& arg)
-{
- switch (this->Doing) {
- case DoingFiles:
- this->Files.push_back(arg);
- break;
- case DoingDestination:
- if (arg.empty() || cmSystemTools::FileIsFullPath(arg)) {
- this->Destination = arg;
- } else {
- this->Destination = this->Makefile->GetCurrentBinaryDirectory();
- this->Destination += "/" + arg;
- }
- this->Doing = DoingNone;
- break;
- case DoingFilesFromDir:
- if (cmSystemTools::FileIsFullPath(arg)) {
- this->FilesFromDir = arg;
- } else {
- this->FilesFromDir = this->Makefile->GetCurrentSourceDirectory();
- this->FilesFromDir += "/" + arg;
- }
- cmSystemTools::ConvertToUnixSlashes(this->FilesFromDir);
- this->Doing = DoingNone;
- break;
- case DoingPattern: {
- // Convert the pattern to a regular expression. Require a
- // leading slash and trailing end-of-string in the matched
- // string to make sure the pattern matches only whole file
- // names.
- std::string regex = "/";
- regex += cmsys::Glob::PatternToRegex(arg, false);
- regex += "$";
- this->MatchRules.emplace_back(regex);
- this->CurrentMatchRule = &*(this->MatchRules.end() - 1);
- if (this->CurrentMatchRule->Regex.is_valid()) {
- this->Doing = DoingNone;
- } else {
- std::ostringstream e;
- e << "could not compile PATTERN \"" << arg << "\".";
- this->FileCommand->SetError(e.str());
- this->Doing = DoingError;
- }
- } break;
- case DoingRegex:
- this->MatchRules.emplace_back(arg);
- this->CurrentMatchRule = &*(this->MatchRules.end() - 1);
- if (this->CurrentMatchRule->Regex.is_valid()) {
- this->Doing = DoingNone;
- } else {
- std::ostringstream e;
- e << "could not compile REGEX \"" << arg << "\".";
- this->FileCommand->SetError(e.str());
- this->Doing = DoingError;
- }
- break;
- case DoingPermissionsFile:
- if (!this->CheckPermissions(arg, this->FilePermissions)) {
- this->Doing = DoingError;
- }
- break;
- case DoingPermissionsDir:
- if (!this->CheckPermissions(arg, this->DirPermissions)) {
- this->Doing = DoingError;
- }
- break;
- case DoingPermissionsMatch:
- if (!this->CheckPermissions(
- arg, this->CurrentMatchRule->Properties.Permissions)) {
- this->Doing = DoingError;
- }
- break;
- default:
- return false;
- }
- return true;
-}
-
-bool cmFileCopier::Run(std::vector<std::string> const& args)
-{
- if (!this->Parse(args)) {
- return false;
- }
-
- for (std::string const& f : this->Files) {
- std::string file;
- if (!f.empty() && !cmSystemTools::FileIsFullPath(f)) {
- if (!this->FilesFromDir.empty()) {
- file = this->FilesFromDir;
- } else {
- file = this->Makefile->GetCurrentSourceDirectory();
- }
- file += "/";
- file += f;
- } else if (!this->FilesFromDir.empty()) {
- this->FileCommand->SetError("option FILES_FROM_DIR requires all files "
- "to be specified as relative paths.");
- return false;
- } else {
- file = f;
- }
-
- // Split the input file into its directory and name components.
- std::vector<std::string> fromPathComponents;
- cmSystemTools::SplitPath(file, fromPathComponents);
- std::string fromName = *(fromPathComponents.end() - 1);
- std::string fromDir = cmSystemTools::JoinPath(
- fromPathComponents.begin(), fromPathComponents.end() - 1);
-
- // Compute the full path to the destination file.
- std::string toFile = this->Destination;
- if (!this->FilesFromDir.empty()) {
- std::string dir = cmSystemTools::GetFilenamePath(f);
- if (!dir.empty()) {
- toFile += "/";
- toFile += dir;
- }
- }
- std::string const& toName = this->ToName(fromName);
- if (!toName.empty()) {
- toFile += "/";
- toFile += toName;
- }
-
- // Construct the full path to the source file. The file name may
- // have been changed above.
- std::string fromFile = fromDir;
- if (!fromName.empty()) {
- fromFile += "/";
- fromFile += fromName;
- }
-
- if (!this->Install(fromFile, toFile)) {
- return false;
- }
- }
- return true;
-}
-
-bool cmFileCopier::Install(const std::string& fromFile,
- const std::string& toFile)
-{
- if (fromFile.empty()) {
- std::ostringstream e;
- e << "INSTALL encountered an empty string input file name.";
- this->FileCommand->SetError(e.str());
- return false;
- }
-
- // Collect any properties matching this file name.
- MatchProperties match_properties = this->CollectMatchProperties(fromFile);
-
- // Skip the file if it is excluded.
- if (match_properties.Exclude) {
- return true;
- }
-
- if (cmSystemTools::SameFile(fromFile, toFile)) {
- return true;
- }
- if (cmSystemTools::FileIsSymlink(fromFile)) {
- return this->InstallSymlink(fromFile, toFile);
- }
- if (cmSystemTools::FileIsDirectory(fromFile)) {
- return this->InstallDirectory(fromFile, toFile, match_properties);
- }
- if (cmSystemTools::FileExists(fromFile)) {
- return this->InstallFile(fromFile, toFile, match_properties);
- }
- return this->ReportMissing(fromFile);
-}
-
-bool cmFileCopier::InstallSymlink(const std::string& fromFile,
- const std::string& toFile)
-{
- // Read the original symlink.
- std::string symlinkTarget;
- if (!cmSystemTools::ReadSymlink(fromFile, symlinkTarget)) {
- std::ostringstream e;
- e << this->Name << " cannot read symlink \"" << fromFile
- << "\" to duplicate at \"" << toFile << "\".";
- this->FileCommand->SetError(e.str());
- return false;
- }
-
- // Compare the symlink value to that at the destination if not
- // always installing.
- bool copy = true;
- if (!this->Always) {
- std::string oldSymlinkTarget;
- if (cmSystemTools::ReadSymlink(toFile, oldSymlinkTarget)) {
- if (symlinkTarget == oldSymlinkTarget) {
- copy = false;
- }
- }
- }
-
- // Inform the user about this file installation.
- this->ReportCopy(toFile, TypeLink, copy);
-
- if (copy) {
- // Remove the destination file so we can always create the symlink.
- cmSystemTools::RemoveFile(toFile);
-
- // Create destination directory if it doesn't exist
- cmSystemTools::MakeDirectory(cmSystemTools::GetFilenamePath(toFile));
-
- // Create the symlink.
- if (!cmSystemTools::CreateSymlink(symlinkTarget, toFile)) {
- std::ostringstream e;
- e << this->Name << " cannot duplicate symlink \"" << fromFile
- << "\" at \"" << toFile << "\".";
- this->FileCommand->SetError(e.str());
- return false;
- }
- }
-
- return true;
-}
-
-bool cmFileCopier::InstallFile(const std::string& fromFile,
- const std::string& toFile,
- MatchProperties match_properties)
-{
- // Determine whether we will copy the file.
- bool copy = true;
- if (!this->Always) {
- // If both files exist with the same time do not copy.
- if (!this->FileTimes.FileTimesDiffer(fromFile, toFile)) {
- copy = false;
- }
- }
-
- // Inform the user about this file installation.
- this->ReportCopy(toFile, TypeFile, copy);
-
- // Copy the file.
- if (copy && !cmSystemTools::CopyAFile(fromFile, toFile, true)) {
- std::ostringstream e;
- e << this->Name << " cannot copy file \"" << fromFile << "\" to \""
- << toFile << "\".";
- this->FileCommand->SetError(e.str());
- return false;
- }
-
- // Set the file modification time of the destination file.
- if (copy && !this->Always) {
- // Add write permission so we can set the file time.
- // Permissions are set unconditionally below anyway.
- mode_t perm = 0;
- if (cmSystemTools::GetPermissions(toFile, perm)) {
- cmSystemTools::SetPermissions(toFile, perm | mode_owner_write);
- }
- if (!cmSystemTools::CopyFileTime(fromFile, toFile)) {
- std::ostringstream e;
- e << this->Name << " cannot set modification time on \"" << toFile
- << "\"";
- this->FileCommand->SetError(e.str());
- return false;
- }
- }
-
- // Set permissions of the destination file.
- mode_t permissions =
- (match_properties.Permissions ? match_properties.Permissions
- : this->FilePermissions);
- if (!permissions) {
- // No permissions were explicitly provided but the user requested
- // that the source file permissions be used.
- cmSystemTools::GetPermissions(fromFile, permissions);
- }
- return this->SetPermissions(toFile, permissions);
-}
-
-bool cmFileCopier::InstallDirectory(const std::string& source,
- const std::string& destination,
- MatchProperties match_properties)
-{
- // Inform the user about this directory installation.
- this->ReportCopy(destination, TypeDir,
- !cmSystemTools::FileIsDirectory(destination));
-
- // check if default dir creation permissions were set
- mode_t default_dir_mode_v = 0;
- mode_t* default_dir_mode = &default_dir_mode_v;
- if (!this->GetDefaultDirectoryPermissions(&default_dir_mode)) {
- return false;
- }
-
- // Make sure the destination directory exists.
- if (!cmSystemTools::MakeDirectory(destination, default_dir_mode)) {
- std::ostringstream e;
- e << this->Name << " cannot make directory \"" << destination
- << "\": " << cmSystemTools::GetLastSystemError();
- this->FileCommand->SetError(e.str());
- return false;
- }
-
- // Compute the requested permissions for the destination directory.
- mode_t permissions =
- (match_properties.Permissions ? match_properties.Permissions
- : this->DirPermissions);
- if (!permissions) {
- // No permissions were explicitly provided but the user requested
- // that the source directory permissions be used.
- cmSystemTools::GetPermissions(source, permissions);
- }
-
- // Compute the set of permissions required on this directory to
- // recursively install files and subdirectories safely.
- mode_t required_permissions =
- mode_owner_read | mode_owner_write | mode_owner_execute;
-
- // If the required permissions are specified it is safe to set the
- // final permissions now. Otherwise we must add the required
- // permissions temporarily during file installation.
- mode_t permissions_before = 0;
- mode_t permissions_after = 0;
- if ((permissions & required_permissions) == required_permissions) {
- permissions_before = permissions;
- } else {
- permissions_before = permissions | required_permissions;
- permissions_after = permissions;
- }
-
- // Set the required permissions of the destination directory.
- if (!this->SetPermissions(destination, permissions_before)) {
- return false;
- }
-
- // Load the directory contents to traverse it recursively.
- cmsys::Directory dir;
- if (!source.empty()) {
- dir.Load(source);
- }
- unsigned long numFiles = static_cast<unsigned long>(dir.GetNumberOfFiles());
- for (unsigned long fileNum = 0; fileNum < numFiles; ++fileNum) {
- if (!(strcmp(dir.GetFile(fileNum), ".") == 0 ||
- strcmp(dir.GetFile(fileNum), "..") == 0)) {
- std::string fromPath = source;
- fromPath += "/";
- fromPath += dir.GetFile(fileNum);
- std::string toPath = destination;
- toPath += "/";
- toPath += dir.GetFile(fileNum);
- if (!this->Install(fromPath, toPath)) {
- return false;
- }
- }
- }
-
- // Set the requested permissions of the destination directory.
- return this->SetPermissions(destination, permissions_after);
-}
-
bool cmFileCommand::HandleCopyCommand(std::vector<std::string> const& args)
{
cmFileCopier copier(this);
return copier.Run(args);
}
-struct cmFileInstaller : public cmFileCopier
-{
- cmFileInstaller(cmFileCommand* command)
- : cmFileCopier(command, "INSTALL")
- , InstallType(cmInstallType_FILES)
- , Optional(false)
- , MessageAlways(false)
- , MessageLazy(false)
- , MessageNever(false)
- , DestDirLength(0)
- {
- // Installation does not use source permissions by default.
- this->UseSourcePermissions = false;
- // Check whether to copy files always or only if they have changed.
- std::string install_always;
- if (cmSystemTools::GetEnv("CMAKE_INSTALL_ALWAYS", install_always)) {
- this->Always = cmSystemTools::IsOn(install_always);
- }
- // Get the current manifest.
- this->Manifest =
- this->Makefile->GetSafeDefinition("CMAKE_INSTALL_MANIFEST_FILES");
- }
- ~cmFileInstaller() override
- {
- // Save the updated install manifest.
- this->Makefile->AddDefinition("CMAKE_INSTALL_MANIFEST_FILES",
- this->Manifest.c_str());
- }
-
-protected:
- cmInstallType InstallType;
- bool Optional;
- bool MessageAlways;
- bool MessageLazy;
- bool MessageNever;
- int DestDirLength;
- std::string Rename;
-
- std::string Manifest;
- void ManifestAppend(std::string const& file)
- {
- if (!this->Manifest.empty()) {
- this->Manifest += ";";
- }
- this->Manifest += file.substr(this->DestDirLength);
- }
-
- std::string const& ToName(std::string const& fromName) override
- {
- return this->Rename.empty() ? fromName : this->Rename;
- }
-
- void ReportCopy(const std::string& toFile, Type type, bool copy) override
- {
- if (!this->MessageNever && (copy || !this->MessageLazy)) {
- std::string message = (copy ? "Installing: " : "Up-to-date: ");
- message += toFile;
- this->Makefile->DisplayStatus(message, -1);
- }
- if (type != TypeDir) {
- // Add the file to the manifest.
- this->ManifestAppend(toFile);
- }
- }
- bool ReportMissing(const std::string& fromFile) override
- {
- return (this->Optional || this->cmFileCopier::ReportMissing(fromFile));
- }
- bool Install(const std::string& fromFile, const std::string& toFile) override
- {
- // Support installing from empty source to make a directory.
- if (this->InstallType == cmInstallType_DIRECTORY && fromFile.empty()) {
- return this->InstallDirectory(fromFile, toFile, MatchProperties());
- }
- return this->cmFileCopier::Install(fromFile, toFile);
- }
-
- bool Parse(std::vector<std::string> const& args) override;
- enum
- {
- DoingType = DoingLast1,
- DoingRename,
- DoingLast2
- };
- bool CheckKeyword(std::string const& arg) override;
- bool CheckValue(std::string const& arg) override;
- void DefaultFilePermissions() override
- {
- this->cmFileCopier::DefaultFilePermissions();
- // Add execute permissions based on the target type.
- switch (this->InstallType) {
- case cmInstallType_SHARED_LIBRARY:
- case cmInstallType_MODULE_LIBRARY:
- if (this->Makefile->IsOn("CMAKE_INSTALL_SO_NO_EXE")) {
- break;
- }
- CM_FALLTHROUGH;
- case cmInstallType_EXECUTABLE:
- case cmInstallType_PROGRAMS:
- this->FilePermissions |= mode_owner_execute;
- this->FilePermissions |= mode_group_execute;
- this->FilePermissions |= mode_world_execute;
- break;
- default:
- break;
- }
- }
- bool GetTargetTypeFromString(const std::string& stype);
- bool HandleInstallDestination();
-};
-
-bool cmFileInstaller::Parse(std::vector<std::string> const& args)
-{
- if (!this->cmFileCopier::Parse(args)) {
- return false;
- }
-
- if (!this->Rename.empty()) {
- if (!this->FilesFromDir.empty()) {
- this->FileCommand->SetError("INSTALL option RENAME may not be "
- "combined with FILES_FROM_DIR.");
- return false;
- }
- if (this->InstallType != cmInstallType_FILES &&
- this->InstallType != cmInstallType_PROGRAMS) {
- this->FileCommand->SetError("INSTALL option RENAME may be used "
- "only with FILES or PROGRAMS.");
- return false;
- }
- if (this->Files.size() > 1) {
- this->FileCommand->SetError("INSTALL option RENAME may be used "
- "only with one file.");
- return false;
- }
- }
-
- if (!this->HandleInstallDestination()) {
- return false;
- }
-
- if (((this->MessageAlways ? 1 : 0) + (this->MessageLazy ? 1 : 0) +
- (this->MessageNever ? 1 : 0)) > 1) {
- this->FileCommand->SetError("INSTALL options MESSAGE_ALWAYS, "
- "MESSAGE_LAZY, and MESSAGE_NEVER "
- "are mutually exclusive.");
- return false;
- }
-
- return true;
-}
-
-bool cmFileInstaller::CheckKeyword(std::string const& arg)
-{
- if (arg == "TYPE") {
- if (this->CurrentMatchRule) {
- this->NotAfterMatch(arg);
- } else {
- this->Doing = DoingType;
- }
- } else if (arg == "FILES") {
- if (this->CurrentMatchRule) {
- this->NotAfterMatch(arg);
- } else {
- this->Doing = DoingFiles;
- }
- } else if (arg == "RENAME") {
- if (this->CurrentMatchRule) {
- this->NotAfterMatch(arg);
- } else {
- this->Doing = DoingRename;
- }
- } else if (arg == "OPTIONAL") {
- if (this->CurrentMatchRule) {
- this->NotAfterMatch(arg);
- } else {
- this->Doing = DoingNone;
- this->Optional = true;
- }
- } else if (arg == "MESSAGE_ALWAYS") {
- if (this->CurrentMatchRule) {
- this->NotAfterMatch(arg);
- } else {
- this->Doing = DoingNone;
- this->MessageAlways = true;
- }
- } else if (arg == "MESSAGE_LAZY") {
- if (this->CurrentMatchRule) {
- this->NotAfterMatch(arg);
- } else {
- this->Doing = DoingNone;
- this->MessageLazy = true;
- }
- } else if (arg == "MESSAGE_NEVER") {
- if (this->CurrentMatchRule) {
- this->NotAfterMatch(arg);
- } else {
- this->Doing = DoingNone;
- this->MessageNever = true;
- }
- } else if (arg == "PERMISSIONS") {
- if (this->CurrentMatchRule) {
- this->Doing = DoingPermissionsMatch;
- } else {
- // file(INSTALL) aliases PERMISSIONS to FILE_PERMISSIONS
- this->Doing = DoingPermissionsFile;
- this->UseGivenPermissionsFile = true;
- }
- } else if (arg == "DIR_PERMISSIONS") {
- if (this->CurrentMatchRule) {
- this->NotAfterMatch(arg);
- } else {
- // file(INSTALL) aliases DIR_PERMISSIONS to DIRECTORY_PERMISSIONS
- this->Doing = DoingPermissionsDir;
- this->UseGivenPermissionsDir = true;
- }
- } else if (arg == "COMPONENTS" || arg == "CONFIGURATIONS" ||
- arg == "PROPERTIES") {
- std::ostringstream e;
- e << "INSTALL called with old-style " << arg << " argument. "
- << "This script was generated with an older version of CMake. "
- << "Re-run this cmake version on your build tree.";
- this->FileCommand->SetError(e.str());
- this->Doing = DoingError;
- } else {
- return this->cmFileCopier::CheckKeyword(arg);
- }
- return true;
-}
-
-bool cmFileInstaller::CheckValue(std::string const& arg)
-{
- switch (this->Doing) {
- case DoingType:
- if (!this->GetTargetTypeFromString(arg)) {
- this->Doing = DoingError;
- }
- break;
- case DoingRename:
- this->Rename = arg;
- break;
- default:
- return this->cmFileCopier::CheckValue(arg);
- }
- return true;
-}
-
-bool cmFileInstaller::GetTargetTypeFromString(const std::string& stype)
-{
- if (stype == "EXECUTABLE") {
- this->InstallType = cmInstallType_EXECUTABLE;
- } else if (stype == "FILE") {
- this->InstallType = cmInstallType_FILES;
- } else if (stype == "PROGRAM") {
- this->InstallType = cmInstallType_PROGRAMS;
- } else if (stype == "STATIC_LIBRARY") {
- this->InstallType = cmInstallType_STATIC_LIBRARY;
- } else if (stype == "SHARED_LIBRARY") {
- this->InstallType = cmInstallType_SHARED_LIBRARY;
- } else if (stype == "MODULE") {
- this->InstallType = cmInstallType_MODULE_LIBRARY;
- } else if (stype == "DIRECTORY") {
- this->InstallType = cmInstallType_DIRECTORY;
- } else {
- std::ostringstream e;
- e << "Option TYPE given unknown value \"" << stype << "\".";
- this->FileCommand->SetError(e.str());
- return false;
- }
- return true;
-}
-
-bool cmFileInstaller::HandleInstallDestination()
-{
- std::string& destination = this->Destination;
-
- // allow for / to be a valid destination
- if (destination.size() < 2 && destination != "/") {
- this->FileCommand->SetError("called with inappropriate arguments. "
- "No DESTINATION provided or .");
- return false;
- }
-
- std::string sdestdir;
- if (cmSystemTools::GetEnv("DESTDIR", sdestdir) && !sdestdir.empty()) {
- cmSystemTools::ConvertToUnixSlashes(sdestdir);
- char ch1 = destination[0];
- char ch2 = destination[1];
- char ch3 = 0;
- if (destination.size() > 2) {
- ch3 = destination[2];
- }
- int skip = 0;
- if (ch1 != '/') {
- int relative = 0;
- if (((ch1 >= 'a' && ch1 <= 'z') || (ch1 >= 'A' && ch1 <= 'Z')) &&
- ch2 == ':') {
- // Assume windows
- // let's do some destdir magic:
- skip = 2;
- if (ch3 != '/') {
- relative = 1;
- }
- } else {
- relative = 1;
- }
- if (relative) {
- // This is relative path on unix or windows. Since we are doing
- // destdir, this case does not make sense.
- this->FileCommand->SetError(
- "called with relative DESTINATION. This "
- "does not make sense when using DESTDIR. Specify "
- "absolute path or remove DESTDIR environment variable.");
- return false;
- }
- } else {
- if (ch2 == '/') {
- // looks like a network path.
- std::string message =
- "called with network path DESTINATION. This "
- "does not make sense when using DESTDIR. Specify local "
- "absolute path or remove DESTDIR environment variable."
- "\nDESTINATION=\n";
- message += destination;
- this->FileCommand->SetError(message);
- return false;
- }
- }
- destination = sdestdir + (destination.c_str() + skip);
- this->DestDirLength = int(sdestdir.size());
- }
-
- // check if default dir creation permissions were set
- mode_t default_dir_mode_v = 0;
- mode_t* default_dir_mode = &default_dir_mode_v;
- if (!this->GetDefaultDirectoryPermissions(&default_dir_mode)) {
- return false;
- }
-
- if (this->InstallType != cmInstallType_DIRECTORY) {
- if (!cmSystemTools::FileExists(destination)) {
- if (!cmSystemTools::MakeDirectory(destination, default_dir_mode)) {
- std::string errstring = "cannot create directory: " + destination +
- ". Maybe need administrative privileges.";
- this->FileCommand->SetError(errstring);
- return false;
- }
- }
- if (!cmSystemTools::FileIsDirectory(destination)) {
- std::string errstring =
- "INSTALL destination: " + destination + " is not a directory.";
- this->FileCommand->SetError(errstring);
- return false;
- }
- }
- return true;
-}
-
bool cmFileCommand::HandleRPathChangeCommand(
std::vector<std::string> const& args)
{