23 #include <sys/types.h> 40 string DirName(
const string& path) {
42 static const char kPathSeparators[] =
"\\/";
44 static const char kPathSeparators[] =
"/";
46 static const char*
const kEnd = kPathSeparators +
sizeof(kPathSeparators) - 1;
48 string::size_type slash_pos = path.find_last_of(kPathSeparators);
49 if (slash_pos == string::npos)
51 while (slash_pos > 0 &&
52 std::find(kPathSeparators, kEnd, path[slash_pos - 1]) != kEnd)
54 return path.substr(0, slash_pos);
57 int MakeDir(
const string& path) {
59 return _mkdir(path.c_str());
61 return mkdir(path.c_str(), 0777);
66 TimeStamp TimeStampFromFileTime(
const FILETIME& filetime) {
73 return (
TimeStamp)mtime - 12622770400LL * (1000000000LL / 100);
76 TimeStamp StatSingleFile(
const string& path,
string* err) {
77 WIN32_FILE_ATTRIBUTE_DATA attrs;
78 if (!GetFileAttributesExA(path.c_str(), GetFileExInfoStandard, &attrs)) {
79 DWORD win_err = GetLastError();
80 if (win_err == ERROR_FILE_NOT_FOUND || win_err == ERROR_PATH_NOT_FOUND)
82 *err =
"GetFileAttributesEx(" + path +
"): " + GetLastErrorString();
85 return TimeStampFromFileTime(attrs.ftLastWriteTime);
88 bool IsWindows7OrLater() {
89 OSVERSIONINFOEX version_info =
90 {
sizeof(OSVERSIONINFOEX), 6, 1, 0, 0, {0}, 0, 0, 0, 0, 0};
91 DWORDLONG comparison = 0;
92 VER_SET_CONDITION(comparison, VER_MAJORVERSION, VER_GREATER_EQUAL);
93 VER_SET_CONDITION(comparison, VER_MINORVERSION, VER_GREATER_EQUAL);
94 return VerifyVersionInfo(
95 &version_info, VER_MAJORVERSION | VER_MINORVERSION, comparison);
98 bool StatAllFilesInDir(
const string& dir, map<string, TimeStamp>* stamps,
101 static bool can_use_basic_info = IsWindows7OrLater();
103 const FINDEX_INFO_LEVELS kFindExInfoBasic =
104 static_cast<FINDEX_INFO_LEVELS
>(1);
105 FINDEX_INFO_LEVELS level =
106 can_use_basic_info ? kFindExInfoBasic : FindExInfoStandard;
107 WIN32_FIND_DATAA ffd;
108 HANDLE find_handle = FindFirstFileExA((dir +
"\\*").c_str(), level, &ffd,
109 FindExSearchNameMatch, NULL, 0);
111 if (find_handle == INVALID_HANDLE_VALUE) {
112 DWORD win_err = GetLastError();
113 if (win_err == ERROR_FILE_NOT_FOUND || win_err == ERROR_PATH_NOT_FOUND)
115 *err =
"FindFirstFileExA(" + dir +
"): " + GetLastErrorString();
119 string lowername = ffd.cFileName;
120 if (lowername ==
"..") {
125 transform(lowername.begin(), lowername.end(), lowername.begin(), ::tolower);
126 stamps->insert(make_pair(lowername,
127 TimeStampFromFileTime(ffd.ftLastWriteTime)));
128 }
while (FindNextFileA(find_handle, &ffd));
129 FindClose(find_handle);
139 string dir = DirName(path);
145 Error(
"%s", err.c_str());
152 bool success = MakeDirs(dir);
165 if (!path.empty() && path[0] !=
'\\' && path.size() > MAX_PATH) {
166 ostringstream err_stream;
167 err_stream <<
"Stat(" << path <<
"): Filename longer than " << MAX_PATH
169 *err = err_stream.str();
173 return StatSingleFile(path, err);
175 string dir = DirName(path);
176 string base(path.substr(dir.size() ? dir.size() + 1 : 0));
183 string dir_lowercase = dir;
184 transform(dir.begin(), dir.end(), dir_lowercase.begin(), ::tolower);
185 transform(base.begin(), base.end(), base.begin(), ::tolower);
187 Cache::iterator ci = cache_.find(dir_lowercase);
188 if (ci == cache_.end()) {
189 ci = cache_.insert(make_pair(dir_lowercase, DirCache())).first;
190 if (!StatAllFilesInDir(dir.empty() ?
"." : dir, &ci->second, err)) {
195 DirCache::iterator di = ci->second.find(base);
196 return di != ci->second.end() ? di->second : 0;
199 if (stat(path.c_str(), &st) < 0) {
200 if (errno == ENOENT || errno == ENOTDIR)
202 *err =
"stat(" + path +
"): " + strerror(errno);
208 if (st.st_mtime == 0)
211 return (
int64_t)st.st_mtime * 1000000000LL + st.st_mtime_n;
212 #elif defined(__APPLE__) 213 return ((
int64_t)st.st_mtimespec.tv_sec * 1000000000LL +
214 st.st_mtimespec.tv_nsec);
215 #elif defined(st_mtime) // A macro, so we're likely on modern POSIX. 216 return (
int64_t)st.st_mtim.tv_sec * 1000000000LL + st.st_mtim.tv_nsec;
218 return (
int64_t)st.st_mtime * 1000000000LL + st.st_mtimensec;
224 FILE* fp = fopen(path.c_str(),
"w");
226 Error(
"WriteFile(%s): Unable to create file. %s",
227 path.c_str(), strerror(errno));
231 if (fwrite(contents.data(), 1, contents.length(), fp) < contents.length()) {
232 Error(
"WriteFile(%s): Unable to write to the file. %s",
233 path.c_str(), strerror(errno));
238 if (fclose(fp) == EOF) {
239 Error(
"WriteFile(%s): Unable to close the file. %s",
240 path.c_str(), strerror(errno));
248 if (::MakeDir(path) < 0) {
249 if (errno == EEXIST) {
252 Error(
"mkdir(%s): %s", path.c_str(), strerror(errno));
261 switch (::
ReadFile(path, contents, err)) {
263 case -ENOENT:
return NotFound;
264 default:
return OtherError;
270 DWORD attributes = GetFileAttributes(path.c_str());
271 if (attributes == INVALID_FILE_ATTRIBUTES) {
272 DWORD win_err = GetLastError();
273 if (win_err == ERROR_FILE_NOT_FOUND || win_err == ERROR_PATH_NOT_FOUND) {
276 }
else if (attributes & FILE_ATTRIBUTE_READONLY) {
281 SetFileAttributes(path.c_str(), attributes & ~FILE_ATTRIBUTE_READONLY);
283 if (attributes & FILE_ATTRIBUTE_DIRECTORY) {
289 if (!RemoveDirectory(path.c_str())) {
290 DWORD win_err = GetLastError();
291 if (win_err == ERROR_FILE_NOT_FOUND || win_err == ERROR_PATH_NOT_FOUND) {
295 Error(
"remove(%s): %s", path.c_str(), GetLastErrorString().c_str());
299 if (!DeleteFile(path.c_str())) {
300 DWORD win_err = GetLastError();
301 if (win_err == ERROR_FILE_NOT_FOUND || win_err == ERROR_PATH_NOT_FOUND) {
305 Error(
"remove(%s): %s", path.c_str(), GetLastErrorString().c_str());
310 if (
remove(path.c_str()) < 0) {
315 Error(
"remove(%s): %s", path.c_str(), strerror(errno));
virtual bool MakeDir(const std::string &path)
Create a directory, returning false on failure.
virtual TimeStamp Stat(const std::string &path, std::string *err) const
stat() a file, returning the mtime, or 0 if missing and -1 on other errors.
signed long long int64_t
A 64-bit integer type.
virtual bool WriteFile(const std::string &path, const std::string &contents)
Create a file, with the specified name and contents Returns true on success, false on failure...
Status
Result of ReadFile.
int ReadFile(const string &path, string *contents, string *err)
#define METRIC_RECORD(name)
The primary interface to metrics.
virtual Status ReadFile(const std::string &path, std::string *contents, std::string *err)
Read and store in given string.
bool MakeDirs(const std::string &path)
Create all the parent directories for path; like mkdir -p basename path.
void AllowStatCache(bool allow)
Whether stat information can be cached. Only has an effect on Windows.
void Error(const char *msg, va_list ap)
unsigned long long uint64_t
virtual int RemoveFile(const std::string &path)
Remove the file named path.