ae1128ecff5fec056ddcb9fd2461558644d6ea47
[framework/web/wrt-installer.git] / src_wearable / jobs / widget_install / task_file_manipulation.cpp
1 /*
2  * Copyright (c) 2010 Samsung Electronics Co., Ltd All Rights Reserved
3  *
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
7  *
8  *        http://www.apache.org/licenses/LICENSE-2.0
9  *
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.
15  */
16 /**
17  * @file    task_db_update.cpp
18  * @author  Lukasz Wrzosek(l.wrzosek@samsung.com)
19  * @version 1.0
20  * @brief   Implementation file for installer task database updating
21  */
22 #include <unistd.h>
23 #include <sys/stat.h>
24 #include <dirent.h>
25 #include <string>
26 #include <fstream>
27 #include <vconf.h>
28
29 #include <widget_install/task_file_manipulation.h>
30 #include <widget_install/job_widget_install.h>
31 #include <widget_install/widget_install_errors.h>
32 #include <widget_install/widget_install_context.h>
33 #include <widget_install/directory_api.h>
34 #include <dpl/utils/wrt_utility.h>
35 #include <dpl/utils/path.h>
36 #include <dpl/foreach.h>
37 #include <dpl/assert.h>
38 #include <dpl/errno_string.h>
39 #include <dpl/utils/folder_size.h>
40 #include <dpl/wrt-dao-ro/global_config.h>
41
42 #include <widget_install_to_external.h>
43 #include <installer_log.h>
44 #include <widget_unzip.h>
45
46 #define WEBAPP_DEFAULT_UID  5000
47 #define WEBAPP_DEFAULT_GID  5000
48
49 namespace {
50 const mode_t PRIVATE_STORAGE_MODE = 0700;
51 const mode_t SHARED_STORAGE_MODE = 0755;
52 }
53
54 using namespace WrtDB;
55
56 namespace {
57 const char* GLIST_RES_DIR = "res";
58
59 bool _FolderCopy(std::string source, std::string dest)
60 {
61     DIR* dir = opendir(source.c_str());
62     if (NULL == dir) {
63         return false;
64     }
65
66     struct dirent dEntry;
67     struct dirent *dEntryResult;
68     int return_code;
69
70     do {
71         struct stat statInfo;
72         return_code = readdir_r(dir, &dEntry, &dEntryResult);
73         if (dEntryResult != NULL && return_code == 0) {
74             std::string fileName = dEntry.d_name;
75             std::string fullName = source + "/" + fileName;
76
77             if (stat(fullName.c_str(), &statInfo) != 0) {
78                 closedir(dir);
79                 return false;
80             }
81
82             if (S_ISDIR(statInfo.st_mode)) {
83                 if (("." == fileName) || (".." == fileName)) {
84                     continue;
85                 }
86                 std::string destFolder = dest + "/" + fileName;
87                 WrtUtilMakeDir(destFolder);
88
89                 if (!_FolderCopy(fullName, destFolder)) {
90                     closedir(dir);
91                     return false;
92                 }
93             }
94
95             std::string destFile = dest + "/" + fileName;
96             std::ifstream infile(fullName);
97             std::ofstream outfile(destFile);
98             outfile << infile.rdbuf();
99             outfile.close();
100             infile.close();
101         }
102     } while (dEntryResult != NULL && return_code == 0);
103     closedir(dir);
104     return true;
105 }
106 }
107
108 namespace Jobs {
109 namespace WidgetInstall {
110 TaskFileManipulation::TaskFileManipulation(InstallerContext& context) :
111     DPL::TaskDecl<TaskFileManipulation>(this),
112     m_context(context),
113     m_extHandle(NULL)
114 {
115     AddStep(&TaskFileManipulation::StartStep);
116     AddStep(&TaskFileManipulation::StepCheckInstallLocation);
117     AddStep(&TaskFileManipulation::StepPrepareRootDirectory);
118     if (m_context.mode.extension != InstallMode::ExtensionType::DIR)
119     {
120         AddStep(&TaskFileManipulation::StepUnzipWgtFile);
121     }
122     AddStep(&TaskFileManipulation::EndStep);
123
124     AddAbortStep(&TaskFileManipulation::StepAbortPrepareRootDirectory);
125 }
126
127 void TaskFileManipulation::StepCheckInstallLocation()
128 {
129     _D("StepCheckInstallLocation");
130     if (m_context.mode.rootPath == InstallMode::RootPath::RO) {
131         m_context.locationType = INSTALL_LOCATION_TYPE_INTERNAL_ONLY;
132         return;
133     }
134
135     // If webapp is hybrid app, it should be installed to internal storage.
136     // Because Service app should be installed to internal.
137     if (m_context.widgetConfig.packagingType == PKG_TYPE_HYBRID_WEB_APP) {
138         m_context.locationType = INSTALL_LOCATION_TYPE_INTERNAL_ONLY;
139         return;
140     }
141
142     std::string installedPath = WrtDB::GlobalConfig::GetUserInstalledWidgetPath();
143     WidgetUnzip wgtUnzip(m_context.requestedPath);
144
145     if (m_context.locationType == INSTALL_LOCATION_TYPE_AUTO) {
146         int storage = 0;
147         // vconf_get_int(VCONFKEY_SETAPPL_DEFAULT_MEM_INSTALL_APPLICATIONS_INT)
148         // 0 : phone internal memory
149         // 1 : SD card
150         if (vconf_get_int(VCONFKEY_SETAPPL_DEFAULT_MEM_INSTALL_APPLICATIONS_INT,
151                     &storage)) {
152             _E("vconf_get_int(VCONFKEY_SETAPPL_DEFAULT_MEM_INSTALL_APPLICATIONS_INT) \
153                     failed.");
154         }
155         _D("default setting : storage [%d]", storage);
156         if (storage) {
157             m_context.locationType = INSTALL_LOCATION_TYPE_PREFER_EXTERNAL;
158         } else {
159             m_context.locationType = INSTALL_LOCATION_TYPE_INTERNAL_ONLY;
160             if(!wgtUnzip.checkAvailableSpace(installedPath)) {
161                 m_context.locationType = INSTALL_LOCATION_TYPE_PREFER_EXTERNAL;
162             }
163         }
164     }
165
166     if (m_context.locationType == INSTALL_LOCATION_TYPE_PREFER_EXTERNAL) {
167         int mmcStatus;
168         if (vconf_get_int(VCONFKEY_SYSMAN_MMC_STATUS, &mmcStatus)) {
169             _E("vconf_get_int(VCONFKEY_SYSMAN_MMC_STATUS) failed.");
170             mmcStatus = VCONFKEY_SYSMAN_MMC_INSERTED_NOT_MOUNTED;
171         }
172
173         if (VCONFKEY_SYSMAN_MMC_MOUNTED != mmcStatus) {
174             _D("mmcStatus is MMC_REMOVED or NOT_MOUNTED.");
175             m_context.locationType = INSTALL_LOCATION_TYPE_INTERNAL_ONLY;
176         }
177     }
178
179     if (m_context.locationType == INSTALL_LOCATION_TYPE_INTERNAL_ONLY) {
180         if(!wgtUnzip.checkAvailableSpace(installedPath)) {
181             ThrowMsg(Exceptions::OutOfStorageFailed, "There is no space for installation");
182         }
183     }
184 }
185
186 void TaskFileManipulation::StepPrepareRootDirectory()
187 {
188     if (m_context.locationType == INSTALL_LOCATION_TYPE_PREFER_EXTERNAL) {
189         prepareExternalDir();
190     } else {
191         std::string widgetPath = m_context.locations->getPackageInstallationDir();
192         std::string widgetBinPath = m_context.locations->getBinaryDir();
193         std::string widgetSrcPath = m_context.locations->getSourceDir();
194
195         if (!m_context.isUpdateMode) {
196             _D("Remove existing directory : %s", widgetPath.c_str());
197             DPL::Utils::TryRemove(DPL::Utils::Path(widgetPath));
198         }
199         WrtUtilMakeDir(widgetPath);
200
201         _D("Create resource directory");
202         WrtUtilMakeDir(widgetBinPath);
203         WrtUtilMakeDir(widgetSrcPath);
204     }
205
206     m_context.job->UpdateProgress(
207         InstallerContext::INSTALL_DIR_CREATE,
208         "Widget Directory Created");
209 }
210
211 void TaskFileManipulation::StepUnzipWgtFile()
212 {
213     if (m_context.widgetConfig.packagingType != PKG_TYPE_HOSTED_WEB_APP) {
214         std::string instDir;
215         if (m_context.widgetConfig.packagingType == PKG_TYPE_HYBRID_WEB_APP) {
216             instDir = m_context.locations->getPackageInstallationDir();
217         } else {
218             instDir = m_context.locations->getSourceDir();
219         }
220
221         _D("unzip file to %s", instDir.c_str());
222
223         WidgetUnzip wgtUnzip(m_context.requestedPath);
224         wgtUnzip.unzipWgtFile(instDir);
225     } else {
226         _D("From browser installation - unzip is not done");
227     }
228
229     m_context.job->UpdateProgress(
230         InstallerContext::INSTALL_UNZIP_WGT,
231         "Unzip Wgt file");
232 }
233
234 void TaskFileManipulation::StepAbortPrepareRootDirectory()
235 {
236     _D("[Create Root Directory]  Aborting.... (Rename path)");
237     if (m_context.locationType == INSTALL_LOCATION_TYPE_PREFER_EXTERNAL) {
238         if (m_context.isUpdateMode) {
239             WidgetInstallToExtSingleton::Instance().postUpgrade(false);
240         } else {
241             WidgetInstallToExtSingleton::Instance().postInstallation(false);
242         }
243         WidgetInstallToExtSingleton::Instance().deinitialize();
244     } else {
245         std::string widgetPath;
246         widgetPath = m_context.locations->getPackageInstallationDir();
247         if (!WrtUtilRemove(widgetPath)) {
248             _E("Error occurs during removing existing folder");
249         }
250         // Remove user data directory if preload web app.
251         std::string userData = m_context.locations->getUserDataRootDir();
252         if (0 == access(userData.c_str(), F_OK)) {
253             if (!WrtUtilRemove(userData)) {
254                 _E("Error occurs during removing user data directory");
255             }
256         }
257     }
258 }
259
260 void TaskFileManipulation::prepareExternalDir()
261 {
262     _D("Step prepare to install in exernal directory");
263     Try {
264         std::string pkgid =
265             DPL::ToUTF8String(m_context.widgetConfig.tzPkgid);
266
267         WidgetInstallToExtSingleton::Instance().initialize(pkgid);
268
269         std::unique_ptr<DPL::ZipInput> zipFile(new
270                 DPL::ZipInput(m_context.requestedPath));
271         double unzipSize = zipFile->GetTotalUncompressedSize();
272         int folderSize = (int)(unzipSize / (1024 * 1024)) + 1;
273
274         GList *list = NULL;
275         app2ext_dir_details* dirDetail = NULL;
276
277         dirDetail = (app2ext_dir_details*) calloc(1,
278                 sizeof(
279                     app2ext_dir_details));
280         if (NULL == dirDetail) {
281             ThrowMsg(Exceptions::ErrorExternalInstallingFailure,
282                     "error in app2ext");
283         }
284         dirDetail->name = strdup(GLIST_RES_DIR);
285         dirDetail->type = APP2EXT_DIR_RO;
286         list = g_list_append(list, dirDetail);
287
288         if (m_context.isUpdateMode) {
289             WidgetInstallToExtSingleton::Instance().preUpgrade(list,
290                                                                folderSize);
291         } else {
292             WidgetInstallToExtSingleton::Instance().preInstallation(list,
293                                                                     folderSize);
294         }
295         free(dirDetail);
296         g_list_free(list);
297
298         /* make bin directory */
299         std::string widgetBinPath = m_context.locations->getBinaryDir();
300         WrtUtilMakeDir(widgetBinPath);
301         std::string sourceDir = m_context.locations->getSourceDir();
302         WrtUtilMakeDir(sourceDir);
303     }
304     Catch(DPL::ZipInput::Exception::OpenFailed) {
305         ReThrowMsg(Exceptions::ErrorExternalInstallingFailure,
306                    "Error during \
307                 create external folder ");
308     }
309     Catch(WidgetInstallToExt::Exception::ErrorInstallToExt)
310     {
311         ReThrowMsg(Exceptions::ErrorExternalInstallingFailure,
312                    "Error during create external folder ");
313     }
314 }
315
316 void TaskFileManipulation::StartStep()
317 {
318     LOGD("--------- <TaskFileManipulation> : START ----------");
319 }
320
321 void TaskFileManipulation::EndStep()
322 {
323     LOGD("--------- <TaskFileManipulation> : END ----------");
324 }
325 } //namespace WidgetInstall
326 } //namespace Jobs