mirror of
https://github.com/AGWA/git-crypt.git
synced 2026-02-04 11:07:57 -08:00
Lay groundwork for Windows support
Move Unix-specific code to util-unix.cpp, and place Windows equivalents in util-win32.cpp. Most of the Windows functions are just stubs at the moment, and we need a build system that works on Windows.
This commit is contained in:
2
Makefile
2
Makefile
@@ -10,6 +10,8 @@ all: git-crypt
|
||||
git-crypt: $(OBJFILES)
|
||||
$(CXX) $(CXXFLAGS) -o $@ $^ $(LDFLAGS)
|
||||
|
||||
util.o: util.cpp util-unix.cpp util-win32.cpp
|
||||
|
||||
clean:
|
||||
rm -f *.o git-crypt
|
||||
|
||||
|
||||
@@ -33,8 +33,6 @@
|
||||
#include "util.hpp"
|
||||
#include "key.hpp"
|
||||
#include "gpg.hpp"
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <unistd.h>
|
||||
#include <stdint.h>
|
||||
#include <algorithm>
|
||||
@@ -202,7 +200,7 @@ int clean (int argc, char** argv)
|
||||
Hmac_sha1_state hmac(key->hmac_key, HMAC_KEY_LEN); // Calculate the file's SHA1 HMAC as we go
|
||||
uint64_t file_size = 0; // Keep track of the length, make sure it doesn't get too big
|
||||
std::string file_contents; // First 8MB or so of the file go here
|
||||
std::fstream temp_file; // The rest of the file spills into a temporary file on disk
|
||||
temp_fstream temp_file; // The rest of the file spills into a temporary file on disk
|
||||
temp_file.exceptions(std::fstream::badbit);
|
||||
|
||||
char buffer[1024];
|
||||
@@ -219,7 +217,7 @@ int clean (int argc, char** argv)
|
||||
file_contents.append(buffer, bytes_read);
|
||||
} else {
|
||||
if (!temp_file.is_open()) {
|
||||
open_tempfile(temp_file, std::fstream::in | std::fstream::out | std::fstream::binary | std::fstream::app);
|
||||
temp_file.open(std::fstream::in | std::fstream::out | std::fstream::binary | std::fstream::app);
|
||||
}
|
||||
temp_file.write(buffer, bytes_read);
|
||||
}
|
||||
|
||||
@@ -82,13 +82,7 @@ try {
|
||||
* General initialization
|
||||
*/
|
||||
|
||||
// The following two lines are essential for achieving good performance:
|
||||
std::ios_base::sync_with_stdio(false);
|
||||
std::cin.tie(0);
|
||||
|
||||
std::cin.exceptions(std::ios_base::badbit);
|
||||
std::cout.exceptions(std::ios_base::badbit);
|
||||
|
||||
init_std_streams();
|
||||
ERR_load_crypto_strings();
|
||||
|
||||
/*
|
||||
@@ -186,11 +180,7 @@ try {
|
||||
std::cerr << "git-crypt: GPG error: " << e.message << std::endl;
|
||||
return 1;
|
||||
} catch (const System_error& e) {
|
||||
std::cerr << "git-crypt: " << e.action << ": ";
|
||||
if (!e.target.empty()) {
|
||||
std::cerr << e.target << ": ";
|
||||
}
|
||||
std::cerr << strerror(e.error) << std::endl;
|
||||
std::cerr << "git-crypt: System error: " << e.message() << std::endl;
|
||||
return 1;
|
||||
} catch (const Crypto_error& e) {
|
||||
std::cerr << "git-crypt: Crypto error: " << e.where << ": " << e.message << std::endl;
|
||||
|
||||
3
key.cpp
3
key.cpp
@@ -33,6 +33,7 @@
|
||||
#include "crypto.hpp"
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <stdint.h>
|
||||
#include <fstream>
|
||||
#include <istream>
|
||||
#include <ostream>
|
||||
@@ -133,7 +134,7 @@ bool Key_file::load_from_file (const char* key_file_name)
|
||||
|
||||
bool Key_file::store_to_file (const char* key_file_name) const
|
||||
{
|
||||
mode_t old_umask = umask(0077); // make sure key file is protected
|
||||
mode_t old_umask = umask(0077); // make sure key file is protected (TODO: Windows compat)
|
||||
std::ofstream key_file_out(key_file_name, std::fstream::binary);
|
||||
umask(old_umask);
|
||||
if (!key_file_out) {
|
||||
|
||||
250
util-unix.cpp
Normal file
250
util-unix.cpp
Normal file
@@ -0,0 +1,250 @@
|
||||
/*
|
||||
* Copyright 2012, 2014 Andrew Ayer
|
||||
*
|
||||
* This file is part of git-crypt.
|
||||
*
|
||||
* git-crypt is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* git-crypt is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with git-crypt. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* Additional permission under GNU GPL version 3 section 7:
|
||||
*
|
||||
* If you modify the Program, or any covered work, by linking or
|
||||
* combining it with the OpenSSL project's OpenSSL library (or a
|
||||
* modified version of that library), containing parts covered by the
|
||||
* terms of the OpenSSL or SSLeay licenses, the licensors of the Program
|
||||
* grant you additional permission to convey the resulting work.
|
||||
* Corresponding Source for a non-source form of such a combination
|
||||
* shall include the source code for the parts of OpenSSL used as well
|
||||
* as that of the covered work.
|
||||
*/
|
||||
|
||||
#include <sys/stat.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/wait.h>
|
||||
#include <errno.h>
|
||||
#include <unistd.h>
|
||||
#include <stdio.h>
|
||||
#include <limits.h>
|
||||
#include <stdlib.h>
|
||||
#include <vector>
|
||||
#include <string>
|
||||
#include <cstring>
|
||||
|
||||
std::string System_error::message () const
|
||||
{
|
||||
std::string mesg(action);
|
||||
if (!target.empty()) {
|
||||
mesg += ": ";
|
||||
mesg += target;
|
||||
}
|
||||
if (error) {
|
||||
mesg += ": ";
|
||||
mesg += strerror(error);
|
||||
}
|
||||
return mesg;
|
||||
}
|
||||
|
||||
void temp_fstream::open (std::ios_base::openmode mode)
|
||||
{
|
||||
close();
|
||||
|
||||
const char* tmpdir = getenv("TMPDIR");
|
||||
size_t tmpdir_len = tmpdir ? std::strlen(tmpdir) : 0;
|
||||
if (tmpdir_len == 0 || tmpdir_len > 4096) {
|
||||
// no $TMPDIR or it's excessively long => fall back to /tmp
|
||||
tmpdir = "/tmp";
|
||||
tmpdir_len = 4;
|
||||
}
|
||||
std::vector<char> path_buffer(tmpdir_len + 18);
|
||||
char* path = &path_buffer[0];
|
||||
std::strcpy(path, tmpdir);
|
||||
std::strcpy(path + tmpdir_len, "/git-crypt.XXXXXX");
|
||||
mode_t old_umask = umask(0077);
|
||||
int fd = mkstemp(path);
|
||||
if (fd == -1) {
|
||||
int mkstemp_errno = errno;
|
||||
umask(old_umask);
|
||||
throw System_error("mkstemp", "", mkstemp_errno);
|
||||
}
|
||||
umask(old_umask);
|
||||
std::fstream::open(path, mode);
|
||||
if (!std::fstream::is_open()) {
|
||||
unlink(path);
|
||||
::close(fd);
|
||||
throw System_error("std::fstream::open", path, 0);
|
||||
}
|
||||
unlink(path);
|
||||
::close(fd);
|
||||
}
|
||||
|
||||
void temp_fstream::close ()
|
||||
{
|
||||
if (std::fstream::is_open()) {
|
||||
std::fstream::close();
|
||||
}
|
||||
}
|
||||
|
||||
void mkdir_parent (const std::string& path)
|
||||
{
|
||||
std::string::size_type slash(path.find('/', 1));
|
||||
while (slash != std::string::npos) {
|
||||
std::string prefix(path.substr(0, slash));
|
||||
struct stat status;
|
||||
if (stat(prefix.c_str(), &status) == 0) {
|
||||
// already exists - make sure it's a directory
|
||||
if (!S_ISDIR(status.st_mode)) {
|
||||
throw System_error("mkdir_parent", prefix, ENOTDIR);
|
||||
}
|
||||
} else {
|
||||
if (errno != ENOENT) {
|
||||
throw System_error("mkdir_parent", prefix, errno);
|
||||
}
|
||||
// doesn't exist - mkdir it
|
||||
if (mkdir(prefix.c_str(), 0777) == -1) {
|
||||
throw System_error("mkdir", prefix, errno);
|
||||
}
|
||||
}
|
||||
|
||||
slash = path.find('/', slash + 1);
|
||||
}
|
||||
}
|
||||
|
||||
static std::string readlink (const char* pathname)
|
||||
{
|
||||
std::vector<char> buffer(64);
|
||||
ssize_t len;
|
||||
|
||||
while ((len = ::readlink(pathname, &buffer[0], buffer.size())) == static_cast<ssize_t>(buffer.size())) {
|
||||
// buffer may have been truncated - grow and try again
|
||||
buffer.resize(buffer.size() * 2);
|
||||
}
|
||||
if (len == -1) {
|
||||
throw System_error("readlink", pathname, errno);
|
||||
}
|
||||
|
||||
return std::string(buffer.begin(), buffer.begin() + len);
|
||||
}
|
||||
|
||||
std::string our_exe_path ()
|
||||
{
|
||||
try {
|
||||
return readlink("/proc/self/exe");
|
||||
} catch (const System_error&) {
|
||||
if (argv0[0] == '/') {
|
||||
// argv[0] starts with / => it's an absolute path
|
||||
return argv0;
|
||||
} else if (std::strchr(argv0, '/')) {
|
||||
// argv[0] contains / => it a relative path that should be resolved
|
||||
char* resolved_path_p = realpath(argv0, NULL);
|
||||
std::string resolved_path(resolved_path_p);
|
||||
free(resolved_path_p);
|
||||
return resolved_path;
|
||||
} else {
|
||||
// argv[0] is just a bare filename => not much we can do
|
||||
return argv0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int exec_command (const char* command, std::ostream& output)
|
||||
{
|
||||
int pipefd[2];
|
||||
if (pipe(pipefd) == -1) {
|
||||
throw System_error("pipe", "", errno);
|
||||
}
|
||||
pid_t child = fork();
|
||||
if (child == -1) {
|
||||
int fork_errno = errno;
|
||||
close(pipefd[0]);
|
||||
close(pipefd[1]);
|
||||
throw System_error("fork", "", fork_errno);
|
||||
}
|
||||
if (child == 0) {
|
||||
close(pipefd[0]);
|
||||
if (pipefd[1] != 1) {
|
||||
dup2(pipefd[1], 1);
|
||||
close(pipefd[1]);
|
||||
}
|
||||
execl("/bin/sh", "sh", "-c", command, NULL);
|
||||
perror("/bin/sh");
|
||||
_exit(-1);
|
||||
}
|
||||
close(pipefd[1]);
|
||||
char buffer[1024];
|
||||
ssize_t bytes_read;
|
||||
while ((bytes_read = read(pipefd[0], buffer, sizeof(buffer))) > 0) {
|
||||
output.write(buffer, bytes_read);
|
||||
}
|
||||
if (bytes_read == -1) {
|
||||
int read_errno = errno;
|
||||
close(pipefd[0]);
|
||||
throw System_error("read", "", read_errno);
|
||||
}
|
||||
close(pipefd[0]);
|
||||
int status = 0;
|
||||
if (waitpid(child, &status, 0) == -1) {
|
||||
throw System_error("waitpid", "", errno);
|
||||
}
|
||||
return status;
|
||||
}
|
||||
|
||||
int exec_command_with_input (const char* command, const char* p, size_t len)
|
||||
{
|
||||
int pipefd[2];
|
||||
if (pipe(pipefd) == -1) {
|
||||
throw System_error("pipe", "", errno);
|
||||
}
|
||||
pid_t child = fork();
|
||||
if (child == -1) {
|
||||
int fork_errno = errno;
|
||||
close(pipefd[0]);
|
||||
close(pipefd[1]);
|
||||
throw System_error("fork", "", fork_errno);
|
||||
}
|
||||
if (child == 0) {
|
||||
close(pipefd[1]);
|
||||
if (pipefd[0] != 0) {
|
||||
dup2(pipefd[0], 0);
|
||||
close(pipefd[0]);
|
||||
}
|
||||
execl("/bin/sh", "sh", "-c", command, NULL);
|
||||
perror("/bin/sh");
|
||||
_exit(-1);
|
||||
}
|
||||
close(pipefd[0]);
|
||||
while (len > 0) {
|
||||
ssize_t bytes_written = write(pipefd[1], p, len);
|
||||
if (bytes_written == -1) {
|
||||
int write_errno = errno;
|
||||
close(pipefd[1]);
|
||||
throw System_error("write", "", write_errno);
|
||||
}
|
||||
p += bytes_written;
|
||||
len -= bytes_written;
|
||||
}
|
||||
close(pipefd[1]);
|
||||
int status = 0;
|
||||
if (waitpid(child, &status, 0) == -1) {
|
||||
throw System_error("waitpid", "", errno);
|
||||
}
|
||||
return status;
|
||||
}
|
||||
|
||||
bool successful_exit (int status)
|
||||
{
|
||||
return status != -1 && WIFEXITED(status) && WEXITSTATUS(status) == 0;
|
||||
}
|
||||
|
||||
static void init_std_streams_platform ()
|
||||
{
|
||||
}
|
||||
124
util-win32.cpp
Normal file
124
util-win32.cpp
Normal file
@@ -0,0 +1,124 @@
|
||||
/*
|
||||
* Copyright 2014 Andrew Ayer
|
||||
*
|
||||
* This file is part of git-crypt.
|
||||
*
|
||||
* git-crypt is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* git-crypt is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with git-crypt. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* Additional permission under GNU GPL version 3 section 7:
|
||||
*
|
||||
* If you modify the Program, or any covered work, by linking or
|
||||
* combining it with the OpenSSL project's OpenSSL library (or a
|
||||
* modified version of that library), containing parts covered by the
|
||||
* terms of the OpenSSL or SSLeay licenses, the licensors of the Program
|
||||
* grant you additional permission to convey the resulting work.
|
||||
* Corresponding Source for a non-source form of such a combination
|
||||
* shall include the source code for the parts of OpenSSL used as well
|
||||
* as that of the covered work.
|
||||
*/
|
||||
|
||||
#include <io.h>
|
||||
#include <stdio.h>
|
||||
#include <fcntl.h>
|
||||
#include <windows.h>
|
||||
|
||||
std::string System_error::message () const
|
||||
{
|
||||
std::string mesg(action);
|
||||
if (!target.empty()) {
|
||||
mesg += ": ";
|
||||
mesg += target;
|
||||
}
|
||||
if (error) {
|
||||
// TODO: use FormatMessage()
|
||||
}
|
||||
return mesg;
|
||||
}
|
||||
|
||||
void temp_fstream::open (std::ios_base::openmode mode)
|
||||
{
|
||||
close();
|
||||
|
||||
char tmpdir[MAX_PATH + 1];
|
||||
|
||||
DWORD ret = GetTempPath(sizeof(tmpdir), tmpdir);
|
||||
if (ret == 0) {
|
||||
throw System_error("GetTempPath", "", GetLastError());
|
||||
} else if (ret > sizeof(tmpdir) - 1) {
|
||||
throw System_error("GetTempPath", "", ERROR_BUFFER_OVERFLOW);
|
||||
}
|
||||
|
||||
char tmpfilename[MAX_PATH + 1];
|
||||
if (GetTempFileName(tmpdir, TEXT("git-crypt"), 0, tmpfilename) == 0) {
|
||||
throw System_error("GetTempFileName", "", GetLastError());
|
||||
}
|
||||
|
||||
filename = tmpfilename;
|
||||
|
||||
std::fstream::open(filename.c_str(), mode);
|
||||
if (!std::fstream::is_open()) {
|
||||
DeleteFile(filename.c_str());
|
||||
throw System_error("std::fstream::open", filename, 0);
|
||||
}
|
||||
}
|
||||
|
||||
void temp_fstream::close ()
|
||||
{
|
||||
if (std::fstream::is_open()) {
|
||||
std::fstream::close();
|
||||
DeleteFile(filename.c_str());
|
||||
}
|
||||
}
|
||||
|
||||
void mkdir_parent (const std::string& path)
|
||||
{
|
||||
std::string::size_type slash(path.find('/', 1));
|
||||
while (slash != std::string::npos) {
|
||||
std::string prefix(path.substr(0, slash));
|
||||
if (GetFileAttributes(prefix.c_str()) == INVALID_FILE_ATTRIBUTES) {
|
||||
// prefix does not exist, so try to create it
|
||||
if (!CreateDirectory(prefix.c_str(), NULL)) {
|
||||
throw System_error("CreateDirectory", prefix, GetLastError());
|
||||
}
|
||||
}
|
||||
|
||||
slash = path.find('/', slash + 1);
|
||||
}
|
||||
}
|
||||
|
||||
std::string our_exe_path () // TODO
|
||||
{
|
||||
return argv0;
|
||||
}
|
||||
|
||||
int exec_command (const char* command, std::ostream& output) // TODO
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
int exec_command_with_input (const char* command, const char* p, size_t len) // TODO
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
bool successful_exit (int status) // TODO
|
||||
{
|
||||
return status == 0;
|
||||
}
|
||||
|
||||
static void init_std_streams_platform ()
|
||||
{
|
||||
_setmode(_fileno(stdin), _O_BINARY);
|
||||
_setmode(_fileno(stdout), _O_BINARY);
|
||||
}
|
||||
212
util.cpp
212
util.cpp
@@ -31,198 +31,7 @@
|
||||
#include "git-crypt.hpp"
|
||||
#include "util.hpp"
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <cstring>
|
||||
#include <cstdio>
|
||||
#include <cstdlib>
|
||||
#include <sys/types.h>
|
||||
#include <sys/wait.h>
|
||||
#include <sys/stat.h>
|
||||
#include <unistd.h>
|
||||
#include <errno.h>
|
||||
#include <fstream>
|
||||
|
||||
void mkdir_parent (const std::string& path)
|
||||
{
|
||||
std::string::size_type slash(path.find('/', 1));
|
||||
while (slash != std::string::npos) {
|
||||
std::string prefix(path.substr(0, slash));
|
||||
struct stat status;
|
||||
if (stat(prefix.c_str(), &status) == 0) {
|
||||
// already exists - make sure it's a directory
|
||||
if (!S_ISDIR(status.st_mode)) {
|
||||
throw System_error("mkdir_parent", prefix, ENOTDIR);
|
||||
}
|
||||
} else {
|
||||
if (errno != ENOENT) {
|
||||
throw System_error("mkdir_parent", prefix, errno);
|
||||
}
|
||||
// doesn't exist - mkdir it
|
||||
if (mkdir(prefix.c_str(), 0777) == -1) {
|
||||
throw System_error("mkdir", prefix, errno);
|
||||
}
|
||||
}
|
||||
|
||||
slash = path.find('/', slash + 1);
|
||||
}
|
||||
}
|
||||
|
||||
std::string readlink (const char* pathname)
|
||||
{
|
||||
std::vector<char> buffer(64);
|
||||
ssize_t len;
|
||||
|
||||
while ((len = ::readlink(pathname, &buffer[0], buffer.size())) == static_cast<ssize_t>(buffer.size())) {
|
||||
// buffer may have been truncated - grow and try again
|
||||
buffer.resize(buffer.size() * 2);
|
||||
}
|
||||
if (len == -1) {
|
||||
throw System_error("readlink", pathname, errno);
|
||||
}
|
||||
|
||||
return std::string(buffer.begin(), buffer.begin() + len);
|
||||
}
|
||||
|
||||
std::string our_exe_path ()
|
||||
{
|
||||
try {
|
||||
return readlink("/proc/self/exe");
|
||||
} catch (const System_error&) {
|
||||
if (argv0[0] == '/') {
|
||||
// argv[0] starts with / => it's an absolute path
|
||||
return argv0;
|
||||
} else if (std::strchr(argv0, '/')) {
|
||||
// argv[0] contains / => it a relative path that should be resolved
|
||||
char* resolved_path_p = realpath(argv0, NULL);
|
||||
std::string resolved_path(resolved_path_p);
|
||||
free(resolved_path_p);
|
||||
return resolved_path;
|
||||
} else {
|
||||
// argv[0] is just a bare filename => not much we can do
|
||||
return argv0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int exec_command (const char* command, std::ostream& output)
|
||||
{
|
||||
int pipefd[2];
|
||||
if (pipe(pipefd) == -1) {
|
||||
throw System_error("pipe", "", errno);
|
||||
}
|
||||
pid_t child = fork();
|
||||
if (child == -1) {
|
||||
int fork_errno = errno;
|
||||
close(pipefd[0]);
|
||||
close(pipefd[1]);
|
||||
throw System_error("fork", "", fork_errno);
|
||||
}
|
||||
if (child == 0) {
|
||||
close(pipefd[0]);
|
||||
if (pipefd[1] != 1) {
|
||||
dup2(pipefd[1], 1);
|
||||
close(pipefd[1]);
|
||||
}
|
||||
execl("/bin/sh", "sh", "-c", command, NULL);
|
||||
perror("/bin/sh");
|
||||
_exit(-1);
|
||||
}
|
||||
close(pipefd[1]);
|
||||
char buffer[1024];
|
||||
ssize_t bytes_read;
|
||||
while ((bytes_read = read(pipefd[0], buffer, sizeof(buffer))) > 0) {
|
||||
output.write(buffer, bytes_read);
|
||||
}
|
||||
if (bytes_read == -1) {
|
||||
int read_errno = errno;
|
||||
close(pipefd[0]);
|
||||
throw System_error("read", "", read_errno);
|
||||
}
|
||||
close(pipefd[0]);
|
||||
int status = 0;
|
||||
if (waitpid(child, &status, 0) == -1) {
|
||||
throw System_error("waitpid", "", errno);
|
||||
}
|
||||
return status;
|
||||
}
|
||||
|
||||
int exec_command_with_input (const char* command, const char* p, size_t len)
|
||||
{
|
||||
int pipefd[2];
|
||||
if (pipe(pipefd) == -1) {
|
||||
throw System_error("pipe", "", errno);
|
||||
}
|
||||
pid_t child = fork();
|
||||
if (child == -1) {
|
||||
int fork_errno = errno;
|
||||
close(pipefd[0]);
|
||||
close(pipefd[1]);
|
||||
throw System_error("fork", "", fork_errno);
|
||||
}
|
||||
if (child == 0) {
|
||||
close(pipefd[1]);
|
||||
if (pipefd[0] != 0) {
|
||||
dup2(pipefd[0], 0);
|
||||
close(pipefd[0]);
|
||||
}
|
||||
execl("/bin/sh", "sh", "-c", command, NULL);
|
||||
perror("/bin/sh");
|
||||
_exit(-1);
|
||||
}
|
||||
close(pipefd[0]);
|
||||
while (len > 0) {
|
||||
ssize_t bytes_written = write(pipefd[1], p, len);
|
||||
if (bytes_written == -1) {
|
||||
int write_errno = errno;
|
||||
close(pipefd[1]);
|
||||
throw System_error("write", "", write_errno);
|
||||
}
|
||||
p += bytes_written;
|
||||
len -= bytes_written;
|
||||
}
|
||||
close(pipefd[1]);
|
||||
int status = 0;
|
||||
if (waitpid(child, &status, 0) == -1) {
|
||||
throw System_error("waitpid", "", errno);
|
||||
}
|
||||
return status;
|
||||
}
|
||||
|
||||
bool successful_exit (int status)
|
||||
{
|
||||
return status != -1 && WIFEXITED(status) && WEXITSTATUS(status) == 0;
|
||||
}
|
||||
|
||||
void open_tempfile (std::fstream& file, std::ios_base::openmode mode)
|
||||
{
|
||||
const char* tmpdir = getenv("TMPDIR");
|
||||
size_t tmpdir_len = tmpdir ? std::strlen(tmpdir) : 0;
|
||||
if (tmpdir_len == 0 || tmpdir_len > 4096) {
|
||||
// no $TMPDIR or it's excessively long => fall back to /tmp
|
||||
tmpdir = "/tmp";
|
||||
tmpdir_len = 4;
|
||||
}
|
||||
std::vector<char> path_buffer(tmpdir_len + 18);
|
||||
char* path = &path_buffer[0];
|
||||
std::strcpy(path, tmpdir);
|
||||
std::strcpy(path + tmpdir_len, "/git-crypt.XXXXXX");
|
||||
mode_t old_umask = umask(0077);
|
||||
int fd = mkstemp(path);
|
||||
if (fd == -1) {
|
||||
int mkstemp_errno = errno;
|
||||
umask(old_umask);
|
||||
throw System_error("mkstemp", "", mkstemp_errno);
|
||||
}
|
||||
umask(old_umask);
|
||||
file.open(path, mode);
|
||||
if (!file.is_open()) {
|
||||
unlink(path);
|
||||
close(fd);
|
||||
throw System_error("std::fstream::open", path, 0);
|
||||
}
|
||||
unlink(path);
|
||||
close(fd);
|
||||
}
|
||||
#include <iostream>
|
||||
|
||||
std::string escape_shell_arg (const std::string& str)
|
||||
{
|
||||
@@ -272,3 +81,22 @@ void write_be32 (std::ostream& out, uint32_t i)
|
||||
out.write(reinterpret_cast<const char*>(buffer), 4);
|
||||
}
|
||||
|
||||
static void init_std_streams_platform (); // platform-specific initialization
|
||||
|
||||
void init_std_streams ()
|
||||
{
|
||||
// The following two lines are essential for achieving good performance:
|
||||
std::ios_base::sync_with_stdio(false);
|
||||
std::cin.tie(0);
|
||||
|
||||
std::cin.exceptions(std::ios_base::badbit);
|
||||
std::cout.exceptions(std::ios_base::badbit);
|
||||
|
||||
init_std_streams_platform();
|
||||
}
|
||||
|
||||
#ifdef _WIN32
|
||||
#include "util-win32.cpp"
|
||||
#else
|
||||
#include "util-unix.cpp"
|
||||
#endif
|
||||
|
||||
15
util.hpp
15
util.hpp
@@ -35,6 +35,7 @@
|
||||
#include <ios>
|
||||
#include <iosfwd>
|
||||
#include <stdint.h>
|
||||
#include <fstream>
|
||||
|
||||
struct System_error {
|
||||
std::string action;
|
||||
@@ -42,20 +43,30 @@ struct System_error {
|
||||
int error;
|
||||
|
||||
System_error (const std::string& a, const std::string& t, int e) : action(a), target(t), error(e) { }
|
||||
|
||||
std::string message () const;
|
||||
};
|
||||
|
||||
class temp_fstream : public std::fstream {
|
||||
std::string filename;
|
||||
public:
|
||||
~temp_fstream () { close(); }
|
||||
|
||||
void open (std::ios_base::openmode);
|
||||
void close ();
|
||||
};
|
||||
|
||||
void mkdir_parent (const std::string& path); // Create parent directories of path, __but not path itself__
|
||||
std::string readlink (const char* pathname);
|
||||
std::string our_exe_path ();
|
||||
int exec_command (const char* command, std::ostream& output);
|
||||
int exec_command_with_input (const char* command, const char* p, size_t len);
|
||||
bool successful_exit (int status);
|
||||
void open_tempfile (std::fstream&, std::ios_base::openmode);
|
||||
std::string escape_shell_arg (const std::string&);
|
||||
uint32_t load_be32 (const unsigned char*);
|
||||
void store_be32 (unsigned char*, uint32_t);
|
||||
bool read_be32 (std::istream& in, uint32_t&);
|
||||
void write_be32 (std::ostream& out, uint32_t);
|
||||
void init_std_streams ();
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
Reference in New Issue
Block a user