• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 &params)
38 {
39     return SUCCESS;
40 }
41 
Execute(const Command & params)42 CommandResult NewCommandFn::Execute(const Command &params)
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 &params)
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 
LoadTarget(const Command & params,size_t & pos,std::vector<uint8_t> & buffer,BlockSet & targetBlock,CommandResult & result)102 bool LoadTarget(const Command &params, size_t &pos, std::vector<uint8_t> &buffer,
103                     BlockSet &targetBlock, CommandResult &result)
104 {
105     CommandType type = params.GetCommandType();
106     // Read sha256 of source and target
107     std::string srcHash = params.GetArgumentByPos(pos++);
108     std::string tgtHash = srcHash;
109     if (type != CommandType::MOVE) {
110         tgtHash = params.GetArgumentByPos(pos++);
111     }
112 
113     // Read the target's buffer to determine whether it needs to be written
114     size_t tgtBlockSize;
115     std::string cmdTmp = params.GetArgumentByPos(pos++);
116     targetBlock.ParserAndInsert(cmdTmp);
117     tgtBlockSize = targetBlock.TotalBlockSize() * H_BLOCK_SIZE;
118     buffer.resize(tgtBlockSize);
119     if (targetBlock.ReadDataFromBlock(params.GetFileDescriptor(), buffer) == 0) {
120         LOG(ERROR) << "Read data from block error, TotalBlockSize: " << targetBlock.TotalBlockSize();
121         result = FAILED;
122         return false;
123     }
124     if (targetBlock.VerifySha256(buffer, targetBlock.TotalBlockSize(), tgtHash) == 0) {
125         LOG(ERROR) << "Will write same sha256 blocks to target, no need to write";
126         result = SUCCESS;
127         return false;
128     }
129 
130     if (targetBlock.LoadTargetBuffer(params, buffer, tgtBlockSize, pos, srcHash) != 0) {
131         LOG(ERROR) << "Failed to load blocks";
132         result = FAILED;
133         return false;
134     }
135     return true;
136 }
137 
Execute(const Command & params)138 CommandResult DiffAndMoveCommandFn::Execute(const Command &params)
139 {
140     CommandType type = params.GetCommandType();
141     if (type != CommandType::MOVE && type != CommandType::BSDIFF && type != CommandType::IMGDIFF) {
142         LOG(ERROR) << "Invalid command type";
143         return FAILED;
144     }
145     size_t pos = H_DIFF_CMD_ARGS_START;
146     bool isImgDiff = false;
147     if (type == CommandType::MOVE) {
148         pos = H_MOVE_CMD_ARGS_START;
149     } else if (type == CommandType::IMGDIFF) {
150         isImgDiff = true;
151     }
152 
153     BlockSet targetBlock;
154     std::vector<uint8_t> buffer;
155     CommandResult result = FAILED;
156     if (!LoadTarget(params, pos, buffer, targetBlock, result)) {
157         return result;
158     }
159 
160     int32_t ret = -1;
161     size_t tgtBlockSize = buffer.size() / H_BLOCK_SIZE;
162     if (type != CommandType::MOVE) {
163         ret = targetBlock.WriteDiffToBlock(const_cast<const Command &>(params), buffer, tgtBlockSize, isImgDiff);
164     } else {
165         ret = targetBlock.WriteDataToBlock(params.GetFileDescriptor(), buffer) == 0 ? -1 : 0;
166     }
167     if (ret != 0) {
168         LOG(ERROR) << "tgtBlockSize is : " <<tgtBlockSize << " , type is :" <<type;
169         return errno == EIO ? NEED_RETRY : FAILED;
170     }
171     std::string storeBase = TransferManager::GetTransferManagerInstance()->GetGlobalParams()->storeBase;
172     std::string freeStash = TransferManager::GetTransferManagerInstance()->GetGlobalParams()->freeStash;
173     if (!freeStash.empty()) {
174         if (Store::FreeStore(storeBase, freeStash) != 0) {
175             LOG(WARNING) << "fail to delete file: " << freeStash;
176         }
177         TransferManager::GetTransferManagerInstance()->GetGlobalParams()->freeStash.clear();
178     }
179     TransferManager::GetTransferManagerInstance()->GetGlobalParams()->written += targetBlock.TotalBlockSize();
180     return SUCCESS;
181 }
182 
Execute(const Command & params)183 CommandResult FreeCommandFn::Execute(const Command &params)
184 {
185     std::string shaStr = params.GetArgumentByPos(1);
186     blocksetMap.erase(shaStr);
187     std::string storeBase = TransferManager::GetTransferManagerInstance()->GetGlobalParams()->storeBase;
188     if (TransferManager::GetTransferManagerInstance()->GetGlobalParams()->storeCreated == 0) {
189         return CommandResult(Store::FreeStore(storeBase, shaStr));
190     }
191     return SUCCESS;
192 }
193 
Execute(const Command & params)194 CommandResult StashCommandFn::Execute(const Command &params)
195 {
196     size_t pos = 1;
197     const std::string shaStr = params.GetArgumentByPos(pos++);
198     BlockSet srcBlk;
199     LOG(INFO) << "Get source block info to block set";
200     srcBlk.ParserAndInsert(params.GetArgumentByPos(pos++));
201     size_t srcBlockSize = srcBlk.TotalBlockSize();
202     std::vector<uint8_t> buffer;
203     buffer.resize(srcBlockSize * H_BLOCK_SIZE);
204     std::string storeBase = TransferManager::GetTransferManagerInstance()->GetGlobalParams()->storeBase;
205     LOG(INFO) << "Confirm whether the block is stored";
206     if (Store::LoadDataFromStore(storeBase, shaStr, buffer) == 0) {
207         LOG(INFO) << "The stash has been stored, skipped";
208         return SUCCESS;
209     }
210     LOG(INFO) << "Read block data to buffer";
211     if (srcBlk.ReadDataFromBlock(params.GetFileDescriptor(), buffer) == 0) {
212         LOG(ERROR) << "Error to load block data";
213         return FAILED;
214     }
215     blocksetMap[shaStr] = srcBlk;
216     if (srcBlk.VerifySha256(buffer, srcBlockSize, shaStr) != 0) {
217         return FAILED;
218     }
219     LOG(INFO) << "store " << srcBlockSize << " blocks to " << shaStr;
220     int ret = Store::WriteDataToStore(storeBase, shaStr, buffer, srcBlockSize * H_BLOCK_SIZE);
221     return CommandResult(ret);
222 }
223 } // namespace Updater
224