1 /*=========================================================================
3 Program: CMake - Cross-Platform Makefile Generator
4 Module: $RCSfile: cmFileTimeComparison.cxx,v $
6 Date: $Date: 2008-01-03 05:01:38 $
7 Version: $Revision: 1.7 $
9 Copyright (c) 2002 Kitware, Inc., Insight Consortium. All rights reserved.
10 See Copyright.txt or http://www.cmake.org/HTML/Copyright.html for details.
12 This software is distributed WITHOUT ANY WARRANTY; without even
13 the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
14 PURPOSE. See the above copyright notices for more information.
16 =========================================================================*/
17 #include "cmFileTimeComparison.h"
19 // Use a hash table to avoid duplicate file time checks from disk.
20 #if defined(CMAKE_BUILD_WITH_CMAKE)
21 # include <cmsys/hash_map.hxx>
24 // Use a platform-specific API to get file times efficiently.
25 #if !defined(_WIN32) || defined(__CYGWIN__)
26 # define cmFileTimeComparison_Type struct stat
28 # include <sys/stat.h>
30 # define cmFileTimeComparison_Type FILETIME
34 //----------------------------------------------------------------------------
35 class cmFileTimeComparisonInternal
38 // Internal comparison method.
39 inline bool FileTimeCompare(const char* f1
, const char* f2
, int* result
);
41 bool FileTimesDiffer(const char* f1
, const char* f2
);
44 #if defined(CMAKE_BUILD_WITH_CMAKE)
45 // Use a hash table to efficiently map from file name to modification time.
49 size_t operator()(const cmStdString
& s
) const
53 cmsys::hash
<const char*> h
;
55 typedef cmsys::hash_map
<cmStdString
,
56 cmFileTimeComparison_Type
, HashString
> FileStatsMap
;
60 // Internal methods to lookup and compare modification times.
61 inline bool Stat(const char* fname
, cmFileTimeComparison_Type
* st
);
62 inline int Compare(cmFileTimeComparison_Type
* st1
,
63 cmFileTimeComparison_Type
* st2
);
64 inline bool TimesDiffer(cmFileTimeComparison_Type
* st1
,
65 cmFileTimeComparison_Type
* st2
);
68 //----------------------------------------------------------------------------
69 bool cmFileTimeComparisonInternal::Stat(const char* fname
,
70 cmFileTimeComparison_Type
* st
)
72 #if defined(CMAKE_BUILD_WITH_CMAKE)
73 // Use the stored time if available.
74 cmFileTimeComparisonInternal::FileStatsMap::iterator fit
=
75 this->Files
.find(fname
);
76 if ( fit
!= this->Files
.end() )
83 #if !defined(_WIN32) || defined(__CYGWIN__)
84 // POSIX version. Use the stat function.
85 int res
= ::stat(fname
, st
);
91 // Windows version. Get the modification time from extended file
93 WIN32_FILE_ATTRIBUTE_DATA fdata
;
94 if(!GetFileAttributesEx(fname
, GetFileExInfoStandard
, &fdata
))
99 // Copy the file time to the output location.
100 *st
= fdata
.ftLastWriteTime
;
103 #if defined(CMAKE_BUILD_WITH_CMAKE)
104 // Store the time for future use.
105 this->Files
[fname
] = *st
;
111 //----------------------------------------------------------------------------
112 cmFileTimeComparison::cmFileTimeComparison()
114 this->Internals
= new cmFileTimeComparisonInternal
;
117 //----------------------------------------------------------------------------
118 cmFileTimeComparison::~cmFileTimeComparison()
120 delete this->Internals
;
123 //----------------------------------------------------------------------------
124 bool cmFileTimeComparison::FileTimeCompare(const char* f1
,
125 const char* f2
, int* result
)
127 return this->Internals
->FileTimeCompare(f1
, f2
, result
);
130 //----------------------------------------------------------------------------
131 bool cmFileTimeComparison::FileTimesDiffer(const char* f1
, const char* f2
)
133 return this->Internals
->FileTimesDiffer(f1
, f2
);
136 //----------------------------------------------------------------------------
137 int cmFileTimeComparisonInternal::Compare(cmFileTimeComparison_Type
* s1
,
138 cmFileTimeComparison_Type
* s2
)
140 #if !defined(_WIN32) || defined(__CYGWIN__)
141 # if cmsys_STAT_HAS_ST_MTIM
142 // Compare using nanosecond resolution.
143 if(s1
->st_mtim
.tv_sec
< s2
->st_mtim
.tv_sec
)
147 else if(s1
->st_mtim
.tv_sec
> s2
->st_mtim
.tv_sec
)
151 else if(s1
->st_mtim
.tv_nsec
< s2
->st_mtim
.tv_nsec
)
155 else if(s1
->st_mtim
.tv_nsec
> s2
->st_mtim
.tv_nsec
)
160 // Compare using 1 second resolution.
161 if(s1
->st_mtime
< s2
->st_mtime
)
165 else if(s1
->st_mtime
> s2
->st_mtime
)
170 // Files have the same time.
173 // Compare using system-provided function.
174 return (int)CompareFileTime(s1
, s2
);
178 //----------------------------------------------------------------------------
179 bool cmFileTimeComparisonInternal::TimesDiffer(cmFileTimeComparison_Type
* s1
,
180 cmFileTimeComparison_Type
* s2
)
182 #if !defined(_WIN32) || defined(__CYGWIN__)
183 # if cmsys_STAT_HAS_ST_MTIM
184 // Times are integers in units of 1ns.
185 long long bil
= 1000000000;
186 long long t1
= s1
->st_mtim
.tv_sec
* bil
+ s1
->st_mtim
.tv_nsec
;
187 long long t2
= s2
->st_mtim
.tv_sec
* bil
+ s2
->st_mtim
.tv_nsec
;
190 return (t2
- t1
) >= bil
;
194 return (t1
- t2
) >= bil
;
201 // Times are integers in units of 1s.
202 if(s1
->st_mtime
< s2
->st_mtime
)
204 return (s2
->st_mtime
- s1
->st_mtime
) >= 1;
206 else if(s1
->st_mtime
> s2
->st_mtime
)
208 return (s1
->st_mtime
- s2
->st_mtime
) >= 1;
216 // Times are integers in units of 100ns.
219 t1
.LowPart
= s1
->dwLowDateTime
;
220 t1
.HighPart
= s1
->dwHighDateTime
;
221 t2
.LowPart
= s2
->dwLowDateTime
;
222 t2
.HighPart
= s2
->dwHighDateTime
;
223 if(t1
.QuadPart
< t2
.QuadPart
)
225 return (t2
.QuadPart
- t1
.QuadPart
) >= static_cast<LONGLONG
>(10000000);
227 else if(t2
.QuadPart
< t1
.QuadPart
)
229 return (t1
.QuadPart
- t2
.QuadPart
) >= static_cast<LONGLONG
>(10000000);
238 //----------------------------------------------------------------------------
239 bool cmFileTimeComparisonInternal::FileTimeCompare(const char* f1
,
243 // Get the modification time for each file.
244 cmFileTimeComparison_Type s1
;
245 cmFileTimeComparison_Type s2
;
246 if(this->Stat(f1
, &s1
) &&
249 // Compare the two modification times.
250 *result
= this->Compare(&s1
, &s2
);
255 // No comparison available. Default to the same time.
261 //----------------------------------------------------------------------------
262 bool cmFileTimeComparisonInternal::FileTimesDiffer(const char* f1
,
265 // Get the modification time for each file.
266 cmFileTimeComparison_Type s1
;
267 cmFileTimeComparison_Type s2
;
268 if(this->Stat(f1
, &s1
) &&
271 // Compare the two modification times.
272 return this->TimesDiffer(&s1
, &s2
);
276 // No comparison available. Default to different times.