summaryrefslogtreecommitdiff
path: root/ninja/src/disk_interface.cc
diff options
context:
space:
mode:
Diffstat (limited to 'ninja/src/disk_interface.cc')
-rw-r--r--ninja/src/disk_interface.cc177
1 files changed, 177 insertions, 0 deletions
diff --git a/ninja/src/disk_interface.cc b/ninja/src/disk_interface.cc
new file mode 100644
index 00000000000..ee3e99a3b98
--- /dev/null
+++ b/ninja/src/disk_interface.cc
@@ -0,0 +1,177 @@
+// Copyright 2011 Google Inc. All Rights Reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#include "disk_interface.h"
+
+#include <errno.h>
+#include <stdio.h>
+#include <string.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+
+#ifdef _WIN32
+#include <windows.h>
+#include <direct.h> // _mkdir
+#endif
+
+#include "util.h"
+
+namespace {
+
+string DirName(const string& path) {
+#ifdef _WIN32
+ const char kPathSeparator = '\\';
+#else
+ const char kPathSeparator = '/';
+#endif
+
+ string::size_type slash_pos = path.rfind(kPathSeparator);
+ if (slash_pos == string::npos)
+ return string(); // Nothing to do.
+ while (slash_pos > 0 && path[slash_pos - 1] == kPathSeparator)
+ --slash_pos;
+ return path.substr(0, slash_pos);
+}
+
+int MakeDir(const string& path) {
+#ifdef _WIN32
+ return _mkdir(path.c_str());
+#else
+ return mkdir(path.c_str(), 0777);
+#endif
+}
+
+} // namespace
+
+// DiskInterface ---------------------------------------------------------------
+
+bool DiskInterface::MakeDirs(const string& path) {
+ string dir = DirName(path);
+ if (dir.empty())
+ return true; // Reached root; assume it's there.
+ TimeStamp mtime = Stat(dir);
+ if (mtime < 0)
+ return false; // Error.
+ if (mtime > 0)
+ return true; // Exists already; we're done.
+
+ // Directory doesn't exist. Try creating its parent first.
+ bool success = MakeDirs(dir);
+ if (!success)
+ return false;
+ return MakeDir(dir);
+}
+
+// RealDiskInterface -----------------------------------------------------------
+
+TimeStamp RealDiskInterface::Stat(const string& path) {
+#ifdef _WIN32
+ // MSDN: "Naming Files, Paths, and Namespaces"
+ // http://msdn.microsoft.com/en-us/library/windows/desktop/aa365247(v=vs.85).aspx
+ if (!path.empty() && path[0] != '\\' && path.size() > MAX_PATH) {
+ if (!quiet_) {
+ Error("Stat(%s): Filename longer than %i characters",
+ path.c_str(), MAX_PATH);
+ }
+ return -1;
+ }
+ WIN32_FILE_ATTRIBUTE_DATA attrs;
+ if (!GetFileAttributesEx(path.c_str(), GetFileExInfoStandard, &attrs)) {
+ DWORD err = GetLastError();
+ if (err == ERROR_FILE_NOT_FOUND || err == ERROR_PATH_NOT_FOUND)
+ return 0;
+ if (!quiet_) {
+ Error("GetFileAttributesEx(%s): %s", path.c_str(),
+ GetLastErrorString().c_str());
+ }
+ return -1;
+ }
+ const FILETIME& filetime = attrs.ftLastWriteTime;
+ // FILETIME is in 100-nanosecond increments since the Windows epoch.
+ // We don't much care about epoch correctness but we do want the
+ // resulting value to fit in an integer.
+ uint64_t mtime = ((uint64_t)filetime.dwHighDateTime << 32) |
+ ((uint64_t)filetime.dwLowDateTime);
+ mtime /= 1000000000LL / 100; // 100ns -> s.
+ mtime -= 12622770400LL; // 1600 epoch -> 2000 epoch (subtract 400 years).
+ return (TimeStamp)mtime;
+#else
+ struct stat st;
+ if (stat(path.c_str(), &st) < 0) {
+ if (errno == ENOENT || errno == ENOTDIR)
+ return 0;
+ if (!quiet_) {
+ Error("stat(%s): %s", path.c_str(), strerror(errno));
+ }
+ return -1;
+ }
+ return st.st_mtime;
+#endif
+}
+
+bool RealDiskInterface::WriteFile(const string& path, const string& contents) {
+ FILE * fp = fopen(path.c_str(), "w");
+ if (fp == NULL) {
+ Error("WriteFile(%s): Unable to create file. %s",
+ path.c_str(), strerror(errno));
+ return false;
+ }
+
+ if (fwrite(contents.data(), 1, contents.length(), fp) < contents.length()) {
+ Error("WriteFile(%s): Unable to write to the file. %s",
+ path.c_str(), strerror(errno));
+ fclose(fp);
+ return false;
+ }
+
+ if (fclose(fp) == EOF) {
+ Error("WriteFile(%s): Unable to close the file. %s",
+ path.c_str(), strerror(errno));
+ return false;
+ }
+
+ return true;
+}
+
+bool RealDiskInterface::MakeDir(const string& path) {
+ if (::MakeDir(path) < 0) {
+ Error("mkdir(%s): %s", path.c_str(), strerror(errno));
+ return false;
+ }
+ return true;
+}
+
+string RealDiskInterface::ReadFile(const string& path, string* err) {
+ string contents;
+ int ret = ::ReadFile(path, &contents, err);
+ if (ret == -ENOENT) {
+ // Swallow ENOENT.
+ err->clear();
+ }
+ return contents;
+}
+
+int RealDiskInterface::RemoveFile(const string& path) {
+ if (remove(path.c_str()) < 0) {
+ switch (errno) {
+ case ENOENT:
+ return 1;
+ default:
+ Error("remove(%s): %s", path.c_str(), strerror(errno));
+ return -1;
+ }
+ } else {
+ return 0;
+ }
+}