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 "random_access_file.h"
23
24 namespace OHOS {
25 namespace SignatureTools {
26 int32_t RandomAccessFile::memoryPageSize = sysconf(_SC_PAGESIZE);
27
RandomAccessFile()28 RandomAccessFile::RandomAccessFile()
29 : fd(-1), fileLength(0)
30 {
31 }
32
~RandomAccessFile()33 RandomAccessFile::~RandomAccessFile()
34 {
35 if (fd != -1) {
36 close(fd);
37 }
38 }
39
Init(const std::string & filePath)40 bool RandomAccessFile::Init(const std::string& filePath)
41 {
42 fd = open(filePath.c_str(), O_RDWR);
43 if (fd == -1) {
44 PrintErrorNumberMsg("IO_ERROR", IO_ERROR, "open file: " + filePath + " failed");
45 return false;
46 }
47
48 if (memoryPageSize <= 0) {
49 PrintErrorNumberMsg("IO_ERROR", IO_ERROR,
50 "getting pagesize failed. memoryPageSize: " + std::to_string(memoryPageSize));
51 return false;
52 }
53
54 struct stat file_stat;
55 if (fstat(fd, &file_stat) == -1) {
56 PrintErrorNumberMsg("IO_ERROR", IO_ERROR,
57 filePath + "get status failed");
58 return false;
59 }
60 fileLength = file_stat.st_size;
61
62 return true;
63 }
64
GetLength() const65 int64_t RandomAccessFile::GetLength() const
66 {
67 return fileLength;
68 }
69
CheckLittleEndian()70 bool RandomAccessFile::CheckLittleEndian()
71 {
72 union LittleEndian {
73 int32_t number;
74 char ch;
75 } t;
76 t.number = 1;
77 return (t.ch == 1);
78 }
79
DoMMap(int32_t bufCapacity,int64_t offset,MmapInfo & mmapInfo)80 int32_t RandomAccessFile::DoMMap(int32_t bufCapacity, int64_t offset, MmapInfo& mmapInfo)
81 {
82 if (!CheckLittleEndian()) {
83 SIGNATURE_TOOLS_LOGE("CheckLittleEndian: failed");
84 return MMAP_FAILED;
85 }
86
87 // Starting address for memory mapping
88 mmapInfo.mapAddr = reinterpret_cast<char*>(MAP_FAILED);
89 if (fd == -1) {
90 SIGNATURE_TOOLS_LOGE("random access file's fd is -1, the file is closed");
91 return FILE_IS_CLOSE;
92 }
93 if (offset < 0 || offset > fileLength - bufCapacity) {
94 SIGNATURE_TOOLS_LOGE("offset is less than 0 OR read offset is out of range. offset: %" PRId64
95 ", range: %" PRId64, offset, fileLength - bufCapacity);
96 return READ_OFFSET_OUT_OF_RANGE;
97 }
98 // Memory mapped file offset, 0 OR an integer multiple of 4K
99 mmapInfo.mmapPosition = (offset / memoryPageSize) * memoryPageSize;
100 // How many more bytes can be read from the current mapped memory page to find
101 mmapInfo.readMoreLen = static_cast<int>(offset - mmapInfo.mmapPosition);
102 mmapInfo.mmapSize = bufCapacity + mmapInfo.readMoreLen;
103 mmapInfo.mapAddr = reinterpret_cast<char*>(mmap(nullptr, mmapInfo.mmapSize, PROT_READ | PROT_WRITE,
104 MAP_SHARED | MAP_POPULATE, fd, mmapInfo.mmapPosition));
105 if (mmapInfo.mapAddr == MAP_FAILED) {
106 SIGNATURE_TOOLS_LOGE("mmap failed");
107 return MMAP_FAILED;
108 }
109 return 0;
110 }
111
ReadFileFullyFromOffset(char buf[],int64_t offset,int64_t bufCapacity)112 int32_t RandomAccessFile::ReadFileFullyFromOffset(char buf[], int64_t offset, int64_t bufCapacity)
113 {
114 if (buf == nullptr) {
115 SIGNATURE_TOOLS_LOGE("The dest buffer is null");
116 return DEST_BUFFER_IS_NULL;
117 }
118
119 MmapInfo mmapInfo;
120 int32_t ret = DoMMap(bufCapacity, offset, mmapInfo);
121 if (ret < 0) {
122 return ret;
123 }
124
125 if (memcpy_s(buf, bufCapacity, mmapInfo.mapAddr + mmapInfo.readMoreLen,
126 mmapInfo.mmapSize - mmapInfo.readMoreLen) != EOK) {
127 munmap(mmapInfo.mapAddr, mmapInfo.mmapSize);
128 SIGNATURE_TOOLS_LOGE("memcpy_s error, errno: %d", IO_ERROR);
129 return MMAP_COPY_FAILED;
130 }
131 munmap(mmapInfo.mapAddr, mmapInfo.mmapSize);
132 return bufCapacity;
133 }
134
ReadFileFullyFromOffset(ByteBuffer & buffer,int64_t offset)135 int32_t RandomAccessFile::ReadFileFullyFromOffset(ByteBuffer& buffer, int64_t offset)
136 {
137 if (!buffer.HasRemaining()) {
138 SIGNATURE_TOOLS_LOGE("The dest buffer has not remaining");
139 return DEST_BUFFER_IS_NULL;
140 }
141
142 MmapInfo mmapInfo;
143 int32_t bufCapacity = buffer.GetCapacity();
144 int64_t ret = DoMMap(bufCapacity, offset, mmapInfo);
145 if (ret < 0) {
146 return ret;
147 }
148
149 buffer.PutData(0, mmapInfo.mapAddr + mmapInfo.readMoreLen, bufCapacity);
150 munmap(mmapInfo.mapAddr, mmapInfo.mmapSize);
151 return bufCapacity;
152 }
153
WriteToFile(ByteBuffer & buffer,int64_t position,int64_t length)154 int32_t RandomAccessFile::WriteToFile(ByteBuffer& buffer, int64_t position, int64_t length)
155 {
156 // write file, file length may change
157 int64_t remainLength = fileLength - position;
158 fileLength = (length <= remainLength) ? fileLength : (fileLength + (length - remainLength));
159 // update file length
160 if (ftruncate(fd, fileLength) == -1) {
161 SIGNATURE_TOOLS_LOGE("RandomAccessFile ftruncate error: %s", strerror(errno));
162 return IO_ERROR;
163 }
164
165 int32_t bufCapacity = buffer.GetCapacity();
166 if (bufCapacity == 0) {
167 SIGNATURE_TOOLS_LOGE("The dest buffer capacity is 0");
168 return DEST_BUFFER_IS_NULL;
169 }
170
171 MmapInfo mmapInfo;
172
173 int32_t ret = DoMMap(bufCapacity, position, mmapInfo);
174 if (ret < 0) {
175 SIGNATURE_TOOLS_LOGE("DoMMap failed: %d", ret);
176 return ret;
177 }
178
179 if (memcpy_s(mmapInfo.mapAddr + mmapInfo.readMoreLen,
180 mmapInfo.mmapSize - mmapInfo.readMoreLen,
181 buffer.GetBufferPtr(), bufCapacity) != RET_OK) {
182 SIGNATURE_TOOLS_LOGE("memcpy_s error, errno: %d", IO_ERROR);
183 return MMAP_COPY_FAILED;
184 }
185 munmap(mmapInfo.mapAddr, mmapInfo.mmapSize);
186 return bufCapacity;
187 }
188
ReadFileFromOffsetAndDigestUpdate(const DigestParameter & digestParam,int32_t chunkSize,int64_t offset)189 bool RandomAccessFile::ReadFileFromOffsetAndDigestUpdate(const DigestParameter& digestParam,
190 int32_t chunkSize, int64_t offset)
191 {
192 MmapInfo mmapInfo;
193 int32_t ret = DoMMap(chunkSize, offset, mmapInfo);
194 if (ret < 0) {
195 SIGNATURE_TOOLS_LOGE("DoMMap failed: %d", ret);
196 return false;
197 }
198 unsigned char* content = reinterpret_cast<unsigned char*>(mmapInfo.mapAddr + mmapInfo.readMoreLen);
199 bool res = DigestCommon::DigestUpdate(digestParam, content, chunkSize);
200 munmap(mmapInfo.mapAddr, mmapInfo.mmapSize);
201 return res;
202 }
203 }
204 }