/* * Copy the native library if needed. * * This function assumes the library and path names passed in are considered safe. */ static install_status_t copyFileIfChanged(JNIEnv *env, void* arg, ZipFileRO* zipFile, ZipEntryRO zipEntry, const char* fileName) { jstring* javaNativeLibPath = (jstring*) arg; ScopedUtfChars nativeLibPath(env, *javaNativeLibPath); size_t uncompLen; long when; long crc; time_t modTime; if (!zipFile->getEntryInfo(zipEntry, NULL, &uncompLen, NULL, NULL, &when, &crc)) { LOGD("Couldn't read zip entry info\n"); return INSTALL_FAILED_INVALID_APK; } else { struct tm t; ZipFileRO::zipTimeToTimespec(when, &t); modTime = mktime(&t); } // Build local file path const size_t fileNameLen = strlen(fileName); char localFileName[nativeLibPath.size() + fileNameLen + 2]; if (strlcpy(localFileName, nativeLibPath.c_str(), sizeof(localFileName)) != nativeLibPath.size()) { LOGD("Couldn't allocate local file name for library"); return INSTALL_FAILED_INTERNAL_ERROR; } *(localFileName + nativeLibPath.size()) = '/'; if (strlcpy(localFileName + nativeLibPath.size() + 1, fileName, sizeof(localFileName) - nativeLibPath.size() - 1) != fileNameLen) { LOGD("Couldn't allocate local file name for library"); return INSTALL_FAILED_INTERNAL_ERROR; } // Only copy out the native file if it's different. struct stat st; if (!isFileDifferent(localFileName, uncompLen, modTime, crc, &st)) { return INSTALL_SUCCEEDED; } char localTmpFileName[nativeLibPath.size() + TMP_FILE_PATTERN_LEN + 2]; if (strlcpy(localTmpFileName, nativeLibPath.c_str(), sizeof(localTmpFileName)) != nativeLibPath.size()) { LOGD("Couldn't allocate local file name for library"); return INSTALL_FAILED_INTERNAL_ERROR; } *(localFileName + nativeLibPath.size()) = '/'; if (strlcpy(localTmpFileName + nativeLibPath.size(), TMP_FILE_PATTERN, sizeof(localTmpFileName) - nativeLibPath.size() - 1) != TMP_FILE_PATTERN_LEN) { LOGI("Couldn't allocate temporary file name for library"); return INSTALL_FAILED_INTERNAL_ERROR; } int fd = mkstemp(localTmpFileName); if (fd < 0) { LOGI("Couldn't open temporary file name: %s: %s\n", localTmpFileName, strerror(errno)); return INSTALL_FAILED_CONTAINER_ERROR; } if (!zipFile->uncompressEntry(zipEntry, fd)) { LOGI("Failed uncompressing %s to %s\n", fileName, localTmpFileName); close(fd); unlink(localTmpFileName); return INSTALL_FAILED_CONTAINER_ERROR; } close(fd); // Set the modification time for this file to the ZIP's mod time. struct timeval times[2]; times[0].tv_sec = st.st_atime; times[1].tv_sec = modTime; times[0].tv_usec = times[1].tv_usec = 0; if (utimes(localTmpFileName, times) < 0) { LOGI("Couldn't change modification time on %s: %s\n", localTmpFileName, strerror(errno)); unlink(localTmpFileName); return INSTALL_FAILED_CONTAINER_ERROR; } // Set the mode to 755 static const mode_t mode = S_IRUSR | S_IWUSR | S_IXUSR | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH; if (chmod(localTmpFileName, mode) < 0) { LOGI("Couldn't change permissions on %s: %s\n", localTmpFileName, strerror(errno)); unlink(localTmpFileName); return INSTALL_FAILED_CONTAINER_ERROR; } // Finally, rename it to the final name. if (rename(localTmpFileName, localFileName) < 0) { LOGI("Couldn't rename %s to %s: %s\n", localTmpFileName, localFileName, strerror(errno)); unlink(localTmpFileName); return INSTALL_FAILED_CONTAINER_ERROR; } LOGV("Successfully moved %s to %s\n", localTmpFileName, localFileName); return INSTALL_SUCCEEDED; }
/* * Copy the native library if needed. * * This function assumes the library and path names passed in are considered safe. */ static install_status_t copyFileIfChanged(JNIEnv *env, void* arg, ZipFileRO* zipFile, ZipEntryRO zipEntry, const char* fileName) { void** args = reinterpret_cast<void**>(arg); jstring* javaNativeLibPath = (jstring*) args[0]; jboolean extractNativeLibs = *(jboolean*) args[1]; jboolean hasNativeBridge = *(jboolean*) args[2]; ScopedUtfChars nativeLibPath(env, *javaNativeLibPath); uint32_t uncompLen; uint32_t when; uint32_t crc; uint16_t method; off64_t offset; if (!zipFile->getEntryInfo(zipEntry, &method, &uncompLen, NULL, &offset, &when, &crc)) { ALOGD("Couldn't read zip entry info\n"); return INSTALL_FAILED_INVALID_APK; } if (!extractNativeLibs) { // check if library is uncompressed and page-aligned if (method != ZipFileRO::kCompressStored) { ALOGD("Library '%s' is compressed - will not be able to open it directly from apk.\n", fileName); return INSTALL_FAILED_INVALID_APK; } if (offset % PAGE_SIZE != 0) { ALOGD("Library '%s' is not page-aligned - will not be able to open it directly from" " apk.\n", fileName); return INSTALL_FAILED_INVALID_APK; } if (!hasNativeBridge) { return INSTALL_SUCCEEDED; } } // Build local file path const size_t fileNameLen = strlen(fileName); char localFileName[nativeLibPath.size() + fileNameLen + 2]; if (strlcpy(localFileName, nativeLibPath.c_str(), sizeof(localFileName)) != nativeLibPath.size()) { ALOGD("Couldn't allocate local file name for library"); return INSTALL_FAILED_INTERNAL_ERROR; } *(localFileName + nativeLibPath.size()) = '/'; if (strlcpy(localFileName + nativeLibPath.size() + 1, fileName, sizeof(localFileName) - nativeLibPath.size() - 1) != fileNameLen) { ALOGD("Couldn't allocate local file name for library"); return INSTALL_FAILED_INTERNAL_ERROR; } // Only copy out the native file if it's different. struct tm t; ZipUtils::zipTimeToTimespec(when, &t); const time_t modTime = mktime(&t); struct stat64 st; if (!isFileDifferent(localFileName, uncompLen, modTime, crc, &st)) { return INSTALL_SUCCEEDED; } char localTmpFileName[nativeLibPath.size() + TMP_FILE_PATTERN_LEN + 2]; if (strlcpy(localTmpFileName, nativeLibPath.c_str(), sizeof(localTmpFileName)) != nativeLibPath.size()) { ALOGD("Couldn't allocate local file name for library"); return INSTALL_FAILED_INTERNAL_ERROR; } *(localFileName + nativeLibPath.size()) = '/'; if (strlcpy(localTmpFileName + nativeLibPath.size(), TMP_FILE_PATTERN, TMP_FILE_PATTERN_LEN - nativeLibPath.size()) != TMP_FILE_PATTERN_LEN) { ALOGI("Couldn't allocate temporary file name for library"); return INSTALL_FAILED_INTERNAL_ERROR; } int fd = mkstemp(localTmpFileName); if (fd < 0) { ALOGI("Couldn't open temporary file name: %s: %s\n", localTmpFileName, strerror(errno)); return INSTALL_FAILED_CONTAINER_ERROR; } if (!zipFile->uncompressEntry(zipEntry, fd)) { ALOGI("Failed uncompressing %s to %s\n", fileName, localTmpFileName); close(fd); unlink(localTmpFileName); return INSTALL_FAILED_CONTAINER_ERROR; } close(fd); // Set the modification time for this file to the ZIP's mod time. struct timeval times[2]; times[0].tv_sec = st.st_atime; times[1].tv_sec = modTime; times[0].tv_usec = times[1].tv_usec = 0; if (utimes(localTmpFileName, times) < 0) { ALOGI("Couldn't change modification time on %s: %s\n", localTmpFileName, strerror(errno)); unlink(localTmpFileName); return INSTALL_FAILED_CONTAINER_ERROR; } // Set the mode to 755 static const mode_t mode = S_IRUSR | S_IWUSR | S_IXUSR | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH; if (chmod(localTmpFileName, mode) < 0) { ALOGI("Couldn't change permissions on %s: %s\n", localTmpFileName, strerror(errno)); unlink(localTmpFileName); return INSTALL_FAILED_CONTAINER_ERROR; } // Finally, rename it to the final name. if (rename(localTmpFileName, localFileName) < 0) { ALOGI("Couldn't rename %s to %s: %s\n", localTmpFileName, localFileName, strerror(errno)); unlink(localTmpFileName); return INSTALL_FAILED_CONTAINER_ERROR; } ALOGV("Successfully moved %s to %s\n", localTmpFileName, localFileName); return INSTALL_SUCCEEDED; }