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 {
52 Manager::Locations Manager::m_locations;
53 const std::size_t Manager::m_maxPathLength = 256;
54 NodeList Manager::m_openedNodes;
56 bool Manager::fileExists(const std::string &file)
60 memset(&info, 0, sizeof(struct stat));
61 int status = lstat(file.c_str(), &info);
64 } else if (errno == ENOENT) {
67 ThrowMsg(Commons::PlatformException, "Cannot stat file.");
70 void Manager::addOpenedNode(const INodePtr& node)
72 NodeListIterator it = m_openedNodes.begin();
73 for (; it != m_openedNodes.end(); ++it) {
74 if (node.Get() == (*it).Get()) {
75 //node is added already
79 m_openedNodes.push_back(node);
82 void Manager::removeOpenedNode(const INodePtr& node)
84 NodeListIterator it = m_openedNodes.begin();
85 for (; it != m_openedNodes.end(); ++it) {
86 if ((*it).Get() == node.Get()) {
87 m_openedNodes.erase(it);
93 bool Manager::checkIfOpened(const IPathPtr& path) const
96 NodeListIterator it = m_openedNodes.begin();
97 for (; it != m_openedNodes.end(); ++it) {
99 if (*path == *(*it)->getPath()) {
108 static bool initialized = init();
116 IPathPtr Manager::getBasePath() const
118 Locations::const_iterator it = m_locations.find(LT_ROOT);
119 if (it == m_locations.end()) {
120 ThrowMsg(Commons::PlatformException, "Base path not available.");
125 IPathPtr Manager::getLocationPath(LocationType type) const
127 Locations::const_iterator it = m_locations.find(type);
128 if (it != m_locations.end()) {
129 return it->second->clone();
134 LocationPaths Manager::getLocationPaths() const
136 LocationPaths result;
137 Locations::const_iterator it = m_locations.begin();
138 for (; it != m_locations.end(); ++it) {
139 result.push_back(it->second->clone());
144 LocationTypes Manager::getLocations() const
146 LocationTypes result;
147 Locations::const_iterator it = m_locations.begin();
148 for (; it != m_locations.end(); ++it) {
149 result.push_back(it->first);
154 void Manager::getNode(const EventResolvePtr& event)
156 EventRequestReceiver<EventResolve>::PostRequest(event);
159 std::size_t Manager::getMaxPathLength() const
161 return m_maxPathLength;
164 void Manager::copy(const EventCopyPtr& event)
166 EventRequestReceiver<EventCopy>::PostRequest(event);
169 void Manager::move(const EventMovePtr& event)
171 EventRequestReceiver<EventMove>::PostRequest(event);
174 void Manager::remove(const EventRemovePtr& event)
176 EventRequestReceiver<EventRemove>::PostRequest(event);
179 void Manager::find(const EventFindPtr& event)
181 EventRequestReceiver<EventFind>::PostRequest(event);
184 void Manager::find(const IPathPtr& path,
185 const FiltersMap& filters,
187 const EventFindPtr& event)
190 Assert(path && "path is NULL");
192 DIR* dir = opendir(path->getFullPath().c_str());
198 struct dirent* entry = NULL;
199 while ((entry = readdir(dir))) {
200 if (event && event->checkCancelled()) {
203 if (!strncmp(entry->d_name, ".",
204 1) || !strncmp(entry->d_name, "..", 2)) {
207 IPathPtr childPath = *path + entry->d_name;
209 memset(&info, 0, sizeof(struct stat));
210 if (lstat(childPath->getFullPath().c_str(), &info) == 0) {
211 if (matchFilters(entry->d_name, info, filters)) {
212 result.push_back(Node::resolve(childPath));
214 if (S_ISDIR(info.st_mode)) {
215 find(childPath, filters, result, event);
221 ThrowMsg(Commons::PlatformException,
222 "Error while reading directory.");
225 if (closedir(dir) != 0) {
226 ThrowMsg(Commons::PlatformException,
227 "Could not close platform node.");
230 Catch(Commons::Exception) {
234 void Manager::copyElement(
235 const std::string &src, const std::string &dest, bool recursive) const
237 LogDebug("Copying src: " << src << " to: " << dest);
240 if (EINA_TRUE != ecore_file_is_dir(src.c_str())) {
241 if (EINA_TRUE != ecore_file_cp(src.c_str(), dest.c_str())) {
242 ThrowMsg(Commons::PlatformException, "Failed to copy file");
246 //element is a directory -> create it:
247 if (EINA_TRUE != ecore_file_mkdir(dest.c_str())) {
248 LogDebug("Failed to create destination directory");
249 ThrowMsg(Commons::PlatformException, "Failed to copy directory");
251 //copy all elements of directory:
253 Eina_List* list = ecore_file_ls(src.c_str());
255 EINA_LIST_FREE(list, data)
259 copyElement((src + '/' + static_cast<char*>(data)).c_str(),
260 (dest + '/' + static_cast<char*>(data)).c_str());
262 Catch(Commons::PlatformException)
264 //remove rest of the list
265 EINA_LIST_FREE(list, data)
269 ReThrowMsg(Commons::PlatformException, "Failed to copy element");
277 bool Manager::access(const IPathPtr& path,
278 int accessType) const
281 if (accessType & AT_EXISTS) { amode |= F_OK; }
282 if (accessType & AT_READ) { amode |= R_OK; }
283 if (accessType & AT_WRITE) { amode |= W_OK; }
284 if (accessType & AT_EXEC) { amode |= X_OK; }
285 return (::access(path->getFullPath().c_str(), amode) == 0);
288 bool Manager::matchFilters(const std::string& name,
289 const struct stat& info,
290 const FiltersMap& filters)
292 FiltersMap::const_iterator it = filters.begin();
293 for (; it != filters.end(); ++it) {
294 if (it->first == FF_NAME) {
295 if (!pcrecpp::RE(it->second).PartialMatch(name)) { return false; }
296 } else if (it->first == FF_SIZE) {
298 std::stringstream ss(it->second);
301 (size != static_cast<size_t>(info.st_size))) { return false; }
302 } else if (it->first == FF_CREATED) {
304 std::stringstream ss(it->second);
306 if (!ss || (created != info.st_ctime)) { return false; }
307 } else if (it->first == FF_MODIFIED) {
308 std::time_t modified;
309 std::stringstream ss(it->second);
311 if (!ss || (modified != info.st_mtime)) { return false; }
317 void Manager::OnRequestReceived(const EventResolvePtr& event)
320 event->setResult(Node::resolve(event->getPath()));
322 catch (const Commons::PlatformException& ex) {
323 LogError("Exception: " << ex.GetMessage());
324 event->setExceptionCode(Commons::ExceptionCodes::PlatformException);
326 event->setCancelAllowed(true);
329 void Manager::OnRequestReceived(const EventCopyPtr& event)
332 INodePtr srcNode = Node::resolve(event->getSource());
334 switch (srcNode->getType()) {
336 requiredAccess = AT_EXEC;
339 requiredAccess = AT_READ;
342 if (!access(srcNode->getPath(), requiredAccess)) {
343 ThrowMsg(Commons::SecurityException,
344 "Not enough permissions to copy source node.");
347 IPathPtr src = event->getSource();
348 IPathPtr dest = event->getDestination();
351 if (!dest->isAbsolute()) {
352 dest = src->getPath() + *dest;
356 ThrowMsg(Commons::PlatformException,
357 "Destination is same as source: " <<
358 srcNode->getPath()->getFullPath());
363 parent = Node::resolve(IPath::create(dest->getPath()));
365 Catch(Commons::PlatformException) {
366 ReThrowMsg(Commons::PlatformException,
367 "Could not get destination's parent node.");
370 if (parent->getType() != NT_DIRECTORY) {
371 ThrowMsg(Commons::PlatformException,
372 "Destination's parent node is not directory.");
375 if (!access(parent->getPath(), AT_WRITE)) {
376 ThrowMsg(Commons::SecurityException,
377 "Not enough permissions to copy source node to destination.");
380 std::string realSrc = src->getFullPath();
381 std::string realDest = dest->getFullPath();
385 memset(&info, 0, sizeof(struct stat));
386 int status = lstat(realDest.c_str(), &info);
387 if ((status != 0) && (errno != ENOENT)) {
388 ThrowMsg(Commons::PlatformException,
389 "No access to platform destination node.");
393 //no owerwrite flag setted -> exception
394 if ((event->getOptions() & OPT_OVERWRITE) == 0) {
395 ThrowMsg(Commons::PlatformException, "Overwrite is not set.");
398 if (event->checkCancelled()) {
399 //file is not copied yet, so we can cancel it now.
400 event->setCancelAllowed(true);
404 //destination exist. Need to be removed
406 INodePtr node = Node::resolve(event->getDestination());
407 node->remove(event->getOptions());
409 Catch(Commons::PlatformException) {
410 LogError("Exception: " << _rethrown_exception.GetMessage());
411 event->setExceptionCode(
412 Commons::ExceptionCodes::PlatformException);
414 Catch(Commons::SecurityException) {
415 event->setExceptionCode(
416 Commons::ExceptionCodes::SecurityException);
419 //Destination is not exist. Start copy now.
420 copyElement(realSrc, realDest);
422 event->setResult(Node::resolve(dest));
424 catch (const Commons::PlatformException& ex) {
425 LogError("Exception: " << ex.GetMessage());
426 event->setExceptionCode(Commons::ExceptionCodes::PlatformException);
428 catch (const Commons::SecurityException& ex) {
429 LogError("Exception: " << ex.GetMessage());
430 event->setExceptionCode(Commons::ExceptionCodes::SecurityException);
432 //file is copied already so we don't allow cancelling anymore.
433 event->setCancelAllowed(false);
436 void Manager::OnRequestReceived(const EventMovePtr& event)
439 IPathPtr src = event->getSource();
440 IPathPtr dest = event->getDestination();
442 INodePtr srcNode = Node::resolve(src);
443 if (!access(srcNode->getParent()->getPath(), AT_WRITE)) {
444 ThrowMsg(Commons::SecurityException,
445 "Not enough permissions to move source node.");
449 if (!dest->isAbsolute()) {
450 dest = src->getPath() + *dest;
454 ThrowMsg(Commons::PlatformException,
455 "Destination is same as source: " <<
456 srcNode->getPath()->getFullPath());
461 parent = Node::resolve(IPath::create(dest->getPath()));
463 Catch(Commons::PlatformException) {
464 ReThrowMsg(Commons::PlatformException,
465 "Could not get destination's parent node.");
468 if (parent->getType() != NT_DIRECTORY) {
469 ThrowMsg(Commons::PlatformException,
470 "Destination's parent node is not directory.");
473 if (!access(parent->getPath(), AT_WRITE)) {
474 ThrowMsg(Commons::SecurityException,
475 "Not enough permissions to move source node to destination.");
480 memset(&info, 0, sizeof(info));
481 int status = lstat(dest->getFullPath().c_str(), &info);
482 if ((status != 0) && (errno != ENOENT)) {
483 ThrowMsg(Commons::PlatformException,
484 "No access to platform destination node.");
487 if ((0 == (event->getOptions() & OPT_OVERWRITE)) && (0 == status)) {
488 ThrowMsg(Commons::PlatformException, "Overwrite is not set.");
491 if (event->checkCancelled()) {
492 //file is not moved yet, so we can cancel it now.
493 event->setCancelAllowed(true);
498 if (0 != ::rename(src->getFullPath().c_str(),
499 dest->getFullPath().c_str()))
507 //destination exist. Need to be removed
509 INodePtr node = Node::resolve(
510 event->getDestination());
511 node->remove(event->getOptions());
513 Catch(Commons::PlatformException) {
514 LogError("Exception while removing dest directory");
515 event->setExceptionCode(
516 Commons::ExceptionCodes::PlatformException);
518 Catch(Commons::SecurityException) {
519 event->setExceptionCode(
520 Commons::ExceptionCodes::SecurityException);
524 copyElement(src->getFullPath(),
525 dest->getFullPath());
526 //remove source files
528 INodePtr node = Node::resolve(event->getSource());
529 node->remove(event->getOptions());
531 Catch(Commons::Exception) {
532 LogError("Exception: "
533 << _rethrown_exception.GetMessage());
538 ThrowMsg(Commons::PlatformException,
539 "Error on rename: " << DPL::GetErrnoString(error));
544 event->setResult(Node::resolve(dest));
546 catch (const Commons::PlatformException& ex) {
547 LogError("Exception: " << ex.GetMessage());
548 event->setExceptionCode(Commons::ExceptionCodes::PlatformException);
550 catch (const Commons::SecurityException& ex) {
551 LogError("Exception: " << ex.GetMessage());
552 event->setExceptionCode(Commons::ExceptionCodes::SecurityException);
554 event->setCancelAllowed(false);
557 void Manager::OnRequestReceived(const EventRemovePtr& event)
559 if (!event->checkCancelled()) {
561 INodePtr node = Node::resolve(event->getPath());
562 node->remove(event->getOptions());
564 Catch(Commons::PlatformException) {
565 LogError("Exception: " << _rethrown_exception.GetMessage());
566 event->setExceptionCode(Commons::ExceptionCodes::PlatformException);
568 Catch(Commons::SecurityException) {
569 event->setExceptionCode(Commons::ExceptionCodes::SecurityException);
571 event->setCancelAllowed(false);
573 event->setCancelAllowed(true);
577 void Manager::OnRequestReceived(const EventFindPtr& event)
581 find(event->getPath(), event->getFilters(), result, event);
582 event->setResult(result);
584 catch (const Commons::Exception& ex) {
585 LogError("Exception: " << ex.GetMessage());
586 event->setExceptionCode(Commons::ExceptionCodes::PlatformException);
588 event->setCancelAllowed(true);
593 m_locations[LT_ROOT] = IPath::create(PATH_ROOT);
594 m_locations[LT_SDCARD] = IPath::create(PATH_SDCARD);
595 setupLocation(LT_DOWNLOADS, PATH_DOWNLOADS);
596 setupLocation(LT_DOCUMENTS, PATH_DOCUMENTS);
597 setupLocation(LT_SOUNDS, PATH_SOUNDS);
598 setupLocation(LT_IMAGES, PATH_IMAGES);
599 setupLocation(LT_VIDEOS, PATH_VIDEOS);
604 void Manager::setupLocation(LocationType location,
607 if (!nodeExists(path)) {
609 makePath(path, 0755);
611 catch (const Commons::PlatformException& ex) {
612 LogError("Exception: " << ex.DumpToString());
616 m_locations[location] = IPath::create(path);