Implement memory-mapped zip files in ijar for Windows.
Progress towards #276.
--
MOS_MIGRATED_REVID=114829911
diff --git a/third_party/ijar/BUILD b/third_party/ijar/BUILD
index 0f4390b..edd6bf1 100644
--- a/third_party/ijar/BUILD
+++ b/third_party/ijar/BUILD
@@ -16,9 +16,15 @@
cc_library(
name = "zip",
srcs = [
- "mapped_file_unix.cc",
"zip.cc",
- ],
+ ] + select({
+ "//src:windows": [
+ "mapped_file_windows.cc",
+ ],
+ "//conditions:default": [
+ "mapped_file_unix.cc",
+ ],
+ }),
hdrs = [
"common.h",
"mapped_file.h",
diff --git a/third_party/ijar/mapped_file_windows.cc b/third_party/ijar/mapped_file_windows.cc
new file mode 100644
index 0000000..6b4ba30
--- /dev/null
+++ b/third_party/ijar/mapped_file_windows.cc
@@ -0,0 +1,203 @@
+// Copyright 2015 The Bazel Authors. 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.
+
+#include <stdio.h>
+#include <windows.h>
+#include <sys/cygwin.h>
+
+#include "third_party/ijar/mapped_file.h"
+
+#define MAX_ERROR 2048
+
+namespace devtools_ijar {
+
+static char errmsg[MAX_ERROR] = "";
+
+void PrintLastError(const char* op) {
+ char *message;
+ DWORD err = GetLastError();
+ FormatMessage(
+ FORMAT_MESSAGE_ALLOCATE_BUFFER
+ | FORMAT_MESSAGE_FROM_SYSTEM
+ | FORMAT_MESSAGE_IGNORE_INSERTS,
+ NULL, err, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
+ reinterpret_cast<char *>(&message),
+ 0, NULL);
+ snprintf(errmsg, MAX_ERROR, "%s: %s", op, message);
+ LocalFree(message);
+}
+
+struct MappedInputFileImpl {
+ HANDLE file_;
+ HANDLE mapping_;
+
+ MappedInputFileImpl(HANDLE file, HANDLE mapping) {
+ file_ = file;
+ mapping_ = mapping;
+ }
+};
+
+MappedInputFile::MappedInputFile(const char* name) {
+ impl_ = NULL;
+ opened_ = false;
+ errmsg_ = errmsg;
+
+ char* path = reinterpret_cast<char*>(
+ cygwin_create_path(CCP_POSIX_TO_WIN_A, name));
+ HANDLE file = CreateFile(
+ path, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, NULL);
+ free(path);
+ if (file == INVALID_HANDLE_VALUE) {
+ PrintLastError("CreateFile()");
+ return;
+ }
+
+ LARGE_INTEGER size;
+ if (!GetFileSizeEx(file, &size)) {
+ PrintLastError("GetFileSizeEx()");
+ CloseHandle(file);
+ return;
+ }
+
+ HANDLE mapping = CreateFileMapping(file, NULL, PAGE_READONLY,
+ size.HighPart, size.LowPart, NULL);
+ if (mapping == NULL) {
+ PrintLastError("CreateFileMapping()");
+ CloseHandle(file);
+ return;
+ }
+
+ void *view = MapViewOfFileEx(mapping, FILE_MAP_READ, 0, 0, 0, NULL);
+ if (view == NULL) {
+ PrintLastError("MapViewOfFileEx()");
+ CloseHandle(mapping);
+ CloseHandle(file);
+ return;
+ }
+
+ impl_ = new MappedInputFileImpl(file, mapping);
+ length_ = size.QuadPart;
+ buffer_ = reinterpret_cast<u1*>(view);
+ opened_ = true;
+}
+
+MappedInputFile::~MappedInputFile() {
+ delete impl_;
+}
+
+void MappedInputFile::Discard(size_t bytes) {
+ // This is not supported on Windows for now. I'm not sure if we can unmap
+ // parts of an existing view and that this is necessary for Windows at all.
+ // At any rate, this only matters for >2GB (or maybe >4GB?) input files.
+}
+
+int MappedInputFile::Close() {
+ if (!UnmapViewOfFile(buffer_)) {
+ PrintLastError("UnmapViewOfFile()");
+ return -1;
+ }
+
+ if (!CloseHandle(impl_->mapping_)) {
+ PrintLastError("CloseHandle(mapping)");
+ return -1;
+ }
+
+ if (!CloseHandle(impl_->file_)) {
+ PrintLastError("CloseHandle(file)");
+ return -1;
+ }
+
+ return 0;
+}
+
+struct MappedOutputFileImpl {
+ HANDLE file_;
+ HANDLE mapping_;
+
+ MappedOutputFileImpl(HANDLE file, HANDLE mapping) {
+ file_ = file;
+ mapping_ = mapping;
+ }
+};
+
+MappedOutputFile::MappedOutputFile(const char* name, u8 estimated_size) {
+ impl_ = NULL;
+ opened_ = false;
+ errmsg_ = errmsg;
+
+ char* path = reinterpret_cast<char*>(
+ cygwin_create_path(CCP_POSIX_TO_WIN_A, name));
+ HANDLE file = CreateFile(
+ path, GENERIC_READ | GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, 0, NULL);
+ free(path);
+ if (file == INVALID_HANDLE_VALUE) {
+ PrintLastError("CreateFile()");
+ return;
+ }
+
+ HANDLE mapping = CreateFileMapping(file, NULL, PAGE_READWRITE,
+ estimated_size >> 32, estimated_size & 0xffffffffUL, NULL);
+ if (mapping == NULL) {
+ PrintLastError("CreateFileMapping()");
+ CloseHandle(file);
+ return;
+ }
+
+ void *view = MapViewOfFileEx(mapping, FILE_MAP_ALL_ACCESS, 0, 0, 0, NULL);
+ if (view == NULL) {
+ PrintLastError("MapViewOfFileEx()");
+ CloseHandle(mapping);
+ CloseHandle(file);
+ return;
+ }
+
+ impl_ = new MappedOutputFileImpl(file, mapping);
+ buffer_ = reinterpret_cast<u1*>(view);
+ opened_ = true;
+}
+
+MappedOutputFile::~MappedOutputFile() {
+ delete impl_;
+}
+
+int MappedOutputFile::Close(int size) {
+ if (!UnmapViewOfFile(buffer_)) {
+ PrintLastError("UnmapViewOfFile()");
+ return -1;
+ }
+
+ if (!CloseHandle(impl_->mapping_)) {
+ PrintLastError("CloseHandle(mapping)");
+ return -1;
+ }
+
+ if (!SetFilePointer(impl_->file_, size, NULL, FILE_BEGIN)) {
+ PrintLastError("SetFilePointer()");
+ return -1;
+ }
+
+ if (!SetEndOfFile(impl_->file_)) {
+ PrintLastError("SetEndOfFile()");
+ return -1;
+ }
+
+ if (!CloseHandle(impl_->file_)) {
+ PrintLastError("CloseHandle(file)");
+ return -1;
+ }
+
+ return 0;
+}
+
+} // namespace devtools_ijar