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 <JSTizenExceptionFactory.h>
32 #include <JSTizenException.h>
33 #include <SecurityExceptions.h>
34 #include <Commons/WrtAccess/WrtAccess.h>
35 #include <WidgetDB/WidgetDBMgr.h>
36 #include <WidgetDB/IWidgetDB.h>
37 #include <TimeTracer.h>
38 #include <ArgumentValidator.h>
39 #include <JSWebAPIError.h>
40 #include <JSWebAPIException.h>
43 #include "FilesystemUtils.h"
44 #include "Converter.h"
45 #include "EventGetNodeData.h"
46 #include "plugin_config.h"
47 #include "StorageStaticController.h"
48 #include "ResponseDispatcher.h"
49 #include "FilesystemAsyncCallbackManager.h"
50 #include "FilesystemListenerManager.h"
53 using namespace WrtDeviceApis::Commons;
54 using namespace WrtDeviceApis::CommonsJavaScript;
55 using namespace DeviceAPI::Common;
56 using namespace WrtDeviceApis;
61 const char* PLUGIN_NAME = "FileSystemManager";
62 const char* PROPERTY_MAXPATHLENGTH = "maxPathLength";
64 JSValueRef getFunctionOrNull(JSContextRef ctx, JSValueRef arg)
66 if (Validator(ctx).isCallback(arg)) {
68 } else if (!JSValueIsNull(ctx, arg) && !JSValueIsUndefined(ctx, arg)) {
69 ThrowMsg(ConversionException, "Not a function nor JS null.");
75 JSValueRef getFunction(JSContextRef ctx, JSValueRef arg)
77 if (Validator(ctx).isCallback(arg)) {
80 ThrowMsg(ConversionException, "JS null passed as function.");
89 namespace Filesystem {
91 JSClassRef JSFilesystemManager::m_classRef = 0;
93 JSClassDefinition JSFilesystemManager::m_classInfo = {
95 kJSClassAttributeNone,
113 JSStaticValue JSFilesystemManager::m_properties[] = {
114 { PROPERTY_MAXPATHLENGTH, getMaxPathLength, NULL, kJSPropertyAttributeReadOnly },
118 JSStaticFunction JSFilesystemManager::m_functions[] = {
119 { "resolve", JSFilesystemManager::resolve, kJSPropertyAttributeNone },
120 { "getStorage", JSFilesystemManager::getStorage, kJSPropertyAttributeNone },
121 { "listStorages", JSFilesystemManager::getStorageList, kJSPropertyAttributeNone },
122 { "addStorageStateChangeListener", JSFilesystemManager::addStorageStateListener, kJSPropertyAttributeNone },
123 { "removeStorageStateChangeListener", JSFilesystemManager::removeStorageStateListener, kJSPropertyAttributeNone },
127 const JSClassRef JSFilesystemManager::getClassRef()
130 m_classRef = JSClassCreate(&m_classInfo);
135 const JSClassDefinition* JSFilesystemManager::getClassInfo()
140 void JSFilesystemManager::initialize(JSContextRef context,
143 PrivateObject* privateObject = new PrivateObject(context);
144 if (!JSObjectSetPrivate(object, privateObject)) {
145 delete privateObject;
148 int widgetId = WrtAccessSingleton::Instance().getWidgetId();
149 WidgetDB::Api::IWidgetDBPtr widgetDB = WidgetDB::Api::getWidgetDB(widgetId);
151 LoggerD(widgetDB->getWidgetInstallationPath());
152 std::string wgtpackage = "wgt-package";
153 std::string wgtprivate = "wgt-private";
154 std::string wgtprivatetemp = "wgt-private-tmp";
156 IManager::getInstance().addWidgetStorage(wgtpackage, widgetDB->getWidgetInstallationPath());
157 IManager::getInstance().addWidgetStorage(wgtprivate, widgetDB->getWidgetPersistentStoragePath());
158 IManager::getInstance().addWidgetStorage(wgtprivatetemp, widgetDB->getWidgetTemporaryStoragePath());
163 void JSFilesystemManager::finalize(JSObjectRef object)
165 PrivateObject* privateObject = static_cast<PrivateObject*>(JSObjectGetPrivate(object));
167 JSObjectSetPrivate(object, NULL);
168 delete privateObject;
172 JSValueRef JSFilesystemManager::getMaxPathLength(JSContextRef context,
174 JSStringRef propertyName,
175 JSValueRef* exception)
177 ConverterPtr converter = ConverterFactory::getConverter(context);
179 return converter->toJSValueRef(IManager::getInstance().getMaxPathLength());
180 } catch (const WrtDeviceApis::Commons::ConversionException& ex) {
181 return JSTizenExceptionFactory::postException(context, exception, JSTizenException::IO_ERROR, "IO error");
185 JSValueRef JSFilesystemManager::getStorage(JSContextRef context,
187 JSObjectRef thisObject,
189 const JSValueRef argv[],
190 JSValueRef* exception)
192 TIME_TRACER_ITEM_BEGIN(__FUNCTION__, 0);
193 PrivateObject* privateObject = static_cast<PrivateObject*>(JSObjectGetPrivate(thisObject));
194 if (!privateObject) {
195 return JSValueMakeUndefined(context);
198 AceSecurityStatus status = FILESYSTEM_CHECK_ACCESS(FILESYSTEM_FUNCTION_API_GET_STORAGE);
199 TIZEN_SYNC_ACCESS_HANDLER(status, context, exception);
201 // argument validation with new validator
203 ArgumentValidator validator(context, argc, argv);
204 validator.toString(0, false);
205 validator.toFunction(1, false);
206 validator.toFunction(2, true);
208 catch (const BasePlatformException &err) {
209 return JSWebAPIException::throwException(context, exception, err);
211 DeviceAPI::Common::UnknownException err("");
212 return JSWebAPIException::throwException(context, exception, err);
216 return JSTizenExceptionFactory::postException(context, exception, JSTizenException::TYPE_MISMATCH_ERROR, "Type missmatch error");
222 JSContextRef globalContext = privateObject->getContext();
223 ConverterPtr converter = ConverterFactory::getConverter(globalContext);
224 JSCallbackManagerPtr cbm = JSCallbackManager::createObject(globalContext);
228 JSValueRef onSuccess = getFunction(globalContext, argv[1]);
229 JSValueRef onError = NULL;
232 onError = getFunctionOrNull(globalContext, argv[2]);
235 cbm->setOnSuccess(onSuccess);
236 cbm->setOnError(onError);
238 EventGetStoragePtr event(new EventGetStorage());
239 event->setLabel(converter->toString(argv[0]));
240 event->setForAsynchronousCall(&ResponseDispatcher::getInstance());
241 event->setPrivateData(DPL::StaticPointerCast<WrtDeviceApis::Commons::IEventPrivateData > (cbm));
242 FilesystemAsyncCallbackManagerSingleton::Instance().registerCallbackManager(cbm, globalContext);
244 IManager::getInstance().getStorage(event);
246 } catch(const WrtDeviceApis::Commons::ConversionException& ex) {
247 return JSTizenExceptionFactory::postException(context, exception, JSTizenException::TYPE_MISMATCH_ERROR, ex.GetMessage());
248 } catch (const WrtDeviceApis::Commons::UnsupportedException& ex) {
249 return JSTizenExceptionFactory::postException(context, exception, JSTizenException::NOT_SUPPORTED_ERROR, ex.GetMessage());
250 } catch(const WrtDeviceApis::Commons::InvalidArgumentException& ex) {
251 cbm->callOnError(JSTizenExceptionFactory::makeErrorObject(context, JSTizenException::INVALID_VALUES_ERROR, ex.GetMessage()));
252 } catch(const WrtDeviceApis::Commons::Exception& ex) {
253 cbm->callOnError(JSTizenExceptionFactory::makeErrorObject(context, JSTizenException::UNKNOWN_ERROR, ex.GetMessage()));
255 TIME_TRACER_ITEM_END(__FUNCTION__, 0);
256 return JSValueMakeUndefined(context);
259 JSValueRef JSFilesystemManager::getStorageList(JSContextRef context,
261 JSObjectRef thisObject,
263 const JSValueRef argv[],
264 JSValueRef* exception)
266 TIME_TRACER_ITEM_BEGIN(__FUNCTION__, 0);
267 PrivateObject* privateObject = static_cast<PrivateObject*>(JSObjectGetPrivate(thisObject));
268 if (!privateObject) {
269 return JSValueMakeUndefined(context);
272 AceSecurityStatus status = FILESYSTEM_CHECK_ACCESS(FILESYSTEM_FUNCTION_API_LIST_STORAGE);
273 TIZEN_SYNC_ACCESS_HANDLER(status, context, exception);
275 // argument validation with new validator
277 ArgumentValidator validator(context, argc, argv);
278 validator.toFunction(0, false);
279 validator.toFunction(1, true);
281 catch (const BasePlatformException &err) {
282 return JSWebAPIException::throwException(context, exception, err);
284 DeviceAPI::Common::UnknownException err("");
285 return JSWebAPIException::throwException(context, exception, err);
289 return JSTizenExceptionFactory::postException(context, exception, JSTizenException::TYPE_MISMATCH_ERROR, "Type missmatch error");
293 JSContextRef globalContext = privateObject->getContext();
294 ConverterPtr converter = ConverterFactory::getConverter(globalContext);
295 JSCallbackManagerPtr cbm = JSCallbackManager::createObject(globalContext);
299 JSValueRef onSuccess = getFunction(globalContext, argv[0]);
300 JSValueRef onError = NULL;
303 onError = getFunctionOrNull(globalContext, argv[1]);
306 cbm->setOnSuccess(onSuccess);
307 cbm->setOnError(onError);
308 cbm->setObject(thisObject);
310 EventListStoragesPtr event(new EventListStorages());
311 event->setForAsynchronousCall(&ResponseDispatcher::getInstance());
312 event->setPrivateData(DPL::StaticPointerCast<WrtDeviceApis::Commons::IEventPrivateData > (cbm));
313 FilesystemAsyncCallbackManagerSingleton::Instance().registerCallbackManager(cbm, globalContext);
316 IManager::getInstance().listStorages(event);
318 } catch(const WrtDeviceApis::Commons::ConversionException& ex) {
319 return JSTizenExceptionFactory::postException(context, exception, JSTizenException::TYPE_MISMATCH_ERROR, ex.GetMessage());
320 } catch (const WrtDeviceApis::Commons::UnsupportedException& ex) {
321 return JSTizenExceptionFactory::postException(context, exception, JSTizenException::NOT_SUPPORTED_ERROR, ex.GetMessage());
322 } catch(const WrtDeviceApis::Commons::InvalidArgumentException& ex) {
323 cbm->callOnError(JSTizenExceptionFactory::makeErrorObject(context, JSTizenException::INVALID_VALUES_ERROR, ex.GetMessage()));
324 } catch(const WrtDeviceApis::Commons::Exception& ex) {
325 cbm->callOnError(JSTizenExceptionFactory::makeErrorObject(context, JSTizenException::UNKNOWN_ERROR, ex.GetMessage()));
327 TIME_TRACER_ITEM_END(__FUNCTION__, 0);
328 return JSValueMakeUndefined(context);
331 JSValueRef JSFilesystemManager::addStorageStateListener(JSContextRef context,
333 JSObjectRef thisObject,
335 const JSValueRef argv[],
336 JSValueRef* exception)
338 TIME_TRACER_ITEM_BEGIN(__FUNCTION__, 0);
339 PrivateObject* privateObject = static_cast<PrivateObject*>(JSObjectGetPrivate(thisObject));
340 if (!privateObject) {
341 return JSValueMakeUndefined(context);
344 AceSecurityStatus status = FILESYSTEM_CHECK_ACCESS(FILESYSTEM_FUNCTION_API_ADD_STORAGE_LISTENER);
345 TIZEN_SYNC_ACCESS_HANDLER(status, context, exception);
348 // argument validation with new validator
350 ArgumentValidator validator(context, argc, argv);
351 validator.toFunction(0, false);
352 validator.toFunction(1, true);
354 catch (const BasePlatformException &err) {
355 LogDebug("Exception");
356 return JSWebAPIException::throwException(context, exception, err);
358 DeviceAPI::Common::UnknownException err("");
359 return JSWebAPIException::throwException(context, exception, err);
364 return JSTizenExceptionFactory::postException(context, exception, JSTizenException::TYPE_MISMATCH_ERROR, "TYPE_MISMATCH_ERROR");
368 JSContextRef globalContext = privateObject->getContext();
369 JSCallbackManagerPtr cbm = JSCallbackManager::createObject(globalContext);
370 ConverterPtr converter = ConverterFactory::getConverter(globalContext);
373 JSValueRef onSuccess = getFunction(globalContext, argv[0]);
374 JSValueRef onError = NULL;
376 onError = getFunctionOrNull(globalContext, argv[1]);
379 cbm->setOnSuccess(onSuccess);
380 cbm->setOnError(onError);
382 EventStorageStateChangedEmitterPtr emitter(new EventStorageStateChangedEmitter);
383 emitter->setListener(&StorageStaticController::getInstance());
384 emitter->setEventPrivateData(DPL::StaticPointerCast<EventStorageStateChanged::PrivateDataType>(cbm));
385 long id = IManager::getInstance().addStorageStateChangeListener(emitter);
387 FilesystemListenerCancellerPtr canceller = FilesystemListenerCancellerPtr(new FilesystemListenerCanceller(globalContext, thisObject, id));
388 IListenerItemPtr listenerItem = DPL::StaticPointerCast<IListenerItem>(canceller);
389 FilesystemListenerManagerSingleton::Instance().registerListener(listenerItem, globalContext);
391 return converter->toJSValueRefLong(id);
392 } catch(const WrtDeviceApis::Commons::ConversionException& ex) {
393 return JSTizenExceptionFactory::postException(context, exception, JSTizenException::TYPE_MISMATCH_ERROR, ex.GetMessage());
394 } catch (const WrtDeviceApis::Commons::UnsupportedException& ex) {
395 return JSTizenExceptionFactory::postException(context, exception, JSTizenException::NOT_SUPPORTED_ERROR, ex.GetMessage());
396 } catch(const WrtDeviceApis::Commons::InvalidArgumentException& ex) {
397 cbm->callOnError(JSTizenExceptionFactory::makeErrorObject(context, JSTizenException::INVALID_VALUES_ERROR, ex.GetMessage()));
398 } catch(const WrtDeviceApis::Commons::Exception& ex) {
399 cbm->callOnError(JSTizenExceptionFactory::makeErrorObject(context, JSTizenException::UNKNOWN_ERROR, ex.GetMessage()));
401 TIME_TRACER_ITEM_END(__FUNCTION__, 0);
402 return JSValueMakeUndefined(context);
405 JSValueRef JSFilesystemManager::removeStorageStateListener(JSContextRef context,
407 JSObjectRef thisObject,
409 const JSValueRef argv[],
410 JSValueRef* exception)
412 TIME_TRACER_ITEM_BEGIN(__FUNCTION__, 0);
413 PrivateObject* privateObject = static_cast<PrivateObject*>(JSObjectGetPrivate(thisObject));
414 if (!privateObject) {
415 return JSValueMakeUndefined(context);
418 AceSecurityStatus status = FILESYSTEM_CHECK_ACCESS(FILESYSTEM_FUNCTION_API_REMOVE_STORAGE_LISTENER);
419 TIZEN_SYNC_ACCESS_HANDLER(status, context, exception);
423 // argument validation with new validator
425 ArgumentValidator validator(context, argc, argv);
426 validator.toLong(0, false);
428 catch (const BasePlatformException &err) {
429 return JSWebAPIException::throwException(context, exception, err);
431 DeviceAPI::Common::UnknownException err("");
432 return JSWebAPIException::throwException(context, exception, err);
436 return JSTizenExceptionFactory::postException(context, exception, JSTizenException::TYPE_MISMATCH_ERROR, "Type missmatch error");
442 JSContextRef globalContext = privateObject->getContext();
443 ConverterPtr converter = ConverterFactory::getConverter(globalContext);
446 long id = static_cast<long>(converter->toLong(argv[0]));
447 LoggerD("id:" << id);
451 FilesystemListenerCancellerPtr canceller = FilesystemListenerCancellerPtr(new FilesystemListenerCanceller(globalContext, thisObject, id));
452 IListenerItemPtr listenerItem = DPL::StaticPointerCast<IListenerItem>(canceller);
453 FilesystemListenerManagerSingleton::Instance().unregisterListener(listenerItem);
455 IManager::getInstance().removeStorageStateChangeListener(id);
458 } catch(const WrtDeviceApis::Commons::ConversionException& ex) {
459 return JSTizenExceptionFactory::postException(context, exception, JSTizenException::TYPE_MISMATCH_ERROR, ex.GetMessage());
460 } catch (const WrtDeviceApis::Commons::UnsupportedException& ex) {
461 return JSTizenExceptionFactory::postException(context, exception, JSTizenException::NOT_SUPPORTED_ERROR, ex.GetMessage());
462 } catch (const WrtDeviceApis::Commons::NotFoundException& ex) {
463 return JSTizenExceptionFactory::postException(context, exception, JSTizenException::NOT_FOUND_ERROR, ex.GetMessage());
464 } catch(const WrtDeviceApis::Commons::InvalidArgumentException& ex) {
465 return JSTizenExceptionFactory::postException(context, exception, JSTizenException::INVALID_VALUES_ERROR, ex.GetMessage());
466 } catch(const WrtDeviceApis::Commons::Exception& ex) {
467 return JSTizenExceptionFactory::postException(context, exception, JSTizenException::UNKNOWN_ERROR, ex.GetMessage());
469 TIME_TRACER_ITEM_END(__FUNCTION__, 0);
470 return JSValueMakeUndefined(context);
473 JSValueRef JSFilesystemManager::resolve(JSContextRef context,
475 JSObjectRef thisObject,
477 const JSValueRef argv[],
478 JSValueRef* exception)
482 TIME_TRACER_ITEM_BEGIN(__FUNCTION__, 0);
484 PrivateObject* privateObject = static_cast<PrivateObject*>(JSObjectGetPrivate(thisObject));
485 if (!privateObject) {
486 return JSValueMakeUndefined(context);
490 AceSecurityStatus status = FILESYSTEM_CHECK_ACCESS(FILESYSTEM_FUNCTION_API_MGR_RESOLVE_ID);
491 TIZEN_SYNC_ACCESS_HANDLER(status, context, exception);
493 // argument validation with new validator
495 ArgumentValidator validator(context, argc, argv);
496 validator.toString(0, false);
497 validator.toFunction(1, false);
498 validator.toFunction(2, true);
499 validator.toString(3, true);
501 catch (const BasePlatformException &err) {
502 return JSWebAPIException::throwException(context, exception, err);
504 DeviceAPI::Common::UnknownException err("");
505 return JSWebAPIException::throwException(context, exception, err);
509 return JSTizenExceptionFactory::postException(context, exception, JSTizenException::TYPE_MISMATCH_ERROR, "Type missmatch error");
517 JSContextRef globalContext = privateObject->getContext();
518 ConverterPtr converter = ConverterFactory::getConverter(globalContext);
521 JSCallbackManagerPtr cbm = JSCallbackManager::createObject(globalContext);
522 JSValueRef reserveArguments[4];
525 for (index = 0; index < 4; index++) {
527 reserveArguments[index] = argv[index];
529 reserveArguments[index] = JSValueMakeUndefined(context);
532 JSValueRef onSuccess = getFunction(globalContext, reserveArguments[1]);
533 JSValueRef onError = NULL;
535 onError = getFunctionOrNull(globalContext, reserveArguments[2]);
537 cbm->setOnSuccess(onSuccess);
538 cbm->setOnError(onError);
539 cbm->setObject(thisObject);
542 std::string virtualPath;
543 path = Utils::fromVirtualPath(globalContext, converter->toString(reserveArguments[0]));
544 virtualPath = converter->toString(reserveArguments[0]);
545 LoggerD("virtualPath:[" << virtualPath << "]");
546 int permissions = PERM_READ | PERM_WRITE;
551 std::string perms = converter->toString(reserveArguments[3]);
552 LoggerD("perms:[" << perms << "]");
553 if (("r" != perms) && ("rw" != perms) && ("w" != perms) && ("a" != perms)) {
554 return JSTizenExceptionFactory::postException(context, exception, JSTizenException::TYPE_MISMATCH_ERROR, "Invalid permission");
555 } else if ("r" == perms) {
556 permissions = PERM_READ;
560 if (permissions & PERM_WRITE && virtualPath == "wgt-package") {
561 return JSTizenExceptionFactory::postException(context, exception, JSTizenException::PERMISSION_DENIED_ERROR, "permission denied");
564 PermissionsAccessInfo perms(permissions, virtualPath);
565 AceSecurityStatus status = FILESYSTEM_PERMISSION_CHECK_ACCESS(
566 FILESYSTEM_FUNCTION_API_MGR_RESOLVE_ID,
569 TIZEN_SYNC_ACCESS_HANDLER(status, context, exception);
571 EventGetNodeDataPtr data(new EventGetNodeData(permissions, cbm));
572 EventResolvePtr event(new EventResolve(path));
573 event->setForAsynchronousCall(&ResponseDispatcher::getInstance());
574 event->setPrivateData(DPL::StaticPointerCast<WrtDeviceApis::Commons::IEventPrivateData > (data));
575 FilesystemAsyncCallbackManagerSingleton::Instance().registerCallbackManager(cbm, globalContext);
577 IManager::getInstance().getNode(event);
579 } catch(const WrtDeviceApis::Commons::ConversionException& ex) {
580 return JSTizenExceptionFactory::postException(context, exception, JSTizenException::TYPE_MISMATCH_ERROR, ex.GetMessage());
581 } catch(const WrtDeviceApis::Commons::NotFoundException& ex) {
582 cbm->callOnError(JSTizenExceptionFactory::makeErrorObject(context, JSTizenException::NOT_FOUND_ERROR, ex.GetMessage()));
583 } catch (const WrtDeviceApis::Commons::UnsupportedException& ex) {
584 return JSTizenExceptionFactory::postException(context, exception, JSTizenException::NOT_SUPPORTED_ERROR, ex.GetMessage());
585 } catch(const WrtDeviceApis::Commons::InvalidArgumentException& ex) {
586 cbm->callOnError(JSTizenExceptionFactory::makeErrorObject(context, JSTizenException::INVALID_VALUES_ERROR, ex.GetMessage()));
587 } catch(const WrtDeviceApis::Commons::Exception& ex) {
588 cbm->callOnError(JSTizenExceptionFactory::makeErrorObject(context, JSTizenException::UNKNOWN_ERROR, ex.GetMessage()));
591 TIME_TRACER_ITEM_END(__FUNCTION__, 0);
592 return JSValueMakeUndefined(context);