summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorJan Niklas Hasse <jhasse@bixense.com>2020-08-18 19:25:45 (GMT)
committerJan Niklas Hasse <jhasse@bixense.com>2020-08-18 19:25:45 (GMT)
commit5c2cde2f7e66b2928c2bcf33df4112850dad0af6 (patch)
tree7787cd5aea4894b2a5018ae4c1a6b469d3e80ef7 /src
parented7f67040b370189d989adbd60ff8ea29957231f (diff)
parent9ddd3c917793bb97eb19d571429cdedf07501c03 (diff)
downloadNinja-5c2cde2f7e66b2928c2bcf33df4112850dad0af6.zip
Ninja-5c2cde2f7e66b2928c2bcf33df4112850dad0af6.tar.gz
Ninja-5c2cde2f7e66b2928c2bcf33df4112850dad0af6.tar.bz2
Merge branch 'master' into release
Diffstat (limited to 'src')
-rwxr-xr-xsrc/browse.py7
-rw-r--r--src/build.cc4
-rw-r--r--src/build_log.cc51
-rw-r--r--src/build_log.h8
-rw-r--r--src/build_log_test.cc2
-rw-r--r--src/build_test.cc2
-rw-r--r--src/depfile_parser.cc87
-rw-r--r--src/depfile_parser.in.cc23
-rw-r--r--src/depfile_parser_test.cc35
-rw-r--r--src/deps_log.cc74
-rw-r--r--src/deps_log.h5
-rw-r--r--src/disk_interface.cc2
-rw-r--r--src/disk_interface_test.cc2
-rw-r--r--src/ninja.cc4
-rw-r--r--src/string_piece_util.cc2
-rw-r--r--src/subprocess-posix.cc7
-rw-r--r--src/subprocess-win32.cc18
-rw-r--r--src/test.cc13
-rw-r--r--src/version.cc2
19 files changed, 248 insertions, 100 deletions
diff --git a/src/browse.py b/src/browse.py
index 1c9c39b..653cbe9 100755
--- a/src/browse.py
+++ b/src/browse.py
@@ -29,12 +29,15 @@ except ImportError:
import BaseHTTPServer as httpserver
import SocketServer as socketserver
import argparse
-import cgi
import os
import socket
import subprocess
import sys
import webbrowser
+if sys.version_info >= (3, 2):
+ from html import escape
+else:
+ from cgi import escape
try:
from urllib.request import unquote
except ImportError:
@@ -62,7 +65,7 @@ def match_strip(line, prefix):
return (True, line[len(prefix):])
def html_escape(text):
- return cgi.escape(text, quote=True)
+ return escape(text, quote=True)
def parse(text):
lines = iter(text.split('\n'))
diff --git a/src/build.cc b/src/build.cc
index cd8df4e..db28e65 100644
--- a/src/build.cc
+++ b/src/build.cc
@@ -183,7 +183,7 @@ void BuildStatus::BuildLoadDyndeps() {
// it considers a portion of the graph to be out of date. Normally
// this is done before the build starts, but our caller is about to
// load a dyndep file during the build. Doing so may generate more
- // exlanation lines (via fprintf directly to stderr), but in an
+ // explanation lines (via fprintf directly to stderr), but in an
// interactive console the cursor is currently at the end of a status
// line. Start a new line so that the first explanation does not
// append to the status line. After the explanations are done a
@@ -1033,7 +1033,7 @@ bool Builder::FinishCommand(CommandRunner::Result* result, string* err) {
}
if (!deps_type.empty() && !config_.dry_run) {
- assert(edge->outputs_.size() >= 1 && "should have been rejected by parser");
+ assert(!edge->outputs_.empty() && "should have been rejected by parser");
for (std::vector<Node*>::const_iterator o = edge->outputs_.begin();
o != edge->outputs_.end(); ++o) {
TimeStamp deps_mtime = disk_interface_->Stat((*o)->path(), err);
diff --git a/src/build_log.cc b/src/build_log.cc
index 98543b6..e5f179c 100644
--- a/src/build_log.cc
+++ b/src/build_log.cc
@@ -23,6 +23,7 @@
#include "build_log.h"
#include "disk_interface.h"
+#include <cassert>
#include <errno.h>
#include <stdlib.h>
#include <string.h>
@@ -132,25 +133,9 @@ bool BuildLog::OpenForWrite(const string& path, const BuildLogUser& user,
return false;
}
- log_file_ = fopen(path.c_str(), "ab");
- if (!log_file_) {
- *err = strerror(errno);
- return false;
- }
- setvbuf(log_file_, NULL, _IOLBF, BUFSIZ);
- SetCloseOnExec(fileno(log_file_));
-
- // Opening a file in append mode doesn't set the file pointer to the file's
- // end on Windows. Do that explicitly.
- fseek(log_file_, 0, SEEK_END);
-
- if (ftell(log_file_) == 0) {
- if (fprintf(log_file_, kFileSignature, kCurrentVersion) < 0) {
- *err = strerror(errno);
- return false;
- }
- }
-
+ assert(!log_file_);
+ log_file_path_ = path; // we don't actually open the file right now, but will
+ // do so on the first write attempt
return true;
}
@@ -174,6 +159,9 @@ bool BuildLog::RecordCommand(Edge* edge, int start_time, int end_time,
log_entry->end_time = end_time;
log_entry->mtime = mtime;
+ if (!OpenForWriteIfNeeded()) {
+ return false;
+ }
if (log_file_) {
if (!WriteEntry(log_file_, *log_entry))
return false;
@@ -186,11 +174,36 @@ bool BuildLog::RecordCommand(Edge* edge, int start_time, int end_time,
}
void BuildLog::Close() {
+ OpenForWriteIfNeeded(); // create the file even if nothing has been recorded
if (log_file_)
fclose(log_file_);
log_file_ = NULL;
}
+bool BuildLog::OpenForWriteIfNeeded() {
+ if (log_file_path_.empty()) {
+ return true;
+ }
+ log_file_ = fopen(log_file_path_.c_str(), "ab");
+ if (!log_file_) {
+ return false;
+ }
+ setvbuf(log_file_, NULL, _IOLBF, BUFSIZ);
+ SetCloseOnExec(fileno(log_file_));
+
+ // Opening a file in append mode doesn't set the file pointer to the file's
+ // end on Windows. Do that explicitly.
+ fseek(log_file_, 0, SEEK_END);
+
+ if (ftell(log_file_) == 0) {
+ if (fprintf(log_file_, kFileSignature, kCurrentVersion) < 0) {
+ return false;
+ }
+ }
+ log_file_path_.clear();
+ return true;
+}
+
struct LineReader {
explicit LineReader(FILE* file)
: file_(file), buf_end_(buf_), line_start_(buf_), line_end_(NULL) {
diff --git a/src/build_log.h b/src/build_log.h
index ebe0530..6d060d1 100644
--- a/src/build_log.h
+++ b/src/build_log.h
@@ -45,7 +45,10 @@ struct BuildLog {
BuildLog();
~BuildLog();
+ /// Prepares writing to the log file without actually opening it - that will
+ /// happen when/if it's needed
bool OpenForWrite(const string& path, const BuildLogUser& user, string* err);
+
bool RecordCommand(Edge* edge, int start_time, int end_time,
TimeStamp mtime = 0);
void Close();
@@ -91,8 +94,13 @@ struct BuildLog {
const Entries& entries() const { return entries_; }
private:
+ /// Should be called before using log_file_. When false is returned, errno
+ /// will be set.
+ bool OpenForWriteIfNeeded();
+
Entries entries_;
FILE* log_file_;
+ std::string log_file_path_;
bool needs_recompaction_;
};
diff --git a/src/build_log_test.cc b/src/build_log_test.cc
index a8b1733..c81f570 100644
--- a/src/build_log_test.cc
+++ b/src/build_log_test.cc
@@ -252,7 +252,7 @@ TEST_F(BuildLogTest, Restat) {
ASSERT_EQ(3, e->mtime);
TestDiskInterface testDiskInterface;
- char out2[] = { 'o', 'u', 't', '2' };
+ char out2[] = { 'o', 'u', 't', '2', 0 };
char* filter2[] = { out2 };
EXPECT_TRUE(log.Restat(kTestFilename, testDiskInterface, 1, filter2, &err));
ASSERT_EQ("", err);
diff --git a/src/build_test.cc b/src/build_test.cc
index 426e825..12c3383 100644
--- a/src/build_test.cc
+++ b/src/build_test.cc
@@ -672,7 +672,7 @@ bool FakeCommandRunner::WaitForCommand(Result* result) {
bool verify_active_edge_found = false;
for (vector<Edge*>::iterator i = active_edges_.begin();
i != active_edges_.end(); ++i) {
- if ((*i)->outputs_.size() >= 1 &&
+ if (!(*i)->outputs_.empty() &&
(*i)->outputs_[0]->path() == verify_active_edge) {
verify_active_edge_found = true;
}
diff --git a/src/depfile_parser.cc b/src/depfile_parser.cc
index 90d4a8a..0b7dce1 100644
--- a/src/depfile_parser.cc
+++ b/src/depfile_parser.cc
@@ -1,4 +1,4 @@
-/* Generated by re2c 1.1.1 */
+/* Generated by re2c 1.3 */
// Copyright 2011 Google Inc. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
@@ -166,22 +166,23 @@ yy12:
goto yy5;
yy13:
yych = *(yymarker = ++in);
- if (yych <= 0x1F) {
+ if (yych <= ' ') {
if (yych <= '\n') {
if (yych <= 0x00) goto yy5;
if (yych <= '\t') goto yy16;
goto yy17;
} else {
if (yych == '\r') goto yy19;
- goto yy16;
+ if (yych <= 0x1F) goto yy16;
+ goto yy21;
}
} else {
- if (yych <= '#') {
- if (yych <= ' ') goto yy21;
- if (yych <= '"') goto yy16;
- goto yy23;
+ if (yych <= '9') {
+ if (yych == '#') goto yy23;
+ goto yy16;
} else {
- if (yych == '\\') goto yy25;
+ if (yych <= ':') goto yy25;
+ if (yych == '\\') goto yy27;
goto yy16;
}
}
@@ -231,26 +232,63 @@ yy23:
}
yy25:
yych = *++in;
- if (yych <= 0x1F) {
+ if (yych <= '\f') {
+ if (yych <= 0x00) goto yy28;
+ if (yych <= 0x08) goto yy26;
+ if (yych <= '\n') goto yy28;
+ } else {
+ if (yych <= '\r') goto yy28;
+ if (yych == ' ') goto yy28;
+ }
+yy26:
+ {
+ // De-escape colon sign, but preserve other leading backslashes.
+ // Regular expression uses lookahead to make sure that no whitespace
+ // nor EOF follows. In that case it'd be the : at the end of a target
+ int len = (int)(in - start);
+ if (len > 2 && out < start)
+ memset(out, '\\', len - 2);
+ out += len - 2;
+ *out++ = ':';
+ continue;
+ }
+yy27:
+ yych = *++in;
+ if (yych <= ' ') {
if (yych <= '\n') {
if (yych <= 0x00) goto yy11;
if (yych <= '\t') goto yy16;
goto yy11;
} else {
if (yych == '\r') goto yy11;
- goto yy16;
+ if (yych <= 0x1F) goto yy16;
+ goto yy30;
}
} else {
- if (yych <= '#') {
- if (yych <= ' ') goto yy26;
- if (yych <= '"') goto yy16;
- goto yy23;
+ if (yych <= '9') {
+ if (yych == '#') goto yy23;
+ goto yy16;
} else {
- if (yych == '\\') goto yy28;
+ if (yych <= ':') goto yy25;
+ if (yych == '\\') goto yy32;
goto yy16;
}
}
-yy26:
+yy28:
+ ++in;
+ {
+ // Backslash followed by : and whitespace.
+ // It is therefore normal text and not an escaped colon
+ int len = (int)(in - start - 1);
+ // Need to shift it over if we're overwriting backslashes.
+ if (out < start)
+ memmove(out, start, len);
+ out += len;
+ if (*(in - 1) == '\n')
+ have_newline = true;
+ break;
+ }
+yy30:
++in;
{
// 2N backslashes plus space -> 2N backslashes, end of filename.
@@ -260,24 +298,25 @@ yy26:
out += len - 1;
break;
}
-yy28:
+yy32:
yych = *++in;
- if (yych <= 0x1F) {
+ if (yych <= ' ') {
if (yych <= '\n') {
if (yych <= 0x00) goto yy11;
if (yych <= '\t') goto yy16;
goto yy11;
} else {
if (yych == '\r') goto yy11;
- goto yy16;
+ if (yych <= 0x1F) goto yy16;
+ goto yy21;
}
} else {
- if (yych <= '#') {
- if (yych <= ' ') goto yy21;
- if (yych <= '"') goto yy16;
- goto yy23;
+ if (yych <= '9') {
+ if (yych == '#') goto yy23;
+ goto yy16;
} else {
- if (yych == '\\') goto yy25;
+ if (yych <= ':') goto yy25;
+ if (yych == '\\') goto yy27;
goto yy16;
}
}
diff --git a/src/depfile_parser.in.cc b/src/depfile_parser.in.cc
index b32b942..95b4346 100644
--- a/src/depfile_parser.in.cc
+++ b/src/depfile_parser.in.cc
@@ -103,6 +103,29 @@ bool DepfileParser::Parse(string* content, string* err) {
*out++ = '#';
continue;
}
+ '\\'+ ':' [\x00\x20\r\n\t] {
+ // Backslash followed by : and whitespace.
+ // It is therefore normal text and not an escaped colon
+ int len = (int)(in - start - 1);
+ // Need to shift it over if we're overwriting backslashes.
+ if (out < start)
+ memmove(out, start, len);
+ out += len;
+ if (*(in - 1) == '\n')
+ have_newline = true;
+ break;
+ }
+ '\\'+ ':' {
+ // De-escape colon sign, but preserve other leading backslashes.
+ // Regular expression uses lookahead to make sure that no whitespace
+ // nor EOF follows. In that case it'd be the : at the end of a target
+ int len = (int)(in - start);
+ if (len > 2 && out < start)
+ memset(out, '\\', len - 2);
+ out += len - 2;
+ *out++ = ':';
+ continue;
+ }
'$$' {
// De-escape dollar character.
*out++ = '$';
diff --git a/src/depfile_parser_test.cc b/src/depfile_parser_test.cc
index bf1a0bc..8e2cd25 100644
--- a/src/depfile_parser_test.cc
+++ b/src/depfile_parser_test.cc
@@ -142,6 +142,41 @@ TEST_F(DepfileParserTest, Escapes) {
ASSERT_EQ(0u, parser_.ins_.size());
}
+TEST_F(DepfileParserTest, EscapedColons)
+{
+ std::string err;
+ // Tests for correct parsing of depfiles produced on Windows
+ // by both Clang, GCC pre 10 and GCC 10
+ EXPECT_TRUE(Parse(
+"c\\:\\gcc\\x86_64-w64-mingw32\\include\\stddef.o: \\\n"
+" c:\\gcc\\x86_64-w64-mingw32\\include\\stddef.h \n",
+ &err));
+ ASSERT_EQ("", err);
+ ASSERT_EQ(1u, parser_.outs_.size());
+ EXPECT_EQ("c:\\gcc\\x86_64-w64-mingw32\\include\\stddef.o",
+ parser_.outs_[0].AsString());
+ ASSERT_EQ(1u, parser_.ins_.size());
+ EXPECT_EQ("c:\\gcc\\x86_64-w64-mingw32\\include\\stddef.h",
+ parser_.ins_[0].AsString());
+}
+
+TEST_F(DepfileParserTest, EscapedTargetColon)
+{
+ std::string err;
+ EXPECT_TRUE(Parse(
+"foo1\\: x\n"
+"foo1\\:\n"
+"foo1\\:\r\n"
+"foo1\\:\t\n"
+"foo1\\:",
+ &err));
+ ASSERT_EQ("", err);
+ ASSERT_EQ(1u, parser_.outs_.size());
+ EXPECT_EQ("foo1\\", parser_.outs_[0].AsString());
+ ASSERT_EQ(1u, parser_.ins_.size());
+ EXPECT_EQ("x", parser_.ins_[0].AsString());
+}
+
TEST_F(DepfileParserTest, SpecialChars) {
// See filenames like istreambuf.iterator_op!= in
// https://github.com/google/libcxx/tree/master/test/iterators/stream.iterators/istreambuf.iterator/
diff --git a/src/deps_log.cc b/src/deps_log.cc
index cf55194..1fb65ae 100644
--- a/src/deps_log.cc
+++ b/src/deps_log.cc
@@ -49,34 +49,9 @@ bool DepsLog::OpenForWrite(const string& path, string* err) {
return false;
}
- file_ = fopen(path.c_str(), "ab");
- if (!file_) {
- *err = strerror(errno);
- return false;
- }
- // Set the buffer size to this and flush the file buffer after every record
- // to make sure records aren't written partially.
- setvbuf(file_, NULL, _IOFBF, kMaxRecordSize + 1);
- SetCloseOnExec(fileno(file_));
-
- // Opening a file in append mode doesn't set the file pointer to the file's
- // end on Windows. Do that explicitly.
- fseek(file_, 0, SEEK_END);
-
- if (ftell(file_) == 0) {
- if (fwrite(kFileSignature, sizeof(kFileSignature) - 1, 1, file_) < 1) {
- *err = strerror(errno);
- return false;
- }
- if (fwrite(&kCurrentVersion, 4, 1, file_) < 1) {
- *err = strerror(errno);
- return false;
- }
- }
- if (fflush(file_) != 0) {
- *err = strerror(errno);
- return false;
- }
+ assert(!file_);
+ file_path_ = path; // we don't actually open the file right now, but will do
+ // so on the first write attempt
return true;
}
@@ -132,6 +107,10 @@ bool DepsLog::RecordDeps(Node* node, TimeStamp mtime,
errno = ERANGE;
return false;
}
+
+ if (!OpenForWriteIfNeeded()) {
+ return false;
+ }
size |= 0x80000000; // Deps record: set high bit.
if (fwrite(&size, 4, 1, file_) < 1)
return false;
@@ -162,6 +141,7 @@ bool DepsLog::RecordDeps(Node* node, TimeStamp mtime,
}
void DepsLog::Close() {
+ OpenForWriteIfNeeded(); // create the file even if nothing has been recorded
if (file_)
fclose(file_);
file_ = NULL;
@@ -396,10 +376,14 @@ bool DepsLog::RecordId(Node* node) {
errno = ERANGE;
return false;
}
+
+ if (!OpenForWriteIfNeeded()) {
+ return false;
+ }
if (fwrite(&size, 4, 1, file_) < 1)
return false;
if (fwrite(node->path().data(), path_size, 1, file_) < 1) {
- assert(node->path().size() > 0);
+ assert(!node->path().empty());
return false;
}
if (padding && fwrite("\0\0", padding, 1, file_) < 1)
@@ -416,3 +400,35 @@ bool DepsLog::RecordId(Node* node) {
return true;
}
+
+bool DepsLog::OpenForWriteIfNeeded() {
+ if (file_path_.empty()) {
+ return true;
+ }
+ file_ = fopen(file_path_.c_str(), "ab");
+ if (!file_) {
+ return false;
+ }
+ // Set the buffer size to this and flush the file buffer after every record
+ // to make sure records aren't written partially.
+ setvbuf(file_, NULL, _IOFBF, kMaxRecordSize + 1);
+ SetCloseOnExec(fileno(file_));
+
+ // Opening a file in append mode doesn't set the file pointer to the file's
+ // end on Windows. Do that explicitly.
+ fseek(file_, 0, SEEK_END);
+
+ if (ftell(file_) == 0) {
+ if (fwrite(kFileSignature, sizeof(kFileSignature) - 1, 1, file_) < 1) {
+ return false;
+ }
+ if (fwrite(&kCurrentVersion, 4, 1, file_) < 1) {
+ return false;
+ }
+ }
+ if (fflush(file_) != 0) {
+ return false;
+ }
+ file_path_.clear();
+ return true;
+}
diff --git a/src/deps_log.h b/src/deps_log.h
index e7974a1..c4ada8b 100644
--- a/src/deps_log.h
+++ b/src/deps_log.h
@@ -110,8 +110,13 @@ struct DepsLog {
// Write a node name record, assigning it an id.
bool RecordId(Node* node);
+ /// Should be called before using file_. When false is returned, errno will
+ /// be set.
+ bool OpenForWriteIfNeeded();
+
bool needs_recompaction_;
FILE* file_;
+ std::string file_path_;
/// Maps id -> Node.
vector<Node*> nodes_;
diff --git a/src/disk_interface.cc b/src/disk_interface.cc
index dc297c4..594bc51 100644
--- a/src/disk_interface.cc
+++ b/src/disk_interface.cc
@@ -26,6 +26,8 @@
#include <sstream>
#include <windows.h>
#include <direct.h> // _mkdir
+#else
+#include <unistd.h>
#endif
#include "metrics.h"
diff --git a/src/disk_interface_test.cc b/src/disk_interface_test.cc
index bac515d..866d1d6 100644
--- a/src/disk_interface_test.cc
+++ b/src/disk_interface_test.cc
@@ -190,7 +190,7 @@ TEST_F(DiskInterfaceTest, ReadFile) {
TEST_F(DiskInterfaceTest, MakeDirs) {
string path = "path/with/double//slash/";
- EXPECT_TRUE(disk_.MakeDirs(path.c_str()));
+ EXPECT_TRUE(disk_.MakeDirs(path));
FILE* f = fopen((path + "a_file").c_str(), "w");
EXPECT_TRUE(f);
EXPECT_EQ(0, fclose(f));
diff --git a/src/ninja.cc b/src/ninja.cc
index 1429639..00e3a5c 100644
--- a/src/ninja.cc
+++ b/src/ninja.cc
@@ -91,7 +91,7 @@ struct NinjaMain : public BuildLogUser {
/// Loaded state (rules, nodes).
State state_;
- /// Functions for accesssing the disk.
+ /// Functions for accessing the disk.
RealDiskInterface disk_interface_;
/// The build directory, used for storing the build log etc.
@@ -1050,7 +1050,7 @@ bool DebugEnable(const string& name) {
}
}
-/// Set a warning flag. Returns false if Ninja should exit instead of
+/// Set a warning flag. Returns false if Ninja should exit instead of
/// continuing.
bool WarningEnable(const string& name, Options* options) {
if (name == "list") {
diff --git a/src/string_piece_util.cc b/src/string_piece_util.cc
index 8e1ecfd..69513f5 100644
--- a/src/string_piece_util.cc
+++ b/src/string_piece_util.cc
@@ -39,7 +39,7 @@ vector<StringPiece> SplitStringPiece(StringPiece input, char sep) {
}
string JoinStringPiece(const vector<StringPiece>& list, char sep) {
- if (list.size() == 0){
+ if (list.empty()) {
return "";
}
diff --git a/src/subprocess-posix.cc b/src/subprocess-posix.cc
index fc5543e..74785d1 100644
--- a/src/subprocess-posix.cc
+++ b/src/subprocess-posix.cc
@@ -18,13 +18,18 @@
#include <assert.h>
#include <errno.h>
#include <fcntl.h>
-#include <poll.h>
#include <unistd.h>
#include <stdio.h>
#include <string.h>
#include <sys/wait.h>
#include <spawn.h>
+#if defined(USE_PPOLL)
+#include <poll.h>
+#else
+#include <sys/select.h>
+#endif
+
extern char** environ;
#include "util.h"
diff --git a/src/subprocess-win32.cc b/src/subprocess-win32.cc
index a4a7669..d221476 100644
--- a/src/subprocess-win32.cc
+++ b/src/subprocess-win32.cc
@@ -124,12 +124,20 @@ bool Subprocess::Start(SubprocessSet* set, const string& command) {
buf_ = "CreateProcess failed: The system cannot find the file "
"specified.\n";
return true;
- } else if (error == ERROR_INVALID_PARAMETER) {
- // This generally means that the command line was too long. Give extra
- // context for this case.
- Win32Fatal("CreateProcess", "is the command line too long?");
} else {
- Win32Fatal("CreateProcess"); // pass all other errors to Win32Fatal
+ fprintf(stderr, "\nCreateProcess failed. Command attempted:\n\"%s\"\n",
+ command.c_str());
+ const char* hint = NULL;
+ // ERROR_INVALID_PARAMETER means the command line was formatted
+ // incorrectly. This can be caused by a command line being too long or
+ // leading whitespace in the command. Give extra context for this case.
+ if (error == ERROR_INVALID_PARAMETER) {
+ if (command.length() > 0 && (command[0] == ' ' || command[0] == '\t'))
+ hint = "command contains leading whitespace";
+ else
+ hint = "is the command line too long?";
+ }
+ Win32Fatal("CreateProcess", hint);
}
}
diff --git a/src/test.cc b/src/test.cc
index 8ba2297..021005e 100644
--- a/src/test.cc
+++ b/src/test.cc
@@ -24,6 +24,7 @@
#include <stdlib.h>
#ifdef _WIN32
#include <windows.h>
+#include <io.h>
#else
#include <unistd.h>
#endif
@@ -45,19 +46,9 @@ extern "C" {
namespace {
#ifdef _WIN32
-#ifndef _mktemp_s
-/// mingw has no mktemp. Implement one with the same type as the one
-/// found in the Windows API.
-int _mktemp_s(char* templ) {
- char* ofs = strchr(templ, 'X');
- sprintf(ofs, "%d", rand() % 1000000);
- return 0;
-}
-#endif
-
/// Windows has no mkdtemp. Implement it in terms of _mktemp_s.
char* mkdtemp(char* name_template) {
- int err = _mktemp_s(name_template);
+ int err = _mktemp_s(name_template, strlen(name_template) + 1);
if (err < 0) {
perror("_mktemp_s");
return NULL;
diff --git a/src/version.cc b/src/version.cc
index 08c0ae9..04dcea5 100644
--- a/src/version.cc
+++ b/src/version.cc
@@ -18,7 +18,7 @@
#include "util.h"
-const char* kNinjaVersion = "1.10.0";
+const char* kNinjaVersion = "1.10.1";
void ParseVersion(const string& version, int* major, int* minor) {
size_t end = version.find('.');