045e8c3ab37049e20758a89b5cba33d5736935cc
[platform/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         AceSecurityStatus status = FILESYSTEM_CHECK_ACCESS(FILESYSTEM_FUNCTION_API_GET_STORAGE);
195         TIZEN_SYNC_ACCESS_HANDLER(status, context, exception);
196
197         if (argc < 2) {
198                 return JSTizenExceptionFactory::postException(context, exception, JSTizenException::TYPE_MISMATCH_ERROR, "Type missmatch error");
199         }
200
201         JSContextRef globalContext = privateObject->getContext();
202         ConverterPtr converter = ConverterFactory::getConverter(globalContext);
203         JSCallbackManagerPtr cbm = JSCallbackManager::createObject(globalContext);
204
205         try {
206
207                 JSValueRef onSuccess = getFunction(globalContext, argv[1]);
208                 JSValueRef onError = NULL;
209                         
210                 if (argc>2) {
211                         onError = getFunctionOrNull(globalContext, argv[2]);
212                 }
213
214                 cbm->setOnSuccess(onSuccess);
215                 cbm->setOnError(onError);
216
217                 EventGetStoragePtr event(new EventGetStorage());
218                 event->setLabel(converter->toString(argv[0]));
219                 event->setForAsynchronousCall(&ResponseDispatcher::getInstance()); 
220                 event->setPrivateData(DPL::StaticPointerCast<WrtDeviceApis::Commons::IEventPrivateData > (cbm));
221                 FilesystemAsyncCallbackManagerSingleton::Instance().registerCallbackManager(cbm, globalContext);
222
223                 IManager::getInstance().getStorage(event);
224
225         } catch(const WrtDeviceApis::Commons::ConversionException& ex) {
226                 return JSTizenExceptionFactory::postException(context, exception, JSTizenException::TYPE_MISMATCH_ERROR, ex.GetMessage());
227         } catch (const WrtDeviceApis::Commons::UnsupportedException& ex) {
228                 return JSTizenExceptionFactory::postException(context, exception, JSTizenException::NOT_SUPPORTED_ERROR, ex.GetMessage());
229         } catch(const WrtDeviceApis::Commons::InvalidArgumentException& ex) {
230                 cbm->callOnError(JSTizenExceptionFactory::makeErrorObject(context, JSTizenException::INVALID_VALUES_ERROR, ex.GetMessage()));
231         } catch(const WrtDeviceApis::Commons::Exception& ex) {
232                 cbm->callOnError(JSTizenExceptionFactory::makeErrorObject(context, JSTizenException::UNKNOWN_ERROR, ex.GetMessage()));
233         }
234
235         return JSValueMakeUndefined(context);
236 }
237
238 JSValueRef JSFilesystemManager::getStorageList(JSContextRef context,
239                 JSObjectRef object,
240                 JSObjectRef thisObject,
241                 size_t argc,
242                 const JSValueRef argv[],
243                 JSValueRef* exception)
244 {
245         PrivateObject* privateObject = static_cast<PrivateObject*>(JSObjectGetPrivate(thisObject));
246         if (!privateObject) {
247                 return JSValueMakeUndefined(context);
248         }
249
250         AceSecurityStatus status = FILESYSTEM_CHECK_ACCESS(FILESYSTEM_FUNCTION_API_LIST_STORAGE);
251         TIZEN_SYNC_ACCESS_HANDLER(status, context, exception);
252         
253
254         if (argc < 1) {
255                 return JSTizenExceptionFactory::postException(context, exception, JSTizenException::TYPE_MISMATCH_ERROR, "Type missmatch error");
256         }
257         
258         JSContextRef globalContext = privateObject->getContext();
259         ConverterPtr converter = ConverterFactory::getConverter(globalContext);
260         JSCallbackManagerPtr cbm = JSCallbackManager::createObject(globalContext);
261         
262         try {
263
264                 JSValueRef onSuccess = getFunction(globalContext, argv[0]);
265                 JSValueRef onError = NULL;
266                         
267                 if (argc > 1) {
268                         onError = getFunctionOrNull(globalContext, argv[1]);
269                 }
270
271                 cbm->setOnSuccess(onSuccess);
272                 cbm->setOnError(onError);
273                 cbm->setObject(thisObject);
274
275                 EventListStoragesPtr event(new EventListStorages());
276                 event->setForAsynchronousCall(&ResponseDispatcher::getInstance()); 
277                 event->setPrivateData(DPL::StaticPointerCast<WrtDeviceApis::Commons::IEventPrivateData > (cbm));
278                 FilesystemAsyncCallbackManagerSingleton::Instance().registerCallbackManager(cbm, globalContext);
279
280
281                 IManager::getInstance().listStorages(event);
282
283         } catch(const WrtDeviceApis::Commons::ConversionException& ex) {
284                 return JSTizenExceptionFactory::postException(context, exception, JSTizenException::TYPE_MISMATCH_ERROR, ex.GetMessage());
285         } catch (const WrtDeviceApis::Commons::UnsupportedException& ex) {
286                 return JSTizenExceptionFactory::postException(context, exception, JSTizenException::NOT_SUPPORTED_ERROR, ex.GetMessage());
287         } catch(const WrtDeviceApis::Commons::InvalidArgumentException& ex) {
288                 cbm->callOnError(JSTizenExceptionFactory::makeErrorObject(context, JSTizenException::INVALID_VALUES_ERROR, ex.GetMessage()));
289         } catch(const WrtDeviceApis::Commons::Exception& ex) {
290                 cbm->callOnError(JSTizenExceptionFactory::makeErrorObject(context, JSTizenException::UNKNOWN_ERROR, ex.GetMessage()));
291         }
292
293         return JSValueMakeUndefined(context);
294 }
295
296 JSValueRef JSFilesystemManager::addStorageStateListener(JSContextRef context, 
297                 JSObjectRef object,
298                 JSObjectRef thisObject,
299                 size_t argc,
300                 const JSValueRef argv[],
301                 JSValueRef* exception)
302 {
303         PrivateObject* privateObject = static_cast<PrivateObject*>(JSObjectGetPrivate(thisObject));
304         if (!privateObject) {
305                 return JSValueMakeUndefined(context);
306         }
307
308         AceSecurityStatus status = FILESYSTEM_CHECK_ACCESS(FILESYSTEM_FUNCTION_API_ADD_STORAGE_LISTENER);
309         TIZEN_SYNC_ACCESS_HANDLER(status, context, exception);
310
311         if (argc < 1) {
312                 return JSTizenExceptionFactory::postException(context, exception, JSTizenException::TYPE_MISMATCH_ERROR, "TYPE_MISMATCH_ERROR");
313         }
314
315
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         AceSecurityStatus status = FILESYSTEM_CHECK_ACCESS(FILESYSTEM_FUNCTION_API_REMOVE_STORAGE_LISTENER);
367         TIZEN_SYNC_ACCESS_HANDLER(status, context, exception);
368
369         if (argc < 1) {
370                 return JSTizenExceptionFactory::postException(context, exception, JSTizenException::TYPE_MISMATCH_ERROR, "Type missmatch error");
371         }
372
373
374
375         JSContextRef globalContext = privateObject->getContext();
376         ConverterPtr converter = ConverterFactory::getConverter(globalContext);
377         
378         try {
379                 long id = static_cast<long>(converter->toLong(argv[0]));
380                 LogDebug("id:" << id);
381
382                 if (id >= 0) {
383                         
384                         FilesystemListenerCancellerPtr canceller = FilesystemListenerCancellerPtr(new FilesystemListenerCanceller(globalContext, thisObject, id));
385                         IListenerItemPtr listenerItem = DPL::StaticPointerCast<IListenerItem>(canceller);
386                         FilesystemListenerManagerSingleton::Instance().unregisterListener(listenerItem);
387
388                         IManager::getInstance().removeStorageStateChangeListener(id);
389
390                 }
391         } catch(const WrtDeviceApis::Commons::ConversionException& ex) {
392                 return JSTizenExceptionFactory::postException(context, exception, JSTizenException::TYPE_MISMATCH_ERROR, ex.GetMessage());
393         } catch (const WrtDeviceApis::Commons::UnsupportedException& ex) {
394                 return JSTizenExceptionFactory::postException(context, exception, JSTizenException::NOT_SUPPORTED_ERROR, ex.GetMessage());
395         } catch (const WrtDeviceApis::Commons::NotFoundException& ex) {
396                 return JSTizenExceptionFactory::postException(context, exception, JSTizenException::NOT_FOUND_ERROR, ex.GetMessage());
397         } catch(const WrtDeviceApis::Commons::InvalidArgumentException& ex) {
398                 return JSTizenExceptionFactory::postException(context, exception, JSTizenException::INVALID_VALUES_ERROR, ex.GetMessage());
399         } catch(const WrtDeviceApis::Commons::Exception& ex) {
400                 return JSTizenExceptionFactory::postException(context, exception, JSTizenException::UNKNOWN_ERROR, ex.GetMessage());
401         }
402         return JSValueMakeUndefined(context);
403 }
404
405 JSValueRef JSFilesystemManager::resolve(JSContextRef context,
406                 JSObjectRef object,
407                 JSObjectRef thisObject,
408                 size_t argc,
409                 const JSValueRef argv[],
410                 JSValueRef* exception)
411 {
412
413         LogDebug("<<<");
414
415         PrivateObject* privateObject = static_cast<PrivateObject*>(JSObjectGetPrivate(thisObject));
416         if (!privateObject) {
417                 return JSValueMakeUndefined(context);
418
419         }
420
421         AceSecurityStatus status = FILESYSTEM_CHECK_ACCESS(FILESYSTEM_FUNCTION_API_MGR_RESOLVE_ID);
422         TIZEN_SYNC_ACCESS_HANDLER(status, context, exception);
423         
424         if (argc < 2) {
425                 return JSTizenExceptionFactory::postException(context, exception, JSTizenException::TYPE_MISMATCH_ERROR, "Type missmatch error");
426         }
427
428         JSContextRef globalContext = privateObject->getContext();
429         ConverterPtr converter = ConverterFactory::getConverter(globalContext);
430
431         size_t index = 0;
432         JSValueRef reserveArguments[4];
433         JSCallbackManagerPtr cbm = JSCallbackManager::createObject(globalContext);      
434
435         
436
437
438         try {
439                 for (index = 0; index < 4; index++) {
440                         if (index < argc)
441                                 reserveArguments[index] = argv[index];
442                         else 
443                                 reserveArguments[index] = JSValueMakeUndefined(context);
444                 }
445                 JSValueRef onSuccess = getFunction(globalContext, reserveArguments[1]);
446                 JSValueRef onError = NULL;
447
448                 onError = getFunctionOrNull(globalContext, reserveArguments[2]);
449
450                 cbm->setOnSuccess(onSuccess);
451                 cbm->setOnError(onError);
452                 cbm->setObject(thisObject);
453
454                 IPathPtr path;
455                 std::string virtualPath;
456                 path = Utils::fromVirtualPath(globalContext, converter->toString(reserveArguments[0]));
457                 virtualPath = converter->toString(reserveArguments[0]);
458                 LogDebug("virtualPath:[" << virtualPath << "]");
459                 int permissions = PERM_READ | PERM_WRITE;
460
461
462                 
463                 if (argc > 3) {
464                         std::string perms = converter->toString(reserveArguments[3]);
465                         LogDebug("perms:[" << perms << "]");
466                         if (("r" != perms) && ("rw" != perms) && ("w" != perms) && ("a" != perms)) {
467                                 return JSTizenExceptionFactory::postException(context, exception, JSTizenException::TYPE_MISMATCH_ERROR, "Invalid permission");
468                         } else if ("r" == perms) {
469                                 permissions = PERM_READ;
470                         }
471                 }
472
473                 if (permissions & PERM_WRITE && virtualPath == "wgt-package") {
474                         return JSTizenExceptionFactory::postException(context, exception, JSTizenException::PERMISSION_DENIED_ERROR, "permission denied");
475                 }
476
477                 PermissionsAccessInfo perms(permissions, virtualPath);
478                 AceSecurityStatus status = FILESYSTEM_PERMISSION_CHECK_ACCESS(
479                                 FILESYSTEM_FUNCTION_API_MGR_RESOLVE_ID,
480                                 perms);
481
482                 TIZEN_SYNC_ACCESS_HANDLER(status, context, exception);
483
484                 EventGetNodeDataPtr data(new EventGetNodeData(permissions, cbm));
485                 EventResolvePtr event(new EventResolve(path));
486                 event->setForAsynchronousCall(&ResponseDispatcher::getInstance()); 
487                 event->setPrivateData(DPL::StaticPointerCast<WrtDeviceApis::Commons::IEventPrivateData > (data));
488                 FilesystemAsyncCallbackManagerSingleton::Instance().registerCallbackManager(cbm, globalContext);
489
490                 IManager::getInstance().getNode(event);
491                 
492         } catch(const WrtDeviceApis::Commons::ConversionException& ex) {
493                 return JSTizenExceptionFactory::postException(context, exception, JSTizenException::TYPE_MISMATCH_ERROR, ex.GetMessage());
494         } catch(const WrtDeviceApis::Commons::NotFoundException& ex) {
495                 cbm->callOnError(JSTizenExceptionFactory::makeErrorObject(context, JSTizenException::NOT_FOUND_ERROR, ex.GetMessage()));
496         } catch (const WrtDeviceApis::Commons::UnsupportedException& ex) {
497                 return JSTizenExceptionFactory::postException(context, exception, JSTizenException::NOT_SUPPORTED_ERROR, ex.GetMessage());
498         } catch(const WrtDeviceApis::Commons::InvalidArgumentException& ex) {
499                 cbm->callOnError(JSTizenExceptionFactory::makeErrorObject(context, JSTizenException::INVALID_VALUES_ERROR, ex.GetMessage()));
500         } catch(const WrtDeviceApis::Commons::Exception& ex) {
501                 cbm->callOnError(JSTizenExceptionFactory::makeErrorObject(context, JSTizenException::UNKNOWN_ERROR, ex.GetMessage()));
502         }
503
504         return JSValueMakeUndefined(context);
505 }
506 }
507 }