Tizen 2.1 base
[platform/framework/web/wrt-plugins-common.git] / src / modules / tizen / Filesystem / Manager.cpp
index 6cdaad9..68d533f 100755 (executable)
@@ -22,7 +22,9 @@
 #include <ctime>
 #include <cstdio>
 #include <sstream>
-#include <dirent.h>
+#include <fts.h>
+#include <ecore-1/Ecore_File.h>
+#include <eina-1/eina/eina_list.h>
 #include <dpl/log/log.h>
 #include <dpl/scoped_ptr.h>
 #include <dpl/errno_string.h>
 #include <Commons/Regex.h>
 #include <Filesystem/PathUtils.h>
 #include "Node.h"
-#include "System.h"
-#include "CopyCommand.h"
-#include "MoveCommand.h"
-#include "RemoveCommand.h"
 #include "Utils.h"
 
 namespace {
@@ -94,8 +92,10 @@ void Manager::removeOpenedNode(const INodePtr& node)
 
 bool Manager::checkIfOpened(const IPathPtr& path) const
 {
+    Assert(path);
     NodeListIterator it = m_openedNodes.begin();
     for (; it != m_openedNodes.end(); ++it) {
+        Assert(*it);
         if (*path == *(*it)->getPath()) {
             return true;
         }
@@ -187,40 +187,59 @@ void Manager::find(const IPathPtr& path,
         const EventFindPtr& event)
 {
     Try {
-        DIR* dir = opendir(path->getFullPath().c_str());
-        if (!dir) {
+        Assert(path && "path is NULL");
+        FTS *fts;
+        FTSENT *ftsent;
+        std::string pth=path->getFullPath();
+        char * const paths[] = {const_cast<char * const>(pth.c_str()), NULL};
+
+        if ((fts = fts_open(paths, FTS_PHYSICAL|FTS_NOCHDIR, NULL)) == NULL) {
+            //ERROR
+            int error = errno;
+            LogError(__PRETTY_FUNCTION__ << ": fts_open on "
+                    << pth
+                    << " failed with error: "
+                    << strerror(error));
             return;
         }
 
-        errno = 0;
-        struct dirent* entry = NULL;
-        while ((entry = readdir(dir))) {
-            if (event && event->checkCancelled()) {
-                break;
-            }
-            if (!strncmp(entry->d_name, ".",
-                         1) || !strncmp(entry->d_name, "..", 2)) {
-                continue;
-            }
-            IPathPtr childPath = *path + entry->d_name;
-            struct stat info;
-            memset(&info, 0, sizeof(struct stat));
-            if (lstat(childPath->getFullPath().c_str(), &info) == 0) {
-                if (matchFilters(entry->d_name, info, filters)) {
-                    result.push_back(Node::resolve(childPath));
-                }
-                if (S_ISDIR(info.st_mode)) {
-                    find(childPath, filters, result, event);
-                }
+        while ((ftsent = fts_read(fts)) != NULL) {
+            if(event && event->checkCancelled()) break;
+            switch (ftsent->fts_info) {
+                case FTS_DP:
+                    //directory in postorder - do nothing
+                    break;
+                case FTS_D:
+                case FTS_DC:
+                case FTS_F:
+                case FTS_SL:
+                case FTS_SLNONE:
+                case FTS_DEFAULT:
+                    //regular files, symbolic links, directories in preorder
+                    //and other file entries that can be processed further
+                    if (matchFilters(ftsent->fts_name, *ftsent->fts_statp, filters)) {
+                        IPathPtr childPath=IPath::create(ftsent->fts_path);
+                        result.push_back(Node::resolve(childPath));
+                    }
+                    break;
+                case FTS_NS:
+                case FTS_NSOK:
+                case FTS_DOT:
+                case FTS_DNR:
+                case FTS_ERR:
+                default:
+                    LogWarning(__PRETTY_FUNCTION__
+                            << ": traversal failed with error: "
+                            << strerror(ftsent->fts_errno));
+                    ThrowMsg(Commons::PlatformException,
+                            "Error reading directory");
             }
         }
 
-        if (errno != 0) {
-            ThrowMsg(Commons::PlatformException,
-                     "Error while reading directory.");
-        }
-
-        if (closedir(dir) != 0) {
+        if (fts_close(fts) == -1) {
+            int error = errno;
+            LogWarning(__PRETTY_FUNCTION__ << ": fts_close failed with error: "
+                    << strerror(error));
             ThrowMsg(Commons::PlatformException,
                      "Could not close platform node.");
         }
@@ -229,6 +248,49 @@ void Manager::find(const IPathPtr& path,
     }
 }
 
+void Manager::copyElement(
+        const std::string &src, const std::string &dest, bool recursive) const
+{
+    LogDebug("Copying src: " << src << " to: " << dest);
+
+    //element is a file:
+    if (EINA_TRUE != ecore_file_is_dir(src.c_str())) {
+        if (EINA_TRUE != ecore_file_cp(src.c_str(), dest.c_str())) {
+            ThrowMsg(Commons::PlatformException, "Failed to copy file");
+        }
+        return;
+    }
+    //element is a directory -> create it:
+    if (EINA_TRUE != ecore_file_mkdir(dest.c_str())) {
+        LogDebug("Failed to create destination directory");
+        ThrowMsg(Commons::PlatformException, "Failed to copy directory");
+    }
+    //copy all elements of directory:
+    if (recursive) {
+        Eina_List* list = ecore_file_ls(src.c_str());
+        void* data;
+        EINA_LIST_FREE(list, data)
+        {
+            Try
+            {
+                copyElement((src + '/' + static_cast<char*>(data)).c_str(),
+                            (dest + '/' + static_cast<char*>(data)).c_str());
+            }
+            Catch(Commons::PlatformException)
+            {
+                //remove rest of the list
+                EINA_LIST_FREE(list, data)
+                {
+                    free(data);
+                }
+                ReThrowMsg(Commons::PlatformException, "Failed to copy element");
+            }
+            free(data);
+        }
+    }
+
+}
+
 bool Manager::access(const IPathPtr& path,
         int accessType) const
 {
@@ -281,79 +343,116 @@ void Manager::OnRequestReceived(const EventResolvePtr& event)
     event->setCancelAllowed(true);
 }
 
+void Manager::checkPaths(
+        Api::IPathPtr &src,
+        Api::IPathPtr &dest) {
+    Assert(dest);
+    Assert(src);
+    if (!dest->isAbsolute()) {
+        dest = src->getPath() + *dest;
+    }
+
+    if (src == dest) {
+        ThrowMsg(Commons::PlatformException,
+                 "Destination is same as source: " << src->getFullPath());
+    }
+
+    INodePtr parent;
+    Try {
+        parent = Node::resolve(IPath::create(dest->getPath()));
+    }
+    Catch(Commons::PlatformException) {
+        ReThrowMsg(Commons::PlatformException,
+                   "Could not get destination's parent node.");
+    }
+
+    if (parent->getType() != NT_DIRECTORY) {
+        ThrowMsg(Commons::PlatformException,
+                 "Destination's parent node is not directory.");
+    }
+
+    if (!access(parent->getPath(), AT_WRITE)) {
+        ThrowMsg(Commons::SecurityException,
+            "Not enough permissions to write to destination.");
+    }
+}
+
+bool Manager::pathExists(const std::string &path) {
+    errno = 0;
+    struct stat info;
+    memset(&info, 0, sizeof(struct stat));
+    int status = lstat(path.c_str(), &info);
+    if ((status != 0) && (errno != ENOENT)) {
+        ThrowMsg(Commons::PlatformException,
+                 "No access to platform destination node.");
+    }
+    return 0 == status;
+}
+
 void Manager::OnRequestReceived(const EventCopyPtr& event)
 {
     Try {
         INodePtr srcNode = Node::resolve(event->getSource());
-        if ((srcNode->getMode() & PERM_READ) == 0) {
+        int requiredAccess;
+        switch (srcNode->getType()) {
+            case NT_DIRECTORY:
+                requiredAccess = AT_EXEC;
+                break;
+            case NT_FILE:
+                requiredAccess = AT_READ;
+                break;
+        }
+        if (!access(srcNode->getPath(), requiredAccess)) {
             ThrowMsg(Commons::SecurityException,
-                     "Not enough permissions to read source node.");
+                "Not enough permissions to copy source node.");
         }
 
         IPathPtr src = event->getSource();
         IPathPtr dest = event->getDestination();
-        if (!dest->isAbsolute()) {
-            dest = src->getPath() + *dest;
-        }
 
-        if (src == dest) {
-            ThrowMsg(Commons::PlatformException,
-                     "Destination is same as source.");
-        }
-
-        INodePtr parent;
-        Try {
-            parent = Node::resolve(IPath::create(dest->getPath()));
-        }
-        Catch(Commons::PlatformException) {
-            ReThrowMsg(Commons::PlatformException,
-                       "Could not get destination's parent node.");
-        }
-
-        if (parent->getType() != NT_DIRECTORY) {
-            ThrowMsg(Commons::PlatformException,
-                     "Destination's parent node is not directory.");
-        }
+        checkPaths(src, dest);
 
         std::string realSrc = src->getFullPath();
         std::string realDest = dest->getFullPath();
 
-        errno = 0;
-        struct stat info;
-        memset(&info, 0, sizeof(struct stat));
-        int status = lstat(realDest.c_str(), &info);
-        if ((status != 0) && (errno != ENOENT)) {
-            ThrowMsg(Commons::PlatformException,
-                     "No access to platform destination node.");
-        }
-
-        if (((event->getOptions() & OPT_OVERWRITE) == 0) && (status == 0)) {
-            ThrowMsg(Commons::PlatformException, "Overwrite is not set.");
-        }
+        if (pathExists(realDest)) {
+            //no owerwrite flag setted -> exception
+            if ((event->getOptions() & OPT_OVERWRITE) == 0) {
+                ThrowMsg(Commons::PlatformException, "Overwrite is not set.");
+            }
 
-        if (event->checkCancelled()) {
-            //file is not copied yet, so we can cancel it now.
-            event->setCancelAllowed(true);
-            return;
-        }
+            if (event->checkCancelled()) {
+                //file is not copied yet, so we can cancel it now.
+                event->setCancelAllowed(true);
+                return;
+            }
 
-        if (event->getOptions() & OPT_OVERWRITE) {
-            DPL::ScopedPtr<RemoveCommand> remove(new RemoveCommand(dest));
-            remove->setRecursive(true);
-            remove->setForce(true);
-            System::run(remove.Get());
+            //destination exist. Need to be removed
+            Try {
+                INodePtr node = Node::resolve(event->getDestination());
+                node->remove(event->getOptions());
+            }
+            Catch(Commons::PlatformException) {
+                LogError("Exception: " << _rethrown_exception.GetMessage());
+                event->setExceptionCode(
+                    Commons::ExceptionCodes::PlatformException);
+            }
+            Catch(Commons::SecurityException) {
+                event->setExceptionCode(
+                    Commons::ExceptionCodes::SecurityException);
+            }
         }
-
-        DPL::ScopedPtr<CopyCommand> copy(new CopyCommand(src, dest));
-        copy->setRecursive(true);
-        System::run(copy.Get());
+        //Destination is not exist. Start copy now.
+        copyElement(realSrc, realDest);
 
         event->setResult(Node::resolve(dest));
     }
-    Catch(Commons::PlatformException) {
+    catch (const Commons::PlatformException& ex) {
+        LogError("Exception: " << ex.GetMessage());
         event->setExceptionCode(Commons::ExceptionCodes::PlatformException);
     }
-    Catch(Commons::SecurityException) {
+    catch (const Commons::SecurityException& ex) {
+        LogError("Exception: " << ex.GetMessage());
         event->setExceptionCode(Commons::ExceptionCodes::SecurityException);
     }
     //file is copied already so we don't allow cancelling anymore.
@@ -367,45 +466,16 @@ void Manager::OnRequestReceived(const EventMovePtr& event)
         IPathPtr dest = event->getDestination();
 
         INodePtr srcNode = Node::resolve(src);
-        if ((srcNode->getMode() & PERM_WRITE) == 0)
-        {
+        if (!access(srcNode->getParent()->getPath(), AT_WRITE)) {
             ThrowMsg(Commons::SecurityException,
-                     "Not enough permissions to move source node.");
-        }
-
-        if (!dest->isAbsolute()) {
-            dest = src->getPath() + *dest;
-        }
-
-        if (src == dest) {
-            ThrowMsg(Commons::PlatformException,
-                     "Destination is same as source.");
+                "Not enough permissions to move source node.");
         }
 
-        INodePtr parent;
-        Try {
-            parent = Node::resolve(IPath::create(dest->getPath()));
-        }
-        Catch(Commons::PlatformException) {
-            ReThrowMsg(Commons::PlatformException,
-                       "Could not get destination's parent node.");
-        }
+        checkPaths(src, dest);
 
-        if (parent->getType() != NT_DIRECTORY) {
-            ThrowMsg(Commons::PlatformException,
-                     "Destination's parent node is not directory.");
-        }
+        bool destExists = pathExists(dest->getFullPath());
 
-        errno = 0;
-        struct stat info;
-        memset(&info, 0, sizeof(info));
-        int status = lstat(dest->getFullPath().c_str(), &info);
-        if ((status != 0) && (errno != ENOENT)) {
-            ThrowMsg(Commons::PlatformException,
-                     "No access to platform destination node.");
-        }
-
-        if ((0 == (event->getOptions() & OPT_OVERWRITE)) && (0 == status)) {
+        if (destExists && (0 == (event->getOptions() & OPT_OVERWRITE))) {
             ThrowMsg(Commons::PlatformException, "Overwrite is not set.");
         }
 
@@ -424,15 +494,35 @@ void Manager::OnRequestReceived(const EventMovePtr& event)
             {
             case EXDEV:
                 {
-                    if ((srcNode->getMode() & PERM_READ) == 0)
-                    {
-                        ThrowMsg(Commons::SecurityException,
-                                 "Not enough permissions to move source node.");
+                    if (destExists) {
+                        //destination exist. Need to be removed
+                        Try {
+                            INodePtr node = Node::resolve(
+                                event->getDestination());
+                            node->remove(event->getOptions());
+                        }
+                        Catch(Commons::PlatformException) {
+                            LogError("Exception while removing dest directory");
+                            event->setExceptionCode(
+                                Commons::ExceptionCodes::PlatformException);
+                        }
+                        Catch(Commons::SecurityException) {
+                            event->setExceptionCode(
+                                Commons::ExceptionCodes::SecurityException);
+                        }
+                    }
+
+                    copyElement(src->getFullPath(),
+                                dest->getFullPath());
+                    //remove source files
+                    Try {
+                        INodePtr node = Node::resolve(event->getSource());
+                        node->remove(event->getOptions());
+                    }
+                    Catch(Commons::Exception) {
+                        LogError("Exception: "
+                                 << _rethrown_exception.GetMessage());
                     }
-                    DPL::ScopedPtr<MoveCommand>
-                            move(new MoveCommand(src, dest));
-                    move->setForce(event->getOptions() & OPT_OVERWRITE);
-                    System::run(move.Get());
                     break;
                 }
             default: