|
|
@@ -185,6 +185,9 @@ bool cmFileCommand::InitialPass(std::vector<std::string> const& args,
|
|
|
if (subCommand == "READ_SYMLINK") {
|
|
|
return this->HandleReadSymlinkCommand(args);
|
|
|
}
|
|
|
+ if (subCommand == "CREATE_LINK") {
|
|
|
+ return this->HandleCreateLinkCommand(args);
|
|
|
+ }
|
|
|
|
|
|
std::string e = "does not recognize sub-command " + subCommand;
|
|
|
this->SetError(e);
|
|
|
@@ -3670,3 +3673,121 @@ bool cmFileCommand::HandleReadSymlinkCommand(
|
|
|
|
|
|
return true;
|
|
|
}
|
|
|
+
|
|
|
+bool cmFileCommand::HandleCreateLinkCommand(
|
|
|
+ std::vector<std::string> const& args)
|
|
|
+{
|
|
|
+ if (args.size() < 3) {
|
|
|
+ this->SetError("CREATE_LINK must be called with at least two additional "
|
|
|
+ "arguments");
|
|
|
+ return false;
|
|
|
+ }
|
|
|
+
|
|
|
+ cmCommandArgumentsHelper argHelper;
|
|
|
+ cmCommandArgumentGroup group;
|
|
|
+
|
|
|
+ cmCAString linkArg(&argHelper, "CREATE_LINK");
|
|
|
+ cmCAString fileArg(&argHelper, nullptr);
|
|
|
+ cmCAString newFileArg(&argHelper, nullptr);
|
|
|
+
|
|
|
+ cmCAString resultArg(&argHelper, "RESULT", &group);
|
|
|
+ cmCAEnabler copyOnErrorArg(&argHelper, "COPY_ON_ERROR", &group);
|
|
|
+ cmCAEnabler symbolicArg(&argHelper, "SYMBOLIC", &group);
|
|
|
+
|
|
|
+ linkArg.Follows(nullptr);
|
|
|
+ fileArg.Follows(&linkArg);
|
|
|
+ newFileArg.Follows(&fileArg);
|
|
|
+ group.Follows(&newFileArg);
|
|
|
+
|
|
|
+ std::vector<std::string> unconsumedArgs;
|
|
|
+ argHelper.Parse(&args, &unconsumedArgs);
|
|
|
+
|
|
|
+ if (!unconsumedArgs.empty()) {
|
|
|
+ this->SetError("unknown argument: \"" + unconsumedArgs.front() + '\"');
|
|
|
+ return false;
|
|
|
+ }
|
|
|
+
|
|
|
+ std::string fileName = fileArg.GetString();
|
|
|
+ std::string newFileName = newFileArg.GetString();
|
|
|
+
|
|
|
+ // Output variable for storing the result.
|
|
|
+ const std::string& resultVar = resultArg.GetString();
|
|
|
+
|
|
|
+ // The system error message generated in the operation.
|
|
|
+ std::string result;
|
|
|
+
|
|
|
+ // Check if the paths are distinct.
|
|
|
+ if (fileName == newFileName) {
|
|
|
+ result = "CREATE_LINK cannot use same file and newfile";
|
|
|
+ if (!resultVar.empty()) {
|
|
|
+ this->Makefile->AddDefinition(resultVar, result.c_str());
|
|
|
+ return true;
|
|
|
+ }
|
|
|
+ this->SetError(result);
|
|
|
+ return false;
|
|
|
+ }
|
|
|
+
|
|
|
+ // Hard link requires original file to exist.
|
|
|
+ if (!symbolicArg.IsEnabled() && !cmSystemTools::FileExists(fileName)) {
|
|
|
+ result = "Cannot hard link \'" + fileName + "\' as it does not exist.";
|
|
|
+ if (!resultVar.empty()) {
|
|
|
+ this->Makefile->AddDefinition(resultVar, result.c_str());
|
|
|
+ return true;
|
|
|
+ }
|
|
|
+ this->SetError(result);
|
|
|
+ return false;
|
|
|
+ }
|
|
|
+
|
|
|
+ // Check if the new file already exists and remove it.
|
|
|
+ if ((cmSystemTools::FileExists(newFileName) ||
|
|
|
+ cmSystemTools::FileIsSymlink(newFileName)) &&
|
|
|
+ !cmSystemTools::RemoveFile(newFileName)) {
|
|
|
+ std::ostringstream e;
|
|
|
+ e << "Failed to create link '" << newFileName
|
|
|
+ << "' because existing path cannot be removed: "
|
|
|
+ << cmSystemTools::GetLastSystemError() << "\n";
|
|
|
+
|
|
|
+ if (!resultVar.empty()) {
|
|
|
+ this->Makefile->AddDefinition(resultVar, e.str().c_str());
|
|
|
+ return true;
|
|
|
+ }
|
|
|
+ this->SetError(e.str());
|
|
|
+ return false;
|
|
|
+ }
|
|
|
+
|
|
|
+ // Whether the operation completed successfully.
|
|
|
+ bool completed = false;
|
|
|
+
|
|
|
+ // Check if the command requires a symbolic link.
|
|
|
+ if (symbolicArg.IsEnabled()) {
|
|
|
+ completed = cmSystemTools::CreateSymlink(fileName, newFileName);
|
|
|
+ } else {
|
|
|
+ completed = cmSystemTools::CreateLink(fileName, newFileName);
|
|
|
+ }
|
|
|
+
|
|
|
+ if (!completed) {
|
|
|
+ // The link method did not succeed. Get the error message.
|
|
|
+ result = "Link failed: " + cmSystemTools::GetLastSystemError();
|
|
|
+
|
|
|
+ // Check if copy-on-error is enabled in the arguments.
|
|
|
+ if (copyOnErrorArg.IsEnabled()) {
|
|
|
+ completed =
|
|
|
+ cmSystemTools::cmCopyFile(fileName.c_str(), newFileName.c_str());
|
|
|
+ if (!completed) {
|
|
|
+ result = "Copy failed: " + cmSystemTools::GetLastSystemError();
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ // Check if the operation was successful.
|
|
|
+ if (completed) {
|
|
|
+ result = "0";
|
|
|
+ }
|
|
|
+
|
|
|
+ if (!resultVar.empty()) {
|
|
|
+ this->Makefile->AddDefinition(resultVar, result.c_str());
|
|
|
+ return true;
|
|
|
+ }
|
|
|
+
|
|
|
+ return completed;
|
|
|
+}
|