diff --git a/b2g/chrome/content/shell.js b/b2g/chrome/content/shell.js index ca9eeadef2a3e..c111b71d51ee4 100644 --- a/b2g/chrome/content/shell.js +++ b/b2g/chrome/content/shell.js @@ -36,6 +36,10 @@ XPCOMUtils.defineLazyModuleGetter(this, "SystemAppProxy", XPCOMUtils.defineLazyModuleGetter(this, "Screenshot", "resource://gre/modules/Screenshot.jsm"); +/* +XPCOMUtils.defineLazyModuleGetter(this, "CloudStorage", + "resource://gre/modules/CloudStorage.jsm"); +*/ Cu.import('resource://gre/modules/Webapps.jsm'); DOMApplicationRegistry.allAppsLaunchable = true; @@ -354,6 +358,7 @@ var shell = { WebappsHelper.init(); UserAgentOverrides.init(); CaptivePortalLoginHelper.init(); +// CloudStorage.init(); this.contentBrowser.src = homeURL; this.isHomeLoaded = false; @@ -829,6 +834,7 @@ window.addEventListener('ContentStart', function ss_onContentStart() { if (e.detail.type !== 'take-screenshot') return; +/* try { shell.sendChromeEvent({ type: 'take-screenshot-success', @@ -841,6 +847,8 @@ window.addEventListener('ContentStart', function ss_onContentStart() { error: String(e) }); } +*/ +// CloudStorage.toggle(); }); }); diff --git a/b2g/installer/package-manifest.in b/b2g/installer/package-manifest.in index 38009786f9c3d..beb7b24e29304 100644 --- a/b2g/installer/package-manifest.in +++ b/b2g/installer/package-manifest.in @@ -176,7 +176,9 @@ #ifdef MOZ_WIDGET_GONK @RESPATH@/components/dom_wifi.xpt @RESPATH@/components/dom_system_gonk.xpt +@RESPATH@/components/dom_system_gonk_cloudstorage.xpt #endif + #ifdef MOZ_B2G_RIL @RESPATH@/components/dom_wappush.xpt @RESPATH@/components/dom_mobileconnection.xpt @@ -465,6 +467,8 @@ @RESPATH@/components/TetheringService.manifest @RESPATH@/components/WifiWorker.js @RESPATH@/components/WifiWorker.manifest +@RESPATH@/components/nsCloudStorageInterface.js +@RESPATH@/components/nsCloudStorageInterface.manifest #endif // MOZ_WIDGET_GONK ; Camera diff --git a/b2g/moz.build b/b2g/moz.build index 48ba17522361b..f0298dd8d98c8 100644 --- a/b2g/moz.build +++ b/b2g/moz.build @@ -15,4 +15,3 @@ if CONFIG['GAIADIR']: DIRS += ['gaia'] DIRS += ['app'] - diff --git a/dom/base/Navigator.cpp b/dom/base/Navigator.cpp index 64c638d71d62a..4641cfc7aa8d4 100644 --- a/dom/base/Navigator.cpp +++ b/dom/base/Navigator.cpp @@ -80,6 +80,9 @@ #ifdef MOZ_B2G_BT #include "BluetoothManager.h" #endif + +#include "nsCloudStorageService.h" + #include "DOMCameraManager.h" #ifdef MOZ_AUDIO_CHANNEL_MANAGER @@ -196,6 +199,7 @@ NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(Navigator) #ifdef MOZ_B2G_BT NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mBluetooth) #endif + NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mCloudStorageService) #ifdef MOZ_AUDIO_CHANNEL_MANAGER NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mAudioChannelManager) #endif @@ -304,6 +308,10 @@ Navigator::Invalidate() } #endif + if (mCloudStorageService) { + mCloudStorageService = nullptr; + } + mCameraManager = nullptr; if (mMessagesManager) { @@ -1859,6 +1867,19 @@ Navigator::GetMozBluetooth(ErrorResult& aRv) } #endif //MOZ_B2G_BT +cloudstorage::nsCloudStorageService* +Navigator::GetCloudStorageService(ErrorResult& aRv) +{ + if (!mCloudStorageService) { + if (!mWindow) { + aRv.Throw(NS_ERROR_UNEXPECTED); + return nullptr; + } + mCloudStorageService = cloudstorage::nsCloudStorageService::Create(mWindow); + } + return mCloudStorageService; +} + nsresult Navigator::EnsureMessagesManager() { diff --git a/dom/base/Navigator.h b/dom/base/Navigator.h index 38cd75d35eedc..97b97496e329b 100644 --- a/dom/base/Navigator.h +++ b/dom/base/Navigator.h @@ -83,6 +83,10 @@ class BluetoothManager; } // namespace bluetooth #endif // MOZ_B2G_BT +namespace cloudstorage { +class nsCloudStorageService; +} + #ifdef MOZ_B2G_RIL class MobileConnectionArray; #endif @@ -253,6 +257,7 @@ class Navigator final : public nsIDOMNavigator #ifdef MOZ_B2G_BT bluetooth::BluetoothManager* GetMozBluetooth(ErrorResult& aRv); #endif // MOZ_B2G_BT + cloudstorage::nsCloudStorageService* GetCloudStorageService(ErrorResult& aRv); #ifdef MOZ_TIME_MANAGER time::TimeManager* GetMozTime(ErrorResult& aRv); #endif // MOZ_TIME_MANAGER @@ -369,6 +374,7 @@ class Navigator final : public nsIDOMNavigator #ifdef MOZ_B2G_BT nsRefPtr mBluetooth; #endif + nsRefPtr mCloudStorageService; #ifdef MOZ_AUDIO_CHANNEL_MANAGER nsRefPtr mAudioChannelManager; #endif diff --git a/dom/base/moz.build b/dom/base/moz.build index e76c9e643bc79..b177110007ba8 100644 --- a/dom/base/moz.build +++ b/dom/base/moz.build @@ -405,6 +405,7 @@ FAIL_ON_WARNINGS = True LOCAL_INCLUDES += [ '../battery', '../bluetooth', + '../cloudstorage', '../events', '../media', '../network', diff --git a/dom/bindings/Bindings.conf b/dom/bindings/Bindings.conf index e148072ed6686..d82ef758f756b 100644 --- a/dom/bindings/Bindings.conf +++ b/dom/bindings/Bindings.conf @@ -282,6 +282,11 @@ DOMInterfaces = { 'headerFile': 'mozilla/dom/workers/bindings/ServiceWorkerClients.h', }, +'CloudStorageService': { + 'nativeType': 'mozilla::dom::cloudstorage::nsCloudStorageService', + 'headerFile': 'nsCloudStorageService.h', +}, + 'Console': { 'implicitJSContext': [ 'trace', 'time', 'timeEnd' ], }, @@ -660,6 +665,11 @@ DOMInterfaces = { 'notflattened': True }, +'InstallEvent': { + 'headerFile': 'ServiceWorkerEvents.h', + 'nativeType': 'mozilla::dom::workers::InstallEvent', +}, + 'KeyEvent': { 'concrete': False }, diff --git a/dom/cloudstorage/CloudStorageChild.cpp b/dom/cloudstorage/CloudStorageChild.cpp new file mode 100644 index 0000000000000..8ff0499a8ea12 --- /dev/null +++ b/dom/cloudstorage/CloudStorageChild.cpp @@ -0,0 +1,46 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* vim: set sw=4 ts=8 et tw=80 : */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#include "CloudStorageChild.h" +#include "CloudStorageRequestChild.h" +#include "mozilla/DebugOnly.h" +#include "CloudStorageLog.h" + +namespace mozilla { +namespace dom { +namespace cloudstorage { + +CloudStorageChild::CloudStorageChild() +{ +} + +CloudStorageChild::~CloudStorageChild() +{ +} + +PCloudStorageRequestChild* +CloudStorageChild::AllocPCloudStorageRequestChild(const CloudStorageRequest& request) +{ + LOG("CloudStorageChild::AllocPCloudStorageRequestChild()"); + MOZ_CRASH("should not be here"); +} + +bool +CloudStorageChild::DeallocPCloudStorageRequestChild(PCloudStorageRequestChild* aActor) +{ + LOG("CloudStorageChild::DeallocPCloudStorageRequestChild()"); + delete aActor; + return true; +} + +void +CloudStorageChild::ActorDestroy(ActorDestroyReason aWhy) +{ +} + +} // end cloudstorage +} // end dom +} // end mozilla diff --git a/dom/cloudstorage/CloudStorageChild.h b/dom/cloudstorage/CloudStorageChild.h new file mode 100644 index 0000000000000..3921325fa36d5 --- /dev/null +++ b/dom/cloudstorage/CloudStorageChild.h @@ -0,0 +1,43 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this file, + * You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#ifndef mozilla_dom_cloudstorage_CloudStorageChild_h +#define mozilla_dom_cloudstorage_CloudStorageChild_h + +#include "mozilla/Attributes.h" +#include "mozilla/dom/cloudstorage/PCloudStorageChild.h" +#include "mozilla/dom/cloudstorage/PCloudStorageRequestChild.h" +#include "mozilla/dom/ContentChild.h" +#include "mozilla/dom/ContentParent.h" + +namespace mozilla { +namespace dom { +namespace cloudstorage { + +class CloudStorageChild : public PCloudStorageChild +{ + friend class mozilla::dom::ContentChild; +public: + CloudStorageChild(); + +protected: + virtual ~CloudStorageChild(); + + virtual PCloudStorageRequestChild* + AllocPCloudStorageRequestChild(const CloudStorageRequest& request) override; + + virtual bool + DeallocPCloudStorageRequestChild(PCloudStorageRequestChild* aActor) override; + + virtual void + ActorDestroy(ActorDestroyReason aWhy) override; + +}; + +} // end cloudstorage +} // end dom +} // end mozilla + +#endif diff --git a/dom/cloudstorage/CloudStorageParent.cpp b/dom/cloudstorage/CloudStorageParent.cpp new file mode 100644 index 0000000000000..5b9de6e56ed37 --- /dev/null +++ b/dom/cloudstorage/CloudStorageParent.cpp @@ -0,0 +1,57 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* vim: set sw=4 ts=8 et tw=80 : */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#include "CloudStorageParent.h" +#include "CloudStorageRequestParent.h" +#include "CloudStorageLog.h" + +namespace mozilla { +namespace dom { +namespace cloudstorage { + +CloudStorageParent::CloudStorageParent() +{ +} + +CloudStorageParent::~CloudStorageParent() +{ +} + +void +CloudStorageParent::ActorDestroy(ActorDestroyReason aWhy) +{ +} + +PCloudStorageRequestParent* +CloudStorageParent::AllocPCloudStorageRequestParent(const CloudStorageRequest& aRequest) +{ + LOG("CloudStorageParent::AllocPCloudStorageRequestParent()"); + // non-used parameter aRequest + return new CloudStorageRequestParent(); +} + +bool +CloudStorageParent::DeallocPCloudStorageRequestParent(PCloudStorageRequestParent* aActor) +{ + LOG("CloudStorageParent::DeallocPCloudStorageRequestParent()"); + delete aActor; + return true; +} + +bool +CloudStorageParent::RecvPCloudStorageRequestConstructor(PCloudStorageRequestParent* aActor, + const CloudStorageRequest& aRequest) +{ + LOG("CloudStorageParent::RecvPCloudStorageRequestConstructor()"); + CloudStorageRequestParent* actor = static_cast(aActor); + return actor->HandleRequest(aRequest); +} + +} // end cloudstorage +} // end dom +} // end mozilla + + diff --git a/dom/cloudstorage/CloudStorageParent.h b/dom/cloudstorage/CloudStorageParent.h new file mode 100644 index 0000000000000..1d89e920ce5c8 --- /dev/null +++ b/dom/cloudstorage/CloudStorageParent.h @@ -0,0 +1,47 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this file, + * You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#ifndef mozilla_dom_cloudstorage_CloudStorageParent_h +#define mozilla_dom_cloudstorage_CloudStorageParent_h + +#include "mozilla/dom/cloudstorage/PCloudStorageParent.h" +#include "mozilla/dom/cloudstorage/PCloudStorageRequestParent.h" +#include "mozilla/dom/ContentChild.h" +#include "mozilla/dom/ContentParent.h" + +#include "mozilla/Attributes.h" + +namespace mozilla { +namespace dom { +namespace cloudstorage { + +class CloudStorageParent : public PCloudStorageParent +{ + friend class mozilla::dom::ContentParent; +public: + CloudStorageParent(); +protected: + virtual ~CloudStorageParent(); + + virtual PCloudStorageRequestParent* + AllocPCloudStorageRequestParent(const CloudStorageRequest& request) override; + + virtual bool + DeallocPCloudStorageRequestParent(PCloudStorageRequestParent* aActor) override; + + virtual bool + RecvPCloudStorageRequestConstructor(PCloudStorageRequestParent* aActor, + const CloudStorageRequest& request) override; + + virtual void + ActorDestroy(ActorDestroyReason aWhy) override; + +}; + +} // end cloudstorage +} // end dom +} // end mozilla + +#endif diff --git a/dom/cloudstorage/CloudStorageRequestChild.cpp b/dom/cloudstorage/CloudStorageRequestChild.cpp new file mode 100644 index 0000000000000..e7e21f4a237f5 --- /dev/null +++ b/dom/cloudstorage/CloudStorageRequestChild.cpp @@ -0,0 +1,48 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* vim: set sw=4 ts=8 et tw=80 : */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#include "CloudStorageRequestChild.h" +#include "CloudStorageLog.h" + +namespace mozilla { +namespace dom { +namespace cloudstorage { + +CloudStorageRequestChild::CloudStorageRequestChild() +{ +} + +CloudStorageRequestChild::~CloudStorageRequestChild() +{ +} + +void +CloudStorageRequestChild::ActorDestroy(ActorDestroyReason aWhy) +{ +} + +bool +CloudStorageRequestChild::Recv__delete__() +{ + LOG("CloudStorageRequestChild::Recv__delete__()"); + /* + MOZ_ASSERT(NS_IsMainThread()); + MOZ_ASSERT(mReplyRunnable); + + nsRefPtr replyRunnable; + mReplyRunnable.swap(replyRunnable); + + if (replyRunnable) { + // XXXbent Need to fix this, it copies unnecessarily. + replyRunnable->SetReply(new BluetoothReply(aReply)); + return NS_SUCCEEDED(NS_DispatchToCurrentThread(replyRunnable)); + } + */ + return true; +} +} // end cloudstorage +} // end dom +} // end mozilla diff --git a/dom/cloudstorage/CloudStorageRequestChild.h b/dom/cloudstorage/CloudStorageRequestChild.h new file mode 100644 index 0000000000000..3dd68c4fc5366 --- /dev/null +++ b/dom/cloudstorage/CloudStorageRequestChild.h @@ -0,0 +1,40 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this file, + * You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#ifndef mozilla_dom_cloudstorage_CloudStorageRequestChild_h +#define mozilla_dom_cloudstorage_CloudStorageRequestChild_h + +#include "mozilla/dom/cloudstorage/PCloudStorageRequestChild.h" +#include "mozilla/dom/ContentChild.h" +#include "mozilla/dom/ContentParent.h" +#include "mozilla/dom/cloudstorage/CloudStorageChild.h" + +#include "mozilla/Attributes.h" + +namespace mozilla { +namespace dom { +namespace cloudstorage { + +class CloudStorageRequestChild : public PCloudStorageRequestChild +{ + friend class mozilla::dom::ContentChild; + friend class mozilla::dom::cloudstorage::CloudStorageChild; +public: + CloudStorageRequestChild(); +protected: + virtual ~CloudStorageRequestChild(); + + virtual void + ActorDestroy(ActorDestroyReason aWhy) override; + + virtual bool + Recv__delete__() override; +}; + +} // end cloudstorage +} // end dom +} // end mozilla + +#endif diff --git a/dom/cloudstorage/CloudStorageRequestParent.cpp b/dom/cloudstorage/CloudStorageRequestParent.cpp new file mode 100644 index 0000000000000..8f1bd20d7c822 --- /dev/null +++ b/dom/cloudstorage/CloudStorageRequestParent.cpp @@ -0,0 +1,62 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* vim: set sw=4 ts=8 et tw=80 : */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#include "CloudStorageRequestParent.h" +#include "CloudStorageLog.h" +#include "CloudStorageManager.h" + +using namespace mozilla::system::cloudstorage; + +namespace mozilla { +namespace dom { +namespace cloudstorage { + +CloudStorageRequestParent::CloudStorageRequestParent() +{ +// might be need CloudStorageManager here +} + +CloudStorageRequestParent::~CloudStorageRequestParent() +{ +} + +bool +CloudStorageRequestParent::HandleRequest(const CloudStorageRequest& aRequest) +{ + LOG("CloudStorageRequestParent::HandleRequest"); + switch (aRequest.type()) { + case CloudStorageRequest::TEnableStorageRequest: { + // handle enable request here + LOG("Handle enable cloud storage request"); + EnableStorageRequest enableReq = aRequest.get_EnableStorageRequest(); + LOG("cloud name: %s, type: %d, accessToken: %s", NS_ConvertUTF16toUTF8(enableReq.cloudName()).get() + , enableReq.cloudType() + , NS_ConvertUTF16toUTF8(enableReq.accessToken()).get()); + CloudStorageManager::FindAddCloudStorageByName(NS_ConvertUTF16toUTF8(enableReq.cloudName())); + CloudStorageManager::StartCloudStorage(NS_ConvertUTF16toUTF8(enableReq.cloudName())); + return true; + } + case CloudStorageRequest::TDisableStorageRequest: { + // handle disable request here + LOG("Handle disable cloud storage request"); + DisableStorageRequest disableReq = aRequest.get_DisableStorageRequest(); + LOG("cloud name: %s", NS_ConvertUTF16toUTF8(disableReq.cloudName()).get()); + CloudStorageManager::StopCloudStorage(NS_ConvertUTF16toUTF8(disableReq.cloudName())); + return true; + } + default: MOZ_CRASH("Unknown type!"); return false; + } + return false; +} + +void +CloudStorageRequestParent::ActorDestroy(ActorDestroyReason aWhy) +{ +} + +} // end cloudstorage +} // end dom +} // end mozilla diff --git a/dom/cloudstorage/CloudStorageRequestParent.h b/dom/cloudstorage/CloudStorageRequestParent.h new file mode 100644 index 0000000000000..9694f60eaf8ef --- /dev/null +++ b/dom/cloudstorage/CloudStorageRequestParent.h @@ -0,0 +1,39 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this file, + * You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#ifndef mozilla_dom_cloudstorage_CloudStorageRequestParent_h +#define mozilla_dom_cloudstorage_CloudStorageRequestParent_h + +#include "mozilla/dom/cloudstorage/PCloudStorageRequestParent.h" +#include "mozilla/dom/ContentChild.h" +#include "mozilla/dom/ContentParent.h" +#include "mozilla/dom/cloudstorage/CloudStorageParent.h" +#include "mozilla/Attributes.h" + +namespace mozilla { +namespace dom { +namespace cloudstorage { + +class CloudStorageRequestParent : public PCloudStorageRequestParent +{ + friend class mozilla::dom::ContentParent; + friend class mozilla::dom::cloudstorage::CloudStorageParent; +public: + CloudStorageRequestParent(); +protected: + virtual ~CloudStorageRequestParent(); + + virtual void + ActorDestroy(ActorDestroyReason aWhy) override; + + bool + HandleRequest(const CloudStorageRequest& aRequest); +}; + +} // end cloudstorage +} // end dom +} // end mozilla + +#endif diff --git a/dom/cloudstorage/CloudStorageService.cpp b/dom/cloudstorage/CloudStorageService.cpp new file mode 100644 index 0000000000000..09374461b1bdf --- /dev/null +++ b/dom/cloudstorage/CloudStorageService.cpp @@ -0,0 +1,89 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* vim: set sw=4 ts=8 et tw=80 : */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#include "CloudStorageService.h" +#include "mozilla/dom/ContentChild.h" +#include "mozilla/dom/Promise.h" +#include "CloudStorageLog.h" + +namespace mozilla { +namespace dom { +namespace cloudstorage { + +CloudStorageService* CloudStorageService::sService = NULL; + +CloudStorageService::CloudStorageService() + : mCloudStorageChild(NULL) +{ + LOG("CloudStorageService constructor"); + mozilla::dom::ContentChild* contentChild = mozilla::dom::ContentChild::GetSingleton(); + MOZ_ASSERT(contentChild); + mCloudStorageChild = new CloudStorageChild(); + contentChild->SendPCloudStorageConstructor(mCloudStorageChild); +} + +CloudStorageService::~CloudStorageService() +{ +} +//static +CloudStorageService* +CloudStorageService::GetSingleton() +{ + LOG("CloudStorageService::GetSingleton()"); + if (sService == NULL) { + sService = new CloudStorageService(); + } + return sService; +} + +PCloudStorageChild* +CloudStorageService::GetCloudStorageChild() +{ + LOG("CloudStorageService::GetCloudStorageChild()"); + return mCloudStorageChild; +} + +nsresult +CloudStorageService::Enable(const nsString& aCloudName, const uint16_t aCloudType, const nsString& aToken, Promise* aPromise) +{ + LOG("CloudStorageService::Enable()"); + EnableStorageRequest request(aCloudName, aCloudType, aToken); + MOZ_ASSERT(NS_IsMainThread()); + CloudStorageRequestChildRunnable* enableRunnable = new CloudStorageRequestChildRunnable(request); + nsresult ret = NS_DispatchToCurrentThread(enableRunnable); + AutoSafeJSContext cx; + JS::Rooted v(cx, JS::BooleanValue(bool(true))); + aPromise->MaybeResolve(v); + return ret; +} + +nsresult +CloudStorageService::Disable(const nsString& aCloudName, Promise* aPromise) +{ + LOG("CloudStorageService::Disable()"); + DisableStorageRequest request(aCloudName); + MOZ_ASSERT(NS_IsMainThread()); + CloudStorageRequestChildRunnable* disableRunnable = new CloudStorageRequestChildRunnable(request); + nsresult ret = NS_DispatchToCurrentThread(disableRunnable); + AutoSafeJSContext cx; + JS::Rooted v(cx, JS::UndefinedValue()); + aPromise->MaybeResolve(v); + return ret; +} + +nsresult +CloudStorageService::CloudStorageRequestChildRunnable::Run() +{ + LOG("CloudStorageRequestChildRunnable::Run()"); + //if (XRE_GetProcessType() != GeckoProcessType_Default) { + PCloudStorageRequestChild* child = new CloudStorageRequestChild(); + CloudStorageService::GetSingleton()->GetCloudStorageChild()->SendPCloudStorageRequestConstructor(child, mRequest); + return NS_OK; +} + +} // end cloudstorage +} // end dom +} // end mozilla diff --git a/dom/cloudstorage/CloudStorageService.h b/dom/cloudstorage/CloudStorageService.h new file mode 100644 index 0000000000000..6a28894daa7fd --- /dev/null +++ b/dom/cloudstorage/CloudStorageService.h @@ -0,0 +1,62 @@ +/* -*- Mode: IDL; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#ifndef mozilla_dom_cloudstorage_CloudStorageService_h +#define mozilla_dom_cloudstorage_CloudStorageService_h + +#include "CloudStorageChild.h" +#include "nsString.h" +#include "nsIObserver.h" +#include "nsIThread.h" + +namespace mozilla { +namespace dom { + +class Promise; + +namespace cloudstorage { + +class CloudStorageService final +{ +public: + NS_INLINE_DECL_THREADSAFE_REFCOUNTING(CloudStorageService) + + static CloudStorageService* GetSingleton(); + + nsresult Enable(const nsString& aCloudName, const uint16_t aCloudType, const nsString& aToken, Promise* aPromise); + nsresult Disable(const nsString& aCloudName, Promise* aPromise); + +private: + CloudStorageService(); + ~CloudStorageService(); + + PCloudStorageChild* GetCloudStorageChild(); + + class CloudStorageRequestChildRunnable final : public nsRunnable + { + public: + CloudStorageRequestChildRunnable(const CloudStorageRequest& aRequest) + : mRequest(aRequest) + {} + + ~CloudStorageRequestChildRunnable() {} + + nsresult Run() override; + private: + void FireSuccess(); + private: + CloudStorageRequest mRequest; + }; + +private: + static CloudStorageService* sService; + + CloudStorageChild* mCloudStorageChild; +}; + +} +} +} +#endif diff --git a/dom/cloudstorage/PCloudStorage.ipdl b/dom/cloudstorage/PCloudStorage.ipdl new file mode 100644 index 0000000000000..f0610a9690bda --- /dev/null +++ b/dom/cloudstorage/PCloudStorage.ipdl @@ -0,0 +1,42 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this file, + * You can obtain one at http://mozilla.org/MPL/2.0/. */ + +include protocol PContent; +include protocol PCloudStorageRequest; + +namespace mozilla { +namespace dom { +namespace cloudstorage { + +struct EnableStorageRequest +{ + nsString cloudName; + uint16_t cloudType; + nsString accessToken; +}; + +struct DisableStorageRequest +{ + nsString cloudName; +}; + +union CloudStorageRequest +{ + EnableStorageRequest; + DisableStorageRequest; +}; + +protocol PCloudStorage +{ + manager PContent; + manages PCloudStorageRequest; +parent: + __delete__(); + PCloudStorageRequest(CloudStorageRequest request); +}; + +} +} +} diff --git a/dom/cloudstorage/PCloudStorageRequest.ipdl b/dom/cloudstorage/PCloudStorageRequest.ipdl new file mode 100644 index 0000000000000..fd8d3aec0e57b --- /dev/null +++ b/dom/cloudstorage/PCloudStorageRequest.ipdl @@ -0,0 +1,22 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this file, + * You can obtain one at http://mozilla.org/MPL/2.0/. */ + +include protocol PCloudStorage; + +namespace mozilla { +namespace dom { +namespace cloudstorage { + +protocol PCloudStorageRequest +{ + manager PCloudStorage; +child: + /* Send when the asynchronous request has completed */ + __delete__(); +}; + +} // end cloudstorage +} // end dom +} // end mozilla diff --git a/dom/cloudstorage/moz.build b/dom/cloudstorage/moz.build new file mode 100644 index 0000000000000..ec54cac73d202 --- /dev/null +++ b/dom/cloudstorage/moz.build @@ -0,0 +1,49 @@ +# -*- Mode: python; c-basic-offset: 4; indent-tabs-mode: nil; tab-width: 40 -*- +# vim: set filetype=python: +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. + +EXPORTS += [ + 'nsCloudStorageService.h', +] + +EXPORTS.mozilla.dom.cloudstorage += [ + 'CloudStorageChild.h', + 'CloudStorageParent.h', + 'CloudStorageRequestChild.h', + 'CloudStorageRequestParent.h', + 'CloudStorageService.h', +] + +UNIFIED_SOURCES += [ + 'CloudStorageChild.cpp', + 'CloudStorageParent.cpp', + 'CloudStorageRequestChild.cpp', + 'CloudStorageRequestParent.cpp', + 'CloudStorageService.cpp', + 'nsCloudStorageService.cpp', +] + +IPDL_SOURCES += [ + 'PCloudStorage.ipdl', + 'PCloudStorageRequest.ipdl', +] + +FAIL_ON_WARNINGS = True + +include('/ipc/chromium/chromium-config.mozbuild') + +FINAL_LIBRARY = 'xul' +LOCAL_INCLUDES += [ + '/dom/base', + '/dom/ipc', + '/dom/system/gonk/cloudstorage', + '/dom/system/gonk/cloudstorage/fuse', +] + +#MOCHITEST_MANIFESTS += [ +# 'ipc/mochitest.ini', +# 'test/mochitest.ini', +#] +#MOCHITEST_CHROME_MANIFESTS += ['test/chrome.ini'] diff --git a/dom/cloudstorage/nsCloudStorageService.cpp b/dom/cloudstorage/nsCloudStorageService.cpp new file mode 100644 index 0000000000000..a2158227ada60 --- /dev/null +++ b/dom/cloudstorage/nsCloudStorageService.cpp @@ -0,0 +1,89 @@ +/* -*- Mode: IDL; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#include "nsCloudStorageService.h" +#include "CloudStorageService.h" +#include "mozilla/ErrorResult.h" +#include "nsString.h" +#include "CloudStorageLog.h" + +using namespace mozilla; +using namespace mozilla::dom; + +namespace mozilla { +namespace dom { +namespace cloudstorage { + +//NS_IMPL_CYCLE_COLLECTION_INHERITED(nsCloudStorageService, DOMEventTargetHelper, __VA_ARGS__) +NS_IMPL_CYCLE_COLLECTION_CLASS(nsCloudStorageService) +NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN_INHERITED(nsCloudStorageService, DOMEventTargetHelper) +//NS_IMPL_CYCLE_COLLECTION_UNLINK(__VA_ARGS__) +NS_IMPL_CYCLE_COLLECTION_UNLINK_END +NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INHERITED(nsCloudStorageService, DOMEventTargetHelper) +//NS_IMPL_CYCLE_COLLECTION_TRAVERSE(__VA_ARGS__) +NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END +NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION_INHERITED(nsCloudStorageService) +NS_INTERFACE_MAP_END_INHERITING(DOMEventTargetHelper) +NS_IMPL_ADDREF_INHERITED(nsCloudStorageService, DOMEventTargetHelper) +NS_IMPL_RELEASE_INHERITED(nsCloudStorageService, DOMEventTargetHelper) + +nsCloudStorageService::nsCloudStorageService(nsPIDOMWindow* aWindow) + : DOMEventTargetHelper(aWindow) +{ + LOG("nsCloudStorageService constructor"); +} + +nsCloudStorageService::~nsCloudStorageService() +{ +} + +already_AddRefed +nsCloudStorageService::Create(nsPIDOMWindow* aWindow) +{ + LOG("nsCloudStorageService::Create"); + MOZ_ASSERT(NS_IsMainThread()); + MOZ_ASSERT(aWindow); + nsRefPtr service = new nsCloudStorageService(aWindow); + return service.forget(); +} + +JSObject* +nsCloudStorageService::WrapObject(JSContext* aCx, JS::Handle aGivenProto) +{ + return CloudStorageServiceBinding::Wrap(aCx, this, aGivenProto); +} + +already_AddRefed +nsCloudStorageService::Enable(const nsAString& aCloudName, CloudStorageType& aType, const nsAString& aAccessToken, ErrorResult& aRv) +{ + LOG("nsCloudStorageService::Enable()"); + nsCOMPtr global = do_QueryInterface(GetParentObject()); + if (!global) { + return nullptr; + } + ErrorResult errorResult; + nsRefPtr promise = Promise::Create(global, aRv); + CloudStorageService* css = CloudStorageService::GetSingleton(); + css->Enable(nsString(aCloudName), (uint16_t) aType, nsString(aAccessToken), promise); + return promise.forget(); +} + +already_AddRefed +nsCloudStorageService::Disable(const nsAString& aCloudName, ErrorResult& aRv) +{ + LOG("nsCloudStorageService::Disable()"); + nsCOMPtr global = do_QueryInterface(GetParentObject()); + if (!global) { + return nullptr; + } + nsRefPtr promise = Promise::Create(global, aRv); + CloudStorageService* css = CloudStorageService::GetSingleton(); + css->Disable(nsString(aCloudName), promise); + return promise.forget(); +} + +} // end cloudstorage +} // end dom +} // end mozilla diff --git a/dom/cloudstorage/nsCloudStorageService.h b/dom/cloudstorage/nsCloudStorageService.h new file mode 100644 index 0000000000000..c84875ec3e89f --- /dev/null +++ b/dom/cloudstorage/nsCloudStorageService.h @@ -0,0 +1,53 @@ +/* -*- Mode: IDL; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#ifndef mozilla_dom_cloudstorage_nsCloudStorageService_h +#define mozilla_dom_cloudstorage_nsCloudStorageService_h + +#include "mozilla/Attributes.h" +#include "mozilla/DOMEventTargetHelper.h" +#include "nsIObserver.h" +#include "nsPIDOMWindow.h" +#include "mozilla/dom/Promise.h" +#include "mozilla/dom/CloudStorageServiceBinding.h" +#include "mozilla/ErrorResult.h" +#include "nsCOMPtr.h" + +namespace mozilla { +namespace dom { +namespace cloudstorage { + +class nsCloudStorageService final : public DOMEventTargetHelper +{ +public: + + NS_DECL_ISUPPORTS_INHERITED + NS_DECL_CYCLE_COLLECTION_CLASS_INHERITED(nsCloudStorageService, DOMEventTargetHelper) + + //IMPL_EVENT_HANDLER(enable); + //IMPL_EVENT_HANDLER(disable); + + static already_AddRefed Create(nsPIDOMWindow* aWindow); + + nsPIDOMWindow* GetParentObject() const + { + return GetOwner(); + } + virtual JSObject* WrapObject(JSContext* aCx, JS::Handle aGivenProto) override; + + // WebIDL implementation + already_AddRefed Enable(const nsAString& aName, CloudStorageType& aType, const nsAString& aToken, ErrorResult& aRv); + already_AddRefed Disable(const nsAString& aName, ErrorResult& aRv); + +private: + nsCloudStorageService(nsPIDOMWindow* aWindow); + ~nsCloudStorageService(); + +}; + +} +} +} +#endif diff --git a/dom/ipc/ContentChild.cpp b/dom/ipc/ContentChild.cpp index 62c0350b4edcc..4bce41356db3d 100644 --- a/dom/ipc/ContentChild.cpp +++ b/dom/ipc/ContentChild.cpp @@ -170,6 +170,7 @@ #include "mozilla/dom/FileSystemTaskBase.h" #include "mozilla/dom/bluetooth/PBluetoothChild.h" #include "mozilla/dom/PFMRadioChild.h" +#include "mozilla/dom/cloudstorage/PCloudStorageChild.h" #include "mozilla/ipc/InputStreamUtils.h" #ifdef MOZ_WEBSPEECH @@ -197,6 +198,7 @@ using namespace mozilla; using namespace mozilla::docshell; using namespace mozilla::dom::bluetooth; using namespace mozilla::dom::cellbroadcast; +using namespace mozilla::dom::cloudstorage; using namespace mozilla::dom::devicestorage; using namespace mozilla::dom::icc; using namespace mozilla::dom::ipc; @@ -875,7 +877,6 @@ class MemoryReportCallback final : public nsIMemoryReporterCallback { public: NS_DECL_ISUPPORTS - explicit MemoryReportCallback(MemoryReportRequestChild* aActor, const nsACString& aProcess) : mActor(aActor) @@ -1829,6 +1830,19 @@ ContentChild::DeallocPWebrtcGlobalChild(PWebrtcGlobalChild *aActor) return true; } +PCloudStorageChild* +ContentChild::AllocPCloudStorageChild() +{ + MOZ_CRASH("No one should be allocating PCloudStorageChild actors"); + return nullptr; +} + +bool +ContentChild::DeallocPCloudStorageChild(PCloudStorageChild* aActor) +{ + delete aActor; + return true; +} bool ContentChild::RecvRegisterChrome(InfallibleTArray&& packages, diff --git a/dom/ipc/ContentChild.h b/dom/ipc/ContentChild.h index 139740418aded..2825c30ac40c8 100644 --- a/dom/ipc/ContentChild.h +++ b/dom/ipc/ContentChild.h @@ -281,6 +281,9 @@ class ContentChild final : public PContentChild virtual PSpeechSynthesisChild* AllocPSpeechSynthesisChild() override; virtual bool DeallocPSpeechSynthesisChild(PSpeechSynthesisChild* aActor) override; + virtual PCloudStorageChild* AllocPCloudStorageChild() override; + virtual bool DeallocPCloudStorageChild(PCloudStorageChild* aActor) override; + virtual bool RecvRegisterChrome(InfallibleTArray&& packages, InfallibleTArray&& resources, InfallibleTArray&& overrides, diff --git a/dom/ipc/ContentParent.cpp b/dom/ipc/ContentParent.cpp index 7a0a5aa358e10..deaa200326efa 100755 --- a/dom/ipc/ContentParent.cpp +++ b/dom/ipc/ContentParent.cpp @@ -64,6 +64,7 @@ #include "mozilla/dom/telephony/TelephonyParent.h" #include "mozilla/dom/time/DateCacheCleaner.h" #include "mozilla/dom/voicemail/VoicemailParent.h" +#include "mozilla/dom/cloudstorage/CloudStorageParent.h" #include "mozilla/embedding/printingui/PrintingParent.h" #include "mozilla/hal_sandbox/PHalParent.h" #include "mozilla/ipc/BackgroundChild.h" @@ -243,6 +244,7 @@ using namespace CrashReporter; #endif using namespace mozilla::dom::bluetooth; using namespace mozilla::dom::cellbroadcast; +using namespace mozilla::dom::cloudstorage; using namespace mozilla::dom::devicestorage; using namespace mozilla::dom::icc; using namespace mozilla::dom::indexedDB; @@ -3958,6 +3960,30 @@ ContentParent::RecvPSpeechSynthesisConstructor(PSpeechSynthesisParent* aActor) #endif } +PCloudStorageParent* +ContentParent::AllocPCloudStorageParent() +{ + return new mozilla::dom::cloudstorage::CloudStorageParent(); +} + +bool +ContentParent::DeallocPCloudStorageParent(PCloudStorageParent* aActor) +{ + delete aActor; + return true; +} + +bool +ContentParent::RecvPCloudStorageConstructor(PCloudStorageParent* aActor) +{ +/* + nsRefPtr btService = BluetoothService::Get(); + NS_ENSURE_TRUE(btService, false); + return static_cast(aActor)->InitWithService(btService); +*/ + return true; +} + bool ContentParent::RecvSpeakerManagerGetSpeakerStatus(bool* aValue) { diff --git a/dom/ipc/ContentParent.h b/dom/ipc/ContentParent.h index a0381c65509d3..2a659fbe85c45 100644 --- a/dom/ipc/ContentParent.h +++ b/dom/ipc/ContentParent.h @@ -660,6 +660,10 @@ class ContentParent final : public PContentParent virtual bool DeallocPSpeechSynthesisParent(PSpeechSynthesisParent* aActor) override; virtual bool RecvPSpeechSynthesisConstructor(PSpeechSynthesisParent* aActor) override; + virtual PCloudStorageParent* AllocPCloudStorageParent() override; + virtual bool DeallocPCloudStorageParent(PCloudStorageParent* aActor) override; + virtual bool RecvPCloudStorageConstructor(PCloudStorageParent* aActor) override; + virtual bool RecvReadPrefsArray(InfallibleTArray* aPrefs) override; virtual bool RecvReadFontList(InfallibleTArray* retValue) override; @@ -846,7 +850,6 @@ class ContentParent final : public PContentParent virtual bool DeallocPDocAccessibleParent(PDocAccessibleParent*) override; virtual bool RecvPDocAccessibleConstructor(PDocAccessibleParent* aDoc, PDocAccessibleParent* aParentDoc, const uint64_t& aParentID) override; - virtual PWebrtcGlobalParent* AllocPWebrtcGlobalParent() override; virtual bool DeallocPWebrtcGlobalParent(PWebrtcGlobalParent *aActor) override; diff --git a/dom/ipc/PContent.ipdl b/dom/ipc/PContent.ipdl index b19f0d26a1525..d599590100906 100644 --- a/dom/ipc/PContent.ipdl +++ b/dom/ipc/PContent.ipdl @@ -51,6 +51,7 @@ include protocol PVoicemail; include protocol PJavaScript; include protocol PRemoteSpellcheckEngine; include protocol PWebrtcGlobal; +include protocol PCloudStorage; include DOMTypes; include JavaScriptTypes; include InputStreamParams; @@ -445,6 +446,7 @@ prio(normal upto urgent) sync protocol PContent manages PJavaScript; manages PRemoteSpellcheckEngine; manages PWebrtcGlobal; + manages PCloudStorage; both: // Depending on exactly how the new browser is being created, it might be @@ -766,6 +768,7 @@ parent: PAsmJSCacheEntry(OpenMode openMode, WriteParams write, Principal principal); PWebrtcGlobal(); + PCloudStorage(); // Services remoting diff --git a/dom/ipc/moz.build b/dom/ipc/moz.build index 3a8111613f7d9..1fad591da83c8 100644 --- a/dom/ipc/moz.build +++ b/dom/ipc/moz.build @@ -124,6 +124,7 @@ LOCAL_INCLUDES += [ '/docshell/base', '/dom/base', '/dom/bluetooth', + '/dom/cloudstorage', '/dom/devicestorage', '/dom/filesystem', '/dom/fmradio/ipc', diff --git a/dom/moz.build b/dom/moz.build index 0855743eeec94..b84b844bc8eca 100644 --- a/dom/moz.build +++ b/dom/moz.build @@ -111,6 +111,7 @@ DIRS += [ 'resourcestats', 'manifest', 'vr', + 'cloudstorage', ] if CONFIG['OS_ARCH'] == 'WINNT': diff --git a/dom/system/gonk/AutoMounter.cpp b/dom/system/gonk/AutoMounter.cpp index 6f1a4c6df98f4..5fdb5c61fe76d 100644 --- a/dom/system/gonk/AutoMounter.cpp +++ b/dom/system/gonk/AutoMounter.cpp @@ -40,8 +40,11 @@ #include "VolumeManager.h" #include "nsIStatusReporter.h" +#include "CloudStorageManager.h" + using namespace mozilla::hal; USING_MTP_NAMESPACE +using namespace mozilla::system::cloudstorage; /************************************************************************** * @@ -1396,6 +1399,7 @@ static StaticRefPtr sAutoMounterSetting; void InitAutoMounter() { + InitCloudStorageManager(); InitVolumeManager(); sAutoMounterSetting = new AutoMounterSetting(); diff --git a/dom/system/gonk/VolumeManager.cpp b/dom/system/gonk/VolumeManager.cpp index bd6c58c0e4ab9..1f228a57cb2e4 100644 --- a/dom/system/gonk/VolumeManager.cpp +++ b/dom/system/gonk/VolumeManager.cpp @@ -155,6 +155,21 @@ VolumeManager::FindAddVolumeByName(const nsCSubstring& aName) return vol; } +//static +void +VolumeManager::RemoveVolumeByName(const nsCSubstring& aName) +{ + VolumeArray::size_type numVolumes = NumVolumes(); + VolumeArray::index_type volIndex; + for (volIndex = 0; volIndex < numVolumes; volIndex++) { + RefPtr vol = GetVolume(volIndex); + if (vol->Name().Equals(aName)) { + break; + } + } + sVolumeManager->mVolumeArray.RemoveElementAt(volIndex); +} + //static void VolumeManager::InitConfig() { diff --git a/dom/system/gonk/VolumeManager.h b/dom/system/gonk/VolumeManager.h index 9fbf53003ec0f..725a025cac303 100644 --- a/dom/system/gonk/VolumeManager.h +++ b/dom/system/gonk/VolumeManager.h @@ -128,6 +128,7 @@ class VolumeManager final : public MessageLoopForIO::LineWatcher static TemporaryRef GetVolume(VolumeArray::index_type aIndex); static TemporaryRef FindVolumeByName(const nsCSubstring& aName); static TemporaryRef FindAddVolumeByName(const nsCSubstring& aName); + static void RemoveVolumeByName(const nsCSubstring& aName); static void InitConfig(); static void PostCommand(VolumeCommand* aCommand); diff --git a/dom/system/gonk/cloudstorage/CloudStorage.cpp b/dom/system/gonk/cloudstorage/CloudStorage.cpp new file mode 100644 index 0000000000000..99a07815d74f8 --- /dev/null +++ b/dom/system/gonk/cloudstorage/CloudStorage.cpp @@ -0,0 +1,308 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this file, + * You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#include "CloudStorage.h" + +#include +#include +#include +#include + +#include "CloudStorageLog.h" +#include "CloudStorageRequestHandler.h" +#include "Volume.h" +#include "VolumeManager.h" +#include "nsThreadUtils.h" + +namespace mozilla { +namespace system { +namespace cloudstorage { + +class CloudStorageRunnable : public nsRunnable +{ +public: + CloudStorageRunnable(CloudStorage* aCloudStorage) + : mCloudStorage(aCloudStorage) + { + } + + nsresult Run() + { + CloudStorageRequestHandler* handler = new CloudStorageRequestHandler(mCloudStorage); + if (handler) { + RefPtr vol = VolumeManager::FindAddVolumeByName(mCloudStorage->Name()); + vol->SetFakeVolume(mCloudStorage->MountPoint()); + VolumeManager::Dump("CloudStorage"); + handler->HandleRequests(); + } else { + LOG("Construct cloud storage handler fail"); + } + VolumeManager::RemoveVolumeByName(mCloudStorage->Name()); + VolumeManager::Dump("CloudStorage"); + LOG("going to finish RequestHandler."); + return NS_OK; + } + +private: + CloudStorage* mCloudStorage; +}; + +CloudStorage::CloudStorage(const nsCString& aCloudStorageName) + : mCloudStorageName(aCloudStorageName), + mMountPoint(""), + mState(CloudStorage::STATE_READY), + mWaitForRequest(false), + mRequestData(), + mResponseData(), + mNodeHashTable(), + mPathHashTable(), + mAttrHashTable(), + mEntryListHashTable(), + mBuffer(NULL), + mBufferSize(-1) +{ + mMountPoint.Append("/data/cloud"); + if ( -1 == mkdir(mMountPoint.get(), S_IRWXU|S_IRWXG)) { + switch (errno) { + case EEXIST: LOG("%s existed.", mMountPoint.get()); break; + case ENOTDIR: LOG("Parent not a directory."); break; + case EACCES: LOG("Search permission is denied."); break; + case EROFS: LOG("Read-only filesystem."); break; + default: LOG("Create %s failed with errno: %d.", mMountPoint.get(), errno); + } + } else { + LOG("%s is created.", mMountPoint.get()); + } + mMountPoint.Append("/"); + mMountPoint.Append(mCloudStorageName); + if ( -1 == mkdir(mMountPoint.get(), S_IRWXU|S_IRWXG)) { + switch (errno) { + case EEXIST: LOG("%s existed.", mMountPoint.get()); break; + case ENOTDIR: LOG("Parent not a directory."); break; + case EACCES: LOG("Search permission is denied."); break; + case EROFS: LOG("Read-only filesystem."); break; + default: LOG("Create %s failed with errno: %d.", mMountPoint.get(), errno); + } + } else { + LOG("%s is created.", mMountPoint.get()); + } + mNodeHashTable.Put(1, NS_LITERAL_CSTRING("/")); + mPathHashTable.Put(NS_LITERAL_CSTRING("/"), 1); +} + +CloudStorage::~CloudStorage() +{ + if (mBuffer != NULL) { + free(mBuffer); + } +} + +//static +const char* CloudStorage::StateStr(const CloudStorage::eState& aState) +{ + switch (aState) { + case CloudStorage::STATE_READY: return "STATE_READY"; + case CloudStorage::STATE_RUNNING: return "STATE_RUNNING"; + default: return "STATE_UNKNOWN"; + } + return "STATE_UNKNOWN"; +} + +void +CloudStorage::StartStorage() +{ + if (mState == CloudStorage::STATE_RUNNING) + return; + + mState = CloudStorage::STATE_RUNNING; + mWaitForRequest = false; + LOG("Start cloud storage %s", mCloudStorageName.get()); + nsresult rv = NS_NewNamedThread("CloudStorage", getter_AddRefs(mRunnableThread)); + if (NS_WARN_IF(NS_FAILED(rv))) { + return; + } + MOZ_ASSERT(mRunnableThread); + mRunnableThread->Dispatch(new CloudStorageRunnable(this), NS_DISPATCH_NORMAL); +} + +void +CloudStorage::StopStorage() +{ + if (mState == CloudStorage::STATE_READY) + return; + LOG("Stop cloud storage %s", mCloudStorageName.get()); + mState = CloudStorage::STATE_READY; + mWaitForRequest = false; +} + +nsCString +CloudStorage::GetPathByNId(uint64_t aKey) +{ + nsCString path; + if (mNodeHashTable.Get(aKey, &path)) { + return path; + } else { + return NS_LITERAL_CSTRING(""); + } +} + +void +CloudStorage::PutPathByNId(uint64_t aKey, nsCString aPath) +{ + mNodeHashTable.Put(aKey, aPath); +} + +void +CloudStorage::RemovePathByNId(uint64_t aKey) +{ + mNodeHashTable.Remove(aKey); +} + +uint64_t +CloudStorage::GetNIdByPath(nsCString aKey) +{ + uint64_t NId; + if (mPathHashTable.Get(aKey, &NId)) { + return NId; + } else { + return 0; + } +} + +void +CloudStorage::PutNIdByPath(nsCString aKey, uint64_t aNId) +{ + mPathHashTable.Put(aKey, aNId); +} + +void +CloudStorage::RemoveNIdByPath(nsCString aKey) +{ + mPathHashTable.Remove(aKey); +} + +FuseAttr +CloudStorage::GetAttrByPath(nsCString aPath) +{ + FuseAttr res; + if (!mAttrHashTable.Get(aPath, &res)) { + LOG("No attr for path %s", aPath.get()); + res.size = 0; + } + return res; +} + +FuseAttr +CloudStorage::CreateAttr(bool aIsDir, uint64_t aSize, uint64_t aMTime, uint64_t aCTime) +{ + FuseAttr attr; + if (aIsDir) { + attr.size = 4096; + attr.blocks = 8; + attr.blksize = 512; + attr.mode = 0x41ff; + } else { + attr.size = aSize; + attr.blocks = aSize/512; + attr.blksize = 512; + attr.mode = 0x81fd; + } + if (aMTime != 0 && aCTime != 0) { + attr.atime = aMTime/1000; + attr.mtime = aMTime/1000; + attr.ctime = aCTime/1000; + } else { + attr.atime = time(NULL); + attr.mtime = attr.atime; + attr.ctime = attr.ctime; + } + attr.uid = 0; + attr.gid = 1015; + + return attr; +} + +void +CloudStorage::SetAttrByPath(nsCString aPath, bool aIsDir, uint64_t aSize, uint64_t aMTime, uint64_t aCTime) +{ + FuseAttr attr = CreateAttr(aIsDir, aSize, aMTime, aCTime); + mAttrHashTable.Put(aPath, attr); +} + +void +CloudStorage::RemoveAttrByPath(nsCString aPath) +{ + mAttrHashTable.Remove(aPath); +} + +void +CloudStorage::AddEntryByPath(nsCString aPath, nsCString aEntry) +{ + nsTArray entryList; + if (!mEntryListHashTable.Get(aPath, &entryList)) { + LOG("No entry list for path %s", aPath.get()); + } + nsTArray::size_type numEntries = entryList.Length(); + nsTArray::index_type entryIndex; + for (entryIndex = 0; entryIndex < numEntries; ++entryIndex) { + if (entryList[entryIndex].Equals(aEntry)) { + return; + } + } + entryList.AppendElement(aEntry); + mEntryListHashTable.Put(aPath, entryList); +} + +void +CloudStorage::RemoveEntryByPath(nsCString aPath, nsCString aEntry) +{ + nsTArray entryList; + if (!mEntryListHashTable.Get(aPath, &entryList)) { + LOG("No entry list for path %s", aPath.get()); + return; + } + nsTArray::size_type numEntries = entryList.Length(); + nsTArray::index_type entryIndex; + for (entryIndex = 0; entryIndex < numEntries; ++entryIndex) { + if (entryList[entryIndex].Equals(aEntry)) { + entryList.RemoveElementAt(entryIndex); + } + } + if (entryList.Length() != 0) { + mEntryListHashTable.Put(aPath, entryList); + } else { + mEntryListHashTable.Remove(aPath); + } +} + +nsCString +CloudStorage::GetEntryByPathAndOffset(nsCString aPath, uint64_t aOffset) +{ + nsTArray entryList; + if (mEntryListHashTable.Get(aPath, &entryList)) { + if (aOffset >= entryList.Length()) { + return NS_LITERAL_CSTRING(""); + } + return entryList[aOffset]; + } + return NS_LITERAL_CSTRING(""); +} + +void +CloudStorage::SetDataBuffer(const char* aBuffer, int32_t aSize) +{ + LOG("buffer size: %d", aSize); + mBufferSize = aSize; + if (mBuffer != NULL) { + free(mBuffer); + } + mBuffer = (char*) malloc(sizeof(char)*aSize); + memset(mBuffer, 0, aSize); + memcpy(mBuffer, aBuffer, aSize); +} + +} // end namespace cloudstorage +} // end namespace system +} // end namespace mozilla + diff --git a/dom/system/gonk/cloudstorage/CloudStorage.h b/dom/system/gonk/cloudstorage/CloudStorage.h new file mode 100644 index 0000000000000..063903bb13a77 --- /dev/null +++ b/dom/system/gonk/cloudstorage/CloudStorage.h @@ -0,0 +1,146 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this file, + * You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#ifndef mozilla_system_cloudstorage_h_ +#define mozilla_system_cloudstorage_h_ + +#include "nsString.h" +#include "nsIThread.h" +#include "nsCOMPtr.h" +#include "nsRefPtr.h" +#include "nsDataHashtable.h" +#include "nsTArray.h" +#include "fuse.h" + +namespace mozilla { +namespace system { +namespace cloudstorage { + +class CloudStorageRequestData final +{ +public: + NS_INLINE_DECL_REFCOUNTING(CloudStorageRequestData) + CloudStorageRequestData() + : RequestID(0), + RequestType(0), + Path(""), + Handle(0), + Offset(0), + NodeId(0), + Size(-1), + RawData(NULL) + {} + + uint64_t RequestID; + uint32_t RequestType; + nsCString Path; + uint64_t Handle; + uint64_t Offset; + uint64_t NodeId; + uint32_t Size; + void* RawData; +}; + +class CloudStorageResponseData final +{ +public: + NS_INLINE_DECL_REFCOUNTING(CloudStorageResponseData) + CloudStorageResponseData() + : ResponseID(0), + IsDir(false), + FileSize(0), + MTime(0), + CTime(0), + EntryName(""), + EntryType(0), + Size(-1), + RawData(NULL) + {} + + uint64_t ResponseID; + bool IsDir; + uint64_t FileSize; + uint64_t MTime; + uint64_t CTime; + nsCString EntryName; + uint32_t EntryType; + int32_t Size; + void* RawData; +}; + +class CloudStorage final +{ +public: +// NS_INLINE_DECL_REFCOUNTING(CloudStorage) + NS_INLINE_DECL_THREADSAFE_REFCOUNTING(CloudStorage) + + CloudStorage(const nsCString& aCloudStorageName); + ~CloudStorage(); + +public: + enum eState { + STATE_READY = 0, + STATE_RUNNING = 1 + }; + + const nsCString& Name() { return mCloudStorageName; } + const char* NameStr() { return mCloudStorageName.get(); } + const nsCString& MountPoint() { return mMountPoint; } + const char* MountPointStr() { return mMountPoint.get(); } + static const char* StateStr(const CloudStorage::eState& aState); + const CloudStorage::eState& State() { return mState; } + const char* StateStr() { return StateStr(mState); } + bool IsWaitForRequest() { return mWaitForRequest; } + void SetWaitForRequest(const bool aWait) { mWaitForRequest = aWait; } + void SetRequestData(const CloudStorageRequestData& aData) { mRequestData = aData; } + CloudStorageRequestData RequestData() { return mRequestData; } + void SetResponseData(const CloudStorageResponseData& aData) { mResponseData = aData; } + CloudStorageResponseData ResponseData() { return mResponseData; } + + + nsCString GetPathByNId(uint64_t aKey); + void PutPathByNId(uint64_t aKey, nsCString aPath); + void RemovePathByNId(uint64_t aKey); + uint64_t GetNIdByPath(nsCString aKey); + void PutNIdByPath(nsCString aKey, uint64_t aNId); + void RemoveNIdByPath(nsCString aKey); + + FuseAttr GetAttrByPath(nsCString aPath); + void SetAttrByPath(nsCString aPath, bool aIsDir, uint64_t aSize, uint64_t aMTime, uint64_t aCTime); + void RemoveAttrByPath(nsCString aPath); + + nsCString GetEntryByPathAndOffset(nsCString aPath, uint64_t aOffset); + void AddEntryByPath(nsCString aPath, nsCString aEntry); + void RemoveEntryByPath(nsCString aPath, nsCString aEntry); + + void StartStorage(); + void StopStorage(); + + void SetDataBuffer(const char* buffer, int32_t size); + const char* DataBuffer() { return mBuffer; } + int32_t DataBufferSize() { return mBufferSize; } + +private: + + FuseAttr CreateAttr(bool aIsDir, uint64_t aSize, uint64_t aMTime, uint64_t aCTime); + + nsCString mCloudStorageName; + nsCString mMountPoint; + eState mState; + nsCOMPtr mRunnableThread; + bool mWaitForRequest; + CloudStorageRequestData mRequestData; + CloudStorageResponseData mResponseData; + nsDataHashtable mNodeHashTable; + nsDataHashtable mPathHashTable; + nsDataHashtable mAttrHashTable; + nsDataHashtable > mEntryListHashTable; + char* mBuffer; + int32_t mBufferSize; +}; + +} // end namespace cloudstorage +} // end namespace system +} // end namespace mozilla +#endif diff --git a/dom/system/gonk/cloudstorage/CloudStorage.jsm b/dom/system/gonk/cloudstorage/CloudStorage.jsm new file mode 100644 index 0000000000000..e7d06c610489a --- /dev/null +++ b/dom/system/gonk/cloudstorage/CloudStorage.jsm @@ -0,0 +1,64 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this file, + * You can obtain one at http://mozilla.org/MPL/2.0/. */ + +'use strict'; + +const { classes: Cc, interfaces: Ci, utils: Cu } = Components; + +Cu.import('resource://gre/modules/XPCOMUtils.jsm'); +Cu.import('resource://gre/modules/Sample.jsm'); +Cu.import('resource://gre/modules/Dropbox.jsm'); +Cu.import('resource://gre/modules/udManager.jsm'); +Cu.import('resource://gre/modules/MetaCache.jsm'); +Cu.import('resource://gre/modules/DataCache.jsm'); +const { console } = Cu.import("resource://gre/modules/devtools/Console.jsm", {}); + +let CloudStorage = { + init: function cloudstorage_init(){ + console.log('cloudstorage_init'); + this.status = false; + + udManager.init({ + accessToken: + 'SAMPLE_ACCESS_TOKEN', + webStorageModule: Dropbox, + metaCacheModule: MetaCache, + dataCacheModule: DataCache + }); + + }, + enable: function cloudstorage_enable() { + console.log('cloudstorage_enable'); + if (!this.status) { + this.status = true; + + udManager.getFileMeta('/', function (error, response) { + console.log(JSON.stringify(response.data)); + }); + + udManager.getFileList('/', function (error, response) { + console.log(JSON.stringify(response.data)); + }); + + console.log('CloudStorage is enabled.'); + } else { + console.log('CloudStorage had already been enabled.'); + } + }, + disable: function cloudstorage_disable() { + console.log('cloudstorage_disable'); + if (this.status) { + this.status = false; + console.log('CloudStorage is disabled.'); + } else { + console.log('CloudStorage had already been disabled.'); + } + }, + toggle: function cloudstorage_toggle() { + console.log('cloudstorage_toggle'); + this.status ? this.disable() : this.enable(); + } +}; +this.EXPORTED_SYMBOLS = ['CloudStorage']; +this.CloudStorage = CloudStorage; diff --git a/dom/system/gonk/cloudstorage/CloudStorageLog.h b/dom/system/gonk/cloudstorage/CloudStorageLog.h new file mode 100644 index 0000000000000..1be9f9867a504 --- /dev/null +++ b/dom/system/gonk/cloudstorage/CloudStorageLog.h @@ -0,0 +1,27 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this file, + * You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#ifndef mozilla_system_cloudstoragelog_h__ +#define mozilla_system_cloudstoragelog_h__ + +#undef USE_DEBUG +#define USE_DEBUG 0 + +#if !defined(CLOUD_STORAGE_LOG_TAG) +#define CLOUD_STORAGE_LOG_TAG "CloudStorage" +#endif + +#undef LOG +#undef ERR +#define LOG(args...) __android_log_print(ANDROID_LOG_INFO, CLOUD_STORAGE_LOG_TAG, ## args) +#define ERR(args...) __android_log_print(ANDROID_LOG_ERROR, CLOUD_STORAGE_LOG_TAG, ## args) + +#undef DBG +#if USE_DEBUG +#define DBG(args...) __android_log_print(ANDROID_LOG_DEBUG, CLOUD_STORAGE_LOG_TAG, ## args) +#else +#define DBG(args...) +#endif + +#endif // mozilla_system_cloudstoragelog_h__ diff --git a/dom/system/gonk/cloudstorage/CloudStorageManager.cpp b/dom/system/gonk/cloudstorage/CloudStorageManager.cpp new file mode 100644 index 0000000000000..0fad8ee85b086 --- /dev/null +++ b/dom/system/gonk/cloudstorage/CloudStorageManager.cpp @@ -0,0 +1,117 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this file, + * You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#include "CloudStorageManager.h" +#include "CloudStorageLog.h" +#include "mozilla/StaticPtr.h" + +namespace mozilla { +namespace system { +namespace cloudstorage { + +static StaticRefPtr sCloudStorageManager; + +CloudStorageManager::CloudStorageManager() +{ + LOG("CloudStorageManager constructor called"); +} + +CloudStorageManager::~CloudStorageManager() +{ +} + +//static +size_t +CloudStorageManager::NumCloudStorages() +{ + if (!sCloudStorageManager) { + return 0; + } + return sCloudStorageManager->mCloudStorageArray.Length(); +} + +//static +TemporaryRef +CloudStorageManager::GetCloudStorage(size_t aIndex) +{ + MOZ_ASSERT(aIndex < NumCloudStorages()); + return sCloudStorageManager->mCloudStorageArray[aIndex]; +} + +//static +TemporaryRef +CloudStorageManager::FindCloudStorageByName(const nsCSubstring& aName) +{ + if (!sCloudStorageManager) { + return nullptr; + } + CloudStorageArray::size_type numCloudStorages = NumCloudStorages(); + CloudStorageArray::index_type csIndex; + for (csIndex = 0; csIndex < numCloudStorages; csIndex++) { + RefPtr cs = GetCloudStorage(csIndex); + if (cs->Name().Equals(aName)) { + return cs; + } + } + return nullptr; +} + +//static +TemporaryRef +CloudStorageManager::FindAddCloudStorageByName(const nsCSubstring& aName) +{ + RefPtr cs = FindCloudStorageByName(aName); + if (cs) { + return cs; + } + // No cloudstorage found, create and add a new one. + cs = new CloudStorage(nsCString(aName)); + sCloudStorageManager->mCloudStorageArray.AppendElement(cs); + return cs; +} + +//static +bool +CloudStorageManager::StartCloudStorage(const nsCSubstring& aName) +{ + RefPtr cs = FindCloudStorageByName(aName); + if (!cs) { + LOG("Specified cloud storage '%s' does not exist.", nsCString(aName).get()); + return false; + } + if (cs->State() != CloudStorage::STATE_READY) { + LOG("Specified cloud storage already executed."); + return false; + } + cs->StartStorage(); + return true; +} + +//static +bool +CloudStorageManager::StopCloudStorage(const nsCSubstring& aName) +{ + RefPtr cs = FindCloudStorageByName(aName); + if (!cs) { + LOG("Specified cloud storage '%s' does not exist.", nsCString(aName).get()); + return false; + } + if (cs->State() != CloudStorage::STATE_RUNNING) { + LOG("Specified cloud storage already stopped."); + return false; + } + cs->StopStorage(); + return true; +} + +void +InitCloudStorageManager() +{ + MOZ_ASSERT(!sCloudStorageManager); + sCloudStorageManager = new CloudStorageManager(); +} + +} // end namespace cloudstorage +} // end namespace system +} // end namespace mozilla diff --git a/dom/system/gonk/cloudstorage/CloudStorageManager.h b/dom/system/gonk/cloudstorage/CloudStorageManager.h new file mode 100644 index 0000000000000..463101b175ec4 --- /dev/null +++ b/dom/system/gonk/cloudstorage/CloudStorageManager.h @@ -0,0 +1,44 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this file, + * You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#ifndef mozilla_system_cloudstoragemanager_h__ +#define mozilla_system_cloudstoragemanager_h__ + +#include "nsString.h" +#include "nsTArray.h" +#include "CloudStorage.h" + +namespace mozilla { +namespace system { +namespace cloudstorage { + +class CloudStorageManager +{ +public: + NS_INLINE_DECL_REFCOUNTING(CloudStorageManager) + + CloudStorageManager(); + ~CloudStorageManager(); + + typedef nsTArray> CloudStorageArray; + + static CloudStorageArray::size_type NumCloudStorages(); + static TemporaryRef GetCloudStorage(CloudStorageArray::index_type aIndex); + static TemporaryRef FindCloudStorageByName(const nsCSubstring& aName); + static TemporaryRef FindAddCloudStorageByName(const nsCSubstring& aName); + + static bool StartCloudStorage(const nsCSubstring& aName); + static bool StopCloudStorage(const nsCSubstring& aName); + +private: + + CloudStorageArray mCloudStorageArray; +}; + +void InitCloudStorageManager(); + +} // end namespace cloudstorage +} // end namespace system +} // end namespace mozilla +#endif diff --git a/dom/system/gonk/cloudstorage/CloudStorageRequestHandler.cpp b/dom/system/gonk/cloudstorage/CloudStorageRequestHandler.cpp new file mode 100644 index 0000000000000..18791e99644bb --- /dev/null +++ b/dom/system/gonk/cloudstorage/CloudStorageRequestHandler.cpp @@ -0,0 +1,870 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this file, + * You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#include "CloudStorageRequestHandler.h" +#include "CloudStorageLog.h" +#include "CloudStorage.h" + +//#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "nsICloudStorageInterface.h" +#include "mozilla/Services.h" +#include "nsCOMPtr.h" + +namespace mozilla { +namespace system { +namespace cloudstorage { + +class CloudStorageRequestRunnable : public nsRunnable +{ +public: + CloudStorageRequestRunnable(CloudStorage* aCloudStorage) + : mCloudStorage(aCloudStorage) + { + } + + nsresult Run() + { + nsresult rv; + if (!mInterface) { + nsCOMPtr mInterface = do_CreateInstance("@mozilla.org/cloudstorageinterface;1", &rv); + if (NS_FAILED(rv)) { + LOG("fail to get cloudstorageinterface [%x]", rv); + if (mCloudStorage->IsWaitForRequest()) { + mCloudStorage->SetWaitForRequest(false); + } + return NS_OK; + } + } + switch (mCloudStorage->RequestData().RequestType) { + case FUSE_GETATTR: { + rv = mInterface->GetFileMeta(mCloudStorage->Name(), mCloudStorage->RequestData().Path); + if (NS_FAILED(rv)) { + LOG("fail to call cloudstorageinterface->GetFileMeta(%s) [%x]", mCloudStorage->RequestData().Path.get(), rv); + } + break; + } + case FUSE_READDIR: { + rv = mInterface->GetFileList(mCloudStorage->Name(), mCloudStorage->RequestData().Path); + if (NS_FAILED(rv)) { + LOG("fail to call cloudstorageinterface->GetFileList(%s) [%x]", mCloudStorage->RequestData().Path.get(), rv); + } + break; + } + case FUSE_READ: { + rv = mInterface->GetData(mCloudStorage->Name(), + mCloudStorage->RequestData().Path, + mCloudStorage->RequestData().Size, + mCloudStorage->RequestData().Offset); + if (NS_FAILED(rv)) { + LOG("fail to call cloudstroageinterface->GetData(%s, %u, %llu) [%x]", mCloudStorage->RequestData().Path.get(), mCloudStorage->RequestData().Size, mCloudStorage->RequestData().Offset, rv); + } + break; + } + default: { + LOG("Unknown request type [%u]", mCloudStorage->RequestData().RequestType); + if (mCloudStorage->IsWaitForRequest()) { + mCloudStorage->SetWaitForRequest(false); + } + } + } + return NS_OK; + } +private: + CloudStorage* mCloudStorage; + static nsCOMPtr mInterface; +}; + +nsCOMPtr CloudStorageRequestRunnable::mInterface = NULL; + +CloudStorageRequestHandler::CloudStorageRequestHandler(CloudStorage* aCloudStorage) + : mCloudStorage(aCloudStorage), + mFuse(NULL), + mFuseHandler(NULL) +{ + Init(); +} + +CloudStorageRequestHandler::~CloudStorageRequestHandler() +{ + Close(); +} + +void +CloudStorageRequestHandler::Init() +{ + int fd; + char opts[256]; + int res; + + umount2(mCloudStorage->MountPoint().get(), 2); + + fd = open("/dev/fuse", O_RDWR); + if (fd < 0){ + LOG("cannot open fuse device: %s", strerror(errno)); + return; + } + + // option for fuse filesystem + snprintf(opts, sizeof(opts), + "fd=%i,rootmode=40000,default_permissions,allow_other,user_id=0,group_id=1015",fd); + + res = mount("/dev/fuse", mCloudStorage->MountPoint().get(), "fuse", MS_NOSUID | MS_NODEV, opts); + if (res < 0) { + LOG("cannot mount fuse filesystem: %s", strerror(errno)); + close(fd); + return; + } + + mFuse = new Fuse(); + mFuse->fd = fd; + mFuse->rootnid = FUSE_ROOT_ID; + mFuse->next_generation = 0; + mFuseHandler = new FuseHandler(); + mFuseHandler->fuse = mFuse; + mFuseHandler->token = 0; + + umask(0); +} + +void +CloudStorageRequestHandler::Close() +{ + umount2(mCloudStorage->MountPoint().get(), 2); + if (mFuse) { + close(mFuse->fd); + delete mFuse; + mFuse = NULL; + } + if (mFuseHandler) { + delete mFuseHandler; + mFuseHandler = NULL; + } + if (mCloudStorage) { + // needn't delete cloudstorage, manager will maintain its life time + mCloudStorage = NULL; + } +} + +void +CloudStorageRequestHandler::HandleRequests() +{ + while (mCloudStorage->State() == CloudStorage::STATE_RUNNING) { + fd_set fds; + FD_ZERO(&fds); + FD_SET(mFuse->fd, &fds); + struct timespec timeout; + timeout.tv_sec = 0; + timeout.tv_nsec = 100000000; + + int res = pselect(mFuse->fd+1, &fds, NULL, NULL, &timeout, NULL); + if (res == -1 && errno != EINTR) { + LOG("pselect error %d.", errno); + continue; + } else if (res == 0) { //timeout + continue; + } else if (FD_ISSET(mFuse->fd, &fds)) { + ssize_t len = read(mFuse->fd, mFuseHandler->request_buffer, sizeof(mFuseHandler->request_buffer)); + if (len < 0) { + if (errno != EINTR) { + LOG("[%d] handle_fuse_requests: errno=%d", mFuseHandler->token, errno); + } + continue; + } + + if ((size_t)len < sizeof(FuseInHeader)) { + LOG("[%d] request too short: len=%zu", mFuseHandler->token, (size_t)len); + continue; + } + + const FuseInHeader *hdr = (const FuseInHeader*)((void*)mFuseHandler->request_buffer); + if (hdr->len != (size_t)len) { + LOG("[%d] malformed header: len=%zu, hdr->len=%u", mFuseHandler->token, (size_t)len, hdr->len); + continue; + } + + const void *data = mFuseHandler->request_buffer + sizeof(FuseInHeader); + size_t data_len = len - sizeof(FuseInHeader); + uint64_t unique = hdr->unique; + + int res = HandleRequest(hdr, data, data_len); + + if (res != CLOUD_STORAGE_NO_STATUS) { + if (res) { + LOG("[%d] LOG %d", mFuseHandler->token, res); + } + FuseOutHeader outhdr; + outhdr.len = sizeof(outhdr); + outhdr.error = res; + outhdr.unique = unique; + write(mFuse->fd, &outhdr, sizeof(outhdr)); + } + } else { + LOG("fds is ready, but not mFuse->fd, should not be here."); + } + } +} + +int +CloudStorageRequestHandler::HandleRequest(const FuseInHeader *hdr, const void *data, size_t data_len) +{ + switch (hdr->opcode) { + case FUSE_LOOKUP: { // bytez[] -> entry_out + const char* name = (const char*)(data); + return HandleLookup(hdr, name); + } + + case FUSE_FORGET: { + const FuseForgetIn *req = (const FuseForgetIn*)(data); + return HandleForget(hdr, req); + } + + case FUSE_GETATTR: { // getattr_in -> attr_out + const FuseGetAttrIn *req = (const FuseGetAttrIn*)(data); + return HandleGetAttr(hdr, req); + } + + case FUSE_SETATTR: { // setattr_in -> attr_out + const FuseSetAttrIn *req = (const FuseSetAttrIn*)(data); + return HandleSetAttr(hdr, req); + } + +// case FUSE_READLINK: +// case FUSE_SYMLINK: + case FUSE_MKNOD: { // mknod_in, bytez[] -> entry_out + const FuseMkNodIn *req = (const FuseMkNodIn*)(data); + const char *name = ((const char*) data) + sizeof(*req); + return HandleMkNod(hdr, req, name); + } + + case FUSE_MKDIR: { // mkdir_in, bytez[] -> entry_out + const FuseMkDirIn *req = (const FuseMkDirIn*)(data); + const char *name = ((const char*) data) + sizeof(*req); + return HandleMkDir(hdr, req, name); + } + + case FUSE_UNLINK: { // bytez[] -> + const char* name = (const char*)(data); + return HandleUnlink(hdr, name); + } + + case FUSE_RMDIR: { // bytez[] -> + const char* name = (const char*)(data); + return HandleRmDir(hdr, name); + } + + case FUSE_RENAME: { // rename_in, oldname, newname -> + const FuseRenameIn *req = (const FuseRenameIn*)(data); + const char *old_name = ((const char*) data) + sizeof(*req); + const char *new_name = old_name + strlen(old_name) + 1; + return HandleRename(hdr, req, old_name, new_name); + } + +// case FUSE_LINK: + case FUSE_OPEN: { // open_in -> open_out + const FuseOpenIn *req = (const FuseOpenIn*)(data); + return HandleOpen(hdr, req); + } + + case FUSE_READ: { // read_in -> byte[] + const FuseReadIn *req = (const FuseReadIn*)(data); + return HandleRead(hdr, req); + } + + case FUSE_WRITE: { // write_in, byte[write_in.size] -> write_out + const FuseWriteIn *req = (const FuseWriteIn*)(data); + const void* buffer = (const __u8*)data + sizeof(*req); + return HandleWrite(hdr, req, buffer); + } + + case FUSE_STATFS: { // getattr_in -> attr_out + return HandleStatfs(hdr); + } + + case FUSE_RELEASE: { // release_in -> + const FuseReleaseIn *req = (const FuseReleaseIn*)(data); + return HandleRelease(hdr, req); + } + + case FUSE_FSYNC: { + const FuseFsyncIn *req = (const FuseFsyncIn*)(data); + return HandleFsync(hdr, req); + } + + case FUSE_FLUSH: { + return HandleFlush(hdr); + } + + case FUSE_OPENDIR: { // open_in -> open_out + const FuseOpenIn *req = (const FuseOpenIn*)(data); + return HandleOpenDir(hdr, req); + } + + case FUSE_READDIR: { + const FuseReadIn *req = (const FuseReadIn*)(data); + return HandleReadDir(hdr, req); + } + + case FUSE_RELEASEDIR: { // release_in -> + const FuseReleaseIn *req = (const FuseReleaseIn*)(data); + return HandleReleaseDir(hdr, req); + } + +// case FUSE_FSYNCDIR: + case FUSE_INIT: { // init_in -> init_out + const FuseInitIn *req = (const FuseInitIn*)(data); + return HandleInit(hdr, req); + } + + default: { + LOG("[%d] NOTIMPL op=%d uniq=%llx nid=%llx", + mFuseHandler->token, hdr->opcode, hdr->unique, hdr->nodeid); + return -ENOSYS; + } + } +} + +void +CloudStorageRequestHandler::SendRequestToMainThread() +{ + mCloudStorage->SetWaitForRequest(true); + nsresult rv = NS_DispatchToMainThread(new CloudStorageRequestRunnable(mCloudStorage)); + if (NS_FAILED(rv)) { + LOG("fail to dispatch to main thread [%x]", rv); + } + while (mCloudStorage->IsWaitForRequest() && mCloudStorage->State() == CloudStorage::STATE_RUNNING) { + usleep(10); + } +} + +uint64_t +CloudStorageRequestHandler::AcquireOrCreateChildNId(const nsCString& childpath) +{ + uint64_t nid = mCloudStorage->GetNIdByPath(childpath); + if (nid != 0) { + return nid; + } + uint64_t* nidptr = (uint64_t*)malloc(sizeof(uint64_t)); + nid = (uint64_t) (uintptr_t)nidptr; + mCloudStorage->PutPathByNId(nid, childpath); + mCloudStorage->PutNIdByPath(childpath, nid); + return nid; +} + +int +CloudStorageRequestHandler::HandleLookup(const FuseInHeader *hdr, const char* name) +{ + LOG("Lookup"); + nsCString path = mCloudStorage->GetPathByNId(hdr->nodeid); + if (path.Equals(NS_LITERAL_CSTRING(""))) { + return -ENOENT; + } + LOG("path: %s, passed name %s", path.get(), name); + nsCString childpath = path; + if (hdr->nodeid != FUSE_ROOT_ID) { + childpath.AppendLiteral("/"); + } + childpath.AppendASCII(name); + LOG("childpath: %s", childpath.get()); + uint64_t childnid = AcquireOrCreateChildNId(childpath); + if (childnid == 0) { + return -ENOMEM; + } + + FuseEntryOut out; + out.attr.ino = hdr->nodeid; + out.attr = mCloudStorage->GetAttrByPath(childpath); + if (out.attr.size == 0) { + CloudStorageRequestData reqData; + reqData.RequestType = (uint32_t) FUSE_GETATTR; + reqData.Path = childpath; + mCloudStorage->SetRequestData(reqData); + SendRequestToMainThread(); + out.attr = mCloudStorage->GetAttrByPath(childpath); + if (out.attr.size == 0) { + return -ENOENT; + } + } + + out.attr_valid = 10; + out.entry_valid = 10; + out.nodeid = childnid; + out.generation = mFuse->next_generation++; + + if (mCloudStorage->State() == CloudStorage::STATE_RUNNING) { + FuseOutHeader outhdr; + struct iovec vec[2]; + int res; + outhdr.len = sizeof(out) + sizeof(outhdr); + outhdr.error = 0; + outhdr.unique = hdr->unique; + vec[0].iov_base = &outhdr; + vec[0].iov_len = sizeof(outhdr); + vec[1].iov_base = (void*) &out; + vec[1].iov_len = sizeof(out); + res = writev(mFuse->fd, vec, 2); + if (res < 0) { + LOG("*** REPLY FAILED ***"); + switch (errno) { + case EAGAIN: LOG("EAGAIN"); break; + case EBADF: LOG("EBADF"); break; + case EFAULT: LOG("EFAULT"); break; + case EFBIG: LOG("EFBIG"); break; + case EINVAL: LOG("EINVAL"); break; + case EINTR: LOG("EINTR"); break; + case EIO: LOG("EIO"); break; + case ENOSPC: LOG("ENOSPC"); break; + case EPIPE: LOG("EPIPE"); break; + default : LOG("Unknown error no %d", errno); + } + } + } + return CLOUD_STORAGE_NO_STATUS; +} + +int +CloudStorageRequestHandler::HandleForget(const FuseInHeader *hdr, const FuseForgetIn *req) +{ + LOG("Forget"); + return CLOUD_STORAGE_NO_STATUS; +} + +int +CloudStorageRequestHandler::HandleGetAttr(const FuseInHeader *hdr, const FuseGetAttrIn* req) +{ + LOG("GetAttr"); + nsCString path = mCloudStorage->GetPathByNId(hdr->nodeid); + if (path.Equals(NS_LITERAL_CSTRING(""))) { + return -ENOENT; + } + LOG("path: %s", path.get()); + + FuseAttrOut attrOut; + attrOut.attr.ino = hdr->nodeid; + attrOut.attr = mCloudStorage->GetAttrByPath(path); + if (attrOut.attr.size == 0) { + CloudStorageRequestData reqData; + reqData.RequestType = (uint32_t) FUSE_GETATTR; + reqData.Path = path; + mCloudStorage->SetRequestData(reqData); + SendRequestToMainThread(); + attrOut.attr = mCloudStorage->GetAttrByPath(path); + if (attrOut.attr.size == 0) { + return -ENOENT; + } + } + attrOut.attr_valid = 10; + + if (mCloudStorage->State() == CloudStorage::STATE_RUNNING) { + FuseOutHeader outhdr; + struct iovec vec[2]; + int res; + outhdr.len = sizeof(attrOut) + sizeof(outhdr); + outhdr.error = 0; + outhdr.unique = hdr->unique; + vec[0].iov_base = &outhdr; + vec[0].iov_len = sizeof(outhdr); + vec[1].iov_base = (void*) &attrOut; + vec[1].iov_len = sizeof(attrOut); + res = writev(mFuse->fd, vec, 2); + if (res < 0) { + LOG("*** reply failed *** %d", errno); + } + } + return CLOUD_STORAGE_NO_STATUS; +} + +int +CloudStorageRequestHandler::HandleSetAttr(const FuseInHeader *hdr, const FuseSetAttrIn *req) +{ + LOG("SetAttr"); + return CLOUD_STORAGE_NO_STATUS; +} + +int +CloudStorageRequestHandler::HandleMkNod(const FuseInHeader* hdr, const FuseMkNodIn* req, const char* name) +{ + LOG("MkNod"); + return CLOUD_STORAGE_NO_STATUS; +} + +int CloudStorageRequestHandler::HandleMkDir(const FuseInHeader* hdr, const FuseMkDirIn* req, const char* name) +{ + LOG("MkDir"); + return CLOUD_STORAGE_NO_STATUS; +} + +int +CloudStorageRequestHandler::HandleUnlink(const FuseInHeader* hdr, const char* name) +{ + LOG("Unlink"); + return CLOUD_STORAGE_NO_STATUS; +} + +int +CloudStorageRequestHandler::HandleRmDir(const FuseInHeader* hdr, const char* name) +{ + LOG("RmDir"); + return CLOUD_STORAGE_NO_STATUS; +} + +int +CloudStorageRequestHandler::HandleRename(const FuseInHeader* hdr, const FuseRenameIn* req, const char* old_name, const char* new_name) +{ + LOG("Rename"); + return CLOUD_STORAGE_NO_STATUS; +} + +int +CloudStorageRequestHandler::HandleOpen(const FuseInHeader* hdr, const FuseOpenIn* req) +{ + LOG("Open"); + nsCString path = mCloudStorage->GetPathByNId(hdr->nodeid); + if (path.Equals(NS_LITERAL_CSTRING(""))) { + return -ENOENT; + } + LOG("path: %s", path.get()); + + FuseOpenOut out; + uint64_t* handle = (uint64_t*) malloc(sizeof(uint64_t)); + out.fh = (uint64_t) (uintptr_t) handle; + out.open_flags = 0; + out.padding = 0; + + if (mCloudStorage->State() == CloudStorage::STATE_RUNNING) { + FuseOutHeader outhdr; + struct iovec vec[2]; + int res; + outhdr.len = sizeof(out) + sizeof(outhdr); + outhdr.error = 0; + outhdr.unique = hdr->unique; + vec[0].iov_base = &outhdr; + vec[0].iov_len = sizeof(outhdr); + vec[1].iov_base = (void*) &out; + vec[1].iov_len = sizeof(out); + res = writev(mFuse->fd, vec, 2); + if (res < 0) { + LOG("*** REPLY FAILED ***"); + switch (errno) { + case EAGAIN: LOG("EAGAIN"); break; + case EBADF: LOG("EBADF"); break; + case EFAULT: LOG("EFAULT"); break; + case EFBIG: LOG("EFBIG"); break; + case EINVAL: LOG("EINVAL"); break; + case EINTR: LOG("EINTR"); break; + case EIO: LOG("EIO"); break; + case ENOSPC: LOG("ENOSPC"); break; + case EPIPE: LOG("EPIPE"); break; + default : LOG("Unknown error no %d", errno); + } + } + } + return CLOUD_STORAGE_NO_STATUS; +} + +int +CloudStorageRequestHandler::HandleRead(const FuseInHeader* hdr, const FuseReadIn* req) +{ + LOG("Read"); + nsCString path = mCloudStorage->GetPathByNId(hdr->nodeid); + if (path.Equals(NS_LITERAL_CSTRING(""))) { + return -ENOENT; + } + LOG("path: %s, nodeid: %llu, size: %d, offset: %d", path.get(), hdr->nodeid, req->size, (int)req->offset); + + CloudStorageRequestData reqData; + reqData.RequestType = (uint32_t) FUSE_READ; + reqData.Path = path; + reqData.Size = req->size; + reqData.Offset = req->offset; + mCloudStorage->SetRequestData(reqData); + SendRequestToMainThread(); + + if (mCloudStorage->State() == CloudStorage::STATE_RUNNING) { + if (mCloudStorage->DataBufferSize() < 0) { + return mCloudStorage->DataBufferSize(); + } + FuseOutHeader outhdr; + struct iovec vec[2]; + int res; + outhdr.len = mCloudStorage->DataBufferSize() + sizeof(outhdr); + outhdr.error = 0; + outhdr.unique = hdr->unique; + vec[0].iov_base = &outhdr; + vec[0].iov_len = sizeof(outhdr); + vec[1].iov_base = (void*) mCloudStorage->DataBuffer(); + vec[1].iov_len = mCloudStorage->DataBufferSize(); + res = writev(mFuse->fd, vec, 2); + if (res < 0) { + LOG("*** REPLY FAILED ***"); + switch (errno) { + case EAGAIN: LOG("EAGAIN"); break; + case EBADF: LOG("EBADF"); break; + case EFAULT: LOG("EFAULT"); break; + case EFBIG: LOG("EFBIG"); break; + case EINVAL: LOG("EINVAL"); break; + case EINTR: LOG("EINTR"); break; + case EIO: LOG("EIO"); break; + case ENOSPC: LOG("ENOSPC"); break; + case EPIPE: LOG("EPIPE"); break; + default : LOG("Unknown error no %d", errno); + } + } + } + return CLOUD_STORAGE_NO_STATUS; +} + +int +CloudStorageRequestHandler::HandleWrite(const FuseInHeader* hdr, const FuseWriteIn* req, const void* buffer) +{ + LOG("Write"); + return CLOUD_STORAGE_NO_STATUS; +} + +int +CloudStorageRequestHandler::HandleStatfs(const FuseInHeader* hdr) +{ + LOG("Statfs"); + return CLOUD_STORAGE_NO_STATUS; +} + +int +CloudStorageRequestHandler::HandleRelease(const FuseInHeader* hdr, const FuseReleaseIn* req) +{ + LOG("Release"); + nsCString path = mCloudStorage->GetPathByNId(hdr->nodeid); + if (path.Equals(NS_LITERAL_CSTRING(""))) { + return -ENOENT; + } + LOG("path: %s", path.get()); + uint64_t* handle = (uint64_t*)(uintptr_t) req->fh; + free(handle); + return 0; +} + +int +CloudStorageRequestHandler::HandleFsync(const FuseInHeader* hdr, const FuseFsyncIn* req) +{ + LOG("Fsync"); + return 0; +} + +int +CloudStorageRequestHandler::HandleFlush(const FuseInHeader* hdr) +{ + LOG("Flush"); + + nsCString path = mCloudStorage->GetPathByNId(hdr->nodeid); + if (path.Equals(NS_LITERAL_CSTRING(""))) { + return -ENOENT; + } + LOG("path: %s", path.get()); + + return 0; +} + +int +CloudStorageRequestHandler::HandleOpenDir(const FuseInHeader* hdr, const FuseOpenIn* req) +{ + + LOG("OpenDir"); + + nsCString path = mCloudStorage->GetPathByNId(hdr->nodeid); + if (path.Equals(NS_LITERAL_CSTRING(""))) { + return -ENOENT; + } + LOG("path: %s", path.get()); + FuseOpenOut out; + // when releaseDir is called, call free for dirHandle + uint64_t* dirHandle = (uint64_t*) malloc(sizeof(uint64_t)); + if (!dirHandle) { + return -ENOMEM; + } + out.fh = (uint64_t) (uintptr_t) dirHandle; + out.open_flags = 0; + out.padding = 0; + FuseOutHeader outhdr; + struct iovec vec[2]; + int res; + outhdr.len = sizeof(out) + sizeof(outhdr); + outhdr.error = 0; + outhdr.unique = hdr->unique; + vec[0].iov_base = &outhdr; + vec[0].iov_len = sizeof(outhdr); + vec[1].iov_base = (void*) &out; + vec[1].iov_len = sizeof(out); + res = writev(mFuse->fd, vec, 2); + if (res < 0) { + LOG("*** REPLY FAILED ***"); + switch (errno) { + case EAGAIN: LOG("EAGAIN"); break; + case EBADF: LOG("EBADF"); break; + case EFAULT: LOG("EFAULT"); break; + case EFBIG: LOG("EFBIG"); break; + case EINVAL: LOG("EINVAL"); break; + case EINTR: LOG("EINTR"); break; + case EIO: LOG("EIO"); break; + case ENOSPC: LOG("ENOSPC"); break; + case EPIPE: LOG("EPIPE"); break; + default : LOG("Unknown error no %d", errno); + } + } + return CLOUD_STORAGE_NO_STATUS; +} + +int +CloudStorageRequestHandler::HandleReadDir(const FuseInHeader* hdr, const FuseReadIn* req) +{ + LOG("ReadDir"); + nsCString path = mCloudStorage->GetPathByNId(hdr->nodeid); + if (path.Equals(NS_LITERAL_CSTRING(""))) { + return -ENOENT; + } + LOG("path: %s, offset: %llu", path.get(), req->offset); + char buffer[8192]; + FuseDirent *fde = (FuseDirent*) buffer; + fde->ino = FUSE_UNKNOWN_INO; + fde->off = req->offset + 1; + nsCString entryName; + + entryName = mCloudStorage->GetEntryByPathAndOffset(path, req->offset); + if (entryName.Equals(NS_LITERAL_CSTRING(""))) { + CloudStorageRequestData reqData; + reqData.RequestType = (uint32_t) FUSE_READDIR; + reqData.Path = path; + mCloudStorage->SetRequestData(reqData); + SendRequestToMainThread(); + entryName = mCloudStorage->GetEntryByPathAndOffset(path, req->offset); + } + + if (mCloudStorage->State() == CloudStorage::STATE_RUNNING) { + if (entryName.Equals("")) { + LOG("No entry"); + return 0; + } + nsCString childPath = path; + if (!path.Equals(NS_LITERAL_CSTRING("/"))) { + childPath.Append(NS_LITERAL_CSTRING("/")); + } + childPath.Append(entryName); + + if (S_ISDIR(mCloudStorage->GetAttrByPath(childPath).mode)) { + fde->type = DT_DIR; + } else { + fde->type = DT_REG; + } + fde->namelen = entryName.Length(); + memcpy(fde->name, entryName.get(), fde->namelen + 1); + + LOG("entry: %s, type: %s", entryName.get(), fde->type == DT_DIR ? "directory" : "file"); + + FuseOutHeader outhdr; + struct iovec vec[2]; + int res; + outhdr.len = FUSE_DIRENT_ALIGN(sizeof(FuseDirent) + fde->namelen) + sizeof(outhdr); + outhdr.error = 0; + outhdr.unique = hdr->unique; + vec[0].iov_base = &outhdr; + vec[0].iov_len = sizeof(outhdr); + vec[1].iov_base = (void*) fde; + vec[1].iov_len = FUSE_DIRENT_ALIGN(sizeof(FuseDirent) + fde->namelen); + res = writev(mFuse->fd, vec, 2); + if (res < 0) { + LOG("*** REPLY FAILED ***"); + switch (errno) { + case EAGAIN: LOG("EAGAIN"); break; + case EBADF: LOG("EBADF"); break; + case EFAULT: LOG("EFAULT"); break; + case EFBIG: LOG("EFBIG"); break; + case EINVAL: LOG("EINVAL"); break; + case EINTR: LOG("EINTR"); break; + case EIO: LOG("EIO"); break; + case ENOSPC: LOG("ENOSPC"); break; + case EPIPE: LOG("EPIPE"); break; + default : LOG("Unknown error no %d", errno); + } + } + } + return CLOUD_STORAGE_NO_STATUS; +} + +int +CloudStorageRequestHandler::HandleReleaseDir(const FuseInHeader* hdr, const FuseReleaseIn* req) +{ + LOG("ReleaseDir"); + nsCString path = mCloudStorage->GetPathByNId(hdr->nodeid); + if (path.Equals(NS_LITERAL_CSTRING(""))) { + return -ENOENT; + } + LOG("path: %s", path.get()); + uint64_t* handle = (uint64_t*)(uintptr_t) req->fh; + free(handle); + return CLOUD_STORAGE_NO_STATUS; +} + +int +CloudStorageRequestHandler::HandleInit(const FuseInHeader* hdr, const FuseInitIn* req) +{ + LOG("Init"); + FuseInitOut out; + out.major = FUSE_KERNEL_VERSION; + out.minor = FUSE_KERNEL_MINOR_VERSION; + out.max_readahead = req->max_readahead; + out.flags = FUSE_ATOMIC_O_TRUNC | FUSE_BIG_WRITES; + out.max_background = 32; + out.congestion_threshold = 32; + out.max_write = CLOUD_STORAGE_MAX_WRITE; + + FuseOutHeader outhdr; + struct iovec vec[2]; + int res; + outhdr.len = sizeof(out) + sizeof(outhdr); + outhdr.error = 0; + outhdr.unique = hdr->unique; + vec[0].iov_base = &outhdr; + vec[0].iov_len = sizeof(outhdr); + vec[1].iov_base = (void*) &out; + vec[1].iov_len = sizeof(out); + res = writev(mFuse->fd, vec, 2); + if (res < 0) { + LOG("*** REPLY FAILED ***"); + switch (errno) { + case EAGAIN: LOG("EAGAIN"); break; + case EBADF: LOG("EBADF"); break; + case EFAULT: LOG("EFAULT"); break; + case EFBIG: LOG("EFBIG"); break; + case EINVAL: LOG("EINVAL"); break; + case EINTR: LOG("EINTR"); break; + case EIO: LOG("EIO"); break; + case ENOSPC: LOG("ENOSPC"); break; + case EPIPE: LOG("EPIPE"); break; + default : LOG("Unknown error no %d", errno); + } + } + + return CLOUD_STORAGE_NO_STATUS; +} + +} //end namespace cloudstorage +} //end namespace system +} //end namespace mozilla + + diff --git a/dom/system/gonk/cloudstorage/CloudStorageRequestHandler.h b/dom/system/gonk/cloudstorage/CloudStorageRequestHandler.h new file mode 100644 index 0000000000000..b4e0af4b19c4f --- /dev/null +++ b/dom/system/gonk/cloudstorage/CloudStorageRequestHandler.h @@ -0,0 +1,70 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this file, + * You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#ifndef mozilla_system_cloudstroagerequesthandler_h__ +#define mozilla_system_cloudstroagerequesthandler_h__ + +#include "nsString.h" +#include "fuse.h" + +namespace mozilla { +namespace system { +namespace cloudstorage { + +class CloudStorage; + +#define CLOUD_STORAGE_NO_STATUS 1 + +class CloudStorageRequestHandler +{ +public: + NS_INLINE_DECL_REFCOUNTING(CloudStorageRequestHandler) + + CloudStorageRequestHandler(CloudStorage* aCloudStorage); + virtual ~CloudStorageRequestHandler(); + + void HandleRequests(); + +protected: + void Init(); + void Close(); + + void SendRequestToMainThread(); + uint64_t AcquireOrCreateChildNId(const nsCString& childpath); + +// void InitFuse(int aFd); +// void InitFuseHandler(); + + int HandleRequest(const FuseInHeader *hdr, const void *data, size_t data_len); + virtual int HandleLookup(const FuseInHeader *hdr, const char* name); + virtual int HandleForget(const FuseInHeader *hdr, const FuseForgetIn *req); + virtual int HandleGetAttr(const FuseInHeader *hdr, const FuseGetAttrIn *req); + virtual int HandleSetAttr(const FuseInHeader *hdr, const FuseSetAttrIn *req); + virtual int HandleMkNod(const FuseInHeader* hdr, const FuseMkNodIn* req, const char* name); + virtual int HandleMkDir(const FuseInHeader* hdr, const FuseMkDirIn* req, const char* name); + virtual int HandleUnlink(const FuseInHeader* hdr, const char* name); + virtual int HandleRmDir(const FuseInHeader* hdr, const char* name); + virtual int HandleRename(const FuseInHeader* hdr, const FuseRenameIn* req, const char* old_name, const char* new_name); + virtual int HandleOpen(const FuseInHeader* hdr, const FuseOpenIn* req); + virtual int HandleRead(const FuseInHeader* hdr, const FuseReadIn* req); + virtual int HandleWrite(const FuseInHeader* hdr, const FuseWriteIn* req, const void* buffer); + virtual int HandleStatfs(const FuseInHeader* hdr); + virtual int HandleRelease(const FuseInHeader* hdr, const FuseReleaseIn* req); + virtual int HandleFsync(const FuseInHeader* hdr, const FuseFsyncIn* req); + virtual int HandleFlush(const FuseInHeader* hdr); + virtual int HandleOpenDir(const FuseInHeader* hdr, const FuseOpenIn* req); + virtual int HandleReadDir(const FuseInHeader* hdr, const FuseReadIn* req); + virtual int HandleReleaseDir(const FuseInHeader* hdr, const FuseReleaseIn* req); + virtual int HandleInit(const FuseInHeader* hdr, const FuseInitIn* req); + + CloudStorage* mCloudStorage; + Fuse* mFuse; + FuseHandler* mFuseHandler; +}; + +} // end namespace cloudstorage +} // end namespace system +} // end namespace mozilla + +#endif // mozilla_system_cloudstoragerequesthandler_h__ diff --git a/dom/system/gonk/cloudstorage/CloudStorageTester.cpp b/dom/system/gonk/cloudstorage/CloudStorageTester.cpp new file mode 100644 index 0000000000000..9604f85d3e9af --- /dev/null +++ b/dom/system/gonk/cloudstorage/CloudStorageTester.cpp @@ -0,0 +1,157 @@ +#include "CloudStorageTester.h" +#include "CloudStorageLog.h" +#include +#include +#include +#include +#include +#include +#include + +namespace mozilla { +namespace system { +namespace cloudstorage { + +nsDataHashtable CloudStorageTester::sFileHash; + +CloudStorageTester::CloudStorageTester() +{ +} + +CloudStorageTester::~CloudStorageTester() +{ + +} + +FuseAttr +CloudStorageTester::GetAttrByPath(const nsCString& aPath, const uint64_t aNodeId) +{ + FuseAttr attr; + nsCString realPath = NS_LITERAL_CSTRING("/data/local/tmp/cloudstorage"); + if (!aPath.Equals(NS_LITERAL_CSTRING("/"))) { + realPath.Append(aPath); + } + + LOG("path: %s, real path: %s", aPath.get(), realPath.get()); + struct stat s; + if (lstat(realPath.get(), &s) < 0) { + LOG("lstat fail"); + switch (errno) { + case EACCES: LOG("EACCES"); break; + case EBADF: LOG("EBADF"); break; + case EFAULT: LOG("EFAULG"); break; + case ENAMETOOLONG: LOG("ENAMETOOLONG"); break; + case ENOENT: LOG("ENOENT"); break; + case ENOMEM: LOG("ENOMEM"); break; + case ENOTDIR: LOG("ENOTDIR"); break; + default: LOG("unknown errno %d", errno); break; + } + } + attr.ino = aNodeId; + attr.size = s.st_size; + attr.blocks = s.st_blocks; + attr.atime = s.st_atime; + attr.mtime = s.st_mtime; + attr.ctime = s.st_ctime; + attr.atimensec = s.st_atime_nsec; + attr.mtimensec = s.st_mtime_nsec; + attr.ctimensec = s.st_ctime_nsec; + attr.mode = s.st_mode; + attr.nlink = s.st_nlink; + attr.uid = 0; + attr.gid = 1015; + LOG("size: %llu", attr.size); + LOG("blocks: %llu", attr.blocks); + LOG("blocksize: %u", attr.blksize); + LOG("atime: %llu", attr.atime); + LOG("mtime: %llu", attr.mtime); + LOG("ctime: %llu", attr.ctime); + LOG("atimensec: %u", attr.atimensec); + LOG("mtimensec: %u", attr.mtimensec); + LOG("ctimensec: %u", attr.ctimensec); + LOG("mode: %x", attr.mode); + LOG("nlinks: %u", attr.nlink); + LOG("rdev: %u", attr.rdev); + LOG("padding: %u", attr.padding); + return attr; +} + +void +CloudStorageTester::GetEntry(const nsCString& aPath, const uint64_t aOffset, nsCString& aEntryName, uint32_t& aEntryType) +{ + LOG("path: %s, offset: %d", aPath.get(), (unsigned int)aOffset); + if (aPath.Equals(NS_LITERAL_CSTRING("/"))) { + if (aOffset == 0) { + aEntryName = NS_LITERAL_CSTRING("A"); + aEntryType = DT_DIR; + } + } else if (aPath.Equals(NS_LITERAL_CSTRING("/A"))) { + switch (aOffset) { + case 0: { + aEntryName = NS_LITERAL_CSTRING("B"); + aEntryType = DT_DIR; + break; + } + case 1: { + aEntryName = NS_LITERAL_CSTRING("c.jpg"); + aEntryType = DT_REG; + break; + } + default: break; + } + } else if (aPath.Equals(NS_LITERAL_CSTRING("/A/B"))) { + if (aOffset == 0) { + aEntryName = NS_LITERAL_CSTRING("d.jpg"); + aEntryType = DT_REG; + } + } +} + +void +CloudStorageTester::GetData(const uint64_t aHandle, const uint32_t aSize, const uint64_t aOffset, char*& aData, int32_t& aActualSize) +{ + int fd = -1; + LOG("search fd for handle %llx", aHandle); + LOG("hash table count: %d", sFileHash.Count()); + if (!sFileHash.Get(aHandle, &fd)) { + LOG("can not find fd(%d) for handle %llx", fd, aHandle); + return; + } + LOG("Size: %d, Offset: %d", aSize, (unsigned int)aOffset); + aActualSize = pread64(fd, aData, aSize, aOffset); + LOG("actual size: %d", aActualSize); +} + +void +CloudStorageTester::Open(const nsCString& aPath, const uint64_t aHandle) +{ + int fd; + nsCString realPath = NS_LITERAL_CSTRING("/data/local/tmp/cloudstorage"); + realPath.Append(aPath); + if (!sFileHash.Get(aHandle, &fd)) { + if((fd = open(realPath.get(), O_RDWR)) < 0) { + LOG("fail to open fd for path %s(%llx)", aPath.get(), aHandle); + return; + } else { + LOG("path: %s(%llx), fd: %d", aPath.get(), aHandle, fd); + sFileHash.Put(aHandle, fd); + LOG("hash table count: %d", sFileHash.Count()); + } + } +} + +void +CloudStorageTester::Close(const uint64_t aHandle) +{ + int fd; + LOG("search fd for handle %llx", aHandle); + if (!sFileHash.Get(aHandle, &fd)) { + return; + } + close(fd); + sFileHash.Remove(aHandle); +} + +} +} +} diff --git a/dom/system/gonk/cloudstorage/CloudStorageTester.h b/dom/system/gonk/cloudstorage/CloudStorageTester.h new file mode 100644 index 0000000000000..dec11a068a779 --- /dev/null +++ b/dom/system/gonk/cloudstorage/CloudStorageTester.h @@ -0,0 +1,31 @@ +#ifndef __CloudStorageTester__h +#define __CloudStorageTester__h + +#include "nsString.h" +#include "fuse.h" +#include "nsDataHashtable.h" + +namespace mozilla { +namespace system { +namespace cloudstorage { + +class CloudStorageTester final +{ +public: + CloudStorageTester(); + ~CloudStorageTester(); + + FuseAttr GetAttrByPath(const nsCString& aPath, const uint64_t aNodeId); + void GetEntry(const nsCString& aPath, const uint64_t aOffset, nsCString& aEntryName, uint32_t& aEntryType); + void GetData(const uint64_t aHandle, const uint32_t aSize, const uint64_t aOffset, char*& aData, int32_t& aActualSize); + void Open(const nsCString& aPath, const uint64_t aHandle); + void Close(const uint64_t aHandle); + +private: + static nsDataHashtable sFileHash; +}; + +} +} +} +#endif diff --git a/dom/system/gonk/cloudstorage/DataCache.jsm b/dom/system/gonk/cloudstorage/DataCache.jsm new file mode 100644 index 0000000000000..c8fef025b3231 --- /dev/null +++ b/dom/system/gonk/cloudstorage/DataCache.jsm @@ -0,0 +1,132 @@ +const { classes: Cc, interfaces: Ci, utils: Cu } = Components; + +Cu.import('resource://gre/modules/MemoryDataStore.jsm'); +const { console } = Cu.import("resource://gre/modules/devtools/Console.jsm", {}); + +var DataCache = {}; + +DataCache.init = function (blockSize) { + this._MAX_DATA_CACHE_ENTRY = 25; + this._BLOCK_SIZE = blockSize; + + this._dataStore = MemoryDataStore; + this._dataStore.init(); + + this._fileDataCache = {}; + this._priorityQueue = []; +}; + +DataCache.update = function (key, data) { + if (this._fileDataCache.hasOwnProperty(key) ) { + // Update an exist cache entry. + this._updateEntry(key, data); + } else { + // Add a new data cache. + if (this._priorityQueue.length < this._MAX_DATA_CACHE_ENTRY) { + // Entry is sufficient to add a new one. + this._pushEntry(key, data); + } else { + // Remove an entry and delete cache file. + var deletingCandidateKey = this._popLowPriorityKey(); + this._removeEntry(deletingCandidateKey); + this._pushEntry(key, data); + } + } +}; + +DataCache._updateEntry = function (key, data) { + this._fileDataCache[key] = data; +}; + +DataCache._pushEntry = function (key, data) { + this._fileDataCache[key] = data; + this._priorityQueue.push(key); +}; + +DataCache._removeEntry = function (key) { + delete this._fileDataCache[key]; + this._dataStore.deleteEntry(key); +}; + +DataCache._popLowPriorityKey = function () { + return this._priorityQueue.shift(); +}; + +DataCache.updateStatus = function (md5sum, status) { + this._fileDataCache[md5sum].status = status; +}; + +DataCache.get = function (md5sum) { + if (this._fileDataCache.hasOwnProperty(md5sum)) { + return this._fileDataCache[md5sum]; + } + return null; +}; + +DataCache.writeCache = function (task, data, cb){ + var self = this; + this._dataStore.writeEntry(task.md5sum, data, function(err) { + if(err) { + console.log(err); + } else { + self.updateStatus(task.md5sum, 'DONE'); + console.log('The file was saved!'); + } + cb(); + }); +}; + +DataCache.readCache = function (path, buffer, offset, size, requestList, cb){ + var seek = 0, + writeSize = 0, + cursor_moved = 0; + + for (var i in requestList) { + var task = requestList[i]; + if (task.priority === 'PREFETCH') { + continue; + } + if (this._fileDataCache[task.md5sum] && + this._fileDataCache[task.md5sum].status === 'DONE') { + seek = ( offset + cursor_moved ) % this._BLOCK_SIZE; + writeSize = this._BLOCK_SIZE - seek; + if ((writeSize + cursor_moved ) > size) { + writeSize = size - cursor_moved; + } + + this._dataStore.readEntry(task.md5sum, + buffer, cursor_moved, seek, writeSize); + + cursor_moved += writeSize ; + } else { + console.error('======= Critical Error ======='); + console.error(path); + console.error(offset); + console.error(size); + console.error(requestList); + console.error(this._fileDataCache); + + throw Error('data is not finished.'); + } + } + cb(); +}; + +DataCache.generateKey = function (task){ + function hashCode(str) { + var hash = 0, i, chr, len; + if (str.length == 0) return hash; + for (i = 0, len = str.length; i < len; i++) { + chr = str.charCodeAt(i); + hash = ((hash << 5) - hash) + chr; + hash |= 0; // Convert to 32bit integer + } + return hash; + } + + var obscured = task.path.replace(/\//g, ':'); + return hashCode(task.path) + '@' + obscured + '@' + task.offset; +}; + +this.EXPORTED_SYMBOLS = ['DataCache']; +this.DataCache = DataCache; diff --git a/dom/system/gonk/cloudstorage/Dropbox.jsm b/dom/system/gonk/cloudstorage/Dropbox.jsm new file mode 100644 index 0000000000000..03a3cc8f45b0a --- /dev/null +++ b/dom/system/gonk/cloudstorage/Dropbox.jsm @@ -0,0 +1,232 @@ +var XMLHttpRequest, getXMLHttpRequest; +const ENV_JS_ENGINE = 'gecko'; +if(ENV_JS_ENGINE === 'gecko'){ + getXMLHttpRequest = function () { + return Components.classes["@mozilla.org/xmlextras/xmlhttprequest;1"]. + createInstance(Components.interfaces.nsIXMLHttpRequest); + }; +}else { + XMLHttpRequest = require('xhr2'); + getXMLHttpRequest = function () { + return new XMLHttpRequest(); + }; +} + +var Dropbox = {}; + +Dropbox.init = function (options){ + if(ENV_JS_ENGINE === 'gecko'){ + this.USERTOKEN = options.accessToken; + return ; + } + var tokenFileName = process.env.HOME + '/.dropbox_token'; + try { + var fs = require('fs'); + var stats = fs.statSync(tokenFileName); + this.USERTOKEN = stats.isFile() ? fs.readFileSync( tokenFileName ) : null; + } catch (e) { + this.USERTOKEN = null; + } +}; + +Dropbox._handleJson = function (xmlhttp, cb){ + var response = { + data: null + }; + if (xmlhttp.status == 200) { + try { + response.data = JSON.parse(xmlhttp.responseText); + cb(null, response); + } catch (e) { + cb({ + error: 'parsing failed.' + }, response); + } + } else if (xmlhttp.status == 404){ + cb(null, response); // File not found + } else { + cb({ + error: 'http status: ' + xmlhttp.status + }, response); + } +}; + +Dropbox.quota = function (cb){ + var self = this; + var xmlhttp = getXMLHttpRequest(); + xmlhttp.open('get', 'https://api.dropbox.com/1/account/info', true); + xmlhttp.setRequestHeader('Authorization', 'Bearer ' + self.USERTOKEN); + xmlhttp.setRequestHeader('Accept', 'application/json'); + xmlhttp.onload = function () { + self._handleJson(xmlhttp, function (error, response){ + if (response.data) { + var quotaInfo = response.data.quota_info; + var result = { + data:{ + quota: quotaInfo.quota, + used: (quotaInfo.normal + quotaInfo.shared) + } + }; + cb(error, result); + } else { + cb(error, response); + } + }); + }; + + xmlhttp.send(); +}; + +Dropbox._convertItem = function (data){ + return { + isdir: data.is_dir ? 1 : 0, + path: data.path, + size: data.bytes, + // Date format: + // "%a, %d %b %Y %H:%M:%S %z" + // + // Example: "Sat, 21 Aug 2010 22:31:20 +0000" + mtime: new Date(data.modified).getTime(), + ctime: new Date(data.modified).getTime() + }; +}; + +Dropbox.getFileMeta = function (path, cb){ + var self = this; + var xmlhttp = getXMLHttpRequest(); + xmlhttp.open('get', 'https://api.dropbox.com/1/metadata/auto' + path, true); + xmlhttp.setRequestHeader('Authorization', 'Bearer ' + self.USERTOKEN); + xmlhttp.setRequestHeader('Accept', 'application/json'); + xmlhttp.onload = function () { + self._handleJson(xmlhttp, function (error, response){ + if (response.data) { + var data = response.data; + var result = { + data:{ + list: [self._convertItem(data)] + } + }; + cb(error, result); + } else { + cb(error, response); + } + }); + }; + + xmlhttp.send('list=false'); +}; + +Dropbox.getFileList = function (path, cb){ + var self = this; + var xmlhttp = getXMLHttpRequest(); + xmlhttp.open('get', 'https://api.dropbox.com/1/metadata/auto' + path, true); + xmlhttp.setRequestHeader('Authorization', 'Bearer ' + self.USERTOKEN); + xmlhttp.setRequestHeader('Accept', 'application/json'); + xmlhttp.onload = function () { + self._handleJson(xmlhttp, function (error, response){ + if (response.data) { + var data = response.data; + var resultList = []; + for(var i = 0; i < data.contents.length; i++){ + var content = data.contents[i]; + resultList.push(self._convertItem(content)); + } + var result = { + data:{ + list: resultList + } + }; + cb(error, result); + } else { + cb(error, response); + } + }); + }; + + xmlhttp.send('list=true'); +}; + +Dropbox.getFileDownload = function (path, offset, size, cb){ + var self = this; + var xmlhttp = getXMLHttpRequest(); + xmlhttp.open('get', 'https://api-content.dropbox.com/1/files/auto' + path, true); + xmlhttp.setRequestHeader('Authorization', 'Bearer ' + self.USERTOKEN); + xmlhttp.setRequestHeader('Range', 'bytes=' + offset + '-' + ( offset + size - 1 )); + xmlhttp.responseType = 'arraybuffer'; + xmlhttp.onload = function () { + var res = xmlhttp.response; + var length = res.byteLength; + cb(null, { + data: res, + length: length + }); + }; + + xmlhttp.send(); +}; + +/* +step 1: Dropbox.getAuthLink +Visit the link: https://www.dropbox.com/1/oauth2/authorize? +client_id=& +response_type=code +*/ + +Dropbox.getAuthLink = function (api_key, cb){ + var link = 'https://www.dropbox.com/1/oauth2/authorize?' + + 'client_id=' + api_key + '&' + + 'response_type=code'; + cb(null, {data: { + authLink: link + }}); +}; + +/* +step 2: Dropbox.getAccessToken +curl https://api.dropbox.com/1/oauth2/token \ +-d code= \ +-d grant_type=authorization_code \ +-u : + +Response: +{ + "access_token": "", + "token_type": "bearer", + "uid": "??????" +} +*/ +Dropbox.getAccessToken = function (api_key, api_secret, device_code, cb){ + var self = this; + var linkToken = 'https://' + api_key + ':' + api_secret + '@' + + 'api.dropbox.com/1/oauth2/token'; + var params = { + 'code': device_code, + 'grant_type': 'authorization_code' + }; + var strParams = 'code=' + encodeURIComponent(params.code) + + '&grant_type=' + encodeURIComponent(params.grant_type); + var xmlhttp = new XMLHttpRequest(); + xmlhttp.open('post', linkToken, true); + xmlhttp.setRequestHeader('Accept', 'application/json'); + xmlhttp.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded'); + xmlhttp.setRequestHeader('Content-length', strParams.length); + xmlhttp.onload = function (){ + self._handleJson(xmlhttp, function (error, response){ + if (response.data) { + var data = response.data; + var result = { + data:{ + access_token: data.access_token + } + }; + cb(error, result); + } else { + cb(error, response); + } + }); + }; + xmlhttp.send(strParams); +}; + +this.EXPORTED_SYMBOLS = ['Dropbox']; +this.Dropbox = Dropbox; diff --git a/dom/system/gonk/cloudstorage/MemoryDataStore.jsm b/dom/system/gonk/cloudstorage/MemoryDataStore.jsm new file mode 100644 index 0000000000000..0be363947ebbe --- /dev/null +++ b/dom/system/gonk/cloudstorage/MemoryDataStore.jsm @@ -0,0 +1,27 @@ +var MemoryDataStore = {}; + +MemoryDataStore.init = function (){ + this._data = {}; +}; + +MemoryDataStore.deleteEntry = function (key){ + delete this._data[key]; + this._data[key] = null; +}; + +MemoryDataStore.readEntry = + function (key, targetBuffer, targetOffset, sourceOffset, length){ + var uint8a = this._data[key]; + var sliced = uint8a.slice(sourceOffset, sourceOffset + length); + for(var i = targetOffset, copied = 0; i < length; i++, copied++){ + targetBuffer[i] = sliced[copied]; + } +}; + +MemoryDataStore.writeEntry = function (key, data, cb){ + this._data[key] = new Uint8Array(data); + cb(null); +}; + +this.EXPORTED_SYMBOLS = ['MemoryDataStore']; +this.MemoryDataStore = MemoryDataStore; diff --git a/dom/system/gonk/cloudstorage/MetaCache.jsm b/dom/system/gonk/cloudstorage/MetaCache.jsm new file mode 100644 index 0000000000000..fc4dc6c0563b1 --- /dev/null +++ b/dom/system/gonk/cloudstorage/MetaCache.jsm @@ -0,0 +1,31 @@ +var MetaCache = {}; + +MetaCache.init = function (){ + this._fileMetaCache = {}; + this._fileListCache = {}; +}; + +MetaCache.update = function (path, data) { + this._fileMetaCache[path] = data; +}; + +MetaCache.get = function (path) { + if (this._fileMetaCache.hasOwnProperty(path)) { + return this._fileMetaCache[path]; + } + return null; +}; + +MetaCache.updateList = function (path, data) { + this._fileListCache[path] = data; +}; + +MetaCache.getList = function (path) { + if (this._fileListCache.hasOwnProperty(path)) { + return this._fileListCache[path]; + } + return null; +}; + +this.EXPORTED_SYMBOLS = ['MetaCache']; +this.MetaCache = MetaCache; diff --git a/dom/system/gonk/cloudstorage/Sample.jsm b/dom/system/gonk/cloudstorage/Sample.jsm new file mode 100644 index 0000000000000..5b510a96fea06 --- /dev/null +++ b/dom/system/gonk/cloudstorage/Sample.jsm @@ -0,0 +1,125 @@ +var Sample = {}; + +function str2ab(str) { + var buf = new ArrayBuffer(str.length*2); // 2 bytes for each char + var bufView = new Uint16Array(buf); + for (var i=0, strLen=str.length; i= list.length) { + var k = new_index - list.length; + while ((k--) + 1) { + list.push(undefined); + } + } + list.splice(new_index, 0, list.splice(old_index, 1)[0]); + } + function removeProcessing(id){ + var index = linearSearch(listProcessing, function (item){ + return item.id === id; + }); + if(index != -1){ + listProcessing.splice(index, 1); + } + } + function done(){ + removeProcessing(this.id); + processTask(); + } + function processTask(){ + //console.log('listQueuing.length ' + listQueuing.length); + if(listQueuing.length === 0){ + //console.log('queue empty'); + } else if(listProcessing.length < concurrency){ + //console.log('task aval ' + listProcessing.length + ' ' + concurrency); + var task = listQueuing.shift(); + listProcessing.push(task); + setTimeout(function (){ + handler(task.id, task.data, done.bind(task)); + }, 0); + } else { + //console.log('task full ' + listProcessing.length + ' ' + concurrency); + } + } + var queue = { + push: function (id, priority, data){ + var task = { + id: id, + priority: priority, + data: data + }; + var index = linearSearch(listQueuing, function (item){ + return item.priority > priority; + }); + if (index === -1) { // Not found + listQueuing.push(task); + } else { + listQueuing.splice(index, 0, task); + } + processTask(); + }, + priorityChange: function (id, priority){ + var indexById = linearSearch(listQueuing, function (item){ + return item.id === id; + }); + if (indexById === -1) { + return ; + } + var indexByPriority = linearSearch(listQueuing, function (item){ + return item.priority > priority; + }); + move(listQueuing, indexById, indexByPriority); + } + }; + return queue; + }; + + if (typeof module !== 'undefined' && module.exports) { // Node.js support + module.exports = foco; + } else { // browser support + root.foco = foco; + } + self.foco = foco; +})(); diff --git a/dom/system/gonk/cloudstorage/fuse/fuse.h b/dom/system/gonk/cloudstorage/fuse/fuse.h new file mode 100644 index 0000000000000..983dc9dad9b9d --- /dev/null +++ b/dom/system/gonk/cloudstorage/fuse/fuse.h @@ -0,0 +1,417 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this file, + * You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#ifndef mozilla_system_fuse_h__ +#define mozilla_system_fuse_h__ + +//#include +//#include + +#define CLOUD_STORAGE_MAX_WRITE (256 * 1024) +#define CLOUD_STORAGE_MAX_READ (128 * 1024) +#define CLOUD_STORAGE_MAX_REQUEST_SIZE (sizeof(FuseInHeader) + sizeof(FuseWriteIn) + CLOUD_STORAGE_MAX_WRITE) + +#define FUSE_KERNEL_VERSION 7 +#define FUSE_KERNEL_MINOR_VERSION 13 +#define FUSE_ROOT_ID 1 +#define FUSE_UNKNOWN_INO 0xffffffff + +#define FUSE_ASYNC_READ (1 << 0) +#define FUSE_POSIX_LOCKS (1 << 1) +#define FUSE_FILE_OPS (1 << 2) +#define FUSE_ATOMIC_O_TRUNC (1 << 3) +#define FUSE_EXPORT_SUPPORT (1 << 4) +#define FUSE_BIG_WRITES (1 << 5) +#define FUSE_DONT_MASK (1 << 6) +#define FUSE_SPLICE_WRITE (1 << 7) +#define FUSE_SPLICE_MOVE (1 << 8) +#define FUSE_SPLICE_READ (1 << 9) +#define FUSE_FLOCK_LOCKS (1 << 10) +#define FUSE_HAS_IOCTL_DIR (1 << 11) +#define FUSE_AUTO_INVAL_DATA (1 << 12) +#define FUSE_DO_READDIRPLUS (1 << 13) +#define FUSE_READDIRPLUS_AUTO (1 << 14) +#define FUSE_ASYNC_DIO (1 << 15) +#define FUSE_WRITEBACK_CACHE (1 << 16) +#define FUSE_NO_OPEN_SUPPORT (1 << 17) + +typedef struct SFuseAttr { + __u64 ino; + __u64 size; + __u64 blocks; + __u64 atime; + __u64 mtime; + __u64 ctime; + __u32 atimensec; + __u32 mtimensec; + __u32 ctimensec; + __u32 mode; + __u32 nlink; + __u32 uid; + __u32 gid; + __u32 rdev; + __u32 blksize; + __u32 padding; +} FuseAttr; + +typedef struct FuseEntryOut { + __u64 nodeid; // Inode ID + __u64 generation; // Inode generation: nodeid:gen must + // be unique for the fs's lifetime + __u64 entry_valid; // Cache timeout for the name + __u64 attr_valid; // Cache timeout for the attributes + __u32 entry_valid_nsec; + __u32 attr_valid_nsec; + FuseAttr attr; +} FuseEntryOut; + +typedef struct SFuseForgetIn { + __u64 nlookup; +} FuseForgetIn; + +typedef struct SFuseGetAttrIn { + __u32 getattr_flags; + __u32 dummy; + __u64 fh; +} FuseGetAttrIn; + +typedef struct SFuseAttrOut { + __u64 attr_valid; // Cache timeout for the attributes + __u32 attr_valid_nsec; + __u32 dummy; + FuseAttr attr; +} FuseAttrOut; + +typedef struct SFuseMkNodIn { + __u32 mode; + __u32 rdev; + __u32 umask; + __u32 padding; +} FuseMkNodIn; + +typedef struct SFuseMkDirIn { + __u32 mode; + __u32 umask; +} FuseMkDirIn; + +typedef struct SFuseRenameIn { + __u64 newdir; +} FuseRenameIn; + +typedef struct SFuseLinkIn { + __u64 oldnodeid; +} FuseLinkIn; + +typedef struct SFuseSetAttrIn { + __u32 valid; + __u32 padding; + __u64 fh; + __u64 size; + __u64 lock_owner; + __u64 atime; + __u64 mtime; + __u64 unused2; + __u32 atimensec; + __u32 mtimensec; + __u32 unused3; + __u32 mode; + __u32 unused4; + __u32 uid; + __u32 gid; + __u32 unused5; +} FuseSetAttrIn; + +typedef struct SFuseOpenIn { + __u32 flags; + __u32 unused; +} FuseOpenIn; + +typedef struct SFuseCreateIn { + __u32 flags; + __u32 mode; + __u32 umask; + __u32 padding; +} FuseCreateIn; + +typedef struct SFuseOpenOut { + __u64 fh; + __u32 open_flags; + __u32 padding; +} FuseOpenOut; + +typedef struct SFuseReleaseIn { + __u64 fh; + __u32 flags; + __u32 release_flags; + __u64 lock_owner; +} FuseReleaseIn; + +typedef struct SFuseFlushIn { + __u64 fh; + __u32 unused; + __u32 padding; + __u64 lock_owner; +} FuseFlushIn; + +typedef struct SFuseReadIn { + __u64 fh; + __u64 offset; + __u32 size; + __u32 read_flags; + __u64 lock_owner; + __u32 flags; + __u32 padding; +} FuseReadIn; + +typedef struct SFuseWriteIn { + __u64 fh; + __u64 offset; + __u32 size; + __u32 write_flags; + __u64 lock_owner; + __u32 flags; + __u32 padding; +} FuseWriteIn; + +typedef struct SFuseWriteOut { + __u32 size; + __u32 padding; +} FuseWriteOut; + +typedef struct SFuseKstatfs { + __u64 blocks; + __u64 bfree; + __u64 bavail; + __u64 files; + __u64 ffree; + __u32 bsize; + __u32 namelen; + __u32 frsize; + __u32 padding; + __u32 spare[6]; +} FuseKstatfs; + + +typedef struct SFuseStatfsOut { + FuseKstatfs st; +} FuseStatfsOut; + +typedef struct SFuseFsyncIn { + __u64 fh; + __u32 fsync_flags; + __u32 padding; +} FuseFsyncIn; + +typedef struct SFuseSetXAttrIn { + __u32 size; + __u32 flags; +} FuseSetXAttrIn; + +typedef struct SFuseGetXAttrIn { + __u32 size; + __u32 padding; +} FuseGetXAttrIn; + +typedef struct SFuseGetXAttrOut { + __u32 size; + __u32 padding; +} FuseGetXAttrOut; + +typedef struct SFuseFileLock { + __u64 start; + __u64 end; + __u32 type; + __u32 pid; // tgid +} FuseFileLock; + +typedef struct SFuseLkIn { + __u64 fh; + __u64 owner; + FuseFileLock lk; + __u32 lk_flags; + __u32 padding; +} FuseLkIn; + +typedef struct SFuseLkOut { + FuseFileLock lk; +} FuseLkOut; + +typedef struct SFuseAccessIn { + __u32 mask; + __u32 padding; +} FuseAccessIn; + +typedef struct SFuseInitIn { + __u32 major; + __u32 minor; + __u32 max_readahead; + __u32 flags; +} FuseInitIn; + +typedef struct SFuseInitOut { + __u32 major; + __u32 minor; + __u32 max_readahead; + __u32 flags; + __u16 max_background; + __u16 congestion_threshold; + __u32 max_write; +} FuseInitOut; + +typedef struct SCuseInitIn { + __u32 major; + __u32 minor; + __u32 unused; + __u32 flags; +} CuseInitIn; + +typedef struct SCuseInitOut { + __u32 major; + __u32 minor; + __u32 unused; + __u32 flags; + __u32 max_read; + __u32 max_write; + __u32 dev_major; // chardev major + __u32 dev_minor; // chardev minor + __u32 spare[10]; +} CuseInitOut; + +typedef struct SFuseInterruptIn { + __u64 unique; +} FuseInterruptIn; + +typedef struct SFuseBmapIn { + __u64 block; + __u32 blocksize; + __u32 padding; +} FuseBmapIn; + +typedef struct SFuseBmapOut { + __u64 block; +} FuseBmapOut; + +typedef struct SFuseIoctlIn { + __u64 fh; + __u32 flags; + __u32 cmd; + __u64 arg; + __u32 in_size; + __u32 out_size; +} FuseIoctlIn; + +typedef struct SFuseIoctlOut { + __s32 result; + __u32 flags; + __u32 in_iovs; + __u32 out_iovs; +} FuseIoctlOut; + +typedef struct SFusePollIn { + __u64 fh; + __u64 kh; + __u32 flags; + __u32 padding; +} FusePollIn; + +typedef struct SFusePollOut { + __u32 revents; + __u32 padding; +} FusePollOut; + +typedef struct SFuseNotifyPollWakeupOut { + __u64 kh; +} FuseNotifyPollWakeupOut; + +typedef struct SFuseInHeader { + __u32 len; + __u32 opcode; + __u64 unique; + __u64 nodeid; + __u32 uid; + __u32 gid; + __u32 pid; + __u32 padding; +} FuseInHeader; + +typedef struct SFuseOutHeader { + __u32 len; + __s32 error; + __u64 unique; +} FuseOutHeader; + +typedef struct SFuse { + //pthread_mutex_t lock; + __u64 next_generation; + __u64 rootnid; + int fd; +} Fuse; + +typedef struct SFuseHandler { + Fuse* fuse; + int token; + union { + __u8 request_buffer[CLOUD_STORAGE_MAX_REQUEST_SIZE]; + __u8 read_buffer[CLOUD_STORAGE_MAX_READ]; + }; +} FuseHandler; + +#define FUSE_NAME_OFFSET offsetof(FuseDirent, name) +#define FUSE_DIRENT_ALIGN(x) (((x) + sizeof(__u64) - 1) & ~(sizeof(__u64) - 1)) +#define FUSE_DIRENT_SIZE(d) \ + FUSE_DIRENT_ALIGN(FUSE_NAME_OFFSET + (d)->namelen) + + +typedef struct SFuseDirent { + __u64 ino; + __u64 off; + __u32 namelen; + __u32 type; + char name[0]; +} FuseDirent; + +typedef enum eFuseOpcode { + FUSE_LOOKUP = 1, + FUSE_FORGET = 2, // no reply + FUSE_GETATTR = 3, + FUSE_SETATTR = 4, + FUSE_READLINK = 5, + FUSE_SYMLINK = 6, + FUSE_MKNOD = 8, + FUSE_MKDIR = 9, + FUSE_UNLINK = 10, + FUSE_RMDIR = 11, + FUSE_RENAME = 12, + FUSE_LINK = 13, + FUSE_OPEN = 14, + FUSE_READ = 15, + FUSE_WRITE = 16, + FUSE_STATFS = 17, + FUSE_RELEASE = 18, + FUSE_FSYNC = 20, + FUSE_SETXATTR = 21, + FUSE_GETXATTR = 22, + FUSE_LISTXATTR = 23, + FUSE_REMOVEXATTR = 24, + FUSE_FLUSH = 25, + FUSE_INIT = 26, + FUSE_OPENDIR = 27, + FUSE_READDIR = 28, + FUSE_RELEASEDIR = 29, + FUSE_FSYNCDIR = 30, + FUSE_GETLK = 31, + FUSE_SETLK = 32, + FUSE_SETLKW = 33, + FUSE_ACCESS = 34, + FUSE_CREATE = 35, + FUSE_INTERRUPT = 36, + FUSE_BMAP = 37, + FUSE_DESTROY = 38, + FUSE_IOCTL = 39, + FUSE_POLL = 40, + // CUSE specific operations + CUSE_INIT = 4096, +} FuseOpcode; + +#endif // end mozilla_system_fuse_h__ diff --git a/dom/system/gonk/cloudstorage/moz.build b/dom/system/gonk/cloudstorage/moz.build new file mode 100644 index 0000000000000..11f9c490c3272 --- /dev/null +++ b/dom/system/gonk/cloudstorage/moz.build @@ -0,0 +1,65 @@ +# -*- Mode: python; c-basic-offset: 4; indent-tabs-mode: nil; tab-width: 40 -*- +# vim: set filetype=python: +# Copyright 2013 Mozilla Foundation and Mozilla contributors +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +XPIDL_SOURCES += [ + 'nsICloudStorageGeckoInterface.idl', + 'nsICloudStorageInterface.idl', +] + +XPIDL_MODULE = 'dom_system_gonk_cloudstorage' + +EXPORTS += [ + 'CloudStorage.h', + 'CloudStorageLog.h', + 'CloudStorageManager.h', +] + +UNIFIED_SOURCES += [ + 'CloudStorage.cpp', + 'CloudStorageManager.cpp', + 'CloudStorageRequestHandler.cpp', + 'CloudStorageTester.cpp', + 'nsCloudStorageGeckoInterface.cpp', + 'nsCloudStorageGeckoInterfaceModule.cpp', +] + +EXTRA_COMPONENTS += [ + 'nsCloudStorageInterface.js', + 'nsCloudStorageInterface.manifest', +] + +EXTRA_JS_MODULES += [ + 'CloudStorage.jsm', + 'DataCache.jsm', + 'Dropbox.jsm', + 'foco.jsm', + 'MemoryDataStore.jsm', + 'MetaCache.jsm', + 'Sample.jsm', + 'udManager.jsm', +] + +FAIL_ON_WARNINGS = True + +include('/ipc/chromium/chromium-config.mozbuild') + +LOCAL_INCLUDES += [ + '/dom/base', + '/dom/system/gonk', + '/dom/system/gonk/cloudstorage/fuse', +] + +FINAL_LIBRARY = 'xul' diff --git a/dom/system/gonk/cloudstorage/nsCloudStorageGeckoInterface.cpp b/dom/system/gonk/cloudstorage/nsCloudStorageGeckoInterface.cpp new file mode 100644 index 0000000000000..22d040565fe4a --- /dev/null +++ b/dom/system/gonk/cloudstorage/nsCloudStorageGeckoInterface.cpp @@ -0,0 +1,92 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this file, + * You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#include "nsCloudStorageGeckoInterface.h" +#include "CloudStorageLog.h" +#include "CloudStorageManager.h" +#include "CloudStorage.h" +#include "fuse.h" +#include + +using namespace mozilla::system::cloudstorage; +using namespace mozilla; + +NS_IMPL_ISUPPORTS(nsCloudStorageGeckoInterface, nsICloudStorageGeckoInterface) + +nsCloudStorageGeckoInterface::nsCloudStorageGeckoInterface() +{ +} + +nsCloudStorageGeckoInterface::~nsCloudStorageGeckoInterface() +{ +} + +nsresult +nsCloudStorageGeckoInterface::Init() +{ + return NS_OK; +} + +NS_IMETHODIMP +nsCloudStorageGeckoInterface::FinishRequest(const nsACString_internal& aCloudName) +{ + nsCString cloudName(aCloudName); + RefPtr cloudStorage = CloudStorageManager::FindCloudStorageByName(cloudName); + cloudStorage->SetWaitForRequest(false); + return NS_OK; +} + +NS_IMETHODIMP +nsCloudStorageGeckoInterface::SetFileMeta(const nsACString_internal& aCloudName, + const nsACString_internal& aPath, + bool aIsDir, + uint64_t aSize, + uint64_t aMTime, + uint64_t aCTime) +{ + nsCString cloudName(aCloudName); + nsCString path(aPath); + RefPtr cloudStorage = CloudStorageManager::FindCloudStorageByName(cloudName); + cloudStorage->SetAttrByPath(path, aIsDir, aSize, aMTime, aCTime); + return NS_OK; +} + +NS_IMETHODIMP +nsCloudStorageGeckoInterface::SetFileList(const nsACString_internal& aCloudName, + const nsACString_internal& aPath, + const nsACString_internal& aChildPath, + bool aIsDir, + uint64_t aSize, + uint64_t aMTime, + uint64_t aCTime) +{ + nsCString cloudName(aCloudName); + nsCString path(aPath); + nsCString childPath(aChildPath); + RefPtr cloudStorage = CloudStorageManager::FindCloudStorageByName(cloudName); + nsCString entry; + if (path.Equals(NS_LITERAL_CSTRING("/"))) { + childPath.Right(entry, childPath.Length()-path.Length()); + } else { + childPath.Right(entry, childPath.Length()-path.Length()-1); + } + cloudStorage->SetAttrByPath(childPath, aIsDir, aSize, aMTime, aCTime); + cloudStorage->AddEntryByPath(path, entry); + return NS_OK; +} + +NS_IMETHODIMP +nsCloudStorageGeckoInterface::SetData(const nsACString_internal& aCloudName, + uint8_t *aBuffer, + uint32_t aSize) +{ + nsCString cloudName(aCloudName); + char* buffer = (char*) malloc(sizeof(char) * aSize); + memset(buffer, 0, aSize); + memcpy(buffer, aBuffer, aSize); + RefPtr cloudStorage = CloudStorageManager::FindCloudStorageByName(cloudName); + cloudStorage->SetDataBuffer(buffer, aSize); + free(buffer); + return NS_OK; +} diff --git a/dom/system/gonk/cloudstorage/nsCloudStorageGeckoInterface.h b/dom/system/gonk/cloudstorage/nsCloudStorageGeckoInterface.h new file mode 100644 index 0000000000000..50e23053d4c46 --- /dev/null +++ b/dom/system/gonk/cloudstorage/nsCloudStorageGeckoInterface.h @@ -0,0 +1,28 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this file, + * You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#ifndef mozilla_system_cloudstoragegeckointerface_h_ +#define mozilla_system_cloudstoragegeckointerface_h_ + +#include "nsICloudStorageGeckoInterface.h" + +#define NS_CLOUDSTORAGEGECKOINTERFACE_CID \ + {0x08569134, 0x0955, 0x11E5, {0x9B, 0xC4, 0xAE, 0x0F, 0x1D, 0x5D, 0x46, 0xB0}} + +#define NS_CLOUDSTORAGEGECKOINTERFACE_CONTRACT_ID "@mozilla.org/cloudstoragegeckointerface;1" + +class nsCloudStorageGeckoInterface : public nsICloudStorageGeckoInterface +{ +public: + NS_DECL_ISUPPORTS + NS_DECL_NSICLOUDSTORAGEGECKOINTERFACE + + virtual nsresult Init(); + nsCloudStorageGeckoInterface(); + +private: + virtual ~nsCloudStorageGeckoInterface(); +}; + +#endif diff --git a/dom/system/gonk/cloudstorage/nsCloudStorageGeckoInterfaceModule.cpp b/dom/system/gonk/cloudstorage/nsCloudStorageGeckoInterfaceModule.cpp new file mode 100644 index 0000000000000..25128763d6ea3 --- /dev/null +++ b/dom/system/gonk/cloudstorage/nsCloudStorageGeckoInterfaceModule.cpp @@ -0,0 +1,37 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this file, + * You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#include "mozilla/ModuleUtils.h" +#include "nsCloudStorageGeckoInterface.h" + +NS_GENERIC_FACTORY_CONSTRUCTOR_INIT(nsCloudStorageGeckoInterface, Init) + +NS_DEFINE_NAMED_CID(NS_CLOUDSTORAGEGECKOINTERFACE_CID); + +// Build a table of ClassIDs (CIDs) which are implemented by this module. +static const mozilla::Module::CIDEntry kCloudStorageGeckoInterfaceCIDs[] = { + { + &kNS_CLOUDSTORAGEGECKOINTERFACE_CID, // CID + false, // service + nullptr, // factoryproc, usually nullptr. + nsCloudStorageGeckoInterfaceConstructor // constructorproc, defined by NS_GENERIC_FACTORY_CONSTRUCTOR + }, { nullptr } +}; + +// Build a table which maps contract IDs to CIDs. +static const mozilla::Module::ContractIDEntry kCloudStorageGeckoInterfaceContracts[] = { + { + NS_CLOUDSTORAGEGECKOINTERFACE_CONTRACT_ID, &kNS_CLOUDSTORAGEGECKOINTERFACE_CID }, + { nullptr } +}; + +static const mozilla::Module kCloudStorageGeckoInterfaceModule = { + mozilla::Module::kVersion, + kCloudStorageGeckoInterfaceCIDs, + kCloudStorageGeckoInterfaceContracts +}; + +// export “NSModule” +NSMODULE_DEFN(CloudStorageGeckoInterfaceModule) = &kCloudStorageGeckoInterfaceModule; + diff --git a/dom/system/gonk/cloudstorage/nsCloudStorageInterface.js b/dom/system/gonk/cloudstorage/nsCloudStorageInterface.js new file mode 100644 index 0000000000000..6edd06278257b --- /dev/null +++ b/dom/system/gonk/cloudstorage/nsCloudStorageInterface.js @@ -0,0 +1,92 @@ +/* Copyright 2012 Mozilla Foundation and Mozilla contributors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +Components.utils.import("resource://gre/modules/XPCOMUtils.jsm"); +Components.utils.import('resource://gre/modules/Sample.jsm'); +Components.utils.import('resource://gre/modules/Dropbox.jsm'); +Components.utils.import('resource://gre/modules/udManager.jsm'); +Components.utils.import('resource://gre/modules/MetaCache.jsm'); +Components.utils.import('resource://gre/modules/DataCache.jsm'); + +XPCOMUtils.defineLazyModuleGetter(this, "CloudStorageUnidiskManager", + "resource://gre/modules/udManager.jsm"); + +function log(msg) { + dump('CloudStorage: ' + msg + '\n'); +} + +function nsCloudStorageInterface() { + log("nsCloudStorageInterface constructor"); + log("call udManager.init()"); + udManager.init({ + accessToken: + '', + webStorageModule: Sample, + metaCacheModule: MetaCache, + dataCacheModule: DataCache + }) +} + +nsCloudStorageInterface.prototype = { + classDescription: "Cloud storage javascript XPCOM Component", + classID: Components.ID("{2A478E9A-FF9D-11E4-BA25-AC271E5D46B0}"), + contractID: "@mozilla.org/cloudstorageinterface;1", + QueryInterface: XPCOMUtils.generateQI([Components.interfaces.nsICloudStorageInterface]), + getFileMeta: function(cloudname, path) { + log("cloudname: " + cloudname + " " + "path: " + path); + log("call udManager.getFileMeta"); + udManager.getFileMeta(path, function(error, response) { + log(JSON.stringify(response.data)); + var cls, instance; + cls = Components.classes["@mozilla.org/cloudstoragegeckointerface;1"]; + instance = cls.createInstance(Components.interfaces.nsICloudStorageGeckoInterface); + if (response.data) { + instance.setFileMeta(cloudname, path, response.data.list[0].isdir, response.data.list[0].size, response.data.list[0].mtime, response.data.list[0].ctime); + } + instance.finishRequest(cloudname); + }); + }, + + getFileList: function(cloudname, path) { + log("cloudname: " + cloudname + " " + "path: " + path); + log("call udManager.getFileList"); + udManager.getFileList(path, function (error, response) { + log(JSON.stringify(response.data)); + var cls, instance; + cls = Components.classes["@mozilla.org/cloudstoragegeckointerface;1"]; + instance = cls.createInstance(Components.interfaces.nsICloudStorageGeckoInterface); + for (var pathIdx = 0; pathIdx < response.data.list.length; pathIdx++ ) { + var fileData = response.data.list[pathIdx]; + instance.setFileList(cloudname, path, fileData.path, fileData.isdir, fileData.size, fileData.mtime, fileData.ctime); + } + instance.finishRequest(cloudname); + }); + }, + + getData: function(cloudname, path, size, offset) { + log("cloudname: " + cloudname + " " + "path: " + path); + log("call udManager.downloadFileInRange"); + var buffer = new Uint8Array(size); + udManager.downloadFileInRangeByCache(path, buffer, offset, size, function () { + var cls, instance; + cls = Components.classes["@mozilla.org/cloudstoragegeckointerface;1"]; + instance = cls.createInstance(Components.interfaces.nsICloudStorageGeckoInterface); + instance.setData(cloudname, buffer, buffer.byteLength); + instance.finishRequest(cloudname); + }); + } +}; + +this.NSGetFactory = XPCOMUtils.generateNSGetFactory([nsCloudStorageInterface]); diff --git a/dom/system/gonk/cloudstorage/nsCloudStorageInterface.manifest b/dom/system/gonk/cloudstorage/nsCloudStorageInterface.manifest new file mode 100644 index 0000000000000..d5910970a082d --- /dev/null +++ b/dom/system/gonk/cloudstorage/nsCloudStorageInterface.manifest @@ -0,0 +1,17 @@ +# Copyright 2012 Mozilla Foundation and Mozilla contributors +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +# nsCloudStorageInterface.js +component {2A478E9A-FF9D-11E4-BA25-AC271E5D46B0} nsCloudStorageInterface.js +contract @mozilla.org/cloudstorageinterface;1 {2A478E9A-FF9D-11E4-BA25-AC271E5D46B0} diff --git a/dom/system/gonk/cloudstorage/nsICloudStorageGeckoInterface.idl b/dom/system/gonk/cloudstorage/nsICloudStorageGeckoInterface.idl new file mode 100644 index 0000000000000..237ddddf0e3a0 --- /dev/null +++ b/dom/system/gonk/cloudstorage/nsICloudStorageGeckoInterface.idl @@ -0,0 +1,32 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#include "nsISupports.idl" + +[scriptable, uuid(6937FB48-0912-11E5-85D3-611D1E5D46B0)] +interface nsICloudStorageGeckoInterface : nsISupports +{ + void setFileMeta(in AUTF8String cloudname, + in AUTF8String path, + in boolean isDir, + in unsigned long long size, + in unsigned long long mtime, + in unsigned long long ctime); + + void setFileList(in AUTF8String cloudname, + in AUTF8String path, + in AUTF8String childpath, + in boolean isdir, + in unsigned long long size, + in unsigned long long mtime, + in unsigned long long ctime); + + void setData(in AUTF8String cloudname, + [array, size_is(length)] in octet buffer, + in unsigned long length ); + + void finishRequest(in AUTF8String cloudname); + +}; + diff --git a/dom/system/gonk/cloudstorage/nsICloudStorageInterface.idl b/dom/system/gonk/cloudstorage/nsICloudStorageInterface.idl new file mode 100644 index 0000000000000..4f65e821067d3 --- /dev/null +++ b/dom/system/gonk/cloudstorage/nsICloudStorageInterface.idl @@ -0,0 +1,21 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#include "nsISupports.idl" + +[scriptable, uuid(2A478E9A-FF9D-11E4-BA25-AC271E5D46B0)] +interface nsICloudStorageInterface : nsISupports +{ + void getFileMeta(in AUTF8String cloudname, + in AUTF8String path); + + void getFileList(in AUTF8String cloudname, + in AUTF8String path); + + void getData(in AUTF8String cloudname, + in AUTF8String path, + in unsigned long long size, + in unsigned long long offset); +}; + diff --git a/dom/system/gonk/cloudstorage/udManager.jsm b/dom/system/gonk/cloudstorage/udManager.jsm new file mode 100644 index 0000000000000..683208a9f05e9 --- /dev/null +++ b/dom/system/gonk/cloudstorage/udManager.jsm @@ -0,0 +1,287 @@ +const { classes: Cc, interfaces: Ci, utils: Cu } = Components; + +Cu.import('resource://gre/modules/foco.jsm'); +const { console } = Cu.import("resource://gre/modules/devtools/Console.jsm", {}); +Cu.import('resource://gre/modules/XPCOMUtils.jsm'); +XPCOMUtils.defineLazyModuleGetter(this, 'setTimeout', + 'resource://gre/modules/Timer.jsm'); + +var UD_BLOCK_SIZE = 1*1024*1024; +var UD_QUEUE_SIZE = 3; +var UD_PREFETCH_SIZE = 10 * UD_BLOCK_SIZE; + +var udManager = {}; + +udManager._isIllegalFileName = function (path) { + var list = path.split('/'); + for(var i = 0; i < list.length; i++){ + if( list[i].indexOf('.') === 0 ){ + return true; + } + } + return false; +} + +udManager.queueHandler = function (id, task, callback) { + console.log(' [B] ' + task.path + "|" + task.offset + '| downloading...'); + var self = this; + task.status = "DOWNLOADING"; + this.downloadFileInRange(task.path, task.offset, task.size, function(error, response){ + console.log(task.path + "|" + task.offset + '| done!! ' + response.length); + + // Write the buffer to the cache file. + self.dataCache.writeCache(task, response.data, function(){ + callback(); + }); + }); +}; + +udManager.init = function(options){ + this.webStorage = options.webStorageModule; + this.metaCache = options.metaCacheModule; + this.dataCache = options.dataCacheModule; + + this.webStorage.init({ + accessToken: options.accessToken + }); + this.metaCache.init(); + this.dataCache.init(UD_BLOCK_SIZE); + this.FileDownloadQueue = foco.priorityQueue( + this.queueHandler.bind(this), UD_QUEUE_SIZE); +} + +udManager.showStat = function (cb) { + var self = this; + var retry = function () { + if( udManager.QuotaCache ) { + cb(null, udManager.QuotaCache ); + } else { + self.webStorage.quota(function(error, response){ + if(error){ + console.log("" + new Date () + "| " + error); + retry(); + }else{ + udManager.QuotaCache = response; + cb(error, response); + } + }); + } + }; + retry(); +} + +udManager.getFileMeta = function (path, cb) { + if(udManager._isIllegalFileName(path)){ + cb(null, {data: null}); + return ; + } + var self = this; + var retry = function () { + var meta = self.metaCache.get(path); + if (meta) { + cb(null, { data : meta }); + }else{ + self.webStorage.getFileMeta(path, function(error, response){ + if(error){ + console.log("" + new Date () + "| " + error); + retry(); + }else{ + self.metaCache.update(path, response.data); + cb(error, response); + } + }); + } + }; + retry(); +} + +udManager.getFileList = function (path, cb) { + if(udManager._isIllegalFileName(path)){ + cb(null, {data: null}); + return ; + } + var self = this; + var retry = function () { + var list = self.metaCache.getList(path); + if (list) { + cb(null, { data : list }); + }else{ + self.webStorage.getFileList(path, function(error, response){ + if(error){ + console.log("" + new Date () + "| " + error); + retry(); + }else{ + self.metaCache.updateList(path, response.data); + cb(error, response); + } + }); + } + }; + retry(); +} + +udManager._generateRequestList = function(fileMeta, offset, size, fileSize){ + const endPos = offset + size; + var requestList = []; + + var alignedOffset = Math.floor( offset / UD_BLOCK_SIZE) * UD_BLOCK_SIZE; + for(; alignedOffset < endPos && alignedOffset < fileSize; alignedOffset += UD_BLOCK_SIZE ){ + var task = { + path: fileMeta.path, + totalSize: fileMeta.size, + mtime: fileMeta.mtime, + status: "INIT", + priority: "HIGH", + md5sum: "", + offset: alignedOffset, + size: ((alignedOffset + UD_BLOCK_SIZE) > fileSize ? (fileSize - alignedOffset) : UD_BLOCK_SIZE ) + }; + var taskMd5sum = this.dataCache.generateKey(task); + task.md5sum = taskMd5sum; + + requestList.push(task); + } + + const prefetchEndPos = endPos + UD_PREFETCH_SIZE; + for(; alignedOffset < prefetchEndPos && alignedOffset < fileSize; alignedOffset += UD_BLOCK_SIZE ){ + var task = { + path: fileMeta.path, + totalSize: fileMeta.size, + mtime: fileMeta.mtime, + status: "INIT", + priority: "PREFETCH", + md5sum: "", + offset: alignedOffset, + size: ((alignedOffset + UD_BLOCK_SIZE) > fileSize ? (fileSize - alignedOffset) : UD_BLOCK_SIZE ) + }; + var taskMd5sum = this.dataCache.generateKey(task); + task.md5sum = taskMd5sum; + + requestList.push(task); + } + + return requestList; +} + +udManager._isAllRequestDone = function (downloadRequest){ + var done = true; + for(var req in downloadRequest){ + var task = downloadRequest[req]; + var taskMd5sum = task.md5sum; + if( task.priority === "PREFETCH" ){ + continue; + } + var data = this.dataCache.get(taskMd5sum); + if (data && data.status === 'DONE') { + // do nothing. + }else{ + done = false; + break; + } + } + return done; +} + +udManager._requestPushAndDownload = function (path, downloadRequest, cb){ + var self = this; + foco.each(downloadRequest, function(index, task, callback){ + var taskMd5sum = task.md5sum; + var data = self.dataCache.get(taskMd5sum); + + if (data) { + console.log(' [C1] ' + data.path + " is in cache: " + data.status + "| " + task.offset); + udManager.FileDownloadQueue.priorityChange(taskMd5sum, 0); + callback(); + } else if ( task.priority === "PREFETCH" ) { + self.dataCache.update(taskMd5sum, task); + udManager.FileDownloadQueue.push(taskMd5sum, 1, task); + callback(); + }else{ + self.dataCache.update(taskMd5sum, task); + udManager.FileDownloadQueue.push(taskMd5sum, 0, task); + callback(); + } + }, function(err){ + // Verify the download request is all finished or not. + function retry () { + if( udManager._isAllRequestDone(downloadRequest) ){ + console.log(' [D] ' + 'All requests are done.'); + cb(); + }else { + console.log("retry to wait all requests done..."); + setTimeout(retry, 1000); + } + } + retry(); + }); +} + +udManager.downloadFileInRangeByCache = function(path, buffer, offset, size, cb) { + console.log('{{'); + console.log(' [A] ' + path + ' ' + offset + ' ' + size); + var self = this; + udManager.getFileMeta(path, function(error, response){ + const totalSize = response.data.list[0].size; + // 1. Split the download request. + var requestList = udManager._generateRequestList(response.data.list[0], parseInt(offset), parseInt(size), totalSize); + + // 2. Push downloading request. + udManager._requestPushAndDownload(path, requestList, function(){ + // 3. All requests are done. Aggregate all data. + // Read the request data from files. + self.dataCache.readCache(path, buffer, offset, size, requestList, function(){ + console.log(' [E] data is prepared.'); + console.log('}}'); + cb(null); + }); + }); + }); +} + +udManager.downloadFileInRange = function(path, offset, size, cb) { + var self = this; + var retry = function () { + self.webStorage.getFileDownload(path, offset, size, function(error, response){ + if(error){ + console.log('[ERROR] retry, error happened: ' + error); + setTimeout(retry , 800); + }else if( !response || !response.data || !response.data instanceof ArrayBuffer ){ + console.log('[ERROR] retry, error response: ' + response); + setTimeout(retry , 800); + }else if( size != response.length ){ + console.log('[ERROR] retry, size error: ' + offset + " " + size + " " + response.length); + setTimeout(retry , 800); + }else{ + cb(error, response); + } + }); + } + retry(); +} + +udManager.downloadFileInMultiRange = function(path, list, cb) { + var listArray = null; + if( typeof list === "string" ){ + try { + listArray = JSON.parse(list).list; + } catch (e) { + cb("Incorrect download list.", null); + return ; + } + }else{ + listArray = list.list; + } + foco.each(listArray, function(index, item, callback){ + udManager.downloadFileInRange(path, item.offset, item.size, function(error, response){ + console.log(response.data); + callback(); + }); + }, function(){ + cb(null, { + data: "OK!" + }); + }); +} + +this.EXPORTED_SYMBOLS = ['udManager']; +this.udManager = udManager; diff --git a/dom/system/gonk/moz.build b/dom/system/gonk/moz.build index e4aadabb1f096..9930fda29e7f8 100644 --- a/dom/system/gonk/moz.build +++ b/dom/system/gonk/moz.build @@ -14,6 +14,8 @@ # See the License for the specific language governing permissions and # limitations under the License. +DIRS += ['cloudstorage'] + XPIDL_SOURCES += [ 'nsIAudioManager.idl', 'nsINetworkInterfaceListService.idl', @@ -115,6 +117,8 @@ LOCAL_INCLUDES += [ '/dom/base', '/dom/bluetooth', '/dom/geolocation', + '/dom/system/gonk/cloudstorage', + '/dom/system/gonk/cloudstorage/fuse', '/dom/wifi', ] diff --git a/dom/webidl/CloudStorageService.webidl b/dom/webidl/CloudStorageService.webidl new file mode 100644 index 0000000000000..1b0b63cd6ed11 --- /dev/null +++ b/dom/webidl/CloudStorageService.webidl @@ -0,0 +1,18 @@ +/* -*- Mode: IDL; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +enum CloudStorageType{ + "Dummy", + "Dropbox", +}; + +interface CloudStorageService : EventTarget +{ + [Throws] + Promise enable(DOMString aName, CloudStorageType type, DOMString accessToken); + [Throws] + Promise disable(DOMString aName); +}; + diff --git a/dom/webidl/Navigator.webidl b/dom/webidl/Navigator.webidl index 175e752624892..6adcdc54b27ab 100644 --- a/dom/webidl/Navigator.webidl +++ b/dom/webidl/Navigator.webidl @@ -253,6 +253,11 @@ partial interface Navigator { sequence getDeviceStorages(DOMString type); }; +partial interface Navigator { + [Throws] + readonly attribute CloudStorageService cloudStorageService; +}; + // nsIDOMNavigatorDesktopNotification partial interface Navigator { [Throws, Pref="notification.feature.enabled", UnsafeInPrerendering] diff --git a/dom/webidl/moz.build b/dom/webidl/moz.build index 5ddfa81842b85..f7e4f3251947e 100644 --- a/dom/webidl/moz.build +++ b/dom/webidl/moz.build @@ -76,6 +76,7 @@ WEBIDL_FILES = [ 'Client.webidl', 'Clients.webidl', 'ClipboardEvent.webidl', + 'CloudStorageService.webidl', 'CommandEvent.webidl', 'Comment.webidl', 'CompositionEvent.webidl',