2 // Tizen Web Device API
3 // Copyright (c) 2012 Samsung Electronics Co., Ltd.
5 // Licensed under the Apache License, Version 2.0 (the License);
6 // you may not use this file except in compliance with the License.
7 // You may obtain a copy of the License at
9 // http://www.apache.org/licenses/LICENSE-2.0
11 // Unless required by applicable law or agreed to in writing, software
12 // distributed under the License is distributed on an "AS IS" BASIS,
13 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 // See the License for the specific language governing permissions and
15 // limitations under the License.
19 #include "JSFilesystemManager.h"
20 #include <Commons/Exception.h>
21 #include "EventResolve.h"
24 #include "EventGetStorage.h"
25 #include "EventListStorages.h"
26 #include "EventStorageStateChanged.h"
27 #include <CommonsJavaScript/JSCallbackManager.h>
28 #include <CommonsJavaScript/Utils.h>
29 #include <CommonsJavaScript/JSUtils.h>
30 #include <CommonsJavaScript/Validator.h>
31 #include <JSWebAPIErrorFactory.h>
32 #include <SecurityExceptions.h>
33 #include <Commons/WrtAccess/WrtAccess.h>
34 #include <WidgetDB/WidgetDBMgr.h>
35 #include <WidgetDB/IWidgetDB.h>
36 #include <TimeTracer.h>
37 #include <ArgumentValidator.h>
38 #include <JSWebAPIException.h>
42 #include "FilesystemUtils.h"
43 #include "Converter.h"
44 #include "EventGetNodeData.h"
45 #include "plugin_config.h"
46 #include "StorageStaticController.h"
47 #include "ResponseDispatcher.h"
48 #include "FilesystemAsyncCallbackManager.h"
49 #include "FilesystemListenerManager.h"
52 using namespace WrtDeviceApis::Commons;
53 using namespace WrtDeviceApis::CommonsJavaScript;
54 using namespace DeviceAPI::Common;
55 using namespace WrtDeviceApis;
60 const char* PLUGIN_NAME = "FileSystemManager";
61 const char* PROPERTY_MAXPATHLENGTH = "maxPathLength";
63 JSValueRef getFunctionOrNull(JSContextRef ctx, JSValueRef arg)
65 if (Validator(ctx).isCallback(arg)) {
67 } else if (!JSValueIsNull(ctx, arg) && !JSValueIsUndefined(ctx, arg)) {
68 ThrowMsg(ConversionException, "Not a function nor JS null.");
74 JSValueRef getFunction(JSContextRef ctx, JSValueRef arg)
76 if (Validator(ctx).isCallback(arg)) {
79 ThrowMsg(ConversionException, "JS null passed as function.");
88 namespace Filesystem {
90 JSClassRef JSFilesystemManager::m_classRef = 0;
92 JSClassDefinition JSFilesystemManager::m_classInfo = {
94 kJSClassAttributeNone,
112 JSStaticValue JSFilesystemManager::m_properties[] = {
113 { PROPERTY_MAXPATHLENGTH, getMaxPathLength, NULL, kJSPropertyAttributeReadOnly },
117 JSStaticFunction JSFilesystemManager::m_functions[] = {
118 { "resolve", JSFilesystemManager::resolve, kJSPropertyAttributeNone },
119 { "getStorage", JSFilesystemManager::getStorage, kJSPropertyAttributeNone },
120 { "listStorages", JSFilesystemManager::getStorageList, kJSPropertyAttributeNone },
121 { "addStorageStateChangeListener", JSFilesystemManager::addStorageStateListener, kJSPropertyAttributeNone },
122 { "removeStorageStateChangeListener", JSFilesystemManager::removeStorageStateListener, kJSPropertyAttributeNone },
126 const JSClassRef DLL_EXPORT JSFilesystemManager::getClassRef()
129 m_classRef = JSClassCreate(&m_classInfo);
134 const JSClassDefinition* JSFilesystemManager::getClassInfo()
139 void JSFilesystemManager::initialize(JSContextRef context,
142 PrivateObject* privateObject = new PrivateObject(context);
143 if (!JSObjectSetPrivate(object, privateObject)) {
144 delete privateObject;
147 int widgetId = WrtAccessSingleton::Instance().getWidgetId();
148 WidgetDB::Api::IWidgetDBPtr widgetDB = WidgetDB::Api::getWidgetDB(widgetId);
150 LoggerD(widgetDB->getWidgetInstallationPath());
151 std::string wgtpackage = "wgt-package";
152 std::string wgtprivate = "wgt-private";
153 std::string wgtprivatetemp = "wgt-private-tmp";
155 IManager::getInstance().addWidgetStorage(wgtpackage, widgetDB->getWidgetInstallationPath());
156 IManager::getInstance().addWidgetStorage(wgtprivate, widgetDB->getWidgetPersistentStoragePath());
157 IManager::getInstance().addWidgetStorage(wgtprivatetemp, widgetDB->getWidgetTemporaryStoragePath());
162 void JSFilesystemManager::finalize(JSObjectRef object)
164 PrivateObject* privateObject = static_cast<PrivateObject*>(JSObjectGetPrivate(object));
166 JSObjectSetPrivate(object, NULL);
167 delete privateObject;
171 JSValueRef JSFilesystemManager::getMaxPathLength(JSContextRef context,
173 JSStringRef propertyName,
174 JSValueRef* exception)
176 ConverterPtr converter = ConverterFactory::getConverter(context);
178 return converter->toJSValueRef(IManager::getInstance().getMaxPathLength());
179 } catch (const WrtDeviceApis::Commons::ConversionException& ex) {
180 return JSWebAPIErrorFactory::postException(context, exception, JSWebAPIErrorFactory::IO_ERROR, "IO error");
184 JSValueRef JSFilesystemManager::getStorage(JSContextRef context,
186 JSObjectRef thisObject,
188 const JSValueRef argv[],
189 JSValueRef* exception)
191 TIME_TRACER_ITEM_BEGIN(__FUNCTION__, 0);
192 PrivateObject* privateObject = static_cast<PrivateObject*>(JSObjectGetPrivate(thisObject));
193 if (!privateObject) {
194 return JSValueMakeUndefined(context);
197 AceSecurityStatus status = FILESYSTEM_CHECK_ACCESS(FILESYSTEM_FUNCTION_API_GET_STORAGE);
198 TIZEN_SYNC_ACCESS_HANDLER(status, context, exception);
200 // argument validation with new validator
202 ArgumentValidator validator(context, argc, argv);
203 validator.toString(0, false);
204 validator.toFunction(1, false);
205 validator.toFunction(2, true);
207 catch (const BasePlatformException &err) {
208 return JSWebAPIErrorFactory::postException(context, exception, err);
210 DeviceAPI::Common::UnknownException err("");
211 return JSWebAPIErrorFactory::postException(context, exception, err);
215 return JSWebAPIErrorFactory::postException(context, exception, JSWebAPIErrorFactory::TYPE_MISMATCH_ERROR, "Type missmatch error");
221 JSContextRef globalContext = privateObject->getContext();
222 ConverterPtr converter = ConverterFactory::getConverter(globalContext);
223 JSCallbackManagerPtr cbm = JSCallbackManager::createObject(globalContext);
227 JSValueRef onSuccess = getFunction(globalContext, argv[1]);
228 JSValueRef onError = NULL;
231 onError = getFunctionOrNull(globalContext, argv[2]);
234 cbm->setOnSuccess(onSuccess);
235 cbm->setOnError(onError);
237 EventGetStoragePtr event(new EventGetStorage());
238 event->setLabel(converter->toString(argv[0]));
239 event->setForAsynchronousCall(&ResponseDispatcher::getInstance());
240 event->setPrivateData(DPL::StaticPointerCast<WrtDeviceApis::Commons::IEventPrivateData > (cbm));
241 FilesystemAsyncCallbackManagerSingleton::Instance().registerCallbackManager(cbm, globalContext);
243 IManager::getInstance().getStorage(event);
245 } catch(const WrtDeviceApis::Commons::ConversionException& ex) {
246 return JSWebAPIErrorFactory::postException(context, exception, JSWebAPIErrorFactory::TYPE_MISMATCH_ERROR, ex.GetMessage());
247 } catch (const WrtDeviceApis::Commons::UnsupportedException& ex) {
248 return JSWebAPIErrorFactory::postException(context, exception, JSWebAPIErrorFactory::NOT_SUPPORTED_ERROR, ex.GetMessage());
249 } catch(const WrtDeviceApis::Commons::InvalidArgumentException& ex) {
250 cbm->callOnError(JSWebAPIErrorFactory::makeErrorObject(context, JSWebAPIErrorFactory::INVALID_VALUES_ERROR, ex.GetMessage()));
251 } catch(const WrtDeviceApis::Commons::Exception& ex) {
252 cbm->callOnError(JSWebAPIErrorFactory::makeErrorObject(context, JSWebAPIErrorFactory::UNKNOWN_ERROR, ex.GetMessage()));
254 TIME_TRACER_ITEM_END(__FUNCTION__, 0);
255 return JSValueMakeUndefined(context);
258 JSValueRef JSFilesystemManager::getStorageList(JSContextRef context,
260 JSObjectRef thisObject,
262 const JSValueRef argv[],
263 JSValueRef* exception)
265 TIME_TRACER_ITEM_BEGIN(__FUNCTION__, 0);
266 PrivateObject* privateObject = static_cast<PrivateObject*>(JSObjectGetPrivate(thisObject));
267 if (!privateObject) {
268 return JSValueMakeUndefined(context);
271 AceSecurityStatus status = FILESYSTEM_CHECK_ACCESS(FILESYSTEM_FUNCTION_API_LIST_STORAGE);
272 TIZEN_SYNC_ACCESS_HANDLER(status, context, exception);
274 // argument validation with new validator
276 ArgumentValidator validator(context, argc, argv);
277 validator.toFunction(0, false);
278 validator.toFunction(1, true);
280 catch (const BasePlatformException &err) {
281 return JSWebAPIErrorFactory::postException(context, exception, err);
283 DeviceAPI::Common::UnknownException err("");
284 return JSWebAPIErrorFactory::postException(context, exception, err);
288 return JSWebAPIErrorFactory::postException(context, exception, JSWebAPIErrorFactory::TYPE_MISMATCH_ERROR, "Type missmatch error");
292 JSContextRef globalContext = privateObject->getContext();
293 ConverterPtr converter = ConverterFactory::getConverter(globalContext);
294 JSCallbackManagerPtr cbm = JSCallbackManager::createObject(globalContext);
298 JSValueRef onSuccess = getFunction(globalContext, argv[0]);
299 JSValueRef onError = NULL;
302 onError = getFunctionOrNull(globalContext, argv[1]);
305 cbm->setOnSuccess(onSuccess);
306 cbm->setOnError(onError);
307 cbm->setObject(thisObject);
309 EventListStoragesPtr event(new EventListStorages());
310 event->setForAsynchronousCall(&ResponseDispatcher::getInstance());
311 event->setPrivateData(DPL::StaticPointerCast<WrtDeviceApis::Commons::IEventPrivateData > (cbm));
312 FilesystemAsyncCallbackManagerSingleton::Instance().registerCallbackManager(cbm, globalContext);
315 IManager::getInstance().listStorages(event);
317 } catch(const WrtDeviceApis::Commons::ConversionException& ex) {
318 return JSWebAPIErrorFactory::postException(context, exception, JSWebAPIErrorFactory::TYPE_MISMATCH_ERROR, ex.GetMessage());
319 } catch (const WrtDeviceApis::Commons::UnsupportedException& ex) {
320 return JSWebAPIErrorFactory::postException(context, exception, JSWebAPIErrorFactory::NOT_SUPPORTED_ERROR, ex.GetMessage());
321 } catch(const WrtDeviceApis::Commons::InvalidArgumentException& ex) {
322 cbm->callOnError(JSWebAPIErrorFactory::makeErrorObject(context, JSWebAPIErrorFactory::INVALID_VALUES_ERROR, ex.GetMessage()));
323 } catch(const WrtDeviceApis::Commons::Exception& ex) {
324 cbm->callOnError(JSWebAPIErrorFactory::makeErrorObject(context, JSWebAPIErrorFactory::UNKNOWN_ERROR, ex.GetMessage()));
326 TIME_TRACER_ITEM_END(__FUNCTION__, 0);
327 return JSValueMakeUndefined(context);
330 JSValueRef JSFilesystemManager::addStorageStateListener(JSContextRef context,
332 JSObjectRef thisObject,
334 const JSValueRef argv[],
335 JSValueRef* exception)
337 TIME_TRACER_ITEM_BEGIN(__FUNCTION__, 0);
338 PrivateObject* privateObject = static_cast<PrivateObject*>(JSObjectGetPrivate(thisObject));
339 if (!privateObject) {
340 return JSValueMakeUndefined(context);
343 AceSecurityStatus status = FILESYSTEM_CHECK_ACCESS(FILESYSTEM_FUNCTION_API_ADD_STORAGE_LISTENER);
344 TIZEN_SYNC_ACCESS_HANDLER(status, context, exception);
347 // argument validation with new validator
349 ArgumentValidator validator(context, argc, argv);
350 validator.toFunction(0, false);
351 validator.toFunction(1, true);
353 catch (const BasePlatformException &err) {
354 LogDebug("Exception");
355 return JSWebAPIErrorFactory::postException(context, exception, err);
357 DeviceAPI::Common::UnknownException err("");
358 return JSWebAPIErrorFactory::postException(context, exception, err);
363 return JSWebAPIErrorFactory::postException(context, exception, JSWebAPIErrorFactory::TYPE_MISMATCH_ERROR, "TYPE_MISMATCH_ERROR");
367 JSContextRef globalContext = privateObject->getContext();
368 JSCallbackManagerPtr cbm = JSCallbackManager::createObject(globalContext);
369 ConverterPtr converter = ConverterFactory::getConverter(globalContext);
372 JSValueRef onSuccess = getFunction(globalContext, argv[0]);
373 JSValueRef onError = NULL;
375 onError = getFunctionOrNull(globalContext, argv[1]);
378 cbm->setOnSuccess(onSuccess);
379 cbm->setOnError(onError);
381 EventStorageStateChangedEmitterPtr emitter(new EventStorageStateChangedEmitter);
382 emitter->setListener(&StorageStaticController::getInstance());
383 emitter->setEventPrivateData(DPL::StaticPointerCast<EventStorageStateChanged::PrivateDataType>(cbm));
384 long id = IManager::getInstance().addStorageStateChangeListener(emitter);
386 FilesystemListenerCancellerPtr canceller = FilesystemListenerCancellerPtr(new FilesystemListenerCanceller(globalContext, thisObject, id));
387 IListenerItemPtr listenerItem = DPL::StaticPointerCast<IListenerItem>(canceller);
388 FilesystemListenerManagerSingleton::Instance().registerListener(listenerItem, globalContext);
390 return converter->toJSValueRefLong(id);
391 } catch(const WrtDeviceApis::Commons::ConversionException& ex) {
392 return JSWebAPIErrorFactory::postException(context, exception, JSWebAPIErrorFactory::TYPE_MISMATCH_ERROR, ex.GetMessage());
393 } catch (const WrtDeviceApis::Commons::UnsupportedException& ex) {
394 return JSWebAPIErrorFactory::postException(context, exception, JSWebAPIErrorFactory::NOT_SUPPORTED_ERROR, ex.GetMessage());
395 } catch(const WrtDeviceApis::Commons::InvalidArgumentException& ex) {
396 cbm->callOnError(JSWebAPIErrorFactory::makeErrorObject(context, JSWebAPIErrorFactory::INVALID_VALUES_ERROR, ex.GetMessage()));
397 } catch(const WrtDeviceApis::Commons::Exception& ex) {
398 cbm->callOnError(JSWebAPIErrorFactory::makeErrorObject(context, JSWebAPIErrorFactory::UNKNOWN_ERROR, ex.GetMessage()));
400 TIME_TRACER_ITEM_END(__FUNCTION__, 0);
401 return JSValueMakeUndefined(context);
404 JSValueRef JSFilesystemManager::removeStorageStateListener(JSContextRef context,
406 JSObjectRef thisObject,
408 const JSValueRef argv[],
409 JSValueRef* exception)
411 TIME_TRACER_ITEM_BEGIN(__FUNCTION__, 0);
412 PrivateObject* privateObject = static_cast<PrivateObject*>(JSObjectGetPrivate(thisObject));
413 if (!privateObject) {
414 return JSValueMakeUndefined(context);
417 AceSecurityStatus status = FILESYSTEM_CHECK_ACCESS(FILESYSTEM_FUNCTION_API_REMOVE_STORAGE_LISTENER);
418 TIZEN_SYNC_ACCESS_HANDLER(status, context, exception);
422 // argument validation with new validator
424 ArgumentValidator validator(context, argc, argv);
425 validator.toLong(0, false);
427 catch (const BasePlatformException &err) {
428 return JSWebAPIErrorFactory::postException(context, exception, err);
430 DeviceAPI::Common::UnknownException err("");
431 return JSWebAPIErrorFactory::postException(context, exception, err);
435 return JSWebAPIErrorFactory::postException(context, exception, JSWebAPIErrorFactory::TYPE_MISMATCH_ERROR, "Type missmatch error");
441 JSContextRef globalContext = privateObject->getContext();
442 ConverterPtr converter = ConverterFactory::getConverter(globalContext);
445 long id = static_cast<long>(converter->toLong(argv[0]));
446 LoggerD("id:" << id);
450 FilesystemListenerCancellerPtr canceller = FilesystemListenerCancellerPtr(new FilesystemListenerCanceller(globalContext, thisObject, id));
451 IListenerItemPtr listenerItem = DPL::StaticPointerCast<IListenerItem>(canceller);
452 FilesystemListenerManagerSingleton::Instance().unregisterListener(listenerItem);
454 IManager::getInstance().removeStorageStateChangeListener(id);
457 } catch(const WrtDeviceApis::Commons::ConversionException& ex) {
458 return JSWebAPIErrorFactory::postException(context, exception, JSWebAPIErrorFactory::TYPE_MISMATCH_ERROR, ex.GetMessage());
459 } catch (const WrtDeviceApis::Commons::UnsupportedException& ex) {
460 return JSWebAPIErrorFactory::postException(context, exception, JSWebAPIErrorFactory::NOT_SUPPORTED_ERROR, ex.GetMessage());
461 } catch (const WrtDeviceApis::Commons::NotFoundException& ex) {
462 return JSWebAPIErrorFactory::postException(context, exception, JSWebAPIErrorFactory::NOT_FOUND_ERROR, ex.GetMessage());
463 } catch(const WrtDeviceApis::Commons::InvalidArgumentException& ex) {
464 return JSWebAPIErrorFactory::postException(context, exception, JSWebAPIErrorFactory::INVALID_VALUES_ERROR, ex.GetMessage());
465 } catch(const WrtDeviceApis::Commons::Exception& ex) {
466 return JSWebAPIErrorFactory::postException(context, exception, JSWebAPIErrorFactory::UNKNOWN_ERROR, ex.GetMessage());
468 TIME_TRACER_ITEM_END(__FUNCTION__, 0);
469 return JSValueMakeUndefined(context);
472 JSValueRef JSFilesystemManager::resolve(JSContextRef context,
474 JSObjectRef thisObject,
476 const JSValueRef argv[],
477 JSValueRef* exception)
481 TIME_TRACER_ITEM_BEGIN(__FUNCTION__, 0);
483 PrivateObject* privateObject = static_cast<PrivateObject*>(JSObjectGetPrivate(thisObject));
484 if (!privateObject) {
485 return JSValueMakeUndefined(context);
489 AceSecurityStatus status = FILESYSTEM_CHECK_ACCESS(FILESYSTEM_FUNCTION_API_MGR_RESOLVE_ID);
490 TIZEN_SYNC_ACCESS_HANDLER(status, context, exception);
492 // argument validation with new validator
494 ArgumentValidator validator(context, argc, argv);
495 validator.toString(0, false);
496 validator.toFunction(1, false);
497 validator.toFunction(2, true);
498 validator.toString(3, true);
500 catch (const BasePlatformException &err) {
501 return JSWebAPIErrorFactory::postException(context, exception, err);
503 DeviceAPI::Common::UnknownException err("");
504 return JSWebAPIErrorFactory::postException(context, exception, err);
508 return JSWebAPIErrorFactory::postException(context, exception, JSWebAPIErrorFactory::TYPE_MISMATCH_ERROR, "Type missmatch error");
516 JSContextRef globalContext = privateObject->getContext();
517 ConverterPtr converter = ConverterFactory::getConverter(globalContext);
520 JSCallbackManagerPtr cbm = JSCallbackManager::createObject(globalContext);
521 JSValueRef reserveArguments[4];
524 for (index = 0; index < 4; index++) {
526 reserveArguments[index] = argv[index];
528 reserveArguments[index] = JSValueMakeUndefined(context);
531 JSValueRef onSuccess = getFunction(globalContext, reserveArguments[1]);
532 JSValueRef onError = NULL;
534 onError = getFunctionOrNull(globalContext, reserveArguments[2]);
536 cbm->setOnSuccess(onSuccess);
537 cbm->setOnError(onError);
538 cbm->setObject(thisObject);
541 std::string virtualPath;
542 path = Utils::fromVirtualPath(globalContext, converter->toString(reserveArguments[0]));
543 virtualPath = converter->toString(reserveArguments[0]);
544 LoggerD("virtualPath:[" << virtualPath << "]");
545 int permissions = PERM_READ | PERM_WRITE;
550 std::string perms = converter->toString(reserveArguments[3]);
551 LoggerD("perms:[" << perms << "]");
552 if (("r" != perms) && ("rw" != perms) && ("w" != perms) && ("a" != perms)) {
553 return JSWebAPIErrorFactory::postException(context, exception, JSWebAPIErrorFactory::TYPE_MISMATCH_ERROR, "Invalid permission");
554 } else if ("r" == perms) {
555 permissions = PERM_READ;
559 if (permissions & PERM_WRITE && virtualPath == "wgt-package") {
560 return JSWebAPIErrorFactory::postException(context, exception, JSWebAPIErrorFactory::PERMISSION_DENIED_ERROR, "permission denied");
563 PermissionsAccessInfo perms(permissions, virtualPath);
564 AceSecurityStatus status = FILESYSTEM_PERMISSION_CHECK_ACCESS(
565 FILESYSTEM_FUNCTION_API_MGR_RESOLVE_ID,
568 TIZEN_SYNC_ACCESS_HANDLER(status, context, exception);
570 EventGetNodeDataPtr data(new EventGetNodeData(permissions, cbm));
571 EventResolvePtr event(new EventResolve(path));
572 event->setForAsynchronousCall(&ResponseDispatcher::getInstance());
573 event->setPrivateData(DPL::StaticPointerCast<WrtDeviceApis::Commons::IEventPrivateData > (data));
574 FilesystemAsyncCallbackManagerSingleton::Instance().registerCallbackManager(cbm, globalContext);
576 IManager::getInstance().getNode(event);
578 } catch(const WrtDeviceApis::Commons::ConversionException& ex) {
579 return JSWebAPIErrorFactory::postException(context, exception, JSWebAPIErrorFactory::TYPE_MISMATCH_ERROR, ex.GetMessage());
580 } catch(const WrtDeviceApis::Commons::NotFoundException& ex) {
581 cbm->callOnError(JSWebAPIErrorFactory::makeErrorObject(context, JSWebAPIErrorFactory::NOT_FOUND_ERROR, ex.GetMessage()));
582 } catch (const WrtDeviceApis::Commons::UnsupportedException& ex) {
583 return JSWebAPIErrorFactory::postException(context, exception, JSWebAPIErrorFactory::NOT_SUPPORTED_ERROR, ex.GetMessage());
584 } catch(const WrtDeviceApis::Commons::InvalidArgumentException& ex) {
585 cbm->callOnError(JSWebAPIErrorFactory::makeErrorObject(context, JSWebAPIErrorFactory::INVALID_VALUES_ERROR, ex.GetMessage()));
586 } catch(const WrtDeviceApis::Commons::Exception& ex) {
587 cbm->callOnError(JSWebAPIErrorFactory::makeErrorObject(context, JSWebAPIErrorFactory::UNKNOWN_ERROR, ex.GetMessage()));
590 TIME_TRACER_ITEM_END(__FUNCTION__, 0);
591 return JSValueMakeUndefined(context);