static int _loki_write_android_header(MbBiWriter *biw, MbFile *file, const AndroidHeader *ahdr) { AndroidHeader dup = *ahdr; size_t n; int ret; android_fix_header_byte_order(&dup); ret = mb_file_seek(file, 0, SEEK_SET, nullptr); if (ret != MB_FILE_OK) { mb_bi_writer_set_error(biw, mb_file_error(file), "Failed to seek to beginning: %s", mb_file_error_string(file)); return ret == MB_FILE_FATAL ? MB_BI_FATAL : MB_BI_FAILED; } ret = mb_file_write_fully(file, &dup, sizeof(dup), &n); if (ret != MB_FILE_OK) { mb_bi_writer_set_error(biw, mb_file_error(file), "Failed to write Android header: %s", mb_file_error_string(file)); return ret == MB_FILE_FATAL ? MB_BI_FATAL : MB_BI_FAILED; } else if (n != sizeof(dup)) { mb_bi_writer_set_error(biw, MB_BI_ERROR_FILE_FORMAT, "Unexpected EOF when writing Android header: %s", mb_file_error_string(file)); return MB_BI_FAILED; } return MB_BI_OK; }
oc::result<void> MtkFormatWriter::close(File &file) { auto reset_state = finally([&] { m_hdr = {}; m_seg = {}; }); if (m_writer.is_open()) { auto swentry = m_seg->entry(); // If successful, finish up the boot image if (swentry == m_seg->entries().end()) { auto file_size = file.seek(0, SEEK_CUR); if (!file_size) { if (file.is_fatal()) { m_writer.set_fatal(); } return file_size.as_failure(); } // Truncate to set size auto truncate_ret = file.truncate(file_size.value()); if (!truncate_ret) { if (file.is_fatal()) { m_writer.set_fatal(); } return truncate_ret.as_failure(); } // Update MTK header sizes for (auto const &entry : m_seg->entries()) { if (entry.type == ENTRY_TYPE_MTK_KERNEL_HEADER) { OUTCOME_TRYV(_mtk_header_update_size( m_writer, file, entry.offset, static_cast<uint32_t>( m_hdr.kernel_size - sizeof(MtkHeader)))); } else if (entry.type == ENTRY_TYPE_MTK_RAMDISK_HEADER) { OUTCOME_TRYV(_mtk_header_update_size( m_writer, file, entry.offset, static_cast<uint32_t>( m_hdr.ramdisk_size - sizeof(MtkHeader)))); } } // We need to take the performance hit and compute the SHA1 here. // We can't fill in the sizes in the MTK headers when we're writing // them. Thus, if we calculated the SHA1sum during write, it would // be incorrect. OUTCOME_TRYV(_mtk_compute_sha1( m_writer, *m_seg, file, reinterpret_cast<unsigned char *>(m_hdr.id))); // Convert fields back to little-endian android_fix_header_byte_order(m_hdr); // Seek back to beginning to write header auto seek_ret = file.seek(0, SEEK_SET); if (!seek_ret) { if (file.is_fatal()) { m_writer.set_fatal(); } return seek_ret.as_failure(); } // Write header auto ret = file_write_exact(file, &m_hdr, sizeof(m_hdr)); if (!ret) { if (file.is_fatal()) { m_writer.set_fatal(); } return ret.as_failure(); } } } return oc::success(); }
MB_BEGIN_C_DECLS /*! * \brief Find and read Android boot image header * * \note The integral fields in the header will be converted to the host's byte * order. * * \pre The file position can be at any offset prior to calling this function. * * \post The file pointer position is undefined after this function returns. * Use mb_file_seek() to return to a known position. * * \param[in] bir MbBiReader for setting error messages * \param[in] file MbFile handle * \param[in] max_header_offset Maximum offset that a header can start (must be * less than #ANDROID_MAX_HEADER_OFFSET) * \param[out] header_out Pointer to store header * \param[out] offset_out Pointer to store header offset * * \return * * #MB_BI_OK if the header is found * * #MB_BI_WARN if the header is not found * * #MB_BI_FAILED if any file operation fails non-fatally * * #MB_BI_FATAL if any file operation fails fatally */ int find_android_header(MbBiReader *bir, MbFile *file, uint64_t max_header_offset, AndroidHeader *header_out, uint64_t *offset_out) { unsigned char buf[ANDROID_MAX_HEADER_OFFSET + sizeof(AndroidHeader)]; size_t n; int ret; void *ptr; size_t offset; if (max_header_offset > ANDROID_MAX_HEADER_OFFSET) { mb_bi_reader_set_error(bir, MB_BI_ERROR_INVALID_ARGUMENT, "Max header offset (%" PRIu64 ") must be less than %d", max_header_offset, ANDROID_MAX_HEADER_OFFSET); return MB_BI_WARN; } ret = mb_file_seek(file, 0, SEEK_SET, nullptr); if (ret != MB_FILE_OK) { mb_bi_reader_set_error(bir, mb_file_error(file), "Failed to seek to beginning: %s", mb_file_error_string(file)); return ret == MB_FILE_FATAL ? MB_BI_FATAL : MB_BI_FAILED; } ret = mb_file_read_fully( file, buf, max_header_offset + sizeof(AndroidHeader), &n); if (ret != MB_FILE_OK) { mb_bi_reader_set_error(bir, mb_file_error(file), "Failed to read header: %s", mb_file_error_string(file)); return ret == MB_FILE_FATAL ? MB_BI_FATAL : MB_BI_FAILED; } ptr = mb_memmem(buf, n, ANDROID_BOOT_MAGIC, ANDROID_BOOT_MAGIC_SIZE); if (!ptr) { mb_bi_reader_set_error(bir, MB_BI_ERROR_FILE_FORMAT, "Android magic not found in first %d bytes", ANDROID_MAX_HEADER_OFFSET); return MB_BI_WARN; } offset = static_cast<unsigned char *>(ptr) - buf; if (n - offset < sizeof(AndroidHeader)) { mb_bi_reader_set_error(bir, MB_BI_ERROR_FILE_FORMAT, "Android header at %" MB_PRIzu " exceeds file size", offset); return MB_BI_WARN; } // Copy header memcpy(header_out, ptr, sizeof(AndroidHeader)); android_fix_header_byte_order(header_out); *offset_out = offset; return MB_BI_OK; }