fddd7704d7db924e30c572c6ac022f3cf282806a
[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 = NULL;
60     do {
61         struct stat statInfo;
62         if (dEntry = readdir(dir)) {
63             std::string fileName = dEntry->d_name;
64             std::string fullName = source + "/" + fileName;
65
66             if (stat(fullName.c_str(), &statInfo) != 0) {
67                 closedir(dir);
68                 return false;
69             }
70
71             if (S_ISDIR(statInfo.st_mode)) {
72                 if (("." == fileName) || (".." == fileName)) {
73                     continue;
74                 }
75                 std::string destFolder = dest + "/" + fileName;
76                 WrtUtilMakeDir(destFolder);
77
78                 if (!_FolderCopy(fullName, destFolder)) {
79                     closedir(dir);
80                     return false;
81                 }
82             }
83
84             std::string destFile = dest + "/" + fileName;
85             std::ifstream infile(fullName);
86             std::ofstream outfile(destFile);
87             outfile << infile.rdbuf();
88             outfile.close();
89             infile.close();
90         }
91     } while (dEntry);
92     closedir(dir);
93     return true;
94 }
95 }
96
97 namespace Jobs {
98 namespace WidgetInstall {
99 TaskFileManipulation::TaskFileManipulation(InstallerContext& context) :
100     DPL::TaskDecl<TaskFileManipulation>(this),
101     m_context(context)
102 {
103     if (INSTALL_LOCATION_TYPE_EXTERNAL !=
104         m_context.locationType)
105     {
106         AddStep(&TaskFileManipulation::StepCreateDirs);
107         AddStep(&TaskFileManipulation::StepCreatePrivateStorageDir);
108         if (m_context.widgetConfig.packagingType !=
109             WrtDB::PKG_TYPE_DIRECTORY_WEB_APP)
110         {
111             AddStep(&TaskFileManipulation::StepRenamePath);
112             AddAbortStep(&TaskFileManipulation::StepAbortRenamePath);
113         }
114     } else {
115         AddStep(&TaskFileManipulation::StepPrepareExternalDir);
116         AddStep(&TaskFileManipulation::StepInstallToExternal);
117         AddStep(&TaskFileManipulation::StepCreatePrivateStorageDir);
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
161         // '5000'.
162         // the process can access private directory 'data' of itself.
163         if (chown(storagePath.c_str(),
164                   WEBAPP_DEFAULT_UID,
165                   WEBAPP_DEFAULT_GID) != 0)
166         {
167             ThrowMsg(Exceptions::InternalError,
168                      "Chown to invaild user");
169         }
170     } else if (euidaccess(storagePath.c_str(), W_OK | R_OK | X_OK) == 0) {
171         LogInfo("Private storage already exists.");
172         // Even if private directory already is created, private dircetory
173         // should change owner.
174         if (chown(storagePath.c_str(),
175                   WEBAPP_DEFAULT_UID,
176                   WEBAPP_DEFAULT_GID) != 0)
177         {
178             ThrowMsg(Exceptions::InternalError,
179                      "Chown to invaild user");
180         }
181         if (chmod(storagePath.c_str(), PRIVATE_STORAGE_MODE) != 0) {
182             ThrowMsg(Exceptions::InternalError,
183                      "chmod to 0700");
184         }
185     } else {
186         ThrowMsg(Exceptions::InternalError,
187                  "No access to private storage.");
188     }
189 }
190
191 void TaskFileManipulation::StepRenamePath()
192 {
193     std::string instDir;
194
195     if (m_context.widgetConfig.packagingType == PKG_TYPE_HYBRID_WEB_APP) {
196         instDir = m_context.locations->getPackageInstallationDir();
197     } else {
198         instDir = m_context.locations->getSourceDir();
199     }
200
201     LogDebug("Copy file from temp directory to " << instDir);
202     if (!WrtUtilRemove(instDir)) {
203         ThrowMsg(Exceptions::RemovingFolderFailure,
204                  "Error occurs during removing existing folder");
205     }
206
207     if (!(rename(m_context.locations->getTemporaryPackageDir().c_str(),
208                  instDir.c_str()) == 0))
209     {
210         ThrowMsg(Exceptions::UnknownError,
211                  "Error occurs during renaming widget folder");
212     }
213     m_context.job->UpdateProgress(
214         InstallerContext::INSTALL_RENAME_PATH,
215         "Widget Rename path Finished");
216 }
217
218 void TaskFileManipulation::StepAbortRenamePath()
219 {
220     LogDebug("[Rename Widget Path] Aborting.... (Rename path)");
221     std::string widgetPath;
222     if (m_context.widgetConfig.packagingType != PKG_TYPE_HYBRID_WEB_APP) {
223         widgetPath = m_context.locations->getPackageInstallationDir();
224         if (!WrtUtilRemove(widgetPath)) {
225             ThrowMsg(Exceptions::RemovingFolderFailure,
226                      "Error occurs during removing existing folder");
227         }
228     }
229     LogDebug("Rename widget path sucessful!");
230 }
231
232 void TaskFileManipulation::StepPrepareExternalDir()
233 {
234     LogDebug("Step prepare to install in exernal directory");
235     Try {
236         std::string appid =
237             DPL::ToUTF8String(m_context.widgetConfig.tzAppid);
238
239         WidgetInstallToExtSingleton::Instance().initialize(appid);
240
241         size_t totalSize =
242             Utils::getFolderSize(m_context.locations->getTemporaryPackageDir());
243
244         int folderSize = (int)(totalSize / (1024 * 1024)) + 1;
245
246         GList *list = NULL;
247         app2ext_dir_details* dirDetail = NULL;
248
249         std::string dirNames[2] = { GLIST_RES_DIR, GLIST_BIN_DIR };
250
251         for (int i = 0; i < 2; i++) {
252             dirDetail = (app2ext_dir_details*) calloc(1,
253                                                       sizeof(
254                                                           app2ext_dir_details));
255             if (NULL == dirDetail) {
256                 ThrowMsg(Exceptions::ErrorExternalInstallingFailure,
257                          "error in app2ext");
258             }
259             dirDetail->name = strdup(dirNames[i].c_str());
260             dirDetail->type = APP2EXT_DIR_RO;
261             list = g_list_append(list, dirDetail);
262         }
263
264         if (false == m_context.existingWidgetInfo.isExist) {
265             WidgetInstallToExtSingleton::Instance().preInstallation(list,
266                                                                     folderSize);
267         } else {
268             WidgetInstallToExtSingleton::Instance().preUpgrade(list,
269                                                                folderSize);
270         }
271         free(dirDetail);
272         g_list_free(list);
273     }
274     Catch(WidgetInstallToExt::Exception::ErrorInstallToExt)
275     {
276         ReThrowMsg(Exceptions::ErrorExternalInstallingFailure,
277                    "Error during \
278                 create external folder ");
279     }
280 }
281
282 void TaskFileManipulation::StepInstallToExternal()
283 {
284     LogDebug("StepInstallExternal");
285     if (!WrtUtilMakeDir(m_context.locations->getSourceDir())) {
286         ThrowMsg(Exceptions::ErrorExternalInstallingFailure,
287                  "To make src \
288                 directory failed");
289     }
290
291     LogDebug("Resource move to external storage " <<
292              m_context.locations->getSourceDir());
293     if (!_FolderCopy(m_context.locations->getTemporaryPackageDir(),
294                      m_context.locations->getSourceDir()))
295     {
296         ThrowMsg(Exceptions::UnknownError,
297                  "Error occurs during renaming widget folder");
298     }
299 }
300
301 void TaskFileManipulation::StepAbortCreateExternalDir()
302 {
303     LogError("Abort StepAbortCreateExternalDir");
304     if (false == m_context.existingWidgetInfo.isExist) {
305         WidgetInstallToExtSingleton::Instance().postInstallation(false);
306     } else {
307         WidgetInstallToExtSingleton::Instance().postUpgrade(false);
308     }
309     WidgetInstallToExtSingleton::Instance().deinitialize();
310 }
311 } //namespace WidgetInstall
312 } //namespace Jobs