2 * Copyright (c) 2016 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 * @file file-system.cpp
18 * @author Dongsun Lee (ds73.lee@samsung.com)
22 #include "service/file-system.h"
25 #include <system_error>
31 #include "common/audit/logger.h"
32 #include "common/exception.h"
33 #include "service/app-deleter.h"
34 #include "service/fs-utils.h"
35 #include "service/dir-blacklist.h"
37 #include <pkgmgr-info.h>
43 inline std::regex makeRegexpr(const char *str)
45 return std::regex(str, std::regex_constants::extended);
48 std::vector<std::regex> g_regexprs{
49 #ifdef PLATFORM_VERSION_3
50 makeRegexpr("^(/opt/usr/apps/([^/]+))"), // /opt/usr/apps/{pkgid}/
51 makeRegexpr("^(/home/([^/]+)/apps_rw/([^/]+))"), // /home/{user}/apps_rw/{pkgid}/
52 makeRegexpr("^(/opt/home/([^/]+)/apps_rw/([^/]+))"), // /opt/home/{user}/apps_rw/{pkgid}/
53 makeRegexpr("^(/sdcard/app2sd/([^/]+)/([^/]+))"), // /sdcard/app2sd/{user}/{pkgid}/
54 makeRegexpr("^(/sdcard/app2sd/([^/]+))"), // /sdcard/app2sd/{pkgid}/
55 makeRegexpr("^(/sdcard/apps/([^/]+)/apps_rw/([^/]+))") // /sdcard/apps/{user}/apps_rw/{pkgid}/
57 makeRegexpr("^(/usr/apps/([^/]+))"), // /usr/apps/{pkgid}/
58 makeRegexpr("^(/opt/usr/apps/([^/]+))"), // /opt/usr/apps/{pkgid}/
59 makeRegexpr("^(/sdcard/apps/([^/]+))"), // /sdcard/apps/{pkgid}/
60 makeRegexpr("^(/sdcard/app2sd/([^/]+))"), // /sdcard/app2sd/{pkgid}/
64 } // namespace anonymous
66 int File::getPkgTypes(const std::string &user, const std::string &pkgid)
68 pkgmgrinfo_pkginfo_h handle;
70 #ifdef PLATFORM_VERSION_3
73 ret = ::pkgmgrinfo_pkginfo_get_pkginfo(pkgid.c_str(), &handle);
75 ret = ::pkgmgrinfo_pkginfo_get_usr_pkginfo(pkgid.c_str(), getUid(user), &handle);
78 auto ret = ::pkgmgrinfo_pkginfo_get_pkginfo(pkgid.c_str(), &handle);
81 if (ret != PMINFO_R_OK) {
82 INFO("Extracted pkgid[" << pkgid << "] from filepath isn't pkg id. "
87 auto type = static_cast<int>(Type::Package);
89 bool isPreloaded = false;
90 ret = ::pkgmgrinfo_pkginfo_is_preload(handle, &isPreloaded);
92 if (ret != PMINFO_R_OK)
93 ERROR("Failed to ::pkgmgrinfo_pkginfo_is_preload: " << ret);
96 type |= static_cast<int>(Type::PreLoaded);
98 ::pkgmgrinfo_pkginfo_destroy_pkginfo(handle);
103 std::string File::getPkgPath(const std::string &path)
107 for (const auto ®e : g_regexprs) {
108 if (!std::regex_search(path, matched, rege))
115 if (matched.size() == 3) {
116 pkgPath = matched[1];
118 } else if (matched.size() == 4) {
119 pkgPath = matched[1];
120 pkgUser = matched[2];
126 auto type = File::getPkgTypes(pkgUser, pkgId);
128 return ((type & static_cast<int>(Type::Package)) &&
129 (!(type & static_cast<int>(Type::PreLoaded)))) ? pkgPath : path;
135 File::File(const std::string &fpath, const FilePtr &parentdir, int type,
136 std::unique_ptr<struct stat> &&statptr) :
137 m_path(fpath), m_type(type), m_statptr(std::move(statptr))
139 if (parentdir != nullptr) {
140 if (parentdir->isPackage()) {
141 this->m_appPkgPath = parentdir->getAppPkgPath();
142 this->m_appPkgId = parentdir->getAppPkgId();
143 this->m_appUser = parentdir->getAppUser();
145 this->m_type |= static_cast<int>(File::Type::Package);
147 if (parentdir->isPreloaded())
148 this->m_type |= static_cast<int>(File::Type::PreLoaded);
151 } else if (!this->isDir()) {
152 this->m_type &= ~(static_cast<int>(File::Type::Package) |
153 static_cast<int>(File::Type::PreLoaded));
159 for (const auto ®e : g_regexprs) {
160 if (!std::regex_search(this->m_path, matched, rege))
163 if (matched.size() == 3) {
164 this->m_appPkgPath = matched[1];
165 this->m_appPkgId = matched[2];
166 this->m_appUser.clear();
167 } else if (matched.size() == 4) {
168 this->m_appPkgPath = matched[1];
169 this->m_appUser = matched[2];
170 this->m_appPkgId = matched[3];
175 this->m_type |= File::getPkgTypes(this->m_appUser, this->m_appPkgId);
181 void File::remove() const
183 if (this->isInApp()) {
184 DEBUG("remove app: " << this->m_appPkgId);
185 AppDeleter::remove(this->m_appPkgId, this->m_appUser);
187 DEBUG("remove file: " << this->m_path);
188 if (::remove(this->m_path.c_str()) != 0)
189 ThrowExc(CSR_ERROR_REMOVE_FAILED,
190 "Failed to remove file: " << this->m_path << " with errno: " << errno);
194 FilePtr File::createIfModified(const std::string &fpath, const FilePtr &parentdir, time_t modifiedSince)
196 return File::createInternal(fpath, parentdir, modifiedSince, true);
199 FilePtr File::create(const std::string &fpath, const FilePtr &parentdir, time_t modifiedSince)
201 return File::createInternal(fpath, parentdir, modifiedSince, false);
204 FilePtr File::createInternal(const std::string &fpath, const FilePtr &parentdir,
205 time_t modifiedSince, bool isModifiedOnly)
207 auto statptr = getStat(fpath);
209 if (statptr == nullptr)
210 ThrowExcWarn(CSR_ERROR_FILE_DO_NOT_EXIST, "file not exist or no permission: " <<
212 else if (!S_ISREG(statptr->st_mode) && !S_ISDIR(statptr->st_mode))
213 ThrowExc(CSR_ERROR_FILE_SYSTEM, "file type is not reguler or dir: " << fpath);
215 auto type = static_cast<int>(S_ISREG(statptr->st_mode) ? Type::File : Type::Directory);
217 if (modifiedSince == -1 || statptr->st_ctime > modifiedSince) {
218 DEBUG("file[" << fpath << "] is changed since[" << modifiedSince << "]");
219 type |= static_cast<int>(Type::Modified);
222 if (isModifiedOnly && !(type & static_cast<int>(Type::Modified)))
225 return FilePtr(new File(fpath, parentdir, type, std::move(statptr)));
228 FsVisitor::DirPtr FsVisitor::openDir(const std::string &dir)
230 return std::unique_ptr<DIR, int(*)(DIR *)>(::opendir(dir.c_str()), ::closedir);
233 FsVisitorPtr FsVisitor::create(const std::string &dirpath, bool isBasedOnName, time_t modifiedSince)
235 auto statptr = getStat(dirpath);
236 if (statptr == nullptr)
237 ThrowExcWarn(CSR_ERROR_FILE_DO_NOT_EXIST, "directory not exist or no "
238 "permission: " << dirpath);
239 else if (!S_ISDIR(statptr->st_mode))
240 ThrowExc(CSR_ERROR_FILE_SYSTEM, "file type is not directory: " << dirpath);
242 return FsVisitorPtr(new FsVisitor(dirpath, isBasedOnName, modifiedSince));
245 FsVisitor::FsVisitor(const std::string &dirpath, bool isBasedOnName, time_t modifiedSince) :
246 m_since(modifiedSince), m_dirptr(nullptr, ::closedir),
247 m_entryBuf(static_cast<struct dirent *>(::malloc(offsetof(struct dirent, d_name) + NAME_MAX + 1))),
248 m_isDone(true), m_isBasedOnName(isBasedOnName)
250 if (this->m_entryBuf == nullptr)
251 throw std::bad_alloc();
253 this->m_dirs.emplace(File::create(dirpath, nullptr));
256 FsVisitor::~FsVisitor()
258 ::free(this->m_entryBuf);
261 FilePtr FsVisitor::next()
264 if (this->m_isDone) {
265 while (!this->m_dirs.empty() &&
266 !(this->m_dirptr = openDir(this->m_dirs.front()->getPath())) &&
267 isInBlackList(this->m_dirs.front()->getPath()))
270 if (this->m_dirs.empty()) {
271 this->m_currentdir.reset();
272 this->m_isDone = true;
275 this->m_currentdir = std::move(this->m_dirs.front());
277 this->m_isDone = false;
278 DEBUG("dir opened: " << this->m_currentdir->getPath());
282 struct dirent *result = nullptr;
283 const auto &parent_dirpath = this->m_currentdir->getPath();
284 if (::readdir_r(this->m_dirptr.get(), this->m_entryBuf, &result) != 0) {
285 ERROR("readdir_r error on dir: " << parent_dirpath <<
286 " with errno: " << errno << ". Silently ignore this error & dir stream"
287 " to reduce side-effect of traversing all the other file systems.");
288 this->m_isDone = true;
290 } else if (result == nullptr) {
291 DEBUG("End of stream of dir: " << parent_dirpath);
292 this->m_isDone = true;
296 const auto &name = result->d_name;
297 auto name_size = ::strlen(name);
302 auto fullpath = (parent_dirpath.back() == '/') ?
303 (parent_dirpath + name) : (parent_dirpath + "/" + name);
305 if (result->d_type == DT_DIR) {
306 if ((name_size == 1 && name[0] == '.') ||
307 (name_size == 2 && name[0] == '.' && name[1] == '.'))
312 dirptr = File::create(fullpath, this->m_currentdir);
313 } catch (const Exception &e) {
314 if (e.error() == CSR_ERROR_FILE_DO_NOT_EXIST) {
315 WARN("Perm denied to create file on pkg path: " << fullpath);
322 if (this->m_isBasedOnName && dirptr->isInApp())
325 DEBUG("push dir to dirs queue: " << fullpath);
326 this->m_dirs.emplace(std::move(dirptr));
327 } else if (result->d_type == DT_REG) {
329 auto fileptr = File::createIfModified(
330 fullpath, this->m_currentdir, this->m_since);
334 } catch (const Exception &e) {
335 if (e.error() == CSR_ERROR_FILE_DO_NOT_EXIST)
336 WARN("file not exist: " << fullpath << " msg: " << e.what());
337 else if (e.error() == CSR_ERROR_FILE_SYSTEM)
338 WARN("file type is not regular...? can it be happened?"
339 " :" << fullpath << " msg: " << e.what());