ENH: Improved file modification time comparison on Windows to use GetFileAttributesEx instead of CreateFile/GetFileTime/CloseHandle to get file times. This results in a 30% reduction in time to do a build system check.

This commit is contained in:
Brad King 2005-10-27 13:57:48 -04:00
parent 6b0c50e824
commit 946c9a2cc6
2 changed files with 56 additions and 57 deletions

View File

@ -9,22 +9,19 @@
Copyright (c) 2002 Kitware, Inc., Insight Consortium. All rights reserved. Copyright (c) 2002 Kitware, Inc., Insight Consortium. All rights reserved.
See Copyright.txt or http://www.cmake.org/HTML/Copyright.html for details. See Copyright.txt or http://www.cmake.org/HTML/Copyright.html for details.
This software is distributed WITHOUT ANY WARRANTY; without even This software is distributed WITHOUT ANY WARRANTY; without even
the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
PURPOSE. See the above copyright notices for more information. PURPOSE. See the above copyright notices for more information.
=========================================================================*/ =========================================================================*/
#include "cmFileTimeComparison.h" #include "cmFileTimeComparison.h"
#include <cmsys/Directory.hxx> // Use a hash table to avoid duplicate file time checks from disk.
#include <cmsys/RegularExpression.hxx>
#include <cmsys/SystemTools.hxx>
#if defined(CMAKE_BUILD_WITH_CMAKE) #if defined(CMAKE_BUILD_WITH_CMAKE)
# include <cmsys/hash_map.hxx> # include <cmsys/hash_map.hxx>
#endif #endif
// Use a platform-specific API to get file times efficiently.
#if !defined(_WIN32) || defined(__CYGWIN__) #if !defined(_WIN32) || defined(__CYGWIN__)
# define cmFileTimeComparison_Type struct stat # define cmFileTimeComparison_Type struct stat
# include <ctype.h> # include <ctype.h>
@ -34,13 +31,16 @@
# include <windows.h> # include <windows.h>
#endif #endif
//----------------------------------------------------------------------------
class cmFileTimeComparisonInternal class cmFileTimeComparisonInternal
{ {
public: public:
// Internal comparison method.
inline bool FileTimeCompare(const char* f1, const char* f2, int* result); inline bool FileTimeCompare(const char* f1, const char* f2, int* result);
private: private:
#if defined(CMAKE_BUILD_WITH_CMAKE) #if defined(CMAKE_BUILD_WITH_CMAKE)
// Use a hash table to efficiently map from file name to modification time.
class HashString class HashString
{ {
public: public:
@ -50,67 +50,78 @@ private:
} }
cmsys::hash<const char*> h; cmsys::hash<const char*> h;
}; };
typedef cmsys::hash_map<cmStdString, cmFileTimeComparison_Type, HashString> FileStatsMap; typedef cmsys::hash_map<cmStdString,
cmFileTimeComparison_Type, HashString> FileStatsMap;
FileStatsMap Files; FileStatsMap Files;
#endif #endif
// Internal methods to lookup and compare modification times.
inline bool Stat(const char* fname, cmFileTimeComparison_Type* st); inline bool Stat(const char* fname, cmFileTimeComparison_Type* st);
inline int Compare(cmFileTimeComparison_Type* st1, cmFileTimeComparison_Type* st2); inline int Compare(cmFileTimeComparison_Type* st1,
cmFileTimeComparison_Type* st2);
}; };
bool cmFileTimeComparisonInternal::Stat(const char* fname, cmFileTimeComparison_Type* st) //----------------------------------------------------------------------------
bool cmFileTimeComparisonInternal::Stat(const char* fname,
cmFileTimeComparison_Type* st)
{ {
#if defined(CMAKE_BUILD_WITH_CMAKE) #if defined(CMAKE_BUILD_WITH_CMAKE)
cmFileTimeComparisonInternal::FileStatsMap::iterator fit = this->Files.find(fname); // Use the stored time if available.
cmFileTimeComparisonInternal::FileStatsMap::iterator fit =
this->Files.find(fname);
if ( fit != this->Files.end() ) if ( fit != this->Files.end() )
{ {
*st = fit->second; *st = fit->second;
return true; return true;
} }
#endif #endif
#if !defined(_WIN32) || defined(__CYGWIN__) #if !defined(_WIN32) || defined(__CYGWIN__)
// POSIX version. Use the stat function.
int res = ::stat(fname, st); int res = ::stat(fname, st);
if ( res != 0 ) if ( res != 0 )
{ {
return false; return false;
} }
#else #else
// Windows version. Create file handles and get the modification times. // Windows version. Get the modification time from extended file attributes.
HANDLE hf1 = CreateFile(fname, GENERIC_READ, FILE_SHARE_READ, WIN32_FILE_ATTRIBUTE_DATA fdata;
NULL, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, if(!GetFileAttributesEx(fname, GetFileExInfoStandard, &fdata))
NULL);
if(hf1 == INVALID_HANDLE_VALUE)
{ {
return false; return false;
} }
if(!GetFileTime(hf1, 0, 0, st))
{ // Copy the file time to the output location.
CloseHandle(hf1); *st = fdata.ftLastWriteTime;
return false;
}
CloseHandle(hf1);
#endif #endif
#if defined(CMAKE_BUILD_WITH_CMAKE) #if defined(CMAKE_BUILD_WITH_CMAKE)
// Store the time for future use.
this->Files[fname] = *st; this->Files[fname] = *st;
#endif #endif
return true; return true;
} }
//----------------------------------------------------------------------------
cmFileTimeComparison::cmFileTimeComparison() cmFileTimeComparison::cmFileTimeComparison()
{ {
m_Internals = new cmFileTimeComparisonInternal; m_Internals = new cmFileTimeComparisonInternal;
} }
//----------------------------------------------------------------------------
cmFileTimeComparison::~cmFileTimeComparison() cmFileTimeComparison::~cmFileTimeComparison()
{ {
delete m_Internals; delete m_Internals;
} }
//----------------------------------------------------------------------------
bool cmFileTimeComparison::FileTimeCompare(const char* f1, const char* f2, int* result) bool cmFileTimeComparison::FileTimeCompare(const char* f1, const char* f2, int* result)
{ {
return m_Internals->FileTimeCompare(f1, f2, result); return m_Internals->FileTimeCompare(f1, f2, result);
} }
//----------------------------------------------------------------------------
int cmFileTimeComparisonInternal::Compare(cmFileTimeComparison_Type* s1, cmFileTimeComparison_Type* s2) int cmFileTimeComparisonInternal::Compare(cmFileTimeComparison_Type* s1, cmFileTimeComparison_Type* s2)
{ {
#if !defined(_WIN32) || defined(__CYGWIN__) #if !defined(_WIN32) || defined(__CYGWIN__)
@ -143,27 +154,33 @@ int cmFileTimeComparisonInternal::Compare(cmFileTimeComparison_Type* s1, cmFileT
return 1; return 1;
} }
# endif # endif
// Files have the same time.
return 0; return 0;
#else #else
// Compare using system-provided function.
return (int)CompareFileTime(s1, s2); return (int)CompareFileTime(s1, s2);
#endif #endif
} }
bool cmFileTimeComparisonInternal::FileTimeCompare(const char* f1, const char* f2, int* result) //----------------------------------------------------------------------------
bool cmFileTimeComparisonInternal::FileTimeCompare(const char* f1,
const char* f2,
int* result)
{ {
// Default to same time. // Get the modification time for each file.
*result = 0;
cmFileTimeComparison_Type s1; cmFileTimeComparison_Type s1;
if(!this->Stat(f1, &s1))
{
return false;
}
cmFileTimeComparison_Type s2; cmFileTimeComparison_Type s2;
if(!this->Stat(f2, &s2)) if(this->Stat(f1, &s1) &&
this->Stat(f2, &s2))
{ {
// Compare the two modification times.
*result = this->Compare(&s1, &s2);
return true;
}
else
{
// No comparison available. Default to the same time.
*result = 0;
return false; return false;
} }
*result = this->Compare(&s1, &s2);
return true;
} }

View File

@ -786,38 +786,20 @@ bool SystemTools::FileTimeCompare(const char* f1, const char* f2,
} }
# endif # endif
#else #else
// Windows version. Create file handles and get the modification times. // Windows version. Get the modification time from extended file attributes.
HANDLE hf1 = CreateFile(f1, GENERIC_READ, FILE_SHARE_READ, WIN32_FILE_ATTRIBUTE_DATA f1d;
NULL, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, WIN32_FILE_ATTRIBUTE_DATA f2d;
NULL); if(!GetFileAttributesEx(f1, GetFileExInfoStandard, &f1d))
if(hf1 == INVALID_HANDLE_VALUE)
{ {
return false; return false;
} }
FILETIME tf1; if(!GetFileAttributesEx(f2, GetFileExInfoStandard, &f2d))
if(!GetFileTime(hf1, 0, 0, &tf1))
{
CloseHandle(hf1);
return false;
}
CloseHandle(hf1);
HANDLE hf2 = CreateFile(f2, GENERIC_READ, FILE_SHARE_READ,
NULL, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS,
NULL);
if(hf2 == INVALID_HANDLE_VALUE)
{ {
return false; return false;
} }
FILETIME tf2;
if(!GetFileTime(hf2, 0, 0, &tf2))
{
CloseHandle(hf2);
return false;
}
CloseHandle(hf2);
// Compare the file times using resolution provided by system call. // Compare the file times using resolution provided by system call.
*result = (int)CompareFileTime(&tf1, &tf2); *result = (int)CompareFileTime(&f1d.ftLastWriteTime, &f2d.ftLastWriteTime);
#endif #endif
return true; return true;
} }