Include manifest size when presizing ijar output
PiperOrigin-RevId: 190010996
diff --git a/third_party/ijar/ijar.cc b/third_party/ijar/ijar.cc
index d7742ee..2ed559d 100644
--- a/third_party/ijar/ijar.cc
+++ b/third_party/ijar/ijar.cc
@@ -36,13 +36,20 @@
const char* CLASS_EXTENSION = ".class";
const size_t CLASS_EXTENSION_LENGTH = strlen(CLASS_EXTENSION);
+const char *MANIFEST_DIR_PATH = "META-INF/";
+const size_t MANIFEST_DIR_PATH_LENGTH = strlen(MANIFEST_DIR_PATH);
+const char *MANIFEST_PATH = "META-INF/MANIFEST.MF";
+const size_t MANIFEST_PATH_LENGTH = strlen(MANIFEST_PATH);
const char *MANIFEST_HEADER =
- "Manifest-Version: 1.0\n"
- "Created-By: bazel\n";
+ "Manifest-Version: 1.0\r\n"
+ "Created-By: bazel\r\n";
+const size_t MANIFEST_HEADER_LENGTH = strlen(MANIFEST_HEADER);
// These attributes are used by JavaBuilder, Turbine, and ijar.
// They must all be kept in sync.
const char *TARGET_LABEL_KEY = "Target-Label: ";
+const size_t TARGET_LABEL_KEY_LENGTH = strlen(TARGET_LABEL_KEY);
const char *INJECTING_RULE_KIND_KEY = "Injecting-Rule-Kind: ";
+const size_t INJECTING_RULE_KIND_KEY_LENGTH = strlen(INJECTING_RULE_KIND_KEY);
// ZipExtractorProcessor that select only .class file and use
// StripClass to generate an interface class, storing as a new file
@@ -120,21 +127,48 @@
return len;
}
+// Computes the size of zip file content for the manifest created by
+// WriteManifest, including zip file format overhead.
+static size_t EstimateManifestOutputSize(const char *target_label,
+ const char *injecting_rule_kind) {
+ if (target_label == NULL) {
+ return 0;
+ }
+ // local headers
+ size_t length = 30 * 2 + MANIFEST_DIR_PATH_LENGTH + MANIFEST_PATH_LENGTH;
+ // central directory
+ length += 46 * 2 + MANIFEST_DIR_PATH_LENGTH + MANIFEST_PATH_LENGTH;
+ // zip64 EOCD entries
+ length += 56 * 2;
+
+ // manifest content
+ length += MANIFEST_HEADER_LENGTH;
+ // target label manifest entry, including newline
+ length += TARGET_LABEL_KEY_LENGTH + strlen(target_label) + 2;
+ if (injecting_rule_kind) {
+ // injecting rule kind manifest entry, including newline
+ length += INJECTING_RULE_KIND_KEY_LENGTH + strlen(injecting_rule_kind) + 2;
+ }
+ return length;
+}
+
static void WriteManifest(ZipBuilder *out, const char *target_label,
const char *injecting_rule_kind) {
if (target_label == NULL) {
return;
}
- out->WriteEmptyFile("META-INF/");
- u1 *start = out->NewFile("META-INF/MANIFEST.MF", 0);
+ out->WriteEmptyFile(MANIFEST_DIR_PATH);
+ u1 *start = out->NewFile(MANIFEST_PATH, 0);
u1 *buf = start;
buf += WriteStr(buf, MANIFEST_HEADER);
buf += WriteStr(buf, TARGET_LABEL_KEY);
buf += WriteStr(buf, target_label);
+ *buf++ = '\r';
*buf++ = '\n';
if (injecting_rule_kind) {
buf += WriteStr(buf, INJECTING_RULE_KIND_KEY);
buf += WriteStr(buf, injecting_rule_kind);
+ *buf++ = '\r';
*buf++ = '\n';
}
size_t total_len = buf - start;
@@ -153,7 +187,9 @@
strerror(errno));
abort();
}
- u8 output_length = in->CalculateOutputLength();
+ u8 output_length =
+ in->CalculateOutputLength() +
+ EstimateManifestOutputSize(target_label, injecting_rule_kind);
std::unique_ptr<ZipBuilder> out(ZipBuilder::Create(file_out, output_length));
if (out.get() == NULL) {
fprintf(stderr, "Unable to open output file %s: %s\n", file_out,
diff --git a/third_party/ijar/mapped_file.h b/third_party/ijar/mapped_file.h
index 6db0673..7653638 100644
--- a/third_party/ijar/mapped_file.h
+++ b/third_party/ijar/mapped_file.h
@@ -62,6 +62,7 @@
const char* errmsg_;
bool opened_;
u1* buffer_;
+ u8 estimated_size_;
public:
MappedOutputFile(const char* name, u8 estimated_size);
diff --git a/third_party/ijar/mapped_file_unix.cc b/third_party/ijar/mapped_file_unix.cc
index d5a0b57..ccb8787 100644
--- a/third_party/ijar/mapped_file_unix.cc
+++ b/third_party/ijar/mapped_file_unix.cc
@@ -90,7 +90,8 @@
int mmap_length_;
};
-MappedOutputFile::MappedOutputFile(const char* name, u8 estimated_size) {
+MappedOutputFile::MappedOutputFile(const char* name, u8 estimated_size)
+ : estimated_size_(estimated_size) {
impl_ = NULL;
opened_ = false;
int fd = open(name, O_CREAT|O_RDWR|O_TRUNC, 0644);
@@ -131,6 +132,12 @@
}
int MappedOutputFile::Close(int size) {
+ if (size > estimated_size_) {
+ snprintf(errmsg, MAX_ERROR, "size %d > estimated size %lld", size,
+ estimated_size_);
+ errmsg_ = errmsg;
+ return -1;
+ }
munmap(buffer_, impl_->mmap_length_);
if (ftruncate(impl_->fd_, size) < 0) {
snprintf(errmsg, MAX_ERROR, "ftruncate(): %s", strerror(errno));
diff --git a/third_party/ijar/test/BUILD b/third_party/ijar/test/BUILD
index d9ab5f7..62b6edd 100644
--- a/third_party/ijar/test/BUILD
+++ b/third_party/ijar/test/BUILD
@@ -109,6 +109,14 @@
tools = ["//third_party/ijar"],
)
+genrule(
+ name = "empty_with_target_label",
+ srcs = [":empty_zip.jar"],
+ outs = ["empty_with_target_label.jar"],
+ cmd = "$(location //third_party/ijar) $< $@ --target_label //empty",
+ tools = ["//third_party/ijar"],
+)
+
java_library(
name = "typeannotations2",
srcs = glob(["typeannotations2/**/*.java"]),
@@ -187,6 +195,7 @@
"UseDeprecatedParts.java",
"UseRestrictedAnnotation.java",
"package-info.java",
+ ":empty_with_target_label",
":interface_ijar_testlib",
":interface_ijar_testlib_with_target_label",
":liblocal_and_anonymous_lib.jar",
@@ -234,6 +243,7 @@
("largest_regular", 65535),
("smallest_zip64", 65536),
("definitely_zip64", 70000),
+ ("empty_zip", 1),
]
]
diff --git a/third_party/ijar/test/IjarTests.java b/third_party/ijar/test/IjarTests.java
index a2e10db..dc6c020 100644
--- a/third_party/ijar/test/IjarTests.java
+++ b/third_party/ijar/test/IjarTests.java
@@ -292,4 +292,16 @@
LocalDateTime.of(2010, 1, 1, 0, 0, 0).atZone(ZoneOffset.systemDefault()).toInstant());
}
}
+
+ @Test
+ public void testEmptyWithTargetLabel() throws Exception {
+ try (JarFile jf = new JarFile("third_party/ijar/test/empty_with_target_label.jar")) {
+ Manifest manifest = jf.getManifest();
+ Attributes attributes = manifest.getMainAttributes();
+ assertThat(attributes.getValue("Target-Label")).isEqualTo("//empty");
+ assertThat(jf.getEntry(JarFile.MANIFEST_NAME).getLastModifiedTime().toInstant())
+ .isEqualTo(
+ LocalDateTime.of(2010, 1, 1, 0, 0, 0).atZone(ZoneOffset.systemDefault()).toInstant());
+ }
+ }
}