Upstream version 10.39.225.0
[platform/framework/web/crosswalk.git] / src / chrome / browser / chromeos / file_manager / filesystem_api_util.cc
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.
4
5 #include "chrome/browser/chromeos/file_manager/filesystem_api_util.h"
6
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"
24
25 namespace file_manager {
26 namespace util {
27
28 namespace {
29
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);
37
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());
41     return;
42   }
43   callback.Run(true, entry->file_specific_info().content_mime_type());
44 }
45
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);
53
54   if (result != base::File::FILE_OK || metadata->mime_type.empty()) {
55     callback.Run(false, std::string());
56     return;
57   }
58   callback.Run(true, metadata->mime_type);
59 }
60
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);
67 }
68
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);
77
78   if (error != base::File::FILE_ERROR_NOT_FOUND) {
79     callback.Run(error);
80     return;
81   }
82
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.)
86   //
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);
90 }
91
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);
99
100   file_system_context->operation_runner()->FileExists(
101       url,
102       base::Bind(&PrepareFileAfterCheckExistOnIOThread,
103                  file_system_context,
104                  url,
105                  base::Bind(&BoolCallbackAsFileErrorCallback, callback)));
106 }
107
108 }  // namespace
109
110 bool IsUnderNonNativeLocalPath(Profile* profile,
111                         const base::FilePath& path) {
112   DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
113
114   GURL url;
115   if (!util::ConvertAbsoluteFilePathToFileSystemUrl(
116            profile, path, kFileManagerAppId, &url)) {
117     return false;
118   }
119
120   storage::FileSystemURL filesystem_url =
121       GetFileSystemContextForExtensionId(profile, kFileManagerAppId)
122           ->CrackURL(url);
123   if (!filesystem_url.is_valid())
124     return false;
125
126   switch (filesystem_url.type()) {
127     case storage::kFileSystemTypeNativeLocal:
128     case storage::kFileSystemTypeRestrictedNativeLocal:
129       return false;
130     default:
131       // The path indeed corresponds to a mount point not associated with a
132       // native local path.
133       return true;
134   }
135 }
136
137 void GetNonNativeLocalPathMimeType(
138     Profile* profile,
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));
143
144   if (drive::util::IsUnderDriveMountPoint(path)) {
145     drive::FileSystemInterface* file_system =
146         drive::util::GetFileSystemByProfile(profile);
147     if (!file_system) {
148       content::BrowserThread::PostTask(
149           content::BrowserThread::UI,
150           FROM_HERE,
151           base::Bind(callback, false, std::string()));
152       return;
153     }
154
155     file_system->GetResourceEntry(
156         drive::util::ExtractDrivePath(path),
157         base::Bind(&GetMimeTypeAfterGetResourceEntryForDrive, callback));
158     return;
159   }
160
161   if (chromeos::file_system_provider::util::IsFileSystemProviderLocalPath(
162           path)) {
163     chromeos::file_system_provider::util::LocalPathParser parser(profile, path);
164     if (!parser.Parse()) {
165       content::BrowserThread::PostTask(
166           content::BrowserThread::UI,
167           FROM_HERE,
168           base::Bind(callback, false, std::string()));
169       return;
170     }
171
172     parser.file_system()->GetMetadata(
173         parser.file_path(),
174         chromeos::file_system_provider::ProvidedFileSystemInterface::
175             METADATA_FIELD_DEFAULT,
176         base::Bind(&GetMimeTypeAfterGetMetadataForProvidedFileSystem,
177                    callback));
178     return;
179   }
180
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
183   // file extensions.
184   content::BrowserThread::PostTask(
185       content::BrowserThread::UI,
186       FROM_HERE,
187       base::Bind(callback, false /* failure */, std::string()));
188 }
189
190 void IsNonNativeLocalPathDirectory(
191     Profile* profile,
192     const base::FilePath& path,
193     const base::Callback<void(bool)>& callback) {
194   DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
195   DCHECK(IsUnderNonNativeLocalPath(profile, path));
196
197   GURL url;
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,
203                                      FROM_HERE,
204                                      base::Bind(callback, false));
205     return;
206   }
207
208   util::CheckIfDirectoryExists(
209       GetFileSystemContextForExtensionId(profile, kFileManagerAppId),
210       url,
211       base::Bind(&BoolCallbackAsFileErrorCallback, callback));
212 }
213
214 void PrepareNonNativeLocalFileForWritableApp(
215     Profile* profile,
216     const base::FilePath& path,
217     const base::Callback<void(bool)>& callback) {
218   DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
219   DCHECK(IsUnderNonNativeLocalPath(profile, path));
220
221   GURL url;
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,
227                                      FROM_HERE,
228                                      base::Bind(callback, false));
229     return;
230   }
231
232   storage::FileSystemContext* const context =
233       GetFileSystemContextForExtensionId(profile, kFileManagerAppId);
234   DCHECK(context);
235
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);
239
240   content::BrowserThread::PostTask(
241       content::BrowserThread::IO,
242       FROM_HERE,
243       base::Bind(&PrepareFileOnIOThread,
244                  make_scoped_refptr(context),
245                  context->CrackURL(url),
246                  google_apis::CreateRelayCallback(callback)));
247 }
248
249 }  // namespace util
250 }  // namespace file_manager