1/* 2 * Copyright (c) 2024-2024 Huawei Device Co., Ltd. 3 * Licensed under the Apache License, Version 2.0 (the "License"); 4 * you may not use this file except in compliance with the License. 5 * You may obtain a copy of the License at 6 * 7 * http://www.apache.org/licenses/LICENSE-2.0 8 * 9 * Unless required by applicable law or agreed to in writing, software 10 * distributed under the License is distributed on an "AS IS" BASIS, 11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 * See the License for the specific language governing permissions and 13 * limitations under the License. 14 */ 15 16#include <cinttypes> 17 18#include "securec.h" 19#include "signature_info.h" 20#include "signature_tools_log.h" 21#include "digest_common.h" 22//#include "verify_hap_openssl_utils.h" 23#include "random_access_file.h" 24 25namespace OHOS { 26namespace SignatureTools { 27int32_t RandomAccessFile::memoryPageSize = sysconf(_SC_PAGESIZE); 28 29RandomAccessFile::RandomAccessFile() 30 : fd(-1), fileLength(0) 31{ 32} 33 34RandomAccessFile::~RandomAccessFile() 35{ 36 if (fd != -1) { 37 close(fd); 38 } 39} 40 41bool RandomAccessFile::Init(const std::string& filePath) 42{ 43 fd = open(filePath.c_str(), O_RDWR); 44 if (fd == -1) { 45 PrintErrorNumberMsg("IO_ERROR", IO_ERROR, "open file: " + filePath + " failed"); 46 return false; 47 } 48 49 if (memoryPageSize <= 0) { 50 PrintErrorNumberMsg("IO_ERROR", IO_ERROR, 51 "getting pagesize failed. memoryPageSize: " + std::to_string(memoryPageSize)); 52 return false; 53 } 54 55 struct stat file_stat; 56 if (fstat(fd, &file_stat) == -1) { 57 PrintErrorNumberMsg("IO_ERROR", IO_ERROR, 58 filePath + "get status failed"); 59 return false; 60 } 61 fileLength = file_stat.st_size; 62 63 return true; 64} 65 66int64_t RandomAccessFile::GetLength() const 67{ 68 return fileLength; 69} 70 71bool RandomAccessFile::CheckLittleEndian() 72{ 73 union LittleEndian { 74 int32_t number; 75 char ch; 76 } t; 77 t.number = 1; 78 return (t.ch == 1); 79} 80 81int32_t RandomAccessFile::DoMMap(int32_t bufCapacity, int64_t offset, MmapInfo& mmapInfo) 82{ 83 if (!CheckLittleEndian()) { 84 SIGNATURE_TOOLS_LOGE("CheckLittleEndian: failed"); 85 return MMAP_FAILED; 86 } 87 88 // Starting address for memory mapping 89 mmapInfo.mapAddr = reinterpret_cast<char*>(MAP_FAILED); 90 if (fd == -1) { 91 SIGNATURE_TOOLS_LOGE("random access file's fd is -1, the file is closed"); 92 return FILE_IS_CLOSE; 93 } 94 if (offset < 0 || offset > fileLength - bufCapacity) { 95 SIGNATURE_TOOLS_LOGE("offset is less than 0 OR read offset is out of range. offset: %" PRId64 96 ", range: %" PRId64, offset, fileLength - bufCapacity); 97 return READ_OFFSET_OUT_OF_RANGE; 98 } 99 // Memory mapped file offset, 0 OR an integer multiple of 4K 100 mmapInfo.mmapPosition = (offset / memoryPageSize) * memoryPageSize; 101 // How many more bytes can be read from the current mapped memory page to find 102 mmapInfo.readMoreLen = static_cast<int>(offset - mmapInfo.mmapPosition); 103 mmapInfo.mmapSize = bufCapacity + mmapInfo.readMoreLen; 104 mmapInfo.mapAddr = reinterpret_cast<char*>(mmap(nullptr, mmapInfo.mmapSize, PROT_READ | PROT_WRITE, 105 MAP_SHARED | MAP_POPULATE, fd, mmapInfo.mmapPosition)); 106 if (mmapInfo.mapAddr == MAP_FAILED) { 107 SIGNATURE_TOOLS_LOGE("mmap failed"); 108 return MMAP_FAILED; 109 } 110 return 0; 111} 112 113int32_t RandomAccessFile::ReadFileFullyFromOffset(char buf[], int64_t offset, int64_t bufCapacity) 114{ 115 if (buf == nullptr) { 116 SIGNATURE_TOOLS_LOGE("The dest buffer is null"); 117 return DEST_BUFFER_IS_NULL; 118 } 119 120 MmapInfo mmapInfo; 121 int32_t ret = DoMMap(bufCapacity, offset, mmapInfo); 122 if (ret < 0) { 123 return ret; 124 } 125 126 if (memcpy_s(buf, bufCapacity, mmapInfo.mapAddr + mmapInfo.readMoreLen, 127 mmapInfo.mmapSize - mmapInfo.readMoreLen) != EOK) { 128 munmap(mmapInfo.mapAddr, mmapInfo.mmapSize); 129 SIGNATURE_TOOLS_LOGE("memcpy_s error, errno: %d", IO_ERROR); 130 return MMAP_COPY_FAILED; 131 } 132 munmap(mmapInfo.mapAddr, mmapInfo.mmapSize); 133 return bufCapacity; 134} 135 136int32_t RandomAccessFile::ReadFileFullyFromOffset(ByteBuffer& buffer, int64_t offset) 137{ 138 if (!buffer.HasRemaining()) { 139 SIGNATURE_TOOLS_LOGE("The dest buffer has not remaining"); 140 return DEST_BUFFER_IS_NULL; 141 } 142 143 MmapInfo mmapInfo; 144 int32_t bufCapacity = buffer.GetCapacity(); 145 int64_t ret = DoMMap(bufCapacity, offset, mmapInfo); 146 if (ret < 0) { 147 return ret; 148 } 149 150 buffer.PutData(0, mmapInfo.mapAddr + mmapInfo.readMoreLen, bufCapacity); 151 munmap(mmapInfo.mapAddr, mmapInfo.mmapSize); 152 return bufCapacity; 153} 154 155int32_t RandomAccessFile::WriteToFile(ByteBuffer& buffer, int64_t position, int64_t length) 156{ 157 // write file, file length may change 158 int64_t remainLength = fileLength - position; 159 fileLength = (length <= remainLength) ? fileLength : (fileLength + (length - remainLength)); 160 // update file length 161 if (ftruncate(fd, fileLength) == -1) { 162 SIGNATURE_TOOLS_LOGE("RandomAccessFile ftruncate error: %s", strerror(errno)); 163 return IO_ERROR; 164 } 165 166 int32_t bufCapacity = buffer.GetCapacity(); 167 if (bufCapacity == 0) { 168 SIGNATURE_TOOLS_LOGE("The dest buffer capacity is 0"); 169 return DEST_BUFFER_IS_NULL; 170 } 171 172 MmapInfo mmapInfo; 173 174 int32_t ret = DoMMap(bufCapacity, position, mmapInfo); 175 if (ret < 0) { 176 SIGNATURE_TOOLS_LOGE("DoMMap failed: %d", ret); 177 return ret; 178 } 179 180 if (memcpy_s(mmapInfo.mapAddr + mmapInfo.readMoreLen, 181 mmapInfo.mmapSize - mmapInfo.readMoreLen, 182 buffer.GetBufferPtr(), bufCapacity) != RET_OK) { 183 SIGNATURE_TOOLS_LOGE("memcpy_s error, errno: %d", IO_ERROR); 184 return MMAP_COPY_FAILED; 185 } 186 munmap(mmapInfo.mapAddr, mmapInfo.mmapSize); 187 return bufCapacity; 188} 189 190bool RandomAccessFile::ReadFileFromOffsetAndDigestUpdate(const DigestParameter& digestParam, 191 int32_t chunkSize, int64_t offset) 192{ 193 MmapInfo mmapInfo; 194 int32_t ret = DoMMap(chunkSize, offset, mmapInfo); 195 if (ret < 0) { 196 SIGNATURE_TOOLS_LOGE("DoMMap failed: %d", ret); 197 return false; 198 } 199 unsigned char* content = reinterpret_cast<unsigned char*>(mmapInfo.mapAddr + mmapInfo.readMoreLen); 200 bool res = DigestCommon::DigestUpdate(digestParam, content, chunkSize); 201 munmap(mmapInfo.mapAddr, mmapInfo.mmapSize); 202 return res; 203} 204} 205}