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.
5 #include "chrome/browser/chromeos/drive/file_system/open_file_operation.h"
8 #include "base/bind_helpers.h"
9 #include "base/callback_helpers.h"
10 #include "base/files/file_path.h"
11 #include "base/logging.h"
12 #include "base/message_loop/message_loop_proxy.h"
13 #include "base/task_runner_util.h"
14 #include "chrome/browser/chromeos/drive/drive.pb.h"
15 #include "chrome/browser/chromeos/drive/file_cache.h"
16 #include "chrome/browser/chromeos/drive/file_errors.h"
17 #include "chrome/browser/chromeos/drive/file_system/create_file_operation.h"
18 #include "chrome/browser/chromeos/drive/file_system/download_operation.h"
19 #include "chrome/browser/chromeos/drive/file_system/operation_delegate.h"
20 #include "chrome/browser/chromeos/drive/job_scheduler.h"
21 #include "content/public/browser/browser_thread.h"
23 using content::BrowserThread
;
26 namespace file_system
{
28 OpenFileOperation::OpenFileOperation(
29 base::SequencedTaskRunner
* blocking_task_runner
,
30 OperationDelegate
* delegate
,
31 JobScheduler
* scheduler
,
32 internal::ResourceMetadata
* metadata
,
33 internal::FileCache
* cache
,
34 const base::FilePath
& temporary_file_directory
)
35 : blocking_task_runner_(blocking_task_runner
),
38 create_file_operation_(new CreateFileOperation(
39 blocking_task_runner
, delegate
, metadata
)),
40 download_operation_(new DownloadOperation(
41 blocking_task_runner
, delegate
, scheduler
,
42 metadata
, cache
, temporary_file_directory
)),
43 weak_ptr_factory_(this) {
46 OpenFileOperation::~OpenFileOperation() {
49 void OpenFileOperation::OpenFile(const base::FilePath
& file_path
,
51 const std::string
& mime_type
,
52 const OpenFileCallback
& callback
) {
53 DCHECK_CURRENTLY_ON(BrowserThread::UI
);
54 DCHECK(!callback
.is_null());
58 // It is not necessary to create a new file even if not exists.
59 // So call OpenFileAfterCreateFile directly with FILE_ERROR_OK
60 // to skip file creation.
61 OpenFileAfterCreateFile(file_path
, callback
, FILE_ERROR_OK
);
64 create_file_operation_
->CreateFile(
66 true, // exclusive: fail if already exists
68 base::Bind(&OpenFileOperation::OpenFileAfterCreateFile
,
69 weak_ptr_factory_
.GetWeakPtr(), file_path
, callback
));
71 case OPEN_OR_CREATE_FILE
:
72 create_file_operation_
->CreateFile(
74 false, // not-exclusive
76 base::Bind(&OpenFileOperation::OpenFileAfterCreateFile
,
77 weak_ptr_factory_
.GetWeakPtr(), file_path
, callback
));
82 void OpenFileOperation::OpenFileAfterCreateFile(
83 const base::FilePath
& file_path
,
84 const OpenFileCallback
& callback
,
86 DCHECK_CURRENTLY_ON(BrowserThread::UI
);
87 DCHECK(!callback
.is_null());
89 if (error
!= FILE_ERROR_OK
) {
90 callback
.Run(error
, base::FilePath(), base::Closure());
94 download_operation_
->EnsureFileDownloadedByPath(
96 ClientContext(USER_INITIATED
),
97 GetFileContentInitializedCallback(),
98 google_apis::GetContentCallback(),
100 &OpenFileOperation::OpenFileAfterFileDownloaded
,
101 weak_ptr_factory_
.GetWeakPtr(), callback
));
104 void OpenFileOperation::OpenFileAfterFileDownloaded(
105 const OpenFileCallback
& callback
,
107 const base::FilePath
& local_file_path
,
108 scoped_ptr
<ResourceEntry
> entry
) {
109 DCHECK_CURRENTLY_ON(BrowserThread::UI
);
110 DCHECK(!callback
.is_null());
112 if (error
== FILE_ERROR_OK
) {
114 DCHECK(entry
->has_file_specific_info());
115 if (entry
->file_specific_info().is_hosted_document())
116 // No support for opening a hosted document.
117 error
= FILE_ERROR_INVALID_OPERATION
;
120 if (error
!= FILE_ERROR_OK
) {
121 callback
.Run(error
, base::FilePath(), base::Closure());
125 scoped_ptr
<base::ScopedClosureRunner
>* file_closer
=
126 new scoped_ptr
<base::ScopedClosureRunner
>;
127 base::PostTaskAndReplyWithResult(
128 blocking_task_runner_
.get(),
130 base::Bind(&internal::FileCache::OpenForWrite
,
131 base::Unretained(cache_
),
134 base::Bind(&OpenFileOperation::OpenFileAfterOpenForWrite
,
135 weak_ptr_factory_
.GetWeakPtr(),
139 base::Owned(file_closer
)));
142 void OpenFileOperation::OpenFileAfterOpenForWrite(
143 const base::FilePath
& local_file_path
,
144 const std::string
& local_id
,
145 const OpenFileCallback
& callback
,
146 scoped_ptr
<base::ScopedClosureRunner
>* file_closer
,
148 DCHECK_CURRENTLY_ON(BrowserThread::UI
);
149 DCHECK(!callback
.is_null());
151 if (error
!= FILE_ERROR_OK
) {
152 callback
.Run(error
, base::FilePath(), base::Closure());
156 ++open_files_
[local_id
];
157 callback
.Run(error
, local_file_path
,
158 base::Bind(&OpenFileOperation::CloseFile
,
159 weak_ptr_factory_
.GetWeakPtr(),
161 base::Passed(file_closer
)));
164 void OpenFileOperation::CloseFile(
165 const std::string
& local_id
,
166 scoped_ptr
<base::ScopedClosureRunner
> file_closer
) {
167 DCHECK_CURRENTLY_ON(BrowserThread::UI
);
168 DCHECK_GT(open_files_
[local_id
], 0);
170 if (--open_files_
[local_id
] == 0) {
171 // All clients closes this file, so notify to upload the file.
172 open_files_
.erase(local_id
);
173 delegate_
->OnEntryUpdatedByOperation(ClientContext(USER_INITIATED
),
176 // Clients may have enlarged the file. By FreeDiskpSpaceIfNeededFor(0),
177 // we try to ensure (0 + the-minimum-safe-margin = 512MB as of now) space.
178 blocking_task_runner_
->PostTask(
180 base::Bind(base::IgnoreResult(
181 base::Bind(&internal::FileCache::FreeDiskSpaceIfNeededFor
,
182 base::Unretained(cache_
),
187 } // namespace file_system