3dce31372183da172e2a558ba28071d471a4a66d
[platform/upstream/csr-framework.git] / src / framework / service / file-system.cpp
1 /*
2  *  Copyright (c) 2016 Samsung Electronics Co., Ltd All Rights Reserved
3  *
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
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
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
15  */
16 /*
17  * @file        file-system.cpp
18  * @author      Dongsun Lee (ds73.lee@samsung.com)
19  * @version     1.0
20  * @brief
21  */
22 #include "service/file-system.h"
23
24 #include <stdexcept>
25 #include <stdio.h>
26 #include <string.h>
27 #include <errno.h>
28 #include <sys/stat.h>
29
30 #include "service/app-deleter.h"
31 #include "common/audit/logger.h"
32
33 namespace Csr {
34
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}/
47 };
48
49 //===========================================================================
50 // File
51 //===========================================================================
52 std::vector<std::regex> File::m_regexprs;
53
54 File::File(const std::string &fpath) : m_path(fpath), m_inApp(false)
55 {
56         if (m_regexprs.size() == 0)
57                 initRegex();
58
59         std::smatch matched;
60
61         for (const auto &rege : m_regexprs) {
62                 if (!std::regex_search(m_path, matched, rege))
63                         continue;
64
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];
72                 } else {
73                         continue;
74                 }
75
76                 m_inApp = true;
77         }
78 }
79
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),
83         m_appPkgPath(pkgPath)
84 {
85 }
86
87 File::~File()
88 {
89 }
90
91 const std::string &File::getPath() const
92 {
93         return m_path;
94 }
95
96 bool File::isInApp() const
97 {
98         return m_inApp;
99 }
100
101 const std::string &File::getAppPkgId() const
102 {
103         return m_appPkgId;
104 }
105
106 const std::string &File::getAppUser() const
107 {
108         return m_appUser;
109 }
110
111 const std::string &File::getAppPkgPath() const
112 {
113         return m_appPkgPath;
114 }
115
116 void File::initRegex()
117 {
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));
121         }
122 }
123
124 bool File::remove()
125 {
126         if (m_inApp)
127                 return AppDeleter::remove(m_appPkgId);
128         else
129                 return ::remove(m_path.c_str()) == 0;
130 }
131
132 //===========================================================================
133 // FileVisitor
134 //===========================================================================
135 FsVisitorShrPtr createVisitor(const std::string &fpath, time_t modifiedSince)
136 {
137         struct stat s;
138         memset(&s, 0x00, sizeof(s));
139         int ret = stat(fpath.c_str(), &s);
140
141         if (ret != 0) {
142                 if (errno == ENOENT) {
143                         WARN("file[" << fpath << "] not exist!");
144                 } else {
145                         // TODO: throw exception? can we trust errno value?
146                         ERROR("stat() failed with file[" << fpath << "]. errno: " << errno);
147                 }
148
149                 return nullptr;
150         }
151
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));
158         } else {
159                 INFO("File type is unknown[" << fpath << "]");
160                 return nullptr;
161         }
162 }
163
164 FileSystemVisitor::FileSystemVisitor()
165 {
166 }
167
168 FileSystemVisitor::~FileSystemVisitor()
169 {
170 }
171
172 bool FileSystemVisitor::isModifiedSince(const std::string &path, time_t since)
173 {
174         struct stat s;
175
176         if (stat(path.c_str(), &s) != 0)
177                 return false;
178         else
179                 return s.st_mtim.tv_sec >= since;
180 }
181
182 FileVisitor::FileVisitor(const std::string &fpath, time_t modifiedSince) :
183         m_path(fpath), m_since(modifiedSince), m_nextItem(std::make_shared<File>(fpath))
184 {
185 }
186
187 FileVisitor::~FileVisitor()
188 {
189 }
190
191 FileShrPtr FileVisitor::next()
192 {
193         if (m_nextItem && !FileSystemVisitor::isModifiedSince(m_path, m_since))
194                 m_nextItem.reset();
195
196         FileShrPtr item = m_nextItem;
197         m_nextItem.reset();
198
199         return item;
200 }
201
202 DirVisitor::DirVisitor(const std::string &fpath, time_t modifiedSince) :
203         m_path(fpath), m_since(modifiedSince), m_currDir(nullptr), m_currEntry(nullptr)
204 {
205         m_dirs.push(m_path);
206 }
207
208
209 DirVisitor::~DirVisitor()
210 {
211 }
212
213 FileShrPtr DirVisitor::next()
214 {
215         struct dirent *result;
216
217         if (!m_currDir) { // no current dir set
218                 if (m_dirs.empty()) // traversed all directories.
219                         return nullptr;
220
221                 std::unique_ptr<DIR, std::function<int(DIR *)>> dirp(
222                                         ::opendir(m_dirs.front().c_str()), ::closedir);
223
224                 if (!dirp) { // fail to open due to no permission
225                         DEBUG("DirVisitor: cannot visit(may be due to permission). dir=" <<
226                                   m_dirs.front());
227                         m_dirs.pop(); // remove front
228                         return next();
229                 }
230
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);
234
235                 m_currDir = std::move(dirp);
236                 m_currEntry = std::move(pEntry);
237                 DEBUG("DirVisitor: start visiting. dir=" << m_dirs.front());
238         }
239
240         while (true) {
241                 if (readdir_r(m_currDir.get(), m_currEntry.get(), &result) != 0)
242                         throw std::runtime_error("exception occurred. reading dir = " + m_dirs.front());
243
244                 if (result == nullptr) { // end of dir stream
245                         DEBUG("DirVisitor: end visiting. dir=" << m_dirs.front());
246                         m_currDir.reset();
247                         m_currEntry.reset();
248                         m_dirs.pop(); // remove front
249                         return next();
250                 }
251
252                 std::string fullPath;
253
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;
257                 else
258                         fullPath = m_dirs.front() + "/" + result->d_name;
259
260                 if (result->d_type ==  DT_DIR) {
261                         if (strcmp(result->d_name, ".") != 0 && strcmp(result->d_name, "..") != 0)
262                                 m_dirs.push(fullPath);
263
264                         continue;
265                 }
266
267                 if (result->d_type ==  DT_REG) {
268                         // check modified time
269                         if (!FileSystemVisitor::isModifiedSince(fullPath, m_since))
270                                 continue;
271
272                         return std::make_shared<File>(fullPath);
273                 }
274         }
275
276         return nullptr;
277 }
278
279 } // namespace Csr