1 /*============================================================================
2 CMake - Cross Platform Makefile Generator
3 Copyright 2000-2009 Kitware, Inc., Insight Software Consortium
5 Distributed under the OSI-approved BSD License (the "License");
6 see accompanying file Copyright.txt for details.
8 This software is distributed WITHOUT ANY WARRANTY; without even the
9 implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
10 See the License for more information.
11 ============================================================================*/
12 #include "cmFileTimeComparison.h"
14 // Use a hash table to avoid duplicate file time checks from disk.
15 #if defined(CMAKE_BUILD_WITH_CMAKE)
16 # include <cmsys/hash_map.hxx>
19 // Use a platform-specific API to get file times efficiently.
20 #if !defined(_WIN32) || defined(__CYGWIN__)
21 # define cmFileTimeComparison_Type struct stat
23 # include <sys/stat.h>
25 # define cmFileTimeComparison_Type FILETIME
29 //----------------------------------------------------------------------------
30 class cmFileTimeComparisonInternal
33 // Internal comparison method.
34 inline bool FileTimeCompare(const char* f1, const char* f2, int* result);
36 bool FileTimesDiffer(const char* f1, const char* f2);
39 #if defined(CMAKE_BUILD_WITH_CMAKE)
40 // Use a hash table to efficiently map from file name to modification time.
44 size_t operator()(const cmStdString& s) const
48 cmsys::hash<const char*> h;
50 typedef cmsys::hash_map<cmStdString,
51 cmFileTimeComparison_Type, HashString> FileStatsMap;
55 // Internal methods to lookup and compare modification times.
56 inline bool Stat(const char* fname, cmFileTimeComparison_Type* st);
57 inline int Compare(cmFileTimeComparison_Type* st1,
58 cmFileTimeComparison_Type* st2);
59 inline bool TimesDiffer(cmFileTimeComparison_Type* st1,
60 cmFileTimeComparison_Type* st2);
63 //----------------------------------------------------------------------------
64 bool cmFileTimeComparisonInternal::Stat(const char* fname,
65 cmFileTimeComparison_Type* st)
67 #if defined(CMAKE_BUILD_WITH_CMAKE)
68 // Use the stored time if available.
69 cmFileTimeComparisonInternal::FileStatsMap::iterator fit =
70 this->Files.find(fname);
71 if ( fit != this->Files.end() )
78 #if !defined(_WIN32) || defined(__CYGWIN__)
79 // POSIX version. Use the stat function.
80 int res = ::stat(fname, st);
86 // Windows version. Get the modification time from extended file
88 WIN32_FILE_ATTRIBUTE_DATA fdata;
89 if(!GetFileAttributesEx(fname, GetFileExInfoStandard, &fdata))
94 // Copy the file time to the output location.
95 *st = fdata.ftLastWriteTime;
98 #if defined(CMAKE_BUILD_WITH_CMAKE)
99 // Store the time for future use.
100 this->Files[fname] = *st;
106 //----------------------------------------------------------------------------
107 cmFileTimeComparison::cmFileTimeComparison()
109 this->Internals = new cmFileTimeComparisonInternal;
112 //----------------------------------------------------------------------------
113 cmFileTimeComparison::~cmFileTimeComparison()
115 delete this->Internals;
118 //----------------------------------------------------------------------------
119 bool cmFileTimeComparison::FileTimeCompare(const char* f1,
120 const char* f2, int* result)
122 return this->Internals->FileTimeCompare(f1, f2, result);
125 //----------------------------------------------------------------------------
126 bool cmFileTimeComparison::FileTimesDiffer(const char* f1, const char* f2)
128 return this->Internals->FileTimesDiffer(f1, f2);
131 //----------------------------------------------------------------------------
132 int cmFileTimeComparisonInternal::Compare(cmFileTimeComparison_Type* s1,
133 cmFileTimeComparison_Type* s2)
135 #if !defined(_WIN32) || defined(__CYGWIN__)
136 # if cmsys_STAT_HAS_ST_MTIM
137 // Compare using nanosecond resolution.
138 if(s1->st_mtim.tv_sec < s2->st_mtim.tv_sec)
142 else if(s1->st_mtim.tv_sec > s2->st_mtim.tv_sec)
146 else if(s1->st_mtim.tv_nsec < s2->st_mtim.tv_nsec)
150 else if(s1->st_mtim.tv_nsec > s2->st_mtim.tv_nsec)
155 // Compare using 1 second resolution.
156 if(s1->st_mtime < s2->st_mtime)
160 else if(s1->st_mtime > s2->st_mtime)
165 // Files have the same time.
168 // Compare using system-provided function.
169 return (int)CompareFileTime(s1, s2);
173 //----------------------------------------------------------------------------
174 bool cmFileTimeComparisonInternal::TimesDiffer(cmFileTimeComparison_Type* s1,
175 cmFileTimeComparison_Type* s2)
177 #if !defined(_WIN32) || defined(__CYGWIN__)
178 # if cmsys_STAT_HAS_ST_MTIM
179 // Times are integers in units of 1ns.
180 long long bil = 1000000000;
181 long long t1 = s1->st_mtim.tv_sec * bil + s1->st_mtim.tv_nsec;
182 long long t2 = s2->st_mtim.tv_sec * bil + s2->st_mtim.tv_nsec;
185 return (t2 - t1) >= bil;
189 return (t1 - t2) >= bil;
196 // Times are integers in units of 1s.
197 if(s1->st_mtime < s2->st_mtime)
199 return (s2->st_mtime - s1->st_mtime) >= 1;
201 else if(s1->st_mtime > s2->st_mtime)
203 return (s1->st_mtime - s2->st_mtime) >= 1;
211 // Times are integers in units of 100ns.
214 t1.LowPart = s1->dwLowDateTime;
215 t1.HighPart = s1->dwHighDateTime;
216 t2.LowPart = s2->dwLowDateTime;
217 t2.HighPart = s2->dwHighDateTime;
218 if(t1.QuadPart < t2.QuadPart)
220 return (t2.QuadPart - t1.QuadPart) >= static_cast<LONGLONG>(10000000);
222 else if(t2.QuadPart < t1.QuadPart)
224 return (t1.QuadPart - t2.QuadPart) >= static_cast<LONGLONG>(10000000);
233 //----------------------------------------------------------------------------
234 bool cmFileTimeComparisonInternal::FileTimeCompare(const char* f1,
238 // Get the modification time for each file.
239 cmFileTimeComparison_Type s1;
240 cmFileTimeComparison_Type s2;
241 if(this->Stat(f1, &s1) &&
244 // Compare the two modification times.
245 *result = this->Compare(&s1, &s2);
250 // No comparison available. Default to the same time.
256 //----------------------------------------------------------------------------
257 bool cmFileTimeComparisonInternal::FileTimesDiffer(const char* f1,
260 // Get the modification time for each file.
261 cmFileTimeComparison_Type s1;
262 cmFileTimeComparison_Type s2;
263 if(this->Stat(f1, &s1) &&
266 // Compare the two modification times.
267 return this->TimesDiffer(&s1, &s2);
271 // No comparison available. Default to different times.