michael@0: /* -*- Mode: c++; c-basic-offset: 2; indent-tabs-mode: nil; tab-width: 40 -*- */ michael@0: /* vim: set ts=2 et sw=2 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: #include "mozilla/dom/DeviceStorageFileSystem.h" michael@0: michael@0: #include "DeviceStorage.h" michael@0: #include "mozilla/Preferences.h" michael@0: #include "mozilla/dom/Directory.h" michael@0: #include "mozilla/dom/FileSystemUtils.h" michael@0: #include "nsCOMPtr.h" michael@0: #include "nsDebug.h" michael@0: #include "nsDeviceStorage.h" michael@0: #include "nsIDOMFile.h" michael@0: #include "nsIFile.h" michael@0: #include "nsPIDOMWindow.h" michael@0: michael@0: namespace mozilla { michael@0: namespace dom { michael@0: michael@0: DeviceStorageFileSystem::DeviceStorageFileSystem( michael@0: const nsAString& aStorageType, michael@0: const nsAString& aStorageName) michael@0: : mDeviceStorage(nullptr) michael@0: { michael@0: MOZ_ASSERT(NS_IsMainThread(), "Only call on main thread!"); michael@0: michael@0: mStorageType = aStorageType; michael@0: mStorageName = aStorageName; michael@0: michael@0: // Generate the string representation of the file system. michael@0: mString.AppendLiteral("devicestorage-"); michael@0: mString.Append(mStorageType); michael@0: mString.AppendLiteral("-"); michael@0: mString.Append(mStorageName); michael@0: michael@0: mIsTesting = michael@0: mozilla::Preferences::GetBool("device.storage.prompt.testing", false); michael@0: michael@0: // Get the permission name required to access the file system. michael@0: nsresult rv = michael@0: DeviceStorageTypeChecker::GetPermissionForType(mStorageType, mPermission); michael@0: NS_WARN_IF(NS_FAILED(rv)); michael@0: michael@0: // Get the local path of the file system root. michael@0: // Since the child process is not allowed to access the file system, we only michael@0: // do this from the parent process. michael@0: if (!FileSystemUtils::IsParentProcess()) { michael@0: return; michael@0: } michael@0: nsCOMPtr rootFile; michael@0: DeviceStorageFile::GetRootDirectoryForType(aStorageType, michael@0: aStorageName, michael@0: getter_AddRefs(rootFile)); michael@0: michael@0: NS_WARN_IF(!rootFile || NS_FAILED(rootFile->GetPath(mLocalRootPath))); michael@0: FileSystemUtils::LocalPathToNormalizedPath(mLocalRootPath, michael@0: mNormalizedLocalRootPath); michael@0: michael@0: // DeviceStorageTypeChecker is a singleton object and must be initialized on michael@0: // the main thread. We initialize it here so that we can use it on the worker michael@0: // thread. michael@0: DebugOnly typeChecker michael@0: = DeviceStorageTypeChecker::CreateOrGet(); michael@0: MOZ_ASSERT(typeChecker); michael@0: } michael@0: michael@0: DeviceStorageFileSystem::~DeviceStorageFileSystem() michael@0: { michael@0: } michael@0: michael@0: void michael@0: DeviceStorageFileSystem::Init(nsDOMDeviceStorage* aDeviceStorage) michael@0: { michael@0: MOZ_ASSERT(NS_IsMainThread(), "Only call on main thread!"); michael@0: MOZ_ASSERT(aDeviceStorage); michael@0: mDeviceStorage = aDeviceStorage; michael@0: } michael@0: michael@0: void michael@0: DeviceStorageFileSystem::Shutdown() michael@0: { michael@0: MOZ_ASSERT(NS_IsMainThread(), "Only call on main thread!"); michael@0: mDeviceStorage = nullptr; michael@0: mShutdown = true; michael@0: } michael@0: michael@0: nsPIDOMWindow* michael@0: DeviceStorageFileSystem::GetWindow() const michael@0: { michael@0: MOZ_ASSERT(NS_IsMainThread(), "Only call on main thread!"); michael@0: if (!mDeviceStorage) { michael@0: return nullptr; michael@0: } michael@0: return mDeviceStorage->GetOwner(); michael@0: } michael@0: michael@0: already_AddRefed michael@0: DeviceStorageFileSystem::GetLocalFile(const nsAString& aRealPath) const michael@0: { michael@0: MOZ_ASSERT(FileSystemUtils::IsParentProcess(), michael@0: "Should be on parent process!"); michael@0: nsAutoString localPath; michael@0: FileSystemUtils::NormalizedPathToLocalPath(aRealPath, localPath); michael@0: localPath = mLocalRootPath + localPath; michael@0: nsCOMPtr file; michael@0: nsresult rv = NS_NewLocalFile(localPath, false, getter_AddRefs(file)); michael@0: if (NS_WARN_IF(NS_FAILED(rv))) { michael@0: return nullptr; michael@0: } michael@0: return file.forget(); michael@0: } michael@0: michael@0: bool michael@0: DeviceStorageFileSystem::GetRealPath(nsIDOMFile* aFile, nsAString& aRealPath) const michael@0: { michael@0: MOZ_ASSERT(FileSystemUtils::IsParentProcess(), michael@0: "Should be on parent process!"); michael@0: MOZ_ASSERT(aFile, "aFile Should not be null."); michael@0: michael@0: aRealPath.Truncate(); michael@0: michael@0: nsAutoString filePath; michael@0: if (NS_FAILED(aFile->GetMozFullPathInternal(filePath))) { michael@0: return false; michael@0: } michael@0: michael@0: return LocalPathToRealPath(filePath, aRealPath); michael@0: } michael@0: michael@0: const nsAString& michael@0: DeviceStorageFileSystem::GetRootName() const michael@0: { michael@0: return mStorageName; michael@0: } michael@0: michael@0: bool michael@0: DeviceStorageFileSystem::IsSafeFile(nsIFile* aFile) const michael@0: { michael@0: MOZ_ASSERT(FileSystemUtils::IsParentProcess(), michael@0: "Should be on parent process!"); michael@0: MOZ_ASSERT(aFile); michael@0: michael@0: // Check if this file belongs to this storage. michael@0: nsAutoString path; michael@0: if (NS_FAILED(aFile->GetPath(path))) { michael@0: return false; michael@0: } michael@0: if (!LocalPathToRealPath(path, path)) { michael@0: return false; michael@0: } michael@0: michael@0: // Check if the file type is compatible with the storage type. michael@0: DeviceStorageTypeChecker* typeChecker michael@0: = DeviceStorageTypeChecker::CreateOrGet(); michael@0: MOZ_ASSERT(typeChecker); michael@0: return typeChecker->Check(mStorageType, aFile); michael@0: } michael@0: michael@0: bool michael@0: DeviceStorageFileSystem::IsSafeDirectory(Directory* aDir) const michael@0: { michael@0: MOZ_ASSERT(NS_IsMainThread(), "Only call on main thread!"); michael@0: MOZ_ASSERT(aDir); michael@0: nsRefPtr fs = aDir->GetFileSystem(); michael@0: MOZ_ASSERT(fs); michael@0: // Check if the given directory is from this storage. michael@0: return fs->ToString() == mString; michael@0: } michael@0: michael@0: bool michael@0: DeviceStorageFileSystem::LocalPathToRealPath(const nsAString& aLocalPath, michael@0: nsAString& aRealPath) const michael@0: { michael@0: nsAutoString path; michael@0: FileSystemUtils::LocalPathToNormalizedPath(aLocalPath, path); michael@0: if (!FileSystemUtils::IsDescendantPath(mNormalizedLocalRootPath, path)) { michael@0: aRealPath.Truncate(); michael@0: return false; michael@0: } michael@0: aRealPath = Substring(path, mNormalizedLocalRootPath.Length()); michael@0: return true; michael@0: } michael@0: michael@0: } // namespace dom michael@0: } // namespace mozilla