tizen 2.3.1 release
[framework/web/wearable/wrt-plugins-tizen.git] / src / Filesystem / Node.cpp
1 //
2 // Tizen Web Device API
3 // Copyright (c) 2012 Samsung Electronics Co., Ltd.
4 //
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
8 //
9 // http://www.apache.org/licenses/LICENSE-2.0
10 //
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.
16 //
17
18 /**
19  * @file        Node.cpp
20  */
21
22 #include "Node.h"
23
24 #include <algorithm>
25 #include <memory>
26 #include <typeinfo>
27 #include <sys/types.h>
28 #include <cstdio>
29 #include <unistd.h>
30 #include <dirent.h>
31 #include <errno.h>
32 #include <pcrecpp.h>
33 #include <sstream>
34 #include <Logger.h>
35 #include <PlatformException.h>
36 #include <CommonsJavaScript/JSUtils.h>
37 #include <GlobalContextManager.h>
38 #include <JSWebAPIErrorFactory.h>
39 #include <JSUtil.h>
40 #include <Export.h>
41
42 #include "Enums.h"
43 #include "Manager.h"
44 #include "Stream.h"
45 #include "Path.h"
46 #include "NodeFilterMatcher.h"
47 #include "JSErrors.h"
48 #include "JSFilestream.h"
49 #include "FilesystemPathUtils.h"
50 #include "Converter.h"
51
52
53
54 namespace DeviceAPI {
55 namespace Filesystem {
56
57 struct EventHandler{
58     EventReadTextPtr ptr;
59 };
60
61 #define MAX_NODE_LENGTH 256
62 bool Node::checkPermission(const PathPtr &path, const std::string &mode, NodeType type)
63 {
64     switch (type)
65     {
66     case NT_DIRECTORY:
67     {
68         DIR* dir = opendir(path->getFullPath().c_str());
69
70         if (!dir) {
71             LOGW("throw InvalidValuesException");
72             throw DeviceAPI::Common::InvalidValuesException(
73                     "Node has been deleted from platform.");
74         }
75
76         if (closedir(dir) != 0) {
77             LOGW("throw InvalidValuesException");
78             throw DeviceAPI::Common::InvalidValuesException(
79                     "Could not close platform node.");
80         }
81
82         if (mode == "r")
83             return true;
84
85         std::stringstream ss;
86         time_t now;
87         time(&now);
88         ss << now;
89         PathPtr tempFilePath = Path::create(path->getFullPath());
90         tempFilePath->append(ss.str());
91         try
92         {
93             createAsFileInternal(tempFilePath);
94             removeAsFile(tempFilePath);
95         }
96         catch (const DeviceAPI::Common::BasePlatformException& ex)
97         {
98             LOGW("Exception: %s", ex.getMessage().c_str());
99             return false;
100         }
101
102         if (mode == "rw" || mode == "w"  || mode == "a") {
103             return true;
104         }
105         LOGW("throw InvalidValuesException");
106         throw DeviceAPI::Common::InvalidValuesException("invalid mode");
107     }
108     break;
109     case NT_FILE:
110     {
111         std::fstream stream;
112         std::ios_base::openmode modeBit = std::fstream::binary;
113
114         if (mode == "r")
115         {
116             modeBit |=     std::fstream::in;
117         }
118         else if (mode == "rw" || mode == "w" || mode == "a")
119         {
120             modeBit |=     std::fstream::app;
121         }
122         else
123         {
124             LOGW("throw InvalidValuesException");
125             throw DeviceAPI::Common::InvalidValuesException("invalid mode");
126         }
127
128         stream.open(path->getFullPath().c_str(), modeBit);
129
130         if (stream.is_open())
131         {
132             stream.close();
133             return true;
134         }
135         return false;
136     }
137     break;
138     }
139     return false;
140 }
141
142 NodePtr DLL_EXPORT Node::resolve(const PathPtr& path)
143 {
144     LOGD("Entered path:[%s]", path->getFullPath().c_str());
145
146     struct stat info;
147     struct stat syminfo;
148
149     if (lstat(path->getFullPath().c_str(), &info) != 0) {
150         LOGE("File:[%s] error no:%d", path->getFullPath().c_str(), errno);
151
152         switch (errno)
153         {
154         case EACCES:
155             LOGW("throw InvalidValuesException for file:[%s]", path->getFullPath().c_str());
156             throw DeviceAPI::Common::InvalidValuesException("Node access denied");
157             break;
158         case ENOENT:
159             LOGW("throw NotFoundException for file:[%s]", path->getFullPath().c_str());
160             throw DeviceAPI::Common::NotFoundException("NotFoundError");
161             break;
162         default:
163             LOGW("throw IOException for file:[%s]", path->getFullPath().c_str());
164             throw DeviceAPI::Common::IOException("Platform exception fail");
165         }
166     }
167
168     if (!S_ISDIR(info.st_mode) & !S_ISREG(info.st_mode) && !S_ISLNK(info.st_mode)) {
169         LOGW("throw IOException for file:[%s]", path->getFullPath().c_str());
170         throw DeviceAPI::Common::IOException(
171                  "Platform node is of unsupported type.");
172     }
173
174     NodeType type = S_ISDIR(info.st_mode) ? NT_DIRECTORY : NT_FILE;
175
176     if (S_ISLNK(info.st_mode)) {
177         syminfo = stat(path);
178
179         type = S_ISDIR(syminfo.st_mode) ? NT_DIRECTORY : NT_FILE;
180         LOGD("%x", type);
181     }
182
183     auto result = std::shared_ptr<Node>(new Node(path, type));
184
185     LOGD("Finished execution for file:[%s] type:%s", path->getFullPath().c_str(),
186          type == NT_DIRECTORY ? "directory" : "file");
187     return result;
188 }
189
190 PathPtr Node::getPath() const
191 {
192     return Path::create(m_path->getFullPath());
193 }
194
195 NodePtr Node::getChild(const PathPtr& path)
196 {
197     if (m_type != NT_DIRECTORY) {
198         LOGW("throw IOException");
199         throw DeviceAPI::Common::IOException("Not a directory.");
200     }
201     return Node::resolve(*m_path + *path);
202 }
203
204 NodeType Node::getType() const
205 {
206     return m_type;
207 }
208
209 int Node::getPermissions() const
210 {
211     return m_perms;
212 }
213
214 void Node::setPermissions(int perms)
215 {
216     m_perms = perms;
217 }
218
219 Node::NameList Node::getChildNames() const
220 {
221     if (m_type != NT_DIRECTORY) {
222         LOGW("throw IOException");
223         throw DeviceAPI::Common::IOException("Node is not directory.");
224     }
225
226     if ((m_perms & PERM_READ) == 0) {
227         LOGW("throw InvalidValuesException");
228         throw DeviceAPI::Common::InvalidValuesException("No permission.");
229     }
230
231     DIR* dir = opendir(m_path->getFullPath().c_str());
232     if (!dir) {
233         LOGW("throw IOException");
234         throw DeviceAPI::Common::IOException(
235                  "Node has been deleted from platform.");
236     }
237
238     NameList result;
239     errno = 0;
240     struct dirent *entry = NULL;
241     while ((entry = readdir(dir))) {
242         if (!strcmp(entry->d_name, ".") || !strncmp(entry->d_name, "..", 2)) {
243             continue;
244         }
245         result.push_back(entry->d_name);
246     }
247     if (errno != 0) {
248         LOGW("throw IOException");
249         throw DeviceAPI::Common::IOException("Error while reading directory.");
250     }
251
252     if (closedir(dir) != 0) {
253         LOGW("throw IOException");
254         throw DeviceAPI::Common::IOException("Could not close platform node.");
255     }
256
257     return result;
258 }
259
260 NodeList Node::getChildNodes(const NodeFilterPtr& filter) const
261 {
262     if (m_type != NT_DIRECTORY) {
263         LOGW("Path %s Perm %d", m_path->getFullPath().c_str(), m_perms);
264         LOGW("throw IOException");
265         throw DeviceAPI::Common::IOException("Node is not directory.");
266         LOGW("Path %s Perm %d", m_path->getFullPath().c_str(), m_perms);
267     }
268
269     if ((m_perms & PERM_READ) == 0) {
270         LOGW("Path %s Perm %d", m_path->getFullPath().c_str(), m_perms);
271         LOGW("throw InvalidValuesException");
272         throw DeviceAPI::Common::InvalidValuesException("No permission.");
273     }
274
275     DIR* dir = opendir(m_path->getFullPath().c_str());
276     if (!dir) {
277         LOGW("Path %s Perm %d", m_path->getFullPath().c_str(), m_perms);
278         LOGW("throw IOException");
279         throw DeviceAPI::Common::IOException(
280                  "Node has been deleted from platform.");
281     }
282
283     errno = 0;
284     NodeList result;
285     struct dirent *entry = NULL;
286     while ((entry = readdir(dir))) {
287         if (!strcmp(entry->d_name, ".") || !strncmp(entry->d_name, "..", 2)) {
288             continue;
289         }
290         try {
291             NodePtr node = Node::resolve(*m_path + entry->d_name);
292             node->setPermissions(getPermissions()); // inherit access rights
293             if (NodeFilterMatcher::match(node, filter)) {
294                 result.push_back(node);
295             }
296         }
297         catch (const DeviceAPI::Common::BasePlatformException& ex)
298         {
299             LOGW("caught BasePlatformException ignored");
300         }
301     }
302
303     if (errno != 0) {
304         LOGW("Path %s Perm %d", m_path->getFullPath().c_str(), m_perms);
305         LOGW("throw IOException");
306         throw DeviceAPI::Common::IOException("Error while reading directory.");
307     }
308
309     if (closedir(dir) != 0) {
310         LOGW("Path %s Perm %d", m_path->getFullPath().c_str(), m_perms);
311         LOGW("throw IOException");
312         throw DeviceAPI::Common::IOException("Could not close platform node.");
313     }
314
315     return result;
316 }
317
318
319 void Node::getChildNodesWorker(EventListNodesPtr aEvent)
320 {
321     NodeList list = aEvent->getNode()->getChildNodes(aEvent->getFilter());
322     aEvent->setResult(list);
323 }
324
325 void Node::getChildNodesEnd(EventListNodesPtr aEvent)
326 {
327     // Convert results into JSCore
328     auto result = aEvent->getResult();
329     Converter converter(aEvent->getContext());
330
331     JSValueRef jsResult = converter.toJSValueRef(
332             result,
333             aEvent->getParentPermissions(),
334             aEvent->getContext());
335     aEvent->callSuccessCallback(jsResult);
336 }
337
338 void Node::getChildNodes(const EventListNodesPtr& event)
339 {
340     LOGD("getChildNodes begin");
341     // This function executes three functions:
342     // 1. Main initialization.
343     // 2. Worker thread.
344     // 3. Main results relay.
345     Utils::executeThreadAndMainFunctions<EventListNodesPtr>(
346         event,
347         Utils::ENoFunction,
348         Node::getChildNodesWorker,
349         Node::getChildNodesEnd);
350     LOGD("getChildNodes end");
351 }
352
353 NodePtr Node::createChild(
354         const PathPtr& path,
355         NodeType type,
356         int options)
357 {
358     if (m_type != NT_DIRECTORY) {
359         LOGW("throw IOException");
360         throw DeviceAPI::Common::IOException("Parent node is not a directory.");
361     }
362
363     if ((m_perms & PERM_WRITE) == 0) {
364         LOGW("throw InvalidValuesException");
365         throw DeviceAPI::Common::InvalidValuesException(
366                 "Not enough permissions.");
367     }
368
369     PathPtr childPath = *m_path + *path;
370     if (exists(childPath)) {
371         LOGW("throw IOException");
372         throw DeviceAPI::Common::IOException("Node already exists.");
373     }
374
375     NodePtr result;
376     switch (type) {
377     case NT_FILE:
378         result = createAsFile(childPath, options);
379         break;
380     case NT_DIRECTORY:
381         result = createAsDirectory(childPath, options);
382         break;
383     default:
384         LOGW("throw IOException");
385         throw DeviceAPI::Common::IOException("Unsupported node type.");
386     }
387     if (!!result) {
388         result->m_perms = m_perms;
389     } else {
390         LOGW("throw IOException");
391         throw DeviceAPI::Common::IOException("Node creation error");
392     }
393
394     return result;
395 }
396
397 StreamPtr Node::open(int mode)
398 {
399     if (m_type == NT_DIRECTORY) {
400         LOGW("throw IOException");
401         throw DeviceAPI::Common::IOException(
402                  "Cannot attach stream to directory.");
403     }
404
405     if (((mode & AM_READ) && ((m_perms & PERM_READ) == 0)) ||
406         (((mode & AM_WRITE) ||
407           (mode & AM_APPEND)) && ((m_perms & PERM_WRITE) == 0))) {
408         LOGW("throw InvalidValuesException");
409         throw DeviceAPI::Common::InvalidValuesException(
410                 "Not enough permissions.");
411     }
412
413     auto stream = std::shared_ptr<Stream>(new Stream(shared_from_this(), mode));
414     return stream;
415 }
416
417 void Node::openBegin(EventOpenPtr aEvent)
418 {
419     StreamPtr result = aEvent->getNode()->open(aEvent->getMode());
420     result->setCharSet(aEvent->getCharSet());
421     aEvent->setResult(result);
422 }
423
424 void Node::openEnd(EventOpenPtr aEvent)
425 {
426     // Convert results into JSCore
427     auto result = aEvent->getResult();
428     Converter converter(aEvent->getContext());
429
430     JSObjectRef object = JSFilestream::makeJSObject(aEvent->getContext(), result,
431             &Manager::getInstance());
432
433     JSValueRef jsResult = converter.toJSValueRef(object);
434     aEvent->callSuccessCallback(jsResult);
435 }
436
437 void Node::open(const EventOpenPtr& event)
438 {
439     LOGD("Open begin");
440     // This function executes three functions:
441     // 1. Main initialization.
442     // 2. Worker thread.
443     // 3. Main results relay.
444     Utils::executeThreadAndMainFunctions<EventOpenPtr>(
445         event,
446         openBegin,
447         Utils::ENoFunction,
448         openEnd);
449     LOGD("Open end");
450 }
451
452 void DLL_EXPORT Node::remove(int options)
453 {
454     switch (m_type) {
455     case NT_FILE:
456         removeAsFile(m_path);
457         break;
458     case NT_DIRECTORY:
459         removeAsDirectory(m_path, (options & OPT_RECURSIVE));
460         break;
461     default:
462         LOGE("throw UnknownError");
463         throw DeviceAPI::Common::UnknownException(
464                 "Not supported value of m_type");
465     }
466 }
467
468 unsigned long long Node::getSize() const
469 {
470     if (m_type == NT_DIRECTORY) {
471         LOGW("throw IOException");
472         throw DeviceAPI::Common::IOException(
473                  "Getting size for directories is not supported.");
474     }
475
476     struct stat info = stat(m_path);
477     if (!S_ISREG(info.st_mode)) {
478         LOGW("throw IOException");
479         throw DeviceAPI::Common::IOException(
480                  "Specified node is not a regular file.");
481     }
482
483     return info.st_size;
484 }
485
486 std::time_t Node::getCreated() const
487 {
488     return stat(m_path).st_ctime;
489 }
490
491 std::time_t Node::getModified() const
492 {
493     return stat(m_path).st_mtime;
494 }
495
496 // TODO Optimize it, maybe store a flag indicating that node is a root.
497 NodePtr Node::getParent() const
498 {
499     LocationPaths roots = Manager::getInstance().getLocationPaths();
500     for (LocationPaths::iterator it = roots.begin(); it != roots.end(); ++it) {
501         if (*(*it) == *m_path) {
502             return NodePtr();
503         }
504     }
505     NodePtr parent = Node::resolve(Path::create(m_path->getPath()));
506     parent->setPermissions(getPermissions());
507     return parent;
508 }
509
510 int Node::getMode() const
511 {
512     int result = 0;
513     struct stat info = stat(m_path);
514     if (info.st_mode & S_IRUSR) { result |= PM_USER_READ; }
515     if (info.st_mode & S_IWUSR) { result |= PM_USER_WRITE; }
516     if (info.st_mode & S_IXUSR) { result |= PM_USER_EXEC; }
517     if (info.st_mode & S_IRGRP) { result |= PM_GROUP_READ; }
518     if (info.st_mode & S_IWGRP) { result |= PM_GROUP_WRITE; }
519     if (info.st_mode & S_IXGRP) { result |= PM_GROUP_EXEC; }
520     if (info.st_mode & S_IROTH) { result |= PM_OTHER_READ; }
521     if (info.st_mode & S_IWOTH) { result |= PM_OTHER_WRITE; }
522     if (info.st_mode & S_IXOTH) { result |= PM_OTHER_EXEC; }
523     return result;
524 }
525
526 void Node::readBegin(EventReadTextPtr aEvent)
527 {
528     auto thiz = aEvent->getNode();
529     // Check access privileges
530     if (thiz->m_type != NT_FILE) {
531         LOGW("throw IOException");
532         throw DeviceAPI::Common::IOException("Node is not a file.");
533     }
534     if ((thiz->m_perms & PERM_READ) == 0) {
535         LOGW("throw IOException");
536         throw DeviceAPI::Common::IOException("No permission.");
537     }
538     // Open stream
539     auto stream =
540         std::shared_ptr<Stream>(new Stream(thiz->shared_from_this(), AM_READ));
541     aEvent->setStream(stream);
542 }
543
544 void Node::readWorker(EventReadTextPtr aEvent)
545 {
546     // Read file in text mode
547     std::string buffer;
548     auto inputStream = aEvent->getStream();
549     while (!inputStream->isEof()) {
550         buffer += inputStream->getLine();
551         if (!inputStream->isEof()) {
552             buffer += "\n";
553         }
554     }
555     //Convert string into UTF8
556     auto currentEncoding = aEvent->getCharSet();
557     std::shared_ptr<std::string> utf8OutStr(new std::string());
558     if (!buffer.empty()) {
559         Utils::toUTF8String(currentEncoding,
560                             buffer.c_str(),
561                             buffer.size(),
562                             *utf8OutStr);
563     }
564     aEvent->setResult(utf8OutStr);
565 }
566
567 void Node::readEnd(EventReadTextPtr aEvent)
568 {
569     // Convert results into JSCore
570     auto stream = aEvent->getStream();
571     stream->close();
572     auto nativeResult = aEvent->getResult();
573     Converter converter(aEvent->getContext());
574
575     JSValueRef jsResult = converter.toJSValueRef(*nativeResult);
576     aEvent->callSuccessCallback(jsResult);
577 }
578
579 gboolean Node::readAsTextCallbackExecutor(void* aEvent)
580 {
581     LOGD("Entered");
582     EventHandler* handl = static_cast<EventHandler*>(aEvent);
583     if (!handl) {
584         LOGE("handl is NULL");
585         return false;
586     }
587
588     auto event = handl->ptr;
589     try{
590         JSContextRef context = event->getContext();
591         if (!DeviceAPI::Common::GlobalContextManager::getInstance()->
592                 isAliveGlobalContext(context)) {
593             LOGE("context was closed");
594             delete handl;
595             return false;
596         }
597
598         if (event->isError()) {
599             LOGE("Error callback invoke");
600             event->callErrorCallback(
601                     DeviceAPI::Common::JSWebAPIErrorFactory::makeErrorObject(context,
602                     event->getExceptionName(),event->getExceptionMessage()));
603         } else {
604             event->callSuccessCallback(
605                     DeviceAPI::Common::JSUtil::toJSValueRef(context, *event->getResult()));
606         }
607
608     } catch(...){
609         LOGE("Exception");
610         delete handl;
611     }
612
613     if (handl) {
614         delete handl;
615     }
616
617     return false;
618 }
619
620 void* Node::readAsTextThread(void* handler)
621 {
622     EventHandler* handl = static_cast<EventHandler*>(handler);
623     auto event = handl->ptr;
624     try{
625         auto node = event->getNode();
626         // Check access privileges
627         if (NT_FILE != node->m_type) {
628             LOGW("throw IOException");
629             throw DeviceAPI::Common::IOException("Node is not a file.");
630         }
631         if (0 == (node->m_perms & PERM_READ)) {
632             LOGW("throw IOException");
633             throw DeviceAPI::Common::IOException("No permission.");
634         }
635         // Open stream
636         auto inputStream =
637             std::shared_ptr<Stream>(new Stream(node->shared_from_this(), AM_READ));
638         std::string buffer;
639         while (!inputStream->isEof()) {
640             buffer += inputStream->getLine();
641             if (!inputStream->isEof()) {
642                 buffer += "\n";
643             }
644         }
645         inputStream->close();
646         //Convert string into UTF8
647         auto currentEncoding = event->getCharSet();
648         std::shared_ptr<std::string> utf8OutStr(new std::string());
649         if (!buffer.empty()) {
650             Utils::toUTF8String(currentEncoding,
651                                 buffer.c_str(),
652                                 buffer.size(),
653                                 *utf8OutStr);
654         }
655         event->setResult(utf8OutStr);
656
657         guint id = g_idle_add(readAsTextCallbackExecutor, handler);
658         if (!id) {
659             LOGE("g_idle_add fails");
660             delete handl;
661         }
662     }catch(const  DeviceAPI::Common::BasePlatformException& err){
663         LOGE("Error %s , message %s", err.getName().c_str(), err.getMessage().c_str());
664         event->setException(err.getName(), err.getMessage());
665         event->setIsError(true);
666         delete handl;
667     }
668     catch(...){
669         LOGE("Unknown Exception");
670         event->setException("", "Unknown error");
671         event->setIsError(true);
672         delete handl;
673     }
674     return NULL;
675 }
676
677 void Node::readAsText(const EventReadTextPtr& aReadData)
678 {
679     EventHandler* handl = new EventHandler();
680     handl->ptr = aReadData;
681     pthread_t thread;
682     if(pthread_create(&thread, NULL, readAsTextThread,
683             static_cast<void*>(handl))) {
684         LOGE("Thread creation failed");
685         delete handl;
686         throw DeviceAPI::Common::UnknownException("Thread creation failed");
687     }
688     if(pthread_detach(thread)) {
689         LOGE("Thread detachment failed");
690     }
691 }
692
693 bool Node::exists(const PathPtr& path)
694 {
695     struct stat info;
696     memset(&info, 0, sizeof(struct stat));
697     int status = lstat(path->getFullPath().c_str(), &info);
698
699     if (0 == status)
700     {
701         return true;
702     }
703     else if (ENAMETOOLONG == errno)
704     {
705         LOGW("throw IOException");
706         throw DeviceAPI::Common::IOException("file name is too long");
707     }
708     else if (errno != ENOENT)
709     {
710         return true;
711     }
712     return false;
713 }
714
715 struct stat Node::stat(const PathPtr& path)
716 {
717     struct stat result;
718     memset(&result, 0, sizeof(struct stat));
719     if (::stat(path->getFullPath().c_str(),
720                 &result) != 0)
721     {
722         LOGE("File: %s", path->getFullPath().c_str());
723         LOGW("throw IOException");
724         throw DeviceAPI::Common::IOException("Node does not exist or no access");
725     }
726     return result;
727 }
728
729 Node::Node(const PathPtr& path, NodeType type):
730     m_path(path),
731     m_type(type),
732     m_perms(PERM_NONE)
733 {
734 }
735
736 NodePtr Node::createAsFile(const PathPtr& path,
737                            int /* options */)
738 {
739     createAsFileInternal(path);
740     return std::shared_ptr<Node>(new Node(path, NT_FILE));
741 }
742
743 void Node::createAsFileInternal(const PathPtr& path)
744 {
745     FILE* file = std::fopen(path->getFullPath().c_str(), "wb");
746     if (!file) {
747         LOGW("fopen fails IOException throw for path [%s]",
748              path->getFullPath().c_str());
749         throw DeviceAPI::Common::IOException(
750                  "Platform node could not be created.");
751     }
752     std::fclose(file);
753 }
754
755 NodePtr Node::createAsDirectory(const PathPtr& path,
756                                 int options)
757 {
758     if (options & OPT_RECURSIVE) {
759         auto parts = Utils::getParts(path);
760         for (auto it = parts.begin(); it != parts.end(); ++it) {
761             if (!exists(*it)) { createAsDirectoryInternal(*it); }
762         }
763     }
764     createAsDirectoryInternal(path);
765     return std::shared_ptr<Node>(new Node(path, NT_DIRECTORY));
766 }
767
768 void Node::createAsDirectoryInternal(const PathPtr& path)
769 {
770     if (mkdir(path->getFullPath().c_str(), S_IRWXU | S_IRWXG | S_IROTH |
771               S_IXOTH) != 0) {
772         LOGW("throw IOException");
773         throw DeviceAPI::Common::IOException(
774                  "Platform node could not be created.");
775     }
776 }
777
778 void Node::removeAsFile(const PathPtr& path)
779 {
780     auto fullPath = path->getFullPath();
781     if (unlink(fullPath.c_str()) != 0) {
782         LOGW("remove [%s]", fullPath.c_str());
783         LOGW("throw IOException");
784         throw DeviceAPI::Common::IOException(
785                  "Error while removing platform node.");
786     }
787 }
788
789 void Node::removeAsDirectory(const PathPtr& path,
790         bool recursive)
791 {
792     if (recursive) {
793         DIR* dir = opendir(path->getFullPath().c_str());
794         if (!dir) {
795             LOGW("File %s", path->getFullPath().c_str());
796             LOGW("throw IOException");
797             throw DeviceAPI::Common::IOException(
798                      "Node does not exist or access denied.");
799         }
800         errno = 0;
801         struct dirent *entry = NULL;
802         while ((entry = readdir(dir))) {
803             if (!strcmp(entry->d_name, ".") || !strncmp(entry->d_name, "..", 2)) {
804                 continue;
805             }
806             PathPtr subPath = *path + entry->d_name;
807             struct stat info;
808             memset(&info, 0, sizeof(struct stat));
809             if (lstat(subPath->getFullPath().c_str(), &info) == 0) {
810                 try {
811                     if (S_ISDIR(info.st_mode)) {
812                         removeAsDirectory(subPath, true);
813                     } else if (S_ISREG(info.st_mode)) {
814                         removeAsFile(subPath);
815                     }
816                 }
817                 catch (const DeviceAPI::Common::BasePlatformException& ex)
818                 {
819                 }
820                 // TODO: Not sure if above exception should be swallowed.
821             }
822         }
823         closedir(dir);
824     }
825
826     errno = 0;
827     if (rmdir(path->getFullPath().c_str()) != 0) {
828         if (errno == EEXIST) {
829             LOGW("throw IOException");
830             throw DeviceAPI::Common::IOException("Node has child nodes.");
831         }
832         LOGW("throw IOException");
833         throw DeviceAPI::Common::IOException(
834                  "Error while removing platform node.");
835     }
836 }
837
838 std::string Node::toUri(int /*widgetId*/) const
839 {
840     // TODO I believe moving this feature to WrtWrapper would make more sense.
841     return "file://" + m_path->getFullPath();
842 }
843
844 bool Node::isSubPath(std::string aDirPath, PathPtr aFilePath)
845 {
846     auto myPath = aDirPath;
847     if(!myPath.empty() && myPath[myPath.length()-1] != Path::getSeparator()) {
848         myPath += Path::getSeparator();
849         LOGD("updated aDirPath to:%s", aDirPath.c_str());
850     }
851
852     auto childPath = aFilePath->getFullPath();
853     bool isSubP = strncmp(myPath.c_str(), childPath.c_str(), myPath.size()) == 0;
854
855     LOGD("aDirPath:%s myPath:%s aFilePath:%s isSubP:%d",
856             aDirPath.c_str(),
857             myPath.c_str(),
858             aFilePath->getFullPath().c_str(),
859             isSubP);
860
861     return isSubP;
862 }
863
864 bool Node::isSubPath(PathPtr aPath) const
865 {
866     LOGD("Entered thisPath:%s aPath: %s",
867             this->getPath()->getFullPath().c_str(),
868             aPath->getFullPath().c_str());
869
870     resolve(aPath);
871
872     bool isSubP = isSubPath(m_path->getFullPath(), aPath);
873     LOGD("thisPath:%s aPath: %s isSubP:%d",
874             this->getPath()->getFullPath().c_str(),
875             aPath->getFullPath().c_str(),
876             isSubP);
877     return isSubP;
878 }
879
880 }
881 }