1 // Copyright 2014 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #include "chrome/browser/chromeos/file_manager/filesystem_api_util.h"
7 #include "base/callback.h"
8 #include "base/files/file.h"
9 #include "base/files/file_path.h"
10 #include "base/memory/scoped_ptr.h"
11 #include "chrome/browser/chromeos/drive/file_errors.h"
12 #include "chrome/browser/chromeos/drive/file_system_interface.h"
13 #include "chrome/browser/chromeos/drive/file_system_util.h"
14 #include "chrome/browser/chromeos/file_manager/app_id.h"
15 #include "chrome/browser/chromeos/file_manager/fileapi_util.h"
16 #include "chrome/browser/chromeos/file_system_provider/mount_path_util.h"
17 #include "chrome/browser/chromeos/file_system_provider/provided_file_system_interface.h"
18 #include "chrome/browser/extensions/extension_util.h"
19 #include "chrome/browser/profiles/profile.h"
20 #include "content/public/browser/browser_thread.h"
21 #include "content/public/browser/storage_partition.h"
22 #include "google_apis/drive/task_util.h"
23 #include "storage/browser/fileapi/file_system_context.h"
25 namespace file_manager {
29 // Helper function used to implement GetNonNativeLocalPathMimeType. It extracts
30 // the mime type from the passed Drive resource entry.
31 void GetMimeTypeAfterGetResourceEntryForDrive(
32 const base::Callback<void(bool, const std::string&)>& callback,
33 drive::FileError error,
34 scoped_ptr<drive::ResourceEntry> entry) {
35 DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
37 if (error != drive::FILE_ERROR_OK || !entry->has_file_specific_info() ||
38 entry->file_specific_info().content_mime_type().empty()) {
39 callback.Run(false, std::string());
42 callback.Run(true, entry->file_specific_info().content_mime_type());
45 // Helper function used to implement GetNonNativeLocalPathMimeType. It extracts
46 // the mime type from the passed metadata from a providing extension.
47 void GetMimeTypeAfterGetMetadataForProvidedFileSystem(
48 const base::Callback<void(bool, const std::string&)>& callback,
49 scoped_ptr<chromeos::file_system_provider::EntryMetadata> metadata,
50 base::File::Error result) {
51 DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
53 if (result != base::File::FILE_OK || metadata->mime_type.empty()) {
54 callback.Run(false, std::string());
57 callback.Run(true, metadata->mime_type);
60 // Helper function to converts a callback that takes boolean value to that takes
61 // File::Error, by regarding FILE_OK as the only successful value.
62 void BoolCallbackAsFileErrorCallback(
63 const base::Callback<void(bool)>& callback,
64 base::File::Error error) {
65 return callback.Run(error == base::File::FILE_OK);
68 // Part of PrepareFileOnIOThread. It tries to create a new file if the given
69 // |url| is not already inhabited.
70 void PrepareFileAfterCheckExistOnIOThread(
71 scoped_refptr<storage::FileSystemContext> file_system_context,
72 const storage::FileSystemURL& url,
73 const storage::FileSystemOperation::StatusCallback& callback,
74 base::File::Error error) {
75 DCHECK_CURRENTLY_ON(content::BrowserThread::IO);
77 if (error != base::File::FILE_ERROR_NOT_FOUND) {
82 // Call with the second argument |exclusive| set to false, meaning that it
83 // is not an error even if the file already exists (it can happen if the file
84 // is created after the previous FileExists call and before this CreateFile.)
86 // Note that the preceding call to FileExists is necessary for handling
87 // read only filesystems that blindly rejects handling CreateFile().
88 file_system_context->operation_runner()->CreateFile(url, false, callback);
91 // Checks whether a file exists at the given |url|, and try creating it if it
92 // is not already there.
93 void PrepareFileOnIOThread(
94 scoped_refptr<storage::FileSystemContext> file_system_context,
95 const storage::FileSystemURL& url,
96 const base::Callback<void(bool)>& callback) {
97 DCHECK_CURRENTLY_ON(content::BrowserThread::IO);
99 file_system_context->operation_runner()->FileExists(
101 base::Bind(&PrepareFileAfterCheckExistOnIOThread,
104 base::Bind(&BoolCallbackAsFileErrorCallback, callback)));
109 bool IsNonNativeFileSystemType(storage::FileSystemType type) {
111 case storage::kFileSystemTypeNativeLocal:
112 case storage::kFileSystemTypeRestrictedNativeLocal:
115 // The path indeed corresponds to a mount point not associated with a
116 // native local path.
121 bool IsUnderNonNativeLocalPath(Profile* profile,
122 const base::FilePath& path) {
123 DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
126 if (!util::ConvertAbsoluteFilePathToFileSystemUrl(
127 profile, path, kFileManagerAppId, &url)) {
131 storage::FileSystemURL filesystem_url =
132 GetFileSystemContextForExtensionId(profile, kFileManagerAppId)
134 if (!filesystem_url.is_valid())
137 return IsNonNativeFileSystemType(filesystem_url.type());
140 void GetNonNativeLocalPathMimeType(
142 const base::FilePath& path,
143 const base::Callback<void(bool, const std::string&)>& callback) {
144 DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
145 DCHECK(IsUnderNonNativeLocalPath(profile, path));
147 if (drive::util::IsUnderDriveMountPoint(path)) {
148 drive::FileSystemInterface* file_system =
149 drive::util::GetFileSystemByProfile(profile);
151 content::BrowserThread::PostTask(
152 content::BrowserThread::UI,
154 base::Bind(callback, false, std::string()));
158 file_system->GetResourceEntry(
159 drive::util::ExtractDrivePath(path),
160 base::Bind(&GetMimeTypeAfterGetResourceEntryForDrive, callback));
164 if (chromeos::file_system_provider::util::IsFileSystemProviderLocalPath(
166 chromeos::file_system_provider::util::LocalPathParser parser(profile, path);
167 if (!parser.Parse()) {
168 content::BrowserThread::PostTask(
169 content::BrowserThread::UI,
171 base::Bind(callback, false, std::string()));
175 parser.file_system()->GetMetadata(
177 chromeos::file_system_provider::ProvidedFileSystemInterface::
178 METADATA_FIELD_DEFAULT,
179 base::Bind(&GetMimeTypeAfterGetMetadataForProvidedFileSystem,
184 // We don't have a way to obtain metadata other than drive and FSP. Returns an
185 // error with empty MIME type, that leads fallback guessing mime type from
187 content::BrowserThread::PostTask(
188 content::BrowserThread::UI,
190 base::Bind(callback, false /* failure */, std::string()));
193 void IsNonNativeLocalPathDirectory(
195 const base::FilePath& path,
196 const base::Callback<void(bool)>& callback) {
197 DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
198 DCHECK(IsUnderNonNativeLocalPath(profile, path));
201 if (!util::ConvertAbsoluteFilePathToFileSystemUrl(
202 profile, path, kFileManagerAppId, &url)) {
203 // Posting to the current thread, so that we always call back asynchronously
204 // independent from whether or not the operation succeeds.
205 content::BrowserThread::PostTask(content::BrowserThread::UI,
207 base::Bind(callback, false));
211 util::CheckIfDirectoryExists(
212 GetFileSystemContextForExtensionId(profile, kFileManagerAppId),
214 base::Bind(&BoolCallbackAsFileErrorCallback, callback));
217 void PrepareNonNativeLocalFileForWritableApp(
219 const base::FilePath& path,
220 const base::Callback<void(bool)>& callback) {
221 DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
222 DCHECK(IsUnderNonNativeLocalPath(profile, path));
225 if (!util::ConvertAbsoluteFilePathToFileSystemUrl(
226 profile, path, kFileManagerAppId, &url)) {
227 // Posting to the current thread, so that we always call back asynchronously
228 // independent from whether or not the operation succeeds.
229 content::BrowserThread::PostTask(content::BrowserThread::UI,
231 base::Bind(callback, false));
235 storage::FileSystemContext* const context =
236 GetFileSystemContextForExtensionId(profile, kFileManagerAppId);
239 // Check the existence of a file using file system API implementation on
240 // behalf of the file manager app. We need to grant access beforehand.
241 context->external_backend()->GrantFullAccessToExtension(kFileManagerAppId);
243 content::BrowserThread::PostTask(
244 content::BrowserThread::IO,
246 base::Bind(&PrepareFileOnIOThread,
247 make_scoped_refptr(context),
248 context->CrackURL(url),
249 google_apis::CreateRelayCallback(callback)));
253 } // namespace file_manager