2 * Copyright (c) 2011 Samsung Electronics Co., Ltd All Rights Reserved
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
8 * http://www.apache.org/licenses/LICENSE-2.0
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
26 #include <ecore-1/Ecore_File.h>
27 #include <eina-1/eina/eina_list.h>
28 #include <dpl/log/log.h>
29 #include <dpl/scoped_ptr.h>
30 #include <dpl/errno_string.h>
31 #include <Commons/Exception.h>
32 #include <Commons/Regex.h>
33 #include <Filesystem/PathUtils.h>
38 const char* PATH_ROOT = "/opt/media";
39 const char* PATH_DOWNLOADS = "/opt/media/Downloads";
40 const char* PATH_DOCUMENTS = "/opt/media/Documents";
41 const char* PATH_SOUNDS = "/opt/media/Music";
42 const char* PATH_IMAGES = "/opt/media/Images";
43 const char* PATH_VIDEOS = "/opt/media/Videos";
44 const char* PATH_SDCARD = "/opt/storage/sdcard";
47 namespace WrtDeviceApis {
48 namespace Filesystem {
51 Manager::Locations Manager::m_locations;
52 const std::size_t Manager::m_maxPathLength = 256;
53 NodeList Manager::m_openedNodes;
55 bool Manager::fileExists(const std::string &file)
59 memset(&info, 0, sizeof(struct stat));
60 int status = lstat(file.c_str(), &info);
63 } else if (errno == ENOENT) {
66 ThrowMsg(Commons::PlatformException, "Cannot stat file.");
69 void Manager::addOpenedNode(const INodePtr& node)
71 NodeListIterator it = m_openedNodes.begin();
72 for (; it != m_openedNodes.end(); ++it) {
73 if (node.Get() == (*it).Get()) {
74 //node is added already
78 m_openedNodes.push_back(node);
81 void Manager::removeOpenedNode(const INodePtr& node)
83 NodeListIterator it = m_openedNodes.begin();
84 for (; it != m_openedNodes.end(); ++it) {
85 if ((*it).Get() == node.Get()) {
86 m_openedNodes.erase(it);
92 bool Manager::checkIfOpened(const IPathPtr& path) const
95 NodeListIterator it = m_openedNodes.begin();
96 for (; it != m_openedNodes.end(); ++it) {
98 if (*path == *(*it)->getPath()) {
107 static bool initialized = init();
114 IPathPtr Manager::getBasePath() const
116 Locations::const_iterator it = m_locations.find(LT_ROOT);
117 if (it == m_locations.end()) {
118 ThrowMsg(Commons::PlatformException, "Base path not available.");
123 IPathPtr Manager::getLocationPath(LocationType type) const
125 Locations::const_iterator it = m_locations.find(type);
126 if (it != m_locations.end()) {
127 return it->second->clone();
132 LocationPaths Manager::getLocationPaths() const
134 LocationPaths result;
135 Locations::const_iterator it = m_locations.begin();
136 for (; it != m_locations.end(); ++it) {
137 result.push_back(it->second->clone());
142 LocationTypes Manager::getLocations() const
144 LocationTypes result;
145 Locations::const_iterator it = m_locations.begin();
146 for (; it != m_locations.end(); ++it) {
147 result.push_back(it->first);
152 void Manager::getNode(const EventResolvePtr& event)
154 EventRequestReceiver<EventResolve>::PostRequest(event);
157 std::size_t Manager::getMaxPathLength() const
159 return m_maxPathLength;
162 void Manager::copy(const EventCopyPtr& event)
164 EventRequestReceiver<EventCopy>::PostRequest(event);
167 void Manager::move(const EventMovePtr& event)
169 EventRequestReceiver<EventMove>::PostRequest(event);
172 void Manager::remove(const EventRemovePtr& event)
174 EventRequestReceiver<EventRemove>::PostRequest(event);
177 void Manager::find(const EventFindPtr& event)
179 EventRequestReceiver<EventFind>::PostRequest(event);
182 void Manager::find(const IPathPtr& path,
183 const FiltersMap& filters,
185 const EventFindPtr& event)
188 Assert(path && "path is NULL");
191 std::string pth = path->getFullPath();
192 char * const paths[] = { const_cast<char * const>(pth.c_str()), NULL };
195 fts_open(paths, FTS_PHYSICAL | FTS_NOCHDIR, NULL)) == NULL)
199 LogError(__PRETTY_FUNCTION__ << ": fts_open on "
201 << " failed with error: "
206 while ((ftsent = fts_read(fts)) != NULL) {
207 if (event && event->checkCancelled()) {
210 switch (ftsent->fts_info) {
212 //directory in postorder - do nothing
220 //regular files, symbolic links, directories in preorder
221 //and other file entries that can be processed further
222 if (matchFilters(ftsent->fts_name, *ftsent->fts_statp,
225 IPathPtr childPath = IPath::create(ftsent->fts_path);
226 result.push_back(Node::resolve(childPath));
235 LogWarning(__PRETTY_FUNCTION__
236 << ": traversal failed with error: "
237 << strerror(ftsent->fts_errno));
238 ThrowMsg(Commons::PlatformException,
239 "Error reading directory");
243 if (fts_close(fts) == -1) {
245 LogWarning(__PRETTY_FUNCTION__ << ": fts_close failed with error: "
247 ThrowMsg(Commons::PlatformException,
248 "Could not close platform node.");
251 Catch(Commons::Exception) {}
254 void Manager::copyElement(
255 const std::string &src, const std::string &dest, bool recursive) const
257 LogDebug("Copying src: " << src << " to: " << dest);
260 if (EINA_TRUE != ecore_file_is_dir(src.c_str())) {
261 if (EINA_TRUE != ecore_file_cp(src.c_str(), dest.c_str())) {
262 ThrowMsg(Commons::PlatformException, "Failed to copy file");
266 //element is a directory -> create it:
267 if (EINA_TRUE != ecore_file_mkdir(dest.c_str())) {
268 LogDebug("Failed to create destination directory");
269 ThrowMsg(Commons::PlatformException, "Failed to copy directory");
271 //copy all elements of directory:
273 Eina_List* list = ecore_file_ls(src.c_str());
275 EINA_LIST_FREE(list, data)
279 copyElement((src + '/' + static_cast<char*>(data)).c_str(),
280 (dest + '/' + static_cast<char*>(data)).c_str());
282 Catch(Commons::PlatformException)
284 //remove rest of the list
285 EINA_LIST_FREE(list, data)
289 ReThrowMsg(Commons::PlatformException, "Failed to copy element");
296 bool Manager::access(const IPathPtr& path,
297 int accessType) const
300 if (accessType & AT_EXISTS) {
303 if (accessType & AT_READ) {
306 if (accessType & AT_WRITE) {
309 if (accessType & AT_EXEC) {
312 return (::access(path->getFullPath().c_str(), amode) == 0);
315 bool Manager::matchFilters(const std::string& name,
316 const struct stat& info,
317 const FiltersMap& filters)
319 FiltersMap::const_iterator it = filters.begin();
320 for (; it != filters.end(); ++it) {
321 if (it->first == FF_NAME) {
322 if (!pcrecpp::RE(it->second).PartialMatch(name)) {
325 } else if (it->first == FF_SIZE) {
327 std::stringstream ss(it->second);
330 (size != static_cast<size_t>(info.st_size)))
334 } else if (it->first == FF_CREATED) {
336 std::stringstream ss(it->second);
338 if (!ss || (created != info.st_ctime)) {
341 } else if (it->first == FF_MODIFIED) {
342 std::time_t modified;
343 std::stringstream ss(it->second);
345 if (!ss || (modified != info.st_mtime)) {
353 void Manager::OnRequestReceived(const EventResolvePtr& event)
356 event->setResult(Node::resolve(event->getPath()));
357 } catch (const Commons::PlatformException& ex) {
358 LogError("Exception: " << ex.GetMessage());
359 event->setExceptionCode(Commons::ExceptionCodes::PlatformException);
361 event->setCancelAllowed(true);
364 void Manager::checkPaths(
370 if (!dest->isAbsolute()) {
371 dest = src->getPath() + *dest;
375 ThrowMsg(Commons::PlatformException,
376 "Destination is same as source: " << src->getFullPath());
381 parent = Node::resolve(IPath::create(dest->getPath()));
383 Catch(Commons::PlatformException) {
384 ReThrowMsg(Commons::PlatformException,
385 "Could not get destination's parent node.");
388 if (parent->getType() != NT_DIRECTORY) {
389 ThrowMsg(Commons::PlatformException,
390 "Destination's parent node is not directory.");
393 if (!access(parent->getPath(), AT_WRITE)) {
394 ThrowMsg(Commons::SecurityException,
395 "Not enough permissions to write to destination.");
399 bool Manager::pathExists(const std::string &path)
403 memset(&info, 0, sizeof(struct stat));
404 int status = lstat(path.c_str(), &info);
405 if ((status != 0) && (errno != ENOENT)) {
406 ThrowMsg(Commons::PlatformException,
407 "No access to platform destination node.");
412 void Manager::OnRequestReceived(const EventCopyPtr& event)
415 INodePtr srcNode = Node::resolve(event->getSource());
417 switch (srcNode->getType()) {
419 requiredAccess = AT_EXEC;
422 requiredAccess = AT_READ;
425 if (!access(srcNode->getPath(), requiredAccess)) {
426 ThrowMsg(Commons::SecurityException,
427 "Not enough permissions to copy source node.");
430 IPathPtr src = event->getSource();
431 IPathPtr dest = event->getDestination();
433 checkPaths(src, dest);
435 std::string realSrc = src->getFullPath();
436 std::string realDest = dest->getFullPath();
438 if (pathExists(realDest)) {
439 //no owerwrite flag setted -> exception
440 if ((event->getOptions() & OPT_OVERWRITE) == 0) {
441 ThrowMsg(Commons::PlatformException, "Overwrite is not set.");
444 if (event->checkCancelled()) {
445 //file is not copied yet, so we can cancel it now.
446 event->setCancelAllowed(true);
450 //destination exist. Need to be removed
452 INodePtr node = Node::resolve(event->getDestination());
453 node->remove(event->getOptions());
455 Catch(Commons::PlatformException) {
456 LogError("Exception: " << _rethrown_exception.GetMessage());
457 event->setExceptionCode(
458 Commons::ExceptionCodes::PlatformException);
460 Catch(Commons::SecurityException) {
461 event->setExceptionCode(
462 Commons::ExceptionCodes::SecurityException);
465 //Destination is not exist. Start copy now.
466 copyElement(realSrc, realDest);
468 event->setResult(Node::resolve(dest));
469 } catch (const Commons::PlatformException& ex) {
470 LogError("Exception: " << ex.GetMessage());
471 event->setExceptionCode(Commons::ExceptionCodes::PlatformException);
472 } catch (const Commons::SecurityException& ex) {
473 LogError("Exception: " << ex.GetMessage());
474 event->setExceptionCode(Commons::ExceptionCodes::SecurityException);
476 //file is copied already so we don't allow cancelling anymore.
477 event->setCancelAllowed(false);
480 void Manager::OnRequestReceived(const EventMovePtr& event)
483 IPathPtr src = event->getSource();
484 IPathPtr dest = event->getDestination();
486 INodePtr srcNode = Node::resolve(src);
487 if (!access(srcNode->getParent()->getPath(), AT_WRITE)) {
488 ThrowMsg(Commons::SecurityException,
489 "Not enough permissions to move source node.");
492 checkPaths(src, dest);
494 bool destExists = pathExists(dest->getFullPath());
496 if (destExists && (0 == (event->getOptions() & OPT_OVERWRITE))) {
497 ThrowMsg(Commons::PlatformException, "Overwrite is not set.");
500 if (event->checkCancelled()) {
501 //file is not moved yet, so we can cancel it now.
502 event->setCancelAllowed(true);
507 if (0 != ::rename(src->getFullPath().c_str(),
508 dest->getFullPath().c_str()))
515 //destination exist. Need to be removed
517 INodePtr node = Node::resolve(
518 event->getDestination());
519 node->remove(event->getOptions());
521 Catch(Commons::PlatformException) {
522 LogError("Exception while removing dest directory");
523 event->setExceptionCode(
524 Commons::ExceptionCodes::PlatformException);
526 Catch(Commons::SecurityException) {
527 event->setExceptionCode(
528 Commons::ExceptionCodes::SecurityException);
532 copyElement(src->getFullPath(),
533 dest->getFullPath());
534 //remove source files
536 INodePtr node = Node::resolve(event->getSource());
537 node->remove(event->getOptions());
539 Catch(Commons::Exception) {
540 LogError("Exception: "
541 << _rethrown_exception.GetMessage());
546 ThrowMsg(Commons::PlatformException,
547 "Error on rename: " << DPL::GetErrnoString(error));
552 event->setResult(Node::resolve(dest));
553 } catch (const Commons::PlatformException& ex) {
554 LogError("Exception: " << ex.GetMessage());
555 event->setExceptionCode(Commons::ExceptionCodes::PlatformException);
556 } catch (const Commons::SecurityException& ex) {
557 LogError("Exception: " << ex.GetMessage());
558 event->setExceptionCode(Commons::ExceptionCodes::SecurityException);
560 event->setCancelAllowed(false);
563 void Manager::OnRequestReceived(const EventRemovePtr& event)
565 if (!event->checkCancelled()) {
567 INodePtr node = Node::resolve(event->getPath());
568 node->remove(event->getOptions());
570 Catch(Commons::PlatformException) {
571 LogError("Exception: " << _rethrown_exception.GetMessage());
572 event->setExceptionCode(Commons::ExceptionCodes::PlatformException);
574 Catch(Commons::SecurityException) {
575 event->setExceptionCode(Commons::ExceptionCodes::SecurityException);
577 event->setCancelAllowed(false);
579 event->setCancelAllowed(true);
583 void Manager::OnRequestReceived(const EventFindPtr& event)
587 find(event->getPath(), event->getFilters(), result, event);
588 event->setResult(result);
589 } catch (const Commons::Exception& ex) {
590 LogError("Exception: " << ex.GetMessage());
591 event->setExceptionCode(Commons::ExceptionCodes::PlatformException);
593 event->setCancelAllowed(true);
598 m_locations[LT_ROOT] = IPath::create(PATH_ROOT);
599 m_locations[LT_SDCARD] = IPath::create(PATH_SDCARD);
600 setupLocation(LT_DOWNLOADS, PATH_DOWNLOADS);
601 setupLocation(LT_DOCUMENTS, PATH_DOCUMENTS);
602 setupLocation(LT_SOUNDS, PATH_SOUNDS);
603 setupLocation(LT_IMAGES, PATH_IMAGES);
604 setupLocation(LT_VIDEOS, PATH_VIDEOS);
609 void Manager::setupLocation(LocationType location,
612 if (!nodeExists(path)) {
614 makePath(path, 0755);
615 } catch (const Commons::PlatformException& ex) {
616 LogError("Exception: " << ex.DumpToString());
620 m_locations[location] = IPath::create(path);