Remove GUID and refactoring update mode
[framework/web/wrt-installer.git] / src / jobs / widget_install / task_file_manipulation.cpp
1 /*
2  * Copyright (c) 2011 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 <widget_install/task_file_manipulation.h>
26 #include <widget_install/job_widget_install.h>
27 #include <widget_install/widget_install_errors.h>
28 #include <widget_install/widget_install_context.h>
29 #include <dpl/utils/wrt_utility.h>
30 #include <dpl/foreach.h>
31 #include <dpl/log/log.h>
32 #include <dpl/assert.h>
33 #include <dpl/utils/folder_size.h>
34 #include <string>
35 #include <fstream>
36 #include <widget_install_to_external.h>
37
38 #define WEBAPP_DEFAULT_UID  5000
39 #define WEBAPP_DEFAULT_GID  5000
40
41 namespace {
42 const mode_t PRIVATE_STORAGE_MODE = 0700;
43 const mode_t SHARE_MODE = 0705;
44 }
45
46 using namespace WrtDB;
47
48 namespace {
49 const char* GLIST_RES_DIR = "res";
50 const char* GLIST_BIN_DIR = "bin";
51
52 bool _FolderCopy(std::string source, std::string dest)
53 {
54     DIR* dir = opendir(source.c_str());
55     if (NULL == dir) {
56         return false;
57     }
58
59     struct dirent dEntry;
60     struct dirent *dEntryResult;
61     int return_code;
62
63     do {
64         struct stat statInfo;
65         return_code = readdir_r(dir, &dEntry, &dEntryResult);
66         if (dEntryResult != NULL && return_code == 0) {
67             std::string fileName = dEntry.d_name;
68             std::string fullName = source + "/" + fileName;
69
70             if (stat(fullName.c_str(), &statInfo) != 0) {
71                 closedir(dir);
72                 return false;
73             }
74
75             if (S_ISDIR(statInfo.st_mode)) {
76                 if (("." == fileName) || (".." == fileName)) {
77                     continue;
78                 }
79                 std::string destFolder = dest + "/" + fileName;
80                 WrtUtilMakeDir(destFolder);
81
82                 if (!_FolderCopy(fullName, destFolder)) {
83                     closedir(dir);
84                     return false;
85                 }
86             }
87
88             std::string destFile = dest + "/" + fileName;
89             std::ifstream infile(fullName);
90             std::ofstream outfile(destFile);
91             outfile << infile.rdbuf();
92             outfile.close();
93             infile.close();
94         }
95     } while (dEntryResult != NULL && return_code == 0);
96     closedir(dir);
97     return true;
98 }
99 }
100
101 namespace Jobs {
102 namespace WidgetInstall {
103 TaskFileManipulation::TaskFileManipulation(InstallerContext& context) :
104     DPL::TaskDecl<TaskFileManipulation>(this),
105     m_context(context),
106     m_extHandle(NULL)
107 {
108     if (INSTALL_LOCATION_TYPE_EXTERNAL !=
109         m_context.locationType)
110     {
111         AddStep(&TaskFileManipulation::StepCreateDirs);
112         AddStep(&TaskFileManipulation::StepCreatePrivateStorageDir);
113         if (m_context.widgetConfig.packagingType !=
114             WrtDB::PKG_TYPE_DIRECTORY_WEB_APP)
115         {
116             AddStep(&TaskFileManipulation::StepRenamePath);
117             AddAbortStep(&TaskFileManipulation::StepAbortRenamePath);
118         }
119     } else {
120         AddStep(&TaskFileManipulation::StepPrepareExternalDir);
121         AddStep(&TaskFileManipulation::StepInstallToExternal);
122         AddStep(&TaskFileManipulation::StepCreatePrivateStorageDir);
123
124         AddAbortStep(&TaskFileManipulation::StepAbortCreateExternalDir);
125     }
126 }
127
128 void TaskFileManipulation::StepCreateDirs()
129 {
130     std::string widgetPath;
131
132     widgetPath = m_context.locations->getPackageInstallationDir();
133
134     std::string widgetBinPath = m_context.locations->getBinaryDir();
135     std::string widgetSrcPath = m_context.locations->getSourceDir();
136
137     WrtUtilMakeDir(widgetPath);
138
139     // If package type is widget with osp service, we don't need to make bin
140     // and src directory
141     if (m_context.widgetConfig.packagingType == PKG_TYPE_HYBRID_WEB_APP) {
142         LogDebug("Doesn't need to create resource directory");
143     } else {
144         LogDebug("Create resource directory");
145         WrtUtilMakeDir(widgetBinPath);
146         WrtUtilMakeDir(widgetSrcPath);
147     }
148
149     m_context.job->UpdateProgress(
150         InstallerContext::INSTALL_DIR_CREATE,
151         "Widget Directory Created");
152 }
153
154 void TaskFileManipulation::StepCreatePrivateStorageDir()
155 {
156     std::string storagePath = m_context.locations->getPrivateStorageDir();
157
158     if (euidaccess(storagePath.c_str(), F_OK) != 0) {
159         if (!WrtUtilMakeDir(storagePath, PRIVATE_STORAGE_MODE)) {
160             LogError("Failed to create directory for private storage");
161             ThrowMsg(Exceptions::FileOperationFailed,
162                      "Failed to create directory for private storage");
163         }
164         // '5000' is default uid, gid for applications.
165         // So installed applications should be launched as process of uid
166         // '5000'.
167         // the process can access private directory 'data' of itself.
168         if (chown(storagePath.c_str(),
169                   WEBAPP_DEFAULT_UID,
170                   WEBAPP_DEFAULT_GID) != 0)
171         {
172             ThrowMsg(Exceptions::FileOperationFailed,
173                      "Chown to invaild user");
174         }
175     } else if (euidaccess(storagePath.c_str(), W_OK | R_OK | X_OK) == 0) {
176         LogInfo("Private storage already exists.");
177         // Even if private directory already is created, private dircetory
178         // should change owner.
179         if (chown(storagePath.c_str(),
180                   WEBAPP_DEFAULT_UID,
181                   WEBAPP_DEFAULT_GID) != 0)
182         {
183             ThrowMsg(Exceptions::FileOperationFailed,
184                      "Chown to invaild user");
185         }
186         if (chmod(storagePath.c_str(), PRIVATE_STORAGE_MODE) != 0) {
187             ThrowMsg(Exceptions::FileOperationFailed,
188                      "chmod to 0700");
189         }
190     } else {
191         ThrowMsg(Exceptions::FileOperationFailed,
192                  "No access to private storage.");
193     }
194 }
195
196 void TaskFileManipulation::StepRenamePath()
197 {
198     std::string instDir;
199
200     if (m_context.widgetConfig.packagingType == PKG_TYPE_HYBRID_WEB_APP) {
201         instDir = m_context.locations->getPackageInstallationDir();
202     } else {
203         instDir = m_context.locations->getSourceDir();
204     }
205
206     LogDebug("Copy file from temp directory to " << instDir);
207     if (!WrtUtilRemove(instDir)) {
208         ThrowMsg(Exceptions::RemovingFolderFailure,
209                  "Error occurs during removing existing folder");
210     }
211
212     if (!(rename(m_context.locations->getTemporaryPackageDir().c_str(),
213                  instDir.c_str()) == 0))
214     {
215         ThrowMsg(Exceptions::FileOperationFailed,
216                  "Error occurs during renaming widget folder");
217     }
218     m_context.job->UpdateProgress(
219         InstallerContext::INSTALL_RENAME_PATH,
220         "Widget Rename path Finished");
221 }
222
223 void TaskFileManipulation::StepAbortRenamePath()
224 {
225     LogDebug("[Rename Widget Path] Aborting.... (Rename path)");
226     std::string widgetPath;
227     if (m_context.widgetConfig.packagingType != PKG_TYPE_HYBRID_WEB_APP) {
228         widgetPath = m_context.locations->getPackageInstallationDir();
229         if (!WrtUtilRemove(widgetPath)) {
230             ThrowMsg(Exceptions::RemovingFolderFailure,
231                      "Error occurs during removing existing folder");
232         }
233     }
234     LogDebug("Rename widget path sucessful!");
235 }
236
237 void TaskFileManipulation::StepPrepareExternalDir()
238 {
239     LogDebug("Step prepare to install in exernal directory");
240     Try {
241         std::string appid =
242             DPL::ToUTF8String(m_context.widgetConfig.tzAppid);
243
244         WidgetInstallToExtSingleton::Instance().initialize(appid);
245
246         size_t totalSize =
247             Utils::getFolderSize(m_context.locations->getTemporaryPackageDir());
248
249         int folderSize = (int)(totalSize / (1024 * 1024)) + 1;
250
251         GList *list = NULL;
252         app2ext_dir_details* dirDetail = NULL;
253
254         std::string dirNames[2] = { GLIST_RES_DIR, GLIST_BIN_DIR };
255
256         for (int i = 0; i < 2; i++) {
257             dirDetail = (app2ext_dir_details*) calloc(1,
258                                                       sizeof(
259                                                           app2ext_dir_details));
260             if (NULL == dirDetail) {
261                 ThrowMsg(Exceptions::ErrorExternalInstallingFailure,
262                          "error in app2ext");
263             }
264             dirDetail->name = strdup(dirNames[i].c_str());
265             dirDetail->type = APP2EXT_DIR_RO;
266             list = g_list_append(list, dirDetail);
267         }
268
269         if (m_context.isUpdateMode) {
270             WidgetInstallToExtSingleton::Instance().preUpgrade(list,
271                                                                folderSize);
272         } else {
273             WidgetInstallToExtSingleton::Instance().preInstallation(list,
274                                                                     folderSize);
275         }
276         free(dirDetail);
277         g_list_free(list);
278     }
279     Catch(WidgetInstallToExt::Exception::ErrorInstallToExt)
280     {
281         ReThrowMsg(Exceptions::ErrorExternalInstallingFailure,
282                    "Error during \
283                 create external folder ");
284     }
285 }
286
287 void TaskFileManipulation::StepInstallToExternal()
288 {
289     LogDebug("StepInstallExternal");
290     if (!WrtUtilMakeDir(m_context.locations->getSourceDir())) {
291         ThrowMsg(Exceptions::ErrorExternalInstallingFailure,
292                  "To make src \
293                 directory failed");
294     }
295
296     LogDebug("Resource move to external storage " <<
297              m_context.locations->getSourceDir());
298     if (!_FolderCopy(m_context.locations->getTemporaryPackageDir(),
299                      m_context.locations->getSourceDir()))
300     {
301         ThrowMsg(Exceptions::ErrorExternalInstallingFailure,
302                  "Error occurs during renaming widget folder");
303     }
304 }
305
306 void TaskFileManipulation::StepAbortCreateExternalDir()
307 {
308     LogError("Abort StepAbortCreateExternalDir");
309     if (m_context.isUpdateMode) {
310         WidgetInstallToExtSingleton::Instance().postUpgrade(false);
311     } else {
312         WidgetInstallToExtSingleton::Instance().postInstallation(false);
313     }
314     WidgetInstallToExtSingleton::Instance().deinitialize();
315 }
316 } //namespace WidgetInstall
317 } //namespace Jobs