/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ /* vim: set ts=2 sw=2 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/. */ #ifndef DeviceStorage_h #define DeviceStorage_h #include "nsIDOMDeviceStorage.h" #include "nsIFile.h" #include "nsIPrincipal.h" #include "nsIObserver.h" #include "nsDOMEventTargetHelper.h" #include "mozilla/RefPtr.h" #include "mozilla/StaticPtr.h" #include "DOMRequest.h" #define DEVICESTORAGE_PICTURES "pictures" #define DEVICESTORAGE_VIDEOS "videos" #define DEVICESTORAGE_MUSIC "music" #define DEVICESTORAGE_APPS "apps" #define DEVICESTORAGE_SDCARD "sdcard" namespace mozilla { namespace dom { class DeviceStorageEnumerationParameters; class DOMCursor; class DOMRequest; } // namespace dom } // namespace mozilla class DeviceStorageFile MOZ_FINAL : public nsISupports { public: nsCOMPtr mFile; nsString mStorageType; nsString mStorageName; nsString mRootDir; nsString mPath; bool mEditable; nsString mMimeType; uint64_t mLength; uint64_t mLastModifiedDate; // Used when the path will be set later via SetPath. DeviceStorageFile(const nsAString& aStorageType, const nsAString& aStorageName); // Used for non-enumeration purposes. DeviceStorageFile(const nsAString& aStorageType, const nsAString& aStorageName, const nsAString& aPath); // Used for enumerations. When you call Enumerate, you can pass in a directory to enumerate // and the results that are returned are relative to that directory, files related to an // enumeration need to know the "root of the enumeration" directory. DeviceStorageFile(const nsAString& aStorageType, const nsAString& aStorageName, const nsAString& aRootDir, const nsAString& aPath); void SetPath(const nsAString& aPath); void SetEditable(bool aEditable); static already_AddRefed CreateUnique(nsAString& aFileName, uint32_t aFileType, uint32_t aFileAttributes); NS_DECL_ISUPPORTS bool IsAvailable(); bool IsComposite(); void GetCompositePath(nsAString& aCompositePath); // we want to make sure that the names of file can't reach // outside of the type of storage the user asked for. bool IsSafePath(); bool IsSafePath(const nsAString& aPath); void Dump(const char* label); nsresult Remove(); nsresult Write(nsIInputStream* aInputStream); nsresult Write(InfallibleTArray& bits); void CollectFiles(nsTArray >& aFiles, PRTime aSince = 0); void collectFilesInternal(nsTArray >& aFiles, PRTime aSince, nsAString& aRootPath); void AccumDiskUsage(uint64_t* aPicturesSoFar, uint64_t* aVideosSoFar, uint64_t* aMusicSoFar, uint64_t* aTotalSoFar); void GetDiskFreeSpace(int64_t* aSoFar); void GetStatus(nsAString& aStatus); static void GetRootDirectoryForType(const nsAString& aStorageType, const nsAString& aStorageName, nsIFile** aFile); nsresult CalculateSizeAndModifiedDate(); nsresult CalculateMimeType(); private: void Init(); void NormalizeFilePath(); void AppendRelativePath(const nsAString& aPath); void GetStatusInternal(nsAString& aStorageName, nsAString& aStatus); void AccumDirectoryUsage(nsIFile* aFile, uint64_t* aPicturesSoFar, uint64_t* aVideosSoFar, uint64_t* aMusicSoFar, uint64_t* aTotalSoFar); }; /* The FileUpdateDispatcher converts file-watcher-notify observer events to file-watcher-update events. This is used to be able to broadcast events from one child to another child in B2G. (f.e., if one child decides to add a file, we want to be able to able to send a onchange notifications to every other child watching that device storage object). We create this object (via GetSingleton) in two places: * ContentParent::Init (for IPC) * nsDOMDeviceStorage::Init (for non-ipc) */ class FileUpdateDispatcher MOZ_FINAL : public nsIObserver { public: NS_DECL_ISUPPORTS NS_DECL_NSIOBSERVER static FileUpdateDispatcher* GetSingleton(); private: static mozilla::StaticRefPtr sSingleton; }; class nsDOMDeviceStorage MOZ_FINAL : public nsDOMEventTargetHelper , public nsIDOMDeviceStorage , public nsIObserver { typedef mozilla::ErrorResult ErrorResult; typedef mozilla::dom::DeviceStorageEnumerationParameters EnumerationParameters; typedef mozilla::dom::DOMCursor DOMCursor; typedef mozilla::dom::DOMRequest DOMRequest; public: typedef nsTArray VolumeNameArray; NS_DECL_ISUPPORTS_INHERITED NS_DECL_NSIDOMDEVICESTORAGE NS_DECL_NSIOBSERVER NS_DECL_NSIDOMEVENTTARGET virtual void AddEventListener(const nsAString& aType, nsIDOMEventListener* aListener, bool aUseCapture, const mozilla::dom::Nullable& aWantsUntrusted, ErrorResult& aRv) MOZ_OVERRIDE; virtual void RemoveEventListener(const nsAString& aType, nsIDOMEventListener* aListener, bool aUseCapture, ErrorResult& aRv) MOZ_OVERRIDE; nsDOMDeviceStorage(); nsresult Init(nsPIDOMWindow* aWindow, const nsAString& aType, nsTArray >& aStores); nsresult Init(nsPIDOMWindow* aWindow, const nsAString& aType, const nsAString& aVolName); bool IsAvailable(); void SetRootDirectoryForType(const nsAString& aType, const nsAString& aVolName); // WebIDL nsPIDOMWindow* GetParentObject() const { return GetOwner(); } virtual JSObject* WrapObject(JSContext* aCx, JS::Handle aScope) MOZ_OVERRIDE; IMPL_EVENT_HANDLER(change) already_AddRefed Add(nsIDOMBlob* aBlob, ErrorResult& aRv); already_AddRefed AddNamed(nsIDOMBlob* aBlob, const nsAString& aPath, ErrorResult& aRv); already_AddRefed Get(const nsAString& aPath, ErrorResult& aRv) { return GetInternal(aPath, false, aRv); } already_AddRefed GetEditable(const nsAString& aPath, ErrorResult& aRv) { return GetInternal(aPath, true, aRv); } already_AddRefed Delete(const nsAString& aPath, ErrorResult& aRv); already_AddRefed Enumerate(const EnumerationParameters& aOptions, ErrorResult& aRv) { return Enumerate(NullString(), aOptions, aRv); } already_AddRefed Enumerate(const nsAString& aPath, const EnumerationParameters& aOptions, ErrorResult& aRv); already_AddRefed EnumerateEditable(const EnumerationParameters& aOptions, ErrorResult& aRv) { return EnumerateEditable(NullString(), aOptions, aRv); } already_AddRefed EnumerateEditable(const nsAString& aPath, const EnumerationParameters& aOptions, ErrorResult& aRv); already_AddRefed FreeSpace(ErrorResult& aRv); already_AddRefed UsedSpace(ErrorResult& aRv); already_AddRefed Available(ErrorResult& aRv); // Uses XPCOM GetStorageName static void CreateDeviceStorageFor(nsPIDOMWindow* aWin, const nsAString& aType, nsDOMDeviceStorage** aStore); static void CreateDeviceStoragesFor(nsPIDOMWindow* aWin, const nsAString& aType, nsTArray >& aStores, bool aCompositeComponent); void Shutdown(); static void GetOrderedVolumeNames(nsTArray& aVolumeNames); static void GetWritableStorageName(const nsAString& aStorageType, nsAString &aStorageName); static bool ParseCompositePath(const nsAString& aCompositePath, nsAString& aOutStorageName, nsAString& aOutStoragePath); private: ~nsDOMDeviceStorage(); already_AddRefed GetInternal(const nsAString& aPath, bool aEditable, ErrorResult& aRv); void GetInternal(nsPIDOMWindow* aWin, const nsAString& aPath, DOMRequest* aRequest, bool aEditable); void DeleteInternal(nsPIDOMWindow* aWin, const nsAString& aPath, DOMRequest* aRequest); already_AddRefed EnumerateInternal(const nsAString& aName, const EnumerationParameters& aOptions, bool aEditable, ErrorResult& aRv); nsString mStorageType; nsCOMPtr mRootDirectory; nsString mStorageName; bool mCompositeComponent; // A composite device storage object is one which front-ends for multiple // real storage objects. The real storage objects will each be stored in // mStores and will each have a unique mStorageName. The composite storage // object will have mStorageName == "", and mRootDirectory will be null. // // Note that on desktop (or other non-gonk), composite storage areas // don't exist, and mStorageName will also be "". // // A device storage object which is stored in mStores is considered to be // a composite component. bool IsComposite() { return mStores.Length() > 0; } bool IsCompositeComponent() { return mCompositeComponent; } nsTArray > mStores; already_AddRefed GetStorage(const nsAString& aCompositePath, nsAString& aOutStoragePath); already_AddRefed GetStorageByName(const nsAString &aStorageName); nsCOMPtr mPrincipal; bool mIsWatchingFile; bool mAllowedToWatchFile; nsresult Notify(const char* aReason, class DeviceStorageFile* aFile); friend class WatchFileEvent; friend class DeviceStorageRequest; class VolumeNameCache : public mozilla::RefCounted { public: nsTArray mVolumeNames; }; static mozilla::StaticRefPtr sVolumeNameCache; #ifdef MOZ_WIDGET_GONK void DispatchMountChangeEvent(nsAString& aVolumeName, nsAString& aVolumeStatus); #endif // nsIDOMDeviceStorage.type enum { DEVICE_STORAGE_TYPE_DEFAULT = 0, DEVICE_STORAGE_TYPE_SHARED, DEVICE_STORAGE_TYPE_EXTERNAL }; }; #endif