dom/filesystem/Directory.cpp
author Gurzau Raul <rgurzau@mozilla.com>
Wed, 13 Dec 2017 23:41:49 +0200
changeset 396289 ccd7b237c4337a00e45bf18ac2d0218c61e1134d
parent 396281 0bd9d964df8a23c193ec4b20b9694f6f8fe57502
child 398232 0918da01e55435aee12708d155e1832103dcd9f0
permissions -rw-r--r--
Backed out 22 changesets (bug 1419771) for build bustage build/src/dom/base/FuzzingFunctions.cpp on a CLOSED TREE Backed out changeset b2b7b46c8ad0 (bug 1419771) Backed out changeset 0206657d2ea2 (bug 1419771) Backed out changeset f0f4b98a07b6 (bug 1419771) Backed out changeset 4b52904694f4 (bug 1419771) Backed out changeset 9f40cc12d6c6 (bug 1419771) Backed out changeset f500a61f564c (bug 1419771) Backed out changeset 0bd9d964df8a (bug 1419771) Backed out changeset 1397a6bbb446 (bug 1419771) Backed out changeset 7e77a00fa8b5 (bug 1419771) Backed out changeset 5f6df771459a (bug 1419771) Backed out changeset 7624e70b2965 (bug 1419771) Backed out changeset b9d674bdc723 (bug 1419771) Backed out changeset 5e44aeda4196 (bug 1419771) Backed out changeset 601b49f51b41 (bug 1419771) Backed out changeset d12dc5557982 (bug 1419771) Backed out changeset 6c863ab2e986 (bug 1419771) Backed out changeset 0866d79873ab (bug 1419771) Backed out changeset 8ecc91474621 (bug 1419771) Backed out changeset 19b14deed8fe (bug 1419771) Backed out changeset 000c8d5fbc03 (bug 1419771) Backed out changeset 2e263a2519c5 (bug 1419771) Backed out changeset b628d9298be8 (bug 1419771)

/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ts=8 sts=2 et sw=2 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 "mozilla/dom/Directory.h"

#include "GetDirectoryListingTask.h"
#include "GetFilesTask.h"
#include "WorkerPrivate.h"

#include "nsCharSeparatedTokenizer.h"
#include "nsString.h"
#include "mozilla/dom/DirectoryBinding.h"
#include "mozilla/dom/FileSystemBase.h"
#include "mozilla/dom/FileSystemUtils.h"
#include "mozilla/dom/OSFileSystem.h"

namespace mozilla {
namespace dom {

NS_IMPL_CYCLE_COLLECTION_CLASS(Directory)

NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(Directory)
  if (tmp->mFileSystem) {
    tmp->mFileSystem->Unlink();
    tmp->mFileSystem = nullptr;
  }
  NS_IMPL_CYCLE_COLLECTION_UNLINK(mParent)
  NS_IMPL_CYCLE_COLLECTION_UNLINK_PRESERVED_WRAPPER
NS_IMPL_CYCLE_COLLECTION_UNLINK_END

NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(Directory)
  if (tmp->mFileSystem) {
    tmp->mFileSystem->Traverse(cb);
  }
  NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mParent)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END

NS_IMPL_CYCLE_COLLECTION_TRACE_WRAPPERCACHE(Directory)

NS_IMPL_CYCLE_COLLECTING_ADDREF(Directory)
NS_IMPL_CYCLE_COLLECTING_RELEASE(Directory)
NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(Directory)
  NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY
  NS_INTERFACE_MAP_ENTRY(nsISupports)
NS_INTERFACE_MAP_END

/* static */ bool
Directory::WebkitBlinkDirectoryPickerEnabled(JSContext* aCx, JSObject* aObj)
{
  if (NS_IsMainThread()) {
    return Preferences::GetBool("dom.webkitBlink.dirPicker.enabled", false);
  }

  // aCx can be null when this function is called by something else than WebIDL
  // binding code.
  workers::WorkerPrivate* workerPrivate =
    workers::GetCurrentThreadWorkerPrivate();
  if (!workerPrivate) {
    return false;
  }

  return workerPrivate->WebkitBlinkDirectoryPickerEnabled();
}

/* static */ already_AddRefed<Directory>
Directory::Constructor(const GlobalObject& aGlobal,
                       const nsAString& aRealPath,
                       ErrorResult& aRv)
{
  nsCOMPtr<nsIFile> path;
  aRv = NS_NewLocalFile(aRealPath, true, getter_AddRefs(path));
  if (NS_WARN_IF(aRv.Failed())) {
    return nullptr;
  }

  return Create(aGlobal.GetAsSupports(), path);
}

/* static */ already_AddRefed<Directory>
Directory::Create(nsISupports* aParent, nsIFile* aFile,
                  FileSystemBase* aFileSystem)
{
  MOZ_ASSERT(aParent);
  MOZ_ASSERT(aFile);

  RefPtr<Directory> directory = new Directory(aParent, aFile, aFileSystem);
  return directory.forget();
}

Directory::Directory(nsISupports* aParent,
                     nsIFile* aFile,
                     FileSystemBase* aFileSystem)
  : mParent(aParent)
  , mFile(aFile)
{
  MOZ_ASSERT(aFile);

  // aFileSystem can be null. In this case we create a OSFileSystem when needed.
  if (aFileSystem) {
    // More likely, this is a OSFileSystem. This object keeps a reference of
    // mParent but it's not cycle collectable and to avoid manual
    // addref/release, it's better to have 1 object per directory. For this
    // reason we clone it here.
    mFileSystem = aFileSystem->Clone();
  }
}

Directory::~Directory()
{
}

nsISupports*
Directory::GetParentObject() const
{
  return mParent;
}

JSObject*
Directory::WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto)
{
  return DirectoryBinding::Wrap(aCx, this, aGivenProto);
}

void
Directory::GetName(nsAString& aRetval, ErrorResult& aRv)
{
  aRetval.Truncate();

  RefPtr<FileSystemBase> fs = GetFileSystem(aRv);
  if (NS_WARN_IF(aRv.Failed())) {
    return;
  }

  fs->GetDirectoryName(mFile, aRetval, aRv);
}

void
Directory::GetPath(nsAString& aRetval, ErrorResult& aRv)
{
  // This operation is expensive. Better to cache the result.
  if (mPath.IsEmpty()) {
    RefPtr<FileSystemBase> fs = GetFileSystem(aRv);
    if (NS_WARN_IF(aRv.Failed())) {
      return;
    }

    fs->GetDOMPath(mFile, mPath, aRv);
    if (NS_WARN_IF(aRv.Failed())) {
      return;
    }
  }

  aRetval = mPath;
}

nsresult
Directory::GetFullRealPath(nsAString& aPath)
{
  nsresult rv = mFile->GetPath(aPath);
  if (NS_WARN_IF(NS_FAILED(rv))) {
    return rv;
  }

  return NS_OK;
}

already_AddRefed<Promise>
Directory::GetFilesAndDirectories(ErrorResult& aRv)
{
  RefPtr<FileSystemBase> fs = GetFileSystem(aRv);
  if (NS_WARN_IF(aRv.Failed())) {
    return nullptr;
  }

  RefPtr<GetDirectoryListingTaskChild> task =
    GetDirectoryListingTaskChild::Create(fs, this, mFile, mFilters, aRv);
  if (NS_WARN_IF(aRv.Failed())) {
    return nullptr;
  }

  task->Start();

  return task->GetPromise();
}

already_AddRefed<Promise>
Directory::GetFiles(bool aRecursiveFlag, ErrorResult& aRv)
{
  ErrorResult rv;
  RefPtr<FileSystemBase> fs = GetFileSystem(rv);
  if (NS_WARN_IF(rv.Failed())) {
    aRv.Throw(NS_ERROR_DOM_INVALID_STATE_ERR);
    return nullptr;
  }

  RefPtr<GetFilesTaskChild> task =
    GetFilesTaskChild::Create(fs, this, mFile, aRecursiveFlag, rv);
  if (NS_WARN_IF(rv.Failed())) {
    aRv.Throw(NS_ERROR_DOM_INVALID_STATE_ERR);
    return nullptr;
  }

  task->Start();

  return task->GetPromise();
}

void
Directory::SetContentFilters(const nsAString& aFilters)
{
  mFilters = aFilters;
}

FileSystemBase*
Directory::GetFileSystem(ErrorResult& aRv)
{
  if (!mFileSystem) {
    nsAutoString path;
    aRv = mFile->GetPath(path);
    if (NS_WARN_IF(aRv.Failed())) {
      return nullptr;
    }

    RefPtr<OSFileSystem> fs = new OSFileSystem(path);
    fs->Init(mParent);

    mFileSystem = fs;
  }

  return mFileSystem;
}

} // namespace dom
} // namespace mozilla