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