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)) {
147 INodePtr node = Node::resolve(*m_path + entry->d_name);
148 node->setPermissions(getPermissions()); // inherit access rights
149 if (NodeFilterMatcher::match(node, filter)) {
150 result.push_back(node);
153 Catch(Commons::PlatformException) {
158 ThrowMsg(Commons::PlatformException, "Error while reading directory.");
161 if (closedir(dir) != 0) {
162 ThrowMsg(Commons::PlatformException, "Could not close platform node.");
168 void Node::getChildNodes(const EventListNodesPtr& event)
171 EventRequestReceiver<EventListNodes>::PostRequest(event);
174 INodePtr Node::createChild(
175 const IPathPtr& path,
179 if (m_type != NT_DIRECTORY) {
180 ThrowMsg(Commons::PlatformException, "Parent node is not a directory.");
183 if ((m_perms & PERM_WRITE) == 0) {
184 ThrowMsg(Commons::SecurityException, "Not enough permissions.");
187 IPathPtr childPath = *m_path + *path;
188 if (exists(childPath)) {
189 ThrowMsg(Commons::PlatformException, "Node already exists.");
195 result.Reset(createAsFile(childPath, options));
198 result.Reset(createAsDirectory(childPath, options));
201 ThrowMsg(Commons::PlatformException, "Unsupported node type.");
204 result->m_perms = m_perms;
206 ThrowMsg(Commons::PlatformException, "Node creation error");
209 return DPL::StaticPointerCast<INode>(result);
212 IStreamPtr Node::open(int mode)
214 if (m_type == NT_DIRECTORY) {
215 ThrowMsg(Commons::PlatformException,
216 "Cannot attach stream to directory.");
219 if (((mode & AM_READ) && ((m_perms & PERM_READ) == 0)) ||
220 (((mode & AM_WRITE) ||
221 (mode & AM_APPEND)) && ((m_perms & PERM_WRITE) == 0))) {
222 ThrowMsg(Commons::SecurityException, "Not enough permissions.");
225 DPL::Mutex::ScopedLock lock(&m_openStreamsMutex);
226 StreamPtr stream(new Stream(SharedFromThis(), mode));
227 m_openStreams.insert(stream);
228 IManager::getInstance().addOpenedNode(DPL::StaticPointerCast<INode>(
230 return DPL::StaticPointerCast<IStream>(stream);
233 void Node::open(const EventOpenPtr& event)
236 EventRequestReceiver<EventOpen>::PostRequest(event);
239 void Node::remove(int options)
243 removeAsFile(m_path);
246 removeAsDirectory(m_path, (options & OPT_RECURSIVE));
251 std::size_t Node::getSize() const
253 if (m_type == NT_DIRECTORY) {
254 ThrowMsg(Commons::PlatformException,
255 "Getting size for directories is not supported.");
258 struct stat info = stat(m_path);
259 if (!S_ISREG(info.st_mode)) {
260 ThrowMsg(Commons::PlatformException,
261 "Specified node is not a regular file.");
267 std::time_t Node::getCreated() const
269 return stat(m_path).st_ctime;
272 std::time_t Node::getModified() const
274 return stat(m_path).st_mtime;
277 // TODO Optimize it, maybe store a flag indicating that node is a root.
278 INodePtr Node::getParent() const
280 LocationPaths roots = IManager::getInstance().getLocationPaths();
281 for (LocationPaths::iterator it = roots.begin(); it != roots.end(); ++it) {
282 if (*(*it) == *m_path) {
286 return Node::resolve(IPath::create(m_path->getPath()));
289 int Node::getMode() const
292 struct stat info = stat(m_path);
293 if (info.st_mode & S_IRUSR) { result |= PM_USER_READ; }
294 if (info.st_mode & S_IWUSR) { result |= PM_USER_WRITE; }
295 if (info.st_mode & S_IXUSR) { result |= PM_USER_EXEC; }
296 if (info.st_mode & S_IRGRP) { result |= PM_GROUP_READ; }
297 if (info.st_mode & S_IWGRP) { result |= PM_GROUP_WRITE; }
298 if (info.st_mode & S_IXGRP) { result |= PM_GROUP_EXEC; }
299 if (info.st_mode & S_IROTH) { result |= PM_OTHER_READ; }
300 if (info.st_mode & S_IWOTH) { result |= PM_OTHER_WRITE; }
301 if (info.st_mode & S_IXOTH) { result |= PM_OTHER_EXEC; }
305 void Node::read(const EventReadTextPtr& event)
308 EventRequestReceiver<EventReadText>::PostRequest(event);
311 void Node::onStreamClose(const StreamPtr& stream)
314 DPL::Mutex::ScopedLock lock(&m_openStreamsMutex);
315 m_openStreams.erase(stream);
317 if (m_openStreams.empty()) {
318 IManager::getInstance().removeOpenedNode(DPL::StaticPointerCast<INode>(
323 bool Node::exists(const IPathPtr& path)
326 memset(&info, 0, sizeof(struct stat));
327 int status = lstat(path->getFullPath().c_str(), &info);
328 if ((status == 0) || ((status != 0) && (errno != ENOENT))) {
334 struct stat Node::stat(const IPathPtr& path)
337 memset(&result, 0, sizeof(struct stat));
338 if (::stat(path->getFullPath().c_str(),
341 LogError("File: " << path->getFullPath().c_str());
342 ThrowMsg(Commons::PlatformException, "Node does not exist or no access");
347 Node::Node(const IPathPtr& path,
355 Node* Node::createAsFile(const IPathPtr& path,
359 createAsFileInternal(path);
360 return new Node(path, NT_FILE);
363 void Node::createAsFileInternal(const IPathPtr& path)
366 FILE* file = std::fopen(path->getFullPath().c_str(), "wb");
368 ThrowMsg(Commons::PlatformException,
369 "Platform node could not be created.");
374 Node* Node::createAsDirectory(const IPathPtr& path,
377 if (options & OPT_RECURSIVE) {
378 PathUtils::PathList parts = PathUtils::getParts(path);
379 PathUtils::PathListIterator it = parts.begin();
380 for (; it != parts.end(); ++it) {
381 if (!exists(*it)) { createAsDirectoryInternal(*it); }
384 createAsDirectoryInternal(path);
385 return new Node(path, NT_DIRECTORY);
388 void Node::createAsDirectoryInternal(const IPathPtr& path)
390 if (mkdir(path->getFullPath().c_str(), S_IRWXU | S_IRWXG | S_IROTH |
392 ThrowMsg(Commons::PlatformException,
393 "Platform node could not be created.");
397 void Node::removeAsFile(const IPathPtr& path)
399 DPL::Mutex::ScopedLock lock(&m_openStreamsMutex);
400 if (!m_openStreams.empty()) {
401 ThrowMsg(Commons::PlatformException, "Node is locked for I/O.");
403 if (IManager::getInstance().checkIfOpened(path)) {
404 ThrowMsg(Commons::PlatformException, "Node is locked for I/O.");
407 if (unlink(path->getFullPath().c_str()) != 0) {
408 ThrowMsg(Commons::PlatformException,
409 "Error while removing platform node.");
413 void Node::removeAsDirectory(const IPathPtr& path,
417 DIR* dir = opendir(path->getFullPath().c_str());
419 LogError("File: " << path->getFullPath().c_str());
420 ThrowMsg(Commons::PlatformException,
421 "Node does not exist or access denied.");
424 struct dirent *entry = NULL;
425 while ((entry = readdir(dir))) {
426 if (!strncmp(entry->d_name, ".",
427 1) || !strncmp(entry->d_name, "..", 2)) {
430 IPathPtr subPath = *path + entry->d_name;
432 memset(&info, 0, sizeof(struct stat));
433 if (lstat(subPath->getFullPath().c_str(), &info) == 0) {
435 if (S_ISDIR(info.st_mode)) {
436 removeAsDirectory(subPath, true);
437 } else if (S_ISREG(info.st_mode)) {
438 removeAsFile(subPath);
441 Catch(Commons::PlatformException) {
443 // TODO: Not sure if above exception should be swallowed.
450 if (rmdir(path->getFullPath().c_str()) != 0) {
451 if (errno == EEXIST) {
452 ThrowMsg(Commons::PlatformException, "Node has child nodes.");
454 ThrowMsg(Commons::PlatformException,
455 "Error while removing platform node.");
459 void Node::OnRequestReceived(const EventListNodesPtr& event)
462 NodeList list = event->getNode()->getChildNodes(event->getFilter());
463 event->setResult(list);
465 catch (const Commons::PlatformException& ex) {
466 LogError("Exception: " << ex.GetMessage());
467 event->setExceptionCode(Commons::ExceptionCodes::PlatformException);
469 catch (const Commons::SecurityException& ex) {
470 LogError("Exception: " << ex.GetMessage());
471 event->setExceptionCode(Commons::ExceptionCodes::SecurityException);
475 void Node::OnRequestReceived(const EventOpenPtr& event)
477 if (!event->checkCancelled()) {
479 IStreamPtr result = open(event->getMode());
480 event->setResult(result);
482 catch (const Commons::PlatformException& ex) {
483 LogError("Exception: " << ex.GetMessage());
484 event->setExceptionCode(Commons::ExceptionCodes::PlatformException);
486 catch (const Commons::SecurityException& ex) {
487 LogError("Exception: " << ex.GetMessage());
488 event->setExceptionCode(Commons::ExceptionCodes::SecurityException);
490 //event can be cancelled before executing this code.
491 //when it comes here we doesn't allow it anymore
492 event->setCancelAllowed(false);
494 event->setCancelAllowed(true);
498 void Node::OnRequestReceived(const EventReadTextPtr& event)
501 event->setResult(readText());
502 LogDebug("LEAVIN GRACEFULLY");
504 Catch(Commons::PlatformException) {
505 event->setExceptionCode(Commons::ExceptionCodes::PlatformException);
507 Catch(Commons::SecurityException) {
508 event->setExceptionCode(Commons::ExceptionCodes::SecurityException);
510 //this function doesn't change state of the platform,
511 //so we can allow to cancel it and discard results.
512 event->setCancelAllowed(true);
515 std::string Node::readText()
517 if (m_type != NT_FILE) {
518 ThrowMsg(Commons::PlatformException, "Node is not a file.");
521 if ((m_perms & PERM_READ) == 0) {
522 ThrowMsg(Commons::SecurityException, "No permission.");
525 std::stringstream result;
526 DPL::SharedPtr<Stream> stream(new Stream(SharedFromThis(), AM_READ));
527 while (!stream->isEof()) {
528 result << stream->getLine();
536 std::string Node::toUri(int /*widgetId*/) const
538 // TODO I believe moving this feature to WrtWrapper would make more sense.
539 return "file://" + m_path->getFullPath();