1fb299fa2Sopenharmony_ci/*
2fb299fa2Sopenharmony_ci * Copyright (c) 2021 Huawei Device Co., Ltd.
3fb299fa2Sopenharmony_ci * Licensed under the Apache License, Version 2.0 (the "License");
4fb299fa2Sopenharmony_ci * you may not use this file except in compliance with the License.
5fb299fa2Sopenharmony_ci * You may obtain a copy of the License at
6fb299fa2Sopenharmony_ci *
7fb299fa2Sopenharmony_ci * http://www.apache.org/licenses/LICENSE-2.0
8fb299fa2Sopenharmony_ci *
9fb299fa2Sopenharmony_ci * Unless required by applicable law or agreed to in writing, software
10fb299fa2Sopenharmony_ci * distributed under the License is distributed on an "AS IS" BASIS,
11fb299fa2Sopenharmony_ci * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12fb299fa2Sopenharmony_ci * See the License for the specific language governing permissions and
13fb299fa2Sopenharmony_ci * limitations under the License.
14fb299fa2Sopenharmony_ci */
15fb299fa2Sopenharmony_ci
16fb299fa2Sopenharmony_ci#include "command_process.h"
17fb299fa2Sopenharmony_ci#include <cstdio>
18fb299fa2Sopenharmony_ci#include <fcntl.h>
19fb299fa2Sopenharmony_ci#include <linux/fs.h>
20fb299fa2Sopenharmony_ci#include <memory>
21fb299fa2Sopenharmony_ci#include <pthread.h>
22fb299fa2Sopenharmony_ci#include <sys/ioctl.h>
23fb299fa2Sopenharmony_ci#include <sys/stat.h>
24fb299fa2Sopenharmony_ci#include <sys/types.h>
25fb299fa2Sopenharmony_ci#include <unistd.h>
26fb299fa2Sopenharmony_ci#include "applypatch/block_set.h"
27fb299fa2Sopenharmony_ci#include "applypatch/block_writer.h"
28fb299fa2Sopenharmony_ci#include "applypatch/data_writer.h"
29fb299fa2Sopenharmony_ci#include "applypatch/store.h"
30fb299fa2Sopenharmony_ci#include "applypatch/transfer_manager.h"
31fb299fa2Sopenharmony_ci#include "log/log.h"
32fb299fa2Sopenharmony_ci#include "securec.h"
33fb299fa2Sopenharmony_ci#include "utils.h"
34fb299fa2Sopenharmony_ci
35fb299fa2Sopenharmony_ciusing namespace Hpackage;
36fb299fa2Sopenharmony_ciusing namespace Updater::Utils;
37fb299fa2Sopenharmony_cinamespace Updater {
38fb299fa2Sopenharmony_ciCommandResult AbortCommandFn::Execute(const Command &params)
39fb299fa2Sopenharmony_ci{
40fb299fa2Sopenharmony_ci    return SUCCESS;
41fb299fa2Sopenharmony_ci}
42fb299fa2Sopenharmony_ci
43fb299fa2Sopenharmony_ciCommandResult NewCommandFn::Execute(const Command &params)
44fb299fa2Sopenharmony_ci{
45fb299fa2Sopenharmony_ci    BlockSet bs;
46fb299fa2Sopenharmony_ci    bs.ParserAndInsert(params.GetArgumentByPos(1));
47fb299fa2Sopenharmony_ci    LOG(INFO) << " writing " << bs.TotalBlockSize() << " blocks of new data";
48fb299fa2Sopenharmony_ci    auto writerThreadInfo = params.GetTransferParams()->writerThreadInfo.get();
49fb299fa2Sopenharmony_ci    pthread_mutex_lock(&writerThreadInfo->mutex);
50fb299fa2Sopenharmony_ci    writerThreadInfo->writer = std::make_unique<BlockWriter>(params.GetFileDescriptor(), bs);
51fb299fa2Sopenharmony_ci    pthread_cond_broadcast(&writerThreadInfo->cond);
52fb299fa2Sopenharmony_ci    while (writerThreadInfo->writer != nullptr) {
53fb299fa2Sopenharmony_ci        LOG(DEBUG) << "wait for new data write done...";
54fb299fa2Sopenharmony_ci        if (!writerThreadInfo->readyToWrite) {
55fb299fa2Sopenharmony_ci            LOG(ERROR) << "writer thread could not write blocks. " << bs.TotalBlockSize() * H_BLOCK_SIZE -
56fb299fa2Sopenharmony_ci                writerThreadInfo->writer->GetTotalWritten() << " bytes lost";
57fb299fa2Sopenharmony_ci            pthread_mutex_unlock(&writerThreadInfo->mutex);
58fb299fa2Sopenharmony_ci            writerThreadInfo->writer.reset();
59fb299fa2Sopenharmony_ci            writerThreadInfo->writer = nullptr;
60fb299fa2Sopenharmony_ci            return FAILED;
61fb299fa2Sopenharmony_ci        }
62fb299fa2Sopenharmony_ci        LOG(DEBUG) << "Writer already written " << writerThreadInfo->writer->GetTotalWritten() << " byte(s)";
63fb299fa2Sopenharmony_ci        pthread_cond_wait(&writerThreadInfo->cond, &writerThreadInfo->mutex);
64fb299fa2Sopenharmony_ci    }
65fb299fa2Sopenharmony_ci    pthread_mutex_unlock(&writerThreadInfo->mutex);
66fb299fa2Sopenharmony_ci
67fb299fa2Sopenharmony_ci    writerThreadInfo->writer.reset();
68fb299fa2Sopenharmony_ci    params.GetTransferParams()->written += bs.TotalBlockSize();
69fb299fa2Sopenharmony_ci    return SUCCESS;
70fb299fa2Sopenharmony_ci}
71fb299fa2Sopenharmony_ci
72fb299fa2Sopenharmony_ciCommandResult ZeroAndEraseCommandFn::Execute(const Command &params)
73fb299fa2Sopenharmony_ci{
74fb299fa2Sopenharmony_ci    bool isErase = false;
75fb299fa2Sopenharmony_ci    if (params.GetCommandType() == CommandType::ERASE) {
76fb299fa2Sopenharmony_ci        isErase = true;
77fb299fa2Sopenharmony_ci        LOG(INFO) << "Start run ERASE command";
78fb299fa2Sopenharmony_ci    }
79fb299fa2Sopenharmony_ci    if (isErase) {
80fb299fa2Sopenharmony_ci        struct stat statBlock {};
81fb299fa2Sopenharmony_ci        if (fstat(params.GetFileDescriptor(), &statBlock) == -1) {
82fb299fa2Sopenharmony_ci            LOG(ERROR) << "Failed to fstat";
83fb299fa2Sopenharmony_ci            return FAILED;
84fb299fa2Sopenharmony_ci        }
85fb299fa2Sopenharmony_ci#ifndef UPDATER_UT
86fb299fa2Sopenharmony_ci        if (!S_ISBLK(statBlock.st_mode)) {
87fb299fa2Sopenharmony_ci            LOG(ERROR) << "Invalid block device";
88fb299fa2Sopenharmony_ci            return FAILED;
89fb299fa2Sopenharmony_ci        }
90fb299fa2Sopenharmony_ci#endif
91fb299fa2Sopenharmony_ci    }
92fb299fa2Sopenharmony_ci
93fb299fa2Sopenharmony_ci    BlockSet blk;
94fb299fa2Sopenharmony_ci    blk.ParserAndInsert(params.GetArgumentByPos(1));
95fb299fa2Sopenharmony_ci    LOG(INFO) << "Parser params to block set";
96fb299fa2Sopenharmony_ci    auto ret = CommandResult(blk.WriteZeroToBlock(params.GetFileDescriptor(), isErase));
97fb299fa2Sopenharmony_ci    if (ret == SUCCESS && !isErase) {
98fb299fa2Sopenharmony_ci        params.GetTransferParams()->written += blk.TotalBlockSize();
99fb299fa2Sopenharmony_ci    }
100fb299fa2Sopenharmony_ci    return ret;
101fb299fa2Sopenharmony_ci}
102fb299fa2Sopenharmony_ci
103fb299fa2Sopenharmony_cibool LoadTarget(const Command &params, size_t &pos, std::vector<uint8_t> &buffer,
104fb299fa2Sopenharmony_ci    BlockSet &targetBlock, CommandResult &result)
105fb299fa2Sopenharmony_ci{
106fb299fa2Sopenharmony_ci    CommandType type = params.GetCommandType();
107fb299fa2Sopenharmony_ci    // Read sha256 of source and target
108fb299fa2Sopenharmony_ci    std::string srcHash = params.GetArgumentByPos(pos++);
109fb299fa2Sopenharmony_ci    std::string tgtHash = srcHash;
110fb299fa2Sopenharmony_ci    if (type != CommandType::MOVE) {
111fb299fa2Sopenharmony_ci        tgtHash = params.GetArgumentByPos(pos++);
112fb299fa2Sopenharmony_ci    }
113fb299fa2Sopenharmony_ci
114fb299fa2Sopenharmony_ci    // Read the target's buffer to determine whether it needs to be written
115fb299fa2Sopenharmony_ci    std::string cmdTmp = params.GetArgumentByPos(pos++);
116fb299fa2Sopenharmony_ci    targetBlock.ParserAndInsert(cmdTmp);
117fb299fa2Sopenharmony_ci    size_t tgtBlockSize = targetBlock.TotalBlockSize() * H_BLOCK_SIZE;
118fb299fa2Sopenharmony_ci    std::vector<uint8_t> tgtBuffer(tgtBlockSize);
119fb299fa2Sopenharmony_ci
120fb299fa2Sopenharmony_ci    if (targetBlock.ReadDataFromBlock(params.GetFileDescriptor(), tgtBuffer) == 0) {
121fb299fa2Sopenharmony_ci        LOG(ERROR) << "Read data from block error, TotalBlockSize: " << targetBlock.TotalBlockSize();
122fb299fa2Sopenharmony_ci        result = FAILED;
123fb299fa2Sopenharmony_ci        return false;
124fb299fa2Sopenharmony_ci    }
125fb299fa2Sopenharmony_ci    if (targetBlock.VerifySha256(tgtBuffer, targetBlock.TotalBlockSize(), tgtHash) == 0) {
126fb299fa2Sopenharmony_ci        LOG(ERROR) << "Will write same sha256 blocks to target, no need to write";
127fb299fa2Sopenharmony_ci        result = SUCCESS;
128fb299fa2Sopenharmony_ci        return false;
129fb299fa2Sopenharmony_ci    }
130fb299fa2Sopenharmony_ci    std::vector<uint8_t>().swap(tgtBuffer);
131fb299fa2Sopenharmony_ci    std::string blockLen = params.GetArgumentByPos(pos++);
132fb299fa2Sopenharmony_ci    size_t srcBlockSize = String2Int<size_t>(blockLen, N_DEC);
133fb299fa2Sopenharmony_ci    buffer.resize(srcBlockSize * H_BLOCK_SIZE);
134fb299fa2Sopenharmony_ci    if (targetBlock.LoadTargetBuffer(params, buffer, srcBlockSize, pos, srcHash) != 0) {
135fb299fa2Sopenharmony_ci        LOG(ERROR) << "Failed to load blocks";
136fb299fa2Sopenharmony_ci        result = FAILED;
137fb299fa2Sopenharmony_ci        return false;
138fb299fa2Sopenharmony_ci    }
139fb299fa2Sopenharmony_ci    result = SUCCESS;
140fb299fa2Sopenharmony_ci    return true;
141fb299fa2Sopenharmony_ci}
142fb299fa2Sopenharmony_ci
143fb299fa2Sopenharmony_ciint32_t DiffAndMoveCommandFn::WriteDiffToBlock(const Command &params, std::vector<uint8_t> &srcBuffer,
144fb299fa2Sopenharmony_ci                                               uint8_t *patchBuffer, size_t patchLength, BlockSet &targetBlock)
145fb299fa2Sopenharmony_ci{
146fb299fa2Sopenharmony_ci    CommandType type = params.GetCommandType();
147fb299fa2Sopenharmony_ci    return targetBlock.WriteDiffToBlock(params, srcBuffer, patchBuffer, patchLength, type == CommandType::IMGDIFF);
148fb299fa2Sopenharmony_ci}
149fb299fa2Sopenharmony_ci
150fb299fa2Sopenharmony_ciCommandResult DiffAndMoveCommandFn::Execute(const Command &params)
151fb299fa2Sopenharmony_ci{
152fb299fa2Sopenharmony_ci    CommandType type = params.GetCommandType();
153fb299fa2Sopenharmony_ci    size_t pos = H_DIFF_CMD_ARGS_START;
154fb299fa2Sopenharmony_ci    if (type == CommandType::MOVE) {
155fb299fa2Sopenharmony_ci        pos = H_MOVE_CMD_ARGS_START;
156fb299fa2Sopenharmony_ci    }
157fb299fa2Sopenharmony_ci
158fb299fa2Sopenharmony_ci    BlockSet targetBlock;
159fb299fa2Sopenharmony_ci    std::vector<uint8_t> buffer;
160fb299fa2Sopenharmony_ci    CommandResult result = FAILED;
161fb299fa2Sopenharmony_ci    if (!LoadTarget(params, pos, buffer, targetBlock, result)) {
162fb299fa2Sopenharmony_ci        return result;
163fb299fa2Sopenharmony_ci    }
164fb299fa2Sopenharmony_ci    if (!params.GetTransferParams()->canWrite) {
165fb299fa2Sopenharmony_ci        return result;
166fb299fa2Sopenharmony_ci    }
167fb299fa2Sopenharmony_ci
168fb299fa2Sopenharmony_ci    int32_t ret = -1;
169fb299fa2Sopenharmony_ci    if (type != CommandType::MOVE) {
170fb299fa2Sopenharmony_ci        pos = H_MOVE_CMD_ARGS_START;
171fb299fa2Sopenharmony_ci        size_t offset = Utils::String2Int<size_t>(params.GetArgumentByPos(pos++), Utils::N_DEC);
172fb299fa2Sopenharmony_ci        size_t patchLength = Utils::String2Int<size_t>(params.GetArgumentByPos(pos++), Utils::N_DEC);
173fb299fa2Sopenharmony_ci        uint8_t *patchBuffer = params.GetTransferParams()->patchDataBuffer + offset;
174fb299fa2Sopenharmony_ci        ret = WriteDiffToBlock(params, buffer, patchBuffer, patchLength, targetBlock);
175fb299fa2Sopenharmony_ci    } else {
176fb299fa2Sopenharmony_ci        ret = targetBlock.WriteDataToBlock(params.GetFileDescriptor(), buffer) == 0 ? -1 : 0;
177fb299fa2Sopenharmony_ci    }
178fb299fa2Sopenharmony_ci    if (ret != 0) {
179fb299fa2Sopenharmony_ci        LOG(ERROR) << "fail to write block data.";
180fb299fa2Sopenharmony_ci        return errno == EIO ? NEED_RETRY : FAILED;
181fb299fa2Sopenharmony_ci    }
182fb299fa2Sopenharmony_ci    std::string storeBase = params.GetTransferParams()->storeBase;
183fb299fa2Sopenharmony_ci    std::string freeStash = params.GetTransferParams()->freeStash;
184fb299fa2Sopenharmony_ci    if (!freeStash.empty()) {
185fb299fa2Sopenharmony_ci        if (Store::FreeStore(storeBase, freeStash) != 0) {
186fb299fa2Sopenharmony_ci            LOG(WARNING) << "fail to delete file: " << freeStash;
187fb299fa2Sopenharmony_ci        }
188fb299fa2Sopenharmony_ci        params.GetTransferParams()->freeStash.clear();
189fb299fa2Sopenharmony_ci    }
190fb299fa2Sopenharmony_ci    params.GetTransferParams()->written += targetBlock.TotalBlockSize();
191fb299fa2Sopenharmony_ci    return SUCCESS;
192fb299fa2Sopenharmony_ci}
193fb299fa2Sopenharmony_ci
194fb299fa2Sopenharmony_ciCommandResult FreeCommandFn::Execute(const Command &params)
195fb299fa2Sopenharmony_ci{
196fb299fa2Sopenharmony_ci    std::string shaStr = params.GetArgumentByPos(1);
197fb299fa2Sopenharmony_ci    std::string storeBase = params.GetTransferParams()->storeBase;
198fb299fa2Sopenharmony_ci    if (params.GetTransferParams()->storeCreated == 0) {
199fb299fa2Sopenharmony_ci        return CommandResult(Store::FreeStore(storeBase, shaStr));
200fb299fa2Sopenharmony_ci    }
201fb299fa2Sopenharmony_ci    return SUCCESS;
202fb299fa2Sopenharmony_ci}
203fb299fa2Sopenharmony_ci
204fb299fa2Sopenharmony_ciCommandResult StashCommandFn::Execute(const Command &params)
205fb299fa2Sopenharmony_ci{
206fb299fa2Sopenharmony_ci    size_t pos = 1;
207fb299fa2Sopenharmony_ci    const std::string shaStr = params.GetArgumentByPos(pos++);
208fb299fa2Sopenharmony_ci    BlockSet srcBlk;
209fb299fa2Sopenharmony_ci    LOG(INFO) << "Get source block info to block set";
210fb299fa2Sopenharmony_ci    srcBlk.ParserAndInsert(params.GetArgumentByPos(pos++));
211fb299fa2Sopenharmony_ci    size_t srcBlockSize = srcBlk.TotalBlockSize();
212fb299fa2Sopenharmony_ci    std::vector<uint8_t> buffer;
213fb299fa2Sopenharmony_ci    buffer.resize(srcBlockSize * H_BLOCK_SIZE);
214fb299fa2Sopenharmony_ci    std::string storeBase = params.GetTransferParams()->storeBase;
215fb299fa2Sopenharmony_ci    LOG(DEBUG) << "Confirm whether the block is stored";
216fb299fa2Sopenharmony_ci    if (Store::LoadDataFromStore(storeBase, shaStr, buffer) == 0) {
217fb299fa2Sopenharmony_ci        LOG(INFO) << "The stash has been stored, skipped";
218fb299fa2Sopenharmony_ci        return SUCCESS;
219fb299fa2Sopenharmony_ci    }
220fb299fa2Sopenharmony_ci    LOG(DEBUG) << "Read block data to buffer";
221fb299fa2Sopenharmony_ci    if (srcBlk.ReadDataFromBlock(params.GetFileDescriptor(), buffer) == 0) {
222fb299fa2Sopenharmony_ci        LOG(ERROR) << "Error to load block data";
223fb299fa2Sopenharmony_ci        return FAILED;
224fb299fa2Sopenharmony_ci    }
225fb299fa2Sopenharmony_ci    int32_t res = srcBlk.VerifySha256(buffer, srcBlockSize, shaStr);
226fb299fa2Sopenharmony_ci    if (res != 0 && !params.GetTransferParams()->canWrite) {
227fb299fa2Sopenharmony_ci        res = BlockVerify(params, buffer, srcBlockSize, shaStr, pos);
228fb299fa2Sopenharmony_ci    }
229fb299fa2Sopenharmony_ci    if (res != 0) {
230fb299fa2Sopenharmony_ci        LOG(WARNING) << "failed to load source blocks for stash";
231fb299fa2Sopenharmony_ci        return SUCCESS;
232fb299fa2Sopenharmony_ci    }
233fb299fa2Sopenharmony_ci    LOG(INFO) << "store " << srcBlockSize << " blocks to " << storeBase << "/" << shaStr;
234fb299fa2Sopenharmony_ci    int ret = Store::WriteDataToStore(storeBase, shaStr, buffer, srcBlockSize * H_BLOCK_SIZE);
235fb299fa2Sopenharmony_ci    return CommandResult(ret);
236fb299fa2Sopenharmony_ci}
237fb299fa2Sopenharmony_ci} // namespace Updater
238