2 * Copyright (c) 2015 Samsung Electronics Co., Ltd All Rights Reserved
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
8 * http://www.apache.org/licenses/LICENSE-2.0
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.
17 #include "archive/archive_instance.h"
19 //#include "archive_manager.h"
21 #include <pkgmgr-info.h>
24 #include "archive_callback_data.h"
25 #include "archive_manager.h"
26 #include "archive_utils.h"
27 #include "common/current_application.h"
28 #include "common/filesystem/filesystem_provider.h"
29 #include "common/logger.h"
30 #include "common/picojson.h"
31 #include "common/tools.h"
37 using common::tools::ReportSuccess;
38 using common::tools::ReportError;
41 const std::string kPrivilegeFilesystemRead = "http://tizen.org/privilege/filesystem.read";
42 const std::string kPrivilegeFilesystemWrite = "http://tizen.org/privilege/filesystem.write";
44 const std::string kArchiveFileEntryOptDest = "destination";
45 const std::string kArchiveFileEntryOptStrip = "stripSourceDirectory";
46 const std::string kArchiveFileEntryOptCompressionLevel = "compressionLevel";
48 const std::string kNoCompressionStr = "STORE";
49 const std::string kFastCompressionStr = "FAST";
50 const std::string kNormalCompressionStr = "NORMAL";
51 const std::string kBestCompressionStr = "BEST";
55 ArchiveInstance::ArchiveInstance() {
58 using std::placeholders::_1;
59 using std::placeholders::_2;
61 #define REGISTER_SYNC(c, x) RegisterSyncHandler(c, std::bind(&ArchiveInstance::x, this, _1, _2));
62 #define REGISTER_ASYNC(c, x) RegisterSyncHandler(c, std::bind(&ArchiveInstance::x, this, _1, _2));
64 REGISTER_ASYNC("ArchiveManager_open", Open);
65 REGISTER_SYNC("ArchiveManager_abort", Abort);
67 REGISTER_ASYNC("ArchiveFile_add", Add);
68 REGISTER_ASYNC("ArchiveFile_extractAll", ExtractAll);
69 REGISTER_ASYNC("ArchiveFile_getEntries", GetEntries);
70 REGISTER_ASYNC("ArchiveFile_getEntryByName", GetEntryByName);
71 REGISTER_SYNC("ArchiveFile_close", Close);
73 REGISTER_ASYNC("ArchiveFileEntry_extract", Extract);
75 REGISTER_SYNC("Archive_fetchStorages", FetchStorages);
81 ArchiveInstance::~ArchiveInstance() {
85 void ArchiveInstance::PostError(const PlatformResult& e, double callback_id) {
88 LoggerE("Posting an error: %d, message: %s", static_cast<int>(e.error_code()),
91 picojson::value val = picojson::value(picojson::object());
92 picojson::object& obj = val.get<picojson::object>();
93 obj[JSON_CALLBACK_ID] = picojson::value(callback_id);
97 Instance::PostMessage(this, val.serialize().c_str());
100 void ArchiveInstance::Open(const picojson::value& args, picojson::object& out) {
101 ScopeLogger("%s", args.serialize().c_str());
103 CHECK_PRIVILEGE_ACCESS(kPrivilegeFilesystemWrite, &out);
104 picojson::object data = args.get<picojson::object>();
105 picojson::value v_file = data.at(PARAM_FILE);
106 CHECK_STORAGE_ACCESS(v_file.get<std::string>(), &out);
108 picojson::value v_mode = data.at(PARAM_MODE);
109 picojson::value v_op_id = data.at(PARAM_OPERATION_ID);
110 picojson::object options = data.at(PARAM_OPTIONS).get<picojson::object>();
111 picojson::value v_overwrite = options.at(PARAM_OVERWRITE);
112 const double callbackId = args.get(JSON_CALLBACK_ID).get<double>();
113 const long operationId = static_cast<long>(v_op_id.get<double>());
115 PlatformResult result = stringToFileMode(v_mode.get<std::string>(), &fm);
116 if (result.error_code() != ErrorCode::NO_ERROR) {
117 LoggerE("File mode conversions error");
118 PostError(result, callbackId);
122 OpenCallbackData* callback = new OpenCallbackData(*this);
126 callback->setOperationId(operationId);
127 callback->setCallbackId(callbackId);
129 bool overwrite = false;
130 if (v_overwrite.is<bool>()) {
131 overwrite = v_overwrite.get<bool>();
134 std::string location_full_path = v_file.get<std::string>();
135 PathPtr path = Path::create(location_full_path);
138 if (lstat(path->getFullPath().c_str(), &info) == 0) {
140 result = Node::resolve(path, &node);
141 if (result.error_code() != ErrorCode::NO_ERROR) {
142 LoggerE("Filesystem exception - calling error callback");
143 PostError(result, callbackId);
149 file_ptr = FilePtr(new File(node, File::PermissionList()));
150 LoggerD("open: %s mode: 0x%d overwrite: %d", location_full_path.c_str(), fm, overwrite);
151 if (FileMode::WRITE == fm || FileMode::READ_WRITE == fm) {
153 LoggerD("Deleting existing file: %s", location_full_path.c_str());
154 result = file_ptr->getNode()->remove(OPT_RECURSIVE);
155 if (result.error_code() != ErrorCode::NO_ERROR) {
156 LoggerE("Couldn't remove existing file: %s", location_full_path.c_str());
157 PostError(result, callbackId);
162 file_ptr.reset(); // We need to create new empty file
163 } else if (FileMode::WRITE == fm) {
164 SLoggerE("open: %s with mode: \"w\" file exists and overwrite is FALSE!",
165 location_full_path.c_str());
166 PostError(PlatformResult(ErrorCode::INVALID_MODIFICATION_ERR, "Zip archive already exists"),
178 if (FileMode::WRITE == fm || FileMode::READ_WRITE == fm || FileMode::ADD == fm) {
180 "Archive file not found - trying to create new one at: "
182 location_full_path.c_str());
184 std::string parent_path_string = path->getPath();
185 PathPtr parent_path = Path::create(parent_path_string);
186 LoggerD("Parent path: %s", parent_path_string.c_str());
189 PlatformResult result = Node::resolve(parent_path, &parent_node);
190 if (result.error_code() != ErrorCode::NO_ERROR) {
191 LoggerE("Filesystem exception - calling error callback");
192 PostError(result, callbackId);
198 parent_node->setPermissions(PERM_READ | PERM_WRITE);
199 std::string filename = path->getName();
200 LoggerD("File name: %s", filename.c_str());
201 result = parent_node->createChild(Path::create(filename), NT_FILE, &node_ptr);
202 if (result.error_code() != ErrorCode::NO_ERROR) {
203 LoggerE("Filesystem exception - calling error callback");
204 PostError(result, callbackId);
210 LoggerE("Archive file not found");
211 PostError(PlatformResult(ErrorCode::NOT_FOUND_ERR, "Archive file not found"), callbackId);
216 file_ptr = FilePtr(new File(node_ptr, File::PermissionList()));
219 ArchiveFilePtr afp = ArchiveFilePtr(new ArchiveFile(fm));
220 afp->setFile(file_ptr);
221 afp->setOverwrite(overwrite);
222 callback->setArchiveFile(afp);
224 result = ArchiveManager::getInstance().open(callback);
229 LogAndReportError(result, &out, ("Failed to open archive."));
233 void ArchiveInstance::Abort(const picojson::value& args, picojson::object& out) {
234 ScopeLogger("%s", args.serialize().c_str());
236 picojson::object data = args.get<picojson::object>();
237 picojson::value v_op_id = data.at(PARAM_OPERATION_ID);
239 const long op_id = static_cast<long>(v_op_id.get<double>());
241 ArchiveManager::getInstance().abort(op_id);
246 unsigned int ConvertStringToCompressionLevel(const std::string& level) {
249 if (kNoCompressionStr == level) {
250 return Z_NO_COMPRESSION;
251 } else if (kFastCompressionStr == level) {
253 } else if (kBestCompressionStr == level) {
254 return Z_BEST_COMPRESSION;
256 return Z_DEFAULT_COMPRESSION;
260 void ArchiveInstance::Add(const picojson::value& args, picojson::object& out) {
261 ScopeLogger("%s", args.serialize().c_str());
263 CHECK_PRIVILEGE_ACCESS(kPrivilegeFilesystemWrite, &out);
264 picojson::object data = args.get<picojson::object>();
265 picojson::value v_source = data.at(PARAM_SOURCE_FILE);
266 CHECK_STORAGE_ACCESS(v_source.get<std::string>(), &out);
268 picojson::value v_options = data.at(PARAM_OPTIONS);
269 picojson::value v_op_id = data.at(PARAM_OPERATION_ID);
270 picojson::value v_handle = data.at(ARCHIVE_FILE_HANDLE);
272 const double callbackId = args.get(JSON_CALLBACK_ID).get<double>();
273 const long operationId = static_cast<long>(v_op_id.get<double>());
274 const long handle = static_cast<long>(v_handle.get<double>());
276 AddProgressCallback* callback = new AddProgressCallback(*this);
279 PlatformResult result = Node::resolve(Path::create(v_source.get<std::string>()), &node);
280 if (result.error_code() != ErrorCode::NO_ERROR) {
281 LoggerE("Filesystem exception - calling error callback");
282 PostError(result, callbackId);
288 FilePtr file_ptr = FilePtr(new File(node, File::PermissionList()));
289 ArchiveFileEntryPtr afep = ArchiveFileEntryPtr(new ArchiveFileEntry(file_ptr));
291 callback->setOperationId(operationId);
292 callback->setCallbackId(callbackId);
293 callback->setFileEntry(afep);
295 callback->setBasePath(file_ptr->getNode()->getPath()->getPath());
297 // check and set options
298 LoggerD("Processing OPTIONS dictionary: %s", v_options.serialize().c_str());
299 const auto& dest = v_options.get(kArchiveFileEntryOptDest);
300 if (dest.is<std::string>()) {
301 std::string dic_destination = dest.get<std::string>();
302 LoggerD("Setting destination path to: \"%s\"", dic_destination.c_str());
303 afep->setDestination(dic_destination);
306 const auto& strip = v_options.get(kArchiveFileEntryOptStrip);
307 if (strip.is<bool>()) {
308 bool dic_strip = strip.get<bool>();
309 LoggerD("Setting strip option to: %d", dic_strip);
310 afep->setStriped(dic_strip);
313 const auto& level = v_options.get(kArchiveFileEntryOptCompressionLevel);
314 if (level.is<std::string>()) {
315 std::string dic_compression_level = level.get<std::string>();
316 LoggerD("Setting compression level to: \"%s\"", dic_compression_level.c_str());
317 afep->setCompressionLevel(ConvertStringToCompressionLevel(dic_compression_level));
320 LoggerD("base path:%s base virt:%s", callback->getBasePath().c_str(),
321 callback->getBaseVirtualPath().c_str());
324 result = ArchiveManager::getInstance().getPrivData(handle, &priv);
325 if (result.error_code() != ErrorCode::NO_ERROR) {
326 LoggerE("Exception occurred");
332 if (!priv->isAllowedOperation(ARCHIVE_FUNCTION_API_ARCHIVE_FILE_ADD)) {
333 LoggerE("Not allowed operation");
339 result = priv->add(callback);
340 if (result.error_code() != ErrorCode::NO_ERROR) {
341 LoggerE("Exception occurred");
348 void ArchiveInstance::ExtractAll(const picojson::value& args, picojson::object& out) {
349 ScopeLogger("%s", args.serialize().c_str());
351 CHECK_PRIVILEGE_ACCESS(kPrivilegeFilesystemWrite, &out);
352 picojson::object data = args.get<picojson::object>();
353 picojson::value v_dest_dir = data.at(PARAM_DESTINATION_DIR);
354 CHECK_STORAGE_ACCESS(v_dest_dir.get<std::string>(), &out);
356 picojson::value v_overwrite = data.at(PARAM_OVERWRITE);
357 picojson::value v_op_id = data.at(PARAM_OPERATION_ID);
358 picojson::value v_handle = data.at(ARCHIVE_FILE_HANDLE);
360 const double callbackId = args.get(JSON_CALLBACK_ID).get<double>();
361 const long operationId = static_cast<long>(v_op_id.get<double>());
362 const long handle = static_cast<long>(v_handle.get<double>());
364 ExtractAllProgressCallback* callback = new ExtractAllProgressCallback(*this);
367 PlatformResult result = Node::resolve(Path::create(v_dest_dir.get<std::string>()), &node);
368 if (result.error_code() != ErrorCode::NO_ERROR) {
369 LoggerE("Filesystem exception - calling error callback");
370 PostError(result, callbackId);
376 FilePtr file_ptr = FilePtr(new File(node, File::PermissionList()));
378 callback->setDirectory(file_ptr);
379 callback->setOperationId(operationId);
380 callback->setCallbackId(callbackId);
382 if (v_overwrite.is<bool>()) {
383 callback->setOverwrite(v_overwrite.get<bool>());
387 result = ArchiveManager::getInstance().getPrivData(handle, &priv);
388 if (result.error_code() != ErrorCode::NO_ERROR) {
389 LoggerE("Exception occurred");
395 if (!priv->isAllowedOperation(ARCHIVE_FUNCTION_API_ARCHIVE_FILE_EXTRACT_ALL)) {
396 LoggerE("Not allowed operation");
402 result = priv->extractAll(callback);
403 if (result.error_code() != ErrorCode::NO_ERROR) {
404 LoggerE("Exception occurred");
411 void ArchiveInstance::GetEntries(const picojson::value& args, picojson::object& out) {
412 ScopeLogger("%s", args.serialize().c_str());
414 CHECK_PRIVILEGE_ACCESS(kPrivilegeFilesystemRead, &out);
416 picojson::object data = args.get<picojson::object>();
417 picojson::value v_op_id = data.at(PARAM_OPERATION_ID);
418 picojson::value v_handle = data.at(ARCHIVE_FILE_HANDLE);
420 const double callbackId = args.get(JSON_CALLBACK_ID).get<double>();
421 const long operationId = static_cast<long>(v_op_id.get<double>());
422 const long handle = static_cast<long>(v_handle.get<double>());
424 GetEntriesCallbackData* callback = new GetEntriesCallbackData(*this);
426 callback->setOperationId(operationId);
427 callback->setCallbackId(callbackId);
428 callback->setHandle(handle);
431 PlatformResult result = ArchiveManager::getInstance().getPrivData(handle, &priv);
432 if (result.error_code() != ErrorCode::NO_ERROR) {
433 LoggerE("Exception occurred");
439 if (!priv->isAllowedOperation(ARCHIVE_FUNCTION_API_ARCHIVE_FILE_GET_ENTRIES)) {
440 LoggerE("Not allowed operation");
446 result = priv->getEntries(callback);
447 if (result.error_code() != ErrorCode::NO_ERROR) {
448 LoggerE("Exception occurred");
455 void ArchiveInstance::GetEntryByName(const picojson::value& args, picojson::object& out) {
456 ScopeLogger("%s", args.serialize().c_str());
458 CHECK_PRIVILEGE_ACCESS(kPrivilegeFilesystemRead, &out);
460 picojson::object data = args.get<picojson::object>();
461 picojson::value v_op_id = data.at(PARAM_OPERATION_ID);
462 picojson::value v_handle = data.at(ARCHIVE_FILE_HANDLE);
463 picojson::value v_name = data.at(PARAM_NAME);
465 const double callbackId = args.get(JSON_CALLBACK_ID).get<double>();
466 const long operationId = static_cast<long>(v_op_id.get<double>());
467 const long handle = static_cast<long>(v_handle.get<double>());
469 GetEntryByNameCallbackData* callback = new GetEntryByNameCallbackData(*this);
471 callback->setOperationId(operationId);
472 callback->setCallbackId(callbackId);
473 callback->setName(v_name.get<std::string>());
474 callback->setHandle(handle);
477 PlatformResult result = ArchiveManager::getInstance().getPrivData(handle, &priv);
478 if (result.error_code() != ErrorCode::NO_ERROR) {
479 LoggerE("Exception occurred");
485 if (!priv->isAllowedOperation(ARCHIVE_FUNCTION_API_ARCHIVE_FILE_GET_ENTRY_BY_NAME)) {
486 LoggerE("Not allowed operation");
492 result = priv->getEntryByName(callback);
493 if (result.error_code() != ErrorCode::NO_ERROR) {
494 LoggerE("Exception occurred");
501 void ArchiveInstance::Close(const picojson::value& args, picojson::object& out) {
502 ScopeLogger("%s", args.serialize().c_str());
504 picojson::object data = args.get<picojson::object>();
505 picojson::value v_handle = data.at(ARCHIVE_FILE_HANDLE);
507 const long handle = static_cast<long>(v_handle.get<double>());
510 PlatformResult result = ArchiveManager::getInstance().getPrivData(handle, &priv);
511 if (result.error_code() == ErrorCode::NO_ERROR) {
513 ArchiveManager::getInstance().erasePrivData(handle);
515 LoggerD("Close method was called on already closed archive. Just end execution");
516 LoggerD("%s", result.message().c_str());
522 void ArchiveInstance::Extract(const picojson::value& args, picojson::object& out) {
523 ScopeLogger("%s", args.serialize().c_str());
525 CHECK_PRIVILEGE_ACCESS(kPrivilegeFilesystemWrite, &out);
526 picojson::object data = args.get<picojson::object>();
527 picojson::value v_dest_dir = data.at(PARAM_DESTINATION_DIR);
528 CHECK_STORAGE_ACCESS(v_dest_dir.get<std::string>(), &out);
530 picojson::value v_strip_name = data.at(PARAM_STRIP_NAME);
531 picojson::value v_overwrite = data.at(PARAM_OVERWRITE);
532 picojson::value v_op_id = data.at(PARAM_OPERATION_ID);
533 picojson::value v_handle = data.at(ARCHIVE_FILE_HANDLE);
534 picojson::value v_entry_name = data.at(PARAM_NAME);
536 const double callbackId = args.get(JSON_CALLBACK_ID).get<double>();
537 const auto entry_path = v_entry_name.get<std::string>();
538 if (pathContainsProhibitedSubstrings(entry_path)) {
539 const std::string error_msg = "Entry path " + entry_path + " contains a prohibited substring";
540 LoggerE("%s", error_msg.c_str());
541 PostError(PlatformResult{ErrorCode::UNKNOWN_ERR, error_msg}, callbackId);
545 const long operationId = static_cast<long>(v_op_id.get<double>());
546 const long handle = static_cast<long>(v_handle.get<double>());
548 ExtractEntryProgressCallback* callback = new ExtractEntryProgressCallback(*this);
551 PlatformResult result = Node::resolve(Path::create(v_dest_dir.get<std::string>()), &node);
552 if (result.error_code() != ErrorCode::NO_ERROR) {
553 LoggerE("Filesystem exception - calling error callback");
554 PostError(result, callbackId);
560 FilePtr file_ptr = FilePtr(new File(node, File::PermissionList()));
562 callback->setDirectory(file_ptr);
563 callback->setOperationId(operationId);
564 callback->setCallbackId(callbackId);
566 if (v_overwrite.is<bool>()) {
567 callback->setOverwrite(v_overwrite.get<bool>());
569 if (v_strip_name.is<bool>()) {
570 callback->setStripName(v_strip_name.get<bool>());
573 ArchiveFilePtr archive_file_ptr;
574 result = ArchiveManager::getInstance().getPrivData(handle, &archive_file_ptr);
575 if (result.error_code() != ErrorCode::NO_ERROR) {
576 LoggerE("Exception occurred");
582 ArchiveFileEntryPtrMapPtr entries = archive_file_ptr->getEntryMap();
583 auto it = entries->find(v_entry_name.get<std::string>());
585 // Not found but if our name does not contain '/'
586 // try looking for directory with such name
587 if (entries->end() == it && !isDirectoryPath(v_entry_name.get<std::string>())) {
588 const std::string try_directory = v_entry_name.get<std::string>() + "/";
589 LoggerD("GetEntryByName Trying directory: [%s]", try_directory.c_str());
590 it = entries->find(try_directory);
593 if (entries->end() == it) {
594 LoggerE("Failed to find entry");
595 PostError(PlatformResult(ErrorCode::UNKNOWN_ERR, "Failed to find entry"), callbackId);
601 result = it->second->extractTo(callback);
602 if (result.error_code() != ErrorCode::NO_ERROR) {
603 LoggerE("ArchiveFileEntry.extractTo error");
604 PostError(result, callbackId);
611 void ArchiveInstance::FetchStorages(const picojson::value& args, picojson::object& out) {
614 picojson::array storages;
615 for (const auto& storage : common::FilesystemProvider::Create().GetAllStorages()) {
616 storages.push_back(storage->ToJson());
618 ReportSuccess(picojson::value(storages), out);
621 } // namespace archive
622 } // namespace extension