• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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_path.h"
9 #include "base/memory/scoped_ptr.h"
10 #include "chrome/browser/chromeos/drive/file_errors.h"
11 #include "chrome/browser/chromeos/drive/file_system_interface.h"
12 #include "chrome/browser/chromeos/drive/file_system_util.h"
13 #include "chrome/browser/chromeos/file_manager/app_id.h"
14 #include "chrome/browser/chromeos/file_manager/fileapi_util.h"
15 #include "chrome/browser/extensions/extension_util.h"
16 #include "chrome/browser/profiles/profile.h"
17 #include "content/public/browser/browser_thread.h"
18 #include "content/public/browser/storage_partition.h"
19 #include "google_apis/drive/task_util.h"
20 #include "webkit/browser/fileapi/file_system_context.h"
21 
22 namespace file_manager {
23 namespace util {
24 
25 namespace {
26 
27 // Helper function used to implement GetNonNativeLocalPathMimeType. It extracts
28 // the mime type from the passed Drive resource entry.
GetMimeTypeAfterGetResourceEntry(const base::Callback<void (bool,const std::string &)> & callback,drive::FileError error,scoped_ptr<drive::ResourceEntry> entry)29 void GetMimeTypeAfterGetResourceEntry(
30     const base::Callback<void(bool, const std::string&)>& callback,
31     drive::FileError error,
32     scoped_ptr<drive::ResourceEntry> entry) {
33   DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
34 
35   if (error != drive::FILE_ERROR_OK || !entry->has_file_specific_info()) {
36     callback.Run(false, std::string());
37     return;
38   }
39   callback.Run(true, entry->file_specific_info().content_mime_type());
40 }
41 
42 // Helper function to converts a callback that takes boolean value to that takes
43 // File::Error, by regarding FILE_OK as the only successful value.
BoolCallbackAsFileErrorCallback(const base::Callback<void (bool)> & callback,base::File::Error error)44 void BoolCallbackAsFileErrorCallback(
45     const base::Callback<void(bool)>& callback,
46     base::File::Error error) {
47   return callback.Run(error == base::File::FILE_OK);
48 }
49 
50 // Part of PrepareFileOnIOThread. It tries to create a new file if the given
51 // |url| is not already inhabited.
PrepareFileAfterCheckExistOnIOThread(scoped_refptr<fileapi::FileSystemContext> file_system_context,const fileapi::FileSystemURL & url,const fileapi::FileSystemOperation::StatusCallback & callback,base::File::Error error)52 void PrepareFileAfterCheckExistOnIOThread(
53     scoped_refptr<fileapi::FileSystemContext> file_system_context,
54     const fileapi::FileSystemURL& url,
55     const fileapi::FileSystemOperation::StatusCallback& callback,
56     base::File::Error error) {
57   DCHECK_CURRENTLY_ON(content::BrowserThread::IO);
58 
59   if (error != base::File::FILE_ERROR_NOT_FOUND) {
60     callback.Run(error);
61     return;
62   }
63 
64   // Call with the second argument |exclusive| set to false, meaning that it
65   // is not an error even if the file already exists (it can happen if the file
66   // is created after the previous FileExists call and before this CreateFile.)
67   //
68   // Note that the preceding call to FileExists is necessary for handling
69   // read only filesystems that blindly rejects handling CreateFile().
70   file_system_context->operation_runner()->CreateFile(url, false, callback);
71 }
72 
73 // Checks whether a file exists at the given |url|, and try creating it if it
74 // is not already there.
PrepareFileOnIOThread(scoped_refptr<fileapi::FileSystemContext> file_system_context,const fileapi::FileSystemURL & url,const base::Callback<void (bool)> & callback)75 void PrepareFileOnIOThread(
76     scoped_refptr<fileapi::FileSystemContext> file_system_context,
77     const fileapi::FileSystemURL& url,
78     const base::Callback<void(bool)>& callback) {
79   DCHECK_CURRENTLY_ON(content::BrowserThread::IO);
80 
81   file_system_context->operation_runner()->FileExists(
82       url,
83       base::Bind(&PrepareFileAfterCheckExistOnIOThread,
84                  file_system_context,
85                  url,
86                  base::Bind(&BoolCallbackAsFileErrorCallback, callback)));
87 }
88 
89 }  // namespace
90 
IsUnderNonNativeLocalPath(Profile * profile,const base::FilePath & path)91 bool IsUnderNonNativeLocalPath(Profile* profile,
92                         const base::FilePath& path) {
93   DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
94 
95   GURL url;
96   if (!util::ConvertAbsoluteFilePathToFileSystemUrl(
97            profile, path, kFileManagerAppId, &url)) {
98     return false;
99   }
100 
101   fileapi::FileSystemURL filesystem_url =
102       GetFileSystemContextForExtensionId(profile,
103                                          kFileManagerAppId)->CrackURL(url);
104   if (!filesystem_url.is_valid())
105     return false;
106 
107   switch (filesystem_url.type()) {
108     case fileapi::kFileSystemTypeNativeLocal:
109     case fileapi::kFileSystemTypeRestrictedNativeLocal:
110       return false;
111     default:
112       // The path indeed corresponds to a mount point not associated with a
113       // native local path.
114       return true;
115   }
116 }
117 
GetNonNativeLocalPathMimeType(Profile * profile,const base::FilePath & path,const base::Callback<void (bool,const std::string &)> & callback)118 void GetNonNativeLocalPathMimeType(
119     Profile* profile,
120     const base::FilePath& path,
121     const base::Callback<void(bool, const std::string&)>& callback) {
122   DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
123   DCHECK(IsUnderNonNativeLocalPath(profile, path));
124 
125   if (!drive::util::IsUnderDriveMountPoint(path)) {
126     // Non-drive mount point does not have mime types as metadata. Just return
127     // success with empty mime type value.
128     content::BrowserThread::PostTask(
129         content::BrowserThread::UI,
130         FROM_HERE,
131         base::Bind(callback, true /* success */, std::string()));
132     return;
133   }
134 
135   drive::FileSystemInterface* file_system =
136       drive::util::GetFileSystemByProfile(profile);
137   if (!file_system) {
138     content::BrowserThread::PostTask(
139         content::BrowserThread::UI,
140         FROM_HERE,
141         base::Bind(callback, false, std::string()));
142     return;
143   }
144 
145   file_system->GetResourceEntry(
146       drive::util::ExtractDrivePath(path),
147       base::Bind(&GetMimeTypeAfterGetResourceEntry, callback));
148 }
149 
IsNonNativeLocalPathDirectory(Profile * profile,const base::FilePath & path,const base::Callback<void (bool)> & callback)150 void IsNonNativeLocalPathDirectory(
151     Profile* profile,
152     const base::FilePath& path,
153     const base::Callback<void(bool)>& callback) {
154   DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
155   DCHECK(IsUnderNonNativeLocalPath(profile, path));
156 
157   GURL url;
158   if (!util::ConvertAbsoluteFilePathToFileSystemUrl(
159            profile, path, kFileManagerAppId, &url)) {
160     // Posting to the current thread, so that we always call back asynchronously
161     // independent from whether or not the operation succeeds.
162     content::BrowserThread::PostTask(content::BrowserThread::UI,
163                                      FROM_HERE,
164                                      base::Bind(callback, false));
165     return;
166   }
167 
168   util::CheckIfDirectoryExists(
169       GetFileSystemContextForExtensionId(profile, kFileManagerAppId),
170       url,
171       base::Bind(&BoolCallbackAsFileErrorCallback, callback));
172 }
173 
PrepareNonNativeLocalFileForWritableApp(Profile * profile,const base::FilePath & path,const base::Callback<void (bool)> & callback)174 void PrepareNonNativeLocalFileForWritableApp(
175     Profile* profile,
176     const base::FilePath& path,
177     const base::Callback<void(bool)>& callback) {
178   DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
179   DCHECK(IsUnderNonNativeLocalPath(profile, path));
180 
181   GURL url;
182   if (!util::ConvertAbsoluteFilePathToFileSystemUrl(
183            profile, path, kFileManagerAppId, &url)) {
184     // Posting to the current thread, so that we always call back asynchronously
185     // independent from whether or not the operation succeeds.
186     content::BrowserThread::PostTask(content::BrowserThread::UI,
187                                      FROM_HERE,
188                                      base::Bind(callback, false));
189     return;
190   }
191 
192   fileapi::FileSystemContext* const context =
193       GetFileSystemContextForExtensionId(profile, kFileManagerAppId);
194   DCHECK(context);
195 
196   // Check the existence of a file using file system API implementation on
197   // behalf of the file manager app. We need to grant access beforehand.
198   context->external_backend()->GrantFullAccessToExtension(kFileManagerAppId);
199 
200   content::BrowserThread::PostTask(
201       content::BrowserThread::IO,
202       FROM_HERE,
203       base::Bind(&PrepareFileOnIOThread,
204                  make_scoped_refptr(context),
205                  context->CrackURL(url),
206                  google_apis::CreateRelayCallback(callback)));
207 }
208 
209 }  // namespace util
210 }  // namespace file_manager
211