1 /* 2 * Licensed to the Apache Software Foundation (ASF) under one or more 3 * contributor license agreements. See the NOTICE file distributed with 4 * this work for additional information regarding copyright ownership. 5 * The ASF licenses this file to You under the Apache License, Version 2.0 6 * (the "License"); you may not use this file except in compliance with 7 * the License. You may obtain a copy of the License at 8 * 9 * http://www.apache.org/licenses/LICENSE-2.0 10 * 11 * Unless required by applicable law or agreed to in writing, software 12 * distributed under the License is distributed on an "AS IS" BASIS, 13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 * See the License for the specific language governing permissions and 15 * limitations under the License. 16 */ 17 18 #define LOG_TAG "StrictJarFile" 19 20 #include <string> 21 22 #include "JNIHelp.h" 23 #include "JniConstants.h" 24 #include "ScopedLocalRef.h" 25 #include "ScopedUtfChars.h" 26 #include "UniquePtr.h" 27 #include "jni.h" 28 #include "ziparchive/zip_archive.h" 29 #include "cutils/log.h" 30 31 static void throwIoException(JNIEnv* env, const int32_t errorCode) { 32 jniThrowException(env, "java/io/IOException", ErrorCodeString(errorCode)); 33 } 34 35 // Constructs a string out of |name| with the default charset (UTF-8 on android). 36 // We prefer this to JNI's NewStringUTF because the string constructor will 37 // replace unmappable and malformed bytes instead of throwing. See b/18584205 38 // 39 // Returns |NULL| iff. we couldn't allocate the string object or its constructor 40 // arguments. 41 // 42 // TODO: switch back to NewStringUTF after libziparchive is modified to reject 43 // files whose names aren't valid UTF-8. 44 static jobject constructString(JNIEnv* env, const char* name, const uint16_t nameLength) { 45 jbyteArray javaNameBytes = env->NewByteArray(nameLength); 46 if (javaNameBytes == NULL) { 47 return NULL; 48 } 49 env->SetByteArrayRegion(javaNameBytes, 0, nameLength, reinterpret_cast<const jbyte*>(name)); 50 51 ScopedLocalRef<jclass> stringClass(env, env->FindClass("java/lang/String")); 52 const jmethodID stringCtor = env->GetMethodID(stringClass.get(), "<init>", "([B)V"); 53 return env->NewObject(stringClass.get(), stringCtor, javaNameBytes); 54 } 55 56 static jobject newZipEntry(JNIEnv* env, const ZipEntry& entry, const jobject entryName, 57 const uint16_t nameLength) { 58 ScopedLocalRef<jclass> zipEntryClass(env, env->FindClass("java/util/zip/ZipEntry")); 59 const jmethodID zipEntryCtor = env->GetMethodID(zipEntryClass.get(), "<init>", 60 "(Ljava/lang/String;Ljava/lang/String;JJJIII[BIJJ)V"); 61 62 return env->NewObject(zipEntryClass.get(), 63 zipEntryCtor, 64 entryName, 65 NULL, // comment 66 static_cast<jlong>(entry.crc32), 67 static_cast<jlong>(entry.compressed_length), 68 static_cast<jlong>(entry.uncompressed_length), 69 static_cast<jint>(entry.method), 70 static_cast<jint>(0), // time 71 static_cast<jint>(0), // modData 72 NULL, // byte[] extra 73 static_cast<jint>(nameLength), 74 static_cast<jlong>(-1), // local header offset 75 static_cast<jlong>(entry.offset)); 76 } 77 78 static jobject newZipEntry(JNIEnv* env, const ZipEntry& entry, const char* name, 79 const uint16_t nameLength) { 80 return newZipEntry(env, entry, constructString(env, name, nameLength), nameLength); 81 } 82 83 static jlong StrictJarFile_nativeOpenJarFile(JNIEnv* env, jobject, jstring fileName) { 84 ScopedUtfChars fileChars(env, fileName); 85 if (fileChars.c_str() == NULL) { 86 return static_cast<jlong>(-1); 87 } 88 89 ZipArchiveHandle handle; 90 int32_t error = OpenArchive(fileChars.c_str(), &handle); 91 if (error) { 92 throwIoException(env, error); 93 return static_cast<jlong>(-1); 94 } 95 96 return reinterpret_cast<jlong>(handle); 97 } 98 99 class IterationHandle { 100 public: 101 IterationHandle(const char* prefix) : 102 cookie_(NULL), prefix_(strdup(prefix)) { 103 } 104 105 void** CookieAddress() { 106 return &cookie_; 107 } 108 109 const char* Prefix() const { 110 return prefix_; 111 } 112 113 ~IterationHandle() { 114 free(prefix_); 115 } 116 117 private: 118 void* cookie_; 119 char* prefix_; 120 }; 121 122 123 static jlong StrictJarFile_nativeStartIteration(JNIEnv* env, jobject, jlong nativeHandle, 124 jstring prefix) { 125 ScopedUtfChars prefixChars(env, prefix); 126 if (prefixChars.c_str() == NULL) { 127 return static_cast<jlong>(-1); 128 } 129 130 IterationHandle* handle = new IterationHandle(prefixChars.c_str()); 131 int32_t error = 0; 132 if (prefixChars.size() == 0) { 133 error = StartIteration(reinterpret_cast<ZipArchiveHandle>(nativeHandle), 134 handle->CookieAddress(), NULL); 135 } else { 136 error = StartIteration(reinterpret_cast<ZipArchiveHandle>(nativeHandle), 137 handle->CookieAddress(), handle->Prefix()); 138 } 139 140 if (error) { 141 throwIoException(env, error); 142 return static_cast<jlong>(-1); 143 } 144 145 return reinterpret_cast<jlong>(handle); 146 } 147 148 static jobject StrictJarFile_nativeNextEntry(JNIEnv* env, jobject, jlong iterationHandle) { 149 ZipEntry data; 150 ZipEntryName entryName; 151 152 IterationHandle* handle = reinterpret_cast<IterationHandle*>(iterationHandle); 153 const int32_t error = Next(*handle->CookieAddress(), &data, &entryName); 154 if (error) { 155 delete handle; 156 return NULL; 157 } 158 159 UniquePtr<char[]> entryNameCString(new char[entryName.name_length + 1]); 160 memcpy(entryNameCString.get(), entryName.name, entryName.name_length); 161 entryNameCString[entryName.name_length] = '\0'; 162 163 return newZipEntry(env, data, entryNameCString.get(), entryName.name_length); 164 } 165 166 static jobject StrictJarFile_nativeFindEntry(JNIEnv* env, jobject, jlong nativeHandle, 167 jstring entryName) { 168 ScopedUtfChars entryNameChars(env, entryName); 169 if (entryNameChars.c_str() == NULL) { 170 return NULL; 171 } 172 173 ZipEntry data; 174 const int32_t error = FindEntry(reinterpret_cast<ZipArchiveHandle>(nativeHandle), 175 entryNameChars.c_str(), &data); 176 if (error) { 177 return NULL; 178 } 179 180 return newZipEntry(env, data, entryName, entryNameChars.size()); 181 } 182 183 static void StrictJarFile_nativeClose(JNIEnv*, jobject, jlong nativeHandle) { 184 CloseArchive(reinterpret_cast<ZipArchiveHandle>(nativeHandle)); 185 } 186 187 static JNINativeMethod gMethods[] = { 188 NATIVE_METHOD(StrictJarFile, nativeOpenJarFile, "(Ljava/lang/String;)J"), 189 NATIVE_METHOD(StrictJarFile, nativeStartIteration, "(JLjava/lang/String;)J"), 190 NATIVE_METHOD(StrictJarFile, nativeNextEntry, "(J)Ljava/util/zip/ZipEntry;"), 191 NATIVE_METHOD(StrictJarFile, nativeFindEntry, "(JLjava/lang/String;)Ljava/util/zip/ZipEntry;"), 192 NATIVE_METHOD(StrictJarFile, nativeClose, "(J)V"), 193 }; 194 195 void register_java_util_jar_StrictJarFile(JNIEnv* env) { 196 jniRegisterNativeMethods(env, "java/util/jar/StrictJarFile", gMethods, NELEM(gMethods)); 197 } 198