1 /*
2 * Copyright (c) 2023 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 "module_zip_helper.h"
17
18 #include <fcntl.h>
19
20 #include "log/log.h"
21 #include "module_utils.h"
22 #include "unique_fd.h"
23
24 namespace OHOS {
25 namespace SysInstaller {
26 using namespace Updater;
27
28 namespace {
29 struct __attribute__((packed)) LocalFileHeader {
30 uint32_t signature = 0;
31 uint16_t versionNeeded = 0;
32 uint16_t flags = 0;
33 uint16_t compressionMethod = 0;
34 uint16_t modifiedTime = 0;
35 uint16_t modifiedDate = 0;
36 uint32_t crc = 0;
37 uint32_t compressedSize = 0;
38 uint32_t uncompressedSize = 0;
39 uint16_t nameSize = 0;
40 uint16_t extraSize = 0;
41 };
42
43 struct __attribute__((packed)) CentralDirEntry {
44 uint32_t signature = 0;
45 uint16_t versionMade = 0;
46 uint16_t versionNeeded = 0;
47 uint16_t flags = 0; // general purpose bit flag
48 uint16_t compressionMethod = 0;
49 uint16_t modifiedTime = 0;
50 uint16_t modifiedDate = 0;
51 uint32_t crc = 0;
52 uint32_t compressedSize = 0;
53 uint32_t uncompressedSize = 0;
54 uint16_t nameSize = 0;
55 uint16_t extraSize = 0;
56 uint16_t commentSize = 0;
57 uint16_t diskNumStart = 0;
58 uint16_t internalAttr = 0;
59 uint32_t externalAttr = 0;
60 uint32_t localHeaderOffset = 0;
61 };
62
63 constexpr uint32_t LOCAL_HEADER_SIGNATURE = 0x04034b50;
64 constexpr uint32_t CENTRAL_SIGNATURE = 0x02014b50;
65 }
66
ModuleZipHelper(const std::string & path)67 ModuleZipHelper::ModuleZipHelper(const std::string &path)
68 {
69 handle_ = unzOpen(path.c_str());
70 hasLocated_ = false;
71 zipPath_ = path;
72 }
73
~ModuleZipHelper()74 ModuleZipHelper::~ModuleZipHelper()
75 {
76 if (IsValid()) {
77 int err = unzClose(handle_);
78 if (err != UNZ_OK) {
79 LOG(WARNING) << "Close handle error " << err << ". path=" << zipPath_;
80 }
81 }
82 }
83
GetNumberOfEntry(uint32_t & number)84 bool ModuleZipHelper::GetNumberOfEntry(uint32_t &number)
85 {
86 if (!IsValid()) {
87 LOG(ERROR) << "Cannot get entry number with invalid handle. path=" << zipPath_;
88 return false;
89 }
90 unz_global_info info;
91 int err = unzGetGlobalInfo(handle_, &info);
92 if (err != UNZ_OK) {
93 LOG(ERROR) << "Get global info error " << err << ". path=" << zipPath_;
94 return false;
95 }
96 number = static_cast<uint32_t>(info.number_entry);
97 return true;
98 }
99
LocateFile(const std::string & filename)100 bool ModuleZipHelper::LocateFile(const std::string &filename)
101 {
102 if (!IsValid()) {
103 LOG(ERROR) << "Cannot locate file with invalid handle. path=" << zipPath_;
104 return false;
105 }
106 int err = unzLocateFile2(handle_, filename.c_str(), 0);
107 if (err != UNZ_OK) {
108 LOG(ERROR) << filename << " is not found in " << zipPath_;
109 hasLocated_ = false;
110 return false;
111 }
112 hasLocated_ = true;
113 filename_ = filename;
114 return true;
115 }
116
GetFileSize(uint32_t & size)117 bool ModuleZipHelper::GetFileSize(uint32_t &size)
118 {
119 if (!hasLocated_) {
120 LOG(ERROR) << "Cannot get file size without located file. path=" << zipPath_;
121 return false;
122 }
123 unz_file_info info;
124 int err = unzGetCurrentFileInfo(handle_, &info, nullptr, 0, nullptr, 0, nullptr, 0);
125 if (err != UNZ_OK) {
126 LOG(ERROR) << "Get file size error " << err << ". " << filename_ << " in " << zipPath_;
127 return false;
128 }
129 size = static_cast<uint32_t>(info.uncompressed_size);
130 return true;
131 }
132
GetFileOffset(uint32_t & offset)133 bool ModuleZipHelper::GetFileOffset(uint32_t &offset)
134 {
135 if (!hasLocated_) {
136 LOG(ERROR) << "Cannot get file offset without located file. path=" << zipPath_;
137 return false;
138 }
139 unz_file_pos filePos;
140 int err = unzGetFilePos(handle_, &filePos);
141 if (err != UNZ_OK) {
142 LOG(ERROR) << "Get file pos error " << err << ". " << filename_ << " in " << zipPath_;
143 return false;
144 }
145 uint32_t centralDirOffset = static_cast<uint32_t>(filePos.pos_in_zip_directory);
146 if (!GetFileEntryOffset(offset, centralDirOffset)) {
147 LOG(ERROR) << "Cannot get file entry offset";
148 return false;
149 }
150 return true;
151 }
152
GetFileEntryOffset(uint32_t & offset,uint32_t centralDirOffset) const153 bool ModuleZipHelper::GetFileEntryOffset(uint32_t &offset, uint32_t centralDirOffset) const
154 {
155 std::string realPath = GetRealPath(zipPath_);
156 if (realPath.empty()) {
157 LOG(ERROR) << "Invalid path " << zipPath_;
158 return false;
159 }
160 UniqueFd fd(open(realPath.c_str(), O_RDONLY | O_CLOEXEC));
161 if (fd.Get() == -1) {
162 LOG(ERROR) << "Cannot open package " << zipPath_;
163 return false;
164 }
165 uint8_t centralDirBuf[sizeof(CentralDirEntry)];
166 if (!ReadFullyAtOffset(fd.Get(), centralDirBuf, sizeof(CentralDirEntry), centralDirOffset)) {
167 LOG(ERROR) << "Unable to read central directory";
168 return false;
169 }
170 uint32_t centralSignature = ReadLE32(centralDirBuf + offsetof(CentralDirEntry, signature));
171 if (centralSignature != CENTRAL_SIGNATURE) {
172 LOG(ERROR) << "Check central signature error";
173 return false;
174 }
175 uint32_t localHeaderOffset = ReadLE32(centralDirBuf + offsetof(CentralDirEntry, localHeaderOffset));
176 uint8_t localHeaderBuf[sizeof(LocalFileHeader)];
177 if (!ReadFullyAtOffset(fd.Get(), localHeaderBuf, sizeof(LocalFileHeader), localHeaderOffset)) {
178 LOG(ERROR) << "Unable to read local file header";
179 return false;
180 }
181 uint32_t localHeaderSignature = ReadLE32(localHeaderBuf + offsetof(LocalFileHeader, signature));
182 if (localHeaderSignature != LOCAL_HEADER_SIGNATURE) {
183 LOG(ERROR) << "Check local header signature error";
184 return false;
185 }
186 uint16_t nameSize = ReadLE16(localHeaderBuf + offsetof(LocalFileHeader, nameSize));
187 uint16_t extraSize = ReadLE16(localHeaderBuf + offsetof(LocalFileHeader, extraSize));
188 offset = localHeaderOffset + sizeof(LocalFileHeader) + nameSize + extraSize;
189 return true;
190 }
191
GetFileContent(std::string & buf)192 bool ModuleZipHelper::GetFileContent(std::string &buf)
193 {
194 if (!hasLocated_) {
195 LOG(ERROR) << "Cannot get file content without located file. path=" << zipPath_;
196 return false;
197 }
198 uint32_t length;
199 if (!GetFileSize(length)) {
200 LOG(ERROR) << "Cannot get buf length.";
201 return false;
202 }
203 buf.resize(length, '\0');
204
205 int err = unzOpenCurrentFile(handle_);
206 if (err != UNZ_OK) {
207 LOG(ERROR) << "Open current file error " << err << ". " << filename_ << " in " << zipPath_;
208 return false;
209 }
210 int size = unzReadCurrentFile(handle_, reinterpret_cast<void *>(&(buf)[0]), length);
211 err = unzCloseCurrentFile(handle_);
212 if (size < 0) {
213 LOG(ERROR) << "Read current file error. " << filename_ << " in " << zipPath_;
214 return false;
215 }
216 if (err != UNZ_OK) {
217 LOG(ERROR) << "Close current file error " << err << ". " << filename_ << " in " << zipPath_;
218 return false;
219 }
220 return true;
221 }
222 } // namespace SysInstaller
223 } // namespace OHOS