michael@0: /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ michael@0: /* vim: set ts=2 sw=2 et tw=80: */ michael@0: /* This Source Code Form is subject to the terms of the Mozilla Public michael@0: * License, v. 2.0. If a copy of the MPL was not distributed with this file, michael@0: * You can obtain one at http://mozilla.org/MPL/2.0/. */ michael@0: michael@0: #ifndef DeviceStorage_h michael@0: #define DeviceStorage_h michael@0: michael@0: #include "nsIDOMDeviceStorage.h" michael@0: #include "nsIFile.h" michael@0: #include "nsIPrincipal.h" michael@0: #include "nsIObserver.h" michael@0: #include "mozilla/DOMEventTargetHelper.h" michael@0: #include "mozilla/RefPtr.h" michael@0: #include "mozilla/StaticPtr.h" michael@0: #include "mozilla/dom/DOMRequest.h" michael@0: michael@0: #define DEVICESTORAGE_PICTURES "pictures" michael@0: #define DEVICESTORAGE_VIDEOS "videos" michael@0: #define DEVICESTORAGE_MUSIC "music" michael@0: #define DEVICESTORAGE_APPS "apps" michael@0: #define DEVICESTORAGE_SDCARD "sdcard" michael@0: #define DEVICESTORAGE_CRASHES "crashes" michael@0: michael@0: class DeviceStorageFile; michael@0: class nsIInputStream; michael@0: michael@0: namespace mozilla { michael@0: class EventListenerManager; michael@0: namespace dom { michael@0: class DeviceStorageEnumerationParameters; michael@0: class DOMCursor; michael@0: class DOMRequest; michael@0: class Promise; michael@0: class DeviceStorageFileSystem; michael@0: } // namespace dom michael@0: namespace ipc { michael@0: class FileDescriptor; michael@0: } michael@0: } // namespace mozilla michael@0: michael@0: class DeviceStorageFile MOZ_FINAL michael@0: : public nsISupports { michael@0: public: michael@0: nsCOMPtr mFile; michael@0: nsString mStorageType; michael@0: nsString mStorageName; michael@0: nsString mRootDir; michael@0: nsString mPath; michael@0: bool mEditable; michael@0: nsString mMimeType; michael@0: uint64_t mLength; michael@0: uint64_t mLastModifiedDate; michael@0: michael@0: // Used when the path will be set later via SetPath. michael@0: DeviceStorageFile(const nsAString& aStorageType, michael@0: const nsAString& aStorageName); michael@0: // Used for non-enumeration purposes. michael@0: DeviceStorageFile(const nsAString& aStorageType, michael@0: const nsAString& aStorageName, michael@0: const nsAString& aPath); michael@0: // Used for enumerations. When you call Enumerate, you can pass in a michael@0: // directory to enumerate and the results that are returned are relative to michael@0: // that directory, files related to an enumeration need to know the "root of michael@0: // the enumeration" directory. michael@0: DeviceStorageFile(const nsAString& aStorageType, michael@0: const nsAString& aStorageName, michael@0: const nsAString& aRootDir, michael@0: const nsAString& aPath); michael@0: michael@0: void SetPath(const nsAString& aPath); michael@0: void SetEditable(bool aEditable); michael@0: michael@0: static already_AddRefed michael@0: CreateUnique(nsAString& aFileName, michael@0: uint32_t aFileType, michael@0: uint32_t aFileAttributes); michael@0: michael@0: NS_DECL_THREADSAFE_ISUPPORTS michael@0: michael@0: bool IsAvailable(); michael@0: void GetFullPath(nsAString& aFullPath); michael@0: michael@0: // we want to make sure that the names of file can't reach michael@0: // outside of the type of storage the user asked for. michael@0: bool IsSafePath(); michael@0: bool IsSafePath(const nsAString& aPath); michael@0: michael@0: void Dump(const char* label); michael@0: michael@0: nsresult Remove(); michael@0: nsresult Write(nsIInputStream* aInputStream); michael@0: nsresult Write(InfallibleTArray& bits); michael@0: void CollectFiles(nsTArray >& aFiles, michael@0: PRTime aSince = 0); michael@0: void collectFilesInternal(nsTArray >& aFiles, michael@0: PRTime aSince, nsAString& aRootPath); michael@0: michael@0: void AccumDiskUsage(uint64_t* aPicturesSoFar, uint64_t* aVideosSoFar, michael@0: uint64_t* aMusicSoFar, uint64_t* aTotalSoFar); michael@0: michael@0: void GetDiskFreeSpace(int64_t* aSoFar); michael@0: void GetStatus(nsAString& aStatus); michael@0: void GetStorageStatus(nsAString& aStatus); michael@0: void DoFormat(nsAString& aStatus); michael@0: void DoMount(nsAString& aStatus); michael@0: void DoUnmount(nsAString& aStatus); michael@0: static void GetRootDirectoryForType(const nsAString& aStorageType, michael@0: const nsAString& aStorageName, michael@0: nsIFile** aFile); michael@0: michael@0: nsresult CalculateSizeAndModifiedDate(); michael@0: nsresult CalculateMimeType(); michael@0: nsresult CreateFileDescriptor(mozilla::ipc::FileDescriptor& aFileDescriptor); michael@0: michael@0: private: michael@0: void Init(); michael@0: void NormalizeFilePath(); michael@0: void AppendRelativePath(const nsAString& aPath); michael@0: void AccumDirectoryUsage(nsIFile* aFile, michael@0: uint64_t* aPicturesSoFar, michael@0: uint64_t* aVideosSoFar, michael@0: uint64_t* aMusicSoFar, michael@0: uint64_t* aTotalSoFar); michael@0: }; michael@0: michael@0: /* michael@0: The FileUpdateDispatcher converts file-watcher-notify michael@0: observer events to file-watcher-update events. This is michael@0: used to be able to broadcast events from one child to michael@0: another child in B2G. (f.e., if one child decides to add michael@0: a file, we want to be able to able to send a onchange michael@0: notifications to every other child watching that device michael@0: storage object). michael@0: michael@0: We create this object (via GetSingleton) in two places: michael@0: * ContentParent::Init (for IPC) michael@0: * nsDOMDeviceStorage::Init (for non-ipc) michael@0: */ michael@0: class FileUpdateDispatcher MOZ_FINAL michael@0: : public nsIObserver michael@0: { michael@0: public: michael@0: NS_DECL_ISUPPORTS michael@0: NS_DECL_NSIOBSERVER michael@0: michael@0: static FileUpdateDispatcher* GetSingleton(); michael@0: private: michael@0: static mozilla::StaticRefPtr sSingleton; michael@0: }; michael@0: michael@0: class nsDOMDeviceStorage MOZ_FINAL michael@0: : public mozilla::DOMEventTargetHelper michael@0: , public nsIDOMDeviceStorage michael@0: , public nsIObserver michael@0: { michael@0: typedef mozilla::ErrorResult ErrorResult; michael@0: typedef mozilla::dom::DeviceStorageEnumerationParameters michael@0: EnumerationParameters; michael@0: typedef mozilla::dom::DOMCursor DOMCursor; michael@0: typedef mozilla::dom::DOMRequest DOMRequest; michael@0: typedef mozilla::dom::Promise Promise; michael@0: typedef mozilla::dom::DeviceStorageFileSystem DeviceStorageFileSystem; michael@0: public: michael@0: typedef nsTArray VolumeNameArray; michael@0: michael@0: NS_DECL_ISUPPORTS_INHERITED michael@0: NS_DECL_NSIDOMDEVICESTORAGE michael@0: michael@0: NS_DECL_NSIOBSERVER michael@0: NS_DECL_NSIDOMEVENTTARGET michael@0: michael@0: virtual mozilla::EventListenerManager* michael@0: GetExistingListenerManager() const MOZ_OVERRIDE; michael@0: virtual mozilla::EventListenerManager* michael@0: GetOrCreateListenerManager() MOZ_OVERRIDE; michael@0: michael@0: virtual void michael@0: AddEventListener(const nsAString& aType, michael@0: mozilla::dom::EventListener* aListener, michael@0: bool aUseCapture, michael@0: const mozilla::dom::Nullable& aWantsUntrusted, michael@0: ErrorResult& aRv) MOZ_OVERRIDE; michael@0: michael@0: virtual void RemoveEventListener(const nsAString& aType, michael@0: mozilla::dom::EventListener* aListener, michael@0: bool aUseCapture, michael@0: ErrorResult& aRv) MOZ_OVERRIDE; michael@0: michael@0: nsDOMDeviceStorage(nsPIDOMWindow* aWindow); michael@0: michael@0: nsresult Init(nsPIDOMWindow* aWindow, const nsAString& aType, michael@0: const nsAString& aVolName); michael@0: michael@0: bool IsAvailable(); michael@0: bool IsFullPath(const nsAString& aPath) michael@0: { michael@0: return aPath.Length() > 0 && aPath.CharAt(0) == '/'; michael@0: } michael@0: michael@0: void SetRootDirectoryForType(const nsAString& aType, michael@0: const nsAString& aVolName); michael@0: michael@0: // WebIDL michael@0: nsPIDOMWindow* michael@0: GetParentObject() const michael@0: { michael@0: return GetOwner(); michael@0: } michael@0: virtual JSObject* michael@0: WrapObject(JSContext* aCx) MOZ_OVERRIDE; michael@0: michael@0: IMPL_EVENT_HANDLER(change) michael@0: michael@0: already_AddRefed michael@0: Add(nsIDOMBlob* aBlob, ErrorResult& aRv); michael@0: already_AddRefed michael@0: AddNamed(nsIDOMBlob* aBlob, const nsAString& aPath, ErrorResult& aRv); michael@0: michael@0: already_AddRefed michael@0: Get(const nsAString& aPath, ErrorResult& aRv) michael@0: { michael@0: return GetInternal(aPath, false, aRv); michael@0: } michael@0: already_AddRefed michael@0: GetEditable(const nsAString& aPath, ErrorResult& aRv) michael@0: { michael@0: return GetInternal(aPath, true, aRv); michael@0: } michael@0: already_AddRefed michael@0: Delete(const nsAString& aPath, ErrorResult& aRv); michael@0: michael@0: already_AddRefed michael@0: Enumerate(const EnumerationParameters& aOptions, ErrorResult& aRv) michael@0: { michael@0: return Enumerate(NullString(), aOptions, aRv); michael@0: } michael@0: already_AddRefed michael@0: Enumerate(const nsAString& aPath, const EnumerationParameters& aOptions, michael@0: ErrorResult& aRv); michael@0: already_AddRefed michael@0: EnumerateEditable(const EnumerationParameters& aOptions, ErrorResult& aRv) michael@0: { michael@0: return EnumerateEditable(NullString(), aOptions, aRv); michael@0: } michael@0: already_AddRefed michael@0: EnumerateEditable(const nsAString& aPath, michael@0: const EnumerationParameters& aOptions, ErrorResult& aRv); michael@0: michael@0: already_AddRefed FreeSpace(ErrorResult& aRv); michael@0: already_AddRefed UsedSpace(ErrorResult& aRv); michael@0: already_AddRefed Available(ErrorResult& aRv); michael@0: already_AddRefed Format(ErrorResult& aRv); michael@0: already_AddRefed StorageStatus(ErrorResult& aRv); michael@0: already_AddRefed Mount(ErrorResult& aRv); michael@0: already_AddRefed Unmount(ErrorResult& aRv); michael@0: michael@0: bool Default(); michael@0: michael@0: // Uses XPCOM GetStorageName michael@0: michael@0: already_AddRefed michael@0: GetRoot(); michael@0: michael@0: static void michael@0: CreateDeviceStorageFor(nsPIDOMWindow* aWin, michael@0: const nsAString& aType, michael@0: nsDOMDeviceStorage** aStore); michael@0: michael@0: static void michael@0: CreateDeviceStoragesFor(nsPIDOMWindow* aWin, michael@0: const nsAString& aType, michael@0: nsTArray >& aStores); michael@0: michael@0: void Shutdown(); michael@0: michael@0: static void GetOrderedVolumeNames(nsTArray& aVolumeNames); michael@0: michael@0: static void GetDefaultStorageName(const nsAString& aStorageType, michael@0: nsAString &aStorageName); michael@0: michael@0: static bool ParseFullPath(const nsAString& aFullPath, michael@0: nsAString& aOutStorageName, michael@0: nsAString& aOutStoragePath); michael@0: private: michael@0: ~nsDOMDeviceStorage(); michael@0: michael@0: already_AddRefed michael@0: GetInternal(const nsAString& aPath, bool aEditable, ErrorResult& aRv); michael@0: michael@0: void michael@0: GetInternal(nsPIDOMWindow* aWin, const nsAString& aPath, DOMRequest* aRequest, michael@0: bool aEditable); michael@0: michael@0: void michael@0: DeleteInternal(nsPIDOMWindow* aWin, const nsAString& aPath, michael@0: DOMRequest* aRequest); michael@0: michael@0: already_AddRefed michael@0: EnumerateInternal(const nsAString& aName, michael@0: const EnumerationParameters& aOptions, bool aEditable, michael@0: ErrorResult& aRv); michael@0: michael@0: nsString mStorageType; michael@0: nsCOMPtr mRootDirectory; michael@0: nsString mStorageName; michael@0: michael@0: already_AddRefed GetStorage(const nsAString& aFullPath, michael@0: nsAString& aOutStoragePath); michael@0: already_AddRefed michael@0: GetStorageByName(const nsAString &aStorageName); michael@0: michael@0: nsCOMPtr mPrincipal; michael@0: michael@0: bool mIsWatchingFile; michael@0: bool mAllowedToWatchFile; michael@0: michael@0: nsresult Notify(const char* aReason, class DeviceStorageFile* aFile); michael@0: michael@0: friend class WatchFileEvent; michael@0: friend class DeviceStorageRequest; michael@0: michael@0: static mozilla::StaticAutoPtr> sVolumeNameCache; michael@0: michael@0: #ifdef MOZ_WIDGET_GONK michael@0: nsString mLastStatus; michael@0: void DispatchMountChangeEvent(nsAString& aVolumeStatus); michael@0: #endif michael@0: michael@0: // nsIDOMDeviceStorage.type michael@0: enum { michael@0: DEVICE_STORAGE_TYPE_DEFAULT = 0, michael@0: DEVICE_STORAGE_TYPE_SHARED, michael@0: DEVICE_STORAGE_TYPE_EXTERNAL michael@0: }; michael@0: michael@0: nsRefPtr mFileSystem; michael@0: }; michael@0: michael@0: #endif