9145bfb902fa5b26ae0f7df1904f8b0d7167fa66
[framework/web/wrt-plugins-tizen.git] / src / Filesystem / JSFilesystemManager.cpp
1 //
2 // Tizen Web Device API
3 // Copyright (c) 2012 Samsung Electronics Co., Ltd.
4 //
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
8 //
9 // http://www.apache.org/licenses/LICENSE-2.0
10 //
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.
16 //
17
18  
19 #include "JSFilesystemManager.h"
20
21 #include <dpl/log/log.h>
22
23 #include <Commons/Exception.h>
24 #include "EventResolve.h"
25 #include "IManager.h"
26 #include "IPath.h"
27 #include "EventGetStorage.h"
28 #include "EventListStorages.h"
29 #include "EventStorageStateChanged.h"
30 #include <CommonsJavaScript/JSCallbackManager.h>
31 #include <CommonsJavaScript/Utils.h>
32 #include <CommonsJavaScript/JSUtils.h>
33 #include <CommonsJavaScript/Validator.h>
34 #include <JSTizenExceptionFactory.h>
35 #include <JSTizenException.h> 
36 #include <SecurityExceptions.h>
37 #include <Commons/WrtAccess/WrtAccess.h>
38 #include <WidgetDB/WidgetDBMgr.h>
39 #include <WidgetDB/IWidgetDB.h>
40
41 #include "JSFile.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"
50
51 using namespace WrtDeviceApis::Commons;
52 using namespace WrtDeviceApis::CommonsJavaScript;
53 using namespace DeviceAPI::Common;
54 using namespace WrtDeviceApis;
55
56
57 namespace {
58 const char* PLUGIN_NAME = "filesystem";
59 const char* PROPERTY_MAXPATHLENGTH = "maxPathLength";
60
61 JSValueRef getFunctionOrNull(JSContextRef ctx, JSValueRef arg)
62 {
63         if (Validator(ctx).isCallback(arg)) {
64                 return arg;
65         } else if (!JSValueIsNull(ctx, arg) && !JSValueIsUndefined(ctx, arg)) {
66                 ThrowMsg(ConversionException, "Not a function nor JS null.");
67         }
68         return NULL;
69 }
70
71
72 JSValueRef getFunction(JSContextRef ctx, JSValueRef arg)
73 {
74         if (Validator(ctx).isCallback(arg)) {
75                 return arg;
76         }else{
77                 ThrowMsg(ConversionException, "JS null passed as function.");
78         }
79 }
80
81 }
82
83
84
85 namespace DeviceAPI {
86 namespace Filesystem {
87
88 JSClassRef JSFilesystemManager::m_classRef = 0;
89
90 JSClassDefinition JSFilesystemManager::m_classInfo = {
91         0,
92         kJSClassAttributeNone,
93         PLUGIN_NAME,
94         0,
95         m_properties,
96         m_functions,
97         initialize,
98         finalize,
99         NULL,
100         NULL,
101         NULL,
102         NULL,
103         NULL,
104         NULL,
105         NULL,
106         NULL,
107         NULL
108 };
109
110 JSStaticValue JSFilesystemManager::m_properties[] = {
111         { PROPERTY_MAXPATHLENGTH, getMaxPathLength, NULL, kJSPropertyAttributeReadOnly },
112         { 0, 0, 0, 0 }
113 };
114
115 JSStaticFunction JSFilesystemManager::m_functions[] = {
116         { "resolve", JSFilesystemManager::resolve, kJSPropertyAttributeNone },
117         { "getStorage", JSFilesystemManager::getStorage, kJSPropertyAttributeNone },
118         { "listStorages", JSFilesystemManager::getStorageList, kJSPropertyAttributeNone },
119         { "addStorageStateChangeListener", JSFilesystemManager::addStorageStateListener, kJSPropertyAttributeNone },
120         { "removeStorageStateChangeListener", JSFilesystemManager::removeStorageStateListener, kJSPropertyAttributeNone },
121         { 0, 0, 0 }
122 };
123
124 const JSClassRef JSFilesystemManager::getClassRef()
125 {
126         if (!m_classRef) {
127                 m_classRef = JSClassCreate(&m_classInfo);
128         }
129         return m_classRef;
130 }
131
132 const JSClassDefinition* JSFilesystemManager::getClassInfo()
133 {
134         return &m_classInfo;
135 }
136
137 void JSFilesystemManager::initialize(JSContextRef context,
138         JSObjectRef object)
139 {
140         PrivateObject* privateObject = new PrivateObject(context);
141         if (!JSObjectSetPrivate(object, privateObject)) {
142                 delete privateObject;
143         }
144         else {
145         int widgetId = WrtAccessSingleton::Instance().getWidgetId();
146                 WidgetDB::Api::IWidgetDBPtr widgetDB = WidgetDB::Api::getWidgetDB(widgetId);
147
148                 LogDebug(widgetDB->getWidgetInstallationPath());
149                 std::string wgtpackage = "wgt-package";
150                 std::string wgtprivate = "wgt-private";
151                 std::string wgtprivatetemp = "wgt-private-tmp";
152                 
153                 IManager::getInstance().addWidgetStorage(wgtpackage, widgetDB->getWidgetInstallationPath());
154                 IManager::getInstance().addWidgetStorage(wgtprivate, widgetDB->getWidgetPersistentStoragePath());
155                 IManager::getInstance().addWidgetStorage(wgtprivatetemp, widgetDB->getWidgetTemporaryStoragePath());
156         
157         }
158 }
159
160 void JSFilesystemManager::finalize(JSObjectRef object)
161 {
162         PrivateObject* privateObject = static_cast<PrivateObject*>(JSObjectGetPrivate(object));
163         if (privateObject) {
164                 JSObjectSetPrivate(object, NULL);
165                 delete privateObject;
166         }
167 }
168
169 JSValueRef JSFilesystemManager::getMaxPathLength(JSContextRef context,
170                 JSObjectRef object,
171                 JSStringRef propertyName,
172                 JSValueRef* exception)
173 {
174         ConverterPtr converter = ConverterFactory::getConverter(context);
175         try {
176                 return converter->toJSValueRef(IManager::getInstance().getMaxPathLength());
177         } catch (const WrtDeviceApis::Commons::ConversionException& ex) {
178                 return JSTizenExceptionFactory::postException(context, exception, JSTizenException::IO_ERROR, "IO error");
179         }
180 }
181
182 JSValueRef JSFilesystemManager::getStorage(JSContextRef context,
183                 JSObjectRef object,
184                 JSObjectRef thisObject,
185                 size_t argc,
186                 const JSValueRef argv[],
187                 JSValueRef* exception)
188 {
189         PrivateObject* privateObject = static_cast<PrivateObject*>(JSObjectGetPrivate(thisObject));
190         if (!privateObject) {
191                 return JSValueMakeUndefined(context);
192         }
193
194         if (argc < 2) {
195                 return JSTizenExceptionFactory::postException(context, exception, JSTizenException::TYPE_MISMATCH_ERROR, "Type missmatch error");
196         }
197
198         AceSecurityStatus status = FILESYSTEM_CHECK_ACCESS(FILESYSTEM_FUNCTION_API_GET_STORAGE);
199         TIZEN_SYNC_ACCESS_HANDLER(status, context, exception);
200         
201
202         JSContextRef globalContext = privateObject->getContext();
203         ConverterPtr converter = ConverterFactory::getConverter(globalContext);
204         JSCallbackManagerPtr cbm = JSCallbackManager::createObject(globalContext);
205
206         try {
207
208                 JSValueRef onSuccess = getFunction(globalContext, argv[1]);
209                 JSValueRef onError = NULL;
210                         
211                 if (argc>2) {
212                         onError = getFunctionOrNull(globalContext, argv[2]);
213                 }
214
215                 cbm->setOnSuccess(onSuccess);
216                 cbm->setOnError(onError);
217
218                 EventGetStoragePtr event(new EventGetStorage());
219                 event->setLabel(converter->toString(argv[0]));
220                 event->setForAsynchronousCall(&ResponseDispatcher::getInstance()); 
221                 event->setPrivateData(DPL::StaticPointerCast<WrtDeviceApis::Commons::IEventPrivateData > (cbm));
222                 FilesystemAsyncCallbackManagerSingleton::Instance().registerCallbackManager(cbm, globalContext);
223
224                 IManager::getInstance().getStorage(event);
225
226         } catch(const WrtDeviceApis::Commons::ConversionException& ex) {
227                 return JSTizenExceptionFactory::postException(context, exception, JSTizenException::TYPE_MISMATCH_ERROR, ex.GetMessage());
228         } catch (const WrtDeviceApis::Commons::UnsupportedException& ex) {
229                 return JSTizenExceptionFactory::postException(context, exception, JSTizenException::NOT_SUPPORTED_ERROR, ex.GetMessage());
230         } catch(const WrtDeviceApis::Commons::InvalidArgumentException& ex) {
231                 cbm->callOnError(JSTizenExceptionFactory::makeErrorObject(context, JSTizenException::INVALID_VALUES_ERROR, ex.GetMessage()));
232         } catch(const WrtDeviceApis::Commons::Exception& ex) {
233                 cbm->callOnError(JSTizenExceptionFactory::makeErrorObject(context, JSTizenException::UNKNOWN_ERROR, ex.GetMessage()));
234         }
235
236         return JSValueMakeUndefined(context);
237 }
238
239 JSValueRef JSFilesystemManager::getStorageList(JSContextRef context,
240                 JSObjectRef object,
241                 JSObjectRef thisObject,
242                 size_t argc,
243                 const JSValueRef argv[],
244                 JSValueRef* exception)
245 {
246         PrivateObject* privateObject = static_cast<PrivateObject*>(JSObjectGetPrivate(thisObject));
247         if (!privateObject) {
248                 return JSValueMakeUndefined(context);
249         }
250
251         if (argc < 1) {
252                 return JSTizenExceptionFactory::postException(context, exception, JSTizenException::TYPE_MISMATCH_ERROR, "Type missmatch error");
253         }
254                 
255
256         AceSecurityStatus status = FILESYSTEM_CHECK_ACCESS(FILESYSTEM_FUNCTION_API_LIST_STORAGE);
257         TIZEN_SYNC_ACCESS_HANDLER(status, context, exception);
258
259
260         JSContextRef globalContext = privateObject->getContext();
261         ConverterPtr converter = ConverterFactory::getConverter(globalContext);
262         JSCallbackManagerPtr cbm = JSCallbackManager::createObject(globalContext);
263         
264         try {
265
266                 JSValueRef onSuccess = getFunction(globalContext, argv[0]);
267                 JSValueRef onError = NULL;
268                         
269                 if (argc > 1) {
270                         onError = getFunctionOrNull(globalContext, argv[1]);
271                 }
272
273                 cbm->setOnSuccess(onSuccess);
274                 cbm->setOnError(onError);
275                 cbm->setObject(thisObject);
276
277                 EventListStoragesPtr event(new EventListStorages());
278                 event->setForAsynchronousCall(&ResponseDispatcher::getInstance()); 
279                 event->setPrivateData(DPL::StaticPointerCast<WrtDeviceApis::Commons::IEventPrivateData > (cbm));
280                 FilesystemAsyncCallbackManagerSingleton::Instance().registerCallbackManager(cbm, globalContext);
281
282
283                 IManager::getInstance().listStorages(event);
284
285         } catch(const WrtDeviceApis::Commons::ConversionException& ex) {
286                 return JSTizenExceptionFactory::postException(context, exception, JSTizenException::TYPE_MISMATCH_ERROR, ex.GetMessage());
287         } catch (const WrtDeviceApis::Commons::UnsupportedException& ex) {
288                 return JSTizenExceptionFactory::postException(context, exception, JSTizenException::NOT_SUPPORTED_ERROR, ex.GetMessage());
289         } catch(const WrtDeviceApis::Commons::InvalidArgumentException& ex) {
290                 cbm->callOnError(JSTizenExceptionFactory::makeErrorObject(context, JSTizenException::INVALID_VALUES_ERROR, ex.GetMessage()));
291         } catch(const WrtDeviceApis::Commons::Exception& ex) {
292                 cbm->callOnError(JSTizenExceptionFactory::makeErrorObject(context, JSTizenException::UNKNOWN_ERROR, ex.GetMessage()));
293         }
294
295         return JSValueMakeUndefined(context);
296 }
297
298 JSValueRef JSFilesystemManager::addStorageStateListener(JSContextRef context, 
299                 JSObjectRef object,
300                 JSObjectRef thisObject,
301                 size_t argc,
302                 const JSValueRef argv[],
303                 JSValueRef* exception)
304 {
305         PrivateObject* privateObject = static_cast<PrivateObject*>(JSObjectGetPrivate(thisObject));
306         if (!privateObject) {
307                 return JSValueMakeUndefined(context);
308         }
309
310         if (argc < 1) {
311                 return JSTizenExceptionFactory::postException(context, exception, JSTizenException::TYPE_MISMATCH_ERROR, "TYPE_MISMATCH_ERROR");
312         }
313
314         AceSecurityStatus status = FILESYSTEM_CHECK_ACCESS(FILESYSTEM_FUNCTION_API_ADD_STORAGE_LISTENER);
315         TIZEN_SYNC_ACCESS_HANDLER(status, context, exception);
316
317         JSContextRef globalContext = privateObject->getContext();
318         JSCallbackManagerPtr cbm = JSCallbackManager::createObject(globalContext);
319         ConverterPtr converter = ConverterFactory::getConverter(globalContext);
320
321         try {
322                 JSValueRef onSuccess = getFunction(globalContext, argv[0]);
323                 JSValueRef onError = NULL;
324                 if (argc > 1) {
325                         onError = getFunctionOrNull(globalContext, argv[1]);
326                 }
327
328                 cbm->setOnSuccess(onSuccess);
329                 cbm->setOnError(onError);
330
331                 EventStorageStateChangedEmitterPtr emitter(new EventStorageStateChangedEmitter);
332                 emitter->setListener(&StorageStaticController::getInstance());
333                 emitter->setEventPrivateData(DPL::StaticPointerCast<EventStorageStateChanged::PrivateDataType>(cbm));
334                 long id = IManager::getInstance().addStorageStateChangeListener(emitter);
335                 
336                 FilesystemListenerCancellerPtr canceller = FilesystemListenerCancellerPtr(new FilesystemListenerCanceller(globalContext, thisObject, id));
337                 IListenerItemPtr listenerItem = DPL::StaticPointerCast<IListenerItem>(canceller);
338                 FilesystemListenerManagerSingleton::Instance().registerListener(listenerItem, globalContext);
339
340                 return converter->toJSValueRefLong(id);
341         } catch(const WrtDeviceApis::Commons::ConversionException& ex) {
342                 return JSTizenExceptionFactory::postException(context, exception, JSTizenException::TYPE_MISMATCH_ERROR, ex.GetMessage());
343         } catch (const WrtDeviceApis::Commons::UnsupportedException& ex) {
344                 return JSTizenExceptionFactory::postException(context, exception, JSTizenException::NOT_SUPPORTED_ERROR, ex.GetMessage());
345         } catch(const WrtDeviceApis::Commons::InvalidArgumentException& ex) {
346                 cbm->callOnError(JSTizenExceptionFactory::makeErrorObject(context, JSTizenException::INVALID_VALUES_ERROR, ex.GetMessage()));
347         } catch(const WrtDeviceApis::Commons::Exception& ex) {
348                 cbm->callOnError(JSTizenExceptionFactory::makeErrorObject(context, JSTizenException::UNKNOWN_ERROR, ex.GetMessage()));
349         }
350
351         return JSValueMakeUndefined(context);
352 }
353
354 JSValueRef JSFilesystemManager::removeStorageStateListener(JSContextRef context,
355                 JSObjectRef object,
356                 JSObjectRef thisObject,
357                 size_t argc,
358                 const JSValueRef argv[],
359                 JSValueRef* exception)
360 {
361         PrivateObject* privateObject = static_cast<PrivateObject*>(JSObjectGetPrivate(thisObject));
362         if (!privateObject) {
363                 return JSValueMakeUndefined(context);
364         }
365
366         if (argc < 1) {
367                 return JSTizenExceptionFactory::postException(context, exception, JSTizenException::TYPE_MISMATCH_ERROR, "Type missmatch error");
368         }
369
370         AceSecurityStatus status = FILESYSTEM_CHECK_ACCESS(FILESYSTEM_FUNCTION_API_REMOVE_STORAGE_LISTENER);
371         TIZEN_SYNC_ACCESS_HANDLER(status, context, exception);
372
373         JSContextRef globalContext = privateObject->getContext();
374         ConverterPtr converter = ConverterFactory::getConverter(globalContext);
375         
376         try {
377                 long id = static_cast<long>(converter->toLong(argv[0]));
378                 LogDebug("id:" << id);
379
380                 if (id >= 0) {
381                         
382                         FilesystemListenerCancellerPtr canceller = FilesystemListenerCancellerPtr(new FilesystemListenerCanceller(globalContext, thisObject, id));
383                         IListenerItemPtr listenerItem = DPL::StaticPointerCast<IListenerItem>(canceller);
384                         FilesystemListenerManagerSingleton::Instance().unregisterListener(listenerItem);
385
386                         IManager::getInstance().removeStorageStateChangeListener(id);
387
388                 }
389         } catch(const WrtDeviceApis::Commons::ConversionException& ex) {
390                 return JSTizenExceptionFactory::postException(context, exception, JSTizenException::TYPE_MISMATCH_ERROR, ex.GetMessage());
391         } catch (const WrtDeviceApis::Commons::UnsupportedException& ex) {
392                 return JSTizenExceptionFactory::postException(context, exception, JSTizenException::NOT_SUPPORTED_ERROR, ex.GetMessage());
393         } catch (const WrtDeviceApis::Commons::NotFoundException& ex) {
394                 return JSTizenExceptionFactory::postException(context, exception, JSTizenException::NOT_FOUND_ERROR, ex.GetMessage());
395         } catch(const WrtDeviceApis::Commons::InvalidArgumentException& ex) {
396                 return JSTizenExceptionFactory::postException(context, exception, JSTizenException::INVALID_VALUES_ERROR, ex.GetMessage());
397         } catch(const WrtDeviceApis::Commons::Exception& ex) {
398                 return JSTizenExceptionFactory::postException(context, exception, JSTizenException::UNKNOWN_ERROR, ex.GetMessage());
399         }
400         return JSValueMakeUndefined(context);
401 }
402
403 JSValueRef JSFilesystemManager::resolve(JSContextRef context,
404                 JSObjectRef object,
405                 JSObjectRef thisObject,
406                 size_t argc,
407                 const JSValueRef argv[],
408                 JSValueRef* exception)
409 {
410
411         LogDebug("<<<");
412
413         PrivateObject* privateObject = static_cast<PrivateObject*>(JSObjectGetPrivate(thisObject));
414         if (!privateObject) {
415                 return JSValueMakeUndefined(context);
416         }
417
418         if (argc < 2) {
419                 return JSTizenExceptionFactory::postException(context, exception, JSTizenException::TYPE_MISMATCH_ERROR, "Type missmatch error");
420         }
421
422         JSContextRef globalContext = privateObject->getContext();
423         ConverterPtr converter = ConverterFactory::getConverter(globalContext);
424
425         size_t index = 0;
426         JSValueRef reserveArguments[4];
427         JSCallbackManagerPtr cbm = JSCallbackManager::createObject(globalContext);      
428         
429
430         try {
431                 for (index = 0; index < 4; index++) {
432                         if (index < argc)
433                                 reserveArguments[index] = argv[index];
434                         else 
435                                 reserveArguments[index] = JSValueMakeUndefined(context);
436                 }
437                 JSValueRef onSuccess = getFunction(globalContext, reserveArguments[1]);
438                 JSValueRef onError = NULL;
439
440                 onError = getFunctionOrNull(globalContext, reserveArguments[2]);
441
442                 cbm->setOnSuccess(onSuccess);
443                 cbm->setOnError(onError);
444                 cbm->setObject(thisObject);
445
446                 IPathPtr path;
447                 std::string virtualPath;
448                 path = Utils::fromVirtualPath(globalContext, converter->toString(reserveArguments[0]));
449                 virtualPath = converter->toString(reserveArguments[0]);
450                 LogDebug("virtualPath:[" << virtualPath << "]");
451                 int permissions = PERM_READ | PERM_WRITE;
452
453
454                 
455                 if (argc > 3) {
456                         std::string perms = converter->toString(reserveArguments[3]);
457                         LogDebug("perms:[" << perms << "]");
458                         if (("r" != perms) && ("rw" != perms) && ("w" != perms) && ("a" != perms)) {
459                                 return JSTizenExceptionFactory::postException(context, exception, JSTizenException::TYPE_MISMATCH_ERROR, "Invalid permission");
460                         } else if ("r" == perms) {
461                                 permissions = PERM_READ;
462                         }
463                 }
464
465                 if (permissions & PERM_WRITE && virtualPath == "wgt-package") {
466                         return JSTizenExceptionFactory::postException(context, exception, JSTizenException::PERMISSION_DENIED_ERROR, "permission denied");
467                 }
468
469                 PermissionsAccessInfo perms(permissions, virtualPath);
470                 AceSecurityStatus status = FILESYSTEM_PERMISSION_CHECK_ACCESS(
471                                 FILESYSTEM_FUNCTION_API_MGR_RESOLVE_ID,
472                                 perms);
473
474                 TIZEN_SYNC_ACCESS_HANDLER(status, context, exception);
475
476                 EventGetNodeDataPtr data(new EventGetNodeData(permissions, cbm));
477                 EventResolvePtr event(new EventResolve(path));
478                 event->setForAsynchronousCall(&ResponseDispatcher::getInstance()); 
479                 event->setPrivateData(DPL::StaticPointerCast<WrtDeviceApis::Commons::IEventPrivateData > (data));
480                 FilesystemAsyncCallbackManagerSingleton::Instance().registerCallbackManager(cbm, globalContext);
481
482                 IManager::getInstance().getNode(event);
483                 
484         } catch(const WrtDeviceApis::Commons::ConversionException& ex) {
485                 return JSTizenExceptionFactory::postException(context, exception, JSTizenException::TYPE_MISMATCH_ERROR, ex.GetMessage());
486         } catch(const WrtDeviceApis::Commons::NotFoundException& ex) {
487                 cbm->callOnError(JSTizenExceptionFactory::makeErrorObject(context, JSTizenException::NOT_FOUND_ERROR, ex.GetMessage()));
488         } catch (const WrtDeviceApis::Commons::UnsupportedException& ex) {
489                 return JSTizenExceptionFactory::postException(context, exception, JSTizenException::NOT_SUPPORTED_ERROR, ex.GetMessage());
490         } catch(const WrtDeviceApis::Commons::InvalidArgumentException& ex) {
491                 cbm->callOnError(JSTizenExceptionFactory::makeErrorObject(context, JSTizenException::INVALID_VALUES_ERROR, ex.GetMessage()));
492         } catch(const WrtDeviceApis::Commons::Exception& ex) {
493                 cbm->callOnError(JSTizenExceptionFactory::makeErrorObject(context, JSTizenException::UNKNOWN_ERROR, ex.GetMessage()));
494         }
495
496         return JSValueMakeUndefined(context);
497 }
498 }
499 }