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 {
30 // Helper function used to implement GetNonNativeLocalPathMimeType. It extracts
31 // the mime type from the passed Drive resource entry.
32 void GetMimeTypeAfterGetResourceEntryForDrive(
33 const base::Callback<void(bool, const std::string&)>& callback,
34 drive::FileError error,
35 scoped_ptr<drive::ResourceEntry> entry) {
36 DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
38 if (error != drive::FILE_ERROR_OK || !entry->has_file_specific_info() ||
39 entry->file_specific_info().content_mime_type().empty()) {
40 callback.Run(false, std::string());
43 callback.Run(true, entry->file_specific_info().content_mime_type());
46 // Helper function used to implement GetNonNativeLocalPathMimeType. It extracts
47 // the mime type from the passed metadata from a providing extension.
48 void GetMimeTypeAfterGetMetadataForProvidedFileSystem(
49 const base::Callback<void(bool, const std::string&)>& callback,
50 scoped_ptr<chromeos::file_system_provider::EntryMetadata> metadata,
51 base::File::Error result) {
52 DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
54 if (result != base::File::FILE_OK || metadata->mime_type.empty()) {
55 callback.Run(false, std::string());
58 callback.Run(true, metadata->mime_type);
61 // Helper function to converts a callback that takes boolean value to that takes
62 // File::Error, by regarding FILE_OK as the only successful value.
63 void BoolCallbackAsFileErrorCallback(
64 const base::Callback<void(bool)>& callback,
65 base::File::Error error) {
66 return callback.Run(error == base::File::FILE_OK);
69 // Part of PrepareFileOnIOThread. It tries to create a new file if the given
70 // |url| is not already inhabited.
71 void PrepareFileAfterCheckExistOnIOThread(
72 scoped_refptr<storage::FileSystemContext> file_system_context,
73 const storage::FileSystemURL& url,
74 const storage::FileSystemOperation::StatusCallback& callback,
75 base::File::Error error) {
76 DCHECK_CURRENTLY_ON(content::BrowserThread::IO);
78 if (error != base::File::FILE_ERROR_NOT_FOUND) {
83 // Call with the second argument |exclusive| set to false, meaning that it
84 // is not an error even if the file already exists (it can happen if the file
85 // is created after the previous FileExists call and before this CreateFile.)
87 // Note that the preceding call to FileExists is necessary for handling
88 // read only filesystems that blindly rejects handling CreateFile().
89 file_system_context->operation_runner()->CreateFile(url, false, callback);
92 // Checks whether a file exists at the given |url|, and try creating it if it
93 // is not already there.
94 void PrepareFileOnIOThread(
95 scoped_refptr<storage::FileSystemContext> file_system_context,
96 const storage::FileSystemURL& url,
97 const base::Callback<void(bool)>& callback) {
98 DCHECK_CURRENTLY_ON(content::BrowserThread::IO);
100 file_system_context->operation_runner()->FileExists(
102 base::Bind(&PrepareFileAfterCheckExistOnIOThread,
105 base::Bind(&BoolCallbackAsFileErrorCallback, callback)));
110 bool IsUnderNonNativeLocalPath(Profile* profile,
111 const base::FilePath& path) {
112 DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
115 if (!util::ConvertAbsoluteFilePathToFileSystemUrl(
116 profile, path, kFileManagerAppId, &url)) {
120 storage::FileSystemURL filesystem_url =
121 GetFileSystemContextForExtensionId(profile, kFileManagerAppId)
123 if (!filesystem_url.is_valid())
126 switch (filesystem_url.type()) {
127 case storage::kFileSystemTypeNativeLocal:
128 case storage::kFileSystemTypeRestrictedNativeLocal:
131 // The path indeed corresponds to a mount point not associated with a
132 // native local path.
137 void GetNonNativeLocalPathMimeType(
139 const base::FilePath& path,
140 const base::Callback<void(bool, const std::string&)>& callback) {
141 DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
142 DCHECK(IsUnderNonNativeLocalPath(profile, path));
144 if (drive::util::IsUnderDriveMountPoint(path)) {
145 drive::FileSystemInterface* file_system =
146 drive::util::GetFileSystemByProfile(profile);
148 content::BrowserThread::PostTask(
149 content::BrowserThread::UI,
151 base::Bind(callback, false, std::string()));
155 file_system->GetResourceEntry(
156 drive::util::ExtractDrivePath(path),
157 base::Bind(&GetMimeTypeAfterGetResourceEntryForDrive, callback));
161 if (chromeos::file_system_provider::util::IsFileSystemProviderLocalPath(
163 chromeos::file_system_provider::util::LocalPathParser parser(profile, path);
164 if (!parser.Parse()) {
165 content::BrowserThread::PostTask(
166 content::BrowserThread::UI,
168 base::Bind(callback, false, std::string()));
172 parser.file_system()->GetMetadata(
174 chromeos::file_system_provider::ProvidedFileSystemInterface::
175 METADATA_FIELD_DEFAULT,
176 base::Bind(&GetMimeTypeAfterGetMetadataForProvidedFileSystem,
181 // We don't have a way to obtain metadata other than drive and FSP. Returns an
182 // error with empty MIME type, that leads fallback guessing mime type from
184 content::BrowserThread::PostTask(
185 content::BrowserThread::UI,
187 base::Bind(callback, false /* failure */, std::string()));
190 void IsNonNativeLocalPathDirectory(
192 const base::FilePath& path,
193 const base::Callback<void(bool)>& callback) {
194 DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
195 DCHECK(IsUnderNonNativeLocalPath(profile, path));
198 if (!util::ConvertAbsoluteFilePathToFileSystemUrl(
199 profile, path, kFileManagerAppId, &url)) {
200 // Posting to the current thread, so that we always call back asynchronously
201 // independent from whether or not the operation succeeds.
202 content::BrowserThread::PostTask(content::BrowserThread::UI,
204 base::Bind(callback, false));
208 util::CheckIfDirectoryExists(
209 GetFileSystemContextForExtensionId(profile, kFileManagerAppId),
211 base::Bind(&BoolCallbackAsFileErrorCallback, callback));
214 void PrepareNonNativeLocalFileForWritableApp(
216 const base::FilePath& path,
217 const base::Callback<void(bool)>& callback) {
218 DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
219 DCHECK(IsUnderNonNativeLocalPath(profile, path));
222 if (!util::ConvertAbsoluteFilePathToFileSystemUrl(
223 profile, path, kFileManagerAppId, &url)) {
224 // Posting to the current thread, so that we always call back asynchronously
225 // independent from whether or not the operation succeeds.
226 content::BrowserThread::PostTask(content::BrowserThread::UI,
228 base::Bind(callback, false));
232 storage::FileSystemContext* const context =
233 GetFileSystemContextForExtensionId(profile, kFileManagerAppId);
236 // Check the existence of a file using file system API implementation on
237 // behalf of the file manager app. We need to grant access beforehand.
238 context->external_backend()->GrantFullAccessToExtension(kFileManagerAppId);
240 content::BrowserThread::PostTask(
241 content::BrowserThread::IO,
243 base::Bind(&PrepareFileOnIOThread,
244 make_scoped_refptr(context),
245 context->CrackURL(url),
246 google_apis::CreateRelayCallback(callback)));
250 } // namespace file_manager