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_system_util.h"
12 #include "chrome/browser/chromeos/file_manager/app_id.h"
13 #include "chrome/browser/chromeos/file_manager/fileapi_util.h"
14 #include "chrome/browser/chromeos/file_system_provider/mount_path_util.h"
15 #include "chrome/browser/chromeos/file_system_provider/provided_file_system_interface.h"
16 #include "chrome/browser/extensions/extension_util.h"
17 #include "chrome/browser/profiles/profile.h"
18 #include "components/drive/file_errors.h"
19 #include "components/drive/file_system_core_util.h"
20 #include "components/drive/file_system_interface.h"
21 #include "content/public/browser/browser_thread.h"
22 #include "content/public/browser/storage_partition.h"
23 #include "google_apis/drive/task_util.h"
24 #include "storage/browser/fileapi/file_system_context.h"
26 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 IsNonNativeFileSystemType(storage::FileSystemType type
) {
112 case storage::kFileSystemTypeNativeLocal
:
113 case storage::kFileSystemTypeRestrictedNativeLocal
:
116 // The path indeed corresponds to a mount point not associated with a
117 // native local path.
122 bool IsUnderNonNativeLocalPath(Profile
* profile
,
123 const base::FilePath
& path
) {
124 DCHECK_CURRENTLY_ON(content::BrowserThread::UI
);
127 if (!util::ConvertAbsoluteFilePathToFileSystemUrl(
128 profile
, path
, kFileManagerAppId
, &url
)) {
132 storage::FileSystemURL filesystem_url
=
133 GetFileSystemContextForExtensionId(profile
, kFileManagerAppId
)
135 if (!filesystem_url
.is_valid())
138 return IsNonNativeFileSystemType(filesystem_url
.type());
141 void GetNonNativeLocalPathMimeType(
143 const base::FilePath
& path
,
144 const base::Callback
<void(bool, const std::string
&)>& callback
) {
145 DCHECK_CURRENTLY_ON(content::BrowserThread::UI
);
146 DCHECK(IsUnderNonNativeLocalPath(profile
, path
));
148 if (drive::util::IsUnderDriveMountPoint(path
)) {
149 drive::FileSystemInterface
* file_system
=
150 drive::util::GetFileSystemByProfile(profile
);
152 content::BrowserThread::PostTask(
153 content::BrowserThread::UI
,
155 base::Bind(callback
, false, std::string()));
159 file_system
->GetResourceEntry(
160 drive::util::ExtractDrivePath(path
),
161 base::Bind(&GetMimeTypeAfterGetResourceEntryForDrive
, callback
));
165 if (chromeos::file_system_provider::util::IsFileSystemProviderLocalPath(
167 chromeos::file_system_provider::util::LocalPathParser
parser(profile
, path
);
168 if (!parser
.Parse()) {
169 content::BrowserThread::PostTask(
170 content::BrowserThread::UI
,
172 base::Bind(callback
, false, std::string()));
176 parser
.file_system()->GetMetadata(
178 chromeos::file_system_provider::ProvidedFileSystemInterface::
179 METADATA_FIELD_DEFAULT
,
180 base::Bind(&GetMimeTypeAfterGetMetadataForProvidedFileSystem
,
185 // We don't have a way to obtain metadata other than drive and FSP. Returns an
186 // error with empty MIME type, that leads fallback guessing mime type from
188 content::BrowserThread::PostTask(
189 content::BrowserThread::UI
,
191 base::Bind(callback
, false /* failure */, std::string()));
194 void IsNonNativeLocalPathDirectory(
196 const base::FilePath
& path
,
197 const base::Callback
<void(bool)>& callback
) {
198 DCHECK_CURRENTLY_ON(content::BrowserThread::UI
);
199 DCHECK(IsUnderNonNativeLocalPath(profile
, path
));
201 util::CheckIfDirectoryExists(
202 GetFileSystemContextForExtensionId(profile
, kFileManagerAppId
), path
,
203 base::Bind(&BoolCallbackAsFileErrorCallback
, callback
));
206 void PrepareNonNativeLocalFileForWritableApp(
208 const base::FilePath
& path
,
209 const base::Callback
<void(bool)>& callback
) {
210 DCHECK_CURRENTLY_ON(content::BrowserThread::UI
);
211 DCHECK(IsUnderNonNativeLocalPath(profile
, path
));
214 if (!util::ConvertAbsoluteFilePathToFileSystemUrl(
215 profile
, path
, kFileManagerAppId
, &url
)) {
216 // Posting to the current thread, so that we always call back asynchronously
217 // independent from whether or not the operation succeeds.
218 content::BrowserThread::PostTask(content::BrowserThread::UI
,
220 base::Bind(callback
, false));
224 scoped_refptr
<storage::FileSystemContext
> const file_system_context
=
225 GetFileSystemContextForExtensionId(profile
, kFileManagerAppId
);
226 DCHECK(file_system_context
);
227 storage::ExternalFileSystemBackend
* const backend
=
228 file_system_context
->external_backend();
230 const storage::FileSystemURL internal_url
=
231 backend
->CreateInternalURL(file_system_context
.get(), path
);
233 content::BrowserThread::PostTask(
234 content::BrowserThread::IO
, FROM_HERE
,
235 base::Bind(&PrepareFileOnIOThread
, file_system_context
, internal_url
,
236 google_apis::CreateRelayCallback(callback
)));
240 } // namespace file_manager