Upstream version 7.36.149.0
[platform/framework/web/crosswalk.git] / src / chrome / browser / chromeos / file_manager / fileapi_util.cc
index 0a74354..31340de 100644 (file)
 
 #include "chrome/browser/chromeos/file_manager/fileapi_util.h"
 
+#include "base/files/file.h"
 #include "base/files/file_path.h"
-#include "chrome/browser/extensions/extension_service.h"
-#include "chrome/browser/extensions/extension_system.h"
+#include "chrome/browser/chromeos/drive/file_system_util.h"
+#include "chrome/browser/extensions/extension_util.h"
 #include "chrome/browser/profiles/profile.h"
 #include "content/public/browser/browser_thread.h"
 #include "content/public/browser/render_view_host.h"
 #include "content/public/browser/site_instance.h"
 #include "content/public/browser/storage_partition.h"
+#include "extensions/common/extension.h"
 #include "net/base/escape.h"
 #include "url/gurl.h"
 #include "webkit/browser/fileapi/file_system_context.h"
+#include "webkit/browser/fileapi/open_file_system_mode.h"
 #include "webkit/common/fileapi/file_system_util.h"
 
+using content::BrowserThread;
+
 namespace file_manager {
 namespace util {
 
+namespace {
+
+GURL ConvertRelativeFilePathToFileSystemUrl(const base::FilePath& relative_path,
+                                            const std::string& extension_id) {
+  GURL base_url = fileapi::GetFileSystemRootURI(
+      extensions::Extension::GetBaseURLFromExtensionId(extension_id),
+      fileapi::kFileSystemTypeExternal);
+  return GURL(base_url.spec() +
+              net::EscapeUrlEncodedData(relative_path.AsUTF8Unsafe(),
+                                        false));  // Space to %20 instead of +.
+}
+
+// Creates an ErrorDefinition with an error set to |error|.
+EntryDefinition CreateEntryDefinitionWithError(base::File::Error error) {
+  EntryDefinition result;
+  result.error = error;
+  return result;
+}
+
+// Helper class for performing conversions from file definitions to entry
+// definitions. It is possible to do it without a class, but the code would be
+// crazy and super tricky.
+//
+// This class copies the input |file_definition_list|,
+// so there is no need to worry about validity of passed |file_definition_list|
+// reference. Also, it automatically deletes itself after converting finished,
+// or if shutdown is invoked during ResolveURL(). Must be called on UI thread.
+class FileDefinitionListConverter {
+ public:
+  FileDefinitionListConverter(Profile* profile,
+                              const std::string& extension_id,
+                              const FileDefinitionList& file_definition_list,
+                              const EntryDefinitionListCallback& callback);
+  ~FileDefinitionListConverter() {}
+
+ private:
+  // Converts the element under the iterator to an entry. First, converts
+  // the virtual path to an URL, and calls OnResolvedURL(). In case of error
+  // calls OnIteratorConverted with an error entry definition.
+  void ConvertNextIterator(scoped_ptr<FileDefinitionListConverter> self_deleter,
+                           FileDefinitionList::const_iterator iterator);
+
+  // Creates an entry definition from the URL as well as the file definition.
+  // Then, calls OnIteratorConverted with the created entry definition.
+  void OnResolvedURL(scoped_ptr<FileDefinitionListConverter> self_deleter,
+                     FileDefinitionList::const_iterator iterator,
+                     base::File::Error error,
+                     const fileapi::FileSystemInfo& info,
+                     const base::FilePath& file_path,
+                     fileapi::FileSystemContext::ResolvedEntryType type);
+
+  // Called when the iterator is converted. Adds the |entry_definition| to
+  // |results_| and calls ConvertNextIterator() for the next element.
+  void OnIteratorConverted(scoped_ptr<FileDefinitionListConverter> self_deleter,
+                           FileDefinitionList::const_iterator iterator,
+                           const EntryDefinition& entry_definition);
+
+  scoped_refptr<fileapi::FileSystemContext> file_system_context_;
+  const std::string extension_id_;
+  const FileDefinitionList file_definition_list_;
+  const EntryDefinitionListCallback callback_;
+  scoped_ptr<EntryDefinitionList> result_;
+};
+
+FileDefinitionListConverter::FileDefinitionListConverter(
+    Profile* profile,
+    const std::string& extension_id,
+    const FileDefinitionList& file_definition_list,
+    const EntryDefinitionListCallback& callback)
+    : extension_id_(extension_id),
+      file_definition_list_(file_definition_list),
+      callback_(callback),
+      result_(new EntryDefinitionList) {
+  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+
+  // File browser APIs are meant to be used only from extension context, so
+  // the extension's site is the one in whose file system context the virtual
+  // path should be found.
+  GURL site = extensions::util::GetSiteForExtensionId(extension_id_, profile);
+  file_system_context_ =
+      content::BrowserContext::GetStoragePartitionForSite(
+          profile, site)->GetFileSystemContext();
+
+  // Deletes the converter, once the scoped pointer gets out of scope. It is
+  // either, if the conversion is finished, or ResolveURL() is terminated, and
+  // the callback not called because of shutdown.
+  scoped_ptr<FileDefinitionListConverter> self_deleter(this);
+  ConvertNextIterator(self_deleter.Pass(), file_definition_list_.begin());
+}
+
+void FileDefinitionListConverter::ConvertNextIterator(
+    scoped_ptr<FileDefinitionListConverter> self_deleter,
+    FileDefinitionList::const_iterator iterator) {
+  if (iterator == file_definition_list_.end()) {
+    // The converter object will be destroyed since |self_deleter| gets out of
+    // scope.
+    callback_.Run(result_.Pass());
+    return;
+  }
+
+  if (!file_system_context_.get()) {
+    OnIteratorConverted(self_deleter.Pass(),
+                        iterator,
+                        CreateEntryDefinitionWithError(
+                            base::File::FILE_ERROR_INVALID_OPERATION));
+    return;
+  }
+
+  fileapi::FileSystemURL url = file_system_context_->CreateCrackedFileSystemURL(
+      extensions::Extension::GetBaseURLFromExtensionId(extension_id_),
+      fileapi::kFileSystemTypeExternal,
+      iterator->virtual_path);
+  DCHECK(url.is_valid());
+
+  // The converter object will be deleted if the callback is not called because
+  // of shutdown during ResolveURL().
+  file_system_context_->ResolveURL(
+      url,
+      base::Bind(&FileDefinitionListConverter::OnResolvedURL,
+                 base::Unretained(this),
+                 base::Passed(&self_deleter),
+                 iterator));
+}
+
+void FileDefinitionListConverter::OnResolvedURL(
+    scoped_ptr<FileDefinitionListConverter> self_deleter,
+    FileDefinitionList::const_iterator iterator,
+    base::File::Error error,
+    const fileapi::FileSystemInfo& info,
+    const base::FilePath& file_path,
+    fileapi::FileSystemContext::ResolvedEntryType type) {
+  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+
+  if (error != base::File::FILE_OK) {
+    OnIteratorConverted(self_deleter.Pass(),
+                        iterator,
+                        CreateEntryDefinitionWithError(error));
+    return;
+  }
+
+  EntryDefinition entry_definition;
+  entry_definition.file_system_root_url = info.root_url.spec();
+  entry_definition.file_system_name = info.name;
+  DCHECK(type == fileapi::FileSystemContext::RESOLVED_ENTRY_NOT_FOUND ||
+         iterator->is_directory ==
+             (type == fileapi::FileSystemContext::RESOLVED_ENTRY_DIRECTORY));
+  entry_definition.is_directory = iterator->is_directory;
+  entry_definition.error = base::File::FILE_OK;
+
+  // Construct a target Entry.fullPath value from the virtual path and the
+  // root URL. Eg. Downloads/A/b.txt -> A/b.txt.
+  const base::FilePath root_virtual_path =
+      file_system_context_->CrackURL(info.root_url).virtual_path();
+  DCHECK(root_virtual_path == iterator->virtual_path ||
+         root_virtual_path.IsParent(iterator->virtual_path));
+  base::FilePath full_path;
+  root_virtual_path.AppendRelativePath(iterator->virtual_path, &full_path);
+  entry_definition.full_path = full_path;
+
+  OnIteratorConverted(self_deleter.Pass(), iterator, entry_definition);
+}
+
+void FileDefinitionListConverter::OnIteratorConverted(
+    scoped_ptr<FileDefinitionListConverter> self_deleter,
+    FileDefinitionList::const_iterator iterator,
+    const EntryDefinition& entry_definition) {
+  result_->push_back(entry_definition);
+  ConvertNextIterator(self_deleter.Pass(), ++iterator);
+}
+
+// Helper function to return the converted definition entry directly, without
+// the redundant container.
+void OnConvertFileDefinitionDone(
+    const EntryDefinitionCallback& callback,
+    scoped_ptr<EntryDefinitionList> entry_definition_list) {
+  DCHECK_EQ(1u, entry_definition_list->size());
+  callback.Run(entry_definition_list->at(0));
+}
+
+}  // namespace
+
+EntryDefinition::EntryDefinition() {
+}
+
+EntryDefinition::~EntryDefinition() {
+}
+
 fileapi::FileSystemContext* GetFileSystemContextForExtensionId(
     Profile* profile,
     const std::string& extension_id) {
-  GURL site = extensions::ExtensionSystem::Get(profile)->
-      extension_service()->GetSiteForExtensionId(extension_id);
+  GURL site = extensions::util::GetSiteForExtensionId(extension_id, profile);
   return content::BrowserContext::GetStoragePartitionForSite(profile, site)->
       GetFileSystemContext();
 }
@@ -37,27 +228,43 @@ fileapi::FileSystemContext* GetFileSystemContextForRenderViewHost(
       GetFileSystemContext();
 }
 
-GURL ConvertRelativeFilePathToFileSystemUrl(const base::FilePath& relative_path,
-                                            const std::string& extension_id) {
-  GURL base_url = fileapi::GetFileSystemRootURI(
-      extensions::Extension::GetBaseURLFromExtensionId(extension_id),
-      fileapi::kFileSystemTypeExternal);
-  return GURL(base_url.spec() +
-              net::EscapeUrlEncodedData(relative_path.AsUTF8Unsafe(),
-                                        false));  // Space to %20 instead of +.
-}
-
-bool ConvertAbsoluteFilePathToFileSystemUrl(
+base::FilePath ConvertDrivePathToRelativeFileSystemPath(
     Profile* profile,
-    const base::FilePath& absolute_path,
     const std::string& extension_id,
-    GURL* url) {
+    const base::FilePath& drive_path) {
+  // "/special/drive-xxx"
+  base::FilePath path = drive::util::GetDriveMountPointPath(profile);
+  // appended with (|drive_path| - "drive").
+  drive::util::GetDriveGrandRootPath().AppendRelativePath(drive_path, &path);
+
+  base::FilePath relative_path;
+  ConvertAbsoluteFilePathToRelativeFileSystemPath(profile,
+                                                  extension_id,
+                                                  path,
+                                                  &relative_path);
+  return relative_path;
+}
+
+GURL ConvertDrivePathToFileSystemUrl(Profile* profile,
+                                     const base::FilePath& drive_path,
+                                     const std::string& extension_id) {
+  const base::FilePath relative_path =
+      ConvertDrivePathToRelativeFileSystemPath(profile, extension_id,
+                                               drive_path);
+  if (relative_path.empty())
+    return GURL();
+  return ConvertRelativeFilePathToFileSystemUrl(relative_path, extension_id);
+}
+
+bool ConvertAbsoluteFilePathToFileSystemUrl(Profile* profile,
+                                            const base::FilePath& absolute_path,
+                                            const std::string& extension_id,
+                                            GURL* url) {
   base::FilePath relative_path;
-  if (!ConvertAbsoluteFilePathToRelativeFileSystemPath(
-          profile,
-          extension_id,
-          absolute_path,
-          &relative_path)) {
+  if (!ConvertAbsoluteFilePathToRelativeFileSystemPath(profile,
+                                                       extension_id,
+                                                       absolute_path,
+                                                       &relative_path)) {
     return false;
   }
   *url = ConvertRelativeFilePathToFileSystemUrl(relative_path, extension_id);
@@ -69,16 +276,10 @@ bool ConvertAbsoluteFilePathToRelativeFileSystemPath(
     const std::string& extension_id,
     const base::FilePath& absolute_path,
     base::FilePath* virtual_path) {
-  ExtensionService* service =
-      extensions::ExtensionSystem::Get(profile)->extension_service();
-  // May be NULL during unit_tests.
-  if (!service)
-    return false;
-
   // File browser APIs are meant to be used only from extension context, so the
   // extension's site is the one in whose file system context the virtual path
   // should be found.
-  GURL site = service->GetSiteForExtensionId(extension_id);
+  GURL site = extensions::util::GetSiteForExtensionId(extension_id, profile);
   fileapi::ExternalFileSystemBackend* backend =
       content::BrowserContext::GetStoragePartitionForSite(profile, site)->
           GetFileSystemContext()->external_backend();
@@ -92,5 +293,33 @@ bool ConvertAbsoluteFilePathToRelativeFileSystemPath(
   return true;
 }
 
+void ConvertFileDefinitionListToEntryDefinitionList(
+    Profile* profile,
+    const std::string& extension_id,
+    const FileDefinitionList& file_definition_list,
+    const EntryDefinitionListCallback& callback) {
+  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+
+  // The converter object destroys itself.
+  new FileDefinitionListConverter(
+      profile, extension_id, file_definition_list, callback);
+}
+
+void ConvertFileDefinitionToEntryDefinition(
+    Profile* profile,
+    const std::string& extension_id,
+    const FileDefinition& file_definition,
+    const EntryDefinitionCallback& callback) {
+  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+
+  FileDefinitionList file_definition_list;
+  file_definition_list.push_back(file_definition);
+  ConvertFileDefinitionListToEntryDefinitionList(
+      profile,
+      extension_id,
+      file_definition_list,
+      base::Bind(&OnConvertFileDefinitionDone, callback));
+}
+
 }  // namespace util
 }  // namespace file_manager