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
48 INodePtr Node::resolve(const IPathPtr& path)
53 if (lstat(path->getFullPath().c_str(), &info) != 0) {
54 LoggerE("File: " << path->getFullPath().c_str() << " error no" <<errno);
59 ThrowMsg(Commons::PlatformException, "Node access denied");
62 ThrowMsg(Commons::NotFoundException, "Node does not exist");
65 ThrowMsg(Commons::PlatformException, "Platform exception fail");
69 if (!S_ISDIR(info.st_mode) & !S_ISREG(info.st_mode) && !S_ISLNK(info.st_mode)) {
70 ThrowMsg(Commons::PlatformException,
71 "Platform node is of unsupported type.");
74 NodeType type = S_ISDIR(info.st_mode) ? NT_DIRECTORY : NT_FILE;
76 if (S_ISLNK(info.st_mode)) {
79 type = S_ISDIR(syminfo.st_mode) ? NT_DIRECTORY : NT_FILE;
83 NodePtr result(new Node(path, type));
85 return DPL::StaticPointerCast<INode>(result);
88 IPathPtr Node::getPath() const
90 return IPath::create(m_path->getFullPath());
93 INodePtr Node::getChild(const IPathPtr& path)
95 if (m_type != NT_DIRECTORY) {
96 ThrowMsg(Commons::PlatformException, "Not a directory.");
98 return Node::resolve(*m_path + *path);
101 NodeType Node::getType() const
106 int Node::getPermissions() const
111 void Node::setPermissions(int perms)
116 Node::NameList Node::getChildNames() const
118 if (m_type != NT_DIRECTORY) {
119 ThrowMsg(Commons::PlatformException, "Node is not directory.");
122 if ((m_perms & PERM_READ) == 0) {
123 ThrowMsg(Commons::SecurityException, "No permission.");
126 DIR* dir = opendir(m_path->getFullPath().c_str());
128 ThrowMsg(Commons::PlatformException,
129 "Node has been deleted from platform.");
134 struct dirent *entry = NULL;
135 while ((entry = readdir(dir))) {
136 if (!strcmp(entry->d_name, ".") || !strncmp(entry->d_name, "..", 2)) {
139 result.push_back(entry->d_name);
142 ThrowMsg(Commons::PlatformException, "Error while reading directory.");
145 if (closedir(dir) != 0) {
146 ThrowMsg(Commons::PlatformException, "Could not close platform node.");
152 NodeList Node::getChildNodes(const NodeFilterPtr& filter) const
154 if (m_type != NT_DIRECTORY) {
155 ThrowMsg(Commons::PlatformException, "Node is not directory.");
158 if ((m_perms & PERM_READ) == 0) {
159 ThrowMsg(Commons::SecurityException, "No permission.");
162 DIR* dir = opendir(m_path->getFullPath().c_str());
164 ThrowMsg(Commons::PlatformException,
165 "Node has been deleted from platform.");
170 struct dirent *entry = NULL;
171 while ((entry = readdir(dir))) {
172 if (!strcmp(entry->d_name, ".") || !strncmp(entry->d_name, "..", 2)) {
176 INodePtr node = Node::resolve(*m_path + entry->d_name);
177 node->setPermissions(getPermissions()); // inherit access rights
178 if (NodeFilterMatcher::match(node, filter)) {
179 result.push_back(node);
182 catch (const Commons::Exception& ex)
188 ThrowMsg(Commons::PlatformException, "Error while reading directory.");
191 if (closedir(dir) != 0) {
192 ThrowMsg(Commons::PlatformException, "Could not close platform node.");
198 void Node::getChildNodes(const EventListNodesPtr& event)
201 EventRequestReceiver<EventListNodes>::PostRequest(event);
204 INodePtr Node::createChild(
205 const IPathPtr& path,
209 if (m_type != NT_DIRECTORY) {
210 ThrowMsg(Commons::PlatformException, "Parent node is not a directory.");
213 if ((m_perms & PERM_WRITE) == 0) {
214 ThrowMsg(Commons::SecurityException, "Not enough permissions.");
217 IPathPtr childPath = *m_path + *path;
218 if (exists(childPath)) {
219 ThrowMsg(Commons::PlatformException, "Node already exists.");
225 result.Reset(createAsFile(childPath, options));
228 result.Reset(createAsDirectory(childPath, options));
231 ThrowMsg(Commons::PlatformException, "Unsupported node type.");
234 result->m_perms = m_perms;
236 ThrowMsg(Commons::PlatformException, "Node creation error");
239 return DPL::StaticPointerCast<INode>(result);
242 IStreamPtr Node::open(int mode)
244 if (m_type == NT_DIRECTORY) {
245 ThrowMsg(Commons::PlatformException,
246 "Cannot attach stream to directory.");
249 if (((mode & AM_READ) && ((m_perms & PERM_READ) == 0)) ||
250 (((mode & AM_WRITE) ||
251 (mode & AM_APPEND)) && ((m_perms & PERM_WRITE) == 0))) {
252 ThrowMsg(Commons::SecurityException, "Not enough permissions.");
255 DPL::Mutex::ScopedLock lock(&m_openStreamsMutex);
256 StreamPtr stream(new Stream(SharedFromThis(), mode));
257 m_openStreams.insert(stream);
258 IManager::getInstance().addOpenedNode(DPL::StaticPointerCast<INode>(
260 return DPL::StaticPointerCast<IStream>(stream);
263 void Node::open(const EventOpenPtr& event)
266 EventRequestReceiver<EventOpen>::PostRequest(event);
269 void Node::remove(int options)
273 removeAsFile(m_path);
276 removeAsDirectory(m_path, (options & OPT_RECURSIVE));
281 unsigned long long Node::getSize() const
283 if (m_type == NT_DIRECTORY) {
284 ThrowMsg(Commons::PlatformException,
285 "Getting size for directories is not supported.");
288 struct stat info = stat(m_path);
289 if (!S_ISREG(info.st_mode)) {
290 ThrowMsg(Commons::PlatformException,
291 "Specified node is not a regular file.");
297 std::time_t Node::getCreated() const
299 return stat(m_path).st_ctime;
302 std::time_t Node::getModified() const
304 return stat(m_path).st_mtime;
307 // TODO Optimize it, maybe store a flag indicating that node is a root.
308 INodePtr Node::getParent() const
310 LocationPaths roots = IManager::getInstance().getLocationPaths();
311 for (LocationPaths::iterator it = roots.begin(); it != roots.end(); ++it) {
312 if (*(*it) == *m_path) {
316 return Node::resolve(IPath::create(m_path->getPath()));
319 int Node::getMode() const
322 struct stat info = stat(m_path);
323 if (info.st_mode & S_IRUSR) { result |= PM_USER_READ; }
324 if (info.st_mode & S_IWUSR) { result |= PM_USER_WRITE; }
325 if (info.st_mode & S_IXUSR) { result |= PM_USER_EXEC; }
326 if (info.st_mode & S_IRGRP) { result |= PM_GROUP_READ; }
327 if (info.st_mode & S_IWGRP) { result |= PM_GROUP_WRITE; }
328 if (info.st_mode & S_IXGRP) { result |= PM_GROUP_EXEC; }
329 if (info.st_mode & S_IROTH) { result |= PM_OTHER_READ; }
330 if (info.st_mode & S_IWOTH) { result |= PM_OTHER_WRITE; }
331 if (info.st_mode & S_IXOTH) { result |= PM_OTHER_EXEC; }
335 void Node::read(const EventReadTextPtr& event)
338 EventRequestReceiver<EventReadText>::PostRequest(event);
341 void Node::onStreamClose(const StreamPtr& stream)
344 DPL::Mutex::ScopedLock lock(&m_openStreamsMutex);
345 m_openStreams.erase(stream);
347 if (m_openStreams.empty()) {
348 IManager::getInstance().removeOpenedNode(DPL::StaticPointerCast<INode>(
353 bool Node::exists(const IPathPtr& path)
356 memset(&info, 0, sizeof(struct stat));
357 int status = lstat(path->getFullPath().c_str(), &info);
358 if ((status == 0) || ((status != 0) && (errno != ENOENT))) {
364 struct stat Node::stat(const IPathPtr& path)
367 memset(&result, 0, sizeof(struct stat));
368 if (::stat(path->getFullPath().c_str(),
371 LoggerE("File: " << path->getFullPath().c_str());
372 ThrowMsg(Commons::PlatformException, "Node does not exist or no access");
377 Node::Node(const IPathPtr& path,
385 Node* Node::createAsFile(const IPathPtr& path,
389 createAsFileInternal(path);
390 return new Node(path, NT_FILE);
393 void Node::createAsFileInternal(const IPathPtr& path)
396 FILE* file = std::fopen(path->getFullPath().c_str(), "wb");
398 ThrowMsg(Commons::PlatformException,
399 "Platform node could not be created.");
404 Node* Node::createAsDirectory(const IPathPtr& path,
407 if (options & OPT_RECURSIVE) {
408 PathUtils::PathList parts = PathUtils::getParts(path);
409 PathUtils::PathListIterator it = parts.begin();
410 for (; it != parts.end(); ++it) {
411 if (!exists(*it)) { createAsDirectoryInternal(*it); }
414 createAsDirectoryInternal(path);
415 return new Node(path, NT_DIRECTORY);
418 void Node::createAsDirectoryInternal(const IPathPtr& path)
420 if (mkdir(path->getFullPath().c_str(), S_IRWXU | S_IRWXG | S_IROTH |
422 ThrowMsg(Commons::PlatformException,
423 "Platform node could not be created.");
427 void Node::removeAsFile(const IPathPtr& path)
429 DPL::Mutex::ScopedLock lock(&m_openStreamsMutex);
430 if (!m_openStreams.empty()) {
431 ThrowMsg(Commons::PlatformException, "Node is locked for I/O.");
433 if (IManager::getInstance().checkIfOpened(path)) {
434 ThrowMsg(Commons::PlatformException, "Node is locked for I/O.");
437 if (unlink(path->getFullPath().c_str()) != 0) {
438 ThrowMsg(Commons::PlatformException,
439 "Error while removing platform node.");
443 void Node::removeAsDirectory(const IPathPtr& path,
447 DIR* dir = opendir(path->getFullPath().c_str());
449 LoggerE("File: " << path->getFullPath().c_str());
450 ThrowMsg(Commons::PlatformException,
451 "Node does not exist or access denied.");
454 struct dirent *entry = NULL;
455 while ((entry = readdir(dir))) {
456 if (!strcmp(entry->d_name, ".") || !strncmp(entry->d_name, "..", 2)) {
459 IPathPtr subPath = *path + entry->d_name;
461 memset(&info, 0, sizeof(struct stat));
462 if (lstat(subPath->getFullPath().c_str(), &info) == 0) {
464 if (S_ISDIR(info.st_mode)) {
465 removeAsDirectory(subPath, true);
466 } else if (S_ISREG(info.st_mode)) {
467 removeAsFile(subPath);
470 catch (const Commons::Exception& ex)
473 // TODO: Not sure if above exception should be swallowed.
480 if (rmdir(path->getFullPath().c_str()) != 0) {
481 if (errno == EEXIST) {
482 ThrowMsg(Commons::PlatformException, "Node has child nodes.");
484 ThrowMsg(Commons::PlatformException,
485 "Error while removing platform node.");
489 void Node::OnRequestReceived(const EventListNodesPtr& event)
492 NodeList list = event->getNode()->getChildNodes(event->getFilter());
493 event->setResult(list);
495 catch (const Commons::Exception& ex)
497 LoggerE("Exception: " << ex.GetMessage());
498 event->setExceptionCode(ex.getCode());
503 void Node::OnRequestReceived(const EventOpenPtr& event)
505 if (!event->checkCancelled()) {
507 IStreamPtr result = open(event->getMode());
508 result->setCharSet(event->getCharSet());
509 event->setResult(result);
512 catch (const Commons::Exception& ex)
514 LoggerE("Exception: " << ex.GetMessage());
515 event->setExceptionCode(ex.getCode());
517 //event can be cancelled before executing this code.
518 //when it comes here we doesn't allow it anymore
519 event->setCancelAllowed(false);
521 event->setCancelAllowed(true);
525 void Node::OnRequestReceived(const EventReadTextPtr& event)
528 event->setResult(readText());
529 LoggerD("LEAVIN GRACEFULLY");
531 catch (const Commons::Exception& ex)
533 LoggerE("Exception: " << ex.GetMessage());
534 event->setExceptionCode(ex.getCode());
536 //this function doesn't change state of the platform,
537 //so we can allow to cancel it and discard results.
538 event->setCancelAllowed(true);
541 std::string Node::readText()
543 if (m_type != NT_FILE) {
544 ThrowMsg(Commons::PlatformException, "Node is not a file.");
547 if ((m_perms & PERM_READ) == 0) {
548 ThrowMsg(Commons::SecurityException, "No permission.");
551 std::stringstream result;
552 DPL::SharedPtr<Stream> stream(new Stream(SharedFromThis(), AM_READ));
553 while (!stream->isEof()) {
554 result << stream->getLine();
562 std::string Node::toUri(int /*widgetId*/) const
564 // TODO I believe moving this feature to WrtWrapper would make more sense.
565 return "file://" + m_path->getFullPath();