#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 {
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;
}
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.");
}
}
}
+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
{
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.
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.");
}
{
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: