blob: eb4fc22fed9d2c3a3cf3d11719ba07ea3505537a [file] [log] [blame]
// 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 <glob.h>
#include <limits.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <unistd.h>
#include <unordered_map>
#include "log.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 GetTimestamp(StringPiece filename) {
CHECK(filename.size() < PATH_MAX);
struct stat st;
if (stat(filename.as_string().c_str(), &st) < 0) {
return -2.0;
}
return st.st_mtime;
}
int RunCommand(const string& shell, const string& cmd, bool redirect_stderr,
string* s) {
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 = 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) {
if (dup2(pipefd[1], 2) < 0)
PERROR("dup2 failed");
}
if (dup2(pipefd[1], 1) < 0)
PERROR("dup2 failed");
close(pipefd[1]);
const char* argv[] = {
shell.c_str(), "-c", cmd.c_str(), NULL
};
execvp(argv[0], const_cast<char**>(argv));
}
abort();
}
namespace {
class GlobCache {
public:
~GlobCache() {
for (auto& p : cache_) {
delete p.second;
}
}
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, GLOB_NOSORT, 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;
}
private:
unordered_map<string, vector<string>*> cache_;
};
} // namespace
void Glob(const char* pat, vector<string>** files) {
static GlobCache gc;
gc.Get(pat, files);
}