Move tep between internal memory and sd card
[platform/core/appfw/app-installers.git] / src / common / step / backup / step_copy_backup.cc
1 // Copyright (c) 2015 Samsung Electronics Co., Ltd All Rights Reserved
2 // Use of this source code is governed by a apache 2.0 license that can be
3 // found in the LICENSE file.
4
5 #include "common/step/backup/step_copy_backup.h"
6
7 #include <boost/filesystem/operations.hpp>
8 #include <boost/system/error_code.hpp>
9
10 #include <cassert>
11 #include <string>
12
13 #include "common/backup_paths.h"
14 #include "common/utils/file_util.h"
15
16 namespace {
17
18 const char kExternalMemoryMountPoint[] = ".mmc";
19
20 }
21
22 namespace common_installer {
23 namespace backup {
24
25 namespace bf = boost::filesystem;
26 namespace bs = boost::system;
27
28 Step::Status StepCopyBackup::precheck() {
29   if (context_->pkgid.get().empty()) {
30     LOG(ERROR) << "pkgid attribute is empty";
31     return Step::Status::PACKAGE_NOT_FOUND;
32   }
33   if (context_->root_application_path.get().empty()) {
34     LOG(ERROR) << "root_application_path attribute is empty";
35     return Step::Status::INVALID_VALUE;
36   }
37
38   // set package path
39   context_->pkg_path.set(
40       context_->root_application_path.get() / context_->pkgid.get());
41   install_path_ = context_->pkg_path.get();
42   backup_path_ = GetBackupPathForPackagePath(context_->pkg_path.get());
43
44   return Status::OK;
45 }
46
47 Step::Status StepCopyBackup::process() {
48   if (!Backup())
49     return Status::APP_DIR_ERROR;
50
51   if (!NewContent())
52     return Status::APP_DIR_ERROR;
53
54   return Status::OK;
55 }
56
57 Step::Status StepCopyBackup::clean() {
58   if (!CleanBackupDirectory()) {
59     LOG(DEBUG) << "Cannot remove backup directory";
60     return Status::APP_DIR_ERROR;
61   }
62   LOG(DEBUG) << "Applications files backup directory removed";
63
64   if (context_->external_storage)
65     context_->external_storage->Commit();
66
67   return Status::OK;
68 }
69
70 Step::Status StepCopyBackup::undo() {
71   // TODO(t.iwanek): this should be done in StepUnzip
72   bs::error_code error;
73   LOG(DEBUG) << "Remove tmp dir: " << context_->unpacked_dir_path.get();
74   bf::remove_all(context_->unpacked_dir_path.get(), error);  // ignore error
75
76   if (context_->external_storage)
77     context_->external_storage->Abort();
78
79   // if backup was created then restore files
80   if (bf::exists(backup_path_)) {
81     if (!RollbackApplicationDirectory()) {
82       LOG(ERROR) << "Failed to revert package directory";
83       return Status::APP_DIR_ERROR;
84     }
85     LOG(DEBUG) << "Application files reverted from backup";
86   }
87   return Status::OK;
88 }
89
90 bool StepCopyBackup::Backup() {
91   // create backup directory
92   bs::error_code error;
93   bf::create_directories(backup_path_, error);
94
95   // create copy of old package content skipping the external memory mount point
96   for (bf::directory_iterator iter(context_->pkg_path.get());
97        iter != bf::directory_iterator(); ++iter) {
98     if (iter->path().filename() == kExternalMemoryMountPoint)
99       continue;
100
101     // external storage directories are mounted
102     // therefore move only content
103     if (context_->external_storage) {
104       auto& ext_dirs = context_->external_storage->external_dirs();
105       auto found = std::find(ext_dirs.begin(), ext_dirs.end(),
106                              iter->path().filename());
107       if (found != ext_dirs.end()) {
108         bool done = MoveMountPointContent(iter->path(),
109             backup_path_ / iter->path().filename());
110         if (!done) {
111           LOG(ERROR) << "Failed to move: " << iter->path();
112           return false;
113         }
114         continue;
115       }
116     }
117
118     if (bf::is_directory(iter->path())) {
119       if (!MoveDir(iter->path(), backup_path_ / iter->path().filename())) {
120         LOG(ERROR) << "Fail to backup package directory of: " << iter->path();
121         return false;
122       }
123     } else {
124       if (!MoveFile(iter->path(), backup_path_ / iter->path().filename())) {
125         LOG(ERROR) << "Fail to backup package file: " << iter->path();
126         return false;
127       }
128     }
129   }
130   LOG(INFO) << "Old package context saved to: " << backup_path_;
131   return true;
132 }
133
134
135 bool StepCopyBackup::MoveMountPointContent(const boost::filesystem::path& from,
136                                            const boost::filesystem::path& to) {
137   bs::error_code error;
138   bf::create_directories(to, error);
139
140   for (bf::directory_iterator iter(from);
141        iter != bf::directory_iterator(); ++iter) {
142     if (bf::is_directory(iter->path())) {
143       if (!MoveDir(iter->path(), to / iter->path().filename())) {
144         LOG(ERROR) << "Fail to backup package directory of: " << iter->path();
145         return false;
146       }
147     } else if (bf::is_symlink(iter->path())) {
148       bs::error_code error;
149       bf::copy_symlink(iter->path(), to / iter->path().filename(), error);
150       if (error) {
151         LOG(ERROR) << "Failed to backup package symlink: " << iter->path();
152         return false;
153       }
154     } else {
155       if (!MoveFile(iter->path(), to / iter->path().filename())) {
156         LOG(ERROR) << "Fail to backup package file: " << iter->path();
157         return false;
158       }
159     }
160   }
161   return true;
162 }
163
164 bool StepCopyBackup::NewContent() {
165   bs::error_code error;
166   bf::create_directories(install_path_.parent_path(), error);
167   if (error) {
168     LOG(ERROR) << "Cannot create package directory";
169     return false;
170   }
171   if (!MoveDir(context_->unpacked_dir_path.get(), install_path_,
172                FSFlag::FS_MERGE_DIRECTORIES)) {
173     LOG(ERROR) << "Fail to copy tmp dir: " << context_->unpacked_dir_path.get()
174                << " to dst dir: " << install_path_;
175     return false;
176   }
177
178   LOG(INFO) << "Successfully move: " << context_->unpacked_dir_path.get()
179             << " to: " << install_path_ << " directory";
180
181   return true;
182 }
183
184 bool StepCopyBackup::CleanBackupDirectory() {
185   if (bf::exists(backup_path_)) {
186     bs::error_code error;
187     bf::remove_all(backup_path_, error);
188     if (error)
189       return false;
190   }
191   return true;
192 }
193
194 bool StepCopyBackup::RollbackApplicationDirectory() {
195   bs::error_code error;
196   if (bf::exists(context_->pkg_path.get())) {
197     bf::remove_all(context_->pkg_path.get(), error);
198     if (error) {
199       return false;
200     }
201   }
202
203   if (!MoveDir(backup_path_, context_->pkg_path.get())) {
204     return false;
205   }
206
207   return true;
208 }
209
210 }  // namespace backup
211 }  // namespace common_installer