summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--Source/cmFileCommand.cxx63
-rw-r--r--Source/cmSystemTools.cxx64
-rw-r--r--Source/cmSystemTools.h5
3 files changed, 114 insertions, 18 deletions
diff --git a/Source/cmFileCommand.cxx b/Source/cmFileCommand.cxx
index 9330bb4..3a31a3f 100644
--- a/Source/cmFileCommand.cxx
+++ b/Source/cmFileCommand.cxx
@@ -17,9 +17,11 @@
#include "cmFileCommand.h"
#include "cmake.h"
#include "cmHexFileConverter.h"
+#include "cmFileTimeComparison.h"
#include <sys/types.h>
#include <sys/stat.h>
+
#include <cmsys/Directory.hxx>
#include <cmsys/Glob.hxx>
#include <cmsys/RegularExpression.hxx>
@@ -716,6 +718,7 @@ struct cmFileInstaller
private:
cmFileCommand* FileCommand;
cmMakefile* Makefile;
+ cmFileTimeComparison FileTimes;
public:
// The length of the destdir setting.
@@ -807,11 +810,6 @@ private:
bool cmFileInstaller::InstallSymlink(const char* fromFile, const char* toFile,
bool always)
{
- // Inform the user about this file installation.
- std::string message = "Installing ";
- message += toFile;
- this->Makefile->DisplayStatus(message.c_str(), -1);
-
// Read the original symlink.
std::string symlinkTarget;
if(!cmSystemTools::ReadSymlink(fromFile, symlinkTarget))
@@ -825,6 +823,7 @@ bool cmFileInstaller::InstallSymlink(const char* fromFile, const char* toFile,
// Compare the symlink value to that at the destination if not
// always installing.
+ bool copy = true;
if(!always)
{
std::string oldSymlinkTarget;
@@ -832,22 +831,30 @@ bool cmFileInstaller::InstallSymlink(const char* fromFile, const char* toFile,
{
if(symlinkTarget == oldSymlinkTarget)
{
- return true;
+ copy = false;
}
}
}
- // Remove the destination file so we can always create the symlink.
- cmSystemTools::RemoveFile(toFile);
+ // Inform the user about this file installation.
+ std::string message = (copy? "Installing: " : "Up-to-date: ");
+ message += toFile;
+ this->Makefile->DisplayStatus(message.c_str(), -1);
- // Create the symlink.
- if(!cmSystemTools::CreateSymlink(symlinkTarget.c_str(), toFile))
+ if(copy)
{
- cmOStringStream e;
- e << "INSTALL cannot duplicate symlink \"" << fromFile
- << "\" at \"" << toFile << "\".";
- this->FileCommand->SetError(e.str().c_str());
- return false;
+ // Remove the destination file so we can always create the symlink.
+ cmSystemTools::RemoveFile(toFile);
+
+ // Create the symlink.
+ if(!cmSystemTools::CreateSymlink(symlinkTarget.c_str(), toFile))
+ {
+ cmOStringStream e;
+ e << "INSTALL cannot duplicate symlink \"" << fromFile
+ << "\" at \"" << toFile << "\".";
+ this->FileCommand->SetError(e.str().c_str());
+ return false;
+ }
}
// Add the file to the manifest.
@@ -875,13 +882,27 @@ bool cmFileInstaller::InstallFile(const char* fromFile, const char* toFile,
return this->InstallSymlink(fromFile, toFile, always);
}
+ // Determine whether we will copy the file.
+ bool copy = true;
+ if(!always)
+ {
+ // If both files exist and "fromFile" is not newer than "toFile"
+ // do not copy.
+ int timeResult;
+ if(this->FileTimes.FileTimeCompare(fromFile, toFile, &timeResult) &&
+ timeResult <= 0)
+ {
+ copy = false;
+ }
+ }
+
// Inform the user about this file installation.
- std::string message = "Installing ";
+ std::string message = (copy? "Installing: " : "Up-to-date: ");
message += toFile;
this->Makefile->DisplayStatus(message.c_str(), -1);
// Copy the file.
- if(!cmSystemTools::CopyAFile(fromFile, toFile, always))
+ if(copy && !cmSystemTools::CopyAFile(fromFile, toFile, true))
{
cmOStringStream e;
e << "INSTALL cannot copy file \"" << fromFile
@@ -893,6 +914,12 @@ bool cmFileInstaller::InstallFile(const char* fromFile, const char* toFile,
// Add the file to the manifest.
this->ManifestAppend(toFile);
+ // Set the file modification time of the destination file.
+ if(copy && !always)
+ {
+ cmSystemTools::CopyFileTime(fromFile, toFile);
+ }
+
// Set permissions of the destination file.
mode_t permissions = (match_properties.Permissions?
match_properties.Permissions : this->FilePermissions);
@@ -934,7 +961,7 @@ bool cmFileInstaller::InstallDirectory(const char* source,
}
// Inform the user about this directory installation.
- std::string message = "Installing ";
+ std::string message = "Installing: ";
message += destination;
this->Makefile->DisplayStatus(message.c_str(), -1);
diff --git a/Source/cmSystemTools.cxx b/Source/cmSystemTools.cxx
index 04d6885..1c2ecc9 100644
--- a/Source/cmSystemTools.cxx
+++ b/Source/cmSystemTools.cxx
@@ -32,6 +32,7 @@
#endif
#if defined(_WIN32) && (defined(_MSC_VER) || defined(__BORLANDC__))
+# define CM_SYSTEM_TOOLS_WINDOWS
#include <string.h>
#include <windows.h>
#include <direct.h>
@@ -41,6 +42,7 @@
#include <sys/types.h>
#include <fcntl.h>
#include <unistd.h>
+#include <utime.h>
#endif
#include <sys/stat.h>
@@ -66,6 +68,26 @@ extern char** environ;
# endif
#endif
+#ifdef CM_SYSTEM_TOOLS_WINDOWS
+class cmSystemToolsWindowsHandle
+{
+public:
+ cmSystemToolsWindowsHandle(HANDLE h): handle_(h) {}
+ ~cmSystemToolsWindowsHandle()
+ {
+ if(this->handle_ != INVALID_HANDLE_VALUE)
+ {
+ CloseHandle(this->handle_);
+ }
+ }
+ operator bool() const { return this->handle_ != INVALID_HANDLE_VALUE; }
+ operator !() const { return this->handle_ == INVALID_HANDLE_VALUE; }
+ operator HANDLE() const { return this->handle_; }
+private:
+ HANDLE handle_;
+};
+#endif
+
bool cmSystemTools::s_RunCommandHideConsole = false;
bool cmSystemTools::s_DisableRunCommandOutput = false;
bool cmSystemTools::s_ErrorOccured = false;
@@ -2006,3 +2028,45 @@ void cmSystemTools::DoNotInheritStdPipes()
}
#endif
}
+
+//----------------------------------------------------------------------------
+bool cmSystemTools::CopyFileTime(const char* fromFile, const char* toFile)
+{
+#if defined(_WIN32) && !defined(__CYGWIN__)
+ cmSystemToolsWindowsHandle hFrom =
+ CreateFile(fromFile, GENERIC_READ, FILE_SHARE_READ, 0,
+ OPEN_EXISTING, 0, 0);
+ cmSystemToolsWindowsHandle hTo =
+ CreateFile(toFile, GENERIC_WRITE, 0, 0, OPEN_EXISTING, 0, 0);
+ if(!hFrom || !hTo)
+ {
+ return false;
+ }
+ FILETIME timeCreation;
+ FILETIME timeLastAccess;
+ FILETIME timeLastWrite;
+ if(!GetFileTime(hFrom, &timeCreation, &timeLastAccess, &timeLastWrite))
+ {
+ return false;
+ }
+ if(!SetFileTime(hFrom, &timeCreation, &timeLastAccess, &timeLastWrite))
+ {
+ return false;
+ }
+#else
+ struct stat fromStat;
+ if(stat(fromFile, &fromStat) < 0)
+ {
+ return false;
+ }
+
+ struct utimbuf buf;
+ buf.actime = fromStat.st_atime;
+ buf.modtime = fromStat.st_mtime;
+ if(utime(toFile, &buf) < 0)
+ {
+ return false;
+ }
+#endif
+ return true;
+}
diff --git a/Source/cmSystemTools.h b/Source/cmSystemTools.h
index ed95bdf..9007537 100644
--- a/Source/cmSystemTools.h
+++ b/Source/cmSystemTools.h
@@ -345,6 +345,11 @@ public:
// if you want to be able to kill child processes and
// not get stuck waiting for all the output on the pipes.
static void DoNotInheritStdPipes();
+
+ /** Copy the file create/access/modify times from the file named by
+ the first argument to that named by the second. */
+ static bool CopyFileTime(const char* fromFile, const char* toFile);
+
private:
static bool s_ForceUnixPaths;
static bool s_RunCommandHideConsole;