Ninja
disk_interface.cc
Go to the documentation of this file.
1 // Copyright 2011 Google Inc. All Rights Reserved.
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 //
7 // http://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14 
15 #include "disk_interface.h"
16 
17 #include <errno.h>
18 #include <stdio.h>
19 #include <string.h>
20 #include <sys/stat.h>
21 #include <sys/types.h>
22 
23 #ifdef _WIN32
24 #include <windows.h>
25 #include <direct.h> // _mkdir
26 #endif
27 
28 #include "util.h"
29 
30 namespace {
31 
32 string DirName(const string& path) {
33 #ifdef _WIN32
34  const char kPathSeparator = '\\';
35 #else
36  const char kPathSeparator = '/';
37 #endif
38 
39  string::size_type slash_pos = path.rfind(kPathSeparator);
40  if (slash_pos == string::npos)
41  return string(); // Nothing to do.
42  while (slash_pos > 0 && path[slash_pos - 1] == kPathSeparator)
43  --slash_pos;
44  return path.substr(0, slash_pos);
45 }
46 
47 int MakeDir(const string& path) {
48 #ifdef _WIN32
49  return _mkdir(path.c_str());
50 #else
51  return mkdir(path.c_str(), 0777);
52 #endif
53 }
54 
55 } // namespace
56 
57 // DiskInterface ---------------------------------------------------------------
58 
59 bool DiskInterface::MakeDirs(const string& path) {
60  string dir = DirName(path);
61  if (dir.empty())
62  return true; // Reached root; assume it's there.
63  TimeStamp mtime = Stat(dir);
64  if (mtime < 0)
65  return false; // Error.
66  if (mtime > 0)
67  return true; // Exists already; we're done.
68 
69  // Directory doesn't exist. Try creating its parent first.
70  bool success = MakeDirs(dir);
71  if (!success)
72  return false;
73  return MakeDir(dir);
74 }
75 
76 // RealDiskInterface -----------------------------------------------------------
77 
78 TimeStamp RealDiskInterface::Stat(const string& path) {
79 #ifdef _WIN32
80  // MSDN: "Naming Files, Paths, and Namespaces"
81  // http://msdn.microsoft.com/en-us/library/windows/desktop/aa365247(v=vs.85).aspx
82  if (!path.empty() && path[0] != '\\' && path.size() > MAX_PATH) {
83  if (!quiet_) {
84  Error("Stat(%s): Filename longer than %i characters",
85  path.c_str(), MAX_PATH);
86  }
87  return -1;
88  }
89  WIN32_FILE_ATTRIBUTE_DATA attrs;
90  if (!GetFileAttributesEx(path.c_str(), GetFileExInfoStandard, &attrs)) {
91  DWORD err = GetLastError();
92  if (err == ERROR_FILE_NOT_FOUND || err == ERROR_PATH_NOT_FOUND)
93  return 0;
94  if (!quiet_) {
95  Error("GetFileAttributesEx(%s): %s", path.c_str(),
96  GetLastErrorString().c_str());
97  }
98  return -1;
99  }
100  const FILETIME& filetime = attrs.ftLastWriteTime;
101  // FILETIME is in 100-nanosecond increments since the Windows epoch.
102  // We don't much care about epoch correctness but we do want the
103  // resulting value to fit in an integer.
104  uint64_t mtime = ((uint64_t)filetime.dwHighDateTime << 32) |
105  ((uint64_t)filetime.dwLowDateTime);
106  mtime /= 1000000000LL / 100; // 100ns -> s.
107  mtime -= 12622770400LL; // 1600 epoch -> 2000 epoch (subtract 400 years).
108  return (TimeStamp)mtime;
109 #else
110  struct stat st;
111  if (stat(path.c_str(), &st) < 0) {
112  if (errno == ENOENT || errno == ENOTDIR)
113  return 0;
114  if (!quiet_) {
115  Error("stat(%s): %s", path.c_str(), strerror(errno));
116  }
117  return -1;
118  }
119  return st.st_mtime;
120 #endif
121 }
122 
123 bool RealDiskInterface::WriteFile(const string& path, const string& contents) {
124  FILE * fp = fopen(path.c_str(), "w");
125  if (fp == NULL) {
126  Error("WriteFile(%s): Unable to create file. %s",
127  path.c_str(), strerror(errno));
128  return false;
129  }
130 
131  if (fwrite(contents.data(), 1, contents.length(), fp) < contents.length()) {
132  Error("WriteFile(%s): Unable to write to the file. %s",
133  path.c_str(), strerror(errno));
134  fclose(fp);
135  return false;
136  }
137 
138  if (fclose(fp) == EOF) {
139  Error("WriteFile(%s): Unable to close the file. %s",
140  path.c_str(), strerror(errno));
141  return false;
142  }
143 
144  return true;
145 }
146 
147 bool RealDiskInterface::MakeDir(const string& path) {
148  if (::MakeDir(path) < 0) {
149  Error("mkdir(%s): %s", path.c_str(), strerror(errno));
150  return false;
151  }
152  return true;
153 }
154 
155 string RealDiskInterface::ReadFile(const string& path, string* err) {
156  string contents;
157  int ret = ::ReadFile(path, &contents, err);
158  if (ret == -ENOENT) {
159  // Swallow ENOENT.
160  err->clear();
161  }
162  return contents;
163 }
164 
165 int RealDiskInterface::RemoveFile(const string& path) {
166  if (remove(path.c_str()) < 0) {
167  switch (errno) {
168  case ENOENT:
169  return 1;
170  default:
171  Error("remove(%s): %s", path.c_str(), strerror(errno));
172  return -1;
173  }
174  } else {
175  return 0;
176  }
177 }
virtual string ReadFile(const string &path, string *err)
Read a file to a string. Fill in |err| on error.
bool MakeDirs(const string &path)
Create all the parent directories for path; like mkdir -p basename path.
int TimeStamp
Definition: timestamp.h:22
virtual bool WriteFile(const string &path, const string &contents)
Create a file, with the specified name and contents Returns true on success, false on failure...
virtual bool MakeDir(const string &path)
Create a directory, returning false on failure.
virtual TimeStamp Stat(const string &path)
stat() a file, returning the mtime, or 0 if missing and -1 on other errors.
virtual int RemoveFile(const string &path)
Remove the file named path.
unsigned long long uint64_t
Definition: win32port.h:22
virtual bool MakeDir(const string &path)=0
Create a directory, returning false on failure.
IN DWORD
bool quiet_
Whether to print on errors. Used to make a test quieter.
virtual TimeStamp Stat(const string &path)=0
stat() a file, returning the mtime, or 0 if missing and -1 on other errors.
void Error(const char *msg,...)
Log an error message.
Definition: util.cc:78