#undef __USE_FILE_OFFSET64
#include <unistd.h>
-#include <string>
#include <sys/stat.h>
#include <fts.h>
#include <string.h>
#include <errno.h>
+#include <cstdio>
+
+#include <memory>
#include <dpl/log/log.h>
#include <dpl/errno_string.h>
#include <dpl/foreach.h>
+#include <dpl/scoped_fclose.h>
#include <dpl/wrt-dao-ro/global_config.h>
+#include <dpl/string.h>
#include <widget_install/job_widget_install.h>
#include <widget_install/widget_install_context.h>
using namespace WRTEncryptor;
namespace {
+const std::size_t ENCRYPTION_CHUNK_MAX_SIZE = 1024; // bytes
+
std::set<std::string>& getSupportedForEncryption()
{
static std::set<std::string> encryptSet;
}
return false;
}
+
+/**
+ * Opens a file.
+ *
+ * @param path Path to a file.
+ * @param mode Mode.
+ * @return Stream handle.
+ * @throw ExtractFileFailed If error (other than EINTR) occurs.
+ */
+FILE* openFile(const std::string& path, const std::string& mode)
+{
+ FILE* result = NULL;
+
+ do
+ {
+ result = fopen(path.c_str(), mode.c_str());
+ } while ((NULL == result) && (EINTR == errno));
+
+ if (NULL == result)
+ {
+ ThrowMsg(Jobs::WidgetInstall::Exceptions::InternalError,
+ "Could not open file " << path);
+ }
+
+ return result;
+}
+
+/**
+ * Reads bytes from a stream.
+ *
+ * @param buffer Buffer to read the bytes into.
+ * @param count Number of bytes to read.
+ * @param stream Stream to read from.
+ * @return Number of bytes read
+ * @throw ExtractFileFailed If error (other than EINTR) occurs.
+ */
+std::size_t readBytes(unsigned char* buffer, std::size_t count, FILE* stream)
+{
+ std::size_t result = std::fread(buffer,
+ sizeof(unsigned char),
+ count,
+ stream);
+
+ if (result != count)
+ {
+ int error = errno;
+ if (0 != std::ferror(stream))
+ {
+ if (EINTR != error)
+ {
+ ThrowMsg(Jobs::WidgetInstall::Exceptions::InternalError,
+ "Error while reading data" <<
+ " [" << DPL::GetErrnoString(error) << "]");
+ }
+ }
+ }
+
+ return result;
+}
+
+/**
+ * Writes bytes to a stream.
+ *
+ * @param buffer Data to write.
+ * @param count Number of bytes.
+ * @param stream Stream to write to.
+ * @throw ExtractFileFailed If error (other than EINTR) occurs.
+ */
+void writeBytes(unsigned char* buffer, std::size_t count, FILE* stream)
+{
+ std::size_t bytesWritten = 0;
+ std::size_t bytesToWrite = 0;
+ do
+ {
+ bytesToWrite = count - bytesWritten;
+ bytesWritten = std::fwrite(buffer + bytesWritten,
+ sizeof(unsigned char),
+ count - bytesWritten,
+ stream);
+ if ((bytesWritten != bytesToWrite) && (EINTR != errno))
+ {
+ int error = errno;
+ ThrowMsg(Jobs::WidgetInstall::Exceptions::InternalError,
+ "Error while writing data" <<
+ " [" << DPL::GetErrnoString(error) << "]");
+ }
+ } while ((bytesWritten != bytesToWrite) && (EINTR == errno));
+}
}
namespace Jobs {
namespace WidgetInstall {
TaskEncryptResource::TaskEncryptResource(InstallerContext& context) :
DPL::TaskDecl<TaskEncryptResource>(this),
- m_context(context)
+ m_context(context),
+ m_resEnc(NULL)
{
AddStep(&TaskEncryptResource::StepEncryptResource);
}
LogDebug("Step Encrypt resource");
m_resEnc = new ResourceEncryptor;
m_resEnc->CreateEncryptionKey(DPL::ToUTF8String(m_context.
- widgetConfig.pkgName));
+ widgetConfig.tzAppid));
EncryptDirectory(m_context.locations->getTemporaryRootDir());
+ m_context.job->UpdateProgress(
+ InstallerContext::INSTALL_ECRYPTION_FILES,
+ "Ecrypt resource files");
}
void TaskEncryptResource::EncryptDirectory(std::string path)
{
FTS *fts;
FTSENT *ftsent;
- char * const paths[] = {const_cast<char * const>(path.c_str()), NULL};
+ char * const paths[] = { const_cast<char * const>(path.c_str()), NULL };
- if ((fts = fts_open(paths, FTS_PHYSICAL|FTS_NOCHDIR, NULL)) == NULL) {
+ if ((fts = fts_open(paths, FTS_PHYSICAL | FTS_NOCHDIR, NULL)) == NULL) {
//ERROR
int error = errno;
LogWarning(__PRETTY_FUNCTION__ << ": fts_open failed with error: "
- << strerror(error));
+ << strerror(error));
ThrowMsg(Exceptions::InternalError, "Error reading directory: "
- << path);
+ << path);
}
while ((ftsent = fts_read(fts)) != NULL) {
switch (ftsent->fts_info) {
- case FTS_DP:
- case FTS_DC:
- case FTS_D:
- case FTS_DEFAULT:
- case FTS_SLNONE:
- //directories, non-regular files, dangling symbolic links
- break;
- case FTS_F:
- case FTS_NSOK:
- case FTS_SL:
- //regular files and other objects that can be counted
- if (isSupportedForEncryption(ftsent->fts_path)) {
- EncryptFile(ftsent->fts_path);
- }
- break;
- case FTS_NS:
- case FTS_DOT:
- case FTS_DNR:
- case FTS_ERR:
- default:
- LogWarning(__PRETTY_FUNCTION__
- << ": traversal failed on file: "
- << ftsent->fts_path
- << " with error: "
- << strerror(ftsent->fts_errno));
- ThrowMsg(Exceptions::InternalError, "Error reading file");
+ case FTS_DP:
+ case FTS_DC:
+ case FTS_D:
+ case FTS_DEFAULT:
+ case FTS_SLNONE:
+ //directories, non-regular files, dangling symbolic links
+ break;
+ case FTS_F:
+ case FTS_NSOK:
+ case FTS_SL:
+ //regular files and other objects that can be counted
+ if (isSupportedForEncryption(ftsent->fts_path)) {
+ EncryptFile(ftsent->fts_path);
+ }
+ break;
+ case FTS_NS:
+ case FTS_DOT:
+ case FTS_DNR:
+ case FTS_ERR:
+ default:
+ LogWarning(__PRETTY_FUNCTION__
+ << ": traversal failed on file: "
+ << ftsent->fts_path
+ << " with error: "
+ << strerror(ftsent->fts_errno));
+ ThrowMsg(Exceptions::InternalError, "Error reading file");
+ break;
}
}
if (fts_close(fts) == -1) {
int error = errno;
LogWarning(__PRETTY_FUNCTION__ << ": fts_close failed with error: "
- << strerror(error));
+ << strerror(error));
}
}
void TaskEncryptResource::EncryptFile(const std::string &fileName)
{
- Try
+ try
{
- LogDebug("Need to ecnrypt file Name " << fileName);
+ LogDebug("Encrypt file: " << fileName);
std::string encFile = fileName + ".enc";
- struct stat buf;
- int ret = stat(fileName.c_str(), &buf);
- if(ret == 0) {
- size_t fileSize = buf.st_size;
+ struct stat info;
+ memset(&info, 0, sizeof(info));
+ if (stat(fileName.c_str(), &info) != 0)
+ {
+ int error = errno;
+ ThrowMsg(Exceptions::InternalError,
+ "Could not access file " << fileName <<
+ "[" << DPL::GetErrnoString(error) << "]");
+ }
+ const std::size_t fileSize = info.st_size;
- FILE* resFp = fopen(fileName.c_str(), "r");
- if ( NULL == resFp) {
- LogError("Couldnot open file : " << fileName);
- return;
- }
+ DPL::ScopedFClose inFile(openFile(fileName, "r"));
+ DPL::ScopedFClose outFile(openFile(encFile, "w"));
- int blockSize = m_resEnc->GetBlockSize(fileSize);
- LogDebug("Get block size : " << blockSize);
+ const std::size_t chunkSize = (fileSize > ENCRYPTION_CHUNK_MAX_SIZE
+ ? ENCRYPTION_CHUNK_MAX_SIZE : fileSize);
+ const int maxBlockSize = m_resEnc->GetBlockSize(chunkSize);
- unsigned char readBuf[fileSize];
- unsigned char outEncBuf[blockSize];
- memset(readBuf, 0, fileSize);
- memset(outEncBuf, 0, blockSize);
+ std::unique_ptr<unsigned char[]> inChunk(new unsigned char[chunkSize]);
+ std::unique_ptr<unsigned char[]> outChunk;
- ret = fread(readBuf, sizeof(unsigned char), fileSize, resFp);
- if (ret!=fileSize){
- LogError("Failed to read ecryption buffer with error: " << strerror(errno) );
- fclose(resFp);
- return;
+ std::size_t bytesRead = 0;
+ int curBlockSize = 0;
+ do
+ {
+ bytesRead = readBytes(inChunk.get(), chunkSize, inFile.Get());
+ if (chunkSize != bytesRead)
+ {
+ curBlockSize = m_resEnc->GetBlockSize(bytesRead);
+ outChunk.reset(new unsigned char[curBlockSize]);
}
-
- m_resEnc->EncryptChunk(readBuf, outEncBuf, fileSize);
-
- FILE* encFp = fopen(encFile.c_str(), "w");
- if (NULL == encFp) {
- LogError("Failed to open ecryption file");
- fclose(resFp);
- return;
+ else
+ {
+ if (maxBlockSize != curBlockSize)
+ {
+ curBlockSize = maxBlockSize;
+ outChunk.reset(new unsigned char[curBlockSize]);
+ }
}
- fwrite(outEncBuf, sizeof(unsigned char), blockSize, encFp);
- fclose(resFp);
- fclose(encFp);
+ m_resEnc->EncryptChunk(inChunk.get(), outChunk.get(), bytesRead);
- LogDebug("Success to encrypt file");
- LogDebug("Remove unecrypted file : " << fileName);
+ writeBytes(outChunk.get(), curBlockSize, outFile.Get());
- unlink(fileName.c_str());
- if ((rename(encFile.c_str(), fileName.c_str())) != 0) {
- ThrowMsg(Exceptions::ExtractFileFailed, fileName);
- }
+ } while (0 == std::feof(inFile.Get()));
- std::string realPath = fileName;
- realPath.replace(0, m_context.locations->getTemporaryRootDir().length(),
- m_context.locations->getSourceDir());
+ LogDebug("File encrypted successfully");
- WrtDB::EncryptedFileInfo info;
- info.fileName = DPL::FromUTF8String(realPath);
- info.fileSize = fileSize;
+ outFile.Reset();
+ inFile.Reset();
- m_context.widgetConfig.encryptedFiles.insert(info);
+ LogDebug("Remove plain-text file: " << fileName);
+ if (0 != unlink(fileName.c_str()))
+ {
+ Throw(Exceptions::InternalError);
}
+
+ LogDebug("Rename encrypted file");
+ if (0 != std::rename(encFile.c_str(), fileName.c_str()))
+ {
+ Throw(Exceptions::InternalError);
+ }
+
+ std::string realPath = fileName;
+ realPath.replace(0,
+ m_context.locations->getTemporaryRootDir().length(),
+ m_context.locations->getSourceDir());
+
+ WrtDB::EncryptedFileInfo fileInfo;
+ fileInfo.fileName = DPL::FromUTF8String(realPath);
+ fileInfo.fileSize = fileSize;
+
+ m_context.widgetConfig.encryptedFiles.insert(fileInfo);
+ }
+ Catch (Exceptions::InternalError)
+ {
+ ReThrowMsg(Exceptions::ExtractFileFailed, fileName);
}
- Catch(ResourceEncryptor::Exception::Base)
+ Catch (ResourceEncryptor::Exception::Base)
{
ReThrowMsg(Exceptions::ExtractFileFailed, fileName);
}
}
+
} //namespace WidgetInstall
} //namespace Jobs