diff options
Diffstat (limited to 'src/fileutil.cc')
| -rw-r--r-- | src/fileutil.cc | 211 |
1 files changed, 211 insertions, 0 deletions
diff --git a/src/fileutil.cc b/src/fileutil.cc new file mode 100644 index 0000000..7ebb8ec --- /dev/null +++ b/src/fileutil.cc @@ -0,0 +1,211 @@ +// Copyright 2015 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. + +// +build ignore + +#include "fileutil.h" + +#include <errno.h> +#include <fcntl.h> +#include <glob.h> +#include <limits.h> +#include <signal.h> +#include <sys/stat.h> +#include <sys/types.h> +#include <sys/wait.h> +#include <unistd.h> +#if defined(__APPLE__) +#include <mach-o/dyld.h> +#endif + +#include <unordered_map> + +#include "log.h" +#include "strutil.h" + +bool Exists(StringPiece filename) { + CHECK(filename.size() < PATH_MAX); + struct stat st; + if (stat(filename.as_string().c_str(), &st) < 0) { + return false; + } + return true; +} + +double GetTimestampFromStat(const struct stat& st) { +#if defined(__linux__) + return st.st_mtime + st.st_mtim.tv_nsec * 0.001 * 0.001 * 0.001; +#else + return st.st_mtime; +#endif +} + +double GetTimestamp(StringPiece filename) { + CHECK(filename.size() < PATH_MAX); + struct stat st; + if (stat(filename.as_string().c_str(), &st) < 0) { + return -2.0; + } + return GetTimestampFromStat(st); +} + +int RunCommand(const string& shell, + const string& shellflag, + const string& cmd, + RedirectStderr redirect_stderr, + string* s) { + const char* argv[] = {NULL, NULL, NULL, NULL}; + string cmd_with_shell; + if (shell[0] != '/' || shell.find_first_of(" $") != string::npos) { + string cmd_escaped = cmd; + EscapeShell(&cmd_escaped); + cmd_with_shell = shell + " " + shellflag + " \"" + cmd_escaped + "\""; + argv[0] = "/bin/sh"; + argv[1] = "-c"; + argv[2] = cmd_with_shell.c_str(); + } else { + // If the shell isn't complicated, we don't need to wrap in /bin/sh + argv[0] = shell.c_str(); + argv[1] = shellflag.c_str(); + argv[2] = cmd.c_str(); + } + + int pipefd[2]; + if (pipe(pipefd) != 0) + PERROR("pipe failed"); + int pid; + if ((pid = vfork())) { + int status; + close(pipefd[1]); + while (true) { + int result = waitpid(pid, &status, WNOHANG); + if (result < 0) + PERROR("waitpid failed"); + + while (true) { + char buf[4096]; + ssize_t r = HANDLE_EINTR(read(pipefd[0], buf, 4096)); + if (r < 0) + PERROR("read failed"); + if (r == 0) + break; + s->append(buf, buf + r); + } + + if (result != 0) { + break; + } + } + close(pipefd[0]); + + return status; + } else { + close(pipefd[0]); + if (redirect_stderr == RedirectStderr::STDOUT) { + if (dup2(pipefd[1], 2) < 0) + PERROR("dup2 failed"); + } else if (redirect_stderr == RedirectStderr::DEV_NULL) { + int fd = open("/dev/null", O_WRONLY); + if (dup2(fd, 2) < 0) + PERROR("dup2 failed"); + close(fd); + } + if (dup2(pipefd[1], 1) < 0) + PERROR("dup2 failed"); + close(pipefd[1]); + + execvp(argv[0], const_cast<char**>(argv)); + PLOG("execvp for %s failed", argv[0]); + kill(getppid(), SIGTERM); + _exit(1); + } +} + +void GetExecutablePath(string* path) { +#if defined(__linux__) + char mypath[PATH_MAX + 1]; + ssize_t l = readlink("/proc/self/exe", mypath, PATH_MAX); + if (l < 0) { + PERROR("readlink for /proc/self/exe"); + } + mypath[l] = '\0'; + *path = mypath; +#elif defined(__APPLE__) + char mypath[PATH_MAX + 1]; + uint32_t size = PATH_MAX; + if (_NSGetExecutablePath(mypath, &size) != 0) { + ERROR("_NSGetExecutablePath failed"); + } + mypath[size] = 0; + *path = mypath; +#else +#error "Unsupported OS" +#endif +} + +namespace { + +class GlobCache { + public: + ~GlobCache() { Clear(); } + + void Get(const char* pat, vector<string>** files) { + auto p = cache_.emplace(pat, nullptr); + if (p.second) { + vector<string>* files = p.first->second = new vector<string>; + if (strcspn(pat, "?*[\\") != strlen(pat)) { + glob_t gl; + glob(pat, 0, NULL, &gl); + for (size_t i = 0; i < gl.gl_pathc; i++) { + files->push_back(gl.gl_pathv[i]); + } + globfree(&gl); + } else { + if (Exists(pat)) + files->push_back(pat); + } + } + *files = p.first->second; + } + + const unordered_map<string, vector<string>*>& GetAll() const { + return cache_; + } + + void Clear() { + for (auto& p : cache_) { + delete p.second; + } + cache_.clear(); + } + + private: + unordered_map<string, vector<string>*> cache_; +}; + +static GlobCache g_gc; + +} // namespace + +void Glob(const char* pat, vector<string>** files) { + g_gc.Get(pat, files); +} + +const unordered_map<string, vector<string>*>& GetAllGlobCache() { + return g_gc.GetAll(); +} + +void ClearGlobCache() { + g_gc.Clear(); +} |
