filesystem_api_util.cc revision 03b57e008b61dfcb1fbad3aea950ae0e001748b0
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 "webkit/browser/fileapi/file_system_context.h" 24 25namespace file_manager { 26namespace util { 27 28namespace { 29 30// Helper function used to implement GetNonNativeLocalPathMimeType. It extracts 31// the mime type from the passed Drive resource entry. 32void 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 callback.Run(false, std::string()); 40 return; 41 } 42 callback.Run(true, entry->file_specific_info().content_mime_type()); 43} 44 45// Helper function used to implement GetNonNativeLocalPathMimeType. It extracts 46// the mime type from the passed metadata from a providing extension. 47void GetMimeTypeAfterGetMetadataForProvidedFileSystem( 48 const base::Callback<void(bool, const std::string&)>& callback, 49 const chromeos::file_system_provider::EntryMetadata& metadata, 50 base::File::Error result) { 51 DCHECK_CURRENTLY_ON(content::BrowserThread::UI); 52 53 if (result != base::File::FILE_OK) { 54 callback.Run(false, std::string()); 55 return; 56 } 57 callback.Run(true, metadata.mime_type); 58} 59 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. 62void BoolCallbackAsFileErrorCallback( 63 const base::Callback<void(bool)>& callback, 64 base::File::Error error) { 65 return callback.Run(error == base::File::FILE_OK); 66} 67 68// Part of PrepareFileOnIOThread. It tries to create a new file if the given 69// |url| is not already inhabited. 70void 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); 76 77 if (error != base::File::FILE_ERROR_NOT_FOUND) { 78 callback.Run(error); 79 return; 80 } 81 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.) 85 // 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); 89} 90 91// Checks whether a file exists at the given |url|, and try creating it if it 92// is not already there. 93void 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); 98 99 file_system_context->operation_runner()->FileExists( 100 url, 101 base::Bind(&PrepareFileAfterCheckExistOnIOThread, 102 file_system_context, 103 url, 104 base::Bind(&BoolCallbackAsFileErrorCallback, callback))); 105} 106 107} // namespace 108 109bool IsUnderNonNativeLocalPath(Profile* profile, 110 const base::FilePath& path) { 111 DCHECK_CURRENTLY_ON(content::BrowserThread::UI); 112 113 GURL url; 114 if (!util::ConvertAbsoluteFilePathToFileSystemUrl( 115 profile, path, kFileManagerAppId, &url)) { 116 return false; 117 } 118 119 storage::FileSystemURL filesystem_url = 120 GetFileSystemContextForExtensionId(profile, kFileManagerAppId) 121 ->CrackURL(url); 122 if (!filesystem_url.is_valid()) 123 return false; 124 125 switch (filesystem_url.type()) { 126 case storage::kFileSystemTypeNativeLocal: 127 case storage::kFileSystemTypeRestrictedNativeLocal: 128 return false; 129 default: 130 // The path indeed corresponds to a mount point not associated with a 131 // native local path. 132 return true; 133 } 134} 135 136void GetNonNativeLocalPathMimeType( 137 Profile* profile, 138 const base::FilePath& path, 139 const base::Callback<void(bool, const std::string&)>& callback) { 140 DCHECK_CURRENTLY_ON(content::BrowserThread::UI); 141 DCHECK(IsUnderNonNativeLocalPath(profile, path)); 142 143 if (drive::util::IsUnderDriveMountPoint(path)) { 144 drive::FileSystemInterface* file_system = 145 drive::util::GetFileSystemByProfile(profile); 146 if (!file_system) { 147 content::BrowserThread::PostTask( 148 content::BrowserThread::UI, 149 FROM_HERE, 150 base::Bind(callback, false, std::string())); 151 return; 152 } 153 154 file_system->GetResourceEntry( 155 drive::util::ExtractDrivePath(path), 156 base::Bind(&GetMimeTypeAfterGetResourceEntryForDrive, callback)); 157 return; 158 } 159 160 if (chromeos::file_system_provider::util::IsFileSystemProviderLocalPath( 161 path)) { 162 chromeos::file_system_provider::util::LocalPathParser parser(profile, path); 163 if (!parser.Parse()) { 164 content::BrowserThread::PostTask( 165 content::BrowserThread::UI, 166 FROM_HERE, 167 base::Bind(callback, false, std::string())); 168 return; 169 } 170 171 parser.file_system()->GetMetadata( 172 parser.file_path(), 173 base::Bind(&GetMimeTypeAfterGetMetadataForProvidedFileSystem, 174 callback)); 175 return; 176 } 177 178 // As a fallback just return success with an empty mime type value. 179 content::BrowserThread::PostTask( 180 content::BrowserThread::UI, 181 FROM_HERE, 182 base::Bind(callback, true /* success */, std::string())); 183} 184 185void IsNonNativeLocalPathDirectory( 186 Profile* profile, 187 const base::FilePath& path, 188 const base::Callback<void(bool)>& callback) { 189 DCHECK_CURRENTLY_ON(content::BrowserThread::UI); 190 DCHECK(IsUnderNonNativeLocalPath(profile, path)); 191 192 GURL url; 193 if (!util::ConvertAbsoluteFilePathToFileSystemUrl( 194 profile, path, kFileManagerAppId, &url)) { 195 // Posting to the current thread, so that we always call back asynchronously 196 // independent from whether or not the operation succeeds. 197 content::BrowserThread::PostTask(content::BrowserThread::UI, 198 FROM_HERE, 199 base::Bind(callback, false)); 200 return; 201 } 202 203 util::CheckIfDirectoryExists( 204 GetFileSystemContextForExtensionId(profile, kFileManagerAppId), 205 url, 206 base::Bind(&BoolCallbackAsFileErrorCallback, callback)); 207} 208 209void PrepareNonNativeLocalFileForWritableApp( 210 Profile* profile, 211 const base::FilePath& path, 212 const base::Callback<void(bool)>& callback) { 213 DCHECK_CURRENTLY_ON(content::BrowserThread::UI); 214 DCHECK(IsUnderNonNativeLocalPath(profile, path)); 215 216 GURL url; 217 if (!util::ConvertAbsoluteFilePathToFileSystemUrl( 218 profile, path, kFileManagerAppId, &url)) { 219 // Posting to the current thread, so that we always call back asynchronously 220 // independent from whether or not the operation succeeds. 221 content::BrowserThread::PostTask(content::BrowserThread::UI, 222 FROM_HERE, 223 base::Bind(callback, false)); 224 return; 225 } 226 227 storage::FileSystemContext* const context = 228 GetFileSystemContextForExtensionId(profile, kFileManagerAppId); 229 DCHECK(context); 230 231 // Check the existence of a file using file system API implementation on 232 // behalf of the file manager app. We need to grant access beforehand. 233 context->external_backend()->GrantFullAccessToExtension(kFileManagerAppId); 234 235 content::BrowserThread::PostTask( 236 content::BrowserThread::IO, 237 FROM_HERE, 238 base::Bind(&PrepareFileOnIOThread, 239 make_scoped_refptr(context), 240 context->CrackURL(url), 241 google_apis::CreateRelayCallback(callback))); 242} 243 244} // namespace util 245} // namespace file_manager 246