Ninja
|
00001 // Copyright 2011 Google Inc. All Rights Reserved. 00002 // 00003 // Licensed under the Apache License, Version 2.0 (the "License"); 00004 // you may not use this file except in compliance with the License. 00005 // You may obtain a copy of the License at 00006 // 00007 // http://www.apache.org/licenses/LICENSE-2.0 00008 // 00009 // Unless required by applicable law or agreed to in writing, software 00010 // distributed under the License is distributed on an "AS IS" BASIS, 00011 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 00012 // See the License for the specific language governing permissions and 00013 // limitations under the License. 00014 00015 #include "disk_interface.h" 00016 00017 #include <errno.h> 00018 #include <stdio.h> 00019 #include <string.h> 00020 #include <sys/stat.h> 00021 #include <sys/types.h> 00022 00023 #ifdef _WIN32 00024 #include <windows.h> 00025 #include <direct.h> // _mkdir 00026 #endif 00027 00028 #include "util.h" 00029 00030 namespace { 00031 00032 string DirName(const string& path) { 00033 #ifdef _WIN32 00034 const char kPathSeparator = '\\'; 00035 #else 00036 const char kPathSeparator = '/'; 00037 #endif 00038 00039 string::size_type slash_pos = path.rfind(kPathSeparator); 00040 if (slash_pos == string::npos) 00041 return string(); // Nothing to do. 00042 while (slash_pos > 0 && path[slash_pos - 1] == kPathSeparator) 00043 --slash_pos; 00044 return path.substr(0, slash_pos); 00045 } 00046 00047 int MakeDir(const string& path) { 00048 #ifdef _WIN32 00049 return _mkdir(path.c_str()); 00050 #else 00051 return mkdir(path.c_str(), 0777); 00052 #endif 00053 } 00054 00055 } // namespace 00056 00057 // DiskInterface --------------------------------------------------------------- 00058 00059 bool DiskInterface::MakeDirs(const string& path) { 00060 string dir = DirName(path); 00061 if (dir.empty()) 00062 return true; // Reached root; assume it's there. 00063 TimeStamp mtime = Stat(dir); 00064 if (mtime < 0) 00065 return false; // Error. 00066 if (mtime > 0) 00067 return true; // Exists already; we're done. 00068 00069 // Directory doesn't exist. Try creating its parent first. 00070 bool success = MakeDirs(dir); 00071 if (!success) 00072 return false; 00073 return MakeDir(dir); 00074 } 00075 00076 // RealDiskInterface ----------------------------------------------------------- 00077 00078 TimeStamp RealDiskInterface::Stat(const string& path) { 00079 #ifdef _WIN32 00080 // MSDN: "Naming Files, Paths, and Namespaces" 00081 // http://msdn.microsoft.com/en-us/library/windows/desktop/aa365247(v=vs.85).aspx 00082 if (!path.empty() && path[0] != '\\' && path.size() > MAX_PATH) { 00083 if (!quiet_) { 00084 Error("Stat(%s): Filename longer than %i characters", 00085 path.c_str(), MAX_PATH); 00086 } 00087 return -1; 00088 } 00089 WIN32_FILE_ATTRIBUTE_DATA attrs; 00090 if (!GetFileAttributesEx(path.c_str(), GetFileExInfoStandard, &attrs)) { 00091 DWORD err = GetLastError(); 00092 if (err == ERROR_FILE_NOT_FOUND || err == ERROR_PATH_NOT_FOUND) 00093 return 0; 00094 if (!quiet_) { 00095 Error("GetFileAttributesEx(%s): %s", path.c_str(), 00096 GetLastErrorString().c_str()); 00097 } 00098 return -1; 00099 } 00100 const FILETIME& filetime = attrs.ftLastWriteTime; 00101 // FILETIME is in 100-nanosecond increments since the Windows epoch. 00102 // We don't much care about epoch correctness but we do want the 00103 // resulting value to fit in an integer. 00104 uint64_t mtime = ((uint64_t)filetime.dwHighDateTime << 32) | 00105 ((uint64_t)filetime.dwLowDateTime); 00106 mtime /= 1000000000LL / 100; // 100ns -> s. 00107 mtime -= 12622770400LL; // 1600 epoch -> 2000 epoch (subtract 400 years). 00108 return (TimeStamp)mtime; 00109 #else 00110 struct stat st; 00111 if (stat(path.c_str(), &st) < 0) { 00112 if (errno == ENOENT || errno == ENOTDIR) 00113 return 0; 00114 if (!quiet_) { 00115 Error("stat(%s): %s", path.c_str(), strerror(errno)); 00116 } 00117 return -1; 00118 } 00119 return st.st_mtime; 00120 #endif 00121 } 00122 00123 bool RealDiskInterface::WriteFile(const string& path, const string& contents) { 00124 FILE * fp = fopen(path.c_str(), "w"); 00125 if (fp == NULL) { 00126 Error("WriteFile(%s): Unable to create file. %s", 00127 path.c_str(), strerror(errno)); 00128 return false; 00129 } 00130 00131 if (fwrite(contents.data(), 1, contents.length(), fp) < contents.length()) { 00132 Error("WriteFile(%s): Unable to write to the file. %s", 00133 path.c_str(), strerror(errno)); 00134 fclose(fp); 00135 return false; 00136 } 00137 00138 if (fclose(fp) == EOF) { 00139 Error("WriteFile(%s): Unable to close the file. %s", 00140 path.c_str(), strerror(errno)); 00141 return false; 00142 } 00143 00144 return true; 00145 } 00146 00147 bool RealDiskInterface::MakeDir(const string& path) { 00148 if (::MakeDir(path) < 0) { 00149 Error("mkdir(%s): %s", path.c_str(), strerror(errno)); 00150 return false; 00151 } 00152 return true; 00153 } 00154 00155 string RealDiskInterface::ReadFile(const string& path, string* err) { 00156 string contents; 00157 int ret = ::ReadFile(path, &contents, err); 00158 if (ret == -ENOENT) { 00159 // Swallow ENOENT. 00160 err->clear(); 00161 } 00162 return contents; 00163 } 00164 00165 int RealDiskInterface::RemoveFile(const string& path) { 00166 if (remove(path.c_str()) < 0) { 00167 switch (errno) { 00168 case ENOENT: 00169 return 1; 00170 default: 00171 Error("remove(%s): %s", path.c_str(), strerror(errno)); 00172 return -1; 00173 } 00174 } else { 00175 return 0; 00176 } 00177 }