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
16 #include "command_process.h"
17 #include <cstdio>
18 #include <fcntl.h>
19 #include <linux/fs.h>
20 #include <memory>
21 #include <pthread.h>
22 #include <sys/ioctl.h>
23 #include <sys/stat.h>
24 #include <sys/types.h>
25 #include <unistd.h>
26 #include "applypatch/block_set.h"
27 #include "applypatch/block_writer.h"
28 #include "applypatch/data_writer.h"
29 #include "applypatch/store.h"
30 #include "applypatch/transfer_manager.h"
31 #include "log/log.h"
32 #include "securec.h"
33 #include "utils.h"
34
35 using namespace Hpackage;
36 namespace Updater {
Execute(const Command & params)37 CommandResult AbortCommandFn::Execute(const Command ¶ms)
38 {
39 return SUCCESS;
40 }
41
Execute(const Command & params)42 CommandResult NewCommandFn::Execute(const Command ¶ms)
43 {
44 BlockSet bs;
45 bs.ParserAndInsert(params.GetArgumentByPos(1));
46 LOG(INFO) << " writing " << bs.TotalBlockSize() << " blocks of new data";
47 auto writerThreadInfo = TransferManager::GetTransferManagerInstance()->GetGlobalParams()->writerThreadInfo.get();
48 pthread_mutex_lock(&writerThreadInfo->mutex);
49 writerThreadInfo->writer = std::make_unique<BlockWriter>(params.GetFileDescriptor(), bs);
50 pthread_cond_broadcast(&writerThreadInfo->cond);
51 while (writerThreadInfo->writer != nullptr) {
52 LOG(DEBUG) << "wait for new data write done...";
53 if (!writerThreadInfo->readyToWrite) {
54 LOG(ERROR) << "writer thread could not write blocks. " << bs.TotalBlockSize() * H_BLOCK_SIZE -
55 writerThreadInfo->writer->GetTotalWritten() << " bytes lost";
56 pthread_mutex_unlock(&writerThreadInfo->mutex);
57 writerThreadInfo->writer.reset();
58 writerThreadInfo->writer = nullptr;
59 return FAILED;
60 }
61 LOG(DEBUG) << "Writer already written " << writerThreadInfo->writer->GetTotalWritten() << " byte(s)";
62 pthread_cond_wait(&writerThreadInfo->cond, &writerThreadInfo->mutex);
63 }
64 pthread_mutex_unlock(&writerThreadInfo->mutex);
65
66 writerThreadInfo->writer.reset();
67 TransferManager::GetTransferManagerInstance()->GetGlobalParams()->written += bs.TotalBlockSize();
68 return SUCCESS;
69 }
70
Execute(const Command & params)71 CommandResult ZeroAndEraseCommandFn::Execute(const Command ¶ms)
72 {
73 bool isErase = false;
74 if (params.GetCommandType() == CommandType::ERASE) {
75 isErase = true;
76 LOG(INFO) << "Start run ERASE command";
77 }
78 if (isErase) {
79 struct stat statBlock {};
80 if (fstat(params.GetFileDescriptor(), &statBlock) == -1) {
81 LOG(ERROR) << "Failed to fstat";
82 return FAILED;
83 }
84 #ifndef UPDATER_UT
85 if (!S_ISBLK(statBlock.st_mode)) {
86 LOG(ERROR) << "Invalid block device";
87 return FAILED;
88 }
89 #endif
90 }
91
92 BlockSet blk;
93 blk.ParserAndInsert(params.GetArgumentByPos(1));
94 LOG(INFO) << "Parser params to block set";
95 auto ret = CommandResult(blk.WriteZeroToBlock(params.GetFileDescriptor(), isErase));
96 if (ret == SUCCESS) {
97 TransferManager::GetTransferManagerInstance()->GetGlobalParams()->written += blk.TotalBlockSize();
98 }
99 return ret;
100 }
101
Execute(const Command & params)102 CommandResult DiffAndMoveCommandFn::Execute(const Command ¶ms)
103 {
104 CommandType type = params.GetCommandType();
105 UPDATER_ERROR_CHECK(type == CommandType::MOVE || type == CommandType::BSDIFF || type == CommandType::IMGDIFF,
106 "Invalid command type", return FAILED);
107 size_t pos = H_DIFF_CMD_ARGS_START;
108 bool isImgDiff = false;
109 if (type == CommandType::MOVE) {
110 pos = H_MOVE_CMD_ARGS_START;
111 } else if (type == CommandType::IMGDIFF) {
112 isImgDiff = true;
113 }
114 // Read sha256 of source and target
115 std::string cmdTmp = params.GetArgumentByPos(pos++);
116 std::string srcHash = cmdTmp;
117 std::string tgtHash = srcHash;
118 if (type != CommandType::MOVE) {
119 tgtHash = params.GetArgumentByPos(pos++);
120 }
121 // Read the target's buffer to determine whether it needs to be written
122 BlockSet targetBlock;
123 size_t tgtBlockSize;
124 cmdTmp = params.GetArgumentByPos(pos++);
125 targetBlock.ParserAndInsert(cmdTmp);
126 tgtBlockSize = targetBlock.TotalBlockSize() * H_BLOCK_SIZE;
127 std::vector<uint8_t> buffer(tgtBlockSize);
128 LOG(INFO) << targetBlock.TotalBlockSize() << " blocks' data need to read";
129 UPDATER_ERROR_CHECK(targetBlock.ReadDataFromBlock(params.GetFileDescriptor(), buffer) > 0,
130 "Read data from block error", return FAILED);
131 UPDATER_ERROR_CHECK(targetBlock.VerifySha256(buffer, targetBlock.TotalBlockSize(), tgtHash) != 0,
132 "Will write same sha256 blocks to target, no need to write", return SUCCESS);
133 auto ret = targetBlock.LoadTargetBuffer(params, buffer, tgtBlockSize, pos, srcHash);
134 UPDATER_ERROR_CHECK(ret == 0, "Failed to load blocks", return FAILED);
135 if (type != CommandType::MOVE) {
136 LOG(INFO) << "Create " << tgtBlockSize << " diff blocks to target position";
137 ret = targetBlock.WriteDiffToBlock(const_cast<const Command &>(params), buffer, tgtBlockSize, isImgDiff);
138 if (ret != 0) {
139 UPDATER_CHECK_ONLY_RETURN(errno != EIO, return NEED_RETRY);
140 return FAILED;
141 }
142 } else {
143 LOG(INFO) << "Moving " << tgtBlockSize << " blocks to target position";
144 if (targetBlock.WriteDataToBlock(params.GetFileDescriptor(), buffer) <= 0) {
145 UPDATER_CHECK_ONLY_RETURN(errno != EIO, return NEED_RETRY);
146 return FAILED;
147 }
148 }
149 TransferManager::GetTransferManagerInstance()->GetGlobalParams()->written += targetBlock.TotalBlockSize();
150 return SUCCESS;
151 }
152
Execute(const Command & params)153 CommandResult FreeCommandFn::Execute(const Command ¶ms)
154 {
155 std::string shaStr = params.GetArgumentByPos(1);
156 blocksetMap.erase(shaStr);
157 std::string storeBase = TransferManager::GetTransferManagerInstance()->GetGlobalParams()->storeBase;
158 if (TransferManager::GetTransferManagerInstance()->GetGlobalParams()->storeCreated != 0) {
159 return CommandResult(Store::FreeStore(storeBase, shaStr));
160 }
161 return SUCCESS;
162 }
163
Execute(const Command & params)164 CommandResult StashCommandFn::Execute(const Command ¶ms)
165 {
166 size_t pos = 1;
167 const std::string shaStr = params.GetArgumentByPos(pos++);
168 BlockSet srcBlk;
169 LOG(INFO) << "Get source block info to block set";
170 srcBlk.ParserAndInsert(params.GetArgumentByPos(pos++));
171 size_t srcBlockSize = srcBlk.TotalBlockSize();
172 std::vector<uint8_t> buffer;
173 buffer.resize(srcBlockSize * H_BLOCK_SIZE);
174 std::string storeBase = TransferManager::GetTransferManagerInstance()->GetGlobalParams()->storeBase;
175 LOG(INFO) << "Confirm whether the block is stored";
176 if (Store::LoadDataFromStore(storeBase, shaStr, buffer) == 0) {
177 LOG(INFO) << "The stash has been stored, skipped";
178 return SUCCESS;
179 }
180 LOG(INFO) << "Read block data to buffer";
181 if (srcBlk.ReadDataFromBlock(params.GetFileDescriptor(), buffer) <= 0) {
182 LOG(ERROR) << "Error to load block data";
183 return FAILED;
184 }
185 blocksetMap[shaStr] = srcBlk;
186 if (srcBlk.VerifySha256(buffer, srcBlockSize, shaStr) != 0) {
187 return FAILED;
188 }
189 LOG(INFO) << "store " << srcBlockSize << " blocks to " << shaStr;
190 int ret = Store::WriteDataToStore(storeBase, shaStr, buffer, srcBlockSize * H_BLOCK_SIZE);
191 return CommandResult(ret);
192 }
193 } // namespace Updater
194