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