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 <dpl/log/log.h>
27 #include <dpl/scoped_ptr.h>
28 #include <dpl/errno_string.h>
29 #include <Commons/Exception.h>
30 #include <Commons/Regex.h>
31 #include <Filesystem/PathUtils.h>
34 #include "CopyCommand.h"
35 #include "MoveCommand.h"
36 #include "RemoveCommand.h"
40 const char* PATH_ROOT = "/opt/media";
41 const char* PATH_DOWNLOADS = "/opt/media/Downloads";
42 const char* PATH_DOCUMENTS = "/opt/media/Documents";
43 const char* PATH_SOUNDS = "/opt/media/Music";
44 const char* PATH_IMAGES = "/opt/media/Images";
45 const char* PATH_VIDEOS = "/opt/media/Videos";
46 const char* PATH_SDCARD = "/opt/storage/sdcard";
49 namespace WrtDeviceApis {
50 namespace Filesystem {
54 Manager::Locations Manager::m_locations;
55 const std::size_t Manager::m_maxPathLength = 256;
56 NodeList Manager::m_openedNodes;
58 bool Manager::fileExists(const std::string &file)
62 memset(&info, 0, sizeof(struct stat));
63 int status = lstat(file.c_str(), &info);
66 } else if (errno == ENOENT) {
69 ThrowMsg(Commons::PlatformException, "Cannot stat file.");
72 void Manager::addOpenedNode(const INodePtr& node)
74 NodeListIterator it = m_openedNodes.begin();
75 for (; it != m_openedNodes.end(); ++it) {
76 if (node.Get() == (*it).Get()) {
77 //node is added already
81 m_openedNodes.push_back(node);
84 void Manager::removeOpenedNode(const INodePtr& node)
86 NodeListIterator it = m_openedNodes.begin();
87 for (; it != m_openedNodes.end(); ++it) {
88 if ((*it).Get() == node.Get()) {
89 m_openedNodes.erase(it);
95 bool Manager::checkIfOpened(const IPathPtr& path) const
97 NodeListIterator it = m_openedNodes.begin();
98 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 DIR* dir = opendir(path->getFullPath().c_str());
196 struct dirent* entry = NULL;
197 while ((entry = readdir(dir))) {
198 if (event && event->checkCancelled()) {
201 if (!strncmp(entry->d_name, ".",
202 1) || !strncmp(entry->d_name, "..", 2)) {
205 IPathPtr childPath = *path + entry->d_name;
207 memset(&info, 0, sizeof(struct stat));
208 if (lstat(childPath->getFullPath().c_str(), &info) == 0) {
209 if (matchFilters(entry->d_name, info, filters)) {
210 result.push_back(Node::resolve(childPath));
212 if (S_ISDIR(info.st_mode)) {
213 find(childPath, filters, result, event);
219 ThrowMsg(Commons::PlatformException,
220 "Error while reading directory.");
223 if (closedir(dir) != 0) {
224 ThrowMsg(Commons::PlatformException,
225 "Could not close platform node.");
228 Catch(Commons::Exception) {
232 bool Manager::access(const IPathPtr& path,
233 int accessType) const
236 if (accessType & AT_EXISTS) { amode |= F_OK; }
237 if (accessType & AT_READ) { amode |= R_OK; }
238 if (accessType & AT_WRITE) { amode |= W_OK; }
239 if (accessType & AT_EXEC) { amode |= X_OK; }
240 return (::access(path->getFullPath().c_str(), amode) == 0);
243 bool Manager::matchFilters(const std::string& name,
244 const struct stat& info,
245 const FiltersMap& filters)
247 FiltersMap::const_iterator it = filters.begin();
248 for (; it != filters.end(); ++it) {
249 if (it->first == FF_NAME) {
250 if (!pcrecpp::RE(it->second).PartialMatch(name)) { return false; }
251 } else if (it->first == FF_SIZE) {
253 std::stringstream ss(it->second);
256 (size != static_cast<size_t>(info.st_size))) { return false; }
257 } else if (it->first == FF_CREATED) {
259 std::stringstream ss(it->second);
261 if (!ss || (created != info.st_ctime)) { return false; }
262 } else if (it->first == FF_MODIFIED) {
263 std::time_t modified;
264 std::stringstream ss(it->second);
266 if (!ss || (modified != info.st_mtime)) { return false; }
272 void Manager::OnRequestReceived(const EventResolvePtr& event)
275 event->setResult(Node::resolve(event->getPath()));
277 catch (const Commons::PlatformException& ex) {
278 LogError("Exception: " << ex.GetMessage());
279 event->setExceptionCode(Commons::ExceptionCodes::PlatformException);
281 event->setCancelAllowed(true);
284 void Manager::OnRequestReceived(const EventCopyPtr& event)
287 INodePtr srcNode = Node::resolve(event->getSource());
288 if ((srcNode->getMode() & PERM_READ) == 0) {
289 ThrowMsg(Commons::SecurityException,
290 "Not enough permissions to read source node.");
293 IPathPtr src = event->getSource();
294 IPathPtr dest = event->getDestination();
295 if (!dest->isAbsolute()) {
296 dest = src->getPath() + *dest;
300 ThrowMsg(Commons::PlatformException,
301 "Destination is same as source.");
306 parent = Node::resolve(IPath::create(dest->getPath()));
308 Catch(Commons::PlatformException) {
309 ReThrowMsg(Commons::PlatformException,
310 "Could not get destination's parent node.");
313 if (parent->getType() != NT_DIRECTORY) {
314 ThrowMsg(Commons::PlatformException,
315 "Destination's parent node is not directory.");
318 std::string realSrc = src->getFullPath();
319 std::string realDest = dest->getFullPath();
323 memset(&info, 0, sizeof(struct stat));
324 int status = lstat(realDest.c_str(), &info);
325 if ((status != 0) && (errno != ENOENT)) {
326 ThrowMsg(Commons::PlatformException,
327 "No access to platform destination node.");
330 if (((event->getOptions() & OPT_OVERWRITE) == 0) && (status == 0)) {
331 ThrowMsg(Commons::PlatformException, "Overwrite is not set.");
334 if (event->checkCancelled()) {
335 //file is not copied yet, so we can cancel it now.
336 event->setCancelAllowed(true);
340 if (event->getOptions() & OPT_OVERWRITE) {
341 DPL::ScopedPtr<RemoveCommand> remove(new RemoveCommand(dest));
342 remove->setRecursive(true);
343 remove->setForce(true);
344 System::run(remove.Get());
347 DPL::ScopedPtr<CopyCommand> copy(new CopyCommand(src, dest));
348 copy->setRecursive(true);
349 System::run(copy.Get());
351 event->setResult(Node::resolve(dest));
353 Catch(Commons::PlatformException) {
354 event->setExceptionCode(Commons::ExceptionCodes::PlatformException);
356 Catch(Commons::SecurityException) {
357 event->setExceptionCode(Commons::ExceptionCodes::SecurityException);
359 //file is copied already so we don't allow cancelling anymore.
360 event->setCancelAllowed(false);
363 void Manager::OnRequestReceived(const EventMovePtr& event)
366 IPathPtr src = event->getSource();
367 IPathPtr dest = event->getDestination();
369 INodePtr srcNode = Node::resolve(src);
370 if ((srcNode->getMode() & PERM_WRITE) == 0)
372 ThrowMsg(Commons::SecurityException,
373 "Not enough permissions to move source node.");
376 if (!dest->isAbsolute()) {
377 dest = src->getPath() + *dest;
381 ThrowMsg(Commons::PlatformException,
382 "Destination is same as source.");
387 parent = Node::resolve(IPath::create(dest->getPath()));
389 Catch(Commons::PlatformException) {
390 ReThrowMsg(Commons::PlatformException,
391 "Could not get destination's parent node.");
394 if (parent->getType() != NT_DIRECTORY) {
395 ThrowMsg(Commons::PlatformException,
396 "Destination's parent node is not directory.");
401 memset(&info, 0, sizeof(info));
402 int status = lstat(dest->getFullPath().c_str(), &info);
403 if ((status != 0) && (errno != ENOENT)) {
404 ThrowMsg(Commons::PlatformException,
405 "No access to platform destination node.");
408 if ((0 == (event->getOptions() & OPT_OVERWRITE)) && (0 == status)) {
409 ThrowMsg(Commons::PlatformException, "Overwrite is not set.");
412 if (event->checkCancelled()) {
413 //file is not moved yet, so we can cancel it now.
414 event->setCancelAllowed(true);
419 if (0 != ::rename(src->getFullPath().c_str(),
420 dest->getFullPath().c_str()))
427 if ((srcNode->getMode() & PERM_READ) == 0)
429 ThrowMsg(Commons::SecurityException,
430 "Not enough permissions to move source node.");
432 DPL::ScopedPtr<MoveCommand>
433 move(new MoveCommand(src, dest));
434 move->setForce(event->getOptions() & OPT_OVERWRITE);
435 System::run(move.Get());
439 ThrowMsg(Commons::PlatformException,
440 "Error on rename: " << DPL::GetErrnoString(error));
445 event->setResult(Node::resolve(dest));
447 catch (const Commons::PlatformException& ex) {
448 LogError("Exception: " << ex.GetMessage());
449 event->setExceptionCode(Commons::ExceptionCodes::PlatformException);
451 catch (const Commons::SecurityException& ex) {
452 LogError("Exception: " << ex.GetMessage());
453 event->setExceptionCode(Commons::ExceptionCodes::SecurityException);
455 event->setCancelAllowed(false);
458 void Manager::OnRequestReceived(const EventRemovePtr& event)
460 if (!event->checkCancelled()) {
462 INodePtr node = Node::resolve(event->getPath());
463 node->remove(event->getOptions());
465 Catch(Commons::PlatformException) {
466 LogError("Exception: " << _rethrown_exception.GetMessage());
467 event->setExceptionCode(Commons::ExceptionCodes::PlatformException);
469 Catch(Commons::SecurityException) {
470 event->setExceptionCode(Commons::ExceptionCodes::SecurityException);
472 event->setCancelAllowed(false);
474 event->setCancelAllowed(true);
478 void Manager::OnRequestReceived(const EventFindPtr& event)
482 find(event->getPath(), event->getFilters(), result, event);
483 event->setResult(result);
485 catch (const Commons::Exception& ex) {
486 LogError("Exception: " << ex.GetMessage());
487 event->setExceptionCode(Commons::ExceptionCodes::PlatformException);
489 event->setCancelAllowed(true);
494 m_locations[LT_ROOT] = IPath::create(PATH_ROOT);
495 m_locations[LT_SDCARD] = IPath::create(PATH_SDCARD);
496 setupLocation(LT_DOWNLOADS, PATH_DOWNLOADS);
497 setupLocation(LT_DOCUMENTS, PATH_DOCUMENTS);
498 setupLocation(LT_SOUNDS, PATH_SOUNDS);
499 setupLocation(LT_IMAGES, PATH_IMAGES);
500 setupLocation(LT_VIDEOS, PATH_VIDEOS);
505 void Manager::setupLocation(LocationType location,
508 if (!nodeExists(path)) {
510 makePath(path, 0755);
512 catch (const Commons::PlatformException& ex) {
513 LogError("Exception: " << ex.DumpToString());
517 m_locations[location] = IPath::create(path);