diff options
Diffstat (limited to 'ninja/src/disk_interface.cc')
-rw-r--r-- | ninja/src/disk_interface.cc | 177 |
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; + } +} |