1 // Copyright 2013 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/extensions/file_manager/private_api_file_system.h"
6
7 #include <sys/statvfs.h>
8
9 #include "base/posix/eintr_wrapper.h"
10 #include "base/strings/string_number_conversions.h"
11 #include "base/strings/stringprintf.h"
12 #include "base/task_runner_util.h"
13 #include "base/threading/sequenced_worker_pool.h"
14 #include "chrome/browser/browser_process.h"
15 #include "chrome/browser/chromeos/drive/drive.pb.h"
16 #include "chrome/browser/chromeos/drive/file_system_interface.h"
17 #include "chrome/browser/chromeos/drive/file_system_util.h"
18 #include "chrome/browser/chromeos/extensions/file_manager/event_router.h"
19 #include "chrome/browser/chromeos/extensions/file_manager/file_browser_private_api.h"
20 #include "chrome/browser/chromeos/extensions/file_manager/private_api_util.h"
21 #include "chrome/browser/chromeos/file_manager/fileapi_util.h"
22 #include "chrome/browser/chromeos/file_manager/volume_manager.h"
23 #include "chrome/browser/chromeos/fileapi/file_system_backend.h"
24 #include "chrome/browser/profiles/profile.h"
25 #include "chrome/browser/profiles/profile_manager.h"
26 #include "chrome/common/extensions/api/file_browser_private.h"
27 #include "chrome/common/extensions/api/file_browser_private_internal.h"
28 #include "chromeos/disks/disk_mount_manager.h"
29 #include "content/public/browser/child_process_security_policy.h"
30 #include "content/public/browser/render_process_host.h"
31 #include "content/public/browser/render_view_host.h"
32 #include "webkit/browser/fileapi/file_system_context.h"
33 #include "webkit/browser/fileapi/file_system_file_util.h"
34 #include "webkit/browser/fileapi/file_system_operation_context.h"
35 #include "webkit/browser/fileapi/file_system_operation_runner.h"
36 #include "webkit/browser/fileapi/file_system_url.h"
37 #include "webkit/common/fileapi/file_system_info.h"
38 #include "webkit/common/fileapi/file_system_types.h"
39 #include "webkit/common/fileapi/file_system_util.h"
40
41 using chromeos::disks::DiskMountManager;
42 using content::BrowserThread;
43 using content::ChildProcessSecurityPolicy;
44 using file_manager::util::EntryDefinition;
45 using file_manager::util::FileDefinition;
46 using fileapi::FileSystemURL;
47
48 namespace extensions {
49 namespace {
50
51 // Retrieves total and remaining available size on |mount_path|.
GetSizeStatsOnBlockingPool(const std::string & mount_path,uint64 * total_size,uint64 * remaining_size)52 void GetSizeStatsOnBlockingPool(const std::string& mount_path,
53 uint64* total_size,
54 uint64* remaining_size) {
55 struct statvfs stat = {}; // Zero-clear
56 if (HANDLE_EINTR(statvfs(mount_path.c_str(), &stat)) == 0) {
57 *total_size = static_cast<uint64>(stat.f_blocks) * stat.f_frsize;
58 *remaining_size = static_cast<uint64>(stat.f_bavail) * stat.f_frsize;
59 }
60 }
61
62 // Retrieves the maximum file name length of the file system of |path|.
63 // Returns 0 if it could not be queried.
GetFileNameMaxLengthOnBlockingPool(const std::string & path)64 size_t GetFileNameMaxLengthOnBlockingPool(const std::string& path) {
65 struct statvfs stat = {};
66 if (HANDLE_EINTR(statvfs(path.c_str(), &stat)) != 0) {
67 // The filesystem seems not supporting statvfs(). Assume it to be a commonly
68 // used bound 255, and log the failure.
69 LOG(ERROR) << "Cannot statvfs() the name length limit for: " << path;
70 return 255;
71 }
72 return stat.f_namemax;
73 }
74
75 // Returns EventRouter for the |profile_id| if available.
GetEventRouterByProfileId(void * profile_id)76 file_manager::EventRouter* GetEventRouterByProfileId(void* profile_id) {
77 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
78
79 // |profile_id| needs to be checked with ProfileManager::IsValidProfile
80 // before using it.
81 Profile* profile = reinterpret_cast<Profile*>(profile_id);
82 if (!g_browser_process->profile_manager()->IsValidProfile(profile))
83 return NULL;
84
85 return file_manager::FileBrowserPrivateAPI::Get(profile)->event_router();
86 }
87
88 // Notifies the copy progress to extensions via event router.
NotifyCopyProgress(void * profile_id,fileapi::FileSystemOperationRunner::OperationID operation_id,fileapi::FileSystemOperation::CopyProgressType type,const FileSystemURL & source_url,const FileSystemURL & destination_url,int64 size)89 void NotifyCopyProgress(
90 void* profile_id,
91 fileapi::FileSystemOperationRunner::OperationID operation_id,
92 fileapi::FileSystemOperation::CopyProgressType type,
93 const FileSystemURL& source_url,
94 const FileSystemURL& destination_url,
95 int64 size) {
96 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
97
98 file_manager::EventRouter* event_router =
99 GetEventRouterByProfileId(profile_id);
100 if (event_router) {
101 event_router->OnCopyProgress(
102 operation_id, type,
103 source_url.ToGURL(), destination_url.ToGURL(), size);
104 }
105 }
106
107 // Callback invoked periodically on progress update of Copy().
OnCopyProgress(void * profile_id,fileapi::FileSystemOperationRunner::OperationID * operation_id,fileapi::FileSystemOperation::CopyProgressType type,const FileSystemURL & source_url,const FileSystemURL & destination_url,int64 size)108 void OnCopyProgress(
109 void* profile_id,
110 fileapi::FileSystemOperationRunner::OperationID* operation_id,
111 fileapi::FileSystemOperation::CopyProgressType type,
112 const FileSystemURL& source_url,
113 const FileSystemURL& destination_url,
114 int64 size) {
115 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
116
117 BrowserThread::PostTask(
118 BrowserThread::UI, FROM_HERE,
119 base::Bind(&NotifyCopyProgress,
120 profile_id, *operation_id, type,
121 source_url, destination_url, size));
122 }
123
124 // Notifies the copy completion to extensions via event router.
NotifyCopyCompletion(void * profile_id,fileapi::FileSystemOperationRunner::OperationID operation_id,const FileSystemURL & source_url,const FileSystemURL & destination_url,base::File::Error error)125 void NotifyCopyCompletion(
126 void* profile_id,
127 fileapi::FileSystemOperationRunner::OperationID operation_id,
128 const FileSystemURL& source_url,
129 const FileSystemURL& destination_url,
130 base::File::Error error) {
131 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
132
133 file_manager::EventRouter* event_router =
134 GetEventRouterByProfileId(profile_id);
135 if (event_router)
136 event_router->OnCopyCompleted(
137 operation_id,
138 source_url.ToGURL(), destination_url.ToGURL(), error);
139 }
140
141 // Callback invoked upon completion of Copy() (regardless of succeeded or
142 // failed).
OnCopyCompleted(void * profile_id,fileapi::FileSystemOperationRunner::OperationID * operation_id,const FileSystemURL & source_url,const FileSystemURL & destination_url,base::File::Error error)143 void OnCopyCompleted(
144 void* profile_id,
145 fileapi::FileSystemOperationRunner::OperationID* operation_id,
146 const FileSystemURL& source_url,
147 const FileSystemURL& destination_url,
148 base::File::Error error) {
149 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
150
151 BrowserThread::PostTask(
152 BrowserThread::UI, FROM_HERE,
153 base::Bind(&NotifyCopyCompletion,
154 profile_id, *operation_id,
155 source_url, destination_url, error));
156 }
157
158 // Starts the copy operation via FileSystemOperationRunner.
StartCopyOnIOThread(void * profile_id,scoped_refptr<fileapi::FileSystemContext> file_system_context,const FileSystemURL & source_url,const FileSystemURL & destination_url)159 fileapi::FileSystemOperationRunner::OperationID StartCopyOnIOThread(
160 void* profile_id,
161 scoped_refptr<fileapi::FileSystemContext> file_system_context,
162 const FileSystemURL& source_url,
163 const FileSystemURL& destination_url) {
164 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
165
166 // Note: |operation_id| is owned by the callback for
167 // FileSystemOperationRunner::Copy(). It is always called in the next message
168 // loop or later, so at least during this invocation it should alive.
169 fileapi::FileSystemOperationRunner::OperationID* operation_id =
170 new fileapi::FileSystemOperationRunner::OperationID;
171 *operation_id = file_system_context->operation_runner()->Copy(
172 source_url, destination_url,
173 fileapi::FileSystemOperation::OPTION_PRESERVE_LAST_MODIFIED,
174 base::Bind(&OnCopyProgress,
175 profile_id, base::Unretained(operation_id)),
176 base::Bind(&OnCopyCompleted,
177 profile_id, base::Owned(operation_id),
178 source_url, destination_url));
179 return *operation_id;
180 }
181
OnCopyCancelled(base::File::Error error)182 void OnCopyCancelled(base::File::Error error) {
183 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
184
185 // We just ignore the status if the copy is actually cancelled or not,
186 // because failing cancellation means the operation is not running now.
187 DLOG_IF(WARNING, error != base::File::FILE_OK)
188 << "Failed to cancel copy: " << error;
189 }
190
191 // Cancels the running copy operation identified by |operation_id|.
CancelCopyOnIOThread(scoped_refptr<fileapi::FileSystemContext> file_system_context,fileapi::FileSystemOperationRunner::OperationID operation_id)192 void CancelCopyOnIOThread(
193 scoped_refptr<fileapi::FileSystemContext> file_system_context,
194 fileapi::FileSystemOperationRunner::OperationID operation_id) {
195 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
196
197 file_system_context->operation_runner()->Cancel(
198 operation_id, base::Bind(&OnCopyCancelled));
199 }
200
201 } // namespace
202
DidFail(base::File::Error error_code)203 void FileBrowserPrivateRequestFileSystemFunction::DidFail(
204 base::File::Error error_code) {
205 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
206
207 SetError(base::StringPrintf("File error %d", static_cast<int>(error_code)));
208 SendResponse(false);
209 }
210
211 bool FileBrowserPrivateRequestFileSystemFunction::
SetupFileSystemAccessPermissions(scoped_refptr<fileapi::FileSystemContext> file_system_context,int child_id,Profile * profile,scoped_refptr<const extensions::Extension> extension)212 SetupFileSystemAccessPermissions(
213 scoped_refptr<fileapi::FileSystemContext> file_system_context,
214 int child_id,
215 Profile* profile,
216 scoped_refptr<const extensions::Extension> extension) {
217 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
218
219 if (!extension.get())
220 return false;
221
222 // Make sure that only component extension can access the entire
223 // local file system.
224 if (extension_->location() != extensions::Manifest::COMPONENT) {
225 NOTREACHED() << "Private method access by non-component extension "
226 << extension->id();
227 return false;
228 }
229
230 fileapi::ExternalFileSystemBackend* backend =
231 file_system_context->external_backend();
232 if (!backend)
233 return false;
234
235 // Grant full access to File API from this component extension.
236 backend->GrantFullAccessToExtension(extension_->id());
237
238 // Grant R/W file permissions to the renderer hosting component
239 // extension for all paths exposed by our local file system backend.
240 std::vector<base::FilePath> root_dirs = backend->GetRootDirectories();
241 for (size_t i = 0; i < root_dirs.size(); ++i) {
242 ChildProcessSecurityPolicy::GetInstance()->GrantCreateReadWriteFile(
243 child_id, root_dirs[i]);
244 }
245
246 // Grant R/W permissions to profile-specific directories (Drive, Downloads)
247 // from other profiles. Those directories may not be mounted at this moment
248 // yet, so we need to do this separately from the above loop over
249 // GetRootDirectories().
250 const std::vector<Profile*>& profiles =
251 g_browser_process->profile_manager()->GetLoadedProfiles();
252 for (size_t i = 0; i < profiles.size(); ++i) {
253 if (!profiles[i]->IsOffTheRecord()) {
254 file_manager::util::SetupProfileFileAccessPermissions(child_id,
255 profiles[i]);
256 }
257 }
258
259 return true;
260 }
261
RunAsync()262 bool FileBrowserPrivateRequestFileSystemFunction::RunAsync() {
263 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
264 using extensions::api::file_browser_private::RequestFileSystem::Params;
265 const scoped_ptr<Params> params(Params::Create(*args_));
266 EXTENSION_FUNCTION_VALIDATE(params);
267
268 if (!dispatcher() || !render_view_host() || !render_view_host()->GetProcess())
269 return false;
270
271 set_log_on_completion(true);
272
273 using file_manager::VolumeManager;
274 using file_manager::VolumeInfo;
275 VolumeManager* volume_manager = VolumeManager::Get(GetProfile());
276 if (!volume_manager)
277 return false;
278
279 VolumeInfo volume_info;
280 if (!volume_manager->FindVolumeInfoById(params->volume_id, &volume_info)) {
281 DidFail(base::File::FILE_ERROR_NOT_FOUND);
282 return false;
283 }
284
285 scoped_refptr<fileapi::FileSystemContext> file_system_context =
286 file_manager::util::GetFileSystemContextForRenderViewHost(
287 GetProfile(), render_view_host());
288
289 // Set up file permission access.
290 const int child_id = render_view_host()->GetProcess()->GetID();
291 if (!SetupFileSystemAccessPermissions(file_system_context,
292 child_id,
293 GetProfile(),
294 GetExtension())) {
295 DidFail(base::File::FILE_ERROR_SECURITY);
296 return false;
297 }
298
299 FileDefinition file_definition;
300 if (!file_manager::util::ConvertAbsoluteFilePathToRelativeFileSystemPath(
301 GetProfile(),
302 extension_id(),
303 volume_info.mount_path,
304 &file_definition.virtual_path)) {
305 DidFail(base::File::FILE_ERROR_INVALID_OPERATION);
306 return false;
307 }
308 file_definition.is_directory = true;
309
310 file_manager::util::ConvertFileDefinitionToEntryDefinition(
311 GetProfile(),
312 extension_id(),
313 file_definition,
314 base::Bind(
315 &FileBrowserPrivateRequestFileSystemFunction::OnEntryDefinition,
316 this));
317 return true;
318 }
319
OnEntryDefinition(const EntryDefinition & entry_definition)320 void FileBrowserPrivateRequestFileSystemFunction::OnEntryDefinition(
321 const EntryDefinition& entry_definition) {
322 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
323
324 if (entry_definition.error != base::File::FILE_OK) {
325 DidFail(entry_definition.error);
326 return;
327 }
328
329 if (!entry_definition.is_directory) {
330 DidFail(base::File::FILE_ERROR_NOT_A_DIRECTORY);
331 return;
332 }
333
334 base::DictionaryValue* dict = new base::DictionaryValue();
335 SetResult(dict);
336 dict->SetString("name", entry_definition.file_system_name);
337 dict->SetString("root_url", entry_definition.file_system_root_url);
338 dict->SetInteger("error", drive::FILE_ERROR_OK);
339 SendResponse(true);
340 }
341
Respond(bool success)342 void FileWatchFunctionBase::Respond(bool success) {
343 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
344
345 SetResult(base::Value::CreateBooleanValue(success));
346 SendResponse(success);
347 }
348
RunAsync()349 bool FileWatchFunctionBase::RunAsync() {
350 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
351
352 if (!render_view_host() || !render_view_host()->GetProcess())
353 return false;
354
355 // First param is url of a file to watch.
356 std::string url;
357 if (!args_->GetString(0, &url) || url.empty())
358 return false;
359
360 scoped_refptr<fileapi::FileSystemContext> file_system_context =
361 file_manager::util::GetFileSystemContextForRenderViewHost(
362 GetProfile(), render_view_host());
363
364 FileSystemURL file_watch_url = file_system_context->CrackURL(GURL(url));
365 base::FilePath local_path = file_watch_url.path();
366 base::FilePath virtual_path = file_watch_url.virtual_path();
367 if (local_path.empty()) {
368 Respond(false);
369 return true;
370 }
371 PerformFileWatchOperation(local_path, virtual_path, extension_id());
372
373 return true;
374 }
375
PerformFileWatchOperation(const base::FilePath & local_path,const base::FilePath & virtual_path,const std::string & extension_id)376 void FileBrowserPrivateAddFileWatchFunction::PerformFileWatchOperation(
377 const base::FilePath& local_path,
378 const base::FilePath& virtual_path,
379 const std::string& extension_id) {
380 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
381
382 file_manager::EventRouter* event_router =
383 file_manager::FileBrowserPrivateAPI::Get(GetProfile())->event_router();
384 event_router->AddFileWatch(
385 local_path,
386 virtual_path,
387 extension_id,
388 base::Bind(&FileBrowserPrivateAddFileWatchFunction::Respond, this));
389 }
390
PerformFileWatchOperation(const base::FilePath & local_path,const base::FilePath & unused,const std::string & extension_id)391 void FileBrowserPrivateRemoveFileWatchFunction::PerformFileWatchOperation(
392 const base::FilePath& local_path,
393 const base::FilePath& unused,
394 const std::string& extension_id) {
395 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
396
397 file_manager::EventRouter* event_router =
398 file_manager::FileBrowserPrivateAPI::Get(GetProfile())->event_router();
399 event_router->RemoveFileWatch(local_path, extension_id);
400 Respond(true);
401 }
402
RunAsync()403 bool FileBrowserPrivateGetSizeStatsFunction::RunAsync() {
404 using extensions::api::file_browser_private::GetSizeStats::Params;
405 const scoped_ptr<Params> params(Params::Create(*args_));
406 EXTENSION_FUNCTION_VALIDATE(params);
407
408 using file_manager::VolumeManager;
409 using file_manager::VolumeInfo;
410 VolumeManager* volume_manager = VolumeManager::Get(GetProfile());
411 if (!volume_manager)
412 return false;
413
414 VolumeInfo volume_info;
415 if (!volume_manager->FindVolumeInfoById(params->volume_id, &volume_info))
416 return false;
417
418 if (volume_info.type == file_manager::VOLUME_TYPE_GOOGLE_DRIVE) {
419 drive::FileSystemInterface* file_system =
420 drive::util::GetFileSystemByProfile(GetProfile());
421 if (!file_system) {
422 // |file_system| is NULL if Drive is disabled.
423 // If stats couldn't be gotten for drive, result should be left
424 // undefined. See comments in GetDriveAvailableSpaceCallback().
425 SendResponse(true);
426 return true;
427 }
428
429 file_system->GetAvailableSpace(
430 base::Bind(&FileBrowserPrivateGetSizeStatsFunction::
431 GetDriveAvailableSpaceCallback,
432 this));
433 } else {
434 uint64* total_size = new uint64(0);
435 uint64* remaining_size = new uint64(0);
436 BrowserThread::PostBlockingPoolTaskAndReply(
437 FROM_HERE,
438 base::Bind(&GetSizeStatsOnBlockingPool,
439 volume_info.mount_path.value(),
440 total_size,
441 remaining_size),
442 base::Bind(&FileBrowserPrivateGetSizeStatsFunction::
443 GetSizeStatsCallback,
444 this,
445 base::Owned(total_size),
446 base::Owned(remaining_size)));
447 }
448 return true;
449 }
450
GetDriveAvailableSpaceCallback(drive::FileError error,int64 bytes_total,int64 bytes_used)451 void FileBrowserPrivateGetSizeStatsFunction::GetDriveAvailableSpaceCallback(
452 drive::FileError error,
453 int64 bytes_total,
454 int64 bytes_used) {
455 if (error == drive::FILE_ERROR_OK) {
456 const uint64 bytes_total_unsigned = bytes_total;
457 const uint64 bytes_remaining_unsigned = bytes_total - bytes_used;
458 GetSizeStatsCallback(&bytes_total_unsigned,
459 &bytes_remaining_unsigned);
460 } else {
461 // If stats couldn't be gotten for drive, result should be left undefined.
462 SendResponse(true);
463 }
464 }
465
GetSizeStatsCallback(const uint64 * total_size,const uint64 * remaining_size)466 void FileBrowserPrivateGetSizeStatsFunction::GetSizeStatsCallback(
467 const uint64* total_size,
468 const uint64* remaining_size) {
469 base::DictionaryValue* sizes = new base::DictionaryValue();
470 SetResult(sizes);
471
472 sizes->SetDouble("totalSize", static_cast<double>(*total_size));
473 sizes->SetDouble("remainingSize", static_cast<double>(*remaining_size));
474
475 SendResponse(true);
476 }
477
RunAsync()478 bool FileBrowserPrivateValidatePathNameLengthFunction::RunAsync() {
479 using extensions::api::file_browser_private::ValidatePathNameLength::Params;
480 const scoped_ptr<Params> params(Params::Create(*args_));
481 EXTENSION_FUNCTION_VALIDATE(params);
482
483 scoped_refptr<fileapi::FileSystemContext> file_system_context =
484 file_manager::util::GetFileSystemContextForRenderViewHost(
485 GetProfile(), render_view_host());
486
487 fileapi::FileSystemURL filesystem_url(
488 file_system_context->CrackURL(GURL(params->parent_directory_url)));
489 if (!chromeos::FileSystemBackend::CanHandleURL(filesystem_url))
490 return false;
491
492 // No explicit limit on the length of Drive file names.
493 if (filesystem_url.type() == fileapi::kFileSystemTypeDrive) {
494 SetResult(new base::FundamentalValue(true));
495 SendResponse(true);
496 return true;
497 }
498
499 base::PostTaskAndReplyWithResult(
500 BrowserThread::GetBlockingPool(),
501 FROM_HERE,
502 base::Bind(&GetFileNameMaxLengthOnBlockingPool,
503 filesystem_url.path().AsUTF8Unsafe()),
504 base::Bind(&FileBrowserPrivateValidatePathNameLengthFunction::
505 OnFilePathLimitRetrieved,
506 this, params->name.size()));
507 return true;
508 }
509
OnFilePathLimitRetrieved(size_t current_length,size_t max_length)510 void FileBrowserPrivateValidatePathNameLengthFunction::OnFilePathLimitRetrieved(
511 size_t current_length,
512 size_t max_length) {
513 SetResult(new base::FundamentalValue(current_length <= max_length));
514 SendResponse(true);
515 }
516
RunAsync()517 bool FileBrowserPrivateFormatVolumeFunction::RunAsync() {
518 using extensions::api::file_browser_private::FormatVolume::Params;
519 const scoped_ptr<Params> params(Params::Create(*args_));
520 EXTENSION_FUNCTION_VALIDATE(params);
521
522 using file_manager::VolumeManager;
523 using file_manager::VolumeInfo;
524 VolumeManager* volume_manager = VolumeManager::Get(GetProfile());
525 if (!volume_manager)
526 return false;
527
528 VolumeInfo volume_info;
529 if (!volume_manager->FindVolumeInfoById(params->volume_id, &volume_info))
530 return false;
531
532 DiskMountManager::GetInstance()->FormatMountedDevice(
533 volume_info.mount_path.AsUTF8Unsafe());
534 SendResponse(true);
535 return true;
536 }
537
RunAsync()538 bool FileBrowserPrivateStartCopyFunction::RunAsync() {
539 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
540
541 using extensions::api::file_browser_private::StartCopy::Params;
542 const scoped_ptr<Params> params(Params::Create(*args_));
543 EXTENSION_FUNCTION_VALIDATE(params);
544
545 if (params->source_url.empty() || params->parent.empty() ||
546 params->new_name.empty()) {
547 // Error code in format of DOMError.name.
548 SetError("EncodingError");
549 return false;
550 }
551
552 scoped_refptr<fileapi::FileSystemContext> file_system_context =
553 file_manager::util::GetFileSystemContextForRenderViewHost(
554 GetProfile(), render_view_host());
555
556 // |parent| may have a trailing slash if it is a root directory.
557 std::string destination_url_string = params->parent;
558 if (destination_url_string[destination_url_string.size() - 1] != '/')
559 destination_url_string += '/';
560 destination_url_string += net::EscapePath(params->new_name);
561
562 fileapi::FileSystemURL source_url(
563 file_system_context->CrackURL(GURL(params->source_url)));
564 fileapi::FileSystemURL destination_url(
565 file_system_context->CrackURL(GURL(destination_url_string)));
566
567 if (!source_url.is_valid() || !destination_url.is_valid()) {
568 // Error code in format of DOMError.name.
569 SetError("EncodingError");
570 return false;
571 }
572
573 return BrowserThread::PostTaskAndReplyWithResult(
574 BrowserThread::IO,
575 FROM_HERE,
576 base::Bind(&StartCopyOnIOThread,
577 GetProfile(),
578 file_system_context,
579 source_url,
580 destination_url),
581 base::Bind(&FileBrowserPrivateStartCopyFunction::RunAfterStartCopy,
582 this));
583 }
584
RunAfterStartCopy(int operation_id)585 void FileBrowserPrivateStartCopyFunction::RunAfterStartCopy(
586 int operation_id) {
587 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
588
589 SetResult(base::Value::CreateIntegerValue(operation_id));
590 SendResponse(true);
591 }
592
RunAsync()593 bool FileBrowserPrivateCancelCopyFunction::RunAsync() {
594 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
595
596 using extensions::api::file_browser_private::CancelCopy::Params;
597 const scoped_ptr<Params> params(Params::Create(*args_));
598 EXTENSION_FUNCTION_VALIDATE(params);
599
600 scoped_refptr<fileapi::FileSystemContext> file_system_context =
601 file_manager::util::GetFileSystemContextForRenderViewHost(
602 GetProfile(), render_view_host());
603
604 // We don't much take care about the result of cancellation.
605 BrowserThread::PostTask(
606 BrowserThread::IO,
607 FROM_HERE,
608 base::Bind(&CancelCopyOnIOThread, file_system_context, params->copy_id));
609 SendResponse(true);
610 return true;
611 }
612
RunAsync()613 bool FileBrowserPrivateInternalResolveIsolatedEntriesFunction::RunAsync() {
614 using extensions::api::file_browser_private_internal::ResolveIsolatedEntries::
615 Params;
616 const scoped_ptr<Params> params(Params::Create(*args_));
617 EXTENSION_FUNCTION_VALIDATE(params);
618
619 scoped_refptr<fileapi::FileSystemContext> file_system_context =
620 file_manager::util::GetFileSystemContextForRenderViewHost(
621 GetProfile(), render_view_host());
622 DCHECK(file_system_context);
623
624 const fileapi::ExternalFileSystemBackend* external_backend =
625 file_system_context->external_backend();
626 DCHECK(external_backend);
627
628 file_manager::util::FileDefinitionList file_definition_list;
629 for (size_t i = 0; i < params->urls.size(); ++i) {
630 FileSystemURL fileSystemUrl =
631 file_system_context->CrackURL(GURL(params->urls[i]));
632 DCHECK(external_backend->CanHandleType(fileSystemUrl.type()));
633
634 FileDefinition file_definition;
635 const bool result =
636 file_manager::util::ConvertAbsoluteFilePathToRelativeFileSystemPath(
637 GetProfile(),
638 extension_->id(),
639 fileSystemUrl.path(),
640 &file_definition.virtual_path);
641 if (!result)
642 continue;
643 // The API only supports isolated files.
644 file_definition.is_directory = false;
645 file_definition_list.push_back(file_definition);
646 }
647
648 file_manager::util::ConvertFileDefinitionListToEntryDefinitionList(
649 GetProfile(),
650 extension_->id(),
651 file_definition_list, // Safe, since copied internally.
652 base::Bind(
653 &FileBrowserPrivateInternalResolveIsolatedEntriesFunction::
654 RunAsyncAfterConvertFileDefinitionListToEntryDefinitionList,
655 this));
656 return true;
657 }
658
659 void FileBrowserPrivateInternalResolveIsolatedEntriesFunction::
RunAsyncAfterConvertFileDefinitionListToEntryDefinitionList(scoped_ptr<file_manager::util::EntryDefinitionList> entry_definition_list)660 RunAsyncAfterConvertFileDefinitionListToEntryDefinitionList(scoped_ptr<
661 file_manager::util::EntryDefinitionList> entry_definition_list) {
662 using extensions::api::file_browser_private_internal::EntryDescription;
663 std::vector<linked_ptr<EntryDescription> > entries;
664
665 for (size_t i = 0; i < entry_definition_list->size(); ++i) {
666 if (entry_definition_list->at(i).error != base::File::FILE_OK)
667 continue;
668 linked_ptr<EntryDescription> entry(new EntryDescription);
669 entry->file_system_name = entry_definition_list->at(i).file_system_name;
670 entry->file_system_root = entry_definition_list->at(i).file_system_root_url;
671 entry->file_full_path =
672 "/" + entry_definition_list->at(i).full_path.AsUTF8Unsafe();
673 entry->file_is_directory = entry_definition_list->at(i).is_directory;
674 entries.push_back(entry);
675 }
676
677 results_ = extensions::api::file_browser_private_internal::
678 ResolveIsolatedEntries::Results::Create(entries);
679 SendResponse(true);
680 }
681 } // namespace extensions
682