diff options
Diffstat (limited to 'Source/cmFileCommand.cxx')
-rw-r--r-- | Source/cmFileCommand.cxx | 1082 |
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) { |