1 // Copyright 2015 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 // +build ignore
16
17 #include "fileutil.h"
18
19 #include <errno.h>
20 #include <fcntl.h>
21 #include <glob.h>
22 #include <limits.h>
23 #include <signal.h>
24 #include <sys/stat.h>
25 #include <sys/types.h>
26 #include <sys/wait.h>
27 #include <unistd.h>
28 #if defined(__APPLE__)
29 #include <mach-o/dyld.h>
30 #endif
31
32 #include <unordered_map>
33
34 #include "log.h"
35 #include "strutil.h"
36
Exists(StringPiece filename)37 bool Exists(StringPiece filename) {
38 CHECK(filename.size() < PATH_MAX);
39 struct stat st;
40 if (stat(filename.as_string().c_str(), &st) < 0) {
41 return false;
42 }
43 return true;
44 }
45
GetTimestampFromStat(const struct stat & st)46 double GetTimestampFromStat(const struct stat& st) {
47 #if defined(__linux__)
48 return st.st_mtime + st.st_mtim.tv_nsec * 0.001 * 0.001 * 0.001;
49 #else
50 return st.st_mtime;
51 #endif
52 }
53
GetTimestamp(StringPiece filename)54 double GetTimestamp(StringPiece filename) {
55 CHECK(filename.size() < PATH_MAX);
56 struct stat st;
57 if (stat(filename.as_string().c_str(), &st) < 0) {
58 return -2.0;
59 }
60 return GetTimestampFromStat(st);
61 }
62
RunCommand(const string & shell,const string & cmd,RedirectStderr redirect_stderr,string * s)63 int RunCommand(const string& shell, const string& cmd,
64 RedirectStderr redirect_stderr,
65 string* s) {
66 string cmd_escaped = cmd;
67 EscapeShell(&cmd_escaped);
68 string cmd_with_shell = shell + " -c \"" + cmd_escaped + "\"";
69 const char* argv[] = {
70 "/bin/sh", "-c", cmd_with_shell.c_str(), NULL
71 };
72
73 int pipefd[2];
74 if (pipe(pipefd) != 0)
75 PERROR("pipe failed");
76 int pid;
77 if ((pid = vfork())) {
78 int status;
79 close(pipefd[1]);
80 while (true) {
81 int result = waitpid(pid, &status, WNOHANG);
82 if (result < 0)
83 PERROR("waitpid failed");
84
85 while (true) {
86 char buf[4096];
87 ssize_t r = read(pipefd[0], buf, 4096);
88 if (r < 0)
89 PERROR("read failed");
90 if (r == 0)
91 break;
92 s->append(buf, buf+r);
93 }
94
95 if (result != 0) {
96 break;
97 }
98 }
99 close(pipefd[0]);
100
101 return status;
102 } else {
103 close(pipefd[0]);
104 if (redirect_stderr == RedirectStderr::STDOUT) {
105 if (dup2(pipefd[1], 2) < 0)
106 PERROR("dup2 failed");
107 } else if (redirect_stderr == RedirectStderr::DEV_NULL) {
108 int fd = open("/dev/null", O_WRONLY);
109 if (dup2(fd, 2) < 0)
110 PERROR("dup2 failed");
111 close(fd);
112 }
113 if (dup2(pipefd[1], 1) < 0)
114 PERROR("dup2 failed");
115 close(pipefd[1]);
116
117 execvp(argv[0], const_cast<char**>(argv));
118 PLOG("execvp for %s failed", argv[0]);
119 kill(getppid(), SIGTERM);
120 _exit(1);
121 }
122 }
123
GetExecutablePath(string * path)124 void GetExecutablePath(string* path) {
125 #if defined(__linux__)
126 char mypath[PATH_MAX + 1];
127 ssize_t l = readlink("/proc/self/exe", mypath, PATH_MAX);
128 if (l < 0) {
129 PERROR("readlink for /proc/self/exe");
130 }
131 mypath[l] = '\0';
132 *path = mypath;
133 #elif defined(__APPLE__)
134 char mypath[PATH_MAX + 1];
135 uint32_t size = PATH_MAX;
136 if (_NSGetExecutablePath(mypath, &size) != 0) {
137 ERROR("_NSGetExecutablePath failed");
138 }
139 mypath[size] = 0;
140 *path = mypath;
141 #else
142 #error "Unsupported OS"
143 #endif
144 }
145
146 namespace {
147
148 class GlobCache {
149 public:
~GlobCache()150 ~GlobCache() {
151 Clear();
152 }
153
Get(const char * pat,vector<string> ** files)154 void Get(const char* pat, vector<string>** files) {
155 auto p = cache_.emplace(pat, nullptr);
156 if (p.second) {
157 vector<string>* files = p.first->second = new vector<string>;
158 if (strcspn(pat, "?*[\\") != strlen(pat)) {
159 glob_t gl;
160 glob(pat, GLOB_NOSORT, NULL, &gl);
161 for (size_t i = 0; i < gl.gl_pathc; i++) {
162 files->push_back(gl.gl_pathv[i]);
163 }
164 globfree(&gl);
165 } else {
166 if (Exists(pat))
167 files->push_back(pat);
168 }
169 }
170 *files = p.first->second;
171 }
172
GetAll() const173 const unordered_map<string, vector<string>*>& GetAll() const {
174 return cache_;
175 }
176
Clear()177 void Clear() {
178 for (auto& p : cache_) {
179 delete p.second;
180 }
181 cache_.clear();
182 }
183
184 private:
185 unordered_map<string, vector<string>*> cache_;
186 };
187
188 static GlobCache g_gc;
189
190 } // namespace
191
Glob(const char * pat,vector<string> ** files)192 void Glob(const char* pat, vector<string>** files) {
193 g_gc.Get(pat, files);
194 }
195
GetAllGlobCache()196 const unordered_map<string, vector<string>*>& GetAllGlobCache() {
197 return g_gc.GetAll();
198 }
199
ClearGlobCache()200 void ClearGlobCache() {
201 g_gc.Clear();
202 }
203