* @version 1.0
* @brief Implementation file for installer task database updating
*/
+#include <unistd.h>
#include <sys/stat.h>
+#include <dirent.h>
#include <widget_install/task_file_manipulation.h>
#include <widget_install/job_widget_install.h>
#include <widget_install/widget_install_errors.h>
#include <widget_install/widget_install_context.h>
+#include <widget_install/directory_api.h>
#include <dpl/utils/wrt_utility.h>
#include <dpl/foreach.h>
#include <dpl/log/log.h>
#include <dpl/assert.h>
+#include <dpl/errno_string.h>
+#include <dpl/utils/folder_size.h>
+#include <dpl/wrt-dao-ro/global_config.h>
#include <string>
+#include <fstream>
+#include <widget_install_to_external.h>
+
+#define WEBAPP_DEFAULT_UID 5000
+#define WEBAPP_DEFAULT_GID 5000
+
+namespace {
+const mode_t PRIVATE_STORAGE_MODE = 0700;
+const mode_t SHARE_MODE = 0705;
+}
using namespace WrtDB;
+namespace {
+const char* GLIST_RES_DIR = "res";
+
+bool _FolderCopy(std::string source, std::string dest)
+{
+ DIR* dir = opendir(source.c_str());
+ if (NULL == dir) {
+ return false;
+ }
+
+ struct dirent dEntry;
+ struct dirent *dEntryResult;
+ int return_code;
+
+ do {
+ struct stat statInfo;
+ return_code = readdir_r(dir, &dEntry, &dEntryResult);
+ if (dEntryResult != NULL && return_code == 0) {
+ std::string fileName = dEntry.d_name;
+ std::string fullName = source + "/" + fileName;
+
+ if (stat(fullName.c_str(), &statInfo) != 0) {
+ closedir(dir);
+ return false;
+ }
+
+ if (S_ISDIR(statInfo.st_mode)) {
+ if (("." == fileName) || (".." == fileName)) {
+ continue;
+ }
+ std::string destFolder = dest + "/" + fileName;
+ WrtUtilMakeDir(destFolder);
+
+ if (!_FolderCopy(fullName, destFolder)) {
+ closedir(dir);
+ return false;
+ }
+ }
+
+ std::string destFile = dest + "/" + fileName;
+ std::ifstream infile(fullName);
+ std::ofstream outfile(destFile);
+ outfile << infile.rdbuf();
+ outfile.close();
+ infile.close();
+ }
+ } while (dEntryResult != NULL && return_code == 0);
+ closedir(dir);
+ return true;
+}
+
+void changeOwnerForDirectory(std::string storagePath) {
+ if (euidaccess(storagePath.c_str(), F_OK) != 0) {
+ if (!WrtUtilMakeDir(storagePath, PRIVATE_STORAGE_MODE)) {
+ LogError("Failed to create directory for private storage");
+ ThrowMsg(Jobs::WidgetInstall::Exceptions::FileOperationFailed,
+ "Failed to create directory for private storage");
+ }
+ // '5000' is default uid, gid for applications.
+ // So installed applications should be launched as process of uid
+ // '5000'.
+ // the process can access private directory 'data' of itself.
+ if (chown(storagePath.c_str(),
+ WEBAPP_DEFAULT_UID,
+ WEBAPP_DEFAULT_GID) != 0)
+ {
+ ThrowMsg(Jobs::WidgetInstall::Exceptions::FileOperationFailed,
+ "Chown to invaild user");
+ }
+ } else if (euidaccess(storagePath.c_str(), W_OK | R_OK | X_OK) == 0) {
+ LogInfo("Private storage already exists.");
+ // Even if private directory already is created, private dircetory
+ // should change owner.
+ if (chown(storagePath.c_str(),
+ WEBAPP_DEFAULT_UID,
+ WEBAPP_DEFAULT_GID) != 0)
+ {
+ ThrowMsg(Jobs::WidgetInstall::Exceptions::FileOperationFailed,
+ "Chown to invaild user");
+ }
+ if (chmod(storagePath.c_str(), PRIVATE_STORAGE_MODE) != 0) {
+ ThrowMsg(Jobs::WidgetInstall::Exceptions::FileOperationFailed,
+ "chmod to 0700");
+ }
+ } else {
+ ThrowMsg(Jobs::WidgetInstall::Exceptions::FileOperationFailed,
+ "No access to private storage.");
+ }
+}
+}
+
namespace Jobs {
namespace WidgetInstall {
TaskFileManipulation::TaskFileManipulation(InstallerContext& context) :
DPL::TaskDecl<TaskFileManipulation>(this),
- m_context(context)
+ m_context(context),
+ m_extHandle(NULL)
{
- AddStep(&TaskFileManipulation::StepCreateDirs);
- AddStep(&TaskFileManipulation::StepRenamePath);
+ if (INSTALL_LOCATION_TYPE_EXTERNAL !=
+ m_context.locationType)
+ {
+ AddStep(&TaskFileManipulation::StepCreateDirs);
+ if (m_context.widgetConfig.packagingType !=
+ WrtDB::PKG_TYPE_DIRECTORY_WEB_APP)
+ {
+ AddStep(&TaskFileManipulation::StepRenamePath);
+ AddAbortStep(&TaskFileManipulation::StepAbortRenamePath);
+ }
+ AddStep(&TaskFileManipulation::StepCreatePrivateStorageDir);
+ AddStep(&TaskFileManipulation::StepCreateSharedFolder);
+ AddStep(&TaskFileManipulation::StepLinkForPreload);
+
+ } else {
+ AddStep(&TaskFileManipulation::StepPrepareExternalDir);
+ AddStep(&TaskFileManipulation::StepInstallToExternal);
+ AddStep(&TaskFileManipulation::StepCreatePrivateStorageDir);
+ AddStep(&TaskFileManipulation::StepCreateSharedFolder);
- AddAbortStep(&TaskFileManipulation::StepAbortRenamePath);
+ AddAbortStep(&TaskFileManipulation::StepAbortCreateExternalDir);
+ }
}
void TaskFileManipulation::StepCreateDirs()
{
std::string widgetPath;
- DPL::OptionalString pkgname = m_context.widgetConfig.pkgname;
- if (pkgname.IsNull()) {
- ThrowMsg(Exceptions::InternalError, "No Package name exists.");
- }
widgetPath = m_context.locations->getPackageInstallationDir();
std::string widgetBinPath = m_context.locations->getBinaryDir();
std::string widgetSrcPath = m_context.locations->getSourceDir();
- _WrtMakeDir(widgetPath.c_str(), 0755, WRT_FILEUTILS_RECUR);
+ WrtUtilMakeDir(widgetPath);
// If package type is widget with osp service, we don't need to make bin
// and src directory
- if (m_context.widgetConfig.pType == PKG_TYPE_TIZEN_WITHSVCAPP) {
+ if (m_context.widgetConfig.packagingType == PKG_TYPE_HYBRID_WEB_APP) {
LogDebug("Doesn't need to create resource directory");
} else {
LogDebug("Create resource directory");
- _WrtMakeDir(widgetBinPath.c_str(), 0755, WRT_FILEUTILS_RECUR);
- _WrtMakeDir(widgetSrcPath.c_str(), 0755, WRT_FILEUTILS_RECUR);
+ WrtUtilMakeDir(widgetBinPath);
+ WrtUtilMakeDir(widgetSrcPath);
+ if (m_context.mode.installTime == InstallMode::InstallTime::PRELOAD) {
+ std::string userWidgetDir = m_context.locations->getUserDataRootDir();
+ WrtUtilMakeDir(userWidgetDir);
+ }
}
m_context.job->UpdateProgress(
"Widget Directory Created");
}
+void TaskFileManipulation::StepCreatePrivateStorageDir()
+{
+ std::string storagePath = m_context.locations->getPrivateStorageDir();
+ LogDebug("Create private storage directory : " <<
+ m_context.locations->getPrivateStorageDir());
+
+ if (m_context.isUpdateMode) { //update
+ std::string backData = m_context.locations->getBackupPrivateDir();
+ LogDebug("copy private storage " << backData << " to " << storagePath);
+ WrtUtilMakeDir(storagePath);
+ if (!DirectoryApi::DirectoryCopy(backData, storagePath)) {
+ LogError("Failed to rename " << backData << " to " << storagePath);
+ ThrowMsg(Exceptions::BackupFailed,
+ "Error occurs copy private strage files");
+ }
+ }
+ changeOwnerForDirectory(storagePath);
+}
+
void TaskFileManipulation::StepRenamePath()
{
std::string instDir;
- DPL::OptionalString pkgname = m_context.widgetConfig.pkgname;
- if (pkgname.IsNull()) {
- ThrowMsg(Exceptions::InternalError, "No Package name exists.");
- }
- if (m_context.widgetConfig.pType == PKG_TYPE_TIZEN_WITHSVCAPP) {
+ if (m_context.widgetConfig.packagingType == PKG_TYPE_HYBRID_WEB_APP) {
instDir = m_context.locations->getPackageInstallationDir();
} else {
instDir = m_context.locations->getSourceDir();
}
LogDebug("Copy file from temp directory to " << instDir);
- if (!_WrtUtilRemoveDir(instDir.c_str())) {
+ if (!WrtUtilRemove(instDir)) {
ThrowMsg(Exceptions::RemovingFolderFailure,
- "Error occurs during removing existing folder");
+ "Error occurs during removing existing folder");
}
- if (!(rename(m_context.locations->getTemporaryPackageDir().c_str(), instDir.c_str()) == 0)) {
- ThrowMsg(Exceptions::UnknownError,
- "Error occurs during renaming widget folder");
+ if (!(rename(m_context.locations->getTemporaryPackageDir().c_str(),
+ instDir.c_str()) == 0))
+ {
+ ThrowMsg(Exceptions::FileOperationFailed,
+ "Error occurs during renaming widget folder");
}
-
m_context.job->UpdateProgress(
InstallerContext::INSTALL_RENAME_PATH,
"Widget Rename path Finished");
}
+void TaskFileManipulation::StepLinkForPreload()
+{
+ if (m_context.mode.rootPath == InstallMode::RootPath::RO) {
+ std::string srcDir = m_context.locations->getUserDataRootDir() +
+ WrtDB::GlobalConfig::GetWidgetSrcPath();
+
+ if (0 != access(srcDir.c_str(), F_OK)) {
+ LogDebug("Make symbolic name for preaload app" <<
+ m_context.locations->getSourceDir() << " to " << srcDir);
+ std::string resDir = m_context.locations->getUserDataRootDir() +
+ "/res";
+
+ WrtUtilMakeDir(resDir);
+ if (symlink(m_context.locations->getSourceDir().c_str(), srcDir.c_str()) != 0)
+ {
+ int error = errno;
+ if (error)
+ LogPedantic("Failed to make a symbolic name for a file "
+ << "[" << DPL::GetErrnoString(error) << "]");
+ ThrowMsg(Exceptions::FileOperationFailed,
+ "Symbolic link creating is not done.");
+ }
+ }
+
+ /* link for data directory */
+ std::string storagePath = m_context.locations->getPrivateStorageDir();
+ std::string dataDir = m_context.locations->getPackageInstallationDir() +
+ "/" + WrtDB::GlobalConfig::GetWidgetPrivateStoragePath();
+ if (0 != access(dataDir.c_str(), F_OK)) {
+ LogDebug("Make symbolic name for preaload app " <<
+ storagePath << " to " << dataDir);
+
+ if (symlink(storagePath.c_str(), dataDir.c_str()) != 0)
+ {
+ int error = errno;
+ if (error)
+ LogPedantic("Failed to make a symbolic name for a file "
+ << "[" << DPL::GetErrnoString(error) << "]");
+ ThrowMsg(Exceptions::FileOperationFailed,
+ "Symbolic link creating is not done.");
+ }
+ changeOwnerForDirectory(dataDir);
+ }
+
+ if (m_context.widgetConfig.packagingType != PKG_TYPE_HYBRID_WEB_APP) {
+ std::string widgetBinPath = m_context.locations->getBinaryDir();
+ std::string userBinPath = m_context.locations->getUserBinaryDir();
+ LogDebug("Make symbolic link for preload app " << widgetBinPath <<
+ " to " << userBinPath);
+ if (symlink(widgetBinPath.c_str(), userBinPath.c_str()) != 0)
+ {
+ int error = errno;
+ if (error)
+ LogPedantic("Failed to make a symbolic name for a file "
+ << "[" << DPL::GetErrnoString(error) << "]");
+ ThrowMsg(Exceptions::FileOperationFailed,
+ "Symbolic link creating is not done.");
+ }
+
+ }
+ }
+}
+
void TaskFileManipulation::StepAbortRenamePath()
{
LogDebug("[Rename Widget Path] Aborting.... (Rename path)");
- Assert(!!m_context.widgetHandle);
std::string widgetPath;
- if (m_context.widgetConfig.pType == PKG_TYPE_TIZEN_WITHSVCAPP) {
+ if (m_context.widgetConfig.packagingType != PKG_TYPE_HYBRID_WEB_APP) {
widgetPath = m_context.locations->getPackageInstallationDir();
- } else {
- widgetPath = m_context.locations->getSourceDir();
+ if (!WrtUtilRemove(widgetPath)) {
+ ThrowMsg(Exceptions::RemovingFolderFailure,
+ "Error occurs during removing existing folder");
+ }
+ // Remove user data directory if preload web app.
+ std::string userData = m_context.locations->getUserDataRootDir();
+ if (0 == access(userData.c_str(), F_OK)) {
+ if (!WrtUtilRemove(userData)) {
+ ThrowMsg(Exceptions::RemovingFolderFailure,
+ "Error occurs during removing user data directory");
+ }
+ }
+
+ }
+ LogDebug("Rename widget path sucessful!");
+}
+
+void TaskFileManipulation::StepPrepareExternalDir()
+{
+ LogDebug("Step prepare to install in exernal directory");
+ Try {
+ std::string pkgid =
+ DPL::ToUTF8String(m_context.widgetConfig.tzPkgid);
+
+ WidgetInstallToExtSingleton::Instance().initialize(pkgid);
+
+ size_t totalSize =
+ Utils::getFolderSize(m_context.locations->getTemporaryPackageDir());
+
+ int folderSize = (int)(totalSize / (1024 * 1024)) + 1;
+
+ GList *list = NULL;
+ app2ext_dir_details* dirDetail = NULL;
+
+ dirDetail = (app2ext_dir_details*) calloc(1,
+ sizeof(
+ app2ext_dir_details));
+ if (NULL == dirDetail) {
+ ThrowMsg(Exceptions::ErrorExternalInstallingFailure,
+ "error in app2ext");
+ }
+ dirDetail->name = strdup(GLIST_RES_DIR);
+ dirDetail->type = APP2EXT_DIR_RO;
+ list = g_list_append(list, dirDetail);
+
+ if (m_context.isUpdateMode) {
+ WidgetInstallToExtSingleton::Instance().preUpgrade(list,
+ folderSize);
+ } else {
+ WidgetInstallToExtSingleton::Instance().preInstallation(list,
+ folderSize);
+ }
+ free(dirDetail);
+ g_list_free(list);
+
+ /* make bin directory */
+ std::string widgetBinPath = m_context.locations->getBinaryDir();
+ WrtUtilMakeDir(widgetBinPath);
}
- struct stat fileInfo;
- if (stat(widgetPath.c_str(), &fileInfo) != 0) {
- LogError("Failed to get widget file path : " << widgetPath);
- return;
+ Catch(WidgetInstallToExt::Exception::ErrorInstallToExt)
+ {
+ ReThrowMsg(Exceptions::ErrorExternalInstallingFailure,
+ "Error during \
+ create external folder ");
}
+}
- if (!(rename(widgetPath.c_str(), m_context.locations->getTemporaryPackageDir().c_str()) == 0)) {
- LogError("Failed to rename");
+void TaskFileManipulation::StepInstallToExternal()
+{
+ LogDebug("StepInstallExternal");
+ if (!WrtUtilMakeDir(m_context.locations->getSourceDir())) {
+ ThrowMsg(Exceptions::ErrorExternalInstallingFailure,
+ "To make src \
+ directory failed");
+ }
+
+ LogDebug("Resource move to external storage " <<
+ m_context.locations->getSourceDir());
+ if (!_FolderCopy(m_context.locations->getTemporaryPackageDir(),
+ m_context.locations->getSourceDir()))
+ {
+ ThrowMsg(Exceptions::ErrorExternalInstallingFailure,
+ "Error occurs during renaming widget folder");
+ }
+}
+
+void TaskFileManipulation::StepAbortCreateExternalDir()
+{
+ LogError("Abort StepAbortCreateExternalDir");
+ if (m_context.isUpdateMode) {
+ WidgetInstallToExtSingleton::Instance().postUpgrade(false);
+ } else {
+ WidgetInstallToExtSingleton::Instance().postInstallation(false);
+ }
+ WidgetInstallToExtSingleton::Instance().deinitialize();
+}
+
+void TaskFileManipulation::StepCreateSharedFolder()
+{
+ LogDebug("StepCreateSharedFolder");
+ std::string sharedPath = m_context.locations->getSharedRootDir();
+ LogDebug("Create shared directory : " <<
+ m_context.locations->getSharedRootDir());
+
+ WrtUtilMakeDir(sharedPath);
+
+ if (m_context.isUpdateMode) { //update
+ std::string backData = m_context.locations->getBackupSharedDir();
+ LogDebug("copy shared storage " << backData << " to " << sharedPath);
+ if (!DirectoryApi::DirectoryCopy(backData, sharedPath)) {
+ LogError("Failed to rename " << backData << " to " << sharedPath);
+ ThrowMsg(Exceptions::BackupFailed,
+ "Error occurs copy shared strage files");
+ }
+ } else {
+ WrtUtilMakeDir(m_context.locations->getSharedResourceDir());
+ WrtUtilMakeDir(m_context.locations->getSharedDataDir());
+ WrtUtilMakeDir(m_context.locations->getSharedTrustedDir());
}
- LogDebug("Rename widget path sucessful!");
}
} //namespace WidgetInstall
} //namespace Jobs