This repository has been archived by the owner on Apr 3, 2020. It is now read-only.
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
[Download] Fix and complete Download API
Refactored Filesytem and Download API to share code related to virtual roots. Pass TCT tests. Fix example. BUG=XWALK-1070
- Loading branch information
Showing
11 changed files
with
536 additions
and
409 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,319 @@ | ||
// Copyright (c) 2014 Intel Corporation. All rights reserved. | ||
// Use of this source code is governed by a BSD-style license that can be | ||
// found in the LICENSE file. | ||
|
||
#include "common/virtual_fs.h" | ||
|
||
#include <dirent.h> | ||
#include <sys/stat.h> | ||
#include <sys/types.h> | ||
|
||
#include <pkgmgr-info.h> | ||
#include <tzplatform_config.h> | ||
|
||
#include <cassert> | ||
#include <algorithm> | ||
#include <sstream> | ||
#include <string> | ||
|
||
#include "common/extension.h" | ||
|
||
namespace { | ||
|
||
const std::string kInternalStorage = "internal"; | ||
const std::string kRemovableStorage = "removable"; | ||
|
||
const std::string kStorageTypeInternal = "INTERNAL"; | ||
const std::string kStorageTypeExternal = "EXTERNAL"; | ||
const std::string kStorageStateMounted = "MOUNTED"; | ||
const std::string kStorageStateRemoved = "REMOVED"; | ||
const std::string kStorageStateUnmountable = "UNMOUNTABLE"; | ||
|
||
}; // namespace | ||
|
||
const std::string VirtualFS::kLocationCamera = "camera"; | ||
const std::string VirtualFS::kLocationMusic = "music"; | ||
const std::string VirtualFS::kLocationImages = "images"; | ||
const std::string VirtualFS::kLocationVideos = "videos"; | ||
const std::string VirtualFS::kLocationDownloads = "downloads"; | ||
const std::string VirtualFS::kLocationDocuments = "documents"; | ||
const std::string VirtualFS::kLocationRingtones = "ringtones"; | ||
const std::string VirtualFS::kLocationWgtPackage = "wgt-package"; | ||
const std::string VirtualFS::kLocationWgtPrivate = "wgt-private"; | ||
const std::string VirtualFS::kLocationWgtPrivateTmp = "wgt-private-tmp"; | ||
|
||
VirtualFS::VirtualFS() { | ||
std::string app_path = GetApplicationPath(); | ||
if (!app_path.empty()) { | ||
AddInternalStorage(kLocationWgtPackage, app_path); | ||
AddInternalStorage(kLocationWgtPrivate, JoinPath(app_path, "private")); | ||
AddInternalStorage(kLocationWgtPrivateTmp, JoinPath(app_path, "tmp")); | ||
} | ||
|
||
AddInternalStorage(kLocationCamera, tzplatform_getenv(TZ_USER_CAMERA)); | ||
AddInternalStorage(kLocationMusic, tzplatform_getenv(TZ_USER_SOUNDS)); | ||
AddInternalStorage(kLocationImages, tzplatform_getenv(TZ_USER_IMAGES)); | ||
AddInternalStorage(kLocationVideos, tzplatform_getenv(TZ_USER_VIDEOS)); | ||
AddInternalStorage(kLocationDownloads, tzplatform_getenv(TZ_USER_DOWNLOADS)); | ||
AddInternalStorage(kLocationDocuments, tzplatform_getenv(TZ_USER_DOCUMENTS)); | ||
AddInternalStorage(kLocationRingtones, | ||
tzplatform_mkpath(TZ_USER_SHARE, "settings/Ringtones")); | ||
storage_changed_cb_ = NULL; | ||
cb_user_data_ = NULL; | ||
} | ||
|
||
VirtualFS::~VirtualFS() { | ||
} | ||
|
||
std::string VirtualFS::JoinPath(const std::string& one, | ||
const std::string& another) { | ||
return one + '/' + another; | ||
} | ||
|
||
bool VirtualFS::MakePath(const std::string& path, int mode) { | ||
// Path should start with '/' and contain at least 1 character after '/'. | ||
if (path.empty() || path[0] != '/' || path.length() < 2) | ||
return false; | ||
|
||
struct stat st; | ||
std::string dir = path; | ||
if (stat(dir.c_str(), &st) == 0) | ||
return true; | ||
|
||
// Add trailing '/' if missing, so we can iterate till the end of the path. | ||
if (dir[dir.size() - 1] != '/') | ||
dir += '/'; | ||
|
||
for (std::string::iterator iter = dir.begin(); iter != dir.end();) { | ||
std::string::iterator cur_iter = std::find(iter, dir.end(), '/'); | ||
|
||
// If '/' is found at the beginning of the string, iterate to the next '/'. | ||
if (cur_iter == iter) { | ||
++iter; | ||
cur_iter = std::find(iter, dir.end(), '/'); | ||
} | ||
|
||
std::string new_path = std::string(dir.begin(), cur_iter); | ||
|
||
// If path doesn't exist, try to create one and continue iteration. | ||
// In case of error, stop iteration and return. | ||
if (stat(new_path.c_str(), &st) != 0) { | ||
if (mkdir(new_path.c_str(), mode) != 0 && errno != EEXIST ) | ||
return false; | ||
// If path exists and it is not a directory, stop iteration and return. | ||
} else if (!S_ISDIR(st.st_mode)) { | ||
return false; | ||
} | ||
|
||
// Advance iterator and create next parent folder. | ||
iter = cur_iter; | ||
if (cur_iter != dir.end()) | ||
++iter; | ||
} | ||
return true; | ||
} | ||
|
||
int VirtualFS::GetDirEntryCount(const char* path) { | ||
int count = 0; | ||
DIR* dir = opendir(path); | ||
if (!dir) | ||
return count; | ||
|
||
struct dirent entry; | ||
struct dirent *result; | ||
int ret = readdir_r(dir, &entry, &result); | ||
|
||
for (; ret == 0 && result != NULL; ret = readdir_r(dir, &entry, &result)) { | ||
if (entry.d_type == DT_REG || entry.d_type == DT_DIR) | ||
count++; | ||
} | ||
|
||
closedir(dir); | ||
return count; | ||
} | ||
|
||
std::string VirtualFS::GetAppId(const std::string& package_id) { | ||
char* appid = NULL; | ||
pkgmgrinfo_pkginfo_h pkginfo_handle; | ||
int ret = pkgmgrinfo_pkginfo_get_pkginfo(package_id.c_str(), &pkginfo_handle); | ||
if (ret != PMINFO_R_OK) | ||
return std::string(); | ||
ret = pkgmgrinfo_pkginfo_get_mainappid(pkginfo_handle, &appid); | ||
if (ret != PMINFO_R_OK) { | ||
pkgmgrinfo_pkginfo_destroy_pkginfo(pkginfo_handle); | ||
return std::string(); | ||
} | ||
|
||
std::string retval(appid); | ||
pkgmgrinfo_pkginfo_destroy_pkginfo(pkginfo_handle); | ||
return retval; | ||
} | ||
|
||
std::string VirtualFS::GetExecPath(const std::string& app_id) { | ||
char* exec_path = NULL; | ||
pkgmgrinfo_appinfo_h appinfo_handle; | ||
int ret = pkgmgrinfo_appinfo_get_appinfo(app_id.c_str(), &appinfo_handle); | ||
if (ret != PMINFO_R_OK) | ||
return std::string(); | ||
ret = pkgmgrinfo_appinfo_get_exec(appinfo_handle, &exec_path); | ||
if (ret != PMINFO_R_OK) { | ||
pkgmgrinfo_appinfo_destroy_appinfo(appinfo_handle); | ||
return std::string(); | ||
} | ||
|
||
std::string retval(exec_path); | ||
pkgmgrinfo_appinfo_destroy_appinfo(appinfo_handle); | ||
return retval; | ||
} | ||
|
||
bool VirtualFS::GetStorageByLabel(const std::string& label, Storage& storage) { | ||
storage_foreach_device_supported(OnStorageDeviceSupported, this); | ||
Storages::const_iterator it = storages_.find(label); | ||
|
||
if (it == storages_.end()) { | ||
return false; | ||
} | ||
storage = it->second; | ||
return true; | ||
} | ||
|
||
Storages::const_iterator VirtualFS::begin() { | ||
storage_foreach_device_supported(OnStorageDeviceSupported, this); | ||
return storages_.begin(); | ||
} | ||
|
||
Storages::const_iterator VirtualFS::end() const { | ||
return storages_.end(); | ||
} | ||
|
||
std::string VirtualFS::GetApplicationPath() { | ||
std::string id_str = common::Extension::GetRuntimeVariable("app_id", 64); | ||
std::string pkg_id = id_str.substr(1, id_str.rfind('"') - 1); | ||
if (pkg_id.empty()) | ||
return std::string(); | ||
std::string app_id = GetAppId(pkg_id); | ||
if (app_id.empty()) | ||
return std::string(); | ||
std::string exec_path = GetExecPath(app_id); | ||
if (exec_path.empty()) | ||
return std::string(); | ||
|
||
size_t index = exec_path.find(pkg_id); | ||
if (index != std::string::npos) | ||
return exec_path.substr(0, index + pkg_id.length()); | ||
return std::string(); | ||
} | ||
|
||
std::string VirtualFS::GetRealPath(const std::string& fullPath) const { | ||
std::size_t pos = fullPath.find_first_of('/'); | ||
std::string virtual_root = fullPath; | ||
|
||
if (pos != std::string::npos) { | ||
virtual_root = fullPath.substr(0, pos); | ||
} | ||
|
||
Storages::const_iterator it = storages_.find(virtual_root); | ||
|
||
if (it == storages_.end()) | ||
return std::string(); | ||
|
||
if (pos != std::string::npos) | ||
return it->second.GetFullPath() + fullPath.substr(pos); | ||
|
||
return it->second.GetFullPath(); | ||
} | ||
|
||
void VirtualFS::AddInternalStorage( | ||
const std::string& label, const std::string& path) { | ||
if (MakePath(path, kDefaultFileMode)) | ||
storages_.insert(SorageLabelPair(label, | ||
Storage(-1, | ||
Storage::STORAGE_TYPE_INTERNAL, | ||
Storage::STORAGE_STATE_MOUNTED, | ||
path))); | ||
} | ||
|
||
void VirtualFS::AddStorage(int id, | ||
storage_type_e type, | ||
storage_state_e state, | ||
const std::string& path) { | ||
std::string label; | ||
if (type == STORAGE_TYPE_INTERNAL) | ||
label = kInternalStorage + std::to_string(id); | ||
else if (type == STORAGE_TYPE_EXTERNAL) | ||
label = kRemovableStorage + std::to_string(id); | ||
|
||
storages_.insert(SorageLabelPair(label, | ||
Storage(id, | ||
type, | ||
state, | ||
path))); | ||
if (std::find(watched_storages_.begin(), | ||
watched_storages_.end(), id) != watched_storages_.end()) { | ||
watched_storages_.push_back(id); | ||
storage_set_state_changed_cb(id, OnStorageStateChanged, this); | ||
} | ||
} | ||
|
||
void VirtualFS::SetOnStorageChangedCb(CallBackFunctionPtr cb, void* user_data) { | ||
storage_changed_cb_ = cb; | ||
cb_user_data_ = user_data; | ||
} | ||
|
||
void VirtualFS::NotifyStorageStateChanged(int id, | ||
storage_state_e state) { | ||
for (Storages::iterator it = storages_.begin(); it != storages_.end(); ++it) { | ||
if (it->second.GetId() == id) { | ||
it->second.SetState(state); | ||
if (storage_changed_cb_) { | ||
storage_changed_cb_(it->first, it->second, cb_user_data_); | ||
} | ||
break; | ||
} | ||
} | ||
} | ||
|
||
bool VirtualFS::OnStorageDeviceSupported( | ||
int id, storage_type_e type, storage_state_e state, | ||
const char* path, void* user_data) { | ||
reinterpret_cast<VirtualFS*>(user_data)->AddStorage( | ||
id, type, state, path); | ||
return true; | ||
} | ||
|
||
void VirtualFS::OnStorageStateChanged( | ||
int id, storage_state_e state, void* user_data) { | ||
reinterpret_cast<VirtualFS*>(user_data)->NotifyStorageStateChanged( | ||
id, state); | ||
} | ||
|
||
/* | ||
* Storage Class | ||
*/ | ||
|
||
Storage::Storage( | ||
int id, int type, int state, const std::string& fullpath) | ||
: id_(id), | ||
type_(type), | ||
state_(state), | ||
fullpath_(fullpath) { } | ||
|
||
std::string Storage::GetType() const { | ||
return (type_ == Storage::STORAGE_TYPE_INTERNAL) ? kStorageTypeInternal : | ||
kStorageTypeExternal; | ||
} | ||
|
||
std::string Storage::GetState() const { | ||
switch (state_) { | ||
case Storage::STORAGE_STATE_MOUNTED: | ||
case Storage::STORAGE_STATE_MOUNTED_READONLY: | ||
return kStorageStateMounted; | ||
case Storage::STORAGE_STATE_REMOVED: | ||
return kStorageStateRemoved; | ||
case Storage::STORAGE_STATE_UNMOUNTABLE: | ||
return kStorageStateUnmountable; | ||
default: | ||
assert(!"Not reached"); | ||
} | ||
return std::string(); | ||
} |
Oops, something went wrong.