blob: eb4fc22fed9d2c3a3cf3d11719ba07ea3505537a [file] [log] [blame]
Shinichiro Hamaji1d545aa2015-06-23 15:29:13 +09001// 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
Fumitoshi Ukai744bb2b2015-06-25 00:10:52 +090015// +build ignore
16
Shinichiro Hamaji776ca302015-06-06 03:52:48 +090017#include "fileutil.h"
18
19#include <errno.h>
Shinichiro Hamaji0e3873a2015-07-05 15:48:28 +090020#include <glob.h>
Shinichiro Hamaji776ca302015-06-06 03:52:48 +090021#include <limits.h>
22#include <sys/stat.h>
Shinichiro Hamaji94d6f2a2015-07-05 05:32:25 +090023#include <sys/types.h>
24#include <sys/wait.h>
Shinichiro Hamaji776ca302015-06-06 03:52:48 +090025#include <unistd.h>
26
Shinichiro Hamaji0e3873a2015-07-05 15:48:28 +090027#include <unordered_map>
28
Shinichiro Hamaji776ca302015-06-06 03:52:48 +090029#include "log.h"
30
31bool Exists(StringPiece filename) {
32 CHECK(filename.size() < PATH_MAX);
Shinichiro Hamaji776ca302015-06-06 03:52:48 +090033 struct stat st;
Shinichiro Hamajifda79432015-07-05 03:17:34 +090034 if (stat(filename.as_string().c_str(), &st) < 0) {
Shinichiro Hamaji776ca302015-06-06 03:52:48 +090035 return false;
36 }
37 return true;
38}
Shinichiro Hamajifda79432015-07-05 03:17:34 +090039
40double GetTimestamp(StringPiece filename) {
41 CHECK(filename.size() < PATH_MAX);
42 struct stat st;
43 if (stat(filename.as_string().c_str(), &st) < 0) {
44 return -2.0;
45 }
46 return st.st_mtime;
47}
Shinichiro Hamaji94d6f2a2015-07-05 05:32:25 +090048
49int RunCommand(const string& shell, const string& cmd, bool redirect_stderr,
50 string* s) {
51 int pipefd[2];
52 if (pipe(pipefd) != 0)
53 PERROR("pipe failed");
54 int pid;
55 if ((pid = vfork())) {
56 int status;
57 close(pipefd[1]);
58 while (true) {
59 int result = waitpid(pid, &status, WNOHANG);
60 if (result < 0)
61 PERROR("waitpid failed");
62
63 while (true) {
64 char buf[4096];
65 ssize_t r = read(pipefd[0], buf, 4096);
66 if (r < 0)
67 PERROR("read failed");
68 if (r == 0)
69 break;
70 s->append(buf, buf+r);
71 }
72
73 if (result != 0) {
74 break;
75 }
76 }
77 close(pipefd[0]);
78
79 return status;
80 } else {
81 close(pipefd[0]);
82 if (redirect_stderr) {
83 if (dup2(pipefd[1], 2) < 0)
84 PERROR("dup2 failed");
85 }
86 if (dup2(pipefd[1], 1) < 0)
87 PERROR("dup2 failed");
88 close(pipefd[1]);
89
90 const char* argv[] = {
91 shell.c_str(), "-c", cmd.c_str(), NULL
92 };
93 execvp(argv[0], const_cast<char**>(argv));
94 }
95 abort();
96}
Shinichiro Hamaji0e3873a2015-07-05 15:48:28 +090097
98namespace {
99
100class GlobCache {
101 public:
102 ~GlobCache() {
103 for (auto& p : cache_) {
104 delete p.second;
105 }
106 }
107
108 void Get(const char* pat, vector<string>** files) {
109 auto p = cache_.emplace(pat, nullptr);
110 if (p.second) {
111 vector<string>* files = p.first->second = new vector<string>;
112 if (strcspn(pat, "?*[\\") != strlen(pat)) {
113 glob_t gl;
114 glob(pat, GLOB_NOSORT, NULL, &gl);
115 for (size_t i = 0; i < gl.gl_pathc; i++) {
116 files->push_back(gl.gl_pathv[i]);
117 }
118 globfree(&gl);
119 } else {
120 if (Exists(pat))
121 files->push_back(pat);
122 }
123 }
124 *files = p.first->second;
125 }
126
127 private:
128 unordered_map<string, vector<string>*> cache_;
129};
130
131} // namespace
132
133void Glob(const char* pat, vector<string>** files) {
134 static GlobCache gc;
135 gc.Get(pat, files);
136}