2 * Copyright (c) 2011 Samsung Electronics Co., Ltd All Rights Reserved
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
8 * http://www.apache.org/licenses/LICENSE-2.0
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
17 * @file task_ecnrypt_resource.cpp
18 * @author Soyoung Kim (sy037.kim@samsung.com)
20 * @brief Implementation file for installer task encrypt resource
22 #include "task_encrypt_resource.h"
24 #undef __USE_FILE_OFFSET64
35 #include <dpl/log/log.h>
36 #include <dpl/errno_string.h>
37 #include <dpl/foreach.h>
38 #include <dpl/scoped_fclose.h>
39 #include <dpl/wrt-dao-ro/global_config.h>
40 #include <dpl/string.h>
42 #include <widget_install/job_widget_install.h>
43 #include <widget_install/widget_install_context.h>
44 #include <widget_install/widget_install_errors.h>
46 using namespace WrtDB;
47 using namespace WRTEncryptor;
50 const std::size_t ENCRYPTION_CHUNK_MAX_SIZE = 1024; // bytes
52 std::set<std::string>& getSupportedForEncryption()
54 static std::set<std::string> encryptSet;
55 if (encryptSet.empty()) {
56 encryptSet.insert(".html");
57 encryptSet.insert(".css");
58 encryptSet.insert(".js");
63 bool isSupportedForEncryption(const std::string &file)
65 size_t foundKey = file.rfind(".");
66 if (std::string::npos != foundKey) {
67 std::string mimeType = file.substr(foundKey);
68 return getSupportedForEncryption().count(mimeType) > 0;
76 * @param path Path to a file.
78 * @return Stream handle.
79 * @throw ExtractFileFailed If error (other than EINTR) occurs.
81 FILE* openFile(const std::string& path, const std::string& mode)
87 result = fopen(path.c_str(), mode.c_str());
88 } while ((NULL == result) && (EINTR == errno));
92 ThrowMsg(Jobs::WidgetInstall::Exceptions::InternalError,
93 "Could not open file " << path);
100 * Reads bytes from a stream.
102 * @param buffer Buffer to read the bytes into.
103 * @param count Number of bytes to read.
104 * @param stream Stream to read from.
105 * @return Number of bytes read
106 * @throw ExtractFileFailed If error (other than EINTR) occurs.
108 std::size_t readBytes(unsigned char* buffer, std::size_t count, FILE* stream)
110 std::size_t result = std::fread(buffer,
111 sizeof(unsigned char),
118 if (0 != std::ferror(stream))
122 ThrowMsg(Jobs::WidgetInstall::Exceptions::InternalError,
123 "Error while reading data" <<
124 " [" << DPL::GetErrnoString(error) << "]");
133 * Writes bytes to a stream.
135 * @param buffer Data to write.
136 * @param count Number of bytes.
137 * @param stream Stream to write to.
138 * @throw ExtractFileFailed If error (other than EINTR) occurs.
140 void writeBytes(unsigned char* buffer, std::size_t count, FILE* stream)
142 std::size_t bytesWritten = 0;
143 std::size_t bytesToWrite = 0;
146 bytesToWrite = count - bytesWritten;
147 bytesWritten = std::fwrite(buffer + bytesWritten,
148 sizeof(unsigned char),
149 count - bytesWritten,
151 if ((bytesWritten != bytesToWrite) && (EINTR != errno))
154 ThrowMsg(Jobs::WidgetInstall::Exceptions::InternalError,
155 "Error while writing data" <<
156 " [" << DPL::GetErrnoString(error) << "]");
158 } while ((bytesWritten != bytesToWrite) && (EINTR == errno));
163 namespace WidgetInstall {
164 TaskEncryptResource::TaskEncryptResource(InstallerContext& context) :
165 DPL::TaskDecl<TaskEncryptResource>(this),
168 AddStep(&TaskEncryptResource::StepEncryptResource);
171 void TaskEncryptResource::StepEncryptResource()
173 LogDebug("Step Encrypt resource");
174 m_resEnc = new ResourceEncryptor;
175 m_resEnc->CreateEncryptionKey(DPL::ToUTF8String(m_context.
176 widgetConfig.tzAppid));
178 EncryptDirectory(m_context.locations->getTemporaryRootDir());
179 m_context.job->UpdateProgress(
180 InstallerContext::INSTALL_ECRYPTION_FILES,
181 "Ecrypt resource files");
184 void TaskEncryptResource::EncryptDirectory(std::string path)
188 char * const paths[] = { const_cast<char * const>(path.c_str()), NULL };
190 if ((fts = fts_open(paths, FTS_PHYSICAL | FTS_NOCHDIR, NULL)) == NULL) {
193 LogWarning(__PRETTY_FUNCTION__ << ": fts_open failed with error: "
195 ThrowMsg(Exceptions::InternalError, "Error reading directory: "
199 while ((ftsent = fts_read(fts)) != NULL) {
200 switch (ftsent->fts_info) {
206 //directories, non-regular files, dangling symbolic links
211 //regular files and other objects that can be counted
212 if (isSupportedForEncryption(ftsent->fts_path)) {
213 EncryptFile(ftsent->fts_path);
221 LogWarning(__PRETTY_FUNCTION__
222 << ": traversal failed on file: "
225 << strerror(ftsent->fts_errno));
226 ThrowMsg(Exceptions::InternalError, "Error reading file");
230 if (fts_close(fts) == -1) {
232 LogWarning(__PRETTY_FUNCTION__ << ": fts_close failed with error: "
237 void TaskEncryptResource::EncryptFile(const std::string &fileName)
241 LogDebug("Encrypt file: " << fileName);
242 std::string encFile = fileName + ".enc";
245 memset(&info, 0, sizeof(info));
246 if (stat(fileName.c_str(), &info) != 0)
249 ThrowMsg(Exceptions::InternalError,
250 "Could not access file " << fileName <<
251 "[" << DPL::GetErrnoString(error) << "]");
253 const std::size_t fileSize = info.st_size;
255 DPL::ScopedFClose inFile(openFile(fileName, "r"));
256 DPL::ScopedFClose outFile(openFile(encFile, "w"));
258 const std::size_t chunkSize = (fileSize > ENCRYPTION_CHUNK_MAX_SIZE
259 ? ENCRYPTION_CHUNK_MAX_SIZE : fileSize);
260 const int maxBlockSize = m_resEnc->GetBlockSize(chunkSize);
262 std::unique_ptr<unsigned char[]> inChunk(new unsigned char[chunkSize]);
263 std::unique_ptr<unsigned char[]> outChunk;
265 std::size_t bytesRead = 0;
266 int curBlockSize = 0;
269 bytesRead = readBytes(inChunk.get(), chunkSize, inFile.Get());
270 if (chunkSize != bytesRead)
272 curBlockSize = m_resEnc->GetBlockSize(bytesRead);
273 outChunk.reset(new unsigned char[curBlockSize]);
277 if (maxBlockSize != curBlockSize)
279 curBlockSize = maxBlockSize;
280 outChunk.reset(new unsigned char[curBlockSize]);
284 m_resEnc->EncryptChunk(inChunk.get(), outChunk.get(), bytesRead);
286 writeBytes(outChunk.get(), curBlockSize, outFile.Get());
288 } while (0 == std::feof(inFile.Get()));
290 LogDebug("File encrypted successfully");
295 LogDebug("Remove plain-text file: " << fileName);
296 if (0 != unlink(fileName.c_str()))
298 Throw(Exceptions::InternalError);
301 LogDebug("Rename encrypted file");
302 if (0 != std::rename(encFile.c_str(), fileName.c_str()))
304 Throw(Exceptions::InternalError);
307 std::string realPath = fileName;
309 m_context.locations->getTemporaryRootDir().length(),
310 m_context.locations->getSourceDir());
312 WrtDB::EncryptedFileInfo fileInfo;
313 fileInfo.fileName = DPL::FromUTF8String(realPath);
314 fileInfo.fileSize = fileSize;
316 m_context.widgetConfig.encryptedFiles.insert(fileInfo);
318 Catch (Exceptions::InternalError)
320 ReThrowMsg(Exceptions::ExtractFileFailed, fileName);
322 Catch (ResourceEncryptor::Exception::Base)
324 ReThrowMsg(Exceptions::ExtractFileFailed, fileName);
328 } //namespace WidgetInstall