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),
169 AddStep(&TaskEncryptResource::StepEncryptResource);
172 void TaskEncryptResource::StepEncryptResource()
174 LogDebug("Step Encrypt resource");
175 m_resEnc = new ResourceEncryptor;
176 m_resEnc->CreateEncryptionKey(DPL::ToUTF8String(m_context.
177 widgetConfig.tzAppid));
179 EncryptDirectory(m_context.locations->getTemporaryRootDir());
180 m_context.job->UpdateProgress(
181 InstallerContext::INSTALL_ECRYPTION_FILES,
182 "Ecrypt resource files");
185 void TaskEncryptResource::EncryptDirectory(std::string path)
189 char * const paths[] = { const_cast<char * const>(path.c_str()), NULL };
191 if ((fts = fts_open(paths, FTS_PHYSICAL | FTS_NOCHDIR, NULL)) == NULL) {
194 LogWarning(__PRETTY_FUNCTION__ << ": fts_open failed with error: "
196 ThrowMsg(Exceptions::InternalError, "Error reading directory: "
200 while ((ftsent = fts_read(fts)) != NULL) {
201 switch (ftsent->fts_info) {
207 //directories, non-regular files, dangling symbolic links
212 //regular files and other objects that can be counted
213 if (isSupportedForEncryption(ftsent->fts_path)) {
214 EncryptFile(ftsent->fts_path);
222 LogWarning(__PRETTY_FUNCTION__
223 << ": traversal failed on file: "
226 << strerror(ftsent->fts_errno));
227 ThrowMsg(Exceptions::InternalError, "Error reading file");
232 if (fts_close(fts) == -1) {
234 LogWarning(__PRETTY_FUNCTION__ << ": fts_close failed with error: "
239 void TaskEncryptResource::EncryptFile(const std::string &fileName)
243 LogDebug("Encrypt file: " << fileName);
244 std::string encFile = fileName + ".enc";
247 memset(&info, 0, sizeof(info));
248 if (stat(fileName.c_str(), &info) != 0)
251 ThrowMsg(Exceptions::InternalError,
252 "Could not access file " << fileName <<
253 "[" << DPL::GetErrnoString(error) << "]");
255 const std::size_t fileSize = info.st_size;
257 DPL::ScopedFClose inFile(openFile(fileName, "r"));
258 DPL::ScopedFClose outFile(openFile(encFile, "w"));
260 const std::size_t chunkSize = (fileSize > ENCRYPTION_CHUNK_MAX_SIZE
261 ? ENCRYPTION_CHUNK_MAX_SIZE : fileSize);
262 const int maxBlockSize = m_resEnc->GetBlockSize(chunkSize);
264 std::unique_ptr<unsigned char[]> inChunk(new unsigned char[chunkSize]);
265 std::unique_ptr<unsigned char[]> outChunk;
267 std::size_t bytesRead = 0;
268 int curBlockSize = 0;
271 bytesRead = readBytes(inChunk.get(), chunkSize, inFile.Get());
272 if (chunkSize != bytesRead)
274 curBlockSize = m_resEnc->GetBlockSize(bytesRead);
275 outChunk.reset(new unsigned char[curBlockSize]);
279 if (maxBlockSize != curBlockSize)
281 curBlockSize = maxBlockSize;
282 outChunk.reset(new unsigned char[curBlockSize]);
286 m_resEnc->EncryptChunk(inChunk.get(), outChunk.get(), bytesRead);
288 writeBytes(outChunk.get(), curBlockSize, outFile.Get());
290 } while (0 == std::feof(inFile.Get()));
292 LogDebug("File encrypted successfully");
297 LogDebug("Remove plain-text file: " << fileName);
298 if (0 != unlink(fileName.c_str()))
300 Throw(Exceptions::InternalError);
303 LogDebug("Rename encrypted file");
304 if (0 != std::rename(encFile.c_str(), fileName.c_str()))
306 Throw(Exceptions::InternalError);
309 std::string realPath = fileName;
311 m_context.locations->getTemporaryRootDir().length(),
312 m_context.locations->getSourceDir());
314 WrtDB::EncryptedFileInfo fileInfo;
315 fileInfo.fileName = DPL::FromUTF8String(realPath);
316 fileInfo.fileSize = fileSize;
318 m_context.widgetConfig.encryptedFiles.insert(fileInfo);
320 Catch (Exceptions::InternalError)
322 ReThrowMsg(Exceptions::ExtractFileFailed, fileName);
324 Catch (ResourceEncryptor::Exception::Base)
326 ReThrowMsg(Exceptions::ExtractFileFailed, fileName);
330 } //namespace WidgetInstall