Rename invalid WRT_SMACK_LABEL macro to WRT_SMACK_ENABLED
[platform/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 <widget_install/directory_api.h>
30 #include <dpl/utils/wrt_utility.h>
31 #include <dpl/foreach.h>
32 #include <dpl/assert.h>
33 #include <dpl/errno_string.h>
34 #include <dpl/utils/folder_size.h>
35 #include <dpl/wrt-dao-ro/global_config.h>
36 #include <string>
37 #include <fstream>
38 #include <widget_install_to_external.h>
39 #include <installer_log.h>
40
41 #define WEBAPP_DEFAULT_UID  5000
42 #define WEBAPP_DEFAULT_GID  5000
43
44 namespace {
45 const mode_t PRIVATE_STORAGE_MODE = 0700;
46 const mode_t SHARED_STORAGE_MODE = 0755;
47 }
48
49 using namespace WrtDB;
50
51 namespace {
52 const char* GLIST_RES_DIR = "res";
53
54 bool _FolderCopy(std::string source, std::string dest)
55 {
56     DIR* dir = opendir(source.c_str());
57     if (NULL == dir) {
58         return false;
59     }
60
61     struct dirent dEntry;
62     struct dirent *dEntryResult;
63     int return_code;
64
65     do {
66         struct stat statInfo;
67         return_code = readdir_r(dir, &dEntry, &dEntryResult);
68         if (dEntryResult != NULL && return_code == 0) {
69             std::string fileName = dEntry.d_name;
70             std::string fullName = source + "/" + fileName;
71
72             if (stat(fullName.c_str(), &statInfo) != 0) {
73                 closedir(dir);
74                 return false;
75             }
76
77             if (S_ISDIR(statInfo.st_mode)) {
78                 if (("." == fileName) || (".." == fileName)) {
79                     continue;
80                 }
81                 std::string destFolder = dest + "/" + fileName;
82                 WrtUtilMakeDir(destFolder);
83
84                 if (!_FolderCopy(fullName, destFolder)) {
85                     closedir(dir);
86                     return false;
87                 }
88             }
89
90             std::string destFile = dest + "/" + fileName;
91             std::ifstream infile(fullName);
92             std::ofstream outfile(destFile);
93             outfile << infile.rdbuf();
94             outfile.close();
95             infile.close();
96         }
97     } while (dEntryResult != NULL && return_code == 0);
98     closedir(dir);
99     return true;
100 }
101
102 void changeOwnerForDirectory(std::string storagePath, mode_t mode) {
103     if (euidaccess(storagePath.c_str(), F_OK) != 0) {
104         if (!WrtUtilMakeDir(storagePath, mode)) {
105             _E("Failed to create directory : %s", storagePath.c_str());
106             ThrowMsg(Jobs::WidgetInstall::Exceptions::FileOperationFailed,
107                      "Failed to create directory : " << storagePath);
108         }
109         // '5000' is default uid, gid for applications.
110         // So installed applications should be launched as process of uid
111         // '5000'.
112         // the process can access private directory 'data' of itself.
113         if (chown(storagePath.c_str(),
114                   WEBAPP_DEFAULT_UID,
115                   WEBAPP_DEFAULT_GID) != 0)
116         {
117             ThrowMsg(Jobs::WidgetInstall::Exceptions::FileOperationFailed,
118                      "Chown to invaild user");
119         }
120     } else if (euidaccess(storagePath.c_str(), W_OK | R_OK | X_OK) == 0) {
121         _D("%s already exists.", storagePath.c_str());
122         // Even if private directory already is created, private dircetory
123         // should change owner.
124         if (chown(storagePath.c_str(),
125                   WEBAPP_DEFAULT_UID,
126                   WEBAPP_DEFAULT_GID) != 0)
127         {
128             ThrowMsg(Jobs::WidgetInstall::Exceptions::FileOperationFailed,
129                      "Chown to invaild user");
130         }
131         if (chmod(storagePath.c_str(), mode) != 0) {
132             ThrowMsg(Jobs::WidgetInstall::Exceptions::FileOperationFailed,
133                      "chmod to 0700");
134         }
135     } else {
136         ThrowMsg(Jobs::WidgetInstall::Exceptions::FileOperationFailed,
137                  "No access to private storage.");
138     }
139 }
140 }
141
142 namespace Jobs {
143 namespace WidgetInstall {
144 TaskFileManipulation::TaskFileManipulation(InstallerContext& context) :
145     DPL::TaskDecl<TaskFileManipulation>(this),
146     m_context(context),
147     m_extHandle(NULL)
148 {
149     AddStep(&TaskFileManipulation::StartStep);
150     if (INSTALL_LOCATION_TYPE_EXTERNAL !=
151             m_context.locationType)
152     {
153         AddStep(&TaskFileManipulation::StepCreateDirs);
154         if (m_context.mode.extension != InstallMode::ExtensionType::DIR)
155         {
156             AddStep(&TaskFileManipulation::StepRenamePath);
157             AddAbortStep(&TaskFileManipulation::StepAbortRenamePath);
158         }
159         AddStep(&TaskFileManipulation::StepCreatePrivateStorageDir);
160         AddStep(&TaskFileManipulation::StepCreateSharedFolder);
161         AddStep(&TaskFileManipulation::StepLinkForPreload);
162
163     } else {
164         AddStep(&TaskFileManipulation::StepPrepareExternalDir);
165         AddStep(&TaskFileManipulation::StepInstallToExternal);
166         AddStep(&TaskFileManipulation::StepCreatePrivateStorageDir);
167         AddStep(&TaskFileManipulation::StepCreateSharedFolder);
168
169         AddAbortStep(&TaskFileManipulation::StepAbortCreateExternalDir);
170     }
171     AddStep(&TaskFileManipulation::EndStep);
172 }
173
174 void TaskFileManipulation::StepCreateDirs()
175 {
176     std::string widgetPath;
177
178     widgetPath = m_context.locations->getPackageInstallationDir();
179
180     std::string widgetBinPath = m_context.locations->getBinaryDir();
181     std::string widgetSrcPath = m_context.locations->getSourceDir();
182
183     WrtUtilMakeDir(widgetPath);
184
185     // If package type is widget with osp service, we don't need to make bin
186     // and src directory
187     if (m_context.widgetConfig.packagingType == PKG_TYPE_HYBRID_WEB_APP) {
188         _D("Doesn't need to create resource directory");
189     } else {
190         _D("Create resource directory");
191         WrtUtilMakeDir(widgetBinPath);
192         WrtUtilMakeDir(widgetSrcPath);
193         if (m_context.mode.installTime == InstallMode::InstallTime::PRELOAD) {
194             std::string userWidgetDir = m_context.locations->getUserDataRootDir();
195             WrtUtilMakeDir(userWidgetDir);
196         }
197     }
198
199     m_context.job->UpdateProgress(
200         InstallerContext::INSTALL_DIR_CREATE,
201         "Widget Directory Created");
202 }
203
204 void TaskFileManipulation::StepCreatePrivateStorageDir()
205 {
206     std::string storagePath = m_context.locations->getPrivateStorageDir();
207     _D("Create private storage directory : %s", m_context.locations->getPrivateStorageDir().c_str());
208
209     changeOwnerForDirectory(storagePath, PRIVATE_STORAGE_MODE);
210
211     if (m_context.isUpdateMode) { //update
212         std::string backData = m_context.locations->getBackupPrivateDir();
213         _D("copy private storage %s to %s", backData.c_str(), storagePath.c_str());
214         if (!DirectoryApi::DirectoryCopy(backData, storagePath)) {
215             _E("Failed to rename %s to %s", backData.c_str(), storagePath.c_str());
216             ThrowMsg(Exceptions::BackupFailed,
217                     "Error occurs copy private strage files");
218         }
219     }
220
221     std::string tempStoragePath = m_context.locations->getPrivateTempStorageDir();
222     _D("Create temp private storage directory : %s", tempStoragePath.c_str());
223     changeOwnerForDirectory(tempStoragePath, PRIVATE_STORAGE_MODE);
224 }
225
226 void TaskFileManipulation::StepRenamePath()
227 {
228     std::string instDir;
229
230     if (m_context.widgetConfig.packagingType == PKG_TYPE_HYBRID_WEB_APP) {
231         instDir = m_context.locations->getPackageInstallationDir();
232     } else {
233         instDir = m_context.locations->getSourceDir();
234     }
235
236     _D("Copy file from temp directory to %s", instDir.c_str());
237     if (!WrtUtilRemove(instDir)) {
238         ThrowMsg(Exceptions::RemovingFolderFailure,
239                  "Error occurs during removing existing folder");
240     }
241
242     if (!(rename(m_context.locations->getTemporaryPackageDir().c_str(),
243                  instDir.c_str()) == 0))
244     {
245         ThrowMsg(Exceptions::FileOperationFailed,
246                  "Error occurs during renaming widget folder");
247     }
248     m_context.job->UpdateProgress(
249         InstallerContext::INSTALL_RENAME_PATH,
250         "Widget Rename path Finished");
251 }
252
253 void TaskFileManipulation::StepLinkForPreload()
254 {
255     if (m_context.mode.rootPath == InstallMode::RootPath::RO) {
256         std::string optRes = m_context.locations->getUserDataRootDir() +
257             WrtDB::GlobalConfig::GetWidgetResPath();
258         std::string usrRes = m_context.locations->getPackageInstallationDir() +
259             WrtDB::GlobalConfig::GetWidgetResPath();
260
261         if (0 != access(optRes.c_str(), F_OK)) {
262             _D("Make symbolic name for preload app %s to %s", usrRes.c_str(), optRes.c_str());
263
264             if (symlink(usrRes.c_str(), optRes.c_str()) != 0)
265             {
266                 int error = errno;
267                 if (error)
268                     _E("Failed to make a symbolic name for a file [%s]", (DPL::GetErrnoString(error)).c_str());
269                 ThrowMsg(Exceptions::FileOperationFailed,
270                         "Symbolic link creating is not done.");
271             }
272         }
273
274         /* link for data directory */
275         std::string storagePath = m_context.locations->getPrivateStorageDir();
276         std::string dataDir = m_context.locations->getPackageInstallationDir() +
277             "/" + WrtDB::GlobalConfig::GetWidgetPrivateStoragePath();
278         if (0 != access(dataDir.c_str(), F_OK)) {
279             _D("Make symbolic name for preload app %s to %s", storagePath.c_str(), dataDir.c_str());
280
281             if (symlink(storagePath.c_str(), dataDir.c_str()) != 0)
282             {
283                 int error = errno;
284                 if (error)
285                     _E("Failed to make a symbolic name for a file [%s]", (DPL::GetErrnoString(error)).c_str());
286                 ThrowMsg(Exceptions::FileOperationFailed,
287                         "Symbolic link creating is not done.");
288             }
289             changeOwnerForDirectory(dataDir, PRIVATE_STORAGE_MODE);
290         }
291
292         if (m_context.widgetConfig.packagingType != PKG_TYPE_HYBRID_WEB_APP) {
293             std::string widgetBinPath = m_context.locations->getBinaryDir();
294             std::string userBinPath = m_context.locations->getUserBinaryDir();
295             _D("Make symbolic link for preload app %s to %s", widgetBinPath.c_str(), userBinPath.c_str());
296             if (symlink(widgetBinPath.c_str(), userBinPath.c_str()) != 0)
297             {
298                 int error = errno;
299                 if (error)
300                     _E("Failed to make a symbolic name for a file [%s]", (DPL::GetErrnoString(error)).c_str());
301                 ThrowMsg(Exceptions::FileOperationFailed,
302                         "Symbolic link creating is not done.");
303             }
304
305         }
306     }
307 }
308
309 void TaskFileManipulation::StepAbortRenamePath()
310 {
311     _D("[Rename Widget Path] Aborting.... (Rename path)");
312     std::string widgetPath;
313     widgetPath = m_context.locations->getPackageInstallationDir();
314     if (!WrtUtilRemove(widgetPath)) {
315         _E("Error occurs during removing existing folder");
316     }
317     // Remove user data directory if preload web app.
318     std::string userData = m_context.locations->getUserDataRootDir();
319     if (0 == access(userData.c_str(), F_OK)) {
320         if (!WrtUtilRemove(userData)) {
321             _E("Error occurs during removing user data directory");
322         }
323     }
324
325     _D("Rename widget path sucessful!");
326 }
327
328 void TaskFileManipulation::StepPrepareExternalDir()
329 {
330     _D("Step prepare to install in exernal directory");
331     Try {
332         std::string pkgid =
333             DPL::ToUTF8String(m_context.widgetConfig.tzPkgid);
334
335         WidgetInstallToExtSingleton::Instance().initialize(pkgid);
336
337         size_t totalSize =
338             Utils::getFolderSize(m_context.locations->getTemporaryPackageDir());
339
340         int folderSize = (int)(totalSize / (1024 * 1024)) + 1;
341
342         GList *list = NULL;
343         app2ext_dir_details* dirDetail = NULL;
344
345         dirDetail = (app2ext_dir_details*) calloc(1,
346                 sizeof(
347                     app2ext_dir_details));
348         if (NULL == dirDetail) {
349             ThrowMsg(Exceptions::ErrorExternalInstallingFailure,
350                     "error in app2ext");
351         }
352         dirDetail->name = strdup(GLIST_RES_DIR);
353         dirDetail->type = APP2EXT_DIR_RO;
354         list = g_list_append(list, dirDetail);
355
356         if (m_context.isUpdateMode) {
357             WidgetInstallToExtSingleton::Instance().preUpgrade(list,
358                                                                folderSize);
359         } else {
360             WidgetInstallToExtSingleton::Instance().preInstallation(list,
361                                                                     folderSize);
362         }
363         free(dirDetail);
364         g_list_free(list);
365
366         /* make bin directory */
367         std::string widgetBinPath = m_context.locations->getBinaryDir();
368         WrtUtilMakeDir(widgetBinPath);
369     }
370     Catch(WidgetInstallToExt::Exception::ErrorInstallToExt)
371     {
372         ReThrowMsg(Exceptions::ErrorExternalInstallingFailure,
373                    "Error during \
374                 create external folder ");
375     }
376 }
377
378 void TaskFileManipulation::StepInstallToExternal()
379 {
380     _D("StepInstallExternal");
381     if (!WrtUtilMakeDir(m_context.locations->getSourceDir())) {
382         ThrowMsg(Exceptions::ErrorExternalInstallingFailure,
383                  "To make src \
384                 directory failed");
385     }
386
387     _D("Resource move to external storage %s", m_context.locations->getSourceDir().c_str());
388     if (!_FolderCopy(m_context.locations->getTemporaryPackageDir(),
389                      m_context.locations->getSourceDir()))
390     {
391         ThrowMsg(Exceptions::ErrorExternalInstallingFailure,
392                  "Error occurs during renaming widget folder");
393     }
394 }
395
396 void TaskFileManipulation::StepAbortCreateExternalDir()
397 {
398     _E("Abort StepAbortCreateExternalDir");
399     if (m_context.isUpdateMode) {
400         WidgetInstallToExtSingleton::Instance().postUpgrade(false);
401     } else {
402         WidgetInstallToExtSingleton::Instance().postInstallation(false);
403     }
404     WidgetInstallToExtSingleton::Instance().deinitialize();
405 }
406
407 void TaskFileManipulation::StepCreateSharedFolder()
408 {
409     _D("StepCreateSharedFolder");
410     std::string sharedPath = m_context.locations->getSharedRootDir();
411     _D("Create shared directory : %s", m_context.locations->getSharedRootDir().c_str());
412
413     WrtUtilMakeDir(sharedPath);
414     WrtUtilMakeDir(m_context.locations->getSharedResourceDir());
415
416     changeOwnerForDirectory(m_context.locations->getSharedDataDir(),
417             SHARED_STORAGE_MODE);
418     changeOwnerForDirectory(m_context.locations->getSharedTrustedDir(),
419             SHARED_STORAGE_MODE);
420
421
422     // additional check for rootPath installation
423     // If this app is preloaded, "shared" diretory is already on place and do not needs to be moved
424     // TODO: why "shared" is on RW partion always but "data" and "tmp" are linked
425     if (m_context.isUpdateMode
426             && !(m_context.mode.rootPath == InstallMode::RootPath::RO
427             && m_context.mode.installTime == InstallMode::InstallTime::PRELOAD)) {
428
429         /* Restore /shared/data */
430         _D("copy %s to %s", m_context.locations->getBackupSharedDataDir().c_str(), m_context.locations->getSharedDataDir().c_str());
431         if (!DirectoryApi::DirectoryCopy(
432                     m_context.locations->getBackupSharedDataDir(),
433                     m_context.locations->getSharedDataDir())) {
434                 _E("Failed to rename %s to %s", m_context.locations->getBackupSharedDataDir().c_str(), m_context.locations->getSharedDataDir().c_str());
435                 ThrowMsg(Exceptions::BackupFailed,
436                         "Error occurs copy shared strage files");
437             }
438
439         /* Restore /shared/trusted */
440         _D("copy %s to %s", m_context.locations->getBackupSharedTrustedDir().c_str(), m_context.locations->getSharedTrustedDir().c_str());
441         if (!DirectoryApi::DirectoryCopy(
442                     m_context.locations->getBackupSharedTrustedDir(),
443                     m_context.locations->getSharedTrustedDir())) {
444             _E("Failed to rename %s to %s", m_context.locations->getBackupSharedTrustedDir().c_str(), m_context.locations->getSharedTrustedDir().c_str());
445             ThrowMsg(Exceptions::BackupFailed,
446                     "Error occurs copy shared strage files");
447         }
448     }
449 }
450
451 void TaskFileManipulation::StartStep()
452 {
453     _D("--------- <TaskFileManipulation> : START ----------");
454 }
455
456 void TaskFileManipulation::EndStep()
457 {
458     _D("--------- <TaskFileManipulation> : END ----------");
459 }
460 } //namespace WidgetInstall
461 } //namespace Jobs