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