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 ¶ms) 39fb299fa2Sopenharmony_ci{ 40fb299fa2Sopenharmony_ci return SUCCESS; 41fb299fa2Sopenharmony_ci} 42fb299fa2Sopenharmony_ci 43fb299fa2Sopenharmony_ciCommandResult NewCommandFn::Execute(const Command ¶ms) 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 ¶ms) 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 ¶ms, 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 ¶ms, 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 ¶ms) 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 ¶ms) 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 ¶ms) 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