#define _XOPEN_SOURCE 700
#include "fac.h"
#include "errors.h"
#include <assert.h>
#include <stdio.h>
void __gcov_flush();
#ifdef _WIN32
#include <windows.h>
#include <direct.h>
#define getcwd _getcwd
#include <process.h>
int ReadChildProcess(char **output, char *cmdline) {
HANDLE g_hChildStd_OUT_Rd = NULL;
HANDLE g_hChildStd_OUT_Wr = NULL;
SECURITY_ATTRIBUTES sa;
printf("\n->Start of parent execution %s.\n", cmdline);
sa.nLength = sizeof(SECURITY_ATTRIBUTES);
sa.bInheritHandle = TRUE;
sa.lpSecurityDescriptor = NULL;
if ( ! CreatePipe(&g_hChildStd_OUT_Rd, &g_hChildStd_OUT_Wr, &sa, 0) ) {
printf("Unable to create stdout pipe!\n");
exit(1);
}
if ( ! SetHandleInformation(g_hChildStd_OUT_Rd, HANDLE_FLAG_INHERIT, 0) ){
printf("Unable to create stdout inherit thingy!\n");
exit(1);
}
PROCESS_INFORMATION piProcInfo;
STARTUPINFO siStartInfo;
bool bSuccess = FALSE;
ZeroMemory( &piProcInfo, sizeof(PROCESS_INFORMATION) );
ZeroMemory( &siStartInfo, sizeof(STARTUPINFO) );
siStartInfo.cb = sizeof(STARTUPINFO);
siStartInfo.hStdOutput = g_hChildStd_OUT_Wr;
siStartInfo.dwFlags |= STARTF_USESTDHANDLES;
char *cwd = malloc(4096);
GetCurrentDirectory(4096, cwd);
bSuccess = CreateProcess(NULL,
cmdline, NULL, NULL, TRUE, 0, GetEnvironmentStrings(), cwd, &siStartInfo, &piProcInfo); CloseHandle(g_hChildStd_OUT_Wr);
free(cwd);
if ( ! bSuccess ) {
printf("Unable to CreateProcess!\n");
exit(1);
}
DWORD dwRead = 0;
int bufsize = 1024;
*output = malloc(bufsize);
int read_offset = 0;
do {
bSuccess=ReadFile( g_hChildStd_OUT_Rd, *output + read_offset,
bufsize-read_offset-1, &dwRead, NULL);
read_offset += dwRead; (*output)[read_offset] = 0; if (bufsize - read_offset < 6) {
bufsize *= 2;
*output = realloc(*output, bufsize);
}
} while (bSuccess && dwRead);
CloseHandle(g_hChildStd_OUT_Rd);
WaitForSingleObject( piProcInfo.hProcess, INFINITE );
int result = -1;
if(!GetExitCodeProcess(piProcInfo.hProcess,(LPDWORD)&result)) {
int myerrno = GetLastError();
error(1, myerrno, "GetExitCodeProcess() failed");
}
return result;
}
#else
#include <sys/types.h>
#include <sys/wait.h>
#include <unistd.h>
#include <string.h>
#include <fcntl.h>
#include <stdlib.h>
#include <errno.h>
#endif
char *go_to_git_top(void) {
char *buf = git_revparse("--show-toplevel");
#ifdef _WIN32
if (strlen(buf) > 2 && buf[0] == '/' && buf[2] == '/') {
buf[0] = buf[1];
buf[1] = ':';
}
#endif
if (!buf) {
printf("Error identifying git toplevel directory!\n");
exit(1);
}
if (chdir(buf) != 0) {
printf("Error changing to git toplevel directory!\n");
exit(1);
}
return buf;
}
char *git_revparse(const char *flag) {
#ifdef _WIN32
char *buf = NULL;
char *cmdline = malloc(500);
if (snprintf(cmdline, 500, "git rev-parse %s", flag) >= 500) {
printf("bug: long argument to git_revparse: %s\n", flag);
return 0;
}
int retval = ReadChildProcess(&buf, cmdline);
free(cmdline);
if (retval) {
printf("bad retval %d from %s\n", retval, flag);
free(buf);
return 0;
}
int stdoutlen = strlen(buf);
#else
const char *templ = "/tmp/fac-XXXXXX";
char *namebuf = malloc(strlen(templ)+1);
strcpy(namebuf, templ);
int out = mkstemp(namebuf);
unlink(namebuf);
free(namebuf);
pid_t new_pid = fork();
if (new_pid == 0) {
char **args = malloc(4*sizeof(char *));
close(1);
if (dup(out) != 1) error(1, errno, "trouble duping stdout for ");
close(2);
open("/dev/null", O_WRONLY);
args[0] = "git";
args[1] = "rev-parse";
args[2] = (char *)flag;
args[3] = NULL;
#ifdef COVERAGE
__gcov_flush();
#endif
execvp("git", args);
exit(0);
}
int status = 0;
if (waitpid(new_pid, &status, 0) != new_pid) {
printf("Unable to exec git ls-files\n");
return NULL; }
if (WEXITSTATUS(status)) {
printf("Unable to run git rev-parse successfully %d\n", WEXITSTATUS(status));
return NULL;
}
off_t stdoutlen = lseek(out, 0, SEEK_END);
lseek(out, 0, SEEK_SET);
char *buf = malloc(stdoutlen);
if (read(out, buf, stdoutlen) != stdoutlen) {
printf("Error reading output of git rev-parse %s\n", flag);
free(buf);
return NULL;
}
#endif
for (int i=0;i<stdoutlen;i++) {
if (buf[i] == '\n') {
buf[i] = 0;
}
}
return buf;
}
void add_git_files(struct all_targets *all) {
#ifdef _WIN32
char *buf = NULL;
int retval = ReadChildProcess(&buf, "git ls-files");
if (retval) {
free(buf);
return;
}
int stdoutlen = strlen(buf);
#else
const char *templ = "/tmp/fac-XXXXXX";
char *namebuf = malloc(strlen(templ)+1);
strcpy(namebuf, templ);
int out = mkstemp(namebuf);
unlink(namebuf);
free(namebuf);
pid_t new_pid = fork();
if (new_pid == 0) {
char **args = malloc(3*sizeof(char *));
close(1);
if (dup(out) != 1) error(1, errno, "trouble duping stdout for git ls-files");
close(2);
open("/dev/null", O_WRONLY);
args[0] = "git";
args[1] = "ls-files";
args[2] = NULL;
#ifdef COVERAGE
__gcov_flush();
#endif
execvp("git", args);
exit(0);
}
int status = 0;
if (waitpid(new_pid, &status, 0) != new_pid) {
printf("Unable to exec git ls-files\n");
return; }
if (WEXITSTATUS(status)) {
printf("Unable to run git ls-files successfully (exit code %d)\n", WEXITSTATUS(status));
exit(1); }
off_t stdoutlen = lseek(out, 0, SEEK_END);
lseek(out, 0, SEEK_SET);
char *buf = malloc(stdoutlen);
if (read(out, buf, stdoutlen) != stdoutlen) {
printf("Error reading output of git ls-files\n");
free(buf);
return; }
#endif
int last_start = 0;
for (int i=0;i<stdoutlen;i++) {
if (buf[i] == '\n') {
buf[i] = 0;
char *path = absolute_path(root, buf + last_start);
struct target *t = create_target(all, path);
free(path);
assert(t);
t->is_in_git = true;
for (int j=i-1;j>last_start;j--) {
if (buf[j] == '/') {
buf[j] = 0;
char *path = absolute_path(root, buf + last_start);
struct target *t = create_target(all, path);
free(path);
assert(t);
t->is_in_git = true;
}
}
last_start = i+1;
}
}
free(buf);
}
void git_add(const char *path) {
const char **args = malloc(5*sizeof(char *));
args[0] = "git";
args[1] = "add";
args[2] = "--";
args[3] = path;
args[4] = NULL;
#ifdef _WIN32
int retval = spawnvp(P_WAIT, "git", (char **)args);
#else
pid_t new_pid = fork();
if (new_pid == 0) {
close(0);
#ifdef COVERAGE
__gcov_flush();
#endif
execvp("git", (char **)args);
error(1, errno, "running git");
}
int status = 0;
if (waitpid(new_pid, &status, 0) != new_pid) {
printf("Unable to exec git add -- %s\n", path);
exit(1); }
int retval = WEXITSTATUS(status);
#endif
if (retval) {
printf("Unable to run git add -- %s successfully (exit code %d)\n", path, retval);
exit(1); }
}