2 // Tizen Web Device API
3 // Copyright (c) 2012 Samsung Electronics Co., Ltd.
5 // Licensed under the Apache License, Version 2.0 (the License);
6 // you may not use this file except in compliance with the License.
7 // You may obtain a copy of the License at
9 // http://www.apache.org/licenses/LICENSE-2.0
11 // Unless required by applicable law or agreed to in writing, software
12 // distributed under the License is distributed on an "AS IS" BASIS,
13 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 // See the License for the specific language governing permissions and
15 // limitations under the License.
24 #include <sys/types.h>
32 #include <Commons/Exception.h>
33 #include "PathUtils.h"
36 #include "NodeFilterMatcher.h"
39 using namespace WrtDeviceApis;
40 using namespace WrtDeviceApis::Commons;
44 namespace Filesystem {
46 #define MAX_NODE_LENGTH 256
47 bool Node::checkPermission(const IPathPtr &path, const std::string &mode, NodeType type)
53 DIR* dir = opendir(path->getFullPath().c_str());
56 ThrowMsg(Commons::SecurityException, "Node has been deleted from platform.");
58 if (closedir(dir) != 0)
59 ThrowMsg(Commons::SecurityException, "Could not close platform node.");
61 LoggerD("open/close dir ok");
71 IPathPtr tempFilePath = IPath::create(path->getFullPath());
72 tempFilePath->append(ss.str());
75 createAsFileInternal(tempFilePath);
76 removeAsFile(tempFilePath);
78 catch (const Commons::Exception& ex)
80 LoggerE("Exception: " << ex.GetMessage());
84 if (mode == "rw" || mode == "w" || mode == "a")
86 ThrowMsg(Commons::InvalidArgumentException, "invalid mode");
92 std::ios_base::openmode modeBit = std::fstream::binary;
96 modeBit |= std::fstream::in;
98 else if (mode == "rw" || mode == "w" || mode == "a")
100 modeBit |= std::fstream::app;
104 ThrowMsg(Commons::InvalidArgumentException, "invalid mode");
107 stream.open(path->getFullPath().c_str(), modeBit);
109 if (stream.is_open())
121 INodePtr Node::resolve(const IPathPtr& path)
126 if (lstat(path->getFullPath().c_str(), &info) != 0) {
127 LoggerE("File: " << path->getFullPath().c_str() << " error no" <<errno);
132 ThrowMsg(Commons::SecurityException, "Node access denied");
135 ThrowMsg(Commons::NotFoundException, "Node does not exist");
138 ThrowMsg(Commons::PlatformException, "Platform exception fail");
142 if (!S_ISDIR(info.st_mode) & !S_ISREG(info.st_mode) && !S_ISLNK(info.st_mode)) {
143 ThrowMsg(Commons::PlatformException,
144 "Platform node is of unsupported type.");
147 NodeType type = S_ISDIR(info.st_mode) ? NT_DIRECTORY : NT_FILE;
149 if (S_ISLNK(info.st_mode)) {
150 syminfo = stat(path);
152 type = S_ISDIR(syminfo.st_mode) ? NT_DIRECTORY : NT_FILE;
156 NodePtr result(new Node(path, type));
158 return DPL::StaticPointerCast<INode>(result);
161 IPathPtr Node::getPath() const
163 return IPath::create(m_path->getFullPath());
166 INodePtr Node::getChild(const IPathPtr& path)
168 if (m_type != NT_DIRECTORY) {
169 ThrowMsg(Commons::PlatformException, "Not a directory.");
171 return Node::resolve(*m_path + *path);
174 NodeType Node::getType() const
179 int Node::getPermissions() const
184 void Node::setPermissions(int perms)
189 Node::NameList Node::getChildNames() const
191 if (m_type != NT_DIRECTORY) {
192 ThrowMsg(Commons::PlatformException, "Node is not directory.");
195 if ((m_perms & PERM_READ) == 0) {
196 ThrowMsg(Commons::SecurityException, "No permission.");
199 DIR* dir = opendir(m_path->getFullPath().c_str());
201 ThrowMsg(Commons::PlatformException,
202 "Node has been deleted from platform.");
207 struct dirent *entry = NULL;
208 while ((entry = readdir(dir))) {
209 if (!strcmp(entry->d_name, ".") || !strncmp(entry->d_name, "..", 2)) {
212 result.push_back(entry->d_name);
215 ThrowMsg(Commons::PlatformException, "Error while reading directory.");
218 if (closedir(dir) != 0) {
219 ThrowMsg(Commons::PlatformException, "Could not close platform node.");
225 NodeList Node::getChildNodes(const NodeFilterPtr& filter) const
227 if (m_type != NT_DIRECTORY) {
228 ThrowMsg(Commons::PlatformException, "Node is not directory.");
231 if ((m_perms & PERM_READ) == 0) {
232 ThrowMsg(Commons::SecurityException, "No permission.");
235 DIR* dir = opendir(m_path->getFullPath().c_str());
237 ThrowMsg(Commons::PlatformException,
238 "Node has been deleted from platform.");
243 struct dirent *entry = NULL;
244 while ((entry = readdir(dir))) {
245 if (!strcmp(entry->d_name, ".") || !strncmp(entry->d_name, "..", 2)) {
249 INodePtr node = Node::resolve(*m_path + entry->d_name);
250 node->setPermissions(getPermissions()); // inherit access rights
251 if (NodeFilterMatcher::match(node, filter)) {
252 result.push_back(node);
255 catch (const Commons::Exception& ex)
261 ThrowMsg(Commons::PlatformException, "Error while reading directory.");
264 if (closedir(dir) != 0) {
265 ThrowMsg(Commons::PlatformException, "Could not close platform node.");
271 void Node::getChildNodes(const EventListNodesPtr& event)
274 EventRequestReceiver<EventListNodes>::PostRequest(event);
277 INodePtr Node::createChild(
278 const IPathPtr& path,
282 if (m_type != NT_DIRECTORY) {
283 ThrowMsg(Commons::PlatformException, "Parent node is not a directory.");
286 if ((m_perms & PERM_WRITE) == 0) {
287 ThrowMsg(Commons::SecurityException, "Not enough permissions.");
290 IPathPtr childPath = *m_path + *path;
291 if (exists(childPath)) {
292 ThrowMsg(Commons::PlatformException, "Node already exists.");
298 result.Reset(createAsFile(childPath, options));
301 result.Reset(createAsDirectory(childPath, options));
304 ThrowMsg(Commons::PlatformException, "Unsupported node type.");
307 result->m_perms = m_perms;
309 ThrowMsg(Commons::PlatformException, "Node creation error");
312 return DPL::StaticPointerCast<INode>(result);
315 IStreamPtr Node::open(int mode)
317 if (m_type == NT_DIRECTORY) {
318 ThrowMsg(Commons::PlatformException,
319 "Cannot attach stream to directory.");
322 if (((mode & AM_READ) && ((m_perms & PERM_READ) == 0)) ||
323 (((mode & AM_WRITE) ||
324 (mode & AM_APPEND)) && ((m_perms & PERM_WRITE) == 0))) {
325 ThrowMsg(Commons::SecurityException, "Not enough permissions.");
328 DPL::Mutex::ScopedLock lock(&m_openStreamsMutex);
329 StreamPtr stream(new Stream(SharedFromThis(), mode));
330 m_openStreams.insert(stream);
331 IManager::getInstance().addOpenedNode(DPL::StaticPointerCast<INode>(
333 return DPL::StaticPointerCast<IStream>(stream);
336 void Node::open(const EventOpenPtr& event)
339 EventRequestReceiver<EventOpen>::PostRequest(event);
342 void Node::remove(int options)
346 removeAsFile(m_path);
349 removeAsDirectory(m_path, (options & OPT_RECURSIVE));
354 unsigned long long Node::getSize() const
356 if (m_type == NT_DIRECTORY) {
357 ThrowMsg(Commons::PlatformException,
358 "Getting size for directories is not supported.");
361 struct stat info = stat(m_path);
362 if (!S_ISREG(info.st_mode)) {
363 ThrowMsg(Commons::PlatformException,
364 "Specified node is not a regular file.");
370 std::time_t Node::getCreated() const
372 return stat(m_path).st_ctime;
375 std::time_t Node::getModified() const
377 return stat(m_path).st_mtime;
380 // TODO Optimize it, maybe store a flag indicating that node is a root.
381 INodePtr Node::getParent() const
383 LocationPaths roots = IManager::getInstance().getLocationPaths();
384 for (LocationPaths::iterator it = roots.begin(); it != roots.end(); ++it) {
385 if (*(*it) == *m_path) {
389 return Node::resolve(IPath::create(m_path->getPath()));
392 int Node::getMode() const
395 struct stat info = stat(m_path);
396 if (info.st_mode & S_IRUSR) { result |= PM_USER_READ; }
397 if (info.st_mode & S_IWUSR) { result |= PM_USER_WRITE; }
398 if (info.st_mode & S_IXUSR) { result |= PM_USER_EXEC; }
399 if (info.st_mode & S_IRGRP) { result |= PM_GROUP_READ; }
400 if (info.st_mode & S_IWGRP) { result |= PM_GROUP_WRITE; }
401 if (info.st_mode & S_IXGRP) { result |= PM_GROUP_EXEC; }
402 if (info.st_mode & S_IROTH) { result |= PM_OTHER_READ; }
403 if (info.st_mode & S_IWOTH) { result |= PM_OTHER_WRITE; }
404 if (info.st_mode & S_IXOTH) { result |= PM_OTHER_EXEC; }
408 void Node::read(const EventReadTextPtr& event)
411 EventRequestReceiver<EventReadText>::PostRequest(event);
414 void Node::onStreamClose(const StreamPtr& stream)
417 DPL::Mutex::ScopedLock lock(&m_openStreamsMutex);
418 m_openStreams.erase(stream);
420 if (m_openStreams.empty()) {
421 IManager::getInstance().removeOpenedNode(DPL::StaticPointerCast<INode>(
426 bool Node::exists(const IPathPtr& path)
429 memset(&info, 0, sizeof(struct stat));
430 int status = lstat(path->getFullPath().c_str(), &info);
431 if ((status == 0) || ((status != 0) && (errno != ENOENT))) {
437 struct stat Node::stat(const IPathPtr& path)
440 memset(&result, 0, sizeof(struct stat));
441 if (::stat(path->getFullPath().c_str(),
444 LoggerE("File: " << path->getFullPath().c_str());
445 ThrowMsg(Commons::PlatformException, "Node does not exist or no access");
450 Node::Node(const IPathPtr& path,
458 Node* Node::createAsFile(const IPathPtr& path,
462 createAsFileInternal(path);
463 return new Node(path, NT_FILE);
466 void Node::createAsFileInternal(const IPathPtr& path)
469 FILE* file = std::fopen(path->getFullPath().c_str(), "wb");
471 ThrowMsg(Commons::PlatformException,
472 "Platform node could not be created.");
477 Node* Node::createAsDirectory(const IPathPtr& path,
480 if (options & OPT_RECURSIVE) {
481 PathUtils::PathList parts = PathUtils::getParts(path);
482 PathUtils::PathListIterator it = parts.begin();
483 for (; it != parts.end(); ++it) {
484 if (!exists(*it)) { createAsDirectoryInternal(*it); }
487 createAsDirectoryInternal(path);
488 return new Node(path, NT_DIRECTORY);
491 void Node::createAsDirectoryInternal(const IPathPtr& path)
493 if (mkdir(path->getFullPath().c_str(), S_IRWXU | S_IRWXG | S_IROTH |
495 ThrowMsg(Commons::PlatformException,
496 "Platform node could not be created.");
500 void Node::removeAsFile(const IPathPtr& path)
502 DPL::Mutex::ScopedLock lock(&m_openStreamsMutex);
503 if (!m_openStreams.empty()) {
504 ThrowMsg(Commons::PlatformException, "Node is locked for I/O.");
506 if (IManager::getInstance().checkIfOpened(path)) {
507 ThrowMsg(Commons::PlatformException, "Node is locked for I/O.");
510 if (unlink(path->getFullPath().c_str()) != 0) {
511 ThrowMsg(Commons::PlatformException,
512 "Error while removing platform node.");
516 void Node::removeAsDirectory(const IPathPtr& path,
520 DIR* dir = opendir(path->getFullPath().c_str());
522 LoggerE("File: " << path->getFullPath().c_str());
523 ThrowMsg(Commons::PlatformException,
524 "Node does not exist or access denied.");
527 struct dirent *entry = NULL;
528 while ((entry = readdir(dir))) {
529 if (!strcmp(entry->d_name, ".") || !strncmp(entry->d_name, "..", 2)) {
532 IPathPtr subPath = *path + entry->d_name;
534 memset(&info, 0, sizeof(struct stat));
535 if (lstat(subPath->getFullPath().c_str(), &info) == 0) {
537 if (S_ISDIR(info.st_mode)) {
538 removeAsDirectory(subPath, true);
539 } else if (S_ISREG(info.st_mode)) {
540 removeAsFile(subPath);
543 catch (const Commons::Exception& ex)
546 // TODO: Not sure if above exception should be swallowed.
553 if (rmdir(path->getFullPath().c_str()) != 0) {
554 if (errno == EEXIST) {
555 ThrowMsg(Commons::PlatformException, "Node has child nodes.");
557 ThrowMsg(Commons::PlatformException,
558 "Error while removing platform node.");
562 void Node::OnRequestReceived(const EventListNodesPtr& event)
565 NodeList list = event->getNode()->getChildNodes(event->getFilter());
566 event->setResult(list);
568 catch (const Commons::Exception& ex)
570 LoggerE("Exception: " << ex.GetMessage());
571 event->setExceptionCode(ex.getCode());
576 void Node::OnRequestReceived(const EventOpenPtr& event)
578 if (!event->checkCancelled()) {
580 IStreamPtr result = open(event->getMode());
581 result->setCharSet(event->getCharSet());
582 event->setResult(result);
585 catch (const Commons::Exception& ex)
587 LoggerE("Exception: " << ex.GetMessage());
588 event->setExceptionCode(ex.getCode());
590 //event can be cancelled before executing this code.
591 //when it comes here we doesn't allow it anymore
592 event->setCancelAllowed(false);
594 event->setCancelAllowed(true);
598 void Node::OnRequestReceived(const EventReadTextPtr& event)
601 event->setResult(readText());
602 LoggerD("LEAVIN GRACEFULLY");
604 catch (const Commons::Exception& ex)
606 LoggerE("Exception: " << ex.GetMessage());
607 event->setExceptionCode(ex.getCode());
609 //this function doesn't change state of the platform,
610 //so we can allow to cancel it and discard results.
611 event->setCancelAllowed(true);
614 std::string Node::readText()
616 if (m_type != NT_FILE) {
617 ThrowMsg(Commons::PlatformException, "Node is not a file.");
620 if ((m_perms & PERM_READ) == 0) {
621 ThrowMsg(Commons::SecurityException, "No permission.");
624 std::stringstream result;
625 DPL::SharedPtr<Stream> stream(new Stream(SharedFromThis(), AM_READ));
626 while (!stream->isEof()) {
627 result << stream->getLine();
635 std::string Node::toUri(int /*widgetId*/) const
637 // TODO I believe moving this feature to WrtWrapper would make more sense.
638 return "file://" + m_path->getFullPath();