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>
27 #include <Commons/Exception.h>
28 #include <Filesystem/PathUtils.h>
29 #include <Filesystem/Enums.h>
31 #include "NodeFilterMatcher.h"
33 namespace WrtDeviceApis {
34 namespace Filesystem {
38 INodePtr Node::resolve(const IPathPtr& path)
41 if (lstat(path->getFullPath().c_str(), &info) != 0) {
42 LogError("File: " << path->getFullPath().c_str());
43 ThrowMsg(Commons::PlatformException,
44 "Node does not exist or access denied.");
47 if (!S_ISDIR(info.st_mode) & !S_ISREG(info.st_mode)) {
48 ThrowMsg(Commons::PlatformException,
49 "Platform node is of unsupported type.");
52 NodeType type = S_ISDIR(info.st_mode) ? NT_DIRECTORY : NT_FILE;
53 NodePtr result(new Node(path, type));
54 return DPL::StaticPointerCast<INode>(result);
57 IPathPtr Node::getPath() const
59 return IPath::create(m_path->getFullPath());
62 INodePtr Node::getChild(const IPathPtr& path)
64 if (m_type != NT_DIRECTORY) {
65 ThrowMsg(Commons::PlatformException, "Not a directory.");
67 return Node::resolve(*m_path + *path);
70 NodeType Node::getType() const
75 int Node::getPermissions() const
80 void Node::setPermissions(int perms)
85 Node::NameList Node::getChildNames() const
87 if (m_type != NT_DIRECTORY) {
88 ThrowMsg(Commons::PlatformException, "Node is not directory.");
91 if ((m_perms & PERM_READ) == 0) {
92 ThrowMsg(Commons::SecurityException, "No permission.");
95 DIR* dir = opendir(m_path->getFullPath().c_str());
97 ThrowMsg(Commons::PlatformException,
98 "Node has been deleted from platform.");
103 struct dirent *entry = NULL;
104 while ((entry = readdir(dir))) {
105 if (!strncmp(entry->d_name, ".",
106 1) || !strncmp(entry->d_name, "..", 2)) {
109 result.push_back(entry->d_name);
112 ThrowMsg(Commons::PlatformException, "Error while reading directory.");
115 if (closedir(dir) != 0) {
116 ThrowMsg(Commons::PlatformException, "Could not close platform node.");
122 NodeList Node::getChildNodes(const NodeFilterPtr& filter) const
124 if (m_type != NT_DIRECTORY) {
125 ThrowMsg(Commons::PlatformException, "Node is not directory.");
128 if ((m_perms & PERM_READ) == 0) {
129 ThrowMsg(Commons::SecurityException, "No permission.");
132 DIR* dir = opendir(m_path->getFullPath().c_str());
134 ThrowMsg(Commons::PlatformException,
135 "Node has been deleted from platform.");
140 struct dirent *entry = NULL;
141 while ((entry = readdir(dir))) {
142 if (!strncmp(entry->d_name, ".",
143 1) || !strncmp(entry->d_name, "..", 2)) {
148 INodePtr node = Node::resolve(*m_path + entry->d_name);
149 node->setPermissions(getPermissions()); // inherit access rights
150 if (NodeFilterMatcher::match(node, filter)) {
151 result.push_back(node);
154 Catch(Commons::PlatformException) {
159 ThrowMsg(Commons::PlatformException, "Error while reading directory.");
162 if (closedir(dir) != 0) {
163 ThrowMsg(Commons::PlatformException, "Could not close platform node.");
169 void Node::getChildNodes(const EventListNodesPtr& event)
172 EventRequestReceiver<EventListNodes>::PostRequest(event);
175 INodePtr Node::createChild(
176 const IPathPtr& path,
180 if (m_type != NT_DIRECTORY) {
181 ThrowMsg(Commons::PlatformException, "Parent node is not a directory.");
184 if ((m_perms & PERM_WRITE) == 0) {
185 ThrowMsg(Commons::SecurityException, "Not enough permissions.");
190 IPathPtr childPath = *m_path + *path;
191 if (exists(childPath)) {
192 ThrowMsg(Commons::PlatformException, "Node already exists.");
198 result.Reset(createAsFile(childPath, options));
201 result.Reset(createAsDirectory(childPath, options));
204 ThrowMsg(Commons::PlatformException, "Unsupported node type.");
207 result->m_perms = m_perms;
209 ThrowMsg(Commons::PlatformException, "Node creation error");
212 return DPL::StaticPointerCast<INode>(result);
215 IStreamPtr Node::open(int mode)
217 if (m_type == NT_DIRECTORY) {
218 ThrowMsg(Commons::PlatformException,
219 "Cannot attach stream to directory.");
222 if (((mode & AM_READ) && ((m_perms & PERM_READ) == 0)) ||
223 (((mode & AM_WRITE) ||
224 (mode & AM_APPEND)) && ((m_perms & PERM_WRITE) == 0))) {
225 ThrowMsg(Commons::SecurityException, "Not enough permissions.");
228 DPL::Mutex::ScopedLock lock(&m_openStreamsMutex);
229 StreamPtr stream(new Stream(SharedFromThis(), mode));
230 m_openStreams.insert(stream);
231 IManager::getInstance().addOpenedNode(DPL::StaticPointerCast<INode>(
233 return DPL::StaticPointerCast<IStream>(stream);
236 void Node::open(const EventOpenPtr& event)
239 EventRequestReceiver<EventOpen>::PostRequest(event);
242 void Node::remove(int options)
246 removeAsFile(m_path);
249 removeAsDirectory(m_path, (options & OPT_RECURSIVE));
254 std::size_t Node::getSize() const
256 if (m_type == NT_DIRECTORY) {
257 ThrowMsg(Commons::PlatformException,
258 "Getting size for directories is not supported.");
261 struct stat info = stat(m_path);
262 if (!S_ISREG(info.st_mode)) {
263 ThrowMsg(Commons::PlatformException,
264 "Specified node is not a regular file.");
270 std::time_t Node::getCreated() const
272 return stat(m_path).st_ctime;
275 std::time_t Node::getModified() const
277 return stat(m_path).st_mtime;
280 // TODO Optimize it, maybe store a flag indicating that node is a root.
281 INodePtr Node::getParent() const
283 LocationPaths roots = IManager::getInstance().getLocationPaths();
284 for (LocationPaths::iterator it = roots.begin(); it != roots.end(); ++it) {
287 if (*(*it) == *m_path) {
291 return Node::resolve(IPath::create(m_path->getPath()));
294 int Node::getMode() const
297 struct stat info = stat(m_path);
298 if (info.st_mode & S_IRUSR) { result |= PM_USER_READ; }
299 if (info.st_mode & S_IWUSR) { result |= PM_USER_WRITE; }
300 if (info.st_mode & S_IXUSR) { result |= PM_USER_EXEC; }
301 if (info.st_mode & S_IRGRP) { result |= PM_GROUP_READ; }
302 if (info.st_mode & S_IWGRP) { result |= PM_GROUP_WRITE; }
303 if (info.st_mode & S_IXGRP) { result |= PM_GROUP_EXEC; }
304 if (info.st_mode & S_IROTH) { result |= PM_OTHER_READ; }
305 if (info.st_mode & S_IWOTH) { result |= PM_OTHER_WRITE; }
306 if (info.st_mode & S_IXOTH) { result |= PM_OTHER_EXEC; }
310 void Node::read(const EventReadTextPtr& event)
313 EventRequestReceiver<EventReadText>::PostRequest(event);
316 void Node::onStreamClose(const StreamPtr& stream)
319 DPL::Mutex::ScopedLock lock(&m_openStreamsMutex);
320 m_openStreams.erase(stream);
322 if (m_openStreams.empty()) {
323 IManager::getInstance().removeOpenedNode(DPL::StaticPointerCast<INode>(
328 bool Node::exists(const IPathPtr& path)
331 memset(&info, 0, sizeof(struct stat));
332 int status = lstat(path->getFullPath().c_str(), &info);
333 if ((status == 0) || ((status != 0) && (errno != ENOENT))) {
339 struct stat Node::stat(const IPathPtr& path)
342 memset(&result, 0, sizeof(struct stat));
343 if (::stat(path->getFullPath().c_str(),
346 LogError("File: " << path->getFullPath().c_str());
347 ThrowMsg(Commons::PlatformException, "Node does not exist or no access");
352 Node::Node(const IPathPtr& path,
360 Node* Node::createAsFile(const IPathPtr& path,
364 createAsFileInternal(path);
365 return new Node(path, NT_FILE);
368 void Node::createAsFileInternal(const IPathPtr& path)
371 FILE* file = std::fopen(path->getFullPath().c_str(), "wb");
373 ThrowMsg(Commons::PlatformException,
374 "Platform node could not be created.");
379 Node* Node::createAsDirectory(const IPathPtr& path,
382 if (options & OPT_RECURSIVE) {
383 PathUtils::PathList parts = PathUtils::getParts(path);
384 PathUtils::PathListIterator it = parts.begin();
385 for (; it != parts.end(); ++it) {
386 if (!exists(*it)) { createAsDirectoryInternal(*it); }
389 createAsDirectoryInternal(path);
390 return new Node(path, NT_DIRECTORY);
393 void Node::createAsDirectoryInternal(const IPathPtr& path)
395 if (mkdir(path->getFullPath().c_str(), S_IRWXU | S_IRWXG | S_IROTH |
397 ThrowMsg(Commons::PlatformException,
398 "Platform node could not be created.");
402 void Node::removeAsFile(const IPathPtr& path)
404 DPL::Mutex::ScopedLock lock(&m_openStreamsMutex);
405 if (!m_openStreams.empty()) {
406 ThrowMsg(Commons::PlatformException, "Node is locked for I/O.");
408 if (IManager::getInstance().checkIfOpened(path)) {
409 ThrowMsg(Commons::PlatformException, "Node is locked for I/O.");
412 if (unlink(path->getFullPath().c_str()) != 0) {
413 ThrowMsg(Commons::PlatformException,
414 "Error while removing platform node.");
418 void Node::removeAsDirectory(const IPathPtr& path,
423 DIR* dir = opendir(path->getFullPath().c_str());
425 LogError("File: " << path->getFullPath().c_str());
426 ThrowMsg(Commons::PlatformException,
427 "Node does not exist or access denied.");
430 struct dirent *entry = NULL;
431 while ((entry = readdir(dir))) {
432 if (!strncmp(entry->d_name, ".",
433 1) || !strncmp(entry->d_name, "..", 2)) {
436 IPathPtr subPath = *path + entry->d_name;
438 memset(&info, 0, sizeof(struct stat));
439 if (lstat(subPath->getFullPath().c_str(), &info) == 0) {
441 if (S_ISDIR(info.st_mode)) {
442 removeAsDirectory(subPath, true);
443 } else if (S_ISREG(info.st_mode)) {
444 removeAsFile(subPath);
447 Catch(Commons::PlatformException) {
449 // TODO: Not sure if above exception should be swallowed.
456 if (rmdir(path->getFullPath().c_str()) != 0) {
457 if (errno == EEXIST) {
458 ThrowMsg(Commons::PlatformException, "Node has child nodes.");
460 ThrowMsg(Commons::PlatformException,
461 "Error while removing platform node.");
465 void Node::OnRequestReceived(const EventListNodesPtr& event)
468 NodeList list = event->getNode()->getChildNodes(event->getFilter());
469 event->setResult(list);
471 catch (const Commons::PlatformException& ex) {
472 LogError("Exception: " << ex.GetMessage());
473 event->setExceptionCode(Commons::ExceptionCodes::PlatformException);
475 catch (const Commons::SecurityException& ex) {
476 LogError("Exception: " << ex.GetMessage());
477 event->setExceptionCode(Commons::ExceptionCodes::SecurityException);
481 void Node::OnRequestReceived(const EventOpenPtr& event)
483 if (!event->checkCancelled()) {
485 IStreamPtr result = open(event->getMode());
486 event->setResult(result);
488 catch (const Commons::PlatformException& ex) {
489 LogError("Exception: " << ex.GetMessage());
490 event->setExceptionCode(Commons::ExceptionCodes::PlatformException);
492 catch (const Commons::SecurityException& ex) {
493 LogError("Exception: " << ex.GetMessage());
494 event->setExceptionCode(Commons::ExceptionCodes::SecurityException);
496 //event can be cancelled before executing this code.
497 //when it comes here we doesn't allow it anymore
498 event->setCancelAllowed(false);
500 event->setCancelAllowed(true);
504 void Node::OnRequestReceived(const EventReadTextPtr& event)
507 event->setResult(readText());
508 LogDebug("LEAVIN GRACEFULLY");
510 Catch(Commons::PlatformException) {
511 event->setExceptionCode(Commons::ExceptionCodes::PlatformException);
513 Catch(Commons::SecurityException) {
514 event->setExceptionCode(Commons::ExceptionCodes::SecurityException);
516 //this function doesn't change state of the platform,
517 //so we can allow to cancel it and discard results.
518 event->setCancelAllowed(true);
521 std::string Node::readText()
523 if (m_type != NT_FILE) {
524 ThrowMsg(Commons::PlatformException, "Node is not a file.");
527 if ((m_perms & PERM_READ) == 0) {
528 ThrowMsg(Commons::SecurityException, "No permission.");
531 std::stringstream result;
532 DPL::SharedPtr<Stream> stream(new Stream(SharedFromThis(), AM_READ));
533 while (!stream->isEof()) {
534 result << stream->getLine();
542 std::string Node::toUri(int /*widgetId*/) const
544 // TODO I believe moving this feature to WrtWrapper would make more sense.
545 return "file://" + m_path->getFullPath();