1 /*
2  * Copyright (c) 2021 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 #include "shared_block.h"
16 #include <ashmem.h>
17 #include <fcntl.h>
18 #include <securec.h>
19 #include <sys/mman.h>
20 #include <unistd.h>
21 
22 #include <codecvt>
23 #include <iostream>
24 
25 #include "string_ex.h"
26 #include "datashare_log.h"
27 
28 namespace OHOS {
29 namespace AppDataFwk {
30 using namespace OHOS::DataShare;
SharedBlock(const std::string & name,sptr<Ashmem> ashmem,size_t size,bool readOnly)31 SharedBlock::SharedBlock(const std::string &name, sptr<Ashmem> ashmem, size_t size, bool readOnly)
32     : mName(name), ashmem_(ashmem), mSize(size), mReadOnly(readOnly), mHeader(nullptr)
33 {
34 }
35 
~SharedBlock()36 SharedBlock::~SharedBlock()
37 {
38     if (ashmem_ != nullptr) {
39         ashmem_->UnmapAshmem();
40         ashmem_->CloseAshmem();
41         ashmem_ = nullptr;
42         LOG_DEBUG("SharedBlock: close ashmem");
43     }
44 }
45 
ToUtf16(const std::string & str)46 std::u16string SharedBlock::ToUtf16(const std::string& str)
47 {
48     return OHOS::Str8ToStr16(str);
49 }
50 
ToUtf8(const std::u16string & str16)51 std::string SharedBlock::ToUtf8(const std::u16string& str16)
52 {
53     return OHOS::Str16ToStr8(str16);
54 }
55 
Init()56 bool SharedBlock::Init()
57 {
58     mData = const_cast<void *>(ashmem_->ReadFromAshmem(sizeof(SharedBlockHeader), 0));
59     mHeader = static_cast<SharedBlockHeader *>(mData);
60     if (mHeader == nullptr) {
61         return false;
62     }
63     return true;
64 }
65 
CreateSharedBlock(const std::string & name,size_t size,sptr<Ashmem> ashmem,SharedBlock * & outSharedBlock)66 int SharedBlock::CreateSharedBlock(const std::string &name, size_t size, sptr<Ashmem> ashmem,
67     SharedBlock *&outSharedBlock)
68 {
69     outSharedBlock = new SharedBlock(name, ashmem, size, false);
70     if (outSharedBlock == nullptr) {
71         LOG_ERROR("CreateSharedBlock: new SharedBlock error.");
72         return SHARED_BLOCK_BAD_VALUE;
73     }
74 
75     if (!outSharedBlock->Init()) {
76         delete outSharedBlock;
77         outSharedBlock = nullptr;
78         LOG_ERROR("CreateSharedBlock: mHeader is null.");
79         return SHARED_BLOCK_ASHMEM_ERROR;
80     }
81     return SHARED_BLOCK_OK;
82 }
83 
Create(const std::string & name,size_t size,SharedBlock * & outSharedBlock)84 int SharedBlock::Create(const std::string &name, size_t size, SharedBlock *&outSharedBlock)
85 {
86     std::string ashmemName = "SharedBlock:" + name;
87 
88     sptr<Ashmem> ashmem = Ashmem::CreateAshmem(ashmemName.c_str(), size);
89     if (ashmem == nullptr) {
90         LOG_ERROR("SharedBlock: CreateAshmem function error.");
91         return SHARED_BLOCK_ASHMEM_ERROR;
92     }
93 
94     bool ret = ashmem->MapReadAndWriteAshmem();
95     if (!ret) {
96         LOG_ERROR("SharedBlock: MapReadAndWriteAshmem function error.");
97         ashmem->CloseAshmem();
98         return SHARED_BLOCK_SET_PORT_ERROR;
99     }
100 
101     int result = CreateSharedBlock(name, size, ashmem, outSharedBlock);
102     if (result == SHARED_BLOCK_OK) {
103         return SHARED_BLOCK_OK;
104     }
105     ashmem->UnmapAshmem();
106     ashmem->CloseAshmem();
107     outSharedBlock = nullptr;
108     return result;
109 }
110 
WriteMessageParcel(MessageParcel & parcel)111 int SharedBlock::WriteMessageParcel(MessageParcel &parcel)
112 {
113     return parcel.WriteString16(ToUtf16(mName)) && parcel.WriteAshmem(ashmem_);
114 }
115 
ReadMessageParcel(MessageParcel & parcel,SharedBlock * & block)116 int SharedBlock::ReadMessageParcel(MessageParcel &parcel, SharedBlock *&block)
117 {
118     std::string name = ToUtf8(parcel.ReadString16());
119     sptr<Ashmem> ashmem = parcel.ReadAshmem();
120     if (ashmem == nullptr) {
121         LOG_ERROR("ReadMessageParcel: No ashmem in the parcel.");
122         return SHARED_BLOCK_BAD_VALUE;
123     }
124     bool ret = ashmem->MapReadAndWriteAshmem();
125     if (!ret) {
126         LOG_ERROR("ReadMessageParcel: MapReadAndWriteAshmem function error.");
127         ashmem->CloseAshmem();
128         return SHARED_BLOCK_SET_PORT_ERROR;
129     }
130     block = new (std::nothrow) SharedBlock(name, ashmem, ashmem->GetAshmemSize(), true);
131     if (block == nullptr) {
132         LOG_ERROR("ReadMessageParcel new SharedBlock error.");
133         return SHARED_BLOCK_BAD_VALUE;
134     }
135     if (!block->Init()) {
136         delete block;
137         block = nullptr;
138         LOG_ERROR("ReadMessageParcel: mHeader is null.");
139         return SHARED_BLOCK_ASHMEM_ERROR;
140     }
141 
142     LOG_DEBUG("Created SharedBlock from parcel: unusedOffset=%{private}" PRIu32 ", "
143               "rowNums=%{private}" PRIu32 ", columnNums=%{private}" PRIu32 ", mSize=%{private}d",
144               block->mHeader->unusedOffset, block->mHeader->rowNums, block->mHeader->columnNums,
145               static_cast<int>(block->mSize));
146 
147     return SHARED_BLOCK_OK;
148 }
149 
Clear()150 int SharedBlock::Clear()
151 {
152     if (mReadOnly) {
153         return SHARED_BLOCK_INVALID_OPERATION;
154     }
155 
156     mHeader->unusedOffset = sizeof(SharedBlockHeader) + sizeof(RowGroupHeader);
157     mHeader->firstRowGroupOffset = sizeof(SharedBlockHeader);
158     mHeader->rowNums = 0;
159     mHeader->columnNums = 0;
160     mHeader->startPos_ = 0;
161     mHeader->lastPos_ = 0;
162     mHeader->blockPos_ = 0;
163 
164     RowGroupHeader *firstGroup = static_cast<RowGroupHeader *>(OffsetToPtr(mHeader->firstRowGroupOffset));
165     if (!firstGroup) {
166         LOG_ERROR("Failed to get group in clear().");
167         return SHARED_BLOCK_BAD_VALUE;
168     }
169     firstGroup->nextGroupOffset = 0;
170     return SHARED_BLOCK_OK;
171 }
172 
SetColumnNum(uint32_t numColumns)173 int SharedBlock::SetColumnNum(uint32_t numColumns)
174 {
175     if (mReadOnly) {
176         return SHARED_BLOCK_INVALID_OPERATION;
177     }
178 
179     uint32_t cur = mHeader->columnNums;
180     if ((cur > 0 || mHeader->rowNums > 0) && cur != numColumns) {
181         LOG_ERROR("Trying to go from %{public}" PRIu32 " columns to %{public}" PRIu32 "", cur, numColumns);
182         return SHARED_BLOCK_INVALID_OPERATION;
183     }
184     if (numColumns > COL_MAX_NUM) {
185         LOG_ERROR("Trying to set %{public}" PRIu32 " columns out of size", numColumns);
186         return SHARED_BLOCK_INVALID_OPERATION;
187     }
188     mHeader->columnNums = numColumns;
189     return SHARED_BLOCK_OK;
190 }
191 
AllocRow()192 int SharedBlock::AllocRow()
193 {
194     if (mReadOnly) {
195         return SHARED_BLOCK_INVALID_OPERATION;
196     }
197 
198     uint32_t *rowOffset = AllocRowOffset();
199     if (rowOffset == nullptr) {
200         return SHARED_BLOCK_NO_MEMORY;
201     }
202 
203     /* Allocate the units for the field directory */
204     size_t fieldDirSize = mHeader->columnNums * sizeof(CellUnit);
205 
206     /* Aligned */
207     uint32_t fieldDirOffset = Alloc(fieldDirSize, true);
208     if (!fieldDirOffset) {
209         mHeader->rowNums--;
210         LOG_INFO("Alloc the row failed, so back out the new row accounting from allocRowoffset %{public}" PRIu32 "",
211             mHeader->rowNums);
212         return SHARED_BLOCK_NO_MEMORY;
213     }
214 
215     CellUnit *fieldDir = static_cast<CellUnit *>(OffsetToPtr(fieldDirOffset));
216     if (fieldDir == nullptr) {
217         return SHARED_BLOCK_BAD_VALUE;
218     }
219     int result = memset_s(fieldDir, fieldDirSize, 0, fieldDirSize);
220     if (result != 0) {
221         LOG_ERROR("Set memory failed");
222         return SHARED_BLOCK_NO_MEMORY;
223     }
224 
225     *rowOffset = fieldDirOffset;
226     return SHARED_BLOCK_OK;
227 }
228 
FreeLastRow()229 int SharedBlock::FreeLastRow()
230 {
231     if (mReadOnly) {
232         return SHARED_BLOCK_INVALID_OPERATION;
233     }
234 
235     if (mHeader->rowNums > 0) {
236         mHeader->rowNums--;
237     }
238 
239     return SHARED_BLOCK_OK;
240 }
241 
Alloc(size_t size,bool aligned)242 uint32_t SharedBlock::Alloc(size_t size, bool aligned)
243 {
244     /* Number of unused offsets in the header */
245     uint32_t offsetDigit = 3;
246     uint32_t padding = aligned ? (~mHeader->unusedOffset + 1) & offsetDigit : 0;
247     uint32_t offset = mHeader->unusedOffset + padding;
248     uint32_t nextFreeOffset;
249 
250     if (offset + size > mSize) {
251         LOG_ERROR("SharedBlock is full: requested allocation %{public}zu bytes,"
252             " free space %{public}zu bytes, block size %{public}zu bytes",
253             size, mSize - mHeader->unusedOffset, mSize);
254         return 0;
255     }
256     nextFreeOffset = offset + size;
257     mHeader->unusedOffset = nextFreeOffset;
258     return offset;
259 }
260 
GetRowOffset(uint32_t row)261 inline uint32_t *SharedBlock::GetRowOffset(uint32_t row)
262 {
263     uint32_t rowPos = row;
264 
265     RowGroupHeader *group = static_cast<RowGroupHeader *>(OffsetToPtr(mHeader->firstRowGroupOffset));
266     if (group == nullptr) {
267         LOG_ERROR("Failed to get group in getRowOffset().");
268         return nullptr;
269     }
270 
271     while (rowPos >= ROW_OFFSETS_NUM) {
272         group = static_cast<RowGroupHeader *>(OffsetToPtr(group->nextGroupOffset));
273         if (group == nullptr) {
274             LOG_ERROR("Failed to get group in OffsetToPtr(group->nextGroupOffset) when while loop.");
275             return nullptr;
276         }
277         rowPos -= ROW_OFFSETS_NUM;
278     }
279 
280     return &group->rowOffsets[rowPos];
281 }
282 
AllocRowOffset()283 uint32_t *SharedBlock::AllocRowOffset()
284 {
285     uint32_t rowPos = mHeader->rowNums;
286 
287     RowGroupHeader *group = static_cast<RowGroupHeader *>(OffsetToPtr(mHeader->firstRowGroupOffset));
288     if (group == nullptr) {
289         LOG_ERROR("Failed to get group in allocRowOffset().");
290         return nullptr;
291     }
292 
293     while (rowPos > ROW_OFFSETS_NUM) {
294         group = static_cast<RowGroupHeader *>(OffsetToPtr(group->nextGroupOffset));
295         if (group == nullptr) {
296             LOG_ERROR("Failed to get group in OffsetToPtr(group->nextGroupOffset) when while loop.");
297             return nullptr;
298         }
299         rowPos -= ROW_OFFSETS_NUM;
300     }
301     if (rowPos == ROW_OFFSETS_NUM) {
302         if (!group->nextGroupOffset) {
303             /* Aligned */
304             group->nextGroupOffset = Alloc(sizeof(RowGroupHeader), true);
305             if (!group->nextGroupOffset) {
306                 return nullptr;
307             }
308         }
309         group = static_cast<RowGroupHeader *>(OffsetToPtr(group->nextGroupOffset));
310         if (group == nullptr) {
311             LOG_ERROR("Failed to get group in OffsetToPtr(group->nextGroupOffset).");
312             return nullptr;
313         }
314         group->nextGroupOffset = 0;
315         rowPos = 0;
316     }
317 
318     mHeader->rowNums += 1;
319     return &group->rowOffsets[rowPos];
320 }
321 
GetCellUnit(uint32_t row,uint32_t column)322 SharedBlock::CellUnit *SharedBlock::GetCellUnit(uint32_t row, uint32_t column)
323 {
324     if (row >= mHeader->rowNums || column >= mHeader->columnNums) {
325         LOG_ERROR("Failed to read row %{public}" PRIu32 ", column %{public}" PRIu32 " from a SharedBlock"
326             " which has %{public}" PRIu32 " rows, %{public}" PRIu32 " columns.",
327             row, column, mHeader->rowNums, mHeader->columnNums);
328         return nullptr;
329     }
330 
331     uint32_t *rowOffset = GetRowOffset(row);
332     if (!rowOffset) {
333         LOG_ERROR("Failed to find rowOffset for row %{public}" PRIu32 ".", row);
334         return nullptr;
335     }
336 
337     CellUnit *cellUnit = static_cast<CellUnit *>(OffsetToPtr(*rowOffset));
338     if (!cellUnit) {
339         LOG_ERROR("Failed to find cellUnit for rowOffset %{public}" PRIu32 ".", *rowOffset);
340         return nullptr;
341     }
342 
343     return &cellUnit[column];
344 }
345 
PutBlob(uint32_t row,uint32_t column,const void * value,size_t size)346 int SharedBlock::PutBlob(uint32_t row, uint32_t column, const void *value, size_t size)
347 {
348     return PutBlobOrString(row, column, value, size, CELL_UNIT_TYPE_BLOB);
349 }
350 
PutString(uint32_t row,uint32_t column,const char * value,size_t sizeIncludingNull)351 int SharedBlock::PutString(uint32_t row, uint32_t column, const char *value, size_t sizeIncludingNull)
352 {
353     return PutBlobOrString(row, column, value, sizeIncludingNull, CELL_UNIT_TYPE_STRING);
354 }
355 
PutBlobOrString(uint32_t row,uint32_t column,const void * value,size_t size,int32_t type)356 int SharedBlock::PutBlobOrString(uint32_t row, uint32_t column, const void *value, size_t size, int32_t type)
357 {
358     if (mReadOnly) {
359         return SHARED_BLOCK_INVALID_OPERATION;
360     }
361 
362     CellUnit *cellUnit = GetCellUnit(row, column);
363     if (!cellUnit) {
364         return SHARED_BLOCK_BAD_VALUE;
365     }
366 
367     uint32_t offset = Alloc(size);
368     if (!offset) {
369         return SHARED_BLOCK_NO_MEMORY;
370     }
371 
372     void *ptr = OffsetToPtr(offset);
373     if (!ptr) {
374         return SHARED_BLOCK_NO_MEMORY;
375     }
376 
377     if (size != 0) {
378         errno_t result = memcpy_s(ptr, size, value, size);
379         if (result != EOK) {
380             return SHARED_BLOCK_NO_MEMORY;
381         }
382     }
383 
384     cellUnit->type = type;
385     cellUnit->cell.stringOrBlobValue.offset = offset;
386     cellUnit->cell.stringOrBlobValue.size = size;
387     return SHARED_BLOCK_OK;
388 }
389 
PutLong(uint32_t row,uint32_t column,int64_t value)390 int SharedBlock::PutLong(uint32_t row, uint32_t column, int64_t value)
391 {
392     if (mReadOnly) {
393         return SHARED_BLOCK_INVALID_OPERATION;
394     }
395 
396     CellUnit *cellUnit = GetCellUnit(row, column);
397     if (!cellUnit) {
398         return SHARED_BLOCK_BAD_VALUE;
399     }
400 
401     cellUnit->type = CELL_UNIT_TYPE_INTEGER;
402     cellUnit->cell.longValue = value;
403     return SHARED_BLOCK_OK;
404 }
405 
PutDouble(uint32_t row,uint32_t column,double value)406 int SharedBlock::PutDouble(uint32_t row, uint32_t column, double value)
407 {
408     if (mReadOnly) {
409         return SHARED_BLOCK_INVALID_OPERATION;
410     }
411 
412     CellUnit *cellUnit = GetCellUnit(row, column);
413     if (!cellUnit) {
414         return SHARED_BLOCK_BAD_VALUE;
415     }
416 
417     cellUnit->type = CELL_UNIT_TYPE_FLOAT;
418     cellUnit->cell.doubleValue = value;
419     return SHARED_BLOCK_OK;
420 }
421 
PutNull(uint32_t row,uint32_t column)422 int SharedBlock::PutNull(uint32_t row, uint32_t column)
423 {
424     if (mReadOnly) {
425         return SHARED_BLOCK_INVALID_OPERATION;
426     }
427 
428     CellUnit *cellUnit = GetCellUnit(row, column);
429     if (!cellUnit) {
430         return SHARED_BLOCK_BAD_VALUE;
431     }
432 
433     cellUnit->type = CELL_UNIT_TYPE_NULL;
434     cellUnit->cell.stringOrBlobValue.offset = 0;
435     cellUnit->cell.stringOrBlobValue.size = 0;
436     return SHARED_BLOCK_OK;
437 }
438 
SetRawData(const void * rawData,size_t size)439 size_t SharedBlock::SetRawData(const void *rawData, size_t size)
440 {
441     if (size <= 0) {
442         LOG_ERROR("SharedBlock rawData is less than or equal to 0M");
443         return SHARED_BLOCK_INVALID_OPERATION;
444     }
445     if (size > mSize) {
446         LOG_ERROR("SharedBlock size is %{public}zu, current byteArray size is %{public}zu", mSize, size);
447         return SHARED_BLOCK_NO_MEMORY;
448     }
449 
450     int result = memcpy_s(mHeader, mSize, rawData, size);
451     if (result != 0) {
452         return SHARED_BLOCK_NO_MEMORY;
453     }
454     return SHARED_BLOCK_OK;
455 }
456 
OffsetFromPtr(void * ptr)457 uint32_t SharedBlock::OffsetFromPtr(void *ptr)
458 {
459     return static_cast<uint8_t *>(ptr) - static_cast<uint8_t *>(mData);
460 }
461 } // namespace AppDataFwk
462 } // namespace OHOS
463