2 * Copyright (c) 2011 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.
20 #include <sys/types.h>
28 #include <Commons/Exception.h>
29 #include <Filesystem/PathUtils.h>
30 #include <Filesystem/Enums.h>
32 #include "NodeFilterMatcher.h"
34 namespace WrtDeviceApis {
35 namespace Filesystem {
39 INodePtr Node::resolve(const IPathPtr& path)
42 if (lstat(path->getFullPath().c_str(), &info) != 0) {
43 LogError("File: " << path->getFullPath().c_str());
44 ThrowMsg(Commons::PlatformException,
45 "Node does not exist or access denied.");
48 if (!S_ISDIR(info.st_mode) & !S_ISREG(info.st_mode)) {
49 ThrowMsg(Commons::PlatformException,
50 "Platform node is of unsupported type.");
53 NodeType type = S_ISDIR(info.st_mode) ? NT_DIRECTORY : NT_FILE;
54 NodePtr result(new Node(path, type));
55 return DPL::StaticPointerCast<INode>(result);
58 IPathPtr Node::getPath() const
60 return IPath::create(m_path->getFullPath());
63 INodePtr Node::getChild(const IPathPtr& path)
65 if (m_type != NT_DIRECTORY) {
66 ThrowMsg(Commons::PlatformException, "Not a directory.");
68 return Node::resolve(*m_path + *path);
71 NodeType Node::getType() const
76 int Node::getPermissions() const
81 void Node::setPermissions(int perms)
86 Node::NameList Node::getChildNames() const
88 if (m_type != NT_DIRECTORY) {
89 ThrowMsg(Commons::PlatformException, "Node is not directory.");
92 if ((m_perms & PERM_READ) == 0) {
93 ThrowMsg(Commons::SecurityException, "No permission.");
96 DIR* dir = opendir(m_path->getFullPath().c_str());
98 ThrowMsg(Commons::PlatformException,
99 "Node has been deleted from platform.");
104 struct dirent *entry = NULL;
105 while ((entry = readdir(dir))) {
106 if (!strncmp(entry->d_name, ".",
107 1) || !strncmp(entry->d_name, "..", 2)) {
110 result.push_back(entry->d_name);
113 ThrowMsg(Commons::PlatformException, "Error while reading directory.");
116 if (closedir(dir) != 0) {
117 ThrowMsg(Commons::PlatformException, "Could not close platform node.");
123 NodeList Node::getChildNodes(const NodeFilterPtr& filter) const
125 if (m_type != NT_DIRECTORY) {
126 ThrowMsg(Commons::PlatformException, "Node is not directory.");
129 if ((m_perms & PERM_READ) == 0) {
130 ThrowMsg(Commons::SecurityException, "No permission.");
133 DIR* dir = opendir(m_path->getFullPath().c_str());
135 ThrowMsg(Commons::PlatformException,
136 "Node has been deleted from platform.");
141 struct dirent *entry = NULL;
142 while ((entry = readdir(dir))) {
143 if (!strncmp(entry->d_name, ".",
144 1) || !strncmp(entry->d_name, "..", 2)) {
149 INodePtr node = Node::resolve(*m_path + entry->d_name);
150 node->setPermissions(getPermissions()); // inherit access rights
151 if (NodeFilterMatcher::match(node, filter)) {
152 result.push_back(node);
155 Catch(Commons::PlatformException) {
160 ThrowMsg(Commons::PlatformException, "Error while reading directory.");
163 if (closedir(dir) != 0) {
164 ThrowMsg(Commons::PlatformException, "Could not close platform node.");
170 void Node::getChildNodes(const EventListNodesPtr& event)
173 EventRequestReceiver<EventListNodes>::PostRequest(event);
176 INodePtr Node::createChild(
177 const IPathPtr& path,
181 if (m_type != NT_DIRECTORY) {
182 ThrowMsg(Commons::PlatformException, "Parent node is not a directory.");
185 if ((m_perms & PERM_WRITE) == 0) {
186 ThrowMsg(Commons::SecurityException, "Not enough permissions.");
191 IPathPtr childPath = *m_path + *path;
192 if (exists(childPath)) {
193 ThrowMsg(Commons::PlatformException, "Node already exists.");
199 result.Reset(createAsFile(childPath, options));
202 result.Reset(createAsDirectory(childPath, options));
205 ThrowMsg(Commons::PlatformException, "Unsupported node type.");
208 result->m_perms = m_perms;
210 ThrowMsg(Commons::PlatformException, "Node creation error");
213 return DPL::StaticPointerCast<INode>(result);
216 IStreamPtr Node::open(int mode)
218 if (m_type == NT_DIRECTORY) {
219 ThrowMsg(Commons::PlatformException,
220 "Cannot attach stream to directory.");
223 if (((mode & AM_READ) && ((m_perms & PERM_READ) == 0)) ||
224 (((mode & AM_WRITE) ||
225 (mode & AM_APPEND)) && ((m_perms & PERM_WRITE) == 0))) {
226 ThrowMsg(Commons::SecurityException, "Not enough permissions.");
229 DPL::Mutex::ScopedLock lock(&m_openStreamsMutex);
230 StreamPtr stream(new Stream(SharedFromThis(), mode));
231 m_openStreams.insert(stream);
232 IManager::getInstance().addOpenedNode(DPL::StaticPointerCast<INode>(
234 return DPL::StaticPointerCast<IStream>(stream);
237 void Node::open(const EventOpenPtr& event)
240 EventRequestReceiver<EventOpen>::PostRequest(event);
243 void Node::remove(int options)
247 removeAsFile(m_path);
250 removeAsDirectory(m_path, (options & OPT_RECURSIVE));
255 std::size_t Node::getSize() const
257 if (m_type == NT_DIRECTORY) {
258 ThrowMsg(Commons::PlatformException,
259 "Getting size for directories is not supported.");
262 struct stat info = stat(m_path);
263 if (!S_ISREG(info.st_mode)) {
264 ThrowMsg(Commons::PlatformException,
265 "Specified node is not a regular file.");
271 std::time_t Node::getCreated() const
273 return stat(m_path).st_ctime;
276 std::time_t Node::getModified() const
278 return stat(m_path).st_mtime;
281 // TODO Optimize it, maybe store a flag indicating that node is a root.
282 INodePtr Node::getParent() const
284 LocationPaths roots = IManager::getInstance().getLocationPaths();
285 for (LocationPaths::iterator it = roots.begin(); it != roots.end(); ++it) {
288 if (*(*it) == *m_path) {
292 return Node::resolve(IPath::create(m_path->getPath()));
295 int Node::getMode() const
298 struct stat info = stat(m_path);
299 if (info.st_mode & S_IRUSR) { result |= PM_USER_READ; }
300 if (info.st_mode & S_IWUSR) { result |= PM_USER_WRITE; }
301 if (info.st_mode & S_IXUSR) { result |= PM_USER_EXEC; }
302 if (info.st_mode & S_IRGRP) { result |= PM_GROUP_READ; }
303 if (info.st_mode & S_IWGRP) { result |= PM_GROUP_WRITE; }
304 if (info.st_mode & S_IXGRP) { result |= PM_GROUP_EXEC; }
305 if (info.st_mode & S_IROTH) { result |= PM_OTHER_READ; }
306 if (info.st_mode & S_IWOTH) { result |= PM_OTHER_WRITE; }
307 if (info.st_mode & S_IXOTH) { result |= PM_OTHER_EXEC; }
311 void Node::read(const EventReadTextPtr& event)
314 EventRequestReceiver<EventReadText>::PostRequest(event);
317 void Node::onStreamClose(const StreamPtr& stream)
320 DPL::Mutex::ScopedLock lock(&m_openStreamsMutex);
321 m_openStreams.erase(stream);
323 if (m_openStreams.empty()) {
324 IManager::getInstance().removeOpenedNode(DPL::StaticPointerCast<INode>(
329 bool Node::exists(const IPathPtr& path)
332 memset(&info, 0, sizeof(struct stat));
333 int status = lstat(path->getFullPath().c_str(), &info);
334 if ((status == 0) || ((status != 0) && (errno != ENOENT))) {
340 struct stat Node::stat(const IPathPtr& path)
343 memset(&result, 0, sizeof(struct stat));
344 if (::stat(path->getFullPath().c_str(),
347 LogError("File: " << path->getFullPath().c_str());
348 ThrowMsg(Commons::PlatformException, "Node does not exist or no access");
353 Node::Node(const IPathPtr& path,
361 Node* Node::createAsFile(const IPathPtr& path,
365 createAsFileInternal(path);
366 return new Node(path, NT_FILE);
369 void Node::createAsFileInternal(const IPathPtr& path)
372 FILE* file = std::fopen(path->getFullPath().c_str(), "wb");
374 ThrowMsg(Commons::PlatformException,
375 "Platform node could not be created.");
380 Node* Node::createAsDirectory(const IPathPtr& path,
383 if (options & OPT_RECURSIVE) {
384 PathUtils::PathList parts = PathUtils::getParts(path);
385 PathUtils::PathListIterator it = parts.begin();
386 for (; it != parts.end(); ++it) {
387 if (!exists(*it)) { createAsDirectoryInternal(*it); }
390 createAsDirectoryInternal(path);
391 return new Node(path, NT_DIRECTORY);
394 void Node::createAsDirectoryInternal(const IPathPtr& path)
396 if (mkdir(path->getFullPath().c_str(), S_IRWXU | S_IRWXG | S_IROTH |
398 ThrowMsg(Commons::PlatformException,
399 "Platform node could not be created.");
403 void Node::removeAsFile(const IPathPtr& path)
405 DPL::Mutex::ScopedLock lock(&m_openStreamsMutex);
406 if (!m_openStreams.empty()) {
407 ThrowMsg(Commons::PlatformException, "Node is locked for I/O.");
409 if (IManager::getInstance().checkIfOpened(path)) {
410 ThrowMsg(Commons::PlatformException, "Node is locked for I/O.");
413 if (unlink(path->getFullPath().c_str()) != 0) {
414 ThrowMsg(Commons::PlatformException,
415 "Error while removing platform node.");
419 void Node::removeAsDirectory(const IPathPtr& path,
427 std::string pth=path->getFullPath();
428 char * const paths[] = {const_cast<char * const>(pth.c_str()), NULL};
430 if ((fts = fts_open(paths, FTS_PHYSICAL|FTS_NOCHDIR, NULL)) == NULL) {
433 LogError(__PRETTY_FUNCTION__ << ": fts_open on "
435 << " failed with error: "
437 ThrowMsg(Commons::PlatformException, "Failed to traverse Node");
440 while ((ftsent = fts_read(fts)) != NULL) {
441 switch (ftsent->fts_info) {
443 //directory in preorder - do nothing
446 //directory in postorder - remove
448 if (rmdir(ftsent->fts_accpath) != 0) {
449 if (errno == EEXIST) {
450 ThrowMsg(Commons::PlatformException,
451 "Node has child nodes.");
453 ThrowMsg(Commons::PlatformException,
454 "Error while removing platform node.");
464 //regular files and other objects that can safely be removed
465 IPathPtr file_path = IPath::create(ftsent->fts_path);
466 removeAsFile(file_path);
474 LogWarning(__PRETTY_FUNCTION__
475 << ": traversal failed with error: "
476 << strerror(ftsent->fts_errno));
481 if (fts_close(fts) == -1) {
483 LogWarning(__PRETTY_FUNCTION__ << ": fts_close failed with error: "
487 if (rmdir(path->getFullPath().c_str()) != 0) {
488 if (errno == EEXIST) {
489 ThrowMsg(Commons::PlatformException, "Node has child nodes.");
491 ThrowMsg(Commons::PlatformException,
492 "Error while removing platform node.");
497 void Node::OnRequestReceived(const EventListNodesPtr& event)
500 NodeList list = event->getNode()->getChildNodes(event->getFilter());
501 event->setResult(list);
503 catch (const Commons::PlatformException& ex) {
504 LogError("Exception: " << ex.GetMessage());
505 event->setExceptionCode(Commons::ExceptionCodes::PlatformException);
507 catch (const Commons::SecurityException& ex) {
508 LogError("Exception: " << ex.GetMessage());
509 event->setExceptionCode(Commons::ExceptionCodes::SecurityException);
513 void Node::OnRequestReceived(const EventOpenPtr& event)
515 if (!event->checkCancelled()) {
517 IStreamPtr result = open(event->getMode());
518 event->setResult(result);
520 catch (const Commons::PlatformException& ex) {
521 LogError("Exception: " << ex.GetMessage());
522 event->setExceptionCode(Commons::ExceptionCodes::PlatformException);
524 catch (const Commons::SecurityException& ex) {
525 LogError("Exception: " << ex.GetMessage());
526 event->setExceptionCode(Commons::ExceptionCodes::SecurityException);
528 //event can be cancelled before executing this code.
529 //when it comes here we doesn't allow it anymore
530 event->setCancelAllowed(false);
532 event->setCancelAllowed(true);
536 void Node::OnRequestReceived(const EventReadTextPtr& event)
539 event->setResult(readText());
540 LogDebug("LEAVIN GRACEFULLY");
542 Catch(Commons::PlatformException) {
543 event->setExceptionCode(Commons::ExceptionCodes::PlatformException);
545 Catch(Commons::SecurityException) {
546 event->setExceptionCode(Commons::ExceptionCodes::SecurityException);
548 //this function doesn't change state of the platform,
549 //so we can allow to cancel it and discard results.
550 event->setCancelAllowed(true);
553 std::string Node::readText()
555 if (m_type != NT_FILE) {
556 ThrowMsg(Commons::PlatformException, "Node is not a file.");
559 if ((m_perms & PERM_READ) == 0) {
560 ThrowMsg(Commons::SecurityException, "No permission.");
563 std::stringstream result;
564 DPL::SharedPtr<Stream> stream(new Stream(SharedFromThis(), AM_READ));
565 while (!stream->isEof()) {
566 result << stream->getLine();
574 std::string Node::toUri(int /*widgetId*/) const
576 // TODO I believe moving this feature to WrtWrapper would make more sense.
577 return "file://" + m_path->getFullPath();