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"
30 #include "service/app-deleter.h"
31 #include "common/audit/logger.h"
35 const char *APP_DIRS[4] = {
36 // Tizen 2.4 app directories
37 "^(/usr/apps/([^/]+))", // /usr/apps/{pkgid}/
38 "^(/opt/usr/apps/([^/]+))", // /opt/usr/apps/{pkgid}/
39 "^(/sdcard/apps/([^/]+))", // /sdcard/apps/{pkgid}/
40 "^(/sdcard/app2sd/([^/]+))", // /sdcard/app2sd/{pkgid}/
41 // Tizen 3.0 app directories
42 //"^(/opt/usr/apps/([^/]+))", // /opt/usr/apps/{pkgid}/
43 //"^(/home/([^/]+)/apps_rw/([^/]+))", // /home/{user}/apps_rw/{pkgid}/
44 //"^(/sdcard/app2sd/([^/]+)/([^/]+))", // /sdcard/app2sd/{user}/{pkgid}/
45 //"^(/sdcard/app2sd/([^/]+))", // /sdcard/app2sd/{pkgid}/
46 //"^(/sdcard/apps/([^/]+)/apps_rw/([^/]+))" // /sdcard/apps/{user}/apps_rw/{pkgid}/
49 //===========================================================================
51 //===========================================================================
52 std::vector<std::regex> File::m_regexprs;
54 File::File(const std::string &fpath) : m_path(fpath), m_inApp(false)
56 if (m_regexprs.size() == 0)
61 for (const auto ®e : m_regexprs) {
62 if (!std::regex_search(m_path, matched, rege))
65 if (matched.size() == 3) {
66 m_appPkgPath = matched[1];
67 m_appPkgId = matched[2];
68 } else if (matched.size() == 4) {
69 m_appPkgPath = matched[1];
70 m_appUser = matched[2];
71 m_appPkgId = matched[3];
80 File::File(const std::string &fpath, bool belongToApp,
81 const std::string &pkgId, const std::string &user, const std::string &pkgPath) :
82 m_path(fpath), m_inApp(belongToApp), m_appPkgId(pkgId), m_appUser(user),
91 const std::string &File::getPath() const
96 bool File::isInApp() const
101 const std::string &File::getAppPkgId() const
106 const std::string &File::getAppUser() const
111 const std::string &File::getAppPkgPath() const
116 void File::initRegex()
118 for (unsigned int i = 0; i < sizeof(APP_DIRS) / sizeof(char *); i++) {
119 std::regex regexpr(APP_DIRS[i], std::regex_constants::extended);
120 m_regexprs.emplace_back(std::move(regexpr));
127 return AppDeleter::remove(m_appPkgId);
129 return ::remove(m_path.c_str()) == 0;
132 //===========================================================================
134 //===========================================================================
135 FsVisitorShrPtr createVisitor(const std::string &fpath, time_t modifiedSince)
138 memset(&s, 0x00, sizeof(s));
139 int ret = stat(fpath.c_str(), &s);
142 if (errno == ENOENT) {
143 WARN("file[" << fpath << "] not exist!");
145 // TODO: throw exception? can we trust errno value?
146 ERROR("stat() failed with file[" << fpath << "]. errno: " << errno);
152 if (S_ISDIR(s.st_mode)) {
153 DEBUG("File type is directory[" << fpath << "]");
154 return FsVisitorShrPtr(new DirVisitor(fpath, modifiedSince));
155 } else if (S_ISREG(s.st_mode)) {
156 DEBUG("File type is regular[" << fpath << "]");
157 return FsVisitorShrPtr(new FileVisitor(fpath, modifiedSince));
159 INFO("File type is unknown[" << fpath << "]");
164 FileSystemVisitor::FileSystemVisitor()
168 FileSystemVisitor::~FileSystemVisitor()
172 bool FileSystemVisitor::isModifiedSince(const std::string &path, time_t since)
176 if (stat(path.c_str(), &s) != 0)
179 return s.st_mtim.tv_sec >= since;
182 FileVisitor::FileVisitor(const std::string &fpath, time_t modifiedSince) :
183 m_path(fpath), m_since(modifiedSince), m_nextItem(std::make_shared<File>(fpath))
187 FileVisitor::~FileVisitor()
191 FileShrPtr FileVisitor::next()
193 if (m_nextItem && !FileSystemVisitor::isModifiedSince(m_path, m_since))
196 FileShrPtr item = m_nextItem;
202 DirVisitor::DirVisitor(const std::string &fpath, time_t modifiedSince) :
203 m_path(fpath), m_since(modifiedSince), m_currDir(nullptr), m_currEntry(nullptr)
209 DirVisitor::~DirVisitor()
213 FileShrPtr DirVisitor::next()
215 struct dirent *result;
217 if (!m_currDir) { // no current dir set
218 if (m_dirs.empty()) // traversed all directories.
221 std::unique_ptr<DIR, std::function<int(DIR *)>> dirp(
222 ::opendir(m_dirs.front().c_str()), ::closedir);
224 if (!dirp) { // fail to open due to no permission
225 DEBUG("DirVisitor: cannot visit(may be due to permission). dir=" <<
227 m_dirs.pop(); // remove front
231 size_t len = offsetof(struct dirent, d_name) + NAME_MAX + 1;
232 std::unique_ptr<struct dirent, std::function<void(void *)>> pEntry(
233 static_cast<struct dirent *>(::malloc(len)), ::free);
235 m_currDir = std::move(dirp);
236 m_currEntry = std::move(pEntry);
237 DEBUG("DirVisitor: start visiting. dir=" << m_dirs.front());
241 if (readdir_r(m_currDir.get(), m_currEntry.get(), &result) != 0)
242 throw std::runtime_error("exception occurred. reading dir = " + m_dirs.front());
244 if (result == nullptr) { // end of dir stream
245 DEBUG("DirVisitor: end visiting. dir=" << m_dirs.front());
248 m_dirs.pop(); // remove front
252 std::string fullPath;
254 if (m_dirs.front().size() > 0 &&
255 m_dirs.front().at(m_dirs.front().size() - 1) == '/')
256 fullPath = m_dirs.front() + result->d_name;
258 fullPath = m_dirs.front() + "/" + result->d_name;
260 if (result->d_type == DT_DIR) {
261 if (strcmp(result->d_name, ".") != 0 && strcmp(result->d_name, "..") != 0)
262 m_dirs.push(fullPath);
267 if (result->d_type == DT_REG) {
268 // check modified time
269 if (!FileSystemVisitor::isModifiedSince(fullPath, m_since))
272 return std::make_shared<File>(fullPath);