Upstream version 5.34.98.0
[platform/framework/web/crosswalk.git] / src / xwalk / application / browser / installer / tizen / package_installer.cc
1 // Copyright (c) 2013 Intel Corporation. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include "xwalk/application/browser/installer/tizen/package_installer.h"
6
7 #include <sys/types.h>
8 #include <pwd.h>
9 #include <unistd.h>
10 #include <pkgmgr/pkgmgr_parser.h>
11
12 #include <algorithm>
13 #include <string>
14 #include "base/file_util.h"
15 #include "base/files/file_enumerator.h"
16 #include "base/logging.h"
17 #include "base/path_service.h"
18 #include "third_party/libxml/chromium/libxml_utils.h"
19 #include "xwalk/application/browser/application_storage.h"
20 #include "xwalk/application/browser/installer/tizen/packageinfo_constants.h"
21
22 namespace info = xwalk::application_packageinfo_constants;
23
24 namespace xwalk {
25 namespace application {
26
27 PackageInstaller::~PackageInstaller() {
28 }
29
30 // static
31 scoped_ptr<PackageInstaller> PackageInstaller::Create(
32     ApplicationService* service,
33     ApplicationStorage* storage,
34     const std::string& package_id,
35     const base::FilePath& data_dir) {
36   if (!base::PathExists(data_dir))
37     return scoped_ptr<PackageInstaller>();
38   scoped_ptr<PackageInstaller> handler(
39       new PackageInstaller(service, storage, package_id, data_dir));
40   if (!handler->Init())
41     return scoped_ptr<PackageInstaller>();
42   return handler.Pass();
43 }
44
45 PackageInstaller::PackageInstaller(
46     ApplicationService* service,
47     ApplicationStorage* storage,
48     const std::string& package_id,
49     const base::FilePath& data_dir)
50     : service_(service)
51     , storage_(storage)
52     , package_id_(package_id)
53     , data_dir_(data_dir) {
54   CHECK(service_);
55 }
56
57 bool PackageInstaller::Init() {
58   app_dir_ = data_dir_.Append(info::kAppDir).AppendASCII(package_id_);
59   xml_path_ = base::FilePath(info::kXmlDir)
60       .AppendASCII(package_id_ + std::string(info::kXmlExtension));
61   execute_path_ = app_dir_.Append(info::kExecDir).AppendASCII(package_id_);
62
63   application_ = storage_->GetApplicationData(package_id_);
64   if (!application_) {
65     LOG(ERROR) << "Application " << package_id_
66                << " haven't been installed in Xwalk database.";
67     return false;
68   }
69   stripped_name_ = application_->Name();
70   stripped_name_.erase(
71       std::remove_if(stripped_name_.begin(), stripped_name_.end(), ::isspace),
72       stripped_name_.end());
73
74   if (!application_->GetManifest()->GetString(info::kIconKey, &icon_name_))
75     LOG(WARNING) << "Fail to get application icon name.";
76
77   icon_path_ = base::FilePath(info::kIconDir).AppendASCII(
78       package_id_ + info::kSeparator + stripped_name_ +
79       base::FilePath::FromUTF8Unsafe(icon_name_).Extension());
80   return true;
81 }
82
83 bool PackageInstaller::GeneratePkgInfoXml() {
84   base::FilePath dir_xml(xml_path_.DirName());
85   if (!base::PathExists(dir_xml) &&
86       !base::CreateDirectory(dir_xml))
87     return false;
88
89   FILE* file = base::OpenFile(xml_path_, "w");
90   XmlWriter xml_writer;
91   xml_writer.StartWriting();
92   xml_writer.StartElement("manifest");
93   xml_writer.AddAttribute("xmlns", "http://tizen.org/ns/packages");
94   xml_writer.AddAttribute("package", package_id_);
95   xml_writer.AddAttribute("version", application_->VersionString());
96   xml_writer.WriteElement("label", application_->Name());
97   xml_writer.WriteElement("description", application_->Description());
98
99   {
100     xml_writer.StartElement("ui-application");
101     xml_writer.AddAttribute("appid",
102         package_id_ + info::kSeparator + stripped_name_);
103     xml_writer.AddAttribute("exec", execute_path_.MaybeAsASCII());
104     xml_writer.AddAttribute("type", "c++app");
105     xml_writer.AddAttribute("taskmanage", "true");
106     xml_writer.WriteElement("label", application_->Name());
107     if (icon_name_.empty())
108       xml_writer.WriteElement("icon", info::kDefaultIconName);
109     else
110       xml_writer.WriteElement("icon", icon_path_.BaseName().MaybeAsASCII());
111     xml_writer.EndElement();  // Ends "ui-application"
112   }
113
114   xml_writer.EndElement();  // Ends "manifest" element.
115   xml_writer.StopWriting();
116
117   file_util::WriteFile(xml_path_,
118                        xml_writer.GetWrittenString().c_str(),
119                        xml_writer.GetWrittenString().size());
120   base::CloseFile(file);
121   LOG(INFO) << "Converting manifest.json into "
122             << xml_path_.BaseName().MaybeAsASCII()
123             << " for installation. [DONE]";
124   return true;
125 }
126
127 bool PackageInstaller::CopyOrLinkResources() {
128   base::FilePath icon = app_dir_.AppendASCII(icon_name_);
129   if (!icon_name_.empty() && base::PathExists(icon))
130     base::CopyFile(icon, icon_path_);
131
132   base::FilePath xwalk_path(info::kXwalkPath);
133   base::FilePath dir_exec(execute_path_.DirName());
134   if (!base::PathExists(dir_exec))
135     base::CreateDirectory(dir_exec);
136
137   base::CreateSymbolicLink(xwalk_path, execute_path_);
138   LOG(INFO) << "Copying and linking files into correct locations. [DONE]";
139   return true;
140 }
141
142 bool PackageInstaller::WriteToPackageInfoDB() {
143   uid_t uid;
144   gid_t gid;
145   struct passwd pwd;
146   char pwd_buffer[1024];
147   struct passwd *res;
148
149   getpwnam_r(info::kOwner, &pwd, pwd_buffer, sizeof(pwd_buffer), &res);
150   if (res == NULL) {
151     LOG(ERROR) << "Fail to get PW name";
152     return false;
153   }
154   uid = pwd.pw_uid;
155   gid = pwd.pw_gid;
156   if (!ChangeOwnerRecursive(data_dir_.Append(info::kAppDir), uid, gid) ||
157       !ChangeOwnerRecursive(data_dir_.Append(info::kAppDBPath), uid, gid) ||
158       !ChangeOwnerRecursive(
159           data_dir_.Append(info::kAppDBJournalPath), uid, gid))
160     return false;
161
162   if (access(xml_path_.MaybeAsASCII().c_str(), F_OK) != 0)
163     return false;
164   int result = pkgmgr_parser_parse_manifest_for_installation(
165       xml_path_.MaybeAsASCII().c_str(), NULL);
166   if (result != 0) {
167     LOG(ERROR) << "Manifest parser error: " << result;
168     return false;
169   }
170   LOG(INFO) << "Writing package information in database. [DONE]";
171   return true;
172 }
173
174 bool PackageInstaller::Install() {
175   return GeneratePkgInfoXml() &&
176       CopyOrLinkResources() &&
177       WriteToPackageInfoDB();
178 }
179
180 bool PackageInstaller::Uninstall() {
181   bool success = true;
182   int result = pkgmgr_parser_parse_manifest_for_uninstallation(
183       xml_path_.MaybeAsASCII().c_str(), NULL);
184   if (result != 0) {
185     LOG(ERROR) << "Manifest parser error: " << result;
186     return false;
187   }
188
189   success &= base::DeleteFile(icon_path_, false);
190   success &= base::DeleteFile(execute_path_, false);
191   success &= base::DeleteFile(xml_path_, false);
192   if (!success)
193     return false;
194
195   LOG(INFO) << "Removing and unlinking files from installed locations. [DONE]";
196   return true;
197 }
198
199 bool PackageInstaller::ChangeOwnerRecursive(
200     const base::FilePath& path,
201     const uid_t& uid,
202     const gid_t& gid) {
203   if (lchown(path.MaybeAsASCII().c_str(), uid, gid) != 0) {
204     LOG(ERROR) << "Failed to change ownership of " << path.MaybeAsASCII();
205     return false;
206   }
207
208   base::FileEnumerator file_iter(
209       path,
210       true,
211       base::FileEnumerator::FILES|base::FileEnumerator::DIRECTORIES);
212   base::FilePath file(file_iter.Next());
213   while (!file.empty()) {
214     if (!ChangeOwnerRecursive(file, uid, gid))
215       return false;
216     file = file_iter.Next();
217   }
218   return true;
219 }
220
221 }  // namespace application
222 }  // namespace xwalk